1 // Created by: Peter KURNEV
2 // Copyright (c) 2010-2014 OPEN CASCADE SAS
3 // Copyright (c) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
4 // Copyright (c) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, CEDRAT,
5 // EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 // This file is part of Open CASCADE Technology software library.
9 // This library is free software; you can redistribute it and/or modify it under
10 // the terms of the GNU Lesser General Public License version 2.1 as published
11 // by the Free Software Foundation, with special exception defined in the file
12 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
13 // distribution for complete text of the license and disclaimer of any warranty.
15 // Alternatively, this file may be used under the terms of Open CASCADE
16 // commercial license or contractual agreement.
19 #include <BOPAlgo_Builder.hxx>
20 #include <BOPAlgo_Alerts.hxx>
21 #include <BOPAlgo_BuilderFace.hxx>
22 #include <BOPAlgo_PaveFiller.hxx>
23 #include <BOPAlgo_Tools.hxx>
24 #include <BOPDS_DS.hxx>
25 #include <BOPDS_FaceInfo.hxx>
26 #include <BOPDS_Interf.hxx>
27 #include <BOPDS_PaveBlock.hxx>
28 #include <BOPDS_ShapeInfo.hxx>
29 #include <BOPDS_VectorOfInterfFF.hxx>
30 #include <BOPTools_AlgoTools.hxx>
31 #include <BOPTools_AlgoTools2D.hxx>
32 #include <BOPTools_AlgoTools3D.hxx>
33 #include <BOPTools_MapOfSet.hxx>
34 #include <BOPTools_Parallel.hxx>
35 #include <BRep_Builder.hxx>
36 #include <BRepLib.hxx>
37 #include <BRep_Tool.hxx>
38 #include <GeomLib.hxx>
39 #include <NCollection_IncAllocator.hxx>
40 #include <NCollection_Vector.hxx>
41 #include <IntTools_Context.hxx>
42 #include <TColStd_ListOfInteger.hxx>
43 #include <TColStd_MapOfInteger.hxx>
44 #include <TopExp_Explorer.hxx>
46 #include <TopoDS_Compound.hxx>
47 #include <TopoDS_Edge.hxx>
48 #include <TopoDS_Face.hxx>
49 #include <TopoDS_Shape.hxx>
50 #include <TopoDS_Vertex.hxx>
51 #include <TopTools_ListOfShape.hxx>
56 TopoDS_Face BuildDraftFace(const TopoDS_Face& theFace,
57 const TopTools_DataMapOfShapeListOfShape& theImages,
58 Handle(IntTools_Context)& theCtx,
59 const Handle(Message_Report)& theReport);
61 //=======================================================================
62 //class : BOPAlgo_PairOfShapeBoolean
64 //=======================================================================
65 class BOPAlgo_PairOfShapeBoolean : public BOPAlgo_ParallelAlgo {
70 BOPAlgo_PairOfShapeBoolean() :
71 BOPAlgo_ParallelAlgo(),
72 myFlag(Standard_False) {
75 virtual ~BOPAlgo_PairOfShapeBoolean() {
78 TopoDS_Shape& Shape1() {
82 TopoDS_Shape& Shape2() {
86 Standard_Boolean& Flag() {
90 void SetContext(const Handle(IntTools_Context)& aContext) {
94 const Handle(IntTools_Context)& Context()const {
98 virtual void Perform() {
99 Message_ProgressScope aPS(myProgressRange, NULL, 1);
105 const TopoDS_Face& aFj=*((TopoDS_Face*)&myShape1);
106 const TopoDS_Face& aFk=*((TopoDS_Face*)&myShape2);
107 myFlag=BOPTools_AlgoTools::AreFacesSameDomain(aFj, aFk, myContext, myFuzzyValue);
111 Standard_Boolean myFlag;
112 TopoDS_Shape myShape1;
113 TopoDS_Shape myShape2;
114 Handle(IntTools_Context) myContext;
117 typedef NCollection_Vector<BOPAlgo_PairOfShapeBoolean> BOPAlgo_VectorOfPairOfShapeBoolean;
119 //=======================================================================
120 //class : BOPAlgo_SplitFace
121 //purpose : Auxiliary class to extend BOPAlgo_BuilderFace with progress support
122 //=======================================================================
123 class BOPAlgo_SplitFace : public BOPAlgo_BuilderFace
126 //! Sets progress range
127 void SetProgressRange(const Message_ProgressRange& theRange)
132 // New perform method, using own progress range
135 Message_ProgressScope aPS(myRange, NULL, 1);
140 BOPAlgo_BuilderFace::Perform(aPS.Next());
144 //! Disable the range enabled method
145 virtual void Perform(const Message_ProgressRange& /*theRange*/) {};
148 Message_ProgressRange myRange;
150 typedef NCollection_Vector<BOPAlgo_SplitFace> BOPAlgo_VectorOfBuilderFace;
152 //=======================================================================
153 //class : BOPAlgo_VFI
155 //=======================================================================
156 class BOPAlgo_VFI : public BOPAlgo_ParallelAlgo {
159 DEFINE_STANDARD_ALLOC
162 BOPAlgo_ParallelAlgo(),
163 myIsInternal(Standard_False) {
166 virtual ~BOPAlgo_VFI(){
169 void SetVertex(const TopoDS_Vertex& aV) {
173 TopoDS_Vertex& Vertex() {
177 void SetFace(const TopoDS_Face& aF) {
181 TopoDS_Face& Face() {
185 Standard_Boolean IsInternal()const {
189 void SetContext(const Handle(IntTools_Context)& aContext) {
193 const Handle(IntTools_Context)& Context()const {
197 virtual void Perform() {
198 Message_ProgressScope aPS(myProgressRange, NULL, 1);
204 Standard_Real aT1, aT2, dummy;
206 Standard_Integer iFlag =
207 myContext->ComputeVF(myV, myF, aT1, aT2, dummy, myFuzzyValue);
208 myIsInternal = (iFlag == 0);
212 Standard_Boolean myIsInternal;
215 Handle(IntTools_Context) myContext;
218 typedef NCollection_Vector<BOPAlgo_VFI> BOPAlgo_VectorOfVFI;
220 //=======================================================================
221 //function : FillImagesFaces
223 //=======================================================================
224 void BOPAlgo_Builder::FillImagesFaces(const Message_ProgressRange& theRange)
226 Message_ProgressScope aPS(theRange, "Filing spligs of faces", 10);
227 BuildSplitFaces(aPS.Next(9));
232 FillSameDomainFaces(aPS.Next(0.5));
237 FillInternalVertices(aPS.Next(0.5));
239 //=======================================================================
240 //function : BuildSplitFaces
242 //=======================================================================
243 void BOPAlgo_Builder::BuildSplitFaces(const Message_ProgressRange& theRange)
245 Standard_Boolean bHasFaceInfo, bIsClosed, bIsDegenerated, bToReverse;
246 Standard_Integer i, j, k, aNbS, aNbPBIn, aNbPBOn, aNbPBSc, aNbAV, nSp;
247 TopoDS_Face aFF, aFSD;
248 TopoDS_Edge aSp, aEE;
249 TopAbs_Orientation anOriF, anOriE;
250 TopExp_Explorer aExp;
251 TopTools_ListIteratorOfListOfShape aIt;
252 TColStd_ListOfInteger aLIAV;
253 TopTools_MapOfShape aMFence;
254 Handle(NCollection_BaseAllocator) aAllocator;
255 BOPAlgo_VectorOfBuilderFace aVBF;
257 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~scope f
259 NCollection_BaseAllocator::CommonBaseAllocator();
261 TopTools_ListOfShape aLE(aAllocator);
262 TopTools_MapOfShape aMDE(100, aAllocator);
264 Message_ProgressScope aPSOuter(theRange, NULL, 10);
265 // Build temporary map of faces images to avoid rebuilding
266 // of the faces without any IN or section edges
267 NCollection_IndexedDataMap<Standard_Integer, TopTools_ListOfShape> aFacesIm;
269 aNbS=myDS->NbSourceShapes();
271 for (i=0; i<aNbS; ++i) {
272 const BOPDS_ShapeInfo& aSI=myDS->ShapeInfo(i);
273 if (aSI.ShapeType()!=TopAbs_FACE) {
276 if (UserBreak(aPSOuter))
281 const TopoDS_Face& aF=(*(TopoDS_Face*)(&aSI.Shape()));
282 Standard_Boolean isUClosed = Standard_False,
283 isVClosed = Standard_False,
284 isChecked = Standard_False;
286 bHasFaceInfo=myDS->HasFaceInfo(i);
291 const BOPDS_FaceInfo& aFI=myDS->FaceInfo(i);
293 const BOPDS_IndexedMapOfPaveBlock& aMPBIn=aFI.PaveBlocksIn();
294 const BOPDS_IndexedMapOfPaveBlock& aMPBOn=aFI.PaveBlocksOn();
295 const BOPDS_IndexedMapOfPaveBlock& aMPBSc=aFI.PaveBlocksSc();
297 myDS->AloneVertices(i, aLIAV);
299 aNbPBIn=aMPBIn.Extent();
300 aNbPBOn=aMPBOn.Extent();
301 aNbPBSc=aMPBSc.Extent();
302 aNbAV=aLIAV.Extent();
303 if (!aNbPBIn && !aNbPBOn && !aNbPBSc && !aNbAV) { // not compete
307 if (!aNbPBIn && !aNbPBSc)
309 // If there are any alone vertices to be put in the face,
310 // the new face has to be created even if the wires of the
311 // face have not been modified.
313 // It is also necessary to check if the face contains any internal edges,
314 // as such edges may split the face on parts and it is better
315 // to send the face be treated by the BuilderFace algorithm.
316 // In case of alone vertices the check for internals will be performed
317 // in the BuildDraftFace method.
318 Standard_Boolean hasInternals = Standard_False;
321 // Check if any wires of the face have been modified.
322 // If no modified and internal wires present in the face
323 // there is no need to create the new face.
324 Standard_Boolean hasModified = Standard_False;
326 TopoDS_Iterator aItW(aF);
327 for (; aItW.More(); aItW.Next())
329 TopoDS_Iterator itE(aItW.Value());
330 hasInternals = (itE.More() && (itE.Value().Orientation() == TopAbs_INTERNAL));
334 hasModified |= myImages.IsBound(aItW.Value());
337 if (!hasInternals && !hasModified)
343 // No internal parts for the face, so just build the draft face
344 // and keep it to pass directly into result.
345 // If the original face has any internal edges or multi-connected vertices,
346 // the draft face will be null, as such sub-shapes may split the face on parts
347 // (as in the case "bugs modalg_5 bug25245_1").
348 // The BuilderFace algorithm will be called in this case.
349 TopoDS_Face aFD = BuildDraftFace(aF, myImages, myContext, myReport);
352 aFacesIm(aFacesIm.Add(i, TopTools_ListOfShape())).Append(aFD);
360 anOriF=aF.Orientation();
362 aFF.Orientation(TopAbs_FORWARD);
364 // 1. Fill the edges set for the face aFF -> LE
367 // 1.1 Bounding edges
368 aExp.Init(aFF, TopAbs_EDGE);
369 for (; aExp.More(); aExp.Next()) {
370 const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current()));
371 anOriE=aE.Orientation();
373 if (!myImages.IsBound(aE)) {
374 if (anOriE==TopAbs_INTERNAL) {
376 aEE.Orientation(TopAbs_FORWARD);
378 aEE.Orientation(TopAbs_REVERSED);
390 const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aF);
391 GeomLib::IsClosed(aSurf, BRep_Tool::Tolerance(aE),
392 isUClosed, isVClosed);
394 isChecked = Standard_True;
397 bIsClosed = Standard_False;
399 if((isUClosed || isVClosed) && BRep_Tool::IsClosed(aE, aF))
402 Standard_Boolean isUIso = Standard_False, isVIso = Standard_False;
403 BOPTools_AlgoTools2D::IsEdgeIsoline(aE, aF, isUIso, isVIso);
405 bIsClosed = ((isUClosed && isUIso) || (isVClosed && isVIso));
408 bIsDegenerated=BRep_Tool::Degenerated(aE);
410 const TopTools_ListOfShape& aLIE=myImages.Find(aE);
411 aIt.Initialize(aLIE);
412 for (; aIt.More(); aIt.Next()) {
413 aSp=(*(TopoDS_Edge*)(&aIt.Value()));
414 if (bIsDegenerated) {
415 aSp.Orientation(anOriE);
420 if (anOriE==TopAbs_INTERNAL) {
421 aSp.Orientation(TopAbs_FORWARD);
423 aSp.Orientation(TopAbs_REVERSED);
429 if (aMFence.Add(aSp)) {
430 if (!BRep_Tool::IsClosed(aSp, aF)){
431 if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, aF))
433 // try different approach
434 if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aE, aSp, aF))
437 BRep_Builder().MakeCompound (aWS);
438 BRep_Builder().Add (aWS, aF);
439 BRep_Builder().Add (aWS, aSp);
440 AddWarning (new BOPAlgo_AlertUnableToMakeClosedEdgeOnFace (aWS));
445 aSp.Orientation(TopAbs_FORWARD);
447 aSp.Orientation(TopAbs_REVERSED);
449 }// if (aMFence.Add(aSp))
453 aSp.Orientation(anOriE);
454 bToReverse=BOPTools_AlgoTools::IsSplitToReverseWithWarn(aSp, aE, myContext, myReport);
459 }// for (; aIt.More(); aIt.Next()) {
460 }// for (; aExp.More(); aExp.Next()) {
464 for (j=1; j<=aNbPBIn; ++j) {
465 const Handle(BOPDS_PaveBlock)& aPB=aMPBIn(j);
467 Standard_ASSERT(nSp >= 0, "Face information is not up to date", continue);
468 aSp=(*(TopoDS_Edge*)(&myDS->Shape(nSp)));
470 aSp.Orientation(TopAbs_FORWARD);
472 aSp.Orientation(TopAbs_REVERSED);
478 for (j=1; j<=aNbPBSc; ++j) {
479 const Handle(BOPDS_PaveBlock)& aPB=aMPBSc(j);
481 aSp=(*(TopoDS_Edge*)(&myDS->Shape(nSp)));
483 aSp.Orientation(TopAbs_FORWARD);
485 aSp.Orientation(TopAbs_REVERSED);
489 if (!myPaveFiller->NonDestructive()) {
490 // speed up for planar faces
491 BRepLib::BuildPCurveForEdgesOnPlane(aLE, aFF);
493 // 3 Build split faces
494 BOPAlgo_SplitFace& aBF=aVBF.Appended();
497 aBF.SetRunParallel(myRunParallel);
499 }// for (i=0; i<aNbS; ++i) {
501 // close preparation task
504 Standard_Integer aNbBF = aVBF.Length();
505 // Set progress range for each task to be run in parallel
506 Message_ProgressScope aPSParallel(aPSOuter.Next(9), "Splitting faces", aNbBF);
507 for (Standard_Integer iF = 0; iF < aNbBF; iF++)
509 BOPAlgo_SplitFace& aBF = aVBF.ChangeValue(iF);
510 aBF.SetProgressRange(aPSParallel.Next());
512 //===================================================
513 BOPTools_Parallel::Perform (myRunParallel, aVBF);
514 //===================================================
515 if (UserBreak(aPSOuter))
519 for (k = 0; k < aNbBF; ++k)
521 BOPAlgo_BuilderFace& aBF = aVBF(k);
522 aFacesIm.Add(myDS->Index(aBF.Face()), aBF.Areas());
523 myReport->Merge(aBF.GetReport());
526 aNbBF = aFacesIm.Extent();
527 for (k = 1; k <= aNbBF; ++k)
529 const TopoDS_Face& aF = TopoDS::Face(myDS->Shape(aFacesIm.FindKey(k)));
530 anOriF = aF.Orientation();
531 const TopTools_ListOfShape& aLFR = aFacesIm(k);
533 TopTools_ListOfShape* pLFIm = myImages.Bound(aF, TopTools_ListOfShape());
534 aIt.Initialize(aLFR);
535 for (; aIt.More(); aIt.Next()) {
536 TopoDS_Shape& aFR=aIt.ChangeValue();
537 if (anOriF==TopAbs_REVERSED)
538 aFR.Orientation(TopAbs_REVERSED);
543 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~scope t
546 //=======================================================================
547 //function : AddEdgeSet
549 //=======================================================================
551 NCollection_IndexedDataMap<BOPTools_Set,
552 TopTools_ListOfShape> BOPAlgo_IndexedDataMapOfSetListOfShape;
554 static void AddEdgeSet(const TopoDS_Shape& theS,
555 BOPAlgo_IndexedDataMapOfSetListOfShape& theMap,
556 const Handle(NCollection_BaseAllocator)& theAllocator)
560 aSE.Add(theS, TopAbs_EDGE);
561 // Add set to the map, keeping connection to the shape
562 TopTools_ListOfShape* pLF = theMap.ChangeSeek(aSE);
564 pLF = &theMap(theMap.Add(aSE, TopTools_ListOfShape(theAllocator)));
568 //=======================================================================
569 //function : FillSameDomainFaces
571 //=======================================================================
572 void BOPAlgo_Builder::FillSameDomainFaces(const Message_ProgressRange& theRange)
574 // It is necessary to analyze all Face/Face intersections
575 // and find all faces with equal sets of edges
576 const BOPDS_VectorOfInterfFF& aFFs = myDS->InterfFF();
577 Standard_Integer aNbFFs = aFFs.Length();
581 Message_ProgressScope aPSOuter(theRange, NULL, 10);
583 Handle(NCollection_BaseAllocator) aAllocator = new NCollection_IncAllocator;
585 // Vector to store the indices of faces for future sorting
586 // for making the SD face for the group from the face with
587 // smallest index in Data structure
588 NCollection_Vector<Standard_Integer> aFIVec(256, aAllocator);
589 // Fence map to avoid repeated checks of the same face.
590 TColStd_MapOfInteger aMFence(1, aAllocator);
592 // Fill the vector with indices of faces
593 for (Standard_Integer i = 0; i < aNbFFs; ++i)
595 if (UserBreak(aPSOuter))
599 const BOPDS_InterfFF& aFF = aFFs(i);
601 Standard_Integer nF[2];
602 aFF.Indices(nF[0], nF[1]);
603 // store indices to the vector
604 for (Standard_Integer j = 0; j < 2; ++j)
606 if (!myDS->HasFaceInfo(nF[j]))
609 if (!aMFence.Add(nF[j]))
612 aFIVec.Appended() = nF[j];
617 std::sort(aFIVec.begin(), aFIVec.end());
619 // Data map of set of edges with all faces having this set
620 NCollection_IndexedDataMap<BOPTools_Set,
621 TopTools_ListOfShape> anESetFaces(1, aAllocator);
622 // Map of planar bounded faces. If such faces have the same Edge set
623 // they are considered Same domain, without additional check.
624 TopTools_MapOfShape aMFPlanar(1, aAllocator);
626 Standard_Integer aNbF = aFIVec.Length();
627 for (Standard_Integer i = 0; i < aNbF; ++i)
629 if (UserBreak(aPSOuter))
633 const Standard_Integer nF = aFIVec(i);
634 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(nF);
635 const TopoDS_Shape& aF = aSI.Shape();
637 Standard_Boolean bCheckPlanar = Standard_False;
639 // At this stage, context should contain adaptor for all intersected faces,
640 // so getting a type of the underlying surface should be done at no cost.
641 if (myContext->SurfaceAdaptor(TopoDS::Face(aF)).GetType() == GeomAbs_Plane)
643 // Check bounding box of the face - it should not be open in any side
644 const Bnd_Box& aBox = aSI.Box();
645 bCheckPlanar = !(aBox.IsOpenXmin() || aBox.IsOpenXmax() ||
646 aBox.IsOpenYmin() || aBox.IsOpenYmax() ||
647 aBox.IsOpenZmin() || aBox.IsOpenZmax());
651 const TopTools_ListOfShape* pLFSp = myImages.Seek(aF);
654 TopTools_ListIteratorOfListOfShape aItLF(*pLFSp);
655 for (; aItLF.More(); aItLF.Next())
657 AddEdgeSet(aItLF.Value(), anESetFaces, aAllocator);
659 aMFPlanar.Add(aItLF.Value());
664 AddEdgeSet(aF, anESetFaces, aAllocator);
670 // Store pairs of faces with equal set of edges to check if they are really Same Domain
671 BOPAlgo_VectorOfPairOfShapeBoolean aVPSB;
673 // Back and forth map of SD faces to make the blocks
674 TopTools_IndexedDataMapOfShapeListOfShape aDMSLS(1, aAllocator);
676 Standard_Integer aNbSets = anESetFaces.Extent();
677 for (Standard_Integer i = 1; i <= aNbSets; ++i)
679 if (UserBreak(aPSOuter))
683 const TopTools_ListOfShape& aLF = anESetFaces(i);
684 if (aLF.Extent() < 2)
687 // All possible pairs from <aLF> should be checked
688 TopTools_ListIteratorOfListOfShape aIt1(aLF);
689 for (; aIt1.More(); aIt1.Next())
691 const TopoDS_Shape& aF1 = aIt1.Value();
692 Standard_Boolean bCheckPlanar = aMFPlanar.Contains(aF1);
694 TopTools_ListIteratorOfListOfShape aIt2 = aIt1;
695 for (aIt2.Next(); aIt2.More(); aIt2.Next())
697 const TopoDS_Shape& aF2 = aIt2.Value();
698 if (bCheckPlanar && aMFPlanar.Contains(aF2))
700 // Consider planar bounded faces as Same Domain without additional check
701 BOPAlgo_Tools::FillMap(aF1, aF2, aDMSLS, aAllocator);
704 // Add pair for analysis
705 BOPAlgo_PairOfShapeBoolean& aPSB = aVPSB.Appended();
708 aPSB.SetFuzzyValue(myFuzzyValue);
715 // Set progress range for each task to be run in parallel
716 Message_ProgressScope aPSParallel(aPSOuter.Next(6), "Checking SD faces", aVPSB.Size());
717 for (Standard_Integer iPSB = 0; iPSB < aVPSB.Size(); ++iPSB)
719 aVPSB.ChangeValue(iPSB).SetProgressRange(aPSParallel.Next());
721 //================================================================
723 BOPTools_Parallel::Perform (myRunParallel, aVPSB, myContext);
724 //================================================================
725 if (UserBreak(aPSOuter))
730 NCollection_List<TopTools_ListOfShape> aMBlocks(aAllocator);
731 // Fill map with SD faces to make the blocks
732 Standard_Integer aNbPairs = aVPSB.Length();
733 for (Standard_Integer i = 0; i < aNbPairs; ++i)
735 BOPAlgo_PairOfShapeBoolean& aPSB = aVPSB(i);
737 BOPAlgo_Tools::FillMap(aPSB.Shape1(), aPSB.Shape2(), aDMSLS, aAllocator);
741 // Make blocks of SD faces using the back and forth map
742 BOPAlgo_Tools::MakeBlocks(aDMSLS, aMBlocks, aAllocator);
744 Message_ProgressScope aPS(aPSOuter.Next(3), "Filling same domain faces map", aMBlocks.Size());
745 // Fill same domain faces map
746 NCollection_List<TopTools_ListOfShape>::Iterator aItB(aMBlocks);
747 for (; aItB.More(); aItB.Next(), aPS.Next())
753 const TopTools_ListOfShape& aLSD = aItB.Value();
754 // If the group contains some original faces, the one with minimal
755 // index in the DS will be chosen as the SD for the whole group.
756 // If there are no original faces in the group, the first face from
757 // the group will be used as the SD face.
758 // Such SD face will be representative of the whole group in the result.
759 TopoDS_Face* pFSD = NULL;
760 Standard_Integer nFMin = ::IntegerLast();
761 TopTools_ListIteratorOfListOfShape aItLF(aLSD);
762 for (; aItLF.More(); aItLF.Next())
764 const TopoDS_Shape& aF = aItLF.Value();
765 // Check the index of the face in DS
766 const Standard_Integer nF = myDS->Index(aF);
769 // The fact that the face is found in the DS, means that
770 // the face has not been change, and thus it is original one.
772 // Such face does not have any splits, but have an SD face.
773 // Consider it being split.
774 myImages.Bound(aF, TopTools_ListOfShape())->Append(aF);
776 // For the SD face chose the one with minimal index
780 pFSD = (TopoDS_Face*)&aF;
787 // No original faces in the group, take the first one
788 pFSD = (TopoDS_Face*)&aLSD.First();
791 // Save all SD connections
792 aItLF.Initialize(aLSD);
793 for (; aItLF.More(); aItLF.Next())
795 const TopoDS_Shape& aF = aItLF.Value();
796 myShapesSD.Bind(aF, *pFSD);
800 // Update the map of images with SD faces and
801 // fill the map of origins.
802 Standard_Integer aNbS = myDS->NbSourceShapes();
803 for (Standard_Integer i = 0; i < aNbS; ++i)
805 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
806 if (aSI.ShapeType() != TopAbs_FACE)
809 const TopoDS_Shape& aF = aSI.Shape();
810 TopTools_ListOfShape* pLFIm = myImages.ChangeSeek(aF);
814 TopTools_ListIteratorOfListOfShape aItLFIm(*pLFIm);
815 for (; aItLFIm.More(); aItLFIm.Next())
817 TopoDS_Shape& aFIm = aItLFIm.ChangeValue();
818 const TopoDS_Shape* pFSD = myShapesSD.Seek(aFIm);
820 // Update image with SD face
823 // Fill the map of origins
824 TopTools_ListOfShape* pLFOr = myOrigins.ChangeSeek(aFIm);
826 pLFOr = myOrigins.Bound(aFIm, TopTools_ListOfShape());
834 //=======================================================================
835 // function: FillImagesFaces1
837 //=======================================================================
838 void BOPAlgo_Builder::FillInternalVertices(const Message_ProgressRange& theRange)
840 Message_ProgressScope aPSOuter(theRange, NULL, 1);
842 // Vector of pairs of Vertex/Face for classification of the vertices
843 // relatively faces, and adding them as internal into the faces
844 BOPAlgo_VectorOfVFI aVVFI;
846 Standard_Integer aNbS = myDS->NbSourceShapes();
847 for (Standard_Integer i = 0; i < aNbS; ++i)
849 const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
850 if (aSI.ShapeType() != TopAbs_FACE)
853 if (UserBreak(aPSOuter))
858 const TopoDS_Shape& aF = aSI.Shape();
859 const TopTools_ListOfShape* pLFIm = myImages.Seek(aF);
863 // Find vertices to add as internal into the splits
864 TColStd_ListOfInteger aLIAV;
865 myDS->AloneVertices(i, aLIAV);
867 // Add vertices and faces for classification
868 TColStd_ListIteratorOfListOfInteger aItLV(aLIAV);
869 for (; aItLV.More(); aItLV.Next())
871 TopoDS_Vertex aV = TopoDS::Vertex(myDS->Shape(aItLV.Value()));
872 aV.Orientation(TopAbs_INTERNAL);
874 TopTools_ListIteratorOfListOfShape aItLFIm(*pLFIm);
875 for (; aItLFIm.More(); aItLFIm.Next())
877 const TopoDS_Face& aFIm = TopoDS::Face(aItLFIm.Value());
879 BOPAlgo_VFI& aVFI = aVVFI.Appended();
882 aVFI.SetFuzzyValue(myFuzzyValue);
887 // Set progress range for each task to be run in parallel
888 Message_ProgressScope aPSParallel(aPSOuter.Next(), "Looking for internal shapes", aVVFI.Size());
889 for (Standard_Integer iVFI = 0; iVFI< aVVFI.Size(); ++iVFI)
891 aVVFI.ChangeValue(iVFI).SetProgressRange(aPSParallel.Next());
893 // Perform classification
894 //================================================================
895 BOPTools_Parallel::Perform (myRunParallel, aVVFI, myContext);
896 //================================================================
897 if (UserBreak(aPSOuter))
902 Standard_Integer aNbVFI = aVVFI.Length();
903 for (Standard_Integer i = 0; i < aNbVFI; ++i)
905 BOPAlgo_VFI& aVFI = aVVFI(i);
906 if (aVFI.IsInternal())
908 TopoDS_Vertex& aV = aVFI.Vertex();
909 TopoDS_Face& aF = aVFI.Face();
910 BRep_Builder().Add(aF, aV);
914 //=======================================================================
915 //function : HasMultiConnected
916 //purpose : Checks if the edge has multi-connected vertices.
917 //=======================================================================
918 static Standard_Boolean HasMultiConnected(const TopoDS_Edge& theEdge,
919 TopTools_DataMapOfShapeListOfShape& theMap)
921 TopoDS_Iterator itV(theEdge);
922 for (; itV.More(); itV.Next())
924 const TopoDS_Shape& aV = itV.Value();
925 TopTools_ListOfShape *pList = theMap.ChangeSeek(aV);
928 pList = theMap.Bound(aV, TopTools_ListOfShape());
929 pList->Append(theEdge);
933 // The list is expected to be 1-2 elements long,
934 // thus using "Contains" is safe.
935 if (!pList->Contains(theEdge))
936 pList->Append(theEdge);
938 if (pList->Extent() > 2)
939 return Standard_True;
942 return Standard_False;
944 //=======================================================================
945 //function : BuildDraftFace
946 //purpose : Build draft faces, updating the bounding edges,
947 // according to the information stored into the <theImages> map
948 //=======================================================================
949 TopoDS_Face BuildDraftFace(const TopoDS_Face& theFace,
950 const TopTools_DataMapOfShapeListOfShape& theImages,
951 Handle(IntTools_Context)& theCtx,
952 const Handle(Message_Report)& theReport)
955 // Take the information from the original face
956 TopLoc_Location aLoc;
957 const Handle(Geom_Surface)& aS = BRep_Tool::Surface(theFace, aLoc);
958 const Standard_Real aTol = BRep_Tool::Tolerance(theFace);
959 // Make the new face, without any wires
960 TopoDS_Face aDraftFace;
961 aBB.MakeFace(aDraftFace, aS, aLoc, aTol);
963 // Check if the thin face can be split by a vertex - in this case
964 // this vertex will be contained in more than two edges. Thus, count
965 // the vertices appearance, and if the multi-connexity is met return
966 // the null face to use the BuilderFace algorithm for checking the
967 // possibility of split.
968 TopTools_DataMapOfShapeListOfShape aVerticesCounter;
970 // Check that the edges of the initial face have not been unified during intersection.
971 // Otherwise, it will be necessary to check validity of the new wires.
972 TopTools_MapOfShape aMEdges;
974 // Update wires of the original face and add them to draft face
975 TopoDS_Iterator aItW(theFace.Oriented(TopAbs_FORWARD));
976 for (; aItW.More(); aItW.Next())
978 const TopoDS_Shape& aW = aItW.Value();
979 if (aW.ShapeType() != TopAbs_WIRE)
982 // Rebuild wire using images of edges
983 TopoDS_Iterator aItE(aW.Oriented(TopAbs_FORWARD));
987 TopoDS_Wire aNewWire;
988 aBB.MakeWire(aNewWire);
990 for (; aItE.More(); aItE.Next())
992 const TopoDS_Edge& aE = TopoDS::Edge(aItE.Value());
994 TopAbs_Orientation anOriE = aE.Orientation();
995 if (anOriE == TopAbs_INTERNAL)
997 // The internal edges could split the original face on halves.
998 // Thus, use the BuilderFace algorithm to build the new face.
999 return TopoDS_Face();
1002 // Check if the original edge is degenerated
1003 Standard_Boolean bIsDegenerated = BRep_Tool::Degenerated(aE);
1004 // Check if the original edge is closed on the face
1005 Standard_Boolean bIsClosed = BRep_Tool::IsClosed(aE, theFace);
1007 // Check for the splits of the edge
1008 const TopTools_ListOfShape* pLEIm = theImages.Seek(aE);
1011 // Check if the edge has multi-connected vertices
1012 if (!bIsDegenerated && HasMultiConnected(aE, aVerticesCounter))
1013 return TopoDS_Face();
1015 // Check edges unification
1016 if (!bIsClosed && !aMEdges.Add(aE))
1017 return TopoDS_Face();
1019 aBB.Add(aNewWire, aE);
1023 TopTools_ListIteratorOfListOfShape aItLEIm(*pLEIm);
1024 for (; aItLEIm.More(); aItLEIm.Next())
1026 TopoDS_Edge& aSp = TopoDS::Edge(aItLEIm.ChangeValue());
1028 // Check if the split has multi-connected vertices
1029 if (!bIsDegenerated && HasMultiConnected(aSp, aVerticesCounter))
1030 return TopoDS_Face();
1032 // Check edges unification
1033 if (!bIsClosed && !aMEdges.Add(aSp))
1034 return TopoDS_Face();
1036 aSp.Orientation(anOriE);
1039 aBB.Add(aNewWire, aSp);
1043 // If the original edge is closed on the face check closeness
1044 // of the split edge and if it is not closed make the second PCurve
1045 if (bIsClosed && !BRep_Tool::IsClosed(aSp, theFace))
1046 BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, theFace);
1048 // Check if the split should be reversed
1049 if (BOPTools_AlgoTools::IsSplitToReverseWithWarn(aSp, aE, theCtx, theReport))
1052 aBB.Add(aNewWire, aSp);
1056 aNewWire.Orientation(aW.Orientation());
1057 aNewWire.Closed(BRep_Tool::IsClosed(aNewWire));
1058 aBB.Add(aDraftFace, aNewWire);
1061 if (theFace.Orientation() == TopAbs_REVERSED)
1062 aDraftFace.Reverse();