Download src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.cpp from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 18.8 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.cpp
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.cpp
-
curl -L -o Wm4ContBox3.cpp https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/Mesh/App/WildMagic4/Wm4ContBox3.cpp
18.8 kB
| // SPDX-License-Identifier: BSL-1.0 | |
| // 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) | |
| 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>&); | |
| //---------------------------------------------------------------------------- | |
| } | |