diff --git a/src/BRepExtrema/BRepExtrema_DistShapeShape.cxx b/src/BRepExtrema/BRepExtrema_DistShapeShape.cxx index dcd92f2fc2..1ef68ed9d6 100644 --- a/src/BRepExtrema/BRepExtrema_DistShapeShape.cxx +++ b/src/BRepExtrema/BRepExtrema_DistShapeShape.cxx @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -56,13 +57,13 @@ namespace } static void BoxCalculation(const TopTools_IndexedMapOfShape& Map, - Bnd_SeqOfBox& SBox) + Bnd_Array1OfBox& SBox) { for (Standard_Integer i = 1; i <= Map.Extent(); i++) { Bnd_Box box; BRepBndLib::Add(Map(i), box); - SBox.Append(box); + SBox[i] = box; } } @@ -105,157 +106,510 @@ namespace } //======================================================================= -//function : DistanceMapMap +//struct : IndexBand //purpose : //======================================================================= - -Standard_Boolean BRepExtrema_DistShapeShape::DistanceMapMap (const TopTools_IndexedMapOfShape& theMap1, - const TopTools_IndexedMapOfShape& theMap2, - const Bnd_SeqOfBox& theLBox1, - const Bnd_SeqOfBox& theLBox2, - const Message_ProgressRange& theRange) +struct IndexBand { - NCollection_Vector aPairList; - const Standard_Integer aCount1 = theMap1.Extent(); - const Standard_Integer aCount2 = theMap2.Extent(); - - Message_ProgressScope aTwinScope(theRange, NULL, 1.0); - Message_ProgressRange aBoxRange(aTwinScope.Next(0.3)); - Message_ProgressScope aBoxScope(aBoxRange, NULL, aCount1); - - for (Standard_Integer anIdx1 = 1; anIdx1 <= aCount1; ++anIdx1) + IndexBand(): + First(0), + Last(0) { - aBoxScope.Next(); - if (!aBoxScope.More()) - { - return Standard_False; - } - for (Standard_Integer anIdx2 = 1; anIdx2 <= aCount2; ++anIdx2) - { - const Bnd_Box& aBox1 = theLBox1.Value (anIdx1); - const Bnd_Box& aBox2 = theLBox2.Value (anIdx2); - if (aBox1.IsVoid() - || aBox2.IsVoid()) - { - continue; - } + } + + IndexBand(Standard_Integer theFirtsIndex, + Standard_Integer theLastIndex): + First(theFirtsIndex), + Last(theLastIndex) + { + } + Standard_Integer First; + Standard_Integer Last; +}; - const Standard_Real aDist = aBox1.Distance (aBox2); - if (aDist < myDistRef - myEps || fabs (aDist - myDistRef) < myEps) +//======================================================================= +//struct : ThreadSolution +//purpose : +//======================================================================= +struct ThreadSolution +{ + ThreadSolution(Standard_Integer theTaskNum): + Shape1(0, theTaskNum-1), + Shape2(0, theTaskNum-1), + Dist(0, theTaskNum-1) + { + Dist.Init(DBL_MAX); + } + + NCollection_Array1 Shape1; + NCollection_Array1 Shape2; + NCollection_Array1 Dist; +}; + +//======================================================================= +//struct : VertexFunctor +//purpose : +//======================================================================= +struct VertexFunctor +{ + VertexFunctor(NCollection_Array1* theBandArray, + const Message_ProgressRange& theRange): + BandArray(theBandArray), + Solution(theBandArray->Size()), + Map1(NULL), + Map2(NULL), + Scope(theRange, "Vertices distances calculating", theBandArray->Size()), + Ranges(0, theBandArray->Size() - 1), + Eps(Precision::Confusion()), + StartDist(0.0) + { + for (Standard_Integer i = 0; i < theBandArray->Size(); ++i) + { + Ranges.SetValue(i, Scope.Next()); + } + } + + void operator() (const Standard_Integer theIndex) const + { + const Standard_Integer aCount2 = Map2->Extent(); + const Standard_Integer aFirst = BandArray->Value(theIndex).First; + const Standard_Integer aLast = BandArray->Value(theIndex).Last; + Solution.Dist[theIndex] = StartDist; + + Message_ProgressScope aScope(Ranges[theIndex], NULL, (double)aLast - aFirst); + + + for (Standard_Integer anIdx1 = aFirst; anIdx1 <= aLast; ++anIdx1) + { + if (!aScope.More()) { - aPairList.Append (BRepExtrema_CheckPair (anIdx1, anIdx2, aDist)); + break; + } + aScope.Next(); + + const TopoDS_Vertex& aVertex1 = TopoDS::Vertex(Map1->FindKey(anIdx1)); + const gp_Pnt aPoint1 = BRep_Tool::Pnt(aVertex1); + for (Standard_Integer anIdx2 = 1; anIdx2 <= aCount2; ++anIdx2) + { + const TopoDS_Vertex& aVertex2 = TopoDS::Vertex(Map2->FindKey(anIdx2)); + const gp_Pnt aPoint2 = BRep_Tool::Pnt(aVertex2); + const Standard_Real aDist = aPoint1.Distance(aPoint2); + { + if (aDist < Solution.Dist[theIndex] - Eps) + { + const BRepExtrema_SolutionElem Sol1(aDist, aPoint1, BRepExtrema_IsVertex, aVertex1); + const BRepExtrema_SolutionElem Sol2(aDist, aPoint2, BRepExtrema_IsVertex, aVertex2); + + Solution.Shape1[theIndex].Clear(); + Solution.Shape2[theIndex].Clear(); + Solution.Shape1[theIndex].Append(Sol1); + Solution.Shape2[theIndex].Append(Sol2); + + Solution.Dist[theIndex] = aDist; + } + else if (Abs(aDist - Solution.Dist[theIndex]) < Eps) + { + const BRepExtrema_SolutionElem Sol1(aDist, aPoint1, BRepExtrema_IsVertex, aVertex1); + const BRepExtrema_SolutionElem Sol2(aDist, aPoint2, BRepExtrema_IsVertex, aVertex2); + Solution.Shape1[theIndex].Append(Sol1); + Solution.Shape2[theIndex].Append(Sol2); + + if (Solution.Dist[theIndex] > aDist) + { + Solution.Dist[theIndex] = aDist; + } + } + } } } } - std::stable_sort(aPairList.begin(), aPairList.end(), BRepExtrema_CheckPair_Comparator); - Message_ProgressRange aDistRange(aTwinScope.Next(0.7)); - Message_ProgressScope aDistScope(aDistRange, NULL, aPairList.Size()); - for (NCollection_Vector::Iterator aPairIter (aPairList); - aPairIter.More(); aPairIter.Next()) + + NCollection_Array1* BandArray; + mutable ThreadSolution Solution; + const TopTools_IndexedMapOfShape* Map1; + const TopTools_IndexedMapOfShape* Map2; + Message_ProgressScope Scope; + NCollection_Array1 Ranges; + Standard_Real Eps; + Standard_Real StartDist; +}; + +//======================================================================= +//function : DistanceVertVert +//purpose : +//======================================================================= +Standard_Boolean BRepExtrema_DistShapeShape::DistanceVertVert(const TopTools_IndexedMapOfShape& theMap1, + const TopTools_IndexedMapOfShape& theMap2, + const Message_ProgressRange& theRange) +{ + const Standard_Integer aCount1 = theMap1.Extent(); + const Standard_Integer aMinTaskSize = aCount1 < 10 ? aCount1 : 10; + const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool(); + const Standard_Integer aNbThreads = aThreadPool->NbThreads(); + Standard_Integer aNbTasks = aNbThreads; + Standard_Integer aTaskSize = (Standard_Integer) Ceiling((double) aCount1 / aNbTasks); + if (aTaskSize < aMinTaskSize) { - aDistScope.Next(); - if (!aDistScope.More()) + aTaskSize = aMinTaskSize; + aNbTasks = (Standard_Integer) Ceiling((double) aCount1 / aTaskSize); + } + + Standard_Integer aFirstIndex(1); + NCollection_Array1 aBandArray(0, aNbTasks - 1); + Message_ProgressScope aDistScope(theRange, NULL, 1); + + for (Standard_Integer anI = 0; anI < aBandArray.Size(); ++anI) + { + if (aCount1 < aFirstIndex + aTaskSize - 1) { - return Standard_False; + aTaskSize = aCount1 - aFirstIndex + 1; } - const BRepExtrema_CheckPair& aPair = aPairIter.Value(); - if (aPair.Distance > myDistRef + myEps) + aBandArray.SetValue(anI, IndexBand(aFirstIndex, aFirstIndex + aTaskSize - 1)); + aFirstIndex += aTaskSize; + } + + VertexFunctor aFunctor(&aBandArray, aDistScope.Next()); + aFunctor.Map1 = &theMap1; + aFunctor.Map2 = &theMap2; + aFunctor.StartDist = myDistRef; + aFunctor.Eps = myEps; + + OSD_Parallel::For(0, aNbTasks, aFunctor, !myIsMultiThread); + if (!aDistScope.More()) + { + return Standard_False; + } + for (Standard_Integer anI = 0; anI < aFunctor.Solution.Dist.Size(); ++anI) + { + Standard_Real aDist = aFunctor.Solution.Dist[anI]; + if (aDist < myDistRef - myEps) { - break; // early search termination + mySolutionsShape1.Clear(); + mySolutionsShape2.Clear(); + mySolutionsShape1.Append(aFunctor.Solution.Shape1[anI]); + mySolutionsShape2.Append(aFunctor.Solution.Shape2[anI]); + myDistRef = aDist; } - - const Bnd_Box& aBox1 = theLBox1.Value (aPair.Index1); - const Bnd_Box& aBox2 = theLBox2.Value (aPair.Index2); - - const TopoDS_Shape& aShape1 = theMap1 (aPair.Index1); - const TopoDS_Shape& aShape2 = theMap2 (aPair.Index2); - - BRepExtrema_DistanceSS aDistTool (aShape1, aShape2, aBox1, aBox2, myDistRef, myEps); - if (aDistTool.IsDone()) + else if (Abs(aDist - myDistRef) < myEps) { - if (aDistTool.DistValue() < myDistRef - myEps) - { - mySolutionsShape1.Clear(); - mySolutionsShape2.Clear(); - - BRepExtrema_SeqOfSolution aSeq1 = aDistTool.Seq1Value(); - BRepExtrema_SeqOfSolution aSeq2 = aDistTool.Seq2Value(); - - mySolutionsShape1.Append (aSeq1); - mySolutionsShape2.Append (aSeq2); - - myDistRef = aDistTool.DistValue(); - } - else if (fabs (aDistTool.DistValue() - myDistRef) < myEps) - { - BRepExtrema_SeqOfSolution aSeq1 = aDistTool.Seq1Value(); - BRepExtrema_SeqOfSolution aSeq2 = aDistTool.Seq2Value(); - - mySolutionsShape1.Append (aSeq1); - mySolutionsShape2.Append (aSeq2); - - if (myDistRef > aDistTool.DistValue()) - { - myDistRef = aDistTool.DistValue(); - } - } + mySolutionsShape1.Append(aFunctor.Solution.Shape1[anI]); + mySolutionsShape2.Append(aFunctor.Solution.Shape2[anI]); + myDistRef = aDist; } } return Standard_True; } //======================================================================= -//function : DistanceVertVert +//struct : DistanceFunctor +//purpose : +//======================================================================= +struct DistanceFunctor +{ + DistanceFunctor(NCollection_Array1 >* theArrayOfArrays, + const Message_ProgressRange& theRange): + ArrayOfArrays(theArrayOfArrays), + Solution(ArrayOfArrays->Size()), + Map1(NULL), + Map2(NULL), + LBox1(NULL), + LBox2(NULL), + Scope(theRange, "Shapes distances calculating", theArrayOfArrays->Size()), + Ranges(0, theArrayOfArrays->Size() - 1), + Eps(Precision::Confusion()), + StartDist(0.0) + { + for (Standard_Integer i = 0; i < theArrayOfArrays->Size(); ++i) + { + Ranges.SetValue(i, Scope.Next()); + } + } + + void operator() (const Standard_Integer theIndex) const + { + Message_ProgressScope aScope(Ranges[theIndex], NULL, ArrayOfArrays->Value(theIndex).Size()); + Solution.Dist[theIndex] = StartDist; + for (Standard_Integer i = 0; i < ArrayOfArrays->Value(theIndex).Size(); i++) + { + if (!aScope.More()) + { + return; + } + aScope.Next(); + const BRepExtrema_CheckPair& aPair = ArrayOfArrays->Value(theIndex).Value(i); + if (aPair.Distance > Solution.Dist[theIndex] + Eps) + { + break; // early search termination + } + const Bnd_Box& aBox1 = LBox1->Value(aPair.Index1); + const Bnd_Box& aBox2 = LBox2->Value(aPair.Index2); + const TopoDS_Shape& aShape1 = Map1->FindKey(aPair.Index1); + const TopoDS_Shape& aShape2 = Map2->FindKey(aPair.Index2); + BRepExtrema_DistanceSS aDistTool(aShape1, aShape2, aBox1, aBox2, Solution.Dist[theIndex], Eps); + const Standard_Real aDist = aDistTool.DistValue(); + if (aDistTool.IsDone()) + { + if (aDist < Solution.Dist[theIndex] - Eps) + { + Solution.Shape1[theIndex].Clear(); + Solution.Shape2[theIndex].Clear(); + + BRepExtrema_SeqOfSolution aSeq1 = aDistTool.Seq1Value(); + BRepExtrema_SeqOfSolution aSeq2 = aDistTool.Seq2Value(); + + Solution.Shape1[theIndex].Append(aSeq1); + Solution.Shape2[theIndex].Append(aSeq2); + + Solution.Dist[theIndex] = aDistTool.DistValue(); + } + else if (Abs(aDist - Solution.Dist[theIndex]) < Eps) + { + BRepExtrema_SeqOfSolution aSeq1 = aDistTool.Seq1Value(); + BRepExtrema_SeqOfSolution aSeq2 = aDistTool.Seq2Value(); + + Solution.Shape1[theIndex].Append(aSeq1); + Solution.Shape2[theIndex].Append(aSeq2); + if (Solution.Dist[theIndex] > aDist) + { + Solution.Dist[theIndex] = aDist; + } + } + } + } + } + + NCollection_Array1 >* ArrayOfArrays; + mutable ThreadSolution Solution; + const TopTools_IndexedMapOfShape* Map1; + const TopTools_IndexedMapOfShape* Map2; + const Bnd_Array1OfBox* LBox1; + const Bnd_Array1OfBox* LBox2; + Message_ProgressScope Scope; + NCollection_Array1 Ranges; + Standard_Real Eps; + Standard_Real StartDist; +}; + + +//======================================================================= +//struct : DistancePairFunctor +//purpose : +//======================================================================= +struct DistancePairFunctor +{ + DistancePairFunctor(NCollection_Array1* theBandArray, + const Message_ProgressRange& theRange): + BandArray(theBandArray), + PairList(0, theBandArray->Size() - 1), + LBox1(NULL), + LBox2(NULL), + Scope(theRange, "Boxes distances calculating", theBandArray->Size()), + Ranges(0, theBandArray->Size() - 1), + DistRef(0), + Eps(Precision::Confusion()) + { + for (Standard_Integer i = 0; i < theBandArray->Size(); ++i) + { + Ranges.SetValue(i, Scope.Next()); + } + } + + void operator() (const Standard_Integer theIndex) const + { + const Standard_Integer aFirst = BandArray->Value(theIndex).First; + const Standard_Integer aLast = BandArray->Value(theIndex).Last; + + Message_ProgressScope aScope(Ranges[theIndex], NULL, (double) aLast - aFirst); + + for (Standard_Integer anIdx1 = aFirst; anIdx1 <= aLast; ++anIdx1) + { + if (!aScope.More()) + { + break; + } + aScope.Next(); + + for (Standard_Integer anIdx2 = 1; anIdx2 <= LBox2->Size(); ++anIdx2) + { + const Bnd_Box& aBox1 = LBox1->Value(anIdx1); + const Bnd_Box& aBox2 = LBox2->Value(anIdx2); + if (aBox1.IsVoid() || aBox2.IsVoid()) + { + continue; + } + + const Standard_Real aDist = aBox1.Distance(aBox2); + if (aDist - DistRef < Eps) + { + PairList[theIndex].Append(BRepExtrema_CheckPair(anIdx1, anIdx2, aDist)); + } + } + } + } + + Standard_Integer ListSize() + { + Standard_Integer aSize(0); + for (Standard_Integer anI = PairList.Lower(); anI <= PairList.Upper(); ++anI) + { + aSize += PairList[anI].Size(); + } + return aSize; + } + + NCollection_Array1* BandArray; + mutable NCollection_Array1 > PairList; + const Bnd_Array1OfBox* LBox1; + const Bnd_Array1OfBox* LBox2; + Message_ProgressScope Scope; + NCollection_Array1 Ranges; + Standard_Real DistRef; + Standard_Real Eps; +}; + +//======================================================================= +//function : DistanceMapMap //purpose : //======================================================================= -Standard_Boolean BRepExtrema_DistShapeShape::DistanceVertVert(const TopTools_IndexedMapOfShape& theMap1, - const TopTools_IndexedMapOfShape& theMap2, - const Message_ProgressRange& theRange) +Standard_Boolean BRepExtrema_DistShapeShape::DistanceMapMap (const TopTools_IndexedMapOfShape& theMap1, + const TopTools_IndexedMapOfShape& theMap2, + const Bnd_Array1OfBox& theLBox1, + const Bnd_Array1OfBox& theLBox2, + const Message_ProgressRange& theRange) { const Standard_Integer aCount1 = theMap1.Extent(); const Standard_Integer aCount2 = theMap2.Extent(); - Message_ProgressScope aScope(theRange, NULL, aCount1); - - for (Standard_Integer anIdx1 = 1; anIdx1 <= aCount1; ++anIdx1) + if (aCount1 == 0 || aCount2 == 0) { - aScope.Next(); - if (!aScope.More()) + return Standard_True; + } + + Message_ProgressScope aTwinScope(theRange, NULL, 1.0); + + const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool(); + const Standard_Integer aNbThreads = aThreadPool->NbThreads(); + const Standard_Integer aMinPairTaskSize = aCount1 < 10 ? aCount1 : 10; + Standard_Integer aNbPairTasks = aNbThreads; + Standard_Integer aPairTaskSize = (Standard_Integer) Ceiling((double) aCount1 / aNbPairTasks); + if (aPairTaskSize < aMinPairTaskSize) + { + aPairTaskSize = aMinPairTaskSize; + aNbPairTasks = (Standard_Integer) Ceiling((double) aCount1 / aPairTaskSize); + } + + Standard_Integer aFirstIndex(1); + NCollection_Array1 aBandArray(0, aNbPairTasks - 1); + + for (Standard_Integer anI = 0; anI < aBandArray.Size(); ++anI) + { + if (aCount1 < aFirstIndex + aPairTaskSize - 1) { - return Standard_False; + aPairTaskSize = aCount1 - aFirstIndex + 1; } - const TopoDS_Vertex& aVertex1 = TopoDS::Vertex(theMap1.FindKey(anIdx1)); - const gp_Pnt aPoint1 = BRep_Tool::Pnt(aVertex1); - for (Standard_Integer anIdx2 = 1; anIdx2 <= aCount2; ++anIdx2) + aBandArray.SetValue(anI, IndexBand(aFirstIndex, aFirstIndex + aPairTaskSize - 1)); + aFirstIndex += aPairTaskSize; + } + + aTwinScope.Next(0.15); + DistancePairFunctor aPairFunctor(&aBandArray, aTwinScope.Next(0.15)); + aPairFunctor.LBox1 = &theLBox1; + aPairFunctor.LBox2 = &theLBox2; + aPairFunctor.DistRef = myDistRef; + aPairFunctor.Eps = myEps; + + OSD_Parallel::For(0, aNbPairTasks, aPairFunctor, !myIsMultiThread); + if (!aTwinScope.More()) + { + return Standard_False; + } + Standard_Integer aListSize = aPairFunctor.ListSize(); + if(aListSize == 0) + { + return Standard_True; + } + NCollection_Array1 aPairList(0, aListSize-1); + Standard_Integer aListIndex(0); + for (Standard_Integer anI = 0; anI < aPairFunctor.PairList.Size(); ++anI) + { + for (Standard_Integer aJ = 0; aJ < aPairFunctor.PairList[anI].Size(); ++aJ) { - const TopoDS_Vertex& aVertex2 = TopoDS::Vertex(theMap2.FindKey(anIdx2)); - const gp_Pnt aPoint2 = BRep_Tool::Pnt(aVertex2); + aPairList[aListIndex] = aPairFunctor.PairList[anI][aJ]; + ++aListIndex; + } + } - const Standard_Real aDist = aPoint1.Distance(aPoint2); - if (aDist < myDistRef - myEps) + std::stable_sort(aPairList.begin(), aPairList.end(), BRepExtrema_CheckPair_Comparator); + + const Standard_Integer aMapSize = aPairList.Size(); + Standard_Integer aNbTasks = aMapSize < aNbThreads ? aMapSize : aNbThreads; + Standard_Integer aTaskSize = (Standard_Integer) Ceiling((double) aMapSize / aNbTasks); + + NCollection_Array1 > anArrayOfArray(0, aNbTasks - 1); + // Since aPairList is sorted in ascending order of distances between Bnd_Boxes, + // BRepExtrema_CheckPair are distributed to tasks one by one from smallest to largest, + // and not ranges, as for DistancePairFunctor. + // Since aMapSize may not be divisible entirely by the number of tasks, + // some tasks should receive one BRepExtrema_CheckPair less than the rest. + // aLastRowLimit defines the task number from which to start tasks containing + // fewer BRepExtrema_CheckPair + Standard_Integer aLastRowLimit = ((aMapSize % aNbTasks) == 0) ? aNbTasks : (aMapSize % aNbTasks); + for (Standard_Integer anI = 0; anI < aTaskSize; ++anI) + { + for (Standard_Integer aJ = 0; aJ < aNbTasks; ++aJ) + { + if (anI == 0) { - mySolutionsShape1.Clear(); - mySolutionsShape2.Clear(); - - const BRepExtrema_SolutionElem Sol1(aDist, aPoint1, BRepExtrema_IsVertex, aVertex1); - const BRepExtrema_SolutionElem Sol2(aDist, aPoint2, BRepExtrema_IsVertex, aVertex2); - mySolutionsShape1.Append(Sol1); - mySolutionsShape2.Append(Sol2); - - myDistRef = aDist; - } - else if (fabs(aDist - myDistRef) < myEps) - { - const BRepExtrema_SolutionElem Sol1(aDist, aPoint1, BRepExtrema_IsVertex, aVertex1); - const BRepExtrema_SolutionElem Sol2(aDist, aPoint2, BRepExtrema_IsVertex, aVertex2); - mySolutionsShape1.Append(Sol1); - mySolutionsShape2.Append(Sol2); - - if (myDistRef > aDist) + Standard_Integer aVectorSize = aTaskSize; + if (aJ >= aLastRowLimit) { - myDistRef = aDist; + aVectorSize--; } + anArrayOfArray[aJ].Resize(0, aVectorSize - 1, Standard_False); + } + if (anI < anArrayOfArray[aJ].Size()) + { + anArrayOfArray[aJ][anI] = aPairList(anI*aNbTasks + aJ); + } + else + { + break; + } + } + } + DistanceFunctor aFunctor(&anArrayOfArray, aTwinScope.Next(0.85)); + aFunctor.Map1 = &theMap1; + aFunctor.Map2 = &theMap2; + aFunctor.LBox1 = &theLBox1; + aFunctor.LBox2 = &theLBox2; + aFunctor.Eps = myEps; + aFunctor.StartDist = myDistRef; + + OSD_Parallel::For(0, aNbTasks, aFunctor, !myIsMultiThread); + if (!aTwinScope.More()) + { + return Standard_False; + } + + for (Standard_Integer anI = 0; anI < aFunctor.Solution.Dist.Size(); ++anI) + { + Standard_Real aDist = aFunctor.Solution.Dist[anI]; + if (aDist < myDistRef - myEps) + { + mySolutionsShape1.Clear(); + mySolutionsShape2.Clear(); + mySolutionsShape1.Append(aFunctor.Solution.Shape1[anI]); + mySolutionsShape2.Append(aFunctor.Solution.Shape2[anI]); + myDistRef = aDist; + } + else if (Abs(aDist - myDistRef) < myEps) + { + mySolutionsShape1.Append(aFunctor.Solution.Shape1[anI]); + mySolutionsShape2.Append(aFunctor.Solution.Shape2[anI]); + if (myDistRef > aDist) + { + myDistRef = aDist; } } } @@ -275,9 +629,9 @@ BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape() myIsInitS1 (Standard_False), myIsInitS2 (Standard_False), myFlag (Extrema_ExtFlag_MINMAX), - myAlgo (Extrema_ExtAlgo_Grad) + myAlgo (Extrema_ExtAlgo_Grad), + myIsMultiThread(Standard_False) { - // } //======================================================================= @@ -296,7 +650,8 @@ BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape myIsInitS1 (Standard_False), myIsInitS2 (Standard_False), myFlag (F), - myAlgo (A) + myAlgo (A), + myIsMultiThread(Standard_False) { LoadS1(Shape1); LoadS2(Shape2); @@ -321,7 +676,8 @@ BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape myIsInitS1 (Standard_False), myIsInitS2 (Standard_False), myFlag (F), - myAlgo (A) + myAlgo (A), + myIsMultiThread(Standard_False) { LoadS1(Shape1); LoadS2(Shape2); @@ -352,37 +708,133 @@ void BRepExtrema_DistShapeShape::LoadS2 (const TopoDS_Shape& Shape2) Decomposition (Shape2, myMapV2, myMapE2, myMapF2); } +//======================================================================= +//struct : TreatmentFunctor +//purpose : +//======================================================================= +struct TreatmentFunctor +{ + TreatmentFunctor(NCollection_Array1 >* theArrayOfArrays, + const Message_ProgressRange& theRange): + ArrayOfArrays(theArrayOfArrays), + SolutionsShape1(NULL), + SolutionsShape2(NULL), + Scope(theRange, "Search for the inner solid", theArrayOfArrays->Size()), + Ranges(0, theArrayOfArrays->Size() - 1), + DistRef(0), + InnerSol(NULL), + IsDone(NULL), + Mutex(NULL) + { + for (Standard_Integer i = 0; i < theArrayOfArrays->Size(); ++i) + { + Ranges.SetValue(i, Scope.Next()); + } + } + + void operator() (const Standard_Integer theIndex) const + { + const Standard_Real aTolerance = 0.001; + Message_ProgressScope aScope(Ranges[theIndex], NULL, ArrayOfArrays->Value(theIndex).Size()); + BRepClass3d_SolidClassifier aClassifier(Shape); + + for (Standard_Integer i = 0; i < ArrayOfArrays->Value(theIndex).Size(); i++) + { + if (!aScope.More()) + { + break; + } + aScope.Next(); + if (*IsDone) + { + break; + } + + const TopoDS_Vertex& aVertex = TopoDS::Vertex(ArrayOfArrays->Value(theIndex).Value(i)); + const gp_Pnt aPnt = BRep_Tool::Pnt(aVertex); + aClassifier.Perform(aPnt, aTolerance); + if (aClassifier.State() == TopAbs_IN) + { + Standard_Mutex::Sentry aLock(Mutex.get()); + *InnerSol = Standard_True; + *DistRef = 0.; + *IsDone = Standard_True; + BRepExtrema_SolutionElem aSolElem(0, aPnt, BRepExtrema_IsVertex, aVertex); + SolutionsShape1->Append(aSolElem); + SolutionsShape2->Append(aSolElem); + break; + } + } + } + + NCollection_Array1 >* ArrayOfArrays; + BRepExtrema_SeqOfSolution* SolutionsShape1; + BRepExtrema_SeqOfSolution* SolutionsShape2; + TopoDS_Shape Shape; + Message_ProgressScope Scope; + NCollection_Array1 Ranges; + Standard_Real* DistRef; + volatile Standard_Boolean* InnerSol; + volatile Standard_Boolean* IsDone; + Handle(Standard_HMutex) Mutex; +}; + //======================================================================= //function : SolidTreatment //purpose : //======================================================================= Standard_Boolean BRepExtrema_DistShapeShape::SolidTreatment(const TopoDS_Shape& theShape, - const TopTools_IndexedMapOfShape& theMap, + const TopTools_IndexedMapOfShape& theVertexMap, const Message_ProgressRange& theRange) { - BRepClass3d_SolidClassifier aClassifier(theShape); - const Standard_Real aTolerance = 0.001; - Message_ProgressScope aScope(theRange, NULL, theMap.Extent()); - for (Standard_Integer i = 1; i < theMap.Extent(); ++i) + const Standard_Integer aMapSize = theVertexMap.Extent(); + const Standard_Integer aMinTaskSize = 3; + const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool(); + const Standard_Integer aNbThreads = aThreadPool->NbThreads(); + Standard_Integer aNbTasks = aNbThreads * 10; + Standard_Integer aTaskSize = (Standard_Integer) Ceiling((double) aMapSize / aNbTasks); + if (aTaskSize < aMinTaskSize) { - aScope.Next(); - if (!aScope.More()) + aTaskSize = aMinTaskSize; + aNbTasks = (Standard_Integer) Ceiling((double) aMapSize / aTaskSize); + } + + NCollection_Array1< NCollection_Array1 > anArrayOfArray(0, aNbTasks - 1); + for (Standard_Integer anI = 1; anI <= aMapSize; ++anI) + { + Standard_Integer aVectIndex = (anI - 1) / aTaskSize; + Standard_Integer aShapeIndex = (anI - 1) % aTaskSize; + if (aShapeIndex == 0) { - return Standard_False; - } - const TopoDS_Vertex& aVertex = TopoDS::Vertex(theMap(i)); - const gp_Pnt& aPnt = BRep_Tool::Pnt(aVertex); - aClassifier.Perform(aPnt, aTolerance); - if (aClassifier.State() == TopAbs_IN) - { - myInnerSol = Standard_True; - myDistRef = 0.; - myIsDone = Standard_True; - BRepExtrema_SolutionElem Sol(0, aPnt, BRepExtrema_IsVertex, aVertex); - mySolutionsShape1.Append(Sol); - mySolutionsShape2.Append(Sol); - break; + Standard_Integer aVectorSize = aTaskSize; + Standard_Integer aTailSize = aMapSize - aVectIndex * aTaskSize; + if (aTailSize < aTaskSize) + { + aVectorSize = aTailSize; + } + anArrayOfArray[aVectIndex].Resize(0, aVectorSize - 1, Standard_False); } + anArrayOfArray[aVectIndex][aShapeIndex] = theVertexMap(anI); + } + + Message_ProgressScope aScope(theRange, "Solid treatment", aNbTasks); + TreatmentFunctor aFunctor(&anArrayOfArray, aScope.Next()); + aFunctor.SolutionsShape1 = &mySolutionsShape1; + aFunctor.SolutionsShape2 = &mySolutionsShape2; + aFunctor.Shape = theShape; + aFunctor.DistRef = &myDistRef; + aFunctor.InnerSol = &myInnerSol; + aFunctor.IsDone = &myIsDone; + if (myIsMultiThread) + { + aFunctor.Mutex.reset(new Standard_HMutex()); + } + + OSD_Parallel::For(0, aNbTasks, aFunctor, !myIsMultiThread); + + if (!aScope.More()) + { + return Standard_False; } return Standard_True; } @@ -394,22 +846,22 @@ Standard_Boolean BRepExtrema_DistShapeShape::SolidTreatment(const TopoDS_Shape& Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange& theRange) { - myIsDone=Standard_False; - myInnerSol=Standard_False; + myIsDone = Standard_False; + myInnerSol = Standard_False; mySolutionsShape1.Clear(); mySolutionsShape2.Clear(); - if ( myShape1.IsNull() || myShape2.IsNull() ) + if (myShape1.IsNull() || myShape2.IsNull()) return Standard_False; // Treatment of solids Standard_Boolean anIsSolid1 = (myShape1.ShapeType() == TopAbs_SOLID) || - (myShape1.ShapeType() == TopAbs_COMPSOLID); + (myShape1.ShapeType() == TopAbs_COMPSOLID); Standard_Boolean anIsSolid2 = (myShape2.ShapeType() == TopAbs_SOLID) || - (myShape2.ShapeType() == TopAbs_COMPSOLID); + (myShape2.ShapeType() == TopAbs_COMPSOLID); Standard_Integer aRootStepsNum = 9; // By num of DistanceMapMap calls - aRootStepsNum = anIsSolid1 ? aRootStepsNum+1 : aRootStepsNum; - aRootStepsNum = anIsSolid2 ? aRootStepsNum+1 : aRootStepsNum; + aRootStepsNum = anIsSolid1 ? aRootStepsNum + 1 : aRootStepsNum; + aRootStepsNum = anIsSolid2 ? aRootStepsNum + 1 : aRootStepsNum; Message_ProgressScope aRootScope(theRange, "calculating distance", aRootStepsNum); if (anIsSolid1) @@ -419,10 +871,10 @@ Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange return Standard_False; } } - + if (anIsSolid2 && (!myInnerSol)) { - if(!SolidTreatment(myShape2, myMapV1, aRootScope.Next())) + if (!SolidTreatment(myShape2, myMapV1, aRootScope.Next())) { return Standard_False; } @@ -432,9 +884,18 @@ Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange { if (!myIsInitS1) // rebuild cached data for 1st shape { - myBV1.Clear(); - myBE1.Clear(); - myBF1.Clear(); + if (!myMapV1.IsEmpty()) + { + myBV1.Resize(1, myMapV1.Extent(), Standard_False); + } + if (!myMapE1.IsEmpty()) + { + myBE1.Resize(1, myMapE1.Extent(), Standard_False); + } + if (!myMapF1.IsEmpty()) + { + myBF1.Resize(1, myMapF1.Extent(), Standard_False); + } BoxCalculation (myMapV1, myBV1); BoxCalculation (myMapE1, myBE1); @@ -445,9 +906,18 @@ Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange if (!myIsInitS2) // rebuild cached data for 2nd shape { - myBV2.Clear(); - myBE2.Clear(); - myBF2.Clear(); + if (!myMapV2.IsEmpty()) + { + myBV2.Resize(1, myMapV2.Extent(), Standard_False); + } + if (!myMapE2.IsEmpty()) + { + myBE2.Resize(1, myMapE2.Extent(), Standard_False); + } + if (!myMapF2.IsEmpty()) + { + myBF2.Resize(1, myMapF2.Extent(), Standard_False); + } BoxCalculation (myMapV2, myBV2); BoxCalculation (myMapE2, myBE2); @@ -458,54 +928,54 @@ Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange if (myMapV1.Extent() && myMapV2.Extent()) { - TopoDS_Vertex V1 = TopoDS::Vertex(myMapV1(1)); - TopoDS_Vertex V2 = TopoDS::Vertex(myMapV2(1)); + const TopoDS_Vertex& V1 = TopoDS::Vertex(myMapV1(1)); + const TopoDS_Vertex& V2 = TopoDS::Vertex(myMapV2(1)); myDistRef = DistanceInitiale(V1, V2); } else - myDistRef= 1.e30; //szv:!!! + myDistRef = 1.e30; //szv:!!! - if(!DistanceVertVert(myMapV1, myMapV2, aRootScope.Next())) + if (!DistanceVertVert(myMapV1, myMapV2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapV1, myMapE2, myBV1, myBE2, aRootScope.Next())) + if (!DistanceMapMap(myMapV1, myMapE2, myBV1, myBE2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapE1, myMapV2, myBE1, myBV2, aRootScope.Next())) + if (!DistanceMapMap(myMapE1, myMapV2, myBE1, myBV2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapV1, myMapF2, myBV1, myBF2, aRootScope.Next())) + if (!DistanceMapMap(myMapV1, myMapF2, myBV1, myBF2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapF1, myMapV2, myBF1, myBV2, aRootScope.Next())) + if (!DistanceMapMap(myMapF1, myMapV2, myBF1, myBV2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapE1, myMapE2, myBE1, myBE2, aRootScope.Next())) + if (!DistanceMapMap(myMapE1, myMapE2, myBE1, myBE2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapE1, myMapF2, myBE1, myBF2, aRootScope.Next())) + if (!DistanceMapMap(myMapE1, myMapF2, myBE1, myBF2, aRootScope.Next())) { return Standard_False; } - if(!DistanceMapMap (myMapF1, myMapE2, myBF1, myBE2, aRootScope.Next())) + if (!DistanceMapMap(myMapF1, myMapE2, myBF1, myBE2, aRootScope.Next())) { return Standard_False; } - if (fabs (myDistRef) > myEps) + if (Abs(myDistRef) > myEps) { - if(!DistanceMapMap (myMapF1, myMapF2, myBF1, myBF2, aRootScope.Next())) + if (!DistanceMapMap(myMapF1, myMapF2, myBF1, myBF2, aRootScope.Next())) { return Standard_False; } } - + // Modified by Sergey KHROMOV - Tue Mar 6 11:55:03 2001 Begin Standard_Integer i = 1; for (; i <= mySolutionsShape1.Length(); i++) @@ -515,7 +985,7 @@ Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange mySolutionsShape2.Remove(i); } // Modified by Sergey KHROMOV - Tue Mar 6 11:55:04 2001 End - myIsDone = ( mySolutionsShape1.Length() > 0 ); + myIsDone = (mySolutionsShape1.Length() > 0); } return myIsDone; diff --git a/src/BRepExtrema/BRepExtrema_DistShapeShape.hxx b/src/BRepExtrema/BRepExtrema_DistShapeShape.hxx index 8b3450e074..67269dbd62 100644 --- a/src/BRepExtrema/BRepExtrema_DistShapeShape.hxx +++ b/src/BRepExtrema/BRepExtrema_DistShapeShape.hxx @@ -14,7 +14,7 @@ #ifndef _BRepExtrema_DistShapeShape_HeaderFile #define _BRepExtrema_DistShapeShape_HeaderFile -#include +#include #include #include #include @@ -28,24 +28,37 @@ #include #include -//! This class provides tools to compute minimum distance
-//! between two Shapes (Compound,CompSolid, Solid, Shell, Face, Wire, Edge, Vertex).
+//! This class provides tools to compute minimum distance +//! between two Shapes (Compound,CompSolid, Solid, Shell, Face, Wire, Edge, Vertex). class BRepExtrema_DistShapeShape { public: DEFINE_STANDARD_ALLOC - //! create empty tool
+ //! create empty tool Standard_EXPORT BRepExtrema_DistShapeShape(); - //! computation of the minimum distance (value and pair of points) using default deflection
- //! Default value is Precision::Confusion().
+ + //! create tool and computation of the minimum distance (value and pair of points) + //! using default deflection in single thread mode.
+ //! Default deflection value is Precision::Confusion().
+ //! @param Shape1 - the first shape for distance computation + //! @param Shape2 - the second shape for distance computation + //! @param F and @param A are not used in computation and are obsolete. + //! @param theRange - the progress indicator of algorithm Standard_EXPORT BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1, const TopoDS_Shape& Shape2, const Extrema_ExtFlag F = Extrema_ExtFlag_MINMAX, const Extrema_ExtAlgo A = Extrema_ExtAlgo_Grad, const Message_ProgressRange& theRange = Message_ProgressRange()); - //! create tool and load both shapes into it
+ //! create tool and computation of the minimum distance + //! (value and pair of points) in single thread mode.
+ //! Default deflection value is Precision::Confusion().
+ //! @param Shape1 - the first shape for distance computation + //! @param Shape2 - the second shape for distance computation + //! @param theDeflection - the presition of distance computation + //! @param F and @param A are not used in computation and are obsolete. + //! @param theRange - the progress indicator of algorithm Standard_EXPORT BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1, const TopoDS_Shape& Shape2, const Standard_Real theDeflection, @@ -53,49 +66,60 @@ class BRepExtrema_DistShapeShape const Extrema_ExtAlgo A = Extrema_ExtAlgo_Grad, const Message_ProgressRange& theRange = Message_ProgressRange()); + //! Sets deflection to computation of the minimum distance
void SetDeflection(const Standard_Real theDeflection) { myEps = theDeflection; } + //! load first shape into extrema
Standard_EXPORT void LoadS1(const TopoDS_Shape& Shape1); + //! load second shape into extrema
Standard_EXPORT void LoadS2(const TopoDS_Shape& Shape1); + //! computation of the minimum distance (value and
//! couple of points). Parameter theDeflection is used
//! to specify a maximum deviation of extreme distances
//! from the minimum one.
//! Returns IsDone status.
- //! theProgress - progress indicator of algorithm + //! theRange - the progress indicator of algorithm Standard_EXPORT Standard_Boolean Perform(const Message_ProgressRange& theRange = Message_ProgressRange()); + //! True if the minimum distance is found.
Standard_Boolean IsDone() const { return myIsDone; } + //! Returns the number of solutions satisfying the minimum distance.
Standard_Integer NbSolution() const { return mySolutionsShape1.Length(); } + //! Returns the value of the minimum distance.
Standard_EXPORT Standard_Real Value() const; + //! True if one of the shapes is a solid and the other shape
//! is completely or partially inside the solid.
Standard_Boolean InnerSolution() const { return myInnerSol; } + //! Returns the Point corresponding to the th solution on the first Shape
const gp_Pnt & PointOnShape1(const Standard_Integer N) const { return mySolutionsShape1.Value(N).Point(); } + //! Returns the Point corresponding to the th solution on the second Shape
const gp_Pnt & PointOnShape2(const Standard_Integer N) const { return mySolutionsShape2.Value(N).Point(); } + //! gives the type of the support where the Nth solution on the first shape is situated:
//! IsVertex => the Nth solution on the first shape is a Vertex
//! IsOnEdge => the Nth soluion on the first shape is on a Edge
@@ -105,6 +129,7 @@ class BRepExtrema_DistShapeShape { return mySolutionsShape1.Value(N).SupportKind(); } + //! gives the type of the support where the Nth solution on the second shape is situated:
//! IsVertex => the Nth solution on the second shape is a Vertex
//! IsOnEdge => the Nth soluion on the secondt shape is on a Edge
@@ -114,44 +139,68 @@ class BRepExtrema_DistShapeShape { return mySolutionsShape2.Value(N).SupportKind(); } + //! gives the support where the Nth solution on the first shape is situated.
//! This support can be a Vertex, an Edge or a Face.
Standard_EXPORT TopoDS_Shape SupportOnShape1(const Standard_Integer N) const; + //! gives the support where the Nth solution on the second shape is situated.
//! This support can be a Vertex, an Edge or a Face.
Standard_EXPORT TopoDS_Shape SupportOnShape2(const Standard_Integer N) const; + //! gives the corresponding parameter t if the Nth solution
//! is situated on an Edge of the first shape
Standard_EXPORT void ParOnEdgeS1(const Standard_Integer N,Standard_Real& t) const; + //! gives the corresponding parameter t if the Nth solution
//! is situated on an Edge of the first shape
Standard_EXPORT void ParOnEdgeS2(const Standard_Integer N,Standard_Real& t) const; + //! gives the corresponding parameters (U,V) if the Nth solution
//! is situated on an face of the first shape
Standard_EXPORT void ParOnFaceS1(const Standard_Integer N,Standard_Real& u,Standard_Real& v) const; + //! gives the corresponding parameters (U,V) if the Nth solution
//! is situated on an Face of the second shape
Standard_EXPORT void ParOnFaceS2(const Standard_Integer N,Standard_Real& u,Standard_Real& v) const; + //! Prints on the stream o information on the current state of the object.
Standard_EXPORT void Dump(Standard_OStream& o) const; + //! Sets unused parameter + //! Obsolete void SetFlag(const Extrema_ExtFlag F) { myFlag = F; } + //! Sets unused parameter + //! Obsolete void SetAlgo(const Extrema_ExtAlgo A) { myAlgo = A; } + //! If isMultiThread == Standard_True then computation will be performed in parallel. + void SetMultiThread(Standard_Boolean theIsMultiThread) + { + myIsMultiThread = theIsMultiThread; + } + + //! Returns Standard_True then computation will be performed in parallel + //! Default value is Standard_False + Standard_Boolean IsMultiThread() const + { + return myIsMultiThread; + } + private: //! computes the minimum distance between two maps of shapes (Face,Edge,Vertex)
Standard_Boolean DistanceMapMap(const TopTools_IndexedMapOfShape& Map1, const TopTools_IndexedMapOfShape& Map2, - const Bnd_SeqOfBox& LBox1, - const Bnd_SeqOfBox& LBox2, + const Bnd_Array1OfBox& LBox1, + const Bnd_Array1OfBox& LBox2, const Message_ProgressRange& theRange); //! computes the minimum distance between two maps of vertices
@@ -183,12 +232,13 @@ private: Standard_Boolean myIsInitS2; Extrema_ExtFlag myFlag; Extrema_ExtAlgo myAlgo; - Bnd_SeqOfBox myBV1; - Bnd_SeqOfBox myBV2; - Bnd_SeqOfBox myBE1; - Bnd_SeqOfBox myBE2; - Bnd_SeqOfBox myBF1; - Bnd_SeqOfBox myBF2; + Bnd_Array1OfBox myBV1; + Bnd_Array1OfBox myBV2; + Bnd_Array1OfBox myBE1; + Bnd_Array1OfBox myBE2; + Bnd_Array1OfBox myBF1; + Bnd_Array1OfBox myBF2; + Standard_Boolean myIsMultiThread; }; #endif diff --git a/src/BRepExtrema/BRepExtrema_DistanceSS.cxx b/src/BRepExtrema/BRepExtrema_DistanceSS.cxx index 61773dd806..7cbd701f3b 100644 --- a/src/BRepExtrema/BRepExtrema_DistanceSS.cxx +++ b/src/BRepExtrema/BRepExtrema_DistanceSS.cxx @@ -64,11 +64,13 @@ //------------------------------------------------------------------------------ static Standard_Boolean TRI_SOLUTION (const BRepExtrema_SeqOfSolution& SeqSol, const gp_Pnt& Pt) { - const Standard_Integer Nbsol = SeqSol.Length(); - for (Standard_Integer i = 1; i <= Nbsol; i++) + for (BRepExtrema_SeqOfSolution::iterator anIt = SeqSol.begin(); anIt != SeqSol.end(); anIt++) { - const Standard_Real dst = SeqSol.Value(i).Point().Distance(Pt); - if (dst <= Precision::Confusion()) return Standard_False; + const Standard_Real dst = anIt->Point().Distance(Pt); + if (dst <= Precision::Confusion()) + { + return Standard_False; + } } return Standard_True; } @@ -83,15 +85,16 @@ static void MIN_SOLUTION (const BRepExtrema_SeqOfSolution& SeqSol1, BRepExtrema_SeqOfSolution& seqSol1, BRepExtrema_SeqOfSolution& seqSol2) { - const Standard_Integer nbSol = SeqSol1.Length(); - for (Standard_Integer i = 1; i <= nbSol; i++) + for (BRepExtrema_SeqOfSolution::iterator anIt1 = SeqSol1.begin(), anIt2 = SeqSol2.begin(); + anIt1 != SeqSol1.end(); + anIt1++, anIt2++) { - const Standard_Real dst1 = SeqSol1.Value(i).Dist(); + const Standard_Real dst1 = anIt1->Dist(); if (fabs(dst1 - DstRef) < Eps) - { - seqSol1.Append(SeqSol1.Value(i)); - seqSol2.Append(SeqSol2.Value(i)); - } + { + seqSol1.Append(*anIt1); + seqSol2.Append(*anIt2); + } } } diff --git a/src/BRepTest/BRepTest_ExtremaCommands.cxx b/src/BRepTest/BRepTest_ExtremaCommands.cxx index 0fa44321d1..3be19ae908 100644 --- a/src/BRepTest/BRepTest_ExtremaCommands.cxx +++ b/src/BRepTest/BRepTest_ExtremaCommands.cxx @@ -64,19 +64,45 @@ static Standard_Integer distance (Draw_Interpretor& di, static Standard_Integer distmini(Draw_Interpretor& di, Standard_Integer n, const char** a) { - if (n != 4 && n != 5 ) + if (n < 4 || n > 6) + { return 1; + } const char *ns1 = (a[2]), *ns2 = (a[3]), *ns0 = (a[1]); TopoDS_Shape S1(DBRep::Get(ns1)), S2(DBRep::Get(ns2)); Standard_Real aDeflection = Precision::Confusion(); - if (n == 5) + Standard_Integer anIndex = 4; + if (n >= 5 && a[4][0] != '-') + { aDeflection = Draw::Atof(a[4]); + anIndex++; + } + + Standard_Boolean isMultiThread = Standard_False; + for (Standard_Integer anI = anIndex; anI < n; anI++) + { + TCollection_AsciiString anArg(a[anI]); + anArg.LowerCase(); + if (anArg == "-parallel") + { + isMultiThread = Standard_True; + } + else + { + di << "Syntax error at '" << anArg << "'"; + return 1; + } + } Handle(Draw_ProgressIndicator) aProgress = new Draw_ProgressIndicator(di, 1); - BRepExtrema_DistShapeShape dst(S1 ,S2, aDeflection, Extrema_ExtFlag_MINMAX, - Extrema_ExtAlgo_Grad, aProgress->Start()); + BRepExtrema_DistShapeShape dst; + dst.LoadS1(S1); + dst.LoadS2(S2); + dst.SetDeflection(aDeflection); + dst.SetMultiThread(isMultiThread); + dst.Perform(aProgress->Start()); if (dst.IsDone()) { @@ -412,7 +438,10 @@ void BRepTest::ExtremaCommands (Draw_Interpretor& theCommands) aGroup); theCommands.Add ("distmini", - "distmini name Shape1 Shape2 [deflection]", + "distmini name Shape1 Shape2 [deflection] [-parallel]", + "\n\t\t: Searches minimal distance between two shapes." + "\n\t\t: The option is:" + "\n\t\t: -parallel : calculate distance in multithreaded mode" __FILE__, distmini, aGroup); diff --git a/tests/perf/modalg/bug32539_1 b/tests/perf/modalg/bug32539_1 new file mode 100644 index 0000000000..6c7a4333c3 --- /dev/null +++ b/tests/perf/modalg/bug32539_1 @@ -0,0 +1,61 @@ +puts "==========" +puts "0032539: Modeling Algorithms - Parallelize BRepExtrema_DistShapeShape algorithm" +puts "==========" +puts "" + +# prepare +pload XDE OCAF +XOpen [locate_data_file bug32539_1.xbf] XB +XGetShape s1 XB 0:1:1:2 +XGetShape s2 XB 0:1:1:4 +Close XB +btranslate s1 0 0 60 +brotate s2 0 0 0 0 0 1 90 + +# multi-thread +dchrono p reset; dchrono p start; +set pres [distmini res s1 s2 -parallel] +dchrono p stop; +regexp {Elapsed time: +([-0-9.+eE]+) Hours +([-0-9.+eE]+) Minutes +([-0-9.+eE]+) Seconds} [dchrono p show] full p_Hours p_Minutes p_Seconds +set p_Time [expr ${p_Hours}*60.*60. + ${p_Minutes}*60. + ${p_Seconds} ] +puts "multithreaded time: $p_Time" + +set pdist [dval res_val] + +vclear +vclose ALL +vinit v1/v1 +vdisplay -dispMode 1 s1 s2 res res2 res3 res4 +vfit +checkview -screenshot -3d -path ${imagedir}/${test_image}_multi.png + +#single-thread +dchrono s reset; dchrono s start; +set cres [distmini res s1 s2] +dchrono s stop; +regexp {Elapsed time: +([-0-9.+eE]+) Hours +([-0-9.+eE]+) Minutes +([-0-9.+eE]+) Seconds} [dchrono s show] full s_Hours s_Minutes s_Seconds +set s_Time [expr ${s_Hours}*60.*60. + ${s_Minutes}*60. + ${s_Seconds} ] +puts "single-threaded time: $s_Time" + +set sdist [dval res_val] + +vclear +vclose ALL +vinit v2/v2 +vdisplay -dispMode 1 s1 s2 res res2 res3 res4 +vfit +checkview -screenshot -3d -path ${imagedir}/${test_image}_single.png + +# compare +set ratio [expr ${s_Time}/${p_Time} ] +puts "acceleration in multi-threaded work: $ratio" + +if {[string compare $cres $pres] != 0} { + puts "Error: different result between single-thread and multi-thread mode" +} + +if {[expr abs(${sdist} - ${pdist})] > 1E-13} { + puts "Error: different distance between single-thread and multi-thread mode" +} + + diff --git a/tests/perf/modalg/bug32539_2 b/tests/perf/modalg/bug32539_2 new file mode 100644 index 0000000000..6d9edaf06d --- /dev/null +++ b/tests/perf/modalg/bug32539_2 @@ -0,0 +1,54 @@ +puts "==========" +puts "0032539: Modeling Algorithms - Parallelize BRepExtrema_DistShapeShape algorithm" +puts "==========" +puts "" + +# prepare +restore [locate_data_file 5000-12.brep] s1 +restore [locate_data_file BPLSEITLI.brep] s2 + +# multi-thread +dchrono p reset; dchrono p start; +set pres [distmini res s1 s2 -parallel] +dchrono p stop; +regexp {Elapsed time: +([-0-9.+eE]+) Hours +([-0-9.+eE]+) Minutes +([-0-9.+eE]+) Seconds} [dchrono p show] full p_Hours p_Minutes p_Seconds +set p_Time [expr ${p_Hours}*60.*60. + ${p_Minutes}*60. + ${p_Seconds} ] +puts "multithreaded time: $p_Time" + +set pdist [dval res_val] + +vclear +vclose ALL +vinit v1/v1 +vdisplay -dispMode 1 s1 s2 res +vzoom 2 +checkview -screenshot -3d -path ${imagedir}/${test_image}_multi.png + +#single-thread +dchrono s reset; dchrono s start; +set cres [distmini res s1 s2] +dchrono s stop; +regexp {Elapsed time: +([-0-9.+eE]+) Hours +([-0-9.+eE]+) Minutes +([-0-9.+eE]+) Seconds} [dchrono s show] full s_Hours s_Minutes s_Seconds +set s_Time [expr ${s_Hours}*60.*60. + ${s_Minutes}*60. + ${s_Seconds} ] +puts "single-threaded time: $s_Time" + +set sdist [dval res_val] + +vclear +vclose ALL +vinit v2/v2 +vdisplay -dispMode 1 s1 s2 res +vzoom 2 +checkview -screenshot -3d -path ${imagedir}/${test_image}_single.png + +# compare +set ratio [expr ${s_Time}/${p_Time} ] +puts "acceleration in multi-threaded work: $ratio" + +if {[string compare $cres $pres] != 0} { + puts "Error: different result between single-thread and multi-thread mode" +} + +if {[expr abs(${sdist} - ${pdist})] > 1E-13} { + puts "Error: different distance between single-thread and multi-thread mode" +}