Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/opencascade/BVH_DistanceField.lxx is written in an unsupported language. File is not indexed.

0001 // Created on: 2014-09-06
0002 // Created by: Denis BOGOLEPOV
0003 // Copyright (c) 2013-2014 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015 
0016 #include <BVH_Triangulation.hxx>
0017 #include <OSD_Parallel.hxx>
0018 #include <BVH_Distance.hxx>
0019 
0020 // =======================================================================
0021 // function : BVH_DistanceField
0022 // purpose  :
0023 // =======================================================================
0024 template<class T, int N>
0025 BVH_DistanceField<T, N>::BVH_DistanceField (const Standard_Integer theMaximumSize,
0026                                             const Standard_Boolean theComputeSign)
0027 : myDimensionX(0),
0028   myDimensionY(0),
0029   myDimensionZ(0),
0030   myMaximumSize (theMaximumSize),
0031   myComputeSign (theComputeSign),
0032   myIsParallel  (Standard_False)
0033 {
0034   Standard_STATIC_ASSERT (N == 3 || N == 4);
0035 
0036   myVoxelData = new T[myMaximumSize * myMaximumSize * myMaximumSize];
0037 }
0038 
0039 // =======================================================================
0040 // function : ~BVH_DistanceField
0041 // purpose  :
0042 // =======================================================================
0043 template<class T, int N>
0044 BVH_DistanceField<T, N>::~BVH_DistanceField()
0045 {
0046   delete [] myVoxelData;
0047 }
0048 
0049 #if defined (_WIN32) && defined (max)
0050   #undef max
0051 #endif
0052 
0053 #include <limits>
0054 
0055 #define BVH_DOT3(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z())
0056 
0057 namespace BVH
0058 {
0059   //=======================================================================
0060   //function : DistanceToBox
0061   //purpose  : Computes squared distance from point to box
0062   //=======================================================================
0063   template<class T, int N>
0064   T DistanceToBox (const typename VectorType<T, N>::Type& thePnt,
0065                    const typename VectorType<T, N>::Type& theMin,
0066                    const typename VectorType<T, N>::Type& theMax)
0067   {
0068     Standard_STATIC_ASSERT (N == 3 || N == 4);
0069 
0070     T aNearestX = Min (Max (thePnt.x(), theMin.x()), theMax.x());
0071     T aNearestY = Min (Max (thePnt.y(), theMin.y()), theMax.y());
0072     T aNearestZ = Min (Max (thePnt.z(), theMin.z()), theMax.z());
0073 
0074     if (aNearestX == thePnt.x()
0075      && aNearestY == thePnt.y()
0076      && aNearestZ == thePnt.z())
0077     {
0078       return static_cast<T> (0);
0079     }
0080 
0081     aNearestX -= thePnt.x();
0082     aNearestY -= thePnt.y();
0083     aNearestZ -= thePnt.z();
0084 
0085     return aNearestX * aNearestX +
0086            aNearestY * aNearestY +
0087            aNearestZ * aNearestZ;
0088   }
0089 
0090   //=======================================================================
0091   //function : DirectionToNearestPoint
0092   //purpose  : Computes squared distance from point to triangle
0093   // ======================================================================
0094   template<class T, int N>
0095   typename VectorType<T, N>::Type DirectionToNearestPoint (
0096     const typename VectorType<T, N>::Type& thePoint,
0097     const typename VectorType<T, N>::Type& theVertA,
0098     const typename VectorType<T, N>::Type& theVertB,
0099     const typename VectorType<T, N>::Type& theVertC)
0100   {
0101     Standard_STATIC_ASSERT (N == 3 || N == 4);
0102 
0103     const typename VectorType<T, N>::Type aAB = theVertB - theVertA;
0104     const typename VectorType<T, N>::Type aAC = theVertC - theVertA;
0105     const typename VectorType<T, N>::Type aAP = thePoint - theVertA;
0106 
0107     const T aABdotAP = BVH_DOT3 (aAB, aAP);
0108     const T aACdotAP = BVH_DOT3 (aAC, aAP);
0109 
0110     if (aABdotAP <= static_cast<T> (0) && aACdotAP <= static_cast<T> (0))
0111     {
0112       return aAP;
0113     }
0114 
0115     const typename VectorType<T, N>::Type aBC = theVertC - theVertB;
0116     const typename VectorType<T, N>::Type aBP = thePoint - theVertB;
0117 
0118     const T aBAdotBP = -BVH_DOT3 (aAB, aBP);
0119     const T aBCdotBP =  BVH_DOT3 (aBC, aBP);
0120 
0121     if (aBAdotBP <= static_cast<T> (0) && aBCdotBP <= static_cast<T> (0))
0122     {
0123       return aBP;
0124     }
0125 
0126     const typename VectorType<T, N>::Type aCP = thePoint - theVertC;
0127 
0128     const T aCBdotCP = -BVH_DOT3 (aBC, aCP);
0129     const T aCAdotCP = -BVH_DOT3 (aAC, aCP);
0130 
0131     if (aCAdotCP <= static_cast<T> (0) && aCBdotCP <= static_cast<T> (0))
0132     {
0133       return aCP;
0134     }
0135 
0136     const T aACdotBP = BVH_DOT3 (aAC, aBP);
0137 
0138     const T aVC = aABdotAP * aACdotBP + aBAdotBP * aACdotAP;
0139 
0140     if (aVC <= static_cast<T> (0) && aABdotAP >= static_cast<T> (0) && aBAdotBP >= static_cast<T> (0))
0141     {
0142       return aAP - aAB * (aABdotAP / (aABdotAP + aBAdotBP));
0143     }
0144 
0145     const T aABdotCP = BVH_DOT3 (aAB, aCP);
0146 
0147     const T aVA = aBAdotBP * aCAdotCP - aABdotCP * aACdotBP;
0148 
0149     if (aVA <= static_cast<T> (0) && aBCdotBP >= static_cast<T> (0) && aCBdotCP >= static_cast<T> (0))
0150     {
0151       return aBP - aBC * (aBCdotBP / (aBCdotBP + aCBdotCP));
0152     }
0153 
0154     const T aVB = aABdotCP * aACdotAP + aABdotAP * aCAdotCP;
0155 
0156     if (aVB <= static_cast<T> (0) && aACdotAP >= static_cast<T> (0) && aCAdotCP >= static_cast<T> (0))
0157     {
0158       return aAP - aAC * (aACdotAP / (aACdotAP + aCAdotCP));
0159     }
0160 
0161     const T aNorm = static_cast<T> (1.0) / (aVA + aVB + aVC);
0162 
0163     const T aU = aVA * aNorm;
0164     const T aV = aVB * aNorm;
0165 
0166     return thePoint - (theVertA * aU + theVertB * aV + theVertC * (static_cast<T> (1.0) - aU - aV));
0167   }
0168 
0169   //=======================================================================
0170   //function : SquareDistanceToPoint
0171   //purpose  : Abstract class to compute squared distance from point to BVH tree
0172   //=======================================================================
0173   template<class T, int N, class BVHSetType>
0174   class SquareDistanceToPoint : public BVH_Distance<T,N,typename VectorType<T, N>::Type, BVHSetType>
0175   {
0176   public:
0177     typedef typename VectorType<T, N>::Type BVH_VecNt;
0178 
0179   public:
0180     SquareDistanceToPoint()
0181       : BVH_Distance<T, N, BVH_VecNt, BVHSetType>(),
0182         myIsOutside (Standard_True)
0183     {}
0184 
0185   public:
0186 
0187     //! IsOutside
0188     Standard_Boolean IsOutside() const { return myIsOutside; }
0189 
0190   public:
0191 
0192     //! Defines the rules for node rejection
0193     virtual Standard_Boolean RejectNode (const BVH_VecNt& theCMin,
0194                                          const BVH_VecNt& theCMax,
0195                                          T& theMetric) const Standard_OVERRIDE
0196     {
0197       theMetric = DistanceToBox<T, N> (this->myObject, theCMin, theCMax);
0198       return theMetric > this->myDistance;
0199     }
0200 
0201   public:
0202 
0203     //! Redefine the Stop to never stop the selection
0204     virtual Standard_Boolean Stop() const Standard_OVERRIDE
0205     {
0206       return Standard_False;
0207     }
0208 
0209   protected:
0210 
0211     Standard_Boolean myIsOutside;
0212   };
0213 
0214   //=======================================================================
0215   //function : PointTriangulationSquareDistance
0216   //purpose  : Computes squared distance from point to BVH triangulation
0217   //=======================================================================
0218   template<class T, int N>
0219   class PointTriangulationSquareDistance: public SquareDistanceToPoint <T,N, BVH_Triangulation<T, N>>
0220   {
0221   public:
0222     typedef typename VectorType<T, N>::Type BVH_VecNt;
0223 
0224   public:
0225     //! Constructor
0226     PointTriangulationSquareDistance()
0227       : SquareDistanceToPoint<T, N, BVH_Triangulation<T, N>>()
0228     {
0229     }
0230 
0231   public:
0232     // Accepting the element
0233     virtual Standard_Boolean Accept (const Standard_Integer theIndex,
0234                                      const T&) Standard_OVERRIDE
0235     {
0236       const BVH_Vec4i aTriangle = this->myBVHSet->Elements[theIndex];
0237 
0238       const BVH_VecNt aVertex0 = this->myBVHSet->Vertices[aTriangle.x()];
0239       const BVH_VecNt aVertex1 = this->myBVHSet->Vertices[aTriangle.y()];
0240       const BVH_VecNt aVertex2 = this->myBVHSet->Vertices[aTriangle.z()];
0241 
0242       const BVH_VecNt aDirection =
0243         DirectionToNearestPoint<T, N> (this->myObject, aVertex0, aVertex1, aVertex2);
0244 
0245       const T aDistance = BVH_DOT3 (aDirection, aDirection);
0246 
0247       if (aDistance < this->myDistance)
0248       {
0249         this->myDistance = aDistance;
0250 
0251         BVH_VecNt aTrgEdges[] = { aVertex1 - aVertex0, aVertex2 - aVertex0 };
0252 
0253         BVH_VecNt aTrgNormal;
0254 
0255         aTrgNormal.x () = aTrgEdges[0].y () * aTrgEdges[1].z () - aTrgEdges[0].z () * aTrgEdges[1].y ();
0256         aTrgNormal.y () = aTrgEdges[0].z () * aTrgEdges[1].x () - aTrgEdges[0].x () * aTrgEdges[1].z ();
0257         aTrgNormal.z () = aTrgEdges[0].x () * aTrgEdges[1].y () - aTrgEdges[0].y () * aTrgEdges[1].x ();
0258 
0259         this->myIsOutside = BVH_DOT3 (aTrgNormal, aDirection) > 0;
0260 
0261         return Standard_True;
0262       }
0263 
0264       return Standard_False;
0265     }
0266   };
0267 
0268   //=======================================================================
0269   //function : SquareDistanceToObject
0270   //purpose  : Computes squared distance from point to BVH triangulation
0271   //=======================================================================
0272   template<class T, int N>
0273   T SquareDistanceToObject (BVH_Object<T, N>* theObject,
0274     const typename VectorType<T, N>::Type& thePnt, Standard_Boolean& theIsOutside)
0275   {
0276     Standard_STATIC_ASSERT (N == 3 || N == 4);
0277 
0278     T aMinDistance = std::numeric_limits<T>::max();
0279 
0280     BVH_Triangulation<T, N>* aTriangulation =
0281       dynamic_cast<BVH_Triangulation<T, N>*> (theObject);
0282 
0283     Standard_ASSERT_RETURN (aTriangulation != NULL,
0284       "Error: Unsupported BVH object (non triangulation)", aMinDistance);
0285 
0286     const opencascade::handle<BVH_Tree<T, N> >& aBVH = aTriangulation->BVH();
0287     if (aBVH.IsNull())
0288     {
0289       return Standard_False;
0290     }
0291 
0292     PointTriangulationSquareDistance<T,N> aDistTool;
0293     aDistTool.SetObject (thePnt);
0294     aDistTool.SetBVHSet (aTriangulation);
0295     aDistTool.ComputeDistance();
0296     theIsOutside = aDistTool.IsOutside();
0297     return aDistTool.Distance();
0298   }
0299 
0300   //=======================================================================
0301   //function : PointGeometrySquareDistance
0302   //purpose  : Computes squared distance from point to BVH geometry
0303   //=======================================================================
0304   template<class T, int N>
0305   class PointGeometrySquareDistance: public SquareDistanceToPoint <T,N,BVH_Geometry<T, N>>
0306   {
0307   public:
0308     typedef typename VectorType<T, N>::Type BVH_VecNt;
0309 
0310   public:
0311     //! Constructor
0312     PointGeometrySquareDistance()
0313       : SquareDistanceToPoint<T, N, BVH_Geometry<T, N>>()
0314     {
0315     }
0316 
0317   public:
0318     // Accepting the element
0319     virtual Standard_Boolean Accept (const Standard_Integer theIndex,
0320                                      const T&) Standard_OVERRIDE
0321     {
0322       Standard_Boolean isOutside = Standard_True;
0323       const T aDistance = SquareDistanceToObject (
0324         this->myBVHSet->Objects ()(theIndex).operator->(), this->myObject, isOutside);
0325 
0326       if (aDistance < this->myDistance)
0327       {
0328         this->myDistance = aDistance;
0329         this->myIsOutside = isOutside;
0330 
0331         return Standard_True;
0332       }
0333       return Standard_False;
0334     }
0335   };
0336 
0337   //=======================================================================
0338   //function : SquareDistanceToGeomerty
0339   //purpose  : Computes squared distance from point to BVH geometry
0340   //=======================================================================
0341   template<class T, int N>
0342   T SquareDistanceToGeomerty (BVH_Geometry<T, N>& theGeometry,
0343     const typename VectorType<T, N>::Type& thePnt, Standard_Boolean& theIsOutside)
0344   {
0345     Standard_STATIC_ASSERT (N == 3 || N == 4);
0346 
0347     const BVH_Tree<T, N, BVH_BinaryTree>* aBVH = theGeometry.BVH().get();
0348 
0349     if (aBVH == NULL)
0350     {
0351       return Standard_False;
0352     }
0353 
0354     PointGeometrySquareDistance<T,N> aDistTool;
0355     aDistTool.SetObject (thePnt);
0356     aDistTool.SetBVHSet (&theGeometry);
0357     aDistTool.ComputeDistance();
0358     theIsOutside = aDistTool.IsOutside();
0359     return aDistTool.Distance();
0360   }
0361 }
0362 
0363 #undef BVH_DOT3
0364 
0365 //! Tool object for parallel construction of distance field (uses Intel TBB).
0366 template<class T, int N>
0367 class BVH_ParallelDistanceFieldBuilder
0368 {
0369 private:
0370 
0371   //! Input BVH geometry.
0372   BVH_Geometry<T, N>* myGeometry;
0373 
0374   //! Output distance field.
0375   BVH_DistanceField<T, N>* myOutField;
0376 
0377 public:
0378 
0379   BVH_ParallelDistanceFieldBuilder (BVH_DistanceField<T, N>* theOutField, BVH_Geometry<T, N>* theGeometry)
0380   : myGeometry (theGeometry),
0381     myOutField (theOutField)
0382   {
0383     //
0384   }
0385 
0386   void operator() (const Standard_Integer theIndex) const
0387   {
0388     myOutField->BuildSlices (*myGeometry, theIndex, theIndex + 1);
0389   }
0390 };
0391 
0392 // =======================================================================
0393 // function : BuildSlices
0394 // purpose  : Performs building of distance field for the given Z slices
0395 // =======================================================================
0396 template<class T, int N>
0397 void BVH_DistanceField<T, N>::BuildSlices (BVH_Geometry<T, N>& theGeometry,
0398   const Standard_Integer theStartSlice, const Standard_Integer theFinalSlice)
0399 {
0400   for (Standard_Integer aZ = theStartSlice; aZ < theFinalSlice; ++aZ)
0401   {
0402     for (Standard_Integer aY = 0; aY < myDimensionY; ++aY)
0403     {
0404       for (Standard_Integer aX = 0; aX < myDimensionX; ++aX)
0405       {
0406         BVH_VecNt aCenter;
0407         
0408         aCenter.x() = myCornerMin.x() + myVoxelSize.x() * (aX + static_cast<T> (0.5));
0409         aCenter.y() = myCornerMin.y() + myVoxelSize.y() * (aY + static_cast<T> (0.5));
0410         aCenter.z() = myCornerMin.z() + myVoxelSize.z() * (aZ + static_cast<T> (0.5));
0411 
0412         Standard_Boolean isOutside = Standard_True;
0413 
0414         const T aDistance = sqrt (
0415           BVH::SquareDistanceToGeomerty<T, N> (theGeometry, aCenter, isOutside));
0416 
0417         Voxel (aX, aY, aZ) = (!myComputeSign || isOutside) ? aDistance : -aDistance;
0418       }
0419     }
0420   }
0421 }
0422 
0423 // =======================================================================
0424 // function : Build
0425 // purpose  : Builds 3D distance field from BVH geometry
0426 // =======================================================================
0427 template<class T, int N>
0428 Standard_Boolean BVH_DistanceField<T, N>::Build (BVH_Geometry<T, N>& theGeometry)
0429 {
0430   if (theGeometry.Size() == 0)
0431   {
0432     return Standard_False;
0433   }
0434 
0435   const BVH_VecNt aGlobalBoxSize = theGeometry.Box().Size();
0436 
0437   const T aMaxBoxSide = Max (Max (aGlobalBoxSize.x(), aGlobalBoxSize.y()), aGlobalBoxSize.z());
0438 
0439   myDimensionX = static_cast<Standard_Integer> (myMaximumSize * aGlobalBoxSize.x() / aMaxBoxSide);
0440   myDimensionY = static_cast<Standard_Integer> (myMaximumSize * aGlobalBoxSize.y() / aMaxBoxSide);
0441   myDimensionZ = static_cast<Standard_Integer> (myMaximumSize * aGlobalBoxSize.z() / aMaxBoxSide);
0442 
0443   myDimensionX = Min (myMaximumSize, Max (myDimensionX, 16));
0444   myDimensionY = Min (myMaximumSize, Max (myDimensionY, 16));
0445   myDimensionZ = Min (myMaximumSize, Max (myDimensionZ, 16));
0446 
0447   const BVH_VecNt aGlobalBoxMin = theGeometry.Box().CornerMin();
0448   const BVH_VecNt aGlobalBoxMax = theGeometry.Box().CornerMax();
0449 
0450   const Standard_Integer aVoxelOffset = 2;
0451 
0452   myCornerMin.x() = aGlobalBoxMin.x() - aVoxelOffset * aGlobalBoxSize.x() / (myDimensionX - 2 * aVoxelOffset);
0453   myCornerMin.y() = aGlobalBoxMin.y() - aVoxelOffset * aGlobalBoxSize.y() / (myDimensionY - 2 * aVoxelOffset);
0454   myCornerMin.z() = aGlobalBoxMin.z() - aVoxelOffset * aGlobalBoxSize.z() / (myDimensionZ - 2 * aVoxelOffset);
0455 
0456   myCornerMax.x() = aGlobalBoxMax.x() + aVoxelOffset * aGlobalBoxSize.x() / (myDimensionX - 2 * aVoxelOffset);
0457   myCornerMax.y() = aGlobalBoxMax.y() + aVoxelOffset * aGlobalBoxSize.y() / (myDimensionY - 2 * aVoxelOffset);
0458   myCornerMax.z() = aGlobalBoxMax.z() + aVoxelOffset * aGlobalBoxSize.z() / (myDimensionZ - 2 * aVoxelOffset);
0459   
0460   myVoxelSize.x() = (myCornerMax.x() - myCornerMin.x()) / myDimensionX;
0461   myVoxelSize.y() = (myCornerMax.y() - myCornerMin.y()) / myDimensionY;
0462   myVoxelSize.z() = (myCornerMax.z() - myCornerMin.z()) / myDimensionZ;
0463 
0464   OSD_Parallel::For (0, myDimensionZ, BVH_ParallelDistanceFieldBuilder<T, N> (this, &theGeometry), !IsParallel());
0465 
0466   return Standard_True;
0467 }