Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
c5f20409cThis file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1996-04-22
// Created by: Herve LOUESSARD
// Copyright (c) 1996-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
// Modified: Mps(10-04-97) portage WNT
#include <BRepExtrema_DistShapeShape.hxx>
#include <Standard_OStream.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <BRepBndLib.hxx>
#include <Bnd_Box.hxx>
#include <TopExp.hxx>
#include <BRepExtrema_DistanceSS.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <Precision.hxx>
#include <BRepExtrema_UnCompatibleShape.hxx>
#include <BRep_Tool.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <NCollection_Vector.hxx>
#include <OSD_Parallel.hxx>
#include <StdFail_NotDone.hxx>
#include <algorithm>
namespace
{
static void Decomposition(const TopoDS_Shape& S,
TopTools_IndexedMapOfShape& MapV,
TopTools_IndexedMapOfShape& MapE,
TopTools_IndexedMapOfShape& MapF)
{
MapV.Clear();
MapE.Clear();
MapF.Clear();
TopExp::MapShapes(S, TopAbs_VERTEX, MapV);
TopExp::MapShapes(S, TopAbs_EDGE, MapE);
TopExp::MapShapes(S, TopAbs_FACE, MapF);
}
static void BoxCalculation(const TopTools_IndexedMapOfShape& Map, Bnd_Array1OfBox& SBox)
{
for (Standard_Integer i = 1; i <= Map.Extent(); i++)
{
Bnd_Box box;
BRepBndLib::Add(Map(i), box);
SBox[i] = box;
}
}
inline Standard_Real DistanceInitiale(const TopoDS_Vertex& V1, const TopoDS_Vertex& V2)
{
return (BRep_Tool::Pnt(V1).Distance(BRep_Tool::Pnt(V2)));
}
//! Pair of objects to check extrema.
struct BRepExtrema_CheckPair
{
Standard_Integer Index1; //!< Index of the 1st sub-shape
Standard_Integer Index2; //!< Index of the 2nd sub-shape
Standard_Real Distance; //!< Distance between sub-shapes
//! Uninitialized constructor for collection.
BRepExtrema_CheckPair()
: Index1(0),
Index2(0),
Distance(0.0)
{
}
//! Creates new pair of sub-shapes.
BRepExtrema_CheckPair(Standard_Integer theIndex1,
Standard_Integer theIndex2,
Standard_Real theDistance)
: Index1(theIndex1),
Index2(theIndex2),
Distance(theDistance)
{
}
};
// Used by std::sort function
static Standard_Boolean BRepExtrema_CheckPair_Comparator(const BRepExtrema_CheckPair& theLeft,
const BRepExtrema_CheckPair& theRight)
{
return (theLeft.Distance < theRight.Distance);
}
} // namespace
//=======================================================================
// struct : IndexBand
// purpose :
//=======================================================================
struct IndexBand
{
IndexBand()
: First(0),
Last(0)
{
}
IndexBand(Standard_Integer theFirtsIndex, Standard_Integer theLastIndex)
: First(theFirtsIndex),
Last(theLastIndex)
{
}
Standard_Integer First;
Standard_Integer Last;
};
//=======================================================================
// 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<BRepExtrema_SeqOfSolution> Shape1;
NCollection_Array1<BRepExtrema_SeqOfSolution> Shape2;
NCollection_Array1<Standard_Real> Dist;
};
//=======================================================================
// struct : VertexFunctor
// purpose :
//=======================================================================
struct VertexFunctor
{
VertexFunctor(NCollection_Array1<IndexBand>* 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())
{
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;
}
}
}
}
}
}
NCollection_Array1<IndexBand>* BandArray;
mutable ThreadSolution Solution;
const TopTools_IndexedMapOfShape* Map1;
const TopTools_IndexedMapOfShape* Map2;
Message_ProgressScope Scope;
NCollection_Array1<Message_ProgressRange> Ranges;
Standard_Real Eps;
Standard_Real StartDist;
};
//=================================================================================================
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)
{
aTaskSize = aMinTaskSize;
aNbTasks = (Standard_Integer)Ceiling((double)aCount1 / aTaskSize);
}
Standard_Integer aFirstIndex(1);
NCollection_Array1<IndexBand> aBandArray(0, aNbTasks - 1);
Message_ProgressScope aDistScope(theRange, NULL, 1);
for (Standard_Integer anI = 0; anI < aBandArray.Size(); ++anI)
{
if (aCount1 < aFirstIndex + aTaskSize - 1)
{
aTaskSize = aCount1 - aFirstIndex + 1;
}
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)
{
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]);
myDistRef = aDist;
}
}
return Standard_True;
}
//=======================================================================
// struct : DistanceFunctor
// purpose :
//=======================================================================
struct DistanceFunctor
{
DistanceFunctor(NCollection_Array1<NCollection_Array1<BRepExtrema_CheckPair>>* 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<NCollection_Array1<BRepExtrema_CheckPair>>* 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<Message_ProgressRange> Ranges;
Standard_Real Eps;
Standard_Real StartDist;
};
//=======================================================================
// struct : DistancePairFunctor
// purpose :
//=======================================================================
struct DistancePairFunctor
{
DistancePairFunctor(NCollection_Array1<IndexBand>* 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<IndexBand>* BandArray;
mutable NCollection_Array1<NCollection_Vector<BRepExtrema_CheckPair>> PairList;
const Bnd_Array1OfBox* LBox1;
const Bnd_Array1OfBox* LBox2;
Message_ProgressScope Scope;
NCollection_Array1<Message_ProgressRange> Ranges;
Standard_Real DistRef;
Standard_Real Eps;
};
//=================================================================================================
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();
if (aCount1 == 0 || aCount2 == 0)
{
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<IndexBand> aBandArray(0, aNbPairTasks - 1);
for (Standard_Integer anI = 0; anI < aBandArray.Size(); ++anI)
{
if (aCount1 < aFirstIndex + aPairTaskSize - 1)
{
aPairTaskSize = aCount1 - aFirstIndex + 1;
}
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<BRepExtrema_CheckPair> 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)
{
aPairList[aListIndex] = aPairFunctor.PairList[anI][aJ];
++aListIndex;
}
}
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<NCollection_Array1<BRepExtrema_CheckPair>> 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)
{
Standard_Integer aVectorSize = aTaskSize;
if (aJ >= aLastRowLimit)
{
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;
}
}
}
return Standard_True;
}
//=================================================================================================
BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape()
: myDistRef(0.0),
myIsDone(Standard_False),
myInnerSol(Standard_False),
myEps(Precision::Confusion()),
myIsInitS1(Standard_False),
myIsInitS2(Standard_False),
myFlag(Extrema_ExtFlag_MINMAX),
myAlgo(Extrema_ExtAlgo_Grad),
myIsMultiThread(Standard_False)
{
}
//=================================================================================================
BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,
const TopoDS_Shape& Shape2,
const Extrema_ExtFlag F,
const Extrema_ExtAlgo A,
const Message_ProgressRange& theRange)
: myDistRef(0.0),
myIsDone(Standard_False),
myInnerSol(Standard_False),
myEps(Precision::Confusion()),
myIsInitS1(Standard_False),
myIsInitS2(Standard_False),
myFlag(F),
myAlgo(A),
myIsMultiThread(Standard_False)
{
LoadS1(Shape1);
LoadS2(Shape2);
Perform(theRange);
}
//=================================================================================================
BRepExtrema_DistShapeShape::BRepExtrema_DistShapeShape(const TopoDS_Shape& Shape1,
const TopoDS_Shape& Shape2,
const Standard_Real theDeflection,
const Extrema_ExtFlag F,
const Extrema_ExtAlgo A,
const Message_ProgressRange& theRange)
: myDistRef(0.0),
myIsDone(Standard_False),
myInnerSol(Standard_False),
myEps(theDeflection),
myIsInitS1(Standard_False),
myIsInitS2(Standard_False),
myFlag(F),
myAlgo(A),
myIsMultiThread(Standard_False)
{
LoadS1(Shape1);
LoadS2(Shape2);
Perform(theRange);
}
//=================================================================================================
void BRepExtrema_DistShapeShape::LoadS1(const TopoDS_Shape& Shape1)
{
myShape1 = Shape1;
myIsInitS1 = Standard_False;
Decomposition(Shape1, myMapV1, myMapE1, myMapF1);
}
//=================================================================================================
void BRepExtrema_DistShapeShape::LoadS2(const TopoDS_Shape& Shape2)
{
myShape2 = Shape2;
myIsInitS2 = Standard_False;
Decomposition(Shape2, myMapV2, myMapE2, myMapF2);
}
//=======================================================================
// struct : TreatmentFunctor
// purpose :
//=======================================================================
struct TreatmentFunctor
{
TreatmentFunctor(NCollection_Array1<NCollection_Array1<TopoDS_Shape>>* 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<NCollection_Array1<TopoDS_Shape>>* ArrayOfArrays;
BRepExtrema_SeqOfSolution* SolutionsShape1;
BRepExtrema_SeqOfSolution* SolutionsShape2;
TopoDS_Shape Shape;
Message_ProgressScope Scope;
NCollection_Array1<Message_ProgressRange> Ranges;
Standard_Real* DistRef;
volatile Standard_Boolean* InnerSol;
volatile Standard_Boolean* IsDone;
Handle(Standard_HMutex) Mutex;
};
//=================================================================================================
Standard_Boolean BRepExtrema_DistShapeShape::SolidTreatment(
const TopoDS_Shape& theShape,
const TopTools_IndexedMapOfShape& theVertexMap,
const Message_ProgressRange& theRange)
{
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)
{
aTaskSize = aMinTaskSize;
aNbTasks = (Standard_Integer)Ceiling((double)aMapSize / aTaskSize);
}
NCollection_Array1<NCollection_Array1<TopoDS_Shape>> 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)
{
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;
}
//=================================================================================================
Standard_Boolean BRepExtrema_DistShapeShape::Perform(const Message_ProgressRange& theRange)
{
myIsDone = Standard_False;
myInnerSol = Standard_False;
mySolutionsShape1.Clear();
mySolutionsShape2.Clear();
if (myShape1.IsNull() || myShape2.IsNull())
return Standard_False;
// Treatment of solids
Standard_Boolean anIsSolid1 =
(myShape1.ShapeType() == TopAbs_SOLID) || (myShape1.ShapeType() == TopAbs_COMPSOLID);
Standard_Boolean anIsSolid2 =
(myShape2.ShapeType() == TopAbs_SOLID) || (myShape2.ShapeType() == TopAbs_COMPSOLID);
Standard_Integer aRootStepsNum = 9; // By num of DistanceMapMap calls
aRootStepsNum = anIsSolid1 ? aRootStepsNum + 1 : aRootStepsNum;
aRootStepsNum = anIsSolid2 ? aRootStepsNum + 1 : aRootStepsNum;
Message_ProgressScope aRootScope(theRange, "calculating distance", aRootStepsNum);
if (anIsSolid1)
{
if (!SolidTreatment(myShape1, myMapV2, aRootScope.Next()))
{
return Standard_False;
}
}
if (anIsSolid2 && (!myInnerSol))
{
if (!SolidTreatment(myShape2, myMapV1, aRootScope.Next()))
{
return Standard_False;
}
}
if (!myInnerSol)
{
if (!myIsInitS1) // rebuild cached data for 1st shape
{
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);
BoxCalculation(myMapF1, myBF1);
myIsInitS1 = Standard_True;
}
if (!myIsInitS2) // rebuild cached data for 2nd shape
{
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);
BoxCalculation(myMapF2, myBF2);
myIsInitS2 = Standard_True;
}
if (myMapV1.Extent() && myMapV2.Extent())
{
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:!!!
if (!DistanceVertVert(myMapV1, myMapV2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapV1, myMapE2, myBV1, myBE2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapE1, myMapV2, myBE1, myBV2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapV1, myMapF2, myBV1, myBF2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapF1, myMapV2, myBF1, myBV2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapE1, myMapE2, myBE1, myBE2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapE1, myMapF2, myBE1, myBF2, aRootScope.Next()))
{
return Standard_False;
}
if (!DistanceMapMap(myMapF1, myMapE2, myBF1, myBE2, aRootScope.Next()))
{
return Standard_False;
}
if (Abs(myDistRef) > myEps)
{
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++)
if (mySolutionsShape1.Value(i).Dist() > myDistRef + myEps)
{
mySolutionsShape1.Remove(i);
mySolutionsShape2.Remove(i);
}
// Modified by Sergey KHROMOV - Tue Mar 6 11:55:04 2001 End
myIsDone = (mySolutionsShape1.Length() > 0);
}
return myIsDone;
}
//=================================================================================================
Standard_Real BRepExtrema_DistShapeShape::Value() const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::Value: There's no solution ");
return myDistRef;
}
//=================================================================================================
TopoDS_Shape BRepExtrema_DistShapeShape::SupportOnShape1(const Standard_Integer N) const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::SupportOnShape1: There's no solution ");
const BRepExtrema_SolutionElem& sol = mySolutionsShape1.Value(N);
switch (sol.SupportKind())
{
case BRepExtrema_IsVertex:
return sol.Vertex();
case BRepExtrema_IsOnEdge:
return sol.Edge();
case BRepExtrema_IsInFace:
return sol.Face();
}
return TopoDS_Shape();
}
//=================================================================================================
TopoDS_Shape BRepExtrema_DistShapeShape::SupportOnShape2(const Standard_Integer N) const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::SupportOnShape2: There's no solution ");
const BRepExtrema_SolutionElem& sol = mySolutionsShape2.Value(N);
switch (sol.SupportKind())
{
case BRepExtrema_IsVertex:
return sol.Vertex();
case BRepExtrema_IsOnEdge:
return sol.Edge();
case BRepExtrema_IsInFace:
return sol.Face();
}
return TopoDS_Shape();
}
//=================================================================================================
void BRepExtrema_DistShapeShape::ParOnEdgeS1(const Standard_Integer N, Standard_Real& t) const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::ParOnEdgeS1: There's no solution");
const BRepExtrema_SolutionElem& sol = mySolutionsShape1.Value(N);
if (sol.SupportKind() != BRepExtrema_IsOnEdge)
throw BRepExtrema_UnCompatibleShape(
"BRepExtrema_DistShapeShape::ParOnEdgeS1: ParOnEdgeS1 is impossible without EDGE");
sol.EdgeParameter(t);
}
//=================================================================================================
void BRepExtrema_DistShapeShape::ParOnEdgeS2(const Standard_Integer N, Standard_Real& t) const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::ParOnEdgeS2: There's no solution");
const BRepExtrema_SolutionElem& sol = mySolutionsShape2.Value(N);
if (sol.SupportKind() != BRepExtrema_IsOnEdge)
throw BRepExtrema_UnCompatibleShape(
"BRepExtrema_DistShapeShape::ParOnEdgeS2: ParOnEdgeS2 is impossible without EDGE");
sol.EdgeParameter(t);
}
//=================================================================================================
void BRepExtrema_DistShapeShape::ParOnFaceS1(const Standard_Integer N,
Standard_Real& u,
Standard_Real& v) const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::ParOnFaceS1: There's no solution");
const BRepExtrema_SolutionElem& sol = mySolutionsShape1.Value(N);
if (sol.SupportKind() != BRepExtrema_IsInFace)
throw BRepExtrema_UnCompatibleShape(
"BRepExtrema_DistShapeShape::ParOnFaceS1: ParOnFaceS1 is impossible without FACE");
sol.FaceParameter(u, v);
}
//=================================================================================================
void BRepExtrema_DistShapeShape::ParOnFaceS2(const Standard_Integer N,
Standard_Real& u,
Standard_Real& v) const
{
if (!myIsDone)
throw StdFail_NotDone("BRepExtrema_DistShapeShape::ParOnFaceS2: There's no solution");
const BRepExtrema_SolutionElem& sol = mySolutionsShape2.Value(N);
if (sol.SupportKind() != BRepExtrema_IsInFace)
throw BRepExtrema_UnCompatibleShape(
"BRepExtrema_DistShapeShape::ParOnFaceS2:ParOnFaceS2 is impossible without FACE ");
sol.FaceParameter(u, v);
}
//=================================================================================================
void BRepExtrema_DistShapeShape::Dump(Standard_OStream& o) const
{
Standard_Integer i;
Standard_Real r1, r2;
o << "the distance value is : " << Value() << std::endl;
o << "the number of solutions is :" << NbSolution() << std::endl;
o << std::endl;
for (i = 1; i <= NbSolution(); i++)
{
o << "solution number " << i << ": " << std::endl;
o << "the type of the solution on the first shape is " << Standard_Integer(SupportTypeShape1(i))
<< std::endl;
o << "the type of the solution on the second shape is "
<< Standard_Integer(SupportTypeShape2(i)) << std::endl;
o << "the coordinates of the point on the first shape are: " << std::endl;
o << "X=" << PointOnShape1(i).X() << " Y=" << PointOnShape1(i).Y()
<< " Z=" << PointOnShape1(i).Z() << std::endl;
o << "the coordinates of the point on the second shape are: " << std::endl;
o << "X=" << PointOnShape2(i).X() << " Y=" << PointOnShape2(i).Y()
<< " Z=" << PointOnShape2(i).Z() << std::endl;
switch (SupportTypeShape1(i))
{
case BRepExtrema_IsVertex:
break;
case BRepExtrema_IsOnEdge:
ParOnEdgeS1(i, r1);
o << "parameter on the first edge : t= " << r1 << std::endl;
break;
case BRepExtrema_IsInFace:
ParOnFaceS1(i, r1, r2);
o << "parameters on the first face : u= " << r1 << " v=" << r2 << std::endl;
break;
}
switch (SupportTypeShape2(i))
{
case BRepExtrema_IsVertex:
break;
case BRepExtrema_IsOnEdge:
ParOnEdgeS2(i, r1);
o << "parameter on the second edge : t=" << r1 << std::endl;
break;
case BRepExtrema_IsInFace:
ParOnFaceS2(i, r1, r2);
o << "parameters on the second face : u= " << r1 << " v=" << r2 << std::endl;
break;
}
o << std::endl;
}
}