+ add WildMagic algorithm to compute minimum volume oriented box

This commit is contained in:
wmayer 2016-07-02 17:01:56 +02:00
parent 8a30ac74b0
commit 0c6d52485c
22 changed files with 5428 additions and 0 deletions

View File

@ -87,6 +87,10 @@ SOURCE_GROUP("Core" FILES ${Core_SRCS})
SET(WildMagic4_SRCS
WildMagic4/Wm4ApprCylinderFit3.cpp
WildMagic4/Wm4ApprCylinderFit3.h
WildMagic4/Wm4ApprGaussPointsFit2.cpp
WildMagic4/Wm4ApprGaussPointsFit2.h
WildMagic4/Wm4ApprGaussPointsFit3.cpp
WildMagic4/Wm4ApprGaussPointsFit3.h
WildMagic4/Wm4ApprLineFit3.cpp
WildMagic4/Wm4ApprLineFit3.h
WildMagic4/Wm4ApprPlaneFit3.cpp
@ -99,8 +103,22 @@ SET(WildMagic4_SRCS
WildMagic4/Wm4ApprSphereFit3.h
WildMagic4/Wm4BandedMatrix.h
WildMagic4/Wm4BandedMatrix.inl
WildMagic4/Wm4Box2.h
WildMagic4/Wm4Box2.inl
WildMagic4/Wm4Box3.h
WildMagic4/Wm4Box3.inl
WildMagic4/Wm4ContBox2.cpp
WildMagic4/Wm4ContBox2.h
WildMagic4/Wm4ContBox3.cpp
WildMagic4/Wm4ContBox3.h
WildMagic4/Wm4ConvexHull.cpp
WildMagic4/Wm4ConvexHull.h
WildMagic4/Wm4ConvexHull1.cpp
WildMagic4/Wm4ConvexHull1.h
WildMagic4/Wm4ConvexHull2.cpp
WildMagic4/Wm4ConvexHull2.h
WildMagic4/Wm4ConvexHull3.cpp
WildMagic4/Wm4ConvexHull3.h
WildMagic4/Wm4DelPolygonEdge.cpp
WildMagic4/Wm4DelPolygonEdge.h
WildMagic4/Wm4DelPolyhedronFace.cpp
@ -207,6 +225,9 @@ SET(WildMagic4_SRCS
WildMagic4/Wm4Polynomial1.inl
WildMagic4/Wm4QuadricSurface.cpp
WildMagic4/Wm4QuadricSurface.h
WildMagic4/Wm4Quaternion.cpp
WildMagic4/Wm4Quaternion.h
WildMagic4/Wm4Quaternion.inl
WildMagic4/Wm4Query.h
WildMagic4/Wm4Query.inl
WildMagic4/Wm4Query2.h

View File

@ -0,0 +1,73 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ApprGaussPointsFit2.h"
#include "Wm4Eigen.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
Box2<Real> GaussPointsFit2 (int iQuantity, const Vector2<Real>* akPoint)
{
Box2<Real> kBox(Vector2<Real>::ZERO,Vector2<Real>::UNIT_X,
Vector2<Real>::UNIT_Y,(Real)1.0,(Real)1.0);
// compute the mean of the points
kBox.Center = akPoint[0];
int i;
for (i = 1; i < iQuantity; i++)
{
kBox.Center += akPoint[i];
}
Real fInvQuantity = ((Real)1.0)/iQuantity;
kBox.Center *= fInvQuantity;
// compute the covariance matrix of the points
Real fSumXX = (Real)0.0, fSumXY = (Real)0.0, fSumYY = (Real)0.0;
for (i = 0; i < iQuantity; i++)
{
Vector2<Real> kDiff = akPoint[i] - kBox.Center;
fSumXX += kDiff.X()*kDiff.X();
fSumXY += kDiff.X()*kDiff.Y();
fSumYY += kDiff.Y()*kDiff.Y();
}
fSumXX *= fInvQuantity;
fSumXY *= fInvQuantity;
fSumYY *= fInvQuantity;
// setup the eigensolver
Eigen<Real> kES(2);
kES(0,0) = fSumXX;
kES(0,1) = fSumXY;
kES(1,0) = fSumXY;
kES(1,1) = fSumYY;
kES.IncrSortEigenStuff2();
for (i = 0; i < 2; i++)
{
kBox.Extent[i] = kES.GetEigenvalue(i);
kES.GetEigenvector(i,kBox.Axis[i]);
}
return kBox;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
Box2<float> GaussPointsFit2<float> (int, const Vector2<float>*);
template WM4_FOUNDATION_ITEM
Box2<double> GaussPointsFit2<double> (int, const Vector2<double>*);
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,28 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4APPRGAUSSPOINTSFIT2_H
#define WM4APPRGAUSSPOINTSFIT2_H
#include "Wm4FoundationLIB.h"
#include "Wm4Box2.h"
namespace Wm4
{
// Fit points with a Gaussian distribution. The center is the mean of the
// points, the axes are the eigenvectors of the covariance matrix, and the
// extents are the eigenvalues of the covariance matrix and are returned in
// increasing order. The quantites are stored in a Box2<Real> just to have a
// single container.
template <class Real> WM4_FOUNDATION_ITEM
Box2<Real> GaussPointsFit2 (int iQuantity, const Vector2<Real>* akPoint);
}
#endif

View File

@ -0,0 +1,86 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ApprGaussPointsFit3.h"
#include "Wm4Eigen.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
Box3<Real> GaussPointsFit3 (int iQuantity, const Vector3<Real>* akPoint)
{
Box3<Real> kBox(Vector3<Real>::ZERO,Vector3<Real>::UNIT_X,
Vector3<Real>::UNIT_Y,Vector3<Real>::UNIT_Z,(Real)1.0,(Real)1.0,
(Real)1.0);
// compute the mean of the points
kBox.Center = akPoint[0];
int i;
for (i = 1; i < iQuantity; i++)
{
kBox.Center += akPoint[i];
}
Real fInvQuantity = ((Real)1.0)/iQuantity;
kBox.Center *= fInvQuantity;
// compute the covariance matrix of the points
Real fSumXX = (Real)0.0, fSumXY = (Real)0.0, fSumXZ = (Real)0.0;
Real fSumYY = (Real)0.0, fSumYZ = (Real)0.0, fSumZZ = (Real)0.0;
for (i = 0; i < iQuantity; i++)
{
Vector3<Real> kDiff = akPoint[i] - kBox.Center;
fSumXX += kDiff.X()*kDiff.X();
fSumXY += kDiff.X()*kDiff.Y();
fSumXZ += kDiff.X()*kDiff.Z();
fSumYY += kDiff.Y()*kDiff.Y();
fSumYZ += kDiff.Y()*kDiff.Z();
fSumZZ += kDiff.Z()*kDiff.Z();
}
fSumXX *= fInvQuantity;
fSumXY *= fInvQuantity;
fSumXZ *= fInvQuantity;
fSumYY *= fInvQuantity;
fSumYZ *= fInvQuantity;
fSumZZ *= fInvQuantity;
// setup the eigensolver
Eigen<Real> kES(3);
kES(0,0) = fSumXX;
kES(0,1) = fSumXY;
kES(0,2) = fSumXZ;
kES(1,0) = fSumXY;
kES(1,1) = fSumYY;
kES(1,2) = fSumYZ;
kES(2,0) = fSumXZ;
kES(2,1) = fSumYZ;
kES(2,2) = fSumZZ;
kES.IncrSortEigenStuff3();
for (i = 0; i < 3; i++)
{
kBox.Extent[i] = kES.GetEigenvalue(i);
kES.GetEigenvector(i,kBox.Axis[i]);
}
return kBox;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
Box3<float> GaussPointsFit3<float> (int, const Vector3<float>*);
template WM4_FOUNDATION_ITEM
Box3<double> GaussPointsFit3<double> (int, const Vector3<double>*);
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,28 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4APPRGAUSSPOINTSFIT3_H
#define WM4APPRGAUSSPOINTSFIT3_H
#include "Wm4FoundationLIB.h"
#include "Wm4Box3.h"
namespace Wm4
{
// Fit points with a Gaussian distribution. The center is the mean of the
// points, the axes are the eigenvectors of the covariance matrix, and the
// extents are the eigenvalues of the covariance matrix and are returned in
// increasing order. The quantites are stored in a Box3<Real> just to have a
// single container.
template <class Real> WM4_FOUNDATION_ITEM
Box3<Real> GaussPointsFit3 (int iQuantity, const Vector3<Real>* akPoint);
}
#endif

View File

@ -0,0 +1,48 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4BOX2_H
#define WM4BOX2_H
#include "Wm4FoundationLIB.h"
#include "Wm4Vector2.h"
namespace Wm4
{
template <class Real>
class Box2
{
public:
// A box has center C, axis directions U[0] and U[1] (both unit-length
// vectors), and extents e[0] and e[1] (both nonnegative numbers). A
// point X = C+y[0]*U[0]+y[1]*U[1] is inside or on the box whenever
// |y[i]| <= e[i] for all i.
// construction
Box2 (); // uninitialized
Box2 (const Vector2<Real>& rkCenter, const Vector2<Real>* akAxis,
const Real* afExtent);
Box2 (const Vector2<Real>& rkCenter, const Vector2<Real>& rkAxis0,
const Vector2<Real>& rkAxis1, Real fExtent0, Real fExtent1);
void ComputeVertices (Vector2<Real> akVertex[4]) const;
Vector2<Real> Center;
Vector2<Real> Axis[2]; // must be an orthonormal set of vectors
Real Extent[2]; // must be nonnegative
};
#include "Wm4Box2.inl"
typedef Box2<float> Box2f;
typedef Box2<double> Box2d;
}
#endif

View File

@ -0,0 +1,55 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
//----------------------------------------------------------------------------
template <class Real>
Box2<Real>::Box2 ()
{
// uninitialized
}
//----------------------------------------------------------------------------
template <class Real>
Box2<Real>::Box2 (const Vector2<Real>& rkCenter, const Vector2<Real>* akAxis,
const Real* afExtent)
:
Center(rkCenter)
{
for (int i = 0; i < 2; i++)
{
Axis[i] = akAxis[i];
Extent[i] = afExtent[i];
}
}
//----------------------------------------------------------------------------
template <class Real>
Box2<Real>::Box2 (const Vector2<Real>& rkCenter, const Vector2<Real>& rkAxis0,
const Vector2<Real>& rkAxis1, Real fExtent0, Real fExtent1)
:
Center(rkCenter)
{
Axis[0] = rkAxis0;
Axis[1] = rkAxis1;
Extent[0] = fExtent0;
Extent[1] = fExtent1;
}
//----------------------------------------------------------------------------
template <class Real>
void Box2<Real>::ComputeVertices (Vector2<Real> akVertex[4]) const
{
Vector2<Real> akEAxis[2] =
{
Axis[0]*Extent[0],
Axis[1]*Extent[1]
};
akVertex[0] = Center - akEAxis[0] - akEAxis[1];
akVertex[1] = Center + akEAxis[0] - akEAxis[1];
akVertex[2] = Center + akEAxis[0] + akEAxis[1];
akVertex[3] = Center - akEAxis[0] + akEAxis[1];
}
//----------------------------------------------------------------------------

View File

@ -0,0 +1,545 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ContBox2.h"
#include "Wm4ApprGaussPointsFit2.h"
#include "Wm4ConvexHull2.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
Box2<Real> ContAlignedBox (int iQuantity, const Vector2<Real>* akPoint)
{
Vector2<Real> kMin, kMax;
Vector2<Real>::ComputeExtremes(iQuantity,akPoint,kMin,kMax);
Box2<Real> kBox;
kBox.Center = ((Real)0.5)*(kMin + kMax);
kBox.Axis[0] = Vector2<Real>::UNIT_X;
kBox.Axis[1] = Vector2<Real>::UNIT_Y;
Vector2<Real> kHalfDiagonal = ((Real)0.5)*(kMax - kMin);
for (int i = 0; i < 2; i++)
{
kBox.Extent[i] = kHalfDiagonal[i];
}
return kBox;
}
//----------------------------------------------------------------------------
template <class Real>
Box2<Real> ContOrientedBox (int iQuantity, const Vector2<Real>* akPoint)
{
Box2<Real> kBox = GaussPointsFit2<Real>(iQuantity,akPoint);
// Let C be the box center and let U0 and U1 be the box axes. Each
// input point is of the form X = C + y0*U0 + y1*U1. The following code
// computes min(y0), max(y0), min(y1), max(y1), min(y2), and max(y2).
// The box center is then adjusted to be
// C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1
Vector2<Real> kDiff = akPoint[0] - kBox.Center;
Vector2<Real> kMin(kDiff.Dot(kBox.Axis[0]),kDiff.Dot(kBox.Axis[1]));
Vector2<Real> kMax = kMin;
for (int i = 1; i < iQuantity; i++)
{
kDiff = akPoint[i] - kBox.Center;
for (int j = 0; j < 2; j++)
{
Real fDot = kDiff.Dot(kBox.Axis[j]);
if (fDot < kMin[j])
{
kMin[j] = fDot;
}
else if (fDot > kMax[j])
{
kMax[j] = fDot;
}
}
}
kBox.Center +=
(((Real)0.5)*(kMin[0]+kMax[0]))*kBox.Axis[0] +
(((Real)0.5)*(kMin[1]+kMax[1]))*kBox.Axis[1];
kBox.Extent[0] = ((Real)0.5)*(kMax[0] - kMin[0]);
kBox.Extent[1] = ((Real)0.5)*(kMax[1] - kMin[1]);
return kBox;
}
//----------------------------------------------------------------------------
template <class Real>
static void UpdateBox (const Vector2<Real>& rkLPoint,
const Vector2<Real>& rkRPoint, const Vector2<Real>& rkBPoint,
const Vector2<Real>& rkTPoint, const Vector2<Real>& rkU,
const Vector2<Real>& rkV, Real& rfMinAreaDiv4, Box2<Real>& rkBox)
{
Vector2<Real> kRLDiff = rkRPoint - rkLPoint;
Vector2<Real> kTBDiff = rkTPoint - rkBPoint;
Real fExtent0 = ((Real)0.5)*(rkU.Dot(kRLDiff));
Real fExtent1 = ((Real)0.5)*(rkV.Dot(kTBDiff));
Real fAreaDiv4 = fExtent0*fExtent1;
if (fAreaDiv4 < rfMinAreaDiv4)
{
rfMinAreaDiv4 = fAreaDiv4;
rkBox.Axis[0] = rkU;
rkBox.Axis[1] = rkV;
rkBox.Extent[0] = fExtent0;
rkBox.Extent[1] = fExtent1;
Vector2<Real> kLBDiff = rkLPoint - rkBPoint;
rkBox.Center = rkLPoint + rkU*fExtent0 +
rkV*(fExtent1 - rkV.Dot(kLBDiff));
}
}
//----------------------------------------------------------------------------
template <class Real>
Box2<Real> ContMinBox (int iQuantity, const Vector2<Real>* akPoint,
Real fEpsilon, Query::Type eQueryType, bool bIsConvexPolygon)
{
Box2<Real> kBox;
// get the convex hull of the points
Vector2<Real>* akHPoint = 0;
if (bIsConvexPolygon)
{
akHPoint = (Vector2<Real>*)akPoint;
}
else
{
ConvexHull2<Real> kHull(iQuantity,(Vector2<Real>*)akPoint,fEpsilon,
false,eQueryType);
int iHDim = kHull.GetDimension();
int iHQuantity = kHull.GetSimplexQuantity();
const int* aiHIndex = kHull.GetIndices();
if (iHDim == 0)
{
kBox.Center = akPoint[0];
kBox.Axis[0] = Vector2<Real>::UNIT_X;
kBox.Axis[1] = Vector2<Real>::UNIT_Y;
kBox.Extent[0] = (Real)0.0;
kBox.Extent[1] = (Real)0.0;
return kBox;
}
if (iHDim == 1)
{
ConvexHull1<Real>* pkHull1 = kHull.GetConvexHull1();
aiHIndex = pkHull1->GetIndices();
kBox.Center = ((Real)0.5)*(akPoint[aiHIndex[0]] +
akPoint[aiHIndex[1]]);
Vector2<Real> kDiff = akPoint[aiHIndex[1]] - akPoint[aiHIndex[0]];
kBox.Extent[0] = ((Real)0.5)*kDiff.Normalize();
kBox.Extent[1] = (Real)0.0;
kBox.Axis[0] = kDiff;
kBox.Axis[1] = -kBox.Axis[0].Perp();
WM4_DELETE pkHull1;
return kBox;
}
iQuantity = iHQuantity;
akHPoint = WM4_NEW Vector2<Real>[iQuantity];
for (int i = 0; i < iQuantity; i++)
{
akHPoint[i] = akPoint[aiHIndex[i]];
}
}
// The input points are V[0] through V[N-1] and are assumed to be the
// vertices of a convex polygon that are counterclockwise ordered. The
// input points must not contain three consecutive collinear points.
// Unit-length edge directions of convex polygon. These could be
// precomputed and passed to this routine if the application requires it.
int iQuantityM1 = iQuantity -1;
Vector2<Real>* akEdge = WM4_NEW Vector2<Real>[iQuantity];
bool* abVisited = WM4_NEW bool[iQuantity];
int i;
for (i = 0; i < iQuantityM1; i++)
{
akEdge[i] = akHPoint[i+1] - akHPoint[i];
akEdge[i].Normalize();
abVisited[i] = false;
}
akEdge[iQuantityM1] = akHPoint[0] - akHPoint[iQuantityM1];
akEdge[iQuantityM1].Normalize();
abVisited[iQuantityM1] = false;
// Find the smallest axis-aligned box containing the points. Keep track
// of the extremum indices, L (left), R (right), B (bottom), and T (top)
// so that the following constraints are met:
// V[L].X() <= V[i].X() for all i and V[(L+1)%N].X() > V[L].X()
// V[R].X() >= V[i].X() for all i and V[(R+1)%N].X() < V[R].X()
// V[B].Y() <= V[i].Y() for all i and V[(B+1)%N].Y() > V[B].Y()
// V[T].Y() >= V[i].Y() for all i and V[(T+1)%N].Y() < V[T].Y()
Real fXMin = akHPoint[0].X(), fXMax = fXMin;
Real fYMin = akHPoint[0].Y(), fYMax = fYMin;
int iLIndex = 0, iRIndex = 0, iBIndex = 0, iTIndex = 0;
for (i = 1; i < iQuantity; i++)
{
if (akHPoint[i].X() <= fXMin)
{
fXMin = akHPoint[i].X();
iLIndex = i;
}
if (akHPoint[i].X() >= fXMax)
{
fXMax = akHPoint[i].X();
iRIndex = i;
}
if (akHPoint[i].Y() <= fYMin)
{
fYMin = akHPoint[i].Y();
iBIndex = i;
}
if (akHPoint[i].Y() >= fYMax)
{
fYMax = akHPoint[i].Y();
iTIndex = i;
}
}
// wrap-around tests to ensure the constraints mentioned above
if (iLIndex == iQuantityM1)
{
if (akHPoint[0].X() <= fXMin)
{
fXMin = akHPoint[0].X();
iLIndex = 0;
}
}
if (iRIndex == iQuantityM1)
{
if (akHPoint[0].X() >= fXMax)
{
fXMax = akHPoint[0].X();
iRIndex = 0;
}
}
if (iBIndex == iQuantityM1)
{
if (akHPoint[0].Y() <= fYMin)
{
fYMin = akHPoint[0].Y();
iBIndex = 0;
}
}
if (iTIndex == iQuantityM1)
{
if (akHPoint[0].Y() >= fYMax)
{
fYMax = akHPoint[0].Y();
iTIndex = 0;
}
}
// dimensions of axis-aligned box (extents store width and height for now)
kBox.Center.X() = ((Real)0.5)*(fXMin + fXMax);
kBox.Center.Y() = ((Real)0.5)*(fYMin + fYMax);
kBox.Axis[0] = Vector2<Real>::UNIT_X;
kBox.Axis[1] = Vector2<Real>::UNIT_Y;
kBox.Extent[0] = ((Real)0.5)*(fXMax - fXMin);
kBox.Extent[1] = ((Real)0.5)*(fYMax - fYMin);
Real fMinAreaDiv4 = kBox.Extent[0]*kBox.Extent[1];
// rotating calipers algorithm
enum { F_NONE, F_LEFT, F_RIGHT, F_BOTTOM, F_TOP };
Vector2<Real> kU = Vector2<Real>::UNIT_X, kV = Vector2<Real>::UNIT_Y;
bool bDone = false;
while (!bDone)
{
// determine edge that forms smallest angle with current box edges
int iFlag = F_NONE;
Real fMaxDot = (Real)0.0;
Real fDot = kU.Dot(akEdge[iBIndex]);
if (fDot > fMaxDot)
{
fMaxDot = fDot;
iFlag = F_BOTTOM;
}
fDot = kV.Dot(akEdge[iRIndex]);
if (fDot > fMaxDot)
{
fMaxDot = fDot;
iFlag = F_RIGHT;
}
fDot = -kU.Dot(akEdge[iTIndex]);
if (fDot > fMaxDot)
{
fMaxDot = fDot;
iFlag = F_TOP;
}
fDot = -kV.Dot(akEdge[iLIndex]);
if (fDot > fMaxDot)
{
fMaxDot = fDot;
iFlag = F_LEFT;
}
switch (iFlag)
{
case F_BOTTOM:
if (abVisited[iBIndex])
{
bDone = true;
}
else
{
// compute box axes with E[B] as an edge
kU = akEdge[iBIndex];
kV = -kU.Perp();
UpdateBox(akHPoint[iLIndex],akHPoint[iRIndex],
akHPoint[iBIndex],akHPoint[iTIndex],kU,kV,fMinAreaDiv4,
kBox);
// mark edge visited and rotate the calipers
abVisited[iBIndex] = true;
if (++iBIndex == iQuantity)
{
iBIndex = 0;
}
}
break;
case F_RIGHT:
if (abVisited[iRIndex])
{
bDone = true;
}
else
{
// compute dimensions of box with E[R] as an edge
kV = akEdge[iRIndex];
kU = kV.Perp();
UpdateBox(akHPoint[iLIndex],akHPoint[iRIndex],
akHPoint[iBIndex],akHPoint[iTIndex],kU,kV,fMinAreaDiv4,
kBox);
// mark edge visited and rotate the calipers
abVisited[iRIndex] = true;
if (++iRIndex == iQuantity)
{
iRIndex = 0;
}
}
break;
case F_TOP:
if (abVisited[iTIndex])
{
bDone = true;
}
else
{
// compute dimensions of box with E[T] as an edge
kU = -akEdge[iTIndex];
kV = -kU.Perp();
UpdateBox(akHPoint[iLIndex],akHPoint[iRIndex],
akHPoint[iBIndex],akHPoint[iTIndex],kU,kV,fMinAreaDiv4,
kBox);
// mark edge visited and rotate the calipers
abVisited[iTIndex] = true;
if (++iTIndex == iQuantity)
{
iTIndex = 0;
}
}
break;
case F_LEFT:
if (abVisited[iLIndex])
{
bDone = true;
}
else
{
// compute dimensions of box with E[L] as an edge
kV = -akEdge[iLIndex];
kU = kV.Perp();
UpdateBox(akHPoint[iLIndex],akHPoint[iRIndex],
akHPoint[iBIndex],akHPoint[iTIndex],kU,kV,fMinAreaDiv4,
kBox);
// mark edge visited and rotate the calipers
abVisited[iLIndex] = true;
if (++iLIndex == iQuantity)
{
iLIndex = 0;
}
}
break;
case F_NONE:
// polygon is a rectangle
bDone = true;
break;
}
}
WM4_DELETE[] abVisited;
WM4_DELETE[] akEdge;
if (!bIsConvexPolygon)
{
WM4_DELETE[] akHPoint;
}
return kBox;
}
//----------------------------------------------------------------------------
template <class Real>
bool InBox (const Vector2<Real>& rkPoint, const Box2<Real>& rkBox)
{
Vector2<Real> kDiff = rkPoint - rkBox.Center;
for (int i = 0; i < 2; i++)
{
Real fCoeff = kDiff.Dot(rkBox.Axis[i]);
if (Math<Real>::FAbs(fCoeff) > rkBox.Extent[i])
{
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
Box2<Real> MergeBoxes (const Box2<Real>& rkBox0, const Box2<Real>& rkBox1)
{
// construct a box that contains the input boxes
Box2<Real> kBox;
// The first guess at the box center. This value will be updated later
// after the input box vertices are projected onto axes determined by an
// average of box axes.
kBox.Center = ((Real)0.5)*(rkBox0.Center + rkBox1.Center);
// The merged box axes are the averages of the input box axes. The
// axes of the second box are negated, if necessary, so they form acute
// angles with the axes of the first box.
if (rkBox0.Axis[0].Dot(rkBox1.Axis[0]) >= (Real)0.0)
{
kBox.Axis[0] = ((Real)0.5)*(rkBox0.Axis[0] + rkBox1.Axis[0]);
kBox.Axis[0].Normalize();
}
else
{
kBox.Axis[0] = ((Real)0.5)*(rkBox0.Axis[0] - rkBox1.Axis[0]);
kBox.Axis[0].Normalize();
}
kBox.Axis[1] = -kBox.Axis[0].Perp();
// Project the input box vertices onto the merged-box axes. Each axis
// D[i] containing the current center C has a minimum projected value
// pmin[i] and a maximum projected value pmax[i]. The corresponding end
// points on the axes are C+pmin[i]*D[i] and C+pmax[i]*D[i]. The point C
// is not necessarily the midpoint for any of the intervals. The actual
// box center will be adjusted from C to a point C' that is the midpoint
// of each interval,
// C' = C + sum_{i=0}^1 0.5*(pmin[i]+pmax[i])*D[i]
// The box extents are
// e[i] = 0.5*(pmax[i]-pmin[i])
int i, j;
Real fDot;
Vector2<Real> akVertex[4], kDiff;
Vector2<Real> kMin = Vector2<Real>::ZERO;
Vector2<Real> kMax = Vector2<Real>::ZERO;
rkBox0.ComputeVertices(akVertex);
for (i = 0; i < 4; i++)
{
kDiff = akVertex[i] - kBox.Center;
for (j = 0; j < 2; j++)
{
fDot = kDiff.Dot(kBox.Axis[j]);
if (fDot > kMax[j])
{
kMax[j] = fDot;
}
else if ( fDot < kMin[j] )
{
kMin[j] = fDot;
}
}
}
rkBox1.ComputeVertices(akVertex);
for (i = 0; i < 4; i++)
{
kDiff = akVertex[i] - kBox.Center;
for (j = 0; j < 2; j++)
{
fDot = kDiff.Dot(kBox.Axis[j]);
if (fDot > kMax[j])
{
kMax[j] = fDot;
}
else if (fDot < kMin[j])
{
kMin[j] = fDot;
}
}
}
// [kMin,kMax] is the axis-aligned box in the coordinate system of the
// merged box axes. Update the current box center to be the center of
// the new box. Compute the extents based on the new center.
for (j = 0; j < 2; j++)
{
kBox.Center += kBox.Axis[j]*(((Real)0.5)*(kMax[j]+kMin[j]));
kBox.Extent[j] = ((Real)0.5)*(kMax[j]-kMin[j]);
}
return kBox;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
Box2<float> ContAlignedBox<float> (int, const Vector2<float>*);
template WM4_FOUNDATION_ITEM
Box2<float> ContOrientedBox<float> (int, const Vector2<float>*);
template WM4_FOUNDATION_ITEM
Box2<float> ContMinBox<float> (int, const Vector2<float>*, float,
Query::Type, bool);
template WM4_FOUNDATION_ITEM
bool InBox<float> (const Vector2<float>&, const Box2<float>&);
template WM4_FOUNDATION_ITEM
Box2<float> MergeBoxes<float> (const Box2<float>&, const Box2<float>&);
template WM4_FOUNDATION_ITEM
Box2<double> ContAlignedBox<double> (int, const Vector2<double>*);
template WM4_FOUNDATION_ITEM
Box2<double> ContOrientedBox<double> (int, const Vector2<double>*);
template WM4_FOUNDATION_ITEM
Box2<double> ContMinBox<double> (int, const Vector2<double>*, double,
Query::Type, bool);
template WM4_FOUNDATION_ITEM
bool InBox<double> (const Vector2<double>&, const Box2<double>&);
template WM4_FOUNDATION_ITEM
Box2<double> MergeBoxes<double> (const Box2<double>&, const Box2<double>&);
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,50 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4CONTBOX2_H
#define WM4CONTBOX2_H
#include "Wm4FoundationLIB.h"
#include "Wm4Box2.h"
#include "Wm4Query.h"
namespace Wm4
{
// Compute the smallest axis-aligned bounding box of the points.
template <class Real> WM4_FOUNDATION_ITEM
Box2<Real> ContAlignedBox (int iQuantity, const Vector2<Real>* akPoint);
// Compute an oriented bounding box of the points. The box center is the
// average of the points. The box axes are the eigenvectors of the covariance
// matrix.
template <class Real> WM4_FOUNDATION_ITEM
Box2<Real> ContOrientedBox (int iQuantity, const Vector2<Real>* akPoint);
// Compute a minimum area oriented box containing the specified points. The
// algorithm uses the rotating calipers method. If the input points represent
// a counterclockwise-ordered polygon, set bIsConvexPolygon to 'true'.
template <class Real> WM4_FOUNDATION_ITEM
Box2<Real> ContMinBox (int iQuantity, const Vector2<Real>* akPoint,
Real fEpsilon, Query::Type eQueryType, bool bIsConvexPolygon);
// Test for containment. Let X = C + y0*U0 + y1*U1 where C is the box center
// and U0 and U1 are the orthonormal axes of the box. X is in the box if
// |y_i| <= E_i for all i where E_i are the extents of the box.
template <class Real> WM4_FOUNDATION_ITEM
bool InBox (const Vector2<Real>& rkPoint, const Box2<Real>& rkBox);
// Construct an oriented box that contains two other oriented boxes. The
// result is not guaranteed to be the minimum volume box containing the
// input boxes.
template <class Real> WM4_FOUNDATION_ITEM
Box2<Real> MergeBoxes (const Box2<Real>& rkBox0, const Box2<Real>& rkBox1);
}
#endif

View File

@ -0,0 +1,532 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ContBox3.h"
#include "Wm4ApprGaussPointsFit3.h"
#include "Wm4ContBox2.h"
#include "Wm4ConvexHull3.h"
#include "Wm4EdgeKey.h"
#include "Wm4Quaternion.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
Box3<Real> ContAlignedBox (int iQuantity, const Vector3<Real>* akPoint)
{
Vector3<Real> kMin, kMax;
Vector3<Real>::ComputeExtremes(iQuantity,akPoint,kMin,kMax);
Box3<Real> kBox;
kBox.Center = ((Real)0.5)*(kMin + kMax);
kBox.Axis[0] = Vector3<Real>::UNIT_X;
kBox.Axis[1] = Vector3<Real>::UNIT_Y;
kBox.Axis[2] = Vector3<Real>::UNIT_Z;
Vector3<Real> kHalfDiagonal = ((Real)0.5)*(kMax - kMin);
for (int i = 0; i < 3; i++)
{
kBox.Extent[i] = kHalfDiagonal[i];
}
return kBox;
}
//----------------------------------------------------------------------------
template <class Real>
Box3<Real> ContOrientedBox (int iQuantity, const Vector3<Real>* akPoint)
{
Box3<Real> kBox = GaussPointsFit3<Real>(iQuantity,akPoint);
// Let C be the box center and let U0, U1, and U2 be the box axes. Each
// input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The
// following code computes min(y0), max(y0), min(y1), max(y1), min(y2),
// and max(y2). The box center is then adjusted to be
// C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 +
// 0.5*(min(y2)+max(y2))*U2
Vector3<Real> kDiff = akPoint[0] - kBox.Center;
Vector3<Real> kMin(kDiff.Dot(kBox.Axis[0]),kDiff.Dot(kBox.Axis[1]),
kDiff.Dot(kBox.Axis[2]));
Vector3<Real> kMax = kMin;
for (int i = 1; i < iQuantity; i++)
{
kDiff = akPoint[i] - kBox.Center;
for (int j = 0; j < 3; j++)
{
Real fDot = kDiff.Dot(kBox.Axis[j]);
if (fDot < kMin[j])
{
kMin[j] = fDot;
}
else if (fDot > kMax[j])
{
kMax[j] = fDot;
}
}
}
kBox.Center +=
(((Real)0.5)*(kMin[0]+kMax[0]))*kBox.Axis[0] +
(((Real)0.5)*(kMin[1]+kMax[1]))*kBox.Axis[1] +
(((Real)0.5)*(kMin[2]+kMax[2]))*kBox.Axis[2];
kBox.Extent[0] = ((Real)0.5)*(kMax[0] - kMin[0]);
kBox.Extent[1] = ((Real)0.5)*(kMax[1] - kMin[1]);
kBox.Extent[2] = ((Real)0.5)*(kMax[2] - kMin[2]);
return kBox;
}
//----------------------------------------------------------------------------
template <class Real>
Box3<Real> ContMinBox (int iQuantity, const Vector3<Real>* akPoint,
Real fEpsilon, Query::Type eQueryType)
{
Box3<Real> kBox;
// Get the convex hull of the points.
ConvexHull3<Real> kHull(iQuantity,(Vector3<Real>*)akPoint,fEpsilon,false,
eQueryType);
int iHDim = kHull.GetDimension();
int iHQuantity;
const int* aiHIndex;
if (iHDim == 0)
{
kBox.Center = akPoint[0];
kBox.Axis[0] = Vector3<Real>::UNIT_X;
kBox.Axis[1] = Vector3<Real>::UNIT_Y;
kBox.Axis[2] = Vector3<Real>::UNIT_Z;
kBox.Extent[0] = (Real)0.0;
kBox.Extent[1] = (Real)0.0;
kBox.Extent[2] = (Real)0.0;
return kBox;
}
if (iHDim == 1)
{
ConvexHull1<Real>* pkHull1 = kHull.GetConvexHull1();
aiHIndex = pkHull1->GetIndices();
kBox.Center = ((Real)0.5)*(akPoint[aiHIndex[0]]+akPoint[aiHIndex[1]]);
Vector3<Real> kDiff = akPoint[aiHIndex[1]] - akPoint[aiHIndex[0]];
kBox.Extent[0] = ((Real)0.5)*kDiff.Normalize();
kBox.Extent[1] = (Real)0.0;
kBox.Extent[2] = (Real)0.0;
kBox.Axis[0] = kDiff;
Vector3<Real>::GenerateComplementBasis(kBox.Axis[1],kBox.Axis[2],
kBox.Axis[0]);
WM4_DELETE pkHull1;
return kBox;
}
int i, j;
Vector3<Real> kOrigin, kDiff, kU, kV, kW;
Vector2<Real>* akPoint2;
Box2<Real> kBox2;
if (iHDim == 2)
{
// When ConvexHull3 reports that the point set is 2-dimensional, the
// caller is responsible for projecting the points onto a plane and
// calling ConvexHull2. ConvexHull3 does provide information about
// the plane of the points. In this application, we need only
// project the input points onto that plane and call ContMinBox in
// two dimensions.
// Get a coordinate system relative to the plane of the points.
kOrigin = kHull.GetPlaneOrigin();
kW = kHull.GetPlaneDirection(0).Cross(kHull.GetPlaneDirection(1));
Vector3<Real>::GenerateComplementBasis(kU,kV,kW);
// Project the input points onto the plane.
akPoint2 = WM4_NEW Vector2<Real>[iQuantity];
for (i = 0; i < iQuantity; i++)
{
kDiff = akPoint[i] - kOrigin;
akPoint2[i].X() = kU.Dot(kDiff);
akPoint2[i].Y() = kV.Dot(kDiff);
}
// Compute the minimum area box in 2D.
kBox2 = ContMinBox<Real>(iQuantity,akPoint2,fEpsilon,eQueryType,
false);
WM4_DELETE[] akPoint2;
// Lift the values into 3D.
kBox.Center = kOrigin + kBox2.Center.X()*kU + kBox2.Center.Y()*kV;
kBox.Axis[0] = kBox2.Axis[0].X()*kU + kBox2.Axis[0].Y()*kV;
kBox.Axis[1] = kBox2.Axis[1].X()*kU + kBox2.Axis[1].Y()*kV;
kBox.Axis[2] = kW;
kBox.Extent[0] = kBox2.Extent[0];
kBox.Extent[1] = kBox2.Extent[1];
kBox.Extent[2] = (Real)0.0;
return kBox;
}
iHQuantity = kHull.GetSimplexQuantity();
aiHIndex = kHull.GetIndices();
Real fVolume, fMinVolume = Math<Real>::MAX_REAL;
// Create the unique set of hull vertices to minimize the time spent
// projecting vertices onto planes of the hull faces.
std::set<int> kUniqueIndices;
for (i = 0; i < 3*iHQuantity; i++)
{
kUniqueIndices.insert(aiHIndex[i]);
}
// Use the rotating calipers method on the projection of the hull onto
// the plane of each face. Also project the hull onto the normal line
// of each face. The minimum area box in the plane and the height on
// the line produce a containing box. If its volume is smaller than the
// current volume, this box is the new candidate for the minimum volume
// box. The unique edges are accumulated into a set for use by a later
// step in the algorithm.
const int* piIndex = aiHIndex;
Real fHeight, fMinHeight, fMaxHeight;
std::set<EdgeKey> kEdges;
akPoint2 = WM4_NEW Vector2<Real>[kUniqueIndices.size()];
for (i = 0; i < iHQuantity; i++)
{
// get triangle
int iV0 = *piIndex++;
int iV1 = *piIndex++;
int iV2 = *piIndex++;
// save the edges for later use
kEdges.insert(EdgeKey(iV0,iV1));
kEdges.insert(EdgeKey(iV1,iV2));
kEdges.insert(EdgeKey(iV2,iV0));
// get 3D coordinate system relative to plane of triangle
kOrigin = (akPoint[iV0] + akPoint[iV1] + akPoint[iV2])/(Real)3.0;
Vector3<Real> kEdge1 = akPoint[iV1] - akPoint[iV0];
Vector3<Real> kEdge2 = akPoint[iV2] - akPoint[iV0];
kW = kEdge2.UnitCross(kEdge1); // inner-pointing normal
if (kW == Vector3<Real>::ZERO)
{
// The triangle is needle-like, so skip it.
continue;
}
Vector3<Real>::GenerateComplementBasis(kU,kV,kW);
// Project points onto plane of triangle, onto normal line of plane.
// TO DO. In theory, minHeight should be zero since W points to the
// interior of the hull. However, the snap rounding used in the 3D
// convex hull finder involves loss of precision, which in turn can
// cause a hull facet to have the wrong ordering (clockwise instead
// of counterclockwise when viewed from outside the hull). The
// height calculations here trap that problem (the incorrectly ordered
// face will not affect the minimum volume box calculations).
fMinHeight = (Real)0.0;
fMaxHeight = (Real)0.0;
j = 0;
std::set<int>::const_iterator pkUI = kUniqueIndices.begin();
while (pkUI != kUniqueIndices.end())
{
int index = *pkUI++;
kDiff = akPoint[index] - kOrigin;
akPoint2[j].X() = kU.Dot(kDiff);
akPoint2[j].Y() = kV.Dot(kDiff);
fHeight = kW.Dot(kDiff);
if (fHeight > fMaxHeight)
{
fMaxHeight = fHeight;
}
else if (fHeight < fMinHeight)
{
fMinHeight = fHeight;
}
j++;
}
if (-fMinHeight > fMaxHeight)
{
fMaxHeight = -fMinHeight;
}
// compute minimum area box in 2D
kBox2 = ContMinBox<Real>((int)kUniqueIndices.size(),akPoint2,fEpsilon,
eQueryType,false);
// update current minimum-volume box (if necessary)
fVolume = fMaxHeight*kBox2.Extent[0]*kBox2.Extent[1];
if (fVolume < fMinVolume)
{
fMinVolume = fVolume;
// lift the values into 3D
kBox.Extent[0] = kBox2.Extent[0];
kBox.Extent[1] = kBox2.Extent[1];
kBox.Extent[2] = ((Real)0.5)*fMaxHeight;
kBox.Axis[0] = kBox2.Axis[0].X()*kU + kBox2.Axis[0].Y()*kV;
kBox.Axis[1] = kBox2.Axis[1].X()*kU + kBox2.Axis[1].Y()*kV;
kBox.Axis[2] = kW;
kBox.Center = kOrigin + kBox2.Center.X()*kU + kBox2.Center.Y()*kV
+ kBox.Extent[2]*kW;
}
}
// The minimum-volume box can also be supported by three mutually
// orthogonal edges of the convex hull. For each triple of orthogonal
// edges, compute the minimum-volume box for that coordinate frame by
// projecting the points onto the axes of the frame.
std::set<EdgeKey>::const_iterator pkE2;
for (pkE2 = kEdges.begin(); pkE2 != kEdges.end(); pkE2++)
{
kW = akPoint[pkE2->V[1]] - akPoint[pkE2->V[0]];
kW.Normalize();
std::set<EdgeKey>::const_iterator pkE1 = pkE2;
for (++pkE1; pkE1 != kEdges.end(); pkE1++)
{
kV = akPoint[pkE1->V[1]] - akPoint[pkE1->V[0]];
kV.Normalize();
Real fDot = kV.Dot(kW);
if (Math<Real>::FAbs(fDot) > Math<Real>::ZERO_TOLERANCE)
{
continue;
}
std::set<EdgeKey>::const_iterator pkE0 = pkE1;
for (++pkE0; pkE0 != kEdges.end(); pkE0++)
{
kU = akPoint[pkE0->V[1]] - akPoint[pkE0->V[0]];
kU.Normalize();
fDot = kU.Dot(kV);
if (Math<Real>::FAbs(fDot) > Math<Real>::ZERO_TOLERANCE)
{
continue;
}
fDot = kU.Dot(kW);
if (Math<Real>::FAbs(fDot) > Math<Real>::ZERO_TOLERANCE)
{
continue;
}
// The three edges are mutually orthogonal. Project the
// hull points onto the lines containing the edges. Use
// hull point zero as the origin.
Real fUMin = (Real)0.0, fUMax = (Real)0.0;
Real fVMin = (Real)0.0, fVMax = (Real)0.0;
Real fWMin = (Real)0.0, fWMax = (Real)0.0;
kOrigin = akPoint[aiHIndex[0]];
std::set<int>::const_iterator pkUI = kUniqueIndices.begin();
while (pkUI != kUniqueIndices.end())
{
int index = *pkUI++;
kDiff = akPoint[index] - kOrigin;
Real fU = kU.Dot(kDiff);
if (fU < fUMin)
{
fUMin = fU;
}
else if (fU > fUMax)
{
fUMax = fU;
}
Real fV = kV.Dot(kDiff);
if (fV < fVMin)
{
fVMin = fV;
}
else if (fV > fVMax)
{
fVMax = fV;
}
Real fW = kW.Dot(kDiff);
if (fW < fWMin)
{
fWMin = fW;
}
else if (fW > fWMax)
{
fWMax = fW;
}
}
Real fUExtent = ((Real)0.5)*(fUMax - fUMin);
Real fVExtent = ((Real)0.5)*(fVMax - fVMin);
Real fWExtent = ((Real)0.5)*(fWMax - fWMin);
// update current minimum-volume box (if necessary)
fVolume = fUExtent*fVExtent*fWExtent;
if (fVolume < fMinVolume)
{
fMinVolume = fVolume;
kBox.Extent[0] = fUExtent;
kBox.Extent[1] = fVExtent;
kBox.Extent[2] = fWExtent;
kBox.Axis[0] = kU;
kBox.Axis[1] = kV;
kBox.Axis[2] = kW;
kBox.Center = kOrigin +
((Real)0.5)*(fUMin+fUMax)*kU +
((Real)0.5)*(fVMin+fVMax)*kV +
((Real)0.5)*(fWMin+fWMax)*kW;
}
}
}
}
WM4_DELETE[] akPoint2;
return kBox;
}
//----------------------------------------------------------------------------
template <class Real>
bool InBox (const Vector3<Real>& rkPoint, const Box3<Real>& rkBox)
{
Vector3<Real> kDiff = rkPoint - rkBox.Center;
for (int i = 0; i < 3; i++)
{
Real fCoeff = kDiff.Dot(rkBox.Axis[i]);
if (Math<Real>::FAbs(fCoeff) > rkBox.Extent[i])
{
return false;
}
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
Box3<Real> MergeBoxes (const Box3<Real>& rkBox0, const Box3<Real>& rkBox1)
{
// construct a box that contains the input boxes
Box3<Real> kBox;
// The first guess at the box center. This value will be updated later
// after the input box vertices are projected onto axes determined by an
// average of box axes.
kBox.Center = ((Real)0.5)*(rkBox0.Center + rkBox1.Center);
// A box's axes, when viewed as the columns of a matrix, form a rotation
// matrix. The input box axes are converted to quaternions. The average
// quaternion is computed, then normalized to unit length. The result is
// the slerp of the two input quaternions with t-value of 1/2. The result
// is converted back to a rotation matrix and its columns are selected as
// the merged box axes.
Quaternion<Real> kQ0, kQ1;
kQ0.FromRotationMatrix(rkBox0.Axis);
kQ1.FromRotationMatrix(rkBox1.Axis);
if (kQ0.Dot(kQ1) < (Real)0.0)
{
kQ1 = -kQ1;
}
Quaternion<Real> kQ = kQ0 + kQ1;
Real fInvLength = Math<Real>::InvSqrt(kQ.Dot(kQ));
kQ = fInvLength*kQ;
kQ.ToRotationMatrix(kBox.Axis);
// Project the input box vertices onto the merged-box axes. Each axis
// D[i] containing the current center C has a minimum projected value
// pmin[i] and a maximum projected value pmax[i]. The corresponding end
// points on the axes are C+pmin[i]*D[i] and C+pmax[i]*D[i]. The point C
// is not necessarily the midpoint for any of the intervals. The actual
// box center will be adjusted from C to a point C' that is the midpoint
// of each interval,
// C' = C + sum_{i=0}^2 0.5*(pmin[i]+pmax[i])*D[i]
// The box extents are
// e[i] = 0.5*(pmax[i]-pmin[i])
int i, j;
Real fDot;
Vector3<Real> akVertex[8], kDiff;
Vector3<Real> kMin = Vector3<Real>::ZERO;
Vector3<Real> kMax = Vector3<Real>::ZERO;
rkBox0.ComputeVertices(akVertex);
for (i = 0; i < 8; i++)
{
kDiff = akVertex[i] - kBox.Center;
for (j = 0; j < 3; j++)
{
fDot = kDiff.Dot(kBox.Axis[j]);
if (fDot > kMax[j])
{
kMax[j] = fDot;
}
else if (fDot < kMin[j])
{
kMin[j] = fDot;
}
}
}
rkBox1.ComputeVertices(akVertex);
for (i = 0; i < 8; i++)
{
kDiff = akVertex[i] - kBox.Center;
for (j = 0; j < 3; j++)
{
fDot = kDiff.Dot(kBox.Axis[j]);
if (fDot > kMax[j])
{
kMax[j] = fDot;
}
else if (fDot < kMin[j])
{
kMin[j] = fDot;
}
}
}
// [kMin,kMax] is the axis-aligned box in the coordinate system of the
// merged box axes. Update the current box center to be the center of
// the new box. Compute the extents based on the new center.
for (j = 0; j < 3; j++)
{
kBox.Center += (((Real)0.5)*(kMax[j]+kMin[j]))*kBox.Axis[j];
kBox.Extent[j] = ((Real)0.5)*(kMax[j]-kMin[j]);
}
return kBox;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
Box3<float> ContAlignedBox<float> (int, const Vector3<float>*);
template WM4_FOUNDATION_ITEM
Box3<float> ContOrientedBox<float> (int, const Vector3<float>*);
template WM4_FOUNDATION_ITEM
Box3<float> ContMinBox<float> (int, const Vector3<float>*, float,
Query::Type);
template WM4_FOUNDATION_ITEM
bool InBox<float> (const Vector3<float>&, const Box3<float>&);
template WM4_FOUNDATION_ITEM
Box3<float> MergeBoxes<float> (const Box3<float>&, const Box3<float>&);
template WM4_FOUNDATION_ITEM
Box3<double> ContAlignedBox<double> (int, const Vector3<double>*);
template WM4_FOUNDATION_ITEM
Box3<double> ContOrientedBox<double> (int, const Vector3<double>*);
template WM4_FOUNDATION_ITEM
Box3<double> ContMinBox<double> (int, const Vector3<double>*, double,
Query::Type);
template WM4_FOUNDATION_ITEM
bool InBox<double> (const Vector3<double>&, const Box3<double>&);
template WM4_FOUNDATION_ITEM
Box3<double> MergeBoxes<double> (const Box3<double>&, const Box3<double>&);
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,48 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4CONTBOX3_H
#define WM4CONTBOX3_H
#include "Wm4FoundationLIB.h"
#include "Wm4Box3.h"
#include "Wm4Query.h"
namespace Wm4
{
// Compute the smallest axis-aligned bounding box of the points.
template <class Real> WM4_FOUNDATION_ITEM
Box3<Real> ContAlignedBox (int iQuantity, const Vector3<Real>* akPoint);
// Compute an oriented bounding box of the points. The box center is the
// average of the points. The box axes are the eigenvectors of the covariance
// matrix.
template <class Real> WM4_FOUNDATION_ITEM
Box3<Real> ContOrientedBox (int iQuantity, const Vector3<Real>* akPoint);
// Compute a minimum volume oriented box containing the specified points.
template <class Real> WM4_FOUNDATION_ITEM
Box3<Real> ContMinBox (int iQuantity, const Vector3<Real>* akPoint,
Real fEpsilon, Query::Type eQueryType);
// Test for containment. Let X = C + y0*U0 + y1*U1 + y2*U2 where C is the
// box center and U0, U1, U2 are the orthonormal axes of the box. X is in
// the box if |y_i| <= E_i for all i where E_i are the extents of the box.
template <class Real> WM4_FOUNDATION_ITEM
bool InBox (const Vector3<Real>& rkPoint, const Box3<Real>& rkBox);
// Construct an oriented box that contains two other oriented boxes. The
// result is not guaranteed to be the minimum volume box containing the
// input boxes.
template <class Real> WM4_FOUNDATION_ITEM
Box3<Real> MergeBoxes (const Box3<Real>& rkBox0, const Box3<Real>& rkBox1);
}
#endif

View File

@ -0,0 +1,146 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ConvexHull.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
ConvexHull<Real>::ConvexHull (int iVertexQuantity, Real fEpsilon, bool bOwner,
Query::Type eQueryType)
{
assert(iVertexQuantity > 0 && fEpsilon >= (Real)0.0);
m_eQueryType = eQueryType;
m_iVertexQuantity = iVertexQuantity;
m_iDimension = 0;
m_iSimplexQuantity = 0;
m_aiIndex = 0;
m_fEpsilon = fEpsilon;
m_bOwner = bOwner;
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull<Real>::~ConvexHull ()
{
WM4_DELETE[] m_aiIndex;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull<Real>::GetQueryType () const
{
return m_eQueryType;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull<Real>::GetVertexQuantity () const
{
return m_iVertexQuantity;
}
//----------------------------------------------------------------------------
template <class Real>
Real ConvexHull<Real>::GetEpsilon () const
{
return m_fEpsilon;
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull<Real>::GetOwner () const
{
return m_bOwner;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull<Real>::GetDimension () const
{
return m_iDimension;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull<Real>::GetSimplexQuantity () const
{
return m_iSimplexQuantity;
}
//----------------------------------------------------------------------------
template <class Real>
const int* ConvexHull<Real>::GetIndices () const
{
return m_aiIndex;
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull<Real>::Load (FILE* pkIFile)
{
WM4_DELETE[] m_aiIndex;
// fixed-size members
int iQueryType;
System::Read4le(pkIFile,1,&iQueryType);
m_eQueryType = (Query::Type)iQueryType;
System::Read4le(pkIFile,1,&m_iVertexQuantity);
System::Read4le(pkIFile,1,&m_iDimension);
System::Read4le(pkIFile,1,&m_iSimplexQuantity);
System::Read4le(pkIFile,1,&m_fEpsilon);
// variable-size members
int iIQuantity;
System::Read4le(pkIFile,1,&iIQuantity);
if (1 <= m_iDimension && m_iDimension <= 3)
{
assert(iIQuantity == (m_iDimension+1)*m_iSimplexQuantity);
m_aiIndex = WM4_NEW int[iIQuantity];
System::Read4le(pkIFile,iIQuantity,m_aiIndex);
return true;
}
m_aiIndex = 0;
return m_iDimension == 0;
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull<Real>::Save (FILE* pkOFile) const
{
// fixed-size members
int iQueryType = (int)m_eQueryType;
System::Write4le(pkOFile,1,&iQueryType);
System::Write4le(pkOFile,1,&m_iVertexQuantity);
System::Write4le(pkOFile,1,&m_iDimension);
System::Write4le(pkOFile,1,&m_iSimplexQuantity);
System::Write4le(pkOFile,1,&m_fEpsilon);
// The member m_bOwner is not streamed because on a Load call, this
// object will allocate the vertices and own this memory.
// variable-size members
int iIQuantity;
if (1 <= m_iDimension && m_iDimension <= 3)
{
iIQuantity = (m_iDimension+1)*m_iSimplexQuantity;
System::Write4le(pkOFile,1,&iIQuantity);
System::Write4le(pkOFile,iIQuantity,m_aiIndex);
return true;
}
iIQuantity = 0;
System::Write4le(pkOFile,1,&iIQuantity);
return m_iDimension == 0;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
class ConvexHull<float>;
template WM4_FOUNDATION_ITEM
class ConvexHull<double>;
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,100 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4CONVEXHULL_H
#define WM4CONVEXHULL_H
#include "Wm4FoundationLIB.h"
#include "Wm4System.h"
#include "Wm4Query.h"
namespace Wm4
{
template <class Real>
class WM4_FOUNDATION_ITEM ConvexHull
{
public:
// Abstract base class.
virtual ~ConvexHull ();
// Member accessors. For notational purposes in this class documentation,
// The number of vertices is VQ and the vertex array is V.
int GetQueryType () const;
int GetVertexQuantity () const;
Real GetEpsilon () const;
bool GetOwner () const;
// The dimension of the result, call it d. If n is the dimension of the
// space of the input points, then 0 <= d <= n.
int GetDimension () const;
// The interpretations of the return values of these functions depends on
// the dimension. Generally, SQ = GetSimplexQuantity() is the number of
// simplices in the mesh. The array I is returned by GetIndices().
int GetSimplexQuantity () const;
const int* GetIndices () const;
// Dimension d = 0.
// SQ = 1
// I = null (use index zero for vertices)
// Dimension d = 1.
// SQ = 2
// I = array of two indices
// The segment has end points
// vertex[0] = V[I[2*i+0]]
// vertex[1] = V[I[2*i+1]]
// Dimension d = 2.
// SQ = number of convex polygon edges
// I = array of into V that represent the convex polygon edges
// (SQ total elements)
// The i-th edge has vertices
// vertex[0] = V[I[2*i+0]]
// vertex[1] = V[I[2*i+1]]
// Dimension d = 3.
// SQ = number of convex polyhedron triangular faces
// I = array of 3-tuples of indices into V that represent the
// triangles (3*SQ total elements)
// The i-th face has vertices
// vertex[0] = V[I[3*i+0]]
// vertex[1] = V[I[3*i+1]]
// vertex[2] = V[I[3*i+2]]
protected:
// Abstract base class. The number of vertices to be processed is
// iVQuantity. The value of fEpsilon is a tolerance used for determining
// the intrinsic dimension of the input set of vertices. Ownership of the
// input points to the constructors for the derived classes may be
// transferred to this class. If you want the input vertices to be
// deleted by this class, set bOwner to 'true'; otherwise, you own the
// array and must delete it yourself.
ConvexHull (int iVertexQuantity, Real fEpsilon, bool bOwner,
Query::Type eQueryType);
// Support for streaming to/from disk.
bool Load (FILE* pkIFile);
bool Save (FILE* pkOFile) const;
Query::Type m_eQueryType;
int m_iVertexQuantity;
int m_iDimension;
int m_iSimplexQuantity;
int* m_aiIndex;
Real m_fEpsilon;
bool m_bOwner;
};
typedef ConvexHull<float> ConvexHullf;
typedef ConvexHull<double> ConvexHulld;
}
#endif

View File

@ -0,0 +1,138 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ConvexHull1.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
ConvexHull1<Real>::ConvexHull1 (int iVertexQuantity, Real* afVertex,
Real fEpsilon, bool bOwner, Query::Type eQueryType)
:
ConvexHull<Real>(iVertexQuantity,fEpsilon,bOwner,eQueryType)
{
assert(afVertex);
m_afVertex = afVertex;
std::vector<SortedVertex> kArray(m_iVertexQuantity);
int i;
for (i = 0; i < m_iVertexQuantity; i++)
{
kArray[i].Value = m_afVertex[i];
kArray[i].Index = i;
}
std::sort(kArray.begin(),kArray.end());
Real fRange = kArray[m_iVertexQuantity-1].Value - kArray[0].Value;
if (fRange >= m_fEpsilon)
{
m_iDimension = 1;
m_iSimplexQuantity = 2;
m_aiIndex = WM4_NEW int[2];
m_aiIndex[0] = kArray[0].Index;
m_aiIndex[1] = kArray[m_iVertexQuantity-1].Index;
}
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull1<Real>::~ConvexHull1 ()
{
if (m_bOwner)
{
WM4_DELETE[] m_afVertex;
}
}
//----------------------------------------------------------------------------
template <class Real>
const Real* ConvexHull1<Real>::GetVertices () const
{
return m_afVertex;
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull1<Real>::ConvexHull1 (const char* acFilename)
:
ConvexHull<Real>(0,(Real)0.0,false,Query::QT_REAL)
{
m_afVertex = 0;
bool bLoaded = Load(acFilename);
assert(bLoaded);
(void)bLoaded; // avoid warning in Release build
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull1<Real>::Load (const char* acFilename)
{
FILE* pkIFile = System::Fopen(acFilename,"rb");
if (!pkIFile)
{
return false;
}
ConvexHull<Real>::Load(pkIFile);
if (m_bOwner)
{
WM4_DELETE[] m_afVertex;
}
m_bOwner = true;
m_afVertex = WM4_NEW Real[m_iVertexQuantity];
size_t uiSize = sizeof(Real);
if (uiSize == 4)
{
System::Read4le(pkIFile,m_iVertexQuantity,m_afVertex);
}
else // uiSize == 8
{
System::Read8le(pkIFile,m_iVertexQuantity,m_afVertex);
}
System::Fclose(pkIFile);
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull1<Real>::Save (const char* acFilename) const
{
FILE* pkOFile = System::Fopen(acFilename,"wb");
if (!pkOFile)
{
return false;
}
ConvexHull<Real>::Save(pkOFile);
size_t uiSize = sizeof(Real);
if (uiSize == 4)
{
System::Write4le(pkOFile,m_iVertexQuantity,m_afVertex);
}
else // uiSize == 8
{
System::Write8le(pkOFile,m_iVertexQuantity,m_afVertex);
}
System::Fclose(pkOFile);
return true;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
class ConvexHull1<float>;
template WM4_FOUNDATION_ITEM
class ConvexHull1<double>;
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,73 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4CONVEXHULL1_H
#define WM4CONVEXHULL1_H
// A fancy class to compute the minimum and maximum of a collection of
// real-valued numbers, but this provides some convenience for ConvexHull2 and
// ConvexHull3 when the input point set has intrinsic dimension smaller than
// the containing space. The interface of ConvexHull1 is also the model for
// those of ConvexHull2 and ConvexHull3.
#include "Wm4FoundationLIB.h"
#include "Wm4ConvexHull.h"
namespace Wm4
{
template <class Real>
class WM4_FOUNDATION_ITEM ConvexHull1 : public ConvexHull<Real>
{
public:
// The input to the constructor is the array of vertices you want to sort.
// If you want ConvexHull1 to delete the array during destruction, set
// bOwner to 'true'. Otherwise, you own the array and must delete it
// yourself. TO DO: The computation type is currently ignored by this
// class. Add support for the various types later.
ConvexHull1 (int iVertexQuantity, Real* afVertex, Real fEpsilon,
bool bOwner, Query::Type eQueryType);
virtual ~ConvexHull1 ();
// The input vertex array.
const Real* GetVertices () const;
// Support for streaming to/from disk.
ConvexHull1 (const char* acFilename);
bool Load (const char* acFilename);
bool Save (const char* acFilename) const;
private:
using ConvexHull<Real>::m_iVertexQuantity;
using ConvexHull<Real>::m_iDimension;
using ConvexHull<Real>::m_iSimplexQuantity;
using ConvexHull<Real>::m_aiIndex;
using ConvexHull<Real>::m_fEpsilon;
using ConvexHull<Real>::m_bOwner;
Real* m_afVertex;
class WM4_FOUNDATION_ITEM SortedVertex
{
public:
Real Value;
int Index;
bool operator< (const SortedVertex& rkProj) const
{
return Value < rkProj.Value;
}
};
};
typedef ConvexHull1<float> ConvexHull1f;
typedef ConvexHull1<double> ConvexHull1d;
}
#endif

View File

@ -0,0 +1,488 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ConvexHull2.h"
#include "Wm4Mapper2.h"
#include "Wm4Query2Filtered.h"
#include "Wm4Query2Int64.h"
#include "Wm4Query2TInteger.h"
#include "Wm4Query2TRational.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
ConvexHull2<Real>::ConvexHull2 (int iVertexQuantity, Vector2<Real>* akVertex,
Real fEpsilon, bool bOwner, Query::Type eQueryType)
:
ConvexHull<Real>(iVertexQuantity,fEpsilon,bOwner,eQueryType),
m_kLineOrigin(Vector2<Real>::ZERO),
m_kLineDirection(Vector2<Real>::ZERO)
{
assert(akVertex);
m_akVertex = akVertex;
m_akSVertex = 0;
m_pkQuery = 0;
Mapper2<Real> kMapper(m_iVertexQuantity,m_akVertex,m_fEpsilon);
if (kMapper.GetDimension() == 0)
{
// The values of m_iDimension, m_aiIndex, and m_aiAdjacent were
// already initialized by the ConvexHull base class.
return;
}
if (kMapper.GetDimension() == 1)
{
// The set is (nearly) collinear. The caller is responsible for
// creating a ConvexHull1 object.
m_iDimension = 1;
m_kLineOrigin = kMapper.GetOrigin();
m_kLineDirection = kMapper.GetDirection(0);
return;
}
m_iDimension = 2;
int i0 = kMapper.GetExtremeIndex(0);
int i1 = kMapper.GetExtremeIndex(1);
int i2 = kMapper.GetExtremeIndex(2);
m_akSVertex = WM4_NEW Vector2<Real>[m_iVertexQuantity];
int i;
if (eQueryType != Query::QT_RATIONAL && eQueryType != Query::QT_FILTERED)
{
// Transform the vertices to the square [0,1]^2.
Vector2<Real> kMin = kMapper.GetMin();
Real fScale = ((Real)1.0)/kMapper.GetMaxRange();
for (i = 0; i < m_iVertexQuantity; i++)
{
m_akSVertex[i] = (m_akVertex[i] - kMin)*fScale;
}
Real fExpand;
if (eQueryType == Query::QT_INT64)
{
// Scale the vertices to the square [0,2^{20}]^2 to allow use of
// 64-bit integers.
fExpand = (Real)(1 << 20);
m_pkQuery = WM4_NEW Query2Int64<Real>(m_iVertexQuantity,
m_akSVertex);
}
else if (eQueryType == Query::QT_INTEGER)
{
// Scale the vertices to the square [0,2^{24}]^2 to allow use of
// TInteger.
fExpand = (Real)(1 << 24);
m_pkQuery = WM4_NEW Query2TInteger<Real>(m_iVertexQuantity,
m_akSVertex);
}
else // eQueryType == Query::QT_REAL
{
// No scaling for floating point.
fExpand = (Real)1.0;
m_pkQuery = WM4_NEW Query2<Real>(m_iVertexQuantity,m_akSVertex);
}
for (i = 0; i < m_iVertexQuantity; i++)
{
m_akSVertex[i] *= fExpand;
}
}
else
{
// No transformation needed for exact rational arithmetic or filtered
// predicates.
size_t uiSize = m_iVertexQuantity*sizeof(Vector2<Real>);
System::Memcpy(m_akSVertex,uiSize,m_akVertex,uiSize);
if (eQueryType == Query::QT_RATIONAL)
{
m_pkQuery = WM4_NEW Query2TRational<Real>(m_iVertexQuantity,
m_akSVertex);
}
else // eQueryType == Query::QT_FILTERED
{
m_pkQuery = WM4_NEW Query2Filtered<Real>(m_iVertexQuantity,
m_akSVertex,m_fEpsilon);
}
}
Edge* pkE0;
Edge* pkE1;
Edge* pkE2;
if (kMapper.GetExtremeCCW())
{
pkE0 = WM4_NEW Edge(i0,i1);
pkE1 = WM4_NEW Edge(i1,i2);
pkE2 = WM4_NEW Edge(i2,i0);
}
else
{
pkE0 = WM4_NEW Edge(i0,i2);
pkE1 = WM4_NEW Edge(i2,i1);
pkE2 = WM4_NEW Edge(i1,i0);
}
pkE0->Insert(pkE2,pkE1);
pkE1->Insert(pkE0,pkE2);
pkE2->Insert(pkE1,pkE0);
Edge* pkHull = pkE0;
for (i = 0; i < m_iVertexQuantity; i++)
{
if (!Update(pkHull,i))
{
pkHull->DeleteAll();
return;
}
}
pkHull->GetIndices(m_iSimplexQuantity,m_aiIndex);
pkHull->DeleteAll();
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull2<Real>::~ConvexHull2 ()
{
if (m_bOwner)
{
WM4_DELETE[] m_akVertex;
}
WM4_DELETE[] m_akSVertex;
WM4_DELETE m_pkQuery;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector2<Real>& ConvexHull2<Real>::GetLineOrigin () const
{
return m_kLineOrigin;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector2<Real>& ConvexHull2<Real>::GetLineDirection () const
{
return m_kLineDirection;
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull1<Real>* ConvexHull2<Real>::GetConvexHull1 () const
{
assert(m_iDimension == 1);
if (m_iDimension != 1)
{
return 0;
}
Real* afProjection = WM4_NEW Real[m_iVertexQuantity];
for (int i = 0; i < m_iVertexQuantity; i++)
{
Vector2<Real> kDiff = m_akVertex[i] - m_kLineOrigin;
afProjection[i] = m_kLineDirection.Dot(kDiff);
}
return WM4_NEW ConvexHull1<Real>(m_iVertexQuantity,afProjection,
m_fEpsilon,true,m_eQueryType);
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull2<Real>::Update (Edge*& rpkHull, int i)
{
// Locate an edge visible to the input point (if possible).
Edge* pkVisible = 0;
Edge* pkCurrent = rpkHull;
do
{
if (pkCurrent->GetSign(i,m_pkQuery) > 0)
{
pkVisible = pkCurrent;
break;
}
pkCurrent = pkCurrent->A[1];
}
while (pkCurrent != rpkHull);
if (!pkVisible)
{
// The point is inside the current hull; nothing to do.
return true;
}
// Remove the visible edges.
Edge* pkAdj0 = pkVisible->A[0];
assert(pkAdj0);
if (!pkAdj0)
{
return false;
}
Edge* pkAdj1 = pkVisible->A[1];
assert(pkAdj1);
if (!pkAdj1)
{
return false;
}
pkVisible->DeleteSelf();
while (pkAdj0->GetSign(i,m_pkQuery) > 0)
{
rpkHull = pkAdj0;
pkAdj0 = pkAdj0->A[0];
assert(pkAdj0);
if (!pkAdj0)
{
return false;
}
pkAdj0->A[1]->DeleteSelf();
}
while (pkAdj1->GetSign(i,m_pkQuery) > 0)
{
rpkHull = pkAdj1;
pkAdj1 = pkAdj1->A[1];
assert(pkAdj1);
if (!pkAdj1)
{
return false;
}
pkAdj1->A[0]->DeleteSelf();
}
// Insert the new edges formed by the input point and the end points of
// the polyline of invisible edges.
Edge* pkEdge0 = WM4_NEW Edge(pkAdj0->V[1],i);
Edge* pkEdge1 = WM4_NEW Edge(i,pkAdj1->V[0]);
pkEdge0->Insert(pkAdj0,pkEdge1);
pkEdge1->Insert(pkEdge0,pkAdj1);
rpkHull = pkEdge0;
return true;
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull2<Real>::ConvexHull2 (const char* acFilename)
:
ConvexHull<Real>(0,(Real)0.0,false,Query::QT_REAL)
{
m_akVertex = 0;
m_akSVertex = 0;
m_pkQuery = 0;
bool bLoaded = Load(acFilename);
assert(bLoaded);
(void)bLoaded; // avoid warning in Release build
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull2<Real>::Load (const char* acFilename)
{
FILE* pkIFile = System::Fopen(acFilename,"rb");
if (!pkIFile)
{
return false;
}
ConvexHull<Real>::Load(pkIFile);
WM4_DELETE m_pkQuery;
WM4_DELETE[] m_akSVertex;
if (m_bOwner)
{
WM4_DELETE[] m_akVertex;
}
m_bOwner = true;
m_akVertex = WM4_NEW Vector2<Real>[m_iVertexQuantity];
m_akSVertex = WM4_NEW Vector2<Real>[m_iVertexQuantity];
size_t uiSize = sizeof(Real);
int iVQ = 2*m_iVertexQuantity;
if (uiSize == 4)
{
System::Read4le(pkIFile,iVQ,m_akVertex);
System::Read4le(pkIFile,iVQ,m_akSVertex);
System::Read4le(pkIFile,2,(Real*)m_kLineOrigin);
System::Read4le(pkIFile,2,(Real*)m_kLineDirection);
}
else // iSize == 8
{
System::Read8le(pkIFile,iVQ,m_akVertex);
System::Read8le(pkIFile,iVQ,m_akSVertex);
System::Read8le(pkIFile,2,(Real*)m_kLineOrigin);
System::Read8le(pkIFile,2,(Real*)m_kLineDirection);
}
System::Fclose(pkIFile);
switch (m_eQueryType)
{
case Query::QT_INT64:
m_pkQuery = WM4_NEW Query2Int64<Real>(m_iVertexQuantity,m_akSVertex);
break;
case Query::QT_INTEGER:
m_pkQuery = WM4_NEW Query2TInteger<Real>(m_iVertexQuantity,
m_akSVertex);
break;
case Query::QT_RATIONAL:
m_pkQuery = WM4_NEW Query2TRational<Real>(m_iVertexQuantity,
m_akSVertex);
break;
case Query::QT_REAL:
m_pkQuery = WM4_NEW Query2<Real>(m_iVertexQuantity,m_akSVertex);
break;
case Query::QT_FILTERED:
m_pkQuery = WM4_NEW Query2Filtered<Real>(m_iVertexQuantity,
m_akSVertex,m_fEpsilon);
break;
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull2<Real>::Save (const char* acFilename) const
{
FILE* pkOFile = System::Fopen(acFilename,"wb");
if (!pkOFile)
{
return false;
}
ConvexHull<Real>::Save(pkOFile);
size_t uiSize = sizeof(Real);
int iVQ = 2*m_iVertexQuantity;
if (uiSize == 4)
{
System::Write4le(pkOFile,iVQ,m_akVertex);
System::Write4le(pkOFile,iVQ,m_akSVertex);
System::Write4le(pkOFile,2,(const Real*)m_kLineOrigin);
System::Write4le(pkOFile,2,(const Real*)m_kLineDirection);
}
else // iSize == 8
{
System::Write8le(pkOFile,iVQ,m_akVertex);
System::Write8le(pkOFile,iVQ,m_akSVertex);
System::Write8le(pkOFile,2,(const Real*)m_kLineOrigin);
System::Write8le(pkOFile,2,(const Real*)m_kLineDirection);
}
System::Fclose(pkOFile);
return true;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// ConvexHull2::Edge
//----------------------------------------------------------------------------
template <class Real>
ConvexHull2<Real>::Edge::Edge (int iV0, int iV1)
{
V[0] = iV0;
V[1] = iV1;
A[0] = 0;
A[1] = 0;
Sign = 0;
Time = -1;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull2<Real>::Edge::GetSign (int i, const Query2<Real>* pkQuery)
{
if (i != Time)
{
Time = i;
Sign = pkQuery->ToLine(i,V[0],V[1]);
}
return Sign;
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull2<Real>::Edge::Insert (Edge* pkAdj0, Edge* pkAdj1)
{
pkAdj0->A[1] = this;
pkAdj1->A[0] = this;
A[0] = pkAdj0;
A[1] = pkAdj1;
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull2<Real>::Edge::DeleteSelf ()
{
if (A[0])
{
A[0]->A[1] = 0;
}
if (A[1])
{
A[1]->A[0] = 0;
}
WM4_DELETE this;
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull2<Real>::Edge::DeleteAll ()
{
Edge* pkAdj = A[1];
while (pkAdj && pkAdj != this)
{
Edge* pkSave = pkAdj->A[1];
WM4_DELETE pkAdj;
pkAdj = pkSave;
}
assert(pkAdj == this);
WM4_DELETE this;
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull2<Real>::Edge::GetIndices (int& riHQuantity, int*& raiHIndex)
{
// Count the number of edge vertices and allocate the index array.
riHQuantity = 0;
Edge* pkCurrent = this;
do
{
riHQuantity++;
pkCurrent = pkCurrent->A[1];
}
while (pkCurrent != this);
raiHIndex = WM4_NEW int[riHQuantity];
// Fill the index array.
riHQuantity = 0;
pkCurrent = this;
do
{
raiHIndex[riHQuantity++] = pkCurrent->V[0];
pkCurrent = pkCurrent->A[1];
}
while (pkCurrent != this);
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
class ConvexHull2<float>;
template WM4_FOUNDATION_ITEM
class ConvexHull2<double>;
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,96 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4CONVEXHULL2_H
#define WM4CONVEXHULL2_H
#include "Wm4FoundationLIB.h"
#include "Wm4ConvexHull1.h"
#include "Wm4Query2.h"
namespace Wm4
{
template <class Real>
class WM4_FOUNDATION_ITEM ConvexHull2 : public ConvexHull<Real>
{
public:
// The input to the constructor is the array of vertices whose convex hull
// is required. If you want ConvexHull2 to delete the vertices during
// destruction, set bOwner to 'true'. Otherwise, you own the vertices and
// must delete them yourself.
//
// You have a choice of speed versus accuracy. The fastest choice is
// Query::QT_INT64, but it gives up a lot of precision, scaling the points
// to [0,2^{20}]^3. The choice Query::QT_INTEGER gives up less precision,
// scaling the points to [0,2^{24}]^3. The choice Query::QT_RATIONAL uses
// exact arithmetic, but is the slowest choice. The choice Query::QT_REAL
// uses floating-point arithmetic, but is not robust in all cases.
ConvexHull2 (int iVertexQuantity, Vector2<Real>* akVertex, Real fEpsilon,
bool bOwner, Query::Type eQueryType);
virtual ~ConvexHull2 ();
// If GetDimension() returns 1, then the points lie on a line. You must
// create a ConvexHull1 object using the function provided.
const Vector2<Real>& GetLineOrigin () const;
const Vector2<Real>& GetLineDirection () const;
ConvexHull1<Real>* GetConvexHull1 () const;
private:
using ConvexHull<Real>::m_eQueryType;
using ConvexHull<Real>::m_iVertexQuantity;
using ConvexHull<Real>::m_iDimension;
using ConvexHull<Real>::m_iSimplexQuantity;
using ConvexHull<Real>::m_aiIndex;
using ConvexHull<Real>::m_fEpsilon;
using ConvexHull<Real>::m_bOwner;
class WM4_FOUNDATION_ITEM Edge
{
public:
Edge (int iV0, int iV1);
int GetSign (int i, const Query2<Real>* pkQuery);
void Insert (Edge* pkAdj0, Edge* pkAdj1);
void DeleteSelf ();
void DeleteAll ();
void GetIndices (int& riHQuantity, int*& raiHIndex);
int V[2];
Edge* A[2];
int Sign;
int Time;
};
// Support for streaming to/from disk.
ConvexHull2 (const char* acFilename);
bool Load (const char* acFilename);
bool Save (const char* acFilename) const;
bool Update (Edge*& rpkHull, int i);
// The input points.
Vector2<Real>* m_akVertex;
// Support for robust queries.
Vector2<Real>* m_akSVertex;
Query2<Real>* m_pkQuery;
// The line of containment if the dimension is 1.
Vector2<Real> m_kLineOrigin, m_kLineDirection;
};
typedef ConvexHull2<float> ConvexHull2f;
typedef ConvexHull2<double> ConvexHull2d;
}
#endif

View File

@ -0,0 +1,591 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4ConvexHull3.h"
#include "Wm4Mapper3.h"
#include "Wm4Query3Filtered.h"
#include "Wm4Query3Int64.h"
#include "Wm4Query3TInteger.h"
#include "Wm4Query3TRational.h"
namespace Wm4
{
//----------------------------------------------------------------------------
template <class Real>
ConvexHull3<Real>::ConvexHull3 (int iVertexQuantity, Vector3<Real>* akVertex,
Real fEpsilon, bool bOwner, Query::Type eQueryType)
:
ConvexHull<Real>(iVertexQuantity,fEpsilon,bOwner,eQueryType),
m_kLineOrigin(Vector3<Real>::ZERO),
m_kLineDirection(Vector3<Real>::ZERO),
m_kPlaneOrigin(Vector3<Real>::ZERO)
{
assert(akVertex);
m_akVertex = akVertex;
m_akPlaneDirection[0] = Vector3<Real>::ZERO;
m_akPlaneDirection[1] = Vector3<Real>::ZERO;
m_akSVertex = 0;
m_pkQuery = 0;
Mapper3<Real> kMapper(m_iVertexQuantity,m_akVertex,m_fEpsilon);
if (kMapper.GetDimension() == 0)
{
// The values of m_iDimension, m_aiIndex, and m_aiAdjacent were
// already initialized by the ConvexHull base class.
return;
}
if (kMapper.GetDimension() == 1)
{
// The set is (nearly) collinear. The caller is responsible for
// creating a ConvexHull1 object.
m_iDimension = 1;
m_kLineOrigin = kMapper.GetOrigin();
m_kLineDirection = kMapper.GetDirection(0);
return;
}
if (kMapper.GetDimension() == 2)
{
// The set is (nearly) coplanar. The caller is responsible for
// creating a ConvexHull2 object.
m_iDimension = 2;
m_kPlaneOrigin = kMapper.GetOrigin();
m_akPlaneDirection[0] = kMapper.GetDirection(0);
m_akPlaneDirection[1] = kMapper.GetDirection(1);
return;
}
m_iDimension = 3;
int i0 = kMapper.GetExtremeIndex(0);
int i1 = kMapper.GetExtremeIndex(1);
int i2 = kMapper.GetExtremeIndex(2);
int i3 = kMapper.GetExtremeIndex(3);
m_akSVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity];
int i;
if (eQueryType != Query::QT_RATIONAL && eQueryType != Query::QT_FILTERED)
{
// Transform the vertices to the cube [0,1]^3.
Vector3<Real> kMin = kMapper.GetMin();
Real fScale = ((Real)1.0)/kMapper.GetMaxRange();
for (i = 0; i < m_iVertexQuantity; i++)
{
m_akSVertex[i] = (m_akVertex[i] - kMin)*fScale;
}
Real fExpand;
if (eQueryType == Query::QT_INT64)
{
// Scale the vertices to the square [0,2^{20}]^2 to allow use of
// 64-bit integers.
fExpand = (Real)(1 << 20);
m_pkQuery = WM4_NEW Query3Int64<Real>(m_iVertexQuantity,
m_akSVertex);
}
else if (eQueryType == Query::QT_INTEGER)
{
// Scale the vertices to the square [0,2^{24}]^2 to allow use of
// TInteger.
fExpand = (Real)(1 << 24);
m_pkQuery = WM4_NEW Query3TInteger<Real>(m_iVertexQuantity,
m_akSVertex);
}
else // eQueryType == Query::QT_REAL
{
// No scaling for floating point.
fExpand = (Real)1.0;
m_pkQuery = WM4_NEW Query3<Real>(m_iVertexQuantity,m_akSVertex);
}
for (i = 0; i < m_iVertexQuantity; i++)
{
m_akSVertex[i] *= fExpand;
}
}
else
{
// No transformation needed for exact rational arithmetic or filtered
// predicates.
size_t uiSize = m_iVertexQuantity*sizeof(Vector3<Real>);
System::Memcpy(m_akSVertex,uiSize,m_akVertex,uiSize);
if (eQueryType == Query::QT_RATIONAL)
{
m_pkQuery = WM4_NEW Query3TRational<Real>(m_iVertexQuantity,
m_akSVertex);
}
else // eQueryType == Query::QT_FILTERED
{
m_pkQuery = WM4_NEW Query3Filtered<Real>(m_iVertexQuantity,
m_akSVertex,m_fEpsilon);
}
}
Triangle* pkT0;
Triangle* pkT1;
Triangle* pkT2;
Triangle* pkT3;
if (kMapper.GetExtremeCCW())
{
pkT0 = WM4_NEW Triangle(i0,i1,i3);
pkT1 = WM4_NEW Triangle(i0,i2,i1);
pkT2 = WM4_NEW Triangle(i0,i3,i2);
pkT3 = WM4_NEW Triangle(i1,i2,i3);
pkT0->AttachTo(pkT1,pkT3,pkT2);
pkT1->AttachTo(pkT2,pkT3,pkT0);
pkT2->AttachTo(pkT0,pkT3,pkT1);
pkT3->AttachTo(pkT1,pkT2,pkT0);
}
else
{
pkT0 = WM4_NEW Triangle(i0,i3,i1);
pkT1 = WM4_NEW Triangle(i0,i1,i2);
pkT2 = WM4_NEW Triangle(i0,i2,i3);
pkT3 = WM4_NEW Triangle(i1,i3,i2);
pkT0->AttachTo(pkT2,pkT3,pkT1);
pkT1->AttachTo(pkT0,pkT3,pkT2);
pkT2->AttachTo(pkT1,pkT3,pkT0);
pkT3->AttachTo(pkT0,pkT2,pkT1);
}
m_kHull.clear();
m_kHull.insert(pkT0);
m_kHull.insert(pkT1);
m_kHull.insert(pkT2);
m_kHull.insert(pkT3);
for (i = 0; i < m_iVertexQuantity; i++)
{
if (!Update(i))
{
DeleteHull();
return;
}
}
ExtractIndices();
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull3<Real>::~ConvexHull3 ()
{
if (m_bOwner)
{
WM4_DELETE[] m_akVertex;
}
WM4_DELETE[] m_akSVertex;
WM4_DELETE m_pkQuery;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector3<Real>& ConvexHull3<Real>::GetLineOrigin () const
{
return m_kLineOrigin;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector3<Real>& ConvexHull3<Real>::GetLineDirection () const
{
return m_kLineDirection;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector3<Real>& ConvexHull3<Real>::GetPlaneOrigin () const
{
return m_kPlaneOrigin;
}
//----------------------------------------------------------------------------
template <class Real>
const Vector3<Real>& ConvexHull3<Real>::GetPlaneDirection (int i) const
{
assert(0 <= i && i < 2);
return m_akPlaneDirection[i];
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull1<Real>* ConvexHull3<Real>::GetConvexHull1 () const
{
assert(m_iDimension == 1);
if (m_iDimension != 1)
{
return 0;
}
Real* afProjection = WM4_NEW Real[m_iVertexQuantity];
for (int i = 0; i < m_iVertexQuantity; i++)
{
Vector3<Real> kDiff = m_akVertex[i] - m_kLineOrigin;
afProjection[i] = m_kLineDirection.Dot(kDiff);
}
return WM4_NEW ConvexHull1<Real>(m_iVertexQuantity,afProjection,
m_fEpsilon,true,m_eQueryType);
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull2<Real>* ConvexHull3<Real>::GetConvexHull2 () const
{
assert(m_iDimension == 2);
if (m_iDimension != 2)
{
return 0;
}
Vector2<Real>* akProjection = WM4_NEW Vector2<Real>[m_iVertexQuantity];
for (int i = 0; i < m_iVertexQuantity; i++)
{
Vector3<Real> kDiff = m_akVertex[i] - m_kPlaneOrigin;
akProjection[i][0] = m_akPlaneDirection[0].Dot(kDiff);
akProjection[i][1] = m_akPlaneDirection[1].Dot(kDiff);
}
return WM4_NEW ConvexHull2<Real>(m_iVertexQuantity,akProjection,
m_fEpsilon,true,m_eQueryType);
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull3<Real>::Update (int i)
{
// Locate a triangle visible to the input point (if possible).
Triangle* pkVisible = 0;
Triangle* pkTri;
typename std::set<Triangle*>::iterator pkIter;
for (pkIter = m_kHull.begin(); pkIter != m_kHull.end(); pkIter++)
{
pkTri = *pkIter;
if (pkTri->GetSign(i,m_pkQuery) > 0)
{
pkVisible = pkTri;
break;
}
}
if (!pkVisible)
{
// The point is inside the current hull; nothing to do.
return true;
}
// Locate and remove the visible triangles.
std::stack<Triangle*> kVisible;
std::map<int,TerminatorData> kTerminator;
kVisible.push(pkVisible);
pkVisible->OnStack = true;
int j, iV0, iV1;
while (!kVisible.empty())
{
pkTri = kVisible.top();
kVisible.pop();
pkTri->OnStack = false;
for (j = 0; j < 3; j++)
{
Triangle* pkAdj = pkTri->A[j];
if (pkAdj)
{
// Detach triangle and adjacent triangle from each other.
int iNullIndex = pkTri->DetachFrom(j,pkAdj);
if (pkAdj->GetSign(i,m_pkQuery) > 0)
{
if (!pkAdj->OnStack)
{
// Adjacent triangle is visible.
kVisible.push(pkAdj);
pkAdj->OnStack = true;
}
}
else
{
// Adjacent triangle is invisible.
iV0 = pkTri->V[j];
iV1 = pkTri->V[(j+1)%3];
kTerminator[iV0] = TerminatorData(iV0,iV1,iNullIndex,
pkAdj);
}
}
}
m_kHull.erase(pkTri);
WM4_DELETE pkTri;
}
// Insert the new edges formed by the input point and the terminator
// between visible and invisible triangles.
int iSize = (int)kTerminator.size();
assert(iSize >= 3);
typename std::map<int,TerminatorData>::iterator pkEdge =
kTerminator.begin();
iV0 = pkEdge->second.V[0];
iV1 = pkEdge->second.V[1];
pkTri = WM4_NEW Triangle(i,iV0,iV1);
m_kHull.insert(pkTri);
// save information for linking first/last inserted new triangles
int iSaveV0 = pkEdge->second.V[0];
Triangle* pkSaveTri = pkTri;
// establish adjacency links across terminator edge
pkTri->A[1] = pkEdge->second.Tri;
pkEdge->second.Tri->A[pkEdge->second.NullIndex] = pkTri;
for (j = 1; j < iSize; j++)
{
pkEdge = kTerminator.find(iV1);
assert(pkEdge != kTerminator.end());
iV0 = iV1;
iV1 = pkEdge->second.V[1];
Triangle* pkNext = WM4_NEW Triangle(i,iV0,iV1);
m_kHull.insert(pkNext);
// establish adjacency links across terminator edge
pkNext->A[1] = pkEdge->second.Tri;
pkEdge->second.Tri->A[pkEdge->second.NullIndex] = pkNext;
// establish adjacency links with previously inserted triangle
pkNext->A[0] = pkTri;
pkTri->A[2] = pkNext;
pkTri = pkNext;
}
assert(iV1 == iSaveV0);
(void)iSaveV0; // avoid warning in Release build
// establish adjacency links between first/last triangles
pkSaveTri->A[0] = pkTri;
pkTri->A[2] = pkSaveTri;
return true;
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull3<Real>::ExtractIndices ()
{
int iTQuantity = (int)m_kHull.size();
m_iSimplexQuantity = iTQuantity;
m_aiIndex = WM4_NEW int[3*m_iSimplexQuantity];
typename std::set<Triangle*>::iterator pkIter;
int i = 0;
for (pkIter = m_kHull.begin(); pkIter != m_kHull.end(); pkIter++)
{
Triangle* pkTri = *pkIter;
for (int j = 0; j < 3; j++)
{
m_aiIndex[i++] = pkTri->V[j];
}
WM4_DELETE pkTri;
}
m_kHull.clear();
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull3<Real>::DeleteHull ()
{
typename std::set<Triangle*>::iterator pkIter;
for (pkIter = m_kHull.begin(); pkIter != m_kHull.end(); pkIter++)
{
Triangle* pkTri = *pkIter;
WM4_DELETE pkTri;
}
m_kHull.clear();
}
//----------------------------------------------------------------------------
template <class Real>
ConvexHull3<Real>::ConvexHull3 (const char* acFilename)
:
ConvexHull<Real>(0,(Real)0.0,false,Query::QT_REAL)
{
m_akVertex = 0;
m_akSVertex = 0;
m_pkQuery = 0;
bool bLoaded = Load(acFilename);
assert(bLoaded);
(void)bLoaded; // avoid warning in Release build
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull3<Real>::Load (const char* acFilename)
{
FILE* pkIFile = System::Fopen(acFilename,"rb");
if (!pkIFile)
{
return false;
}
ConvexHull<Real>::Load(pkIFile);
WM4_DELETE m_pkQuery;
WM4_DELETE[] m_akSVertex;
if (m_bOwner)
{
WM4_DELETE[] m_akVertex;
}
m_bOwner = true;
m_akVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity];
m_akSVertex = WM4_NEW Vector3<Real>[m_iVertexQuantity+4];
size_t uiSize = sizeof(Real);
int iVQ = 3*m_iVertexQuantity;
if (uiSize == 4)
{
System::Read4le(pkIFile,iVQ,m_akVertex);
System::Read4le(pkIFile,iVQ,m_akSVertex);
System::Read4le(pkIFile,3,(Real*)m_kLineOrigin);
System::Read4le(pkIFile,3,(Real*)m_kLineDirection);
System::Read4le(pkIFile,3,(Real*)m_kPlaneOrigin);
System::Read4le(pkIFile,3,(Real*)m_akPlaneDirection[0]);
System::Read4le(pkIFile,3,(Real*)m_akPlaneDirection[1]);
}
else // iSize == 8
{
System::Read8le(pkIFile,iVQ,m_akVertex);
System::Read8le(pkIFile,iVQ,m_akSVertex);
System::Read8le(pkIFile,3,(Real*)m_kLineOrigin);
System::Read8le(pkIFile,3,(Real*)m_kLineDirection);
System::Read8le(pkIFile,3,(Real*)m_kPlaneOrigin);
System::Read8le(pkIFile,3,(Real*)m_akPlaneDirection[0]);
System::Read8le(pkIFile,3,(Real*)m_akPlaneDirection[1]);
}
System::Fclose(pkIFile);
switch (m_eQueryType)
{
case Query::QT_INT64:
m_pkQuery = WM4_NEW Query3Int64<Real>(m_iVertexQuantity,m_akSVertex);
break;
case Query::QT_INTEGER:
m_pkQuery = WM4_NEW Query3TInteger<Real>(m_iVertexQuantity,
m_akSVertex);
break;
case Query::QT_RATIONAL:
m_pkQuery = WM4_NEW Query3TRational<Real>(m_iVertexQuantity,
m_akSVertex);
break;
case Query::QT_REAL:
m_pkQuery = WM4_NEW Query3<Real>(m_iVertexQuantity,m_akSVertex);
break;
case Query::QT_FILTERED:
m_pkQuery = WM4_NEW Query3Filtered<Real>(m_iVertexQuantity,
m_akSVertex,m_fEpsilon);
break;
}
return true;
}
//----------------------------------------------------------------------------
template <class Real>
bool ConvexHull3<Real>::Save (const char* acFilename) const
{
FILE* pkOFile = System::Fopen(acFilename,"wb");
if (!pkOFile)
{
return false;
}
ConvexHull<Real>::Save(pkOFile);
size_t uiSize = sizeof(Real);
int iVQ = 3*m_iVertexQuantity;
if (uiSize == 4)
{
System::Write4le(pkOFile,iVQ,m_akVertex);
System::Write4le(pkOFile,iVQ,m_akSVertex);
System::Write4le(pkOFile,3,(const Real*)m_kLineOrigin);
System::Write4le(pkOFile,3,(const Real*)m_kLineDirection);
System::Write4le(pkOFile,3,(const Real*)m_kPlaneOrigin);
System::Write4le(pkOFile,3,(const Real*)m_akPlaneDirection[0]);
System::Write4le(pkOFile,3,(const Real*)m_akPlaneDirection[1]);
}
else // iSize == 8
{
System::Write8le(pkOFile,iVQ,m_akVertex);
System::Write8le(pkOFile,iVQ,m_akSVertex);
System::Write8le(pkOFile,3,(const Real*)m_kLineOrigin);
System::Write8le(pkOFile,3,(const Real*)m_kLineDirection);
System::Write8le(pkOFile,3,(const Real*)m_kPlaneOrigin);
System::Write8le(pkOFile,3,(const Real*)m_akPlaneDirection[0]);
System::Write8le(pkOFile,3,(const Real*)m_akPlaneDirection[1]);
}
System::Fclose(pkOFile);
return true;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// ConvexHull3::Triangle
//----------------------------------------------------------------------------
template <class Real>
ConvexHull3<Real>::Triangle::Triangle (int iV0, int iV1, int iV2)
{
V[0] = iV0;
V[1] = iV1;
V[2] = iV2;
A[0] = 0;
A[1] = 0;
A[2] = 0;
Sign = 0;
Time = -1;
OnStack = false;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull3<Real>::Triangle::GetSign (int i, const Query3<Real>* pkQuery)
{
if (i != Time)
{
Time = i;
Sign = pkQuery->ToPlane(i,V[0],V[1],V[2]);
}
return Sign;
}
//----------------------------------------------------------------------------
template <class Real>
void ConvexHull3<Real>::Triangle::AttachTo (Triangle* pkAdj0,
Triangle* pkAdj1, Triangle* pkAdj2)
{
// assert: The input adjacent triangles are correctly ordered.
A[0] = pkAdj0;
A[1] = pkAdj1;
A[2] = pkAdj2;
}
//----------------------------------------------------------------------------
template <class Real>
int ConvexHull3<Real>::Triangle::DetachFrom (int iAdj, Triangle* pkAdj)
{
assert(0 <= iAdj && iAdj < 3 && A[iAdj] == pkAdj);
A[iAdj] = 0;
for (int i = 0; i < 3; i++)
{
if (pkAdj->A[i] == this)
{
pkAdj->A[i] = 0;
return i;
}
}
return -1;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// explicit instantiation
//----------------------------------------------------------------------------
template WM4_FOUNDATION_ITEM
class ConvexHull3<float>;
template WM4_FOUNDATION_ITEM
class ConvexHull3<double>;
//----------------------------------------------------------------------------
}

View File

@ -0,0 +1,126 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4CONVEXHULL3_H
#define WM4CONVEXHULL3_H
#include "Wm4FoundationLIB.h"
#include "Wm4ConvexHull1.h"
#include "Wm4ConvexHull2.h"
#include "Wm4Query3.h"
namespace Wm4
{
template <class Real>
class WM4_FOUNDATION_ITEM ConvexHull3 : public ConvexHull<Real>
{
public:
// The input to the constructor is the array of vertices whose convex hull
// is required. If you want ConvexHull3 to delete the vertices during
// destruction, set bOwner to 'true'. Otherwise, you own the vertices and
// must delete them yourself.
//
// You have a choice of speed versus accuracy. The fastest choice is
// Query::QT_INT64, but it gives up a lot of precision, scaling the points
// to [0,2^{20}]^3. The choice Query::QT_INTEGER gives up less precision,
// scaling the points to [0,2^{24}]^3. The choice Query::QT_RATIONAL uses
// exact arithmetic, but is the slowest choice. The choice Query::QT_REAL
// uses floating-point arithmetic, but is not robust in all cases.
ConvexHull3 (int iVertexQuantity, Vector3<Real>* akVertex, Real fEpsilon,
bool bOwner, Query::Type eQueryType);
virtual ~ConvexHull3 ();
// If GetDimension() returns 1, then the points lie on a line. You must
// create a ConvexHull1 object using the function provided.
const Vector3<Real>& GetLineOrigin () const;
const Vector3<Real>& GetLineDirection () const;
ConvexHull1<Real>* GetConvexHull1 () const;
// If GetDimension() returns 2, then the points lie on a plane. The plane
// has two direction vectors (inputs 0 or 1). You must create a
// ConvexHull2 object using the function provided.
const Vector3<Real>& GetPlaneOrigin () const;
const Vector3<Real>& GetPlaneDirection (int i) const;
ConvexHull2<Real>* GetConvexHull2 () const;
// Support for streaming to/from disk.
ConvexHull3 (const char* acFilename);
bool Load (const char* acFilename);
bool Save (const char* acFilename) const;
private:
using ConvexHull<Real>::m_eQueryType;
using ConvexHull<Real>::m_iVertexQuantity;
using ConvexHull<Real>::m_iDimension;
using ConvexHull<Real>::m_iSimplexQuantity;
using ConvexHull<Real>::m_aiIndex;
using ConvexHull<Real>::m_fEpsilon;
using ConvexHull<Real>::m_bOwner;
class WM4_FOUNDATION_ITEM Triangle
{
public:
Triangle (int iV0, int iV1, int iV2);
int GetSign (int i, const Query3<Real>* pkQuery);
void AttachTo (Triangle* pkAdj0, Triangle* pkAdj1, Triangle* pkAdj2);
int DetachFrom (int iAdj, Triangle* pkAdj);
int V[3];
Triangle* A[3];
int Sign;
int Time;
bool OnStack;
};
bool Update (int i);
void ExtractIndices ();
void DeleteHull ();
// The input points.
Vector3<Real>* m_akVertex;
// Support for robust queries.
Vector3<Real>* m_akSVertex;
Query3<Real>* m_pkQuery;
// The line of containment if the dimension is 1.
Vector3<Real> m_kLineOrigin, m_kLineDirection;
// The plane of containment if the dimension is 2.
Vector3<Real> m_kPlaneOrigin, m_akPlaneDirection[2];
// The current hull.
std::set<Triangle*> m_kHull;
class WM4_FOUNDATION_ITEM TerminatorData
{
public:
TerminatorData (int iV0 = -1, int iV1 = -1, int iNullIndex = -1,
Triangle* pkTri = 0)
{
V[0] = iV0;
V[1] = iV1;
NullIndex = iNullIndex;
Tri = pkTri;
}
int V[2];
int NullIndex;
Triangle* Tri;
};
};
typedef ConvexHull3<float> ConvexHull3f;
typedef ConvexHull3<double> ConvexHull3d;
}
#endif

View File

@ -0,0 +1,31 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#include "Wm4FoundationPCH.h"
#include "Wm4Quaternion.h"
namespace Wm4
{
template<> const Quaternion<float>
Quaternion<float>::IDENTITY(1.0f,0.0f,0.0f,0.0f);
template<> const Quaternion<float>
Quaternion<float>::ZERO(0.0f,0.0f,0.0f,0.0f);
template<> int Quaternion<float>::ms_iNext[3] = { 1, 2, 0 };
template<> float Quaternion<float>::ms_fTolerance = 1e-06f;
template<> float Quaternion<float>::ms_fRootTwo = (float)sqrt(2.0);
template<> float Quaternion<float>::ms_fRootHalf = (float)sqrt(0.5);
template<> const Quaternion<double>
Quaternion<double>::IDENTITY(1.0,0.0,0.0,0.0);
template<> const Quaternion<double>
Quaternion<double>::ZERO(0.0,0.0,0.0,0.0);
template<> int Quaternion<double>::ms_iNext[3] = { 1, 2, 0 };
template<> double Quaternion<double>::ms_fTolerance = 1e-08;
template<> double Quaternion<double>::ms_fRootTwo = sqrt(2.0);
template<> double Quaternion<double>::ms_fRootHalf = sqrt(0.5);
}

View File

@ -0,0 +1,326 @@
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
// http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
//
// File Version: 4.10.0 (2009/11/18)
#ifndef WM4QUATERNION_H
#define WM4QUATERNION_H
#include "Wm4FoundationLIB.h"
#include "Wm4Matrix3.h"
namespace Wm4
{
template <class Real>
class Quaternion
{
public:
// A quaternion is q = w + x*i + y*j + z*k where (w,x,y,z) is not
// necessarily a unit length vector in 4D.
// construction
Quaternion (); // uninitialized
Quaternion (Real fW, Real fX, Real fY, Real fZ);
Quaternion (const Quaternion& rkQ);
// quaternion for the input rotation matrix
Quaternion (const Matrix3<Real>& rkRot);
// quaternion for the rotation of the axis-angle pair
Quaternion (const Vector3<Real>& rkAxis, Real fAngle);
// quaternion for the rotation matrix with specified columns
Quaternion (const Vector3<Real> akRotColumn[3]);
// member access: 0 = w, 1 = x, 2 = y, 3 = z
inline operator const Real* () const;
inline operator Real* ();
inline Real operator[] (int i) const;
inline Real& operator[] (int i);
inline Real W () const;
inline Real& W ();
inline Real X () const;
inline Real& X ();
inline Real Y () const;
inline Real& Y ();
inline Real Z () const;
inline Real& Z ();
// assignment
inline Quaternion& operator= (const Quaternion& rkQ);
// comparison
bool operator== (const Quaternion& rkQ) const;
bool operator!= (const Quaternion& rkQ) const;
bool operator< (const Quaternion& rkQ) const;
bool operator<= (const Quaternion& rkQ) const;
bool operator> (const Quaternion& rkQ) const;
bool operator>= (const Quaternion& rkQ) const;
// arithmetic operations
inline Quaternion operator+ (const Quaternion& rkQ) const;
inline Quaternion operator- (const Quaternion& rkQ) const;
inline Quaternion operator* (const Quaternion& rkQ) const;
inline Quaternion operator* (Real fScalar) const;
inline Quaternion operator/ (Real fScalar) const;
inline Quaternion operator- () const;
// arithmetic updates
inline Quaternion& operator+= (const Quaternion& rkQ);
inline Quaternion& operator-= (const Quaternion& rkQ);
inline Quaternion& operator*= (Real fScalar);
inline Quaternion& operator/= (Real fScalar);
// conversion between quaternions, matrices, and axis-angle
Quaternion& FromRotationMatrix (const Matrix3<Real>& rkRot);
void ToRotationMatrix (Matrix3<Real>& rkRot) const;
Quaternion& FromRotationMatrix (const Vector3<Real> akRotColumn[3]);
void ToRotationMatrix (Vector3<Real> akRotColumn[3]) const;
Quaternion& FromAxisAngle (const Vector3<Real>& rkAxis, Real fAngle);
void ToAxisAngle (Vector3<Real>& rkAxis, Real& rfAngle) const;
// functions of a quaternion
inline Real Length () const; // length of 4-tuple
inline Real SquaredLength () const; // squared length of 4-tuple
inline Real Dot (const Quaternion& rkQ) const; // dot product of 4-tuples
inline Real Normalize (); // make the 4-tuple unit length
Quaternion Inverse () const; // apply to non-zero quaternion
Quaternion Conjugate () const;
Quaternion Exp () const; // apply to quaternion with w = 0
Quaternion Log () const; // apply to unit-length quaternion
// rotation of a vector by a quaternion
Vector3<Real> Rotate (const Vector3<Real>& rkVector) const;
// spherical linear interpolation
Quaternion& Slerp (Real fT, const Quaternion& rkP, const Quaternion& rkQ);
Quaternion& SlerpExtraSpins (Real fT, const Quaternion& rkP,
const Quaternion& rkQ, int iExtraSpins);
// intermediate terms for spherical quadratic interpolation
Quaternion& Intermediate (const Quaternion& rkQ0,
const Quaternion& rkQ1, const Quaternion& rkQ2);
// spherical quadratic interpolation
Quaternion& Squad (Real fT, const Quaternion& rkQ0,
const Quaternion& rkA0, const Quaternion& rkA1,
const Quaternion& rkQ1);
// Compute a quaternion that rotates unit-length vector V1 to unit-length
// vector V2. The rotation is about the axis perpendicular to both V1 and
// V2, with angle of that between V1 and V2. If V1 and V2 are parallel,
// any axis of rotation will do, such as the permutation (z2,x2,y2), where
// V2 = (x2,y2,z2).
Quaternion& Align (const Vector3<Real>& rkV1, const Vector3<Real>& rkV2);
// Decompose a quaternion into q = q_twist * q_swing, where q is 'this'
// quaternion. If V1 is the input axis and V2 is the rotation of V1 by
// q, q_swing represents the rotation about the axis perpendicular to
// V1 and V2 (see Quaternion::Align), and q_twist is a rotation about V1.
void DecomposeTwistTimesSwing (const Vector3<Real>& rkV1,
Quaternion& rkTwist, Quaternion& rkSwing);
// Decompose a quaternion into q = q_swing * q_twist, where q is 'this'
// quaternion. If V1 is the input axis and V2 is the rotation of V1 by
// q, q_swing represents the rotation about the axis perpendicular to
// V1 and V2 (see Quaternion::Align), and q_twist is a rotation about V1.
void DecomposeSwingTimesTwist (const Vector3<Real>& rkV1,
Quaternion& rkSwing, Quaternion& rkTwist);
// *** Find closest quaternions with unconstrained angles.
// Closest quaternion of the form (cx + sx*i).
Quaternion GetClosestX () const;
// Closest quaternion of the form (cy + sy*j).
Quaternion GetClosestY () const;
// Closest quaternion of the form (cz + sz*k).
Quaternion GetClosestZ () const;
// Closest quaternion of the form (cx + sx*i)*(cy + sy*j).
Quaternion GetClosestXY () const;
// Closest quaternion of the form (cy + sy*j)*(cx + sx*i).
Quaternion GetClosestYX () const;
// Closest quaternion of the form (cz + sz*k)*(cx + sx*i).
Quaternion GetClosestZX () const;
// Closest quaternion of the form (cx + sx*i)*(cz + sz*k).
Quaternion GetClosestXZ () const;
// Closest quaternion of the form (cy + sy*j)*(cz + sz*k).
Quaternion GetClosestYZ () const;
// Closest quaternion of the form (cz + sz*k)*(cy + sy*j).
Quaternion GetClosestZY () const;
// Factor to (cx + sx*i)*(cy + sy*j)*(cz + sz*k).
void FactorXYZ (Real& rfCx, Real& rfSx, Real& rfCy, Real& rfSy,
Real& rfCz, Real& rfSz);
// Factor to (cx + sx*i)*(cz + sz*k)*(cy + sy*j).
void FactorXZY (Real& rfCx, Real& rfSx, Real& rfCz, Real& rfSz,
Real& rfCy, Real& rfSy);
// Factor to (cy + sy*j)*(cz + sz*k)*(cx + sx*i).
void FactorYZX (Real& rfCy, Real& rfSy, Real& rfCz, Real& rfSz,
Real& rfCx, Real& rfSx);
// Factor to (cy + sy*j)*(cx + sx*i)*(cz + sz*k).
void FactorYXZ (Real& rfCy, Real& rfSy, Real& rfCx, Real& rfSx,
Real& rfCz, Real& rfSz);
// Factor to (cz + sz*k)*(cx + sx*i)*(cy + sy*j).
void FactorZXY (Real& rfCz, Real& rfSz, Real& rfCx, Real& rfSx,
Real& rfCy, Real& rfSy);
// Factor to (cz + sz*k)*(cy + sy*j)*(cx + sx*i).
void FactorZYX (Real& rfCz, Real& rfSz, Real& rfCy, Real& rfSy,
Real& rfCx, Real& rfSx);
// *** Find closest quaternions with constrained angles.
class Constraints
{
public:
Constraints ()
{
// Members are uninitialized.
}
Constraints (Real fMinAngle, Real fMaxAngle)
{
SetAngles(fMinAngle,fMaxAngle);
}
void SetAngles (Real fMinAngle, Real fMaxAngle)
{
m_fMinAngle = fMinAngle;
m_fMaxAngle = fMaxAngle;
m_fCosMinAngle = Math<Real>::Cos(m_fMinAngle);
m_fSinMinAngle = Math<Real>::Sin(m_fMinAngle);
m_fCosMaxAngle = Math<Real>::Cos(m_fMaxAngle);
m_fSinMaxAngle = Math<Real>::Sin(m_fMaxAngle);
m_fDiffCosMaxMin = m_fCosMaxAngle - m_fCosMinAngle;
m_fDiffSinMaxMin = m_fSinMaxAngle - m_fSinMinAngle;
Real fAvrAngle = ((Real)0.5)*(m_fMinAngle + m_fMaxAngle);
m_fCosAvrAngle = Math<Real>::Cos(fAvrAngle);
m_fSinAvrAngle = Math<Real>::Sin(fAvrAngle);
}
bool IsValid (Real fX, Real fY) const
{
// (x,y) must be unit-length.
// Test whether (x,y) satisfies the constraints.
Real fXm = fX - m_fCosMinAngle;
Real fYm = fY - m_fSinMinAngle;
if (fXm*m_fDiffSinMaxMin >= fYm*m_fDiffCosMaxMin)
{
return true;
}
// Test whether (-x,-y) satisfies the constraints.
Real fXp = fX + m_fCosMinAngle;
Real fYp = fY + m_fSinMinAngle;
if (fXp*m_fDiffSinMaxMin <= fYp*m_fDiffCosMaxMin)
{
return true;
}
return false;
}
Real m_fMinAngle; // in [-PI/2,PI/2]
Real m_fMaxAngle; // in [m_fMinAngle/2,PI/2]
Real m_fCosMinAngle; // = cos(m_fMinAngle)
Real m_fSinMinAngle; // = sin(m_fMinAngle)
Real m_fCosMaxAngle; // = cos(m_fMaxAngle)
Real m_fSinMaxAngle; // = sin(m_fMaxAngle)
Real m_fDiffCosMaxMin; // = cos(m_fMaxAngle) - cos(m_fMinAngle)
Real m_fDiffSinMaxMin; // = sin(m_fMaxAngle) - sin(m_fMinAngle)
Real m_fCosAvrAngle; // = cos((m_fMinAngle + m_fMaxAngle)/2)
Real m_fSinAvrAngle; // = sin((m_fMinAngle + mM_faxAngle)/2)
};
// Closest constrained quaternion of the form (cx + sx*i).
Quaternion GetClosestX (const Constraints& rkXCon) const;
// Closest constrained quaternion of the form (cy + sy*j).
Quaternion GetClosestY (const Constraints& rkYCon) const;
// Closest constrained quaternion of the form (cz + sz*k).
Quaternion GetClosestZ (const Constraints& rkZCon) const;
// Closest constrained quaternion of the form (cx + sx*i)*(cy + sy*j).
Quaternion GetClosestXY (const Constraints& rkXCon,
const Constraints& rkYCon) const;
// Closest constrained quaternion of the form (cy + sy*j)*(cx + sx*i).
Quaternion GetClosestYX (const Constraints& rkYCon,
const Constraints& rkXCon) const;
// Closest constrained quaternion of the form (cz + sz*k)*(cx + sx*i).
Quaternion GetClosestZX (const Constraints& rkZCon,
const Constraints& rkXCon) const;
// Closest constrained quaternion of the form (cx + sx*i)*(cz + sz*k).
Quaternion GetClosestXZ (const Constraints& rkXCon,
const Constraints& rkZCon) const;
// Closest constrained quaternion of the form (cz + sz*k)*(cy + sy*j).
Quaternion GetClosestZY (const Constraints& rkZCon,
const Constraints& rkYCon) const;
// Closest constrained quaternion of the form (cy + sy*j)*(cz + sz*k).
Quaternion GetClosestYZ (const Constraints& rkYCon,
const Constraints& rkZCon) const;
// special values
WM4_FOUNDATION_ITEM static const Quaternion IDENTITY;
WM4_FOUNDATION_ITEM static const Quaternion ZERO;
private:
// support for comparisons
int CompareArrays (const Quaternion& rkQ) const;
// Closest unconstrained quaternion of the form:
// (cx + sx*i) when iAxis = 1,
// (cy + sy*j) when iAxis = 2,
// (cz + sz*k) when iAxis = 3
Quaternion GetClosest (int iAxis) const;
// Closest constrained quaternion of the form:
// (cx + sx*i) when iAxis = 1,
// (cy + sy*j) when iAxis = 2,
// (cz + sz*k) when iAxis = 3
Quaternion GetClosest (int iAxis, const Constraints& rkCon) const;
// support for FromRotationMatrix
WM4_FOUNDATION_ITEM static int ms_iNext[3];
// support for closest quaternions
WM4_FOUNDATION_ITEM static Real ms_fTolerance;
WM4_FOUNDATION_ITEM static Real ms_fRootTwo;
WM4_FOUNDATION_ITEM static Real ms_fRootHalf;
Real m_afTuple[4];
};
template <class Real>
inline Quaternion<Real> operator* (Real fScalar, const Quaternion<Real>& rkQ);
#include "Wm4Quaternion.inl"
typedef Quaternion<float> Quaternionf;
typedef Quaternion<double> Quaterniond;
}
#endif

File diff suppressed because it is too large Load Diff