+ add WildMagic algorithm to compute minimum volume oriented box
This commit is contained in:
parent
8a30ac74b0
commit
0c6d52485c
|
@ -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
|
||||
|
|
73
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit2.cpp
Normal file
73
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit2.cpp
Normal 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>*);
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
28
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit2.h
Normal file
28
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit2.h
Normal 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
|
86
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit3.cpp
Normal file
86
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit3.cpp
Normal 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>*);
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
28
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit3.h
Normal file
28
src/Mod/Mesh/App/WildMagic4/Wm4ApprGaussPointsFit3.h
Normal 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
|
48
src/Mod/Mesh/App/WildMagic4/Wm4Box2.h
Normal file
48
src/Mod/Mesh/App/WildMagic4/Wm4Box2.h
Normal 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
|
55
src/Mod/Mesh/App/WildMagic4/Wm4Box2.inl
Normal file
55
src/Mod/Mesh/App/WildMagic4/Wm4Box2.inl
Normal 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];
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
545
src/Mod/Mesh/App/WildMagic4/Wm4ContBox2.cpp
Normal file
545
src/Mod/Mesh/App/WildMagic4/Wm4ContBox2.cpp
Normal 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>&);
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
50
src/Mod/Mesh/App/WildMagic4/Wm4ContBox2.h
Normal file
50
src/Mod/Mesh/App/WildMagic4/Wm4ContBox2.h
Normal 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
|
532
src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.cpp
Normal file
532
src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.cpp
Normal 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>&);
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
48
src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.h
Normal file
48
src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.h
Normal 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
|
146
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull.cpp
Normal file
146
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull.cpp
Normal 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>;
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
100
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull.h
Normal file
100
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull.h
Normal 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
|
138
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull1.cpp
Normal file
138
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull1.cpp
Normal 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>;
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
73
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull1.h
Normal file
73
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull1.h
Normal 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
|
488
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull2.cpp
Normal file
488
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull2.cpp
Normal 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>;
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
96
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull2.h
Normal file
96
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull2.h
Normal 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
|
591
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull3.cpp
Normal file
591
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull3.cpp
Normal 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>;
|
||||
//----------------------------------------------------------------------------
|
||||
}
|
126
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull3.h
Normal file
126
src/Mod/Mesh/App/WildMagic4/Wm4ConvexHull3.h
Normal 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
|
31
src/Mod/Mesh/App/WildMagic4/Wm4Quaternion.cpp
Normal file
31
src/Mod/Mesh/App/WildMagic4/Wm4Quaternion.cpp
Normal 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);
|
||||
}
|
326
src/Mod/Mesh/App/WildMagic4/Wm4Quaternion.h
Normal file
326
src/Mod/Mesh/App/WildMagic4/Wm4Quaternion.h
Normal 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
|
1799
src/Mod/Mesh/App/WildMagic4/Wm4Quaternion.inl
Normal file
1799
src/Mod/Mesh/App/WildMagic4/Wm4Quaternion.inl
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user