#region Sharp3D.Math, Copyright(C) 2003-2004 Eran Kampf, Licensed under LGPL.
// Sharp3D.Math math library
// Copyright (C) 2003-2004
// Eran Kampf
// tentacle@zahav.net.il
// http://tentacle.flipcode.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#endregion
using System;
using System.Diagnostics;
using NUnit.Framework;
using Sharp3D.Math.Core;
namespace Sharp3D.Math.Geometry3D
{
/// <summary>
/// Provides various distance computation methods.
/// </summary>
public sealed class DistanceMethods
{
#region Point-OBB
/// <summary>
/// Calculates the squared distance between a point and a solid oriented box.
/// </summary>
/// <param name="point">A <see cref="Vector3F"/> instance.</param>
/// <param name="obb">An <see cref="OrientedBox"/> instance.</param>
/// <param name="closestPoint">The closest point in box coordinates.</param>
/// <returns>The squared distance between a point and a solid oriented box.</returns>
/// <remarks>
/// Treating the oriented box as solid means that any point inside the box has
/// distance zero from the box.
/// </remarks>
public static float SquaredDistancePointSolidOrientedBox(Vector3F point, OrientedBox obb, out Vector3F closestPoint)
{
Vector3F diff = point - obb.Center;
Vector3F closest = new Vector3F(
Vector3F.DotProduct(diff, obb.Axis1),
Vector3F.DotProduct(diff, obb.Axis2),
Vector3F.DotProduct(diff, obb.Axis3));
float sqrDist = 0.0f;
float delta = 0.0f;
if (closest.X < -obb.Extent1)
{
delta = closest.X + obb.Extent1;
sqrDist += delta*delta;
closest.X = -obb.Extent1;
}
else if (closest.X > obb.Extent1)
{
delta = closest.X - obb.Extent1;
sqrDist += delta*delta;
closest.X = obb.Extent1;
}
if (closest.Y < -obb.Extent2)
{
delta = closest.Y + obb.Extent2;
sqrDist += delta*delta;
closest.Y = -obb.Extent2;
}
else if (closest.Y > obb.Extent2)
{
delta = closest.Y - obb.Extent2;
sqrDist += delta*delta;
closest.Y = obb.Extent2;
}
if (closest.Z < -obb.Extent3)
{
delta = closest.Z + obb.Extent3;
sqrDist += delta*delta;
closest.Z = -obb.Extent3;
}
else if (closest.Z > obb.Extent3)
{
delta = closest.Z - obb.Extent3;
sqrDist += delta*delta;
closest.Z = obb.Extent3;
}
closestPoint = closest;
return sqrDist;
}
/// <summary>
/// Calculates the squared distance between a point and a solid oriented box.
/// </summary>
/// <param name="point">A <see cref="Vector3F"/> instance.</param>
/// <param name="obb">An <see cref="OrientedBox"/> instance.</param>
/// <returns>The squared distance between a point and a solid oriented box.</returns>
/// <remarks>
/// Treating the oriented box as solid means that any point inside the box has
/// distance zero from the box.
/// </remarks>
public static float SquaredDistance(Vector3F point, OrientedBox obb)
{
Vector3F temp;
return SquaredDistancePointSolidOrientedBox(point, obb, out temp);
}
/// <summary>
/// Calculates the distance between a point and a solid oriented box.
/// </summary>
/// <param name="point">A <see cref="Vector3F"/> instance.</param>
/// <param name="obb">An <see cref="OrientedBox"/> instance.</param>
/// <returns>The distance between a point and a solid oriented box.</returns>
/// <remarks>
/// Treating the oriented box as solid means that any point inside the box has
/// distance zero from the box.
/// </remarks>
public static float Distance(Vector3F point, OrientedBox obb)
{
return (float)System.Math.Sqrt(SquaredDistance(point, obb));
}
#endregion
#region Private Constructor
private DistanceMethods()
{
}
#endregion
}
#region TestDistanceMethods
/// <summary>
/// Tests the DistanceMethods class.
/// </summary>
[TestFixture]
public class TestDistanceMethods
{
/// <summary>
/// Point-OrientedBox distance test
/// </summary>
[Test]
public void PointToOrientedBox()
{
Vector3F p = Vector3F.Zero;
OrientedBox obb = new OrientedBox(
Vector3F.Zero,
new Vector3F[3] {Vector3F.XAxis, Vector3F.YAxis, Vector3F.ZAxis},
new float[3] {1.0f, 1.0f, 1.0f});
// Point inside the box. Should return 0.
Assertion.AssertEquals(0,DistanceMethods.Distance(p, obb));
// Point on the box edge. Should return 0.
p = new Vector3F(1,1,1);
Assertion.AssertEquals(0,DistanceMethods.Distance(p, obb));
p = new Vector3F(2,0,0);
Assertion.AssertEquals(1,DistanceMethods.Distance(p, obb));
p = new Vector3F(0,10,0);
Assertion.AssertEquals(9,DistanceMethods.Distance(p, obb));
p = new Vector3F(0,0,5);
Assertion.AssertEquals(4,DistanceMethods.Distance(p, obb));
p = new Vector3F(2,2,2);
Assertion.AssertEquals(3,DistanceMethods.SquaredDistance(p, obb));
}
}
#endregion
}