0028426: Implementation of the EdgesToFaces function
[occt.git] / src / BOPAlgo / BOPAlgo_Tools.cxx
CommitLineData
4e57c75e 1// Created by: Peter KURNEV
973c2be1 2// Copyright (c) 1999-2014 OPEN CASCADE SAS
4e57c75e 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
4e57c75e 5//
d5f74e42 6// This library is free software; you can redistribute it and/or modify it under
7// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 8// by the Free Software Foundation, with special exception defined in the file
9// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10// distribution for complete text of the license and disclaimer of any warranty.
4e57c75e 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
4e57c75e 14
42cf5bc1 15
16#include <BOPAlgo_Tools.hxx>
e6ae74fd 17
18#include <gp_Pnt.hxx>
19#include <gp_Vec.hxx>
20#include <gp_Dir.hxx>
21#include <gp_Pln.hxx>
22#include <gp_Circ.hxx>
23#include <gp_Elips.hxx>
24#include <gp_Hypr.hxx>
25#include <gp_Parab.hxx>
26
27#include <Standard_ErrorHandler.hxx>
28#include <Standard_Failure.hxx>
29
30#include <TopoDS.hxx>
31#include <TopoDS_Edge.hxx>
32
33#include <BOPCol_MapOfShape.hxx>
34#include <BOPCol_IndexedMapOfShape.hxx>
42cf5bc1 35#include <BOPCol_IndexedMapOfInteger.hxx>
e6ae74fd 36#include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
37
38#include <TopExp_Explorer.hxx>
39
40#include <BRepAdaptor_Curve.hxx>
41
42#include <BRepBuilderAPI_MakeFace.hxx>
43
44#include <BRep_Tool.hxx>
45#include <BRep_Builder.hxx>
46
47#include <GeomAPI_ProjectPointOnCurve.hxx>
48#include <GeomAPI_ProjectPointOnSurf.hxx>
49
50#include <BOPAlgo_Builder.hxx>
51#include <BOPAlgo_BuilderFace.hxx>
52
4e57c75e 53#include <BOPDS_CommonBlock.hxx>
54#include <BOPDS_DataMapOfPaveBlockListOfPaveBlock.hxx>
42cf5bc1 55#include <BOPDS_DS.hxx>
56#include <BOPDS_IndexedMapOfPaveBlock.hxx>
57#include <BOPDS_MapOfPaveBlock.hxx>
58#include <BOPDS_PaveBlock.hxx>
e6ae74fd 59
60#include <BOPTools.hxx>
61#include <BOPTools_AlgoTools.hxx>
62#include <BOPTools_AlgoTools2D.hxx>
63
3510db62 64#include <IntTools_Context.hxx>
e6ae74fd 65
66typedef NCollection_IndexedDataMap
67 <TopoDS_Shape, gp_Dir, TopTools_ShapeMapHasher> BOPAlgo_IndexedDataMapOfShapeDir;
68typedef NCollection_IndexedDataMap
69 <TopoDS_Shape, gp_Pln, TopTools_ShapeMapHasher> BOPAlgo_IndexedDataMapOfShapePln;
70
71static
72 void MakeWires(const BOPCol_IndexedMapOfShape& theEdges,
73 TopoDS_Compound& theWires,
74 const Standard_Boolean theCheckUniquePlane,
75 BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
76 BOPCol_MapOfShape& theMEdgesNoUniquePlane);
77
78static
79 Standard_Boolean FindPlane(const BRepAdaptor_Curve& theCurve,
80 gp_Pln& thePlane);
81
82static
83 Standard_Boolean FindPlane(const TopoDS_Shape& theWire,
84 gp_Pln& thePlane,
85 BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
86 BOPCol_MapOfShape& theMEdgesNoUniquePlane);
87
88static
89 Standard_Boolean FindEdgeTangent(const TopoDS_Edge& theEdge,
90 BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
91 gp_Dir& theTgt);
92
93static
94 Standard_Boolean FindEdgeTangent(const BRepAdaptor_Curve& theCurve,
95 gp_Vec& theTangent);
4e57c75e 96
97//=======================================================================
98//function : MakeBlocksCnx
99//purpose :
100//=======================================================================
3510db62 101void BOPAlgo_Tools::MakeBlocksCnx(const BOPCol_IndexedDataMapOfIntegerListOfInteger& aMILI,
102 BOPCol_DataMapOfIntegerListOfInteger& aMBlocks,
103 const Handle(NCollection_BaseAllocator)& aAllocator)
4e57c75e 104{
105 Standard_Integer aNbV, nV, aNbVS, nVP, nVx, aNbVP, aNbEC, k, i, j;
106 BOPCol_ListIteratorOfListOfInteger aItLI;
107 //
108 BOPCol_MapOfInteger aMVS(100, aAllocator);
109 BOPCol_IndexedMapOfInteger aMEC(100, aAllocator);
110 BOPCol_IndexedMapOfInteger aMVP(100, aAllocator);
111 BOPCol_IndexedMapOfInteger aMVAdd(100, aAllocator);
112 //
113 aNbV=aMILI.Extent();
114 //
115 for (k=0,i=1; i<=aNbV; ++i) {
116 aNbVS=aMVS.Extent();
117 if (aNbVS==aNbV) {
118 break;
119 }
120 //
121 nV = aMILI.FindKey(i);
122 if (aMVS.Contains(nV)){
123 continue;
124 }
125 aMVS.Add(nV);
126 //
127 aMEC.Clear();
128 aMVP.Clear();
129 aMVAdd.Clear();
130 //
131 aMVP.Add(nV);
302f96fb 132 for(;;) {
4e57c75e 133 aNbVP=aMVP.Extent();
134 for (j=1; j<=aNbVP; ++j) {
135 nVP=aMVP(j);
136 const BOPCol_ListOfInteger& aLV=aMILI.FindFromKey(nVP);
137 aItLI.Initialize(aLV);
138 for (; aItLI.More(); aItLI.Next()) {
139 nVx=aItLI.Value();
140 if (aMEC.Contains(nVx)) {
141 continue;
142 }
143 //
144 aMVS.Add(nVx);
145 aMEC.Add(nVx);
146 aMVAdd.Add(nVx);
147 }
148 }
149 //
150 aNbVP=aMVAdd.Extent();
151 if (!aNbVP) {
152 break; // from while(1)
153 }
154 //
155 aMVP.Clear();
156 for (j=1; j<=aNbVP; ++j) {
157 aMVP.Add(aMVAdd(j));
158 }
159 aMVAdd.Clear();
160 }//while(1) {
161 //
162 BOPCol_ListOfInteger aLIx(aAllocator);
163 //
164 aNbEC = aMEC.Extent();
165 for (j=1; j<=aNbEC; ++j) {
166 nVx=aMEC(j);
167 aLIx.Append(nVx);
168 }
169 //
170 aMBlocks.Bind(k, aLIx);
171 ++k;
172 }//for (k=0,i=1; i<=aNbV; ++i)
173 aMVAdd.Clear();
174 aMVP.Clear();
175 aMEC.Clear();
176 aMVS.Clear();
177}
178//=======================================================================
179//function : FillMap
180//purpose :
181//=======================================================================
3510db62 182void BOPAlgo_Tools::FillMap(const Standard_Integer n1,
183 const Standard_Integer n2,
184 BOPCol_IndexedDataMapOfIntegerListOfInteger& aMILI,
185 const Handle(NCollection_BaseAllocator)& aAllocator)
4e57c75e 186{
187 if (aMILI.Contains(n1)) {
188 BOPCol_ListOfInteger& aLI=aMILI.ChangeFromKey(n1);
189 aLI.Append(n2);
190 }
191 else {
192 BOPCol_ListOfInteger aLI(aAllocator);
193 aLI.Append(n2);
194 aMILI.Add(n1, aLI);
195 }
196 if (aMILI.Contains(n2)) {
197 BOPCol_ListOfInteger& aLI=aMILI.ChangeFromKey(n2);
198 aLI.Append(n1);
199 }
200 else {
201 BOPCol_ListOfInteger aLI(aAllocator);
202 aLI.Append(n1);
203 aMILI.Add(n2, aLI);
204 }
205}
206//=======================================================================
207//function : FillMap
208//purpose :
209//=======================================================================
3510db62 210void BOPAlgo_Tools::FillMap(const Handle(BOPDS_PaveBlock)& aPB1,
211 const Handle(BOPDS_PaveBlock)& aPB2,
212 BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock& aMPBLPB,
213 const Handle(NCollection_BaseAllocator)& aAllocator)
4e57c75e 214{
215 if (aMPBLPB.Contains(aPB1)) {
216 BOPDS_ListOfPaveBlock& aLPB=aMPBLPB.ChangeFromKey(aPB1);
217 aLPB.Append(aPB2);
218 }
219 else {
220 BOPDS_ListOfPaveBlock aLPB(aAllocator);
221 aLPB.Append(aPB2);
222 aMPBLPB.Add(aPB1, aLPB);
223 }
224 if (aMPBLPB.Contains(aPB2)) {
225 BOPDS_ListOfPaveBlock& aLPB=aMPBLPB.ChangeFromKey(aPB2);
226 aLPB.Append(aPB1);
227 }
228 else {
229 BOPDS_ListOfPaveBlock aLPB(aAllocator);
230 aLPB.Append(aPB1);
231 aMPBLPB.Add(aPB2, aLPB);
232 }
233}
234//=======================================================================
235//function : FillMap
236//purpose :
237//=======================================================================
3510db62 238void BOPAlgo_Tools::FillMap(const Handle(BOPDS_PaveBlock)& aPB,
239 const Standard_Integer nF,
240 BOPDS_IndexedDataMapOfPaveBlockListOfInteger& aMPBLI,
241 const Handle(NCollection_BaseAllocator)& aAllocator)
4e57c75e 242{
243 if (aMPBLI.Contains(aPB)) {
244 BOPCol_ListOfInteger& aLI=aMPBLI.ChangeFromKey(aPB);
245 aLI.Append(nF);
246 }
247 else {
248 BOPCol_ListOfInteger aLI(aAllocator);
249 aLI.Append(nF);
250 aMPBLI.Add(aPB, aLI);
251 }
252}
253//=======================================================================
254//function : MakeBlocks
255//purpose :
256//=======================================================================
3510db62 257void BOPAlgo_Tools::MakeBlocks(const BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock& aMILI,
258 BOPDS_DataMapOfIntegerListOfPaveBlock& aMBlocks,
259 const Handle(NCollection_BaseAllocator)& aAllocator)
4e57c75e 260{
261 Standard_Integer aNbV, aNbVS, aNbVP, aNbEC, k, i, j;
262 BOPDS_ListIteratorOfListOfPaveBlock aItLI;
263 //
264 BOPDS_MapOfPaveBlock aMVS(100, aAllocator);
265 BOPDS_IndexedMapOfPaveBlock aMEC(100, aAllocator);
266 BOPDS_IndexedMapOfPaveBlock aMVP(100, aAllocator);
267 BOPDS_IndexedMapOfPaveBlock aMVAdd(100, aAllocator);
268 //
269 aNbV=aMILI.Extent();
270 //
271 for (k=0, i=1; i<=aNbV; ++i) {
272 aNbVS=aMVS.Extent();
273 if (aNbVS==aNbV) {
274 break;
275 }
276 //
277 const Handle(BOPDS_PaveBlock)& nV=aMILI.FindKey(i);
278 if (aMVS.Contains(nV)){
279 continue;
280 }
281 aMVS.Add(nV);
282 //
283 aMEC.Clear();
284 aMVP.Clear();
285 aMVAdd.Clear();
286 //
287 aMVP.Add(nV);
302f96fb 288 for(;;) {
4e57c75e 289 aNbVP=aMVP.Extent();
290 for (j=1; j<=aNbVP; ++j) {
291 const Handle(BOPDS_PaveBlock)& nVP=aMVP(j);
292 const BOPDS_ListOfPaveBlock& aLV=aMILI.FindFromKey(nVP);
293 aItLI.Initialize(aLV);
294 for (; aItLI.More(); aItLI.Next()) {
295 const Handle(BOPDS_PaveBlock)& nVx=aItLI.Value();
296 if (aMEC.Contains(nVx)) {
297 continue;
298 }
299 //
300 aMVS.Add(nVx);
301 aMEC.Add(nVx);
302 aMVAdd.Add(nVx);
303 }
304 }
305 //
306 aNbVP=aMVAdd.Extent();
307 if (!aNbVP) {
308 break; // from while(1)
309 }
310 //
311 aMVP.Clear();
312 for (j=1; j<=aNbVP; ++j) {
313 aMVP.Add(aMVAdd(j));
314 }
315 aMVAdd.Clear();
316 }//while(1) {
317 //
318 BOPDS_ListOfPaveBlock aLIx(aAllocator);
319 //
320 aNbEC = aMEC.Extent();
321 for (j=1; j<=aNbEC; ++j) {
322 const Handle(BOPDS_PaveBlock)& nVx=aMEC(j);
323 aLIx.Append(nVx);
324 }
325 //
326 aMBlocks.Bind(k, aLIx);
327 ++k;
328 }//for (k=0, i=1; i<=aNbV; ++i)
329 aMVAdd.Clear();
330 aMVP.Clear();
331 aMEC.Clear();
332 aMVS.Clear();
333}
334//=======================================================================
335//function : PerformCommonBlocks
336//purpose :
337//=======================================================================
3510db62 338void BOPAlgo_Tools::PerformCommonBlocks(BOPDS_IndexedDataMapOfPaveBlockListOfPaveBlock& aMPBLPB,
339 const Handle(NCollection_BaseAllocator)& aAllocator,
340 BOPDS_PDS& pDS)
4e57c75e 341{
342 Standard_Integer aNbCB;
343 //
344 aNbCB=aMPBLPB.Extent();
345 if (!aNbCB) {
346 return;
347 }
348 //
349 Standard_Integer aNbPB, aNbBlocks, k;
350 BOPDS_ListIteratorOfListOfPaveBlock aItLPB;
351 Handle(BOPDS_CommonBlock) aCB;
352 BOPDS_DataMapOfIntegerListOfPaveBlock aMBlocks(100, aAllocator);
353 //
354 BOPAlgo_Tools::MakeBlocks(aMPBLPB, aMBlocks, aAllocator);
355 //
356 aNbBlocks = aMBlocks.Extent();
357 for (k=0; k<aNbBlocks; ++k) {
358 const BOPDS_ListOfPaveBlock& aLPB=aMBlocks.Find(k);
359 aNbPB=aLPB.Extent();
360 if (aNbPB>1) {
361 aCB=new BOPDS_CommonBlock;
362 //
363 aItLPB.Initialize(aLPB);
364 for (; aItLPB.More(); aItLPB.Next()) {
365 const Handle(BOPDS_PaveBlock)& aPBx=aItLPB.Value();
366 aCB->AddPaveBlock(aPBx);
367 }
368 //
369 aItLPB.Initialize(aLPB);
370 for (; aItLPB.More(); aItLPB.Next()) {
371 const Handle(BOPDS_PaveBlock)& aPBx=aItLPB.Value();
5a77460e 372 pDS->SetCommonBlock(aPBx, aCB);
4e57c75e 373 }
374 }//if (aNbPB>1) {
375 }
376}
377//=======================================================================
378//function : PerformCommonBlocks
379//purpose :
380//=======================================================================
3510db62 381void BOPAlgo_Tools::PerformCommonBlocks(const BOPDS_IndexedDataMapOfPaveBlockListOfInteger& aMPBLI,
382 const Handle(NCollection_BaseAllocator)& ,//aAllocator
383 BOPDS_PDS& pDS)
4e57c75e 384{
385 Standard_Integer nF, i, aNb;
386 BOPCol_ListIteratorOfListOfInteger aItLI;
387 Handle(BOPDS_PaveBlock) aPB;
388 Handle(BOPDS_CommonBlock) aCB;
389 //
390 aNb=aMPBLI.Extent();
391 for (i=1; i<=aNb; ++i) {
392 aPB=aMPBLI.FindKey(i);
5a77460e 393 if (pDS->IsCommonBlock(aPB)) {
394 aCB=pDS->CommonBlock(aPB);
4e57c75e 395 }
396 else {
397 aCB=new BOPDS_CommonBlock;
398 aCB->AddPaveBlock(aPB);
399 }
400 //
401 const BOPCol_ListOfInteger& aLI=aMPBLI.FindFromKey(aPB);
3510db62 402 BOPCol_ListOfInteger aNewFaces;
403 const BOPCol_ListOfInteger& anOldFaces = aCB->Faces();
4e57c75e 404 aItLI.Initialize(aLI);
405 for (; aItLI.More(); aItLI.Next()) {
406 nF=aItLI.Value();
3510db62 407 // the both lists aLI and anOldFaces are expected to be short,
408 // so we can allow to run nested loop here
409 BOPCol_ListIteratorOfListOfInteger it(anOldFaces);
410 for (; it.More(); it.Next()) {
411 if (it.Value() == nF)
412 break;
413 }
414 if (!it.More()) {
415 aNewFaces.Append(nF);
416 }
4e57c75e 417 }
3510db62 418 aCB->AppendFaces(aNewFaces);
5a77460e 419 pDS->SetCommonBlock(aPB, aCB);
4e57c75e 420 }
421}
3510db62 422//=======================================================================
423//function : ComputeToleranceOfCB
424//purpose :
425//=======================================================================
426Standard_Real BOPAlgo_Tools::ComputeToleranceOfCB
427 (const Handle(BOPDS_CommonBlock)& theCB,
428 const BOPDS_PDS theDS,
429 const Handle(IntTools_Context)& theContext)
430{
431 Standard_Real aTolMax = 0.;
432 if (theCB.IsNull()) {
433 return aTolMax;
434 }
435 //
436 const Handle(BOPDS_PaveBlock)& aPBR = theCB->PaveBlock1();
437 Standard_Integer nE = aPBR->OriginalEdge();
438 const TopoDS_Edge& aEOr = *(TopoDS_Edge*)&theDS->Shape(nE);
439 aTolMax = BRep_Tool::Tolerance(aEOr);
440 //
441 const BOPDS_ListOfPaveBlock& aLPB = theCB->PaveBlocks();
442 const BOPCol_ListOfInteger& aLFI = theCB->Faces();
443 //
444 if ((aLPB.Extent() < 2) && aLFI.IsEmpty()) {
445 return aTolMax;
446 }
447 //
448 const Standard_Integer aNbPnt = 11;
449 Standard_Real aTol, aT, aT1, aT2, aDt;
450 gp_Pnt aP;
451 //
452 const Handle(Geom_Curve)& aC3D = BRep_Tool::Curve(aEOr, aT1, aT2);
453 //
454 aPBR->Range(aT1, aT2);
455 aDt = (aT2 - aT1) / (aNbPnt + 1);
456 //
457 // compute max tolerance for common blocks on edges
458 if (aLPB.Extent() > 1) {
459 // compute max distance between edges
460 BOPDS_ListIteratorOfListOfPaveBlock aItPB;
461 GeomAPI_ProjectPointOnCurve aProjPC;
462 //
463 aItPB.Initialize(aLPB);
464 for (; aItPB.More(); aItPB.Next()) {
465 const Handle(BOPDS_PaveBlock)& aPB = aItPB.Value();
466 if (aPB == aPBR) {
467 continue;
468 }
469 //
470 nE = aPB->OriginalEdge();
471 const TopoDS_Edge& aE = *(TopoDS_Edge*)&theDS->Shape(nE);
472 aTol = BRep_Tool::Tolerance(aE);
473 //
474 aProjPC = theContext->ProjPC(aE);
475 //
476 aT = aT1;
477 for (Standard_Integer i=1; i <= aNbPnt; i++) {
478 aT += aDt;
479 aC3D->D0(aT, aP);
480 aProjPC.Perform(aP);
481 if (aProjPC.NbPoints()) {
482 Standard_Real aTolNew = aTol + aProjPC.LowerDistance();
483 if (aTolNew > aTolMax) {
484 aTolMax = aTolNew;
485 }
486 }
487 }
488 }
489 }
490 //
491 // compute max tolerance for common blocks on faces
492 if (aLFI.Extent()) {
493 Standard_Integer nF;
494 GeomAPI_ProjectPointOnSurf aProjPS;
495 BOPCol_ListIteratorOfListOfInteger aItLI;
496 //
497 aItLI.Initialize(aLFI);
498 for (; aItLI.More(); aItLI.Next()) {
499 nF = aItLI.Value();
500 const TopoDS_Face& aF = *(TopoDS_Face*)&theDS->Shape(nF);
501 aTol = BRep_Tool::Tolerance(aF);
502 //
503 aProjPS = theContext->ProjPS(aF);
504 //
505 aT = aT1;
506 for (Standard_Integer i=1; i <= aNbPnt; i++) {
507 aT += aDt;
508 aC3D->D0(aT, aP);
509 aProjPS.Perform(aP);
510 if (aProjPS.NbPoints()) {
511 Standard_Real aTolNew = aTol + aProjPS.LowerDistance();
512 if (aTolNew > aTolMax) {
513 aTolMax = aTolNew;
514 }
515 }
516 }
517 }
518 }
519 //
520 return aTolMax;
521}
e6ae74fd 522
523//=======================================================================
524//function : EdgesToWires
525//purpose :
526//=======================================================================
527Standard_Integer BOPAlgo_Tools::EdgesToWires(const TopoDS_Shape& theEdges,
528 TopoDS_Shape& theWires,
529 const Standard_Boolean theShared,
530 const Standard_Real theAngTol)
531{
532 Standard_Integer iErr = 0;
533 //
534 // 1. Check the input edges
535 //
536 // List of edges to process
537 BOPCol_ListOfShape aLE;
538 //
539 TopExp_Explorer aExp(theEdges, TopAbs_EDGE);
540 for (; aExp.More(); aExp.Next()) {
541 const TopoDS_Edge& aE = TopoDS::Edge(aExp.Current());
542 if (!BRep_Tool::Degenerated(aE) && BRep_Tool::IsGeometric(aE)) {
543 aLE.Append(aExp.Current());
544 }
545 }
546 //
547 if (aLE.IsEmpty()) {
548 // no edges to process
549 iErr = 1;
550 return iErr;
551 }
552 //
553 BRep_Builder aBB;
554 TopoDS_Compound aRWires;
555 aBB.MakeCompound(aRWires);
556 //
557 if (aLE.Extent() == 1) {
558 TopoDS_Wire aWire;
559 aBB.MakeWire(aWire);
560 aBB.Add(aWire, aLE.First());
561 aBB.Add(aRWires, aWire);
562 theWires = aRWires;
563 return iErr;
564 }
565 //
566 // 2. Make compound of shared edges
567 TopoDS_Shape aSEdges;
568 //
569 if (!theShared) {
570 // intersect the edges if necessary
571 BOPAlgo_Builder aGF;
572 aGF.SetArguments(aLE);
573 aGF.Perform();
574 if (aGF.ErrorStatus()) {
575 // unable to share the edges
576 iErr = 2;
577 return iErr;
578 }
579 //
580 aSEdges = aGF.Shape();
581 }
582 else {
583 aBB.MakeCompound(TopoDS::Compound(aSEdges));
584 BOPCol_ListIteratorOfListOfShape aItLE(aLE);
585 for (; aItLE.More(); aItLE.Next()) {
586 aBB.Add(aSEdges, aItLE.Value());
587 }
588 }
589 //
590 // 3. Find edges located in the same planes and make wires from them.
591 // If the plane cannot be found for a single edge, then it is necessary
592 // to find all pairs of connected edges with the same cross product.
593
594 // Try to compute the plane in which the edge is located
595 BOPAlgo_IndexedDataMapOfShapePln aDMEdgePln;
596 // Compute the tangent direction for the edges for which the plane is not defined
597 BOPAlgo_IndexedDataMapOfShapeDir aDMEdgeTgt;
598 //
599 // edges for which the plane is not found
600 BOPCol_MapOfShape aMEdgesNoUniquePlane;
601 //
602 // edges for which the plane cannot be found on a single edge
603 TopoDS_Compound aLEdges;
604 aBB.MakeCompound(aLEdges);
605 //
606 aExp.Init(aSEdges, TopAbs_EDGE);
607 for (; aExp.More(); aExp.Next()) {
608 const TopoDS_Edge& aE = TopoDS::Edge(aExp.Current());
609 BRepAdaptor_Curve aBAC(aE);
610 //
611 gp_Pln aPln;
612 if (FindPlane(aBAC, aPln)) {
613 aDMEdgePln.Add(aE, aPln);
614 }
615 else {
616 gp_Vec aVT;
617 if (FindEdgeTangent(aBAC, aVT)) {
618 aDMEdgeTgt.Add(aE, gp_Dir(aVT));
619 aBB.Add(aLEdges, aE);
620 aMEdgesNoUniquePlane.Add(aE);
621 }
622 }
623 }
624 //
625 typedef NCollection_List<gp_Dir> BOPAlgo_ListOfDir;
626 //
627 // to avoid processing of the same edges in the same plane store
628 // the processed planes into a list and use it as a fence map
629 BOPAlgo_ListOfDir aLPFence;
630 //
631 // used edges
632 BOPCol_MapOfShape aMEFence;
633 //
634 // look for a planes on the single edges
635 Standard_Integer i, j, aNbPlanes = aDMEdgePln.Extent(), aNbEdges = aDMEdgeTgt.Extent();
636 for (i = 1; i <= aNbPlanes; ++i) {
637 const TopoDS_Shape& aEI = aDMEdgePln.FindKey(i);
638 if (!aMEFence.Add(aEI)) {
639 continue;
640 }
641 //
642 const gp_Pln& aPlnI = aDMEdgePln(i);
643 const gp_Dir& aDI = aPlnI.Position().Direction();
644 //
645 aLPFence.Append(aDI);
646 //
647 BOPCol_IndexedMapOfShape aMEPln;
648 aMEPln.Add(aEI);
649 //
650 BOPCol_IndexedMapOfShape aMV;
651 BOPTools::MapShapes(aEI, TopAbs_VERTEX, aMV);
652 //
653 // look for other edges with the plane parallel to current one
654 for (j = i + 1; j <= aNbPlanes; ++j) {
655 const gp_Dir& aDJ = aDMEdgePln(j).Position().Direction();
656 if (aDI.IsParallel(aDJ, theAngTol)) {
657 const TopoDS_Shape& aEJ = aDMEdgePln.FindKey(j);
658 aMEPln.Add(aEJ);
659 aMEFence.Add(aEJ);
660 BOPTools::MapShapes(aEJ, TopAbs_VERTEX, aMV);
661 }
662 }
663 //
664 // look for all other edges located in the plane parallel to current one
665 TopoDS_Compound aCEPln;
666 aBB.MakeCompound(aCEPln);
667 //
668 for (j = 1; j <= aNbEdges; ++j) {
669 const gp_Dir& aDJ = aDMEdgeTgt(j);
670 if (aDI.IsNormal(aDJ, theAngTol)) {
671 aBB.Add(aCEPln, aDMEdgeTgt.FindKey(j));
672 }
673 }
674 //
675 // make blocks of these edges and check blocks to be connected
676 // to any of the already added edges or forming a wire themselves
677 BOPCol_ListOfShape aLCBE;
678 BOPTools_AlgoTools::MakeConnexityBlocks(aCEPln, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
679 //
680 // make wire from each block
681 BOPCol_ListIteratorOfListOfShape aItLCB(aLCBE);
682 for (; aItLCB.More(); aItLCB.Next()) {
683 const TopoDS_Shape& aCBE = aItLCB.Value();
684 //
685 // check connectivity
686 TopExp_Explorer aExpV(aCBE, TopAbs_VERTEX);
687 for (; aExpV.More(); aExpV.Next()) {
688 if (aMV.Contains(aExpV.Current())) {
689 break;
690 }
691 }
692 //
693 Standard_Boolean bAddBlock = aExpV.More();
694 if (!bAddBlock) {
695 // check if the edges are forming a wire
696 gp_Pln aPln;
697 bAddBlock = FindPlane(aCBE, aPln, aDMEdgeTgt, aMEdgesNoUniquePlane);
698 }
699 //
700 if (bAddBlock) {
701 // add edges
702 for (TopoDS_Iterator aItE(aCBE); aItE.More(); aItE.Next()) {
703 aMEPln.Add(aItE.Value());
704 }
705 }
706 }
707 //
708 MakeWires(aMEPln, aRWires, Standard_False, aDMEdgeTgt, aMEdgesNoUniquePlane);
709 }
710 //
711 // make connection map from vertices to edges to find the connected pairs
712 BOPCol_IndexedDataMapOfShapeListOfShape aDMVE;
713 BOPTools::MapShapesAndAncestors(aLEdges, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
714 //
715 // find planes for connected edges
716 Standard_Integer aNbV = aDMVE.Extent();
717 for (i = 1; i <= aNbV; ++i) {
718 const BOPCol_ListOfShape& aLEI = aDMVE(i);
719 if (aLEI.Extent() < 2) {
720 continue;
721 }
722 //
723 BOPCol_ListIteratorOfListOfShape aItLEI1(aLEI);
724 for (; aItLEI1.More(); aItLEI1.Next()) {
725 const TopoDS_Shape& aEI1 = aItLEI1.Value();
726 const gp_Dir& aDI1 = aDMEdgeTgt.FindFromKey(aEI1);
727 //
728 BOPCol_ListIteratorOfListOfShape aItLEI2(aLEI);
729 for (; aItLEI2.More(); aItLEI2.Next()) {
730 const TopoDS_Shape& aEI2 = aItLEI2.Value();
731 if (aEI2.IsSame(aEI1)) {
732 continue;
733 }
734 //
735 const gp_Dir& aDI2 = aDMEdgeTgt.FindFromKey(aEI2);
736 //
737 if (aDI1.IsParallel(aDI2, theAngTol)) {
738 continue;
739 }
740 //
741 gp_Dir aDNI = aDI1^aDI2;
742 //
743 // check if this normal direction has not been checked yet
744 BOPAlgo_ListOfDir::Iterator aItLPln(aLPFence);
745 for (; aItLPln.More(); aItLPln.Next()) {
746 if (aDNI.IsParallel(aItLPln.Value(), theAngTol)) {
747 break;
748 }
749 }
750 if (aItLPln.More()) {
751 continue;
752 }
753 //
754 aLPFence.Append(aDNI);
755 //
756 // find all other edges in the plane parallel to current one
757 BOPCol_IndexedMapOfShape aMEPln;
758 aMEPln.Add(aEI1);
759 aMEPln.Add(aEI2);
760 //
761 // iterate on all other edges to find all edges lying in the plane parallel to current one
762 for (j = 1; j <= aNbEdges; ++j) {
763 const gp_Dir& aDJ = aDMEdgeTgt(j);
764 if (aDNI.IsNormal(aDJ, theAngTol)) {
765 aMEPln.Add(aDMEdgeTgt.FindKey(j));
766 }
767 }
768 //
769 MakeWires(aMEPln, aRWires, Standard_True, aDMEdgeTgt, aMEdgesNoUniquePlane);
770 } // for (; aItLEI2.More(); aItLEI2.Next()) {
771 } // for (; aItLEI1.More(); aItLEI1.Next()) {
772 } // for (i = 1; i < aNb; ++i) {
773 //
774 // 4. Find unused edges and make wires from them
775 BOPCol_IndexedMapOfShape aMEAlone, aMEUsed;
776 BOPTools::MapShapes(aRWires, TopAbs_EDGE, aMEUsed);
777 //
778 for (i = 1; i <= aNbEdges; ++i) {
779 const TopoDS_Shape& aE = aDMEdgeTgt.FindKey(i);
780 if (!aMEUsed.Contains(aE)) {
781 aMEAlone.Add(aE);
782 }
783 }
784 //
785 MakeWires(aMEAlone, aRWires, Standard_False, aDMEdgeTgt, aMEdgesNoUniquePlane);
786 //
787 theWires = aRWires;
788 //
789 return iErr;
790}
791
792//=======================================================================
793//function : WiresToFaces
794//purpose :
795//=======================================================================
796Standard_Boolean BOPAlgo_Tools::WiresToFaces(const TopoDS_Shape& theWires,
797 TopoDS_Shape& theFaces,
798 const Standard_Real theAngTol)
799{
800 BRep_Builder aBB;
801 BOPCol_MapOfShape aMFence;
802 TopoDS_Compound aRFaces;
803 aBB.MakeCompound(aRFaces);
804 //
805 const Standard_Real aMax = 1.e+8;
806 //
807 // map to store the tangent vectors for the edges
808 BOPAlgo_IndexedDataMapOfShapeDir aDMEdgeTgt;
809 // maps to store the planes found for the wires
810 BOPAlgo_IndexedDataMapOfShapePln aDMWirePln;
811 // map to store the tolerance for the wire
812 NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher> aDMWireTol;
813 // edges for which the plane is not found
814 BOPCol_MapOfShape aMEdgesNoUniquePlane;
815 //
816 // Find planes for the wires
817 TopExp_Explorer aExpW(theWires, TopAbs_WIRE);
818 for (; aExpW.More(); aExpW.Next()) {
819 const TopoDS_Wire& aWire = TopoDS::Wire(aExpW.Current());
820 gp_Pln aPlane;
821 if (FindPlane(aWire, aPlane, aDMEdgeTgt, aMEdgesNoUniquePlane)) {
822 aDMWirePln.Add(aWire, aPlane);
823 // find tolerance for the wire - max tolerance of its edges
824 aDMWireTol.Bind(aWire, BRep_Tool::MaxTolerance(aWire, TopAbs_EDGE));
825 }
826 }
827 //
828 Standard_Integer i, j, aNb = aDMWirePln.Extent();
829 for (i = 1; i <= aNb; ++i) {
830 const TopoDS_Shape& aWireI = aDMWirePln.FindKey(i);
831 if (aMFence.Contains(aWireI)) {
832 continue;
833 }
834 //
835 const gp_Pln& aPlnI = aDMWirePln(i);
836 //
837 BOPCol_ListOfShape aLW;
838 aLW.Append(aWireI);
839 aMFence.Add(aWireI);
840 //
841 Standard_Real aTolI = aDMWireTol.Find(aWireI);
842 //
843 // Find other wires in the same plane
844 for (j = i + 1; j <= aNb; ++j) {
845 const TopoDS_Shape& aWireJ = aDMWirePln.FindKey(j);
846 if (aMFence.Contains(aWireJ)) {
847 continue;
848 }
849 //
850 // check if the planes are the same
851 const gp_Pln& aPlnJ = aDMWirePln(j);
852 // check direction of the planes
853 if (!aPlnI.Position().Direction().IsParallel(aPlnJ.Position().Direction(), theAngTol)) {
854 continue;
855 }
856 // check distance between the planes
857 Standard_Real aDist = aPlnI.Distance(aPlnJ.Location());
858 Standard_Real aTolJ = aDMWireTol.Find(aWireJ);
859 if (aDist > (aTolI + aTolJ)) {
860 continue;
861 }
862 //
863 aLW.Append(aWireJ);
864 aMFence.Add(aWireJ);
865 }
866 //
867 // Take the edges to build the face
868 BOPCol_ListOfShape aLE;
869 BOPCol_ListIteratorOfListOfShape aItLW(aLW);
870 for (; aItLW.More(); aItLW.Next()) {
871 TopoDS_Iterator aItE(aItLW.Value());
872 for (; aItE.More(); aItE.Next()) {
873 aLE.Append(aItE.Value().Oriented(TopAbs_FORWARD));
874 aLE.Append(aItE.Value().Oriented(TopAbs_REVERSED));
875 }
876 }
877 //
878 // build planar face
879 TopoDS_Face aFF = BRepBuilderAPI_MakeFace
880 (aPlnI, -aMax, aMax, -aMax, aMax).Face();
881 aFF.Orientation(TopAbs_FORWARD);
882 //
883 try {
884 OCC_CATCH_SIGNALS
885 //
886 // build pcurves for edges on this face
887 BOPTools_AlgoTools2D::BuildPCurveForEdgesOnPlane(aLE, aFF);
888 //
889 // split the face with the edges
890 BOPAlgo_BuilderFace aBF;
891 aBF.SetShapes(aLE);
892 aBF.SetFace(aFF);
893 aBF.Perform();
894 if (aBF.ErrorStatus()) {
895 continue;
896 }
897 //
898 const BOPCol_ListOfShape& aLFSp = aBF.Areas();
899 BOPCol_ListIteratorOfListOfShape aItLF(aLFSp);
900 for (; aItLF.More(); aItLF.Next()) {
901 const TopoDS_Shape& aFSp = aItLF.ChangeValue();
902 aBB.Add(aRFaces, aFSp);
903 }
904 }
905 catch (Standard_Failure) {
906 continue;
907 }
908 }
909 //
910 // fix tolerances of the resulting faces
911 BOPCol_IndexedMapOfShape aMEmpty;
912 BOPTools_AlgoTools::CorrectTolerances(aRFaces, aMEmpty, 0.05, Standard_False);
913 BOPTools_AlgoTools::CorrectShapeTolerances(aRFaces, aMEmpty, Standard_False);
914 //
915 theFaces = aRFaces;
916 TopoDS_Iterator aItF(theFaces);
917 return aItF.More();
918}
919
920//=======================================================================
921//function : MakeWires
922//purpose : Makes wires from the separate blocks of the given edges
923//=======================================================================
924void MakeWires(const BOPCol_IndexedMapOfShape& theEdges,
925 TopoDS_Compound& theWires,
926 const Standard_Boolean theCheckUniquePlane,
927 BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
928 BOPCol_MapOfShape& theMEdgesNoUniquePlane)
929{
930 TopoDS_Compound aCE;
931 BRep_Builder().MakeCompound(aCE);
932 Standard_Integer i, aNbE = theEdges.Extent();
933 for (i = 1; i <= aNbE; ++i) {
934 BRep_Builder().Add(aCE, theEdges(i));
935 }
936 //
937 BOPCol_ListOfShape aLCBE;
938 BOPTools_AlgoTools::MakeConnexityBlocks(aCE, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
939 //
940 // make wire from each block
941 BOPCol_ListIteratorOfListOfShape aItLCB(aLCBE);
942 for (; aItLCB.More(); aItLCB.Next()) {
943 const TopoDS_Shape& aCBE = aItLCB.Value();
944 //
945 if (theCheckUniquePlane) {
946 gp_Pln aPln;
947 if (!FindPlane(aCBE, aPln, theDMEdgeTgt, theMEdgesNoUniquePlane)) {
948 continue;
949 }
950 }
951 //
952 TopoDS_Wire aWire;
953 BRep_Builder().MakeWire(aWire);
954 for (TopoDS_Iterator aItE(aCBE); aItE.More(); aItE.Next()) {
955 BRep_Builder().Add(aWire, aItE.Value());
956 }
957 //
958 BRep_Builder().Add(theWires, aWire);
959 }
960}
961
962//=======================================================================
963//function : FindEdgeTangent
964//purpose : Finds the tangent for the edge using the map
965//=======================================================================
966Standard_Boolean FindEdgeTangent(const TopoDS_Edge& theEdge,
967 BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
968 gp_Dir& theTgt)
969{
970 gp_Dir *pDTE = theDMEdgeTgt.ChangeSeek(theEdge);
971 if (!pDTE) {
972 gp_Vec aVTE;
973 BRepAdaptor_Curve aBAC(theEdge);
974 if (!FindEdgeTangent(aBAC, aVTE)) {
975 return Standard_False;
976 }
977 pDTE = &theDMEdgeTgt(theDMEdgeTgt.Add(theEdge, gp_Dir(aVTE)));
978 }
979 theTgt = *pDTE;
980 return Standard_True;
981}
982
983//=======================================================================
984//function : FindEdgeTangent
985//purpose : Finds the tangent for the edge
986//=======================================================================
987Standard_Boolean FindEdgeTangent(const BRepAdaptor_Curve& theCurve,
988 gp_Vec& theTangent)
989{
990 if (!theCurve.Is3DCurve()) {
991 return Standard_False;
992 }
993 // for the line the tangent is defined by the direction
994 if (theCurve.GetType() == GeomAbs_Line) {
995 theTangent = theCurve.Line().Position().Direction();
996 return Standard_True;
997 }
998 //
999 // for other curves take D1 and check for its length
1000 Standard_Real aT, aT1(theCurve.FirstParameter()), aT2(theCurve.LastParameter());
1001 const Standard_Integer aNbP = 11;
1002 const Standard_Real aDt = (aT2 - aT1) / aNbP;
1003 //
1004 for (aT = aT1 + aDt; aT <= aT2; aT += aDt) {
1005 gp_Pnt aP;
1006 theCurve.D1(aT, aP, theTangent);
1007 if (theTangent.Magnitude() > Precision::Confusion()) {
1008 return Standard_True;
1009 }
1010 }
1011 //
1012 return Standard_False;
1013}
1014
1015//=======================================================================
1016//function : FindPlane
1017//purpose : Finds the plane in which the edge is located
1018//=======================================================================
1019Standard_Boolean FindPlane(const BRepAdaptor_Curve& theCurve,
1020 gp_Pln& thePlane)
1021{
1022 if (!theCurve.Is3DCurve()) {
1023 return Standard_False;
1024 }
1025 //
1026 Standard_Boolean bFound = Standard_True;
1027 gp_Vec aVN;
1028 switch (theCurve.GetType()) {
1029 case GeomAbs_Line:
1030 return Standard_False;
1031 case GeomAbs_Circle:
1032 aVN = theCurve.Circle().Position().Direction();
1033 break;
1034 case GeomAbs_Ellipse:
1035 aVN = theCurve.Ellipse().Position().Direction();
1036 break;
1037 case GeomAbs_Hyperbola:
1038 aVN = theCurve.Hyperbola().Position().Direction();
1039 break;
1040 case GeomAbs_Parabola:
1041 aVN = theCurve.Parabola().Position().Direction();
1042 break;
1043 default: {
1044 // for all other types of curve compute two tangent vectors
1045 // on the curve and cross them
1046 bFound = Standard_False;
1047 Standard_Real aT, aT1(theCurve.FirstParameter()), aT2(theCurve.LastParameter());
1048 const Standard_Integer aNbP = 11;
1049 const Standard_Real aDt = (aT2 - aT1) / aNbP;
1050 //
1051 aT = aT1;
1052 gp_Pnt aP1;
1053 gp_Vec aV1;
1054 theCurve.D1(aT, aP1, aV1);
1055 //
1056 for (aT = aT1 + aDt; aT <= aT2; aT += aDt) {
1057 gp_Pnt aP2;
1058 gp_Vec aV2;
1059 theCurve.D1(aT, aP2, aV2);
1060 //
1061 aVN = aV1^aV2;
1062 if (aVN.Magnitude() > Precision::Confusion()) {
1063 bFound = Standard_True;
1064 break;
1065 }
1066 }
1067 break;
1068 }
1069 }
1070 //
1071 if (bFound) {
1072 thePlane = gp_Pln(theCurve.Value(theCurve.FirstParameter()), gp_Dir(aVN));
1073 }
1074 return bFound;
1075}
1076
1077//=======================================================================
1078//function : FindPlane
1079//purpose : Finds the plane in which the wire is located
1080//=======================================================================
1081Standard_Boolean FindPlane(const TopoDS_Shape& theWire,
1082 gp_Pln& thePlane,
1083 BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
1084 BOPCol_MapOfShape& theMEdgesNoUniquePlane)
1085{
1086 TopExp_Explorer aExpE1(theWire, TopAbs_EDGE);
1087 if (!aExpE1.More()) {
1088 return Standard_False;
1089 }
1090 //
1091 // try to find two not parallel edges in wire to get normal of the plane
1092 for (; aExpE1.More(); aExpE1.Next()) {
1093 // get the first edge in the wire
1094 const TopoDS_Edge& aE1 = TopoDS::Edge(aExpE1.Current());
1095 //
1096 // find tangent for the first edge
1097 gp_Dir aDTE1;
1098 if (!FindEdgeTangent(aE1, theDMEdgeTgt, aDTE1)) {
1099 continue;
1100 }
1101 //
1102 // find the other edge not parallel to the first one
1103 TopExp_Explorer aExpE2(theWire, TopAbs_EDGE);
1104 for (; aExpE2.More(); aExpE2.Next()) {
1105 const TopoDS_Edge& aE2 = TopoDS::Edge(aExpE2.Current());
1106 if (aE1.IsSame(aE2)) {
1107 continue;
1108 }
1109 //
1110 // find tangent for the second edge
1111 gp_Dir aDTE2;
1112 if (!FindEdgeTangent(aE2, theDMEdgeTgt, aDTE2)) {
1113 continue;
1114 }
1115 //
1116 if (aDTE1.IsParallel(aDTE2, Precision::Angular())) {
1117 continue;
1118 }
1119 //
1120 gp_Dir aDN = aDTE1^aDTE2;
1121 //
1122 TopoDS_Iterator aItV(aE1);
1123 thePlane = gp_Pln(BRep_Tool::Pnt(TopoDS::Vertex(aItV.Value())), aDN);
1124 return Standard_True;
1125 }
1126 }
1127 //
1128 // try to compute normal on the single edge
1129 aExpE1.Init(theWire, TopAbs_EDGE);
1130 for (; aExpE1.More(); aExpE1.Next()) {
1131 const TopoDS_Edge& aE = TopoDS::Edge(aExpE1.Current());
1132 if (theMEdgesNoUniquePlane.Contains(aE)) {
1133 continue;
1134 }
1135 BRepAdaptor_Curve aBAC(aE);
1136 if (FindPlane(aBAC, thePlane)) {
1137 return Standard_True;
1138 }
1139 theMEdgesNoUniquePlane.Add(aE);
1140 }
1141 return Standard_False;
1142}