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