0022946: BRepFeat_SplitShape crashes on splitting a face by two edges
[occt.git] / src / LocOpe / LocOpe_Spliter.cxx
1 // Created on: 1996-01-09
2 // Created by: Jacques GOUSSARD
3 // Copyright (c) 1996-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
5 //
6 // The content of this file is subject to the Open CASCADE Technology Public
7 // License Version 6.5 (the "License"). You may not use the content of this file
8 // except in compliance with the License. Please obtain a copy of the License
9 // at http://www.opencascade.org and read it completely before using this file.
10 //
11 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 //
14 // The Original Code and all software distributed under the License is
15 // distributed on an "AS IS" basis, without warranty of any kind, and the
16 // Initial Developer hereby disclaims all such warranties, including without
17 // limitation, any warranties of merchantability, fitness for a particular
18 // purpose or non-infringement. Please see the License for the specific terms
19 // and conditions governing the rights and limitations under the License.
20
21
22 //  Modified by skv - Mon May 31 12:34:09 2004 OCC5865
23
24 #include <LocOpe_Spliter.ixx>
25
26 #include <LocOpe_ProjectedWires.hxx>
27
28 #include <TopTools_MapOfShape.hxx>
29 #include <TopTools_DataMapOfShapeShape.hxx>
30 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
31 #include <TopTools_ListIteratorOfListOfShape.hxx>
32 #include <TopTools_MapIteratorOfMapOfShape.hxx>
33 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
34 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
35 #include <TopExp_Explorer.hxx>
36 #include <TopoDS_Iterator.hxx>
37 #include <TopoDS_Vertex.hxx>
38 #include <TopoDS_Edge.hxx>
39 #include <TopoDS_Wire.hxx>
40 #include <TopoDS_Face.hxx>
41
42 #include <LocOpe_BuildWires.hxx>
43
44 #include <gp_Vec2d.hxx>
45 #include <gp_Vec.hxx>
46 #include <Geom_Curve.hxx>
47 #include <GeomAPI_ProjectPointOnCurve.hxx>
48 #include <BRep_Tool.hxx>
49
50 #include <BRepTools_Substitution.hxx>
51 #include <LocOpe_SplitShape.hxx>
52
53 #include <BRep_Builder.hxx>
54
55 #include <TopoDS.hxx>
56 #include <TopExp.hxx>
57
58 #include <Standard_ConstructionError.hxx>
59
60
61 //  Modified by skv - Mon May 31 13:00:30 2004 OCC5865 Begin
62 // static void RebuildWires(TopTools_ListOfShape&);
63 static void RebuildWires(TopTools_ListOfShape&,
64                          const Handle(LocOpe_ProjectedWires)&);
65 //  Modified by skv - Mon May 31 13:00:31 2004 OCC5865 End
66
67 static void Put(const TopoDS_Shape&,
68                 TopTools_DataMapOfShapeListOfShape&);
69
70 static void Select(const TopoDS_Edge&,
71                    TopTools_ListOfShape&);
72
73
74 //=======================================================================
75 //function : Perform
76 //purpose  : 
77 //=======================================================================
78
79 void LocOpe_Spliter::Perform(const Handle(LocOpe_ProjectedWires)& PW)
80 {
81   if (myShape.IsNull()) {
82     Standard_NullObject::Raise();
83   }
84   myDone = Standard_False;
85   myMap.Clear();
86   myRes.Nullify();
87
88   Put(myShape,myMap);
89
90   TopTools_MapOfShape mapV,mapE;
91   TopTools_DataMapOfShapeShape EdgOnEdg;
92   TopTools_IndexedDataMapOfShapeListOfShape mapFE;
93   TopExp_Explorer exp,exp2;
94   
95   // 1ere etape : substitution des vertex
96
97   TopoDS_Vertex Vb;
98   TopTools_ListOfShape lsubs;
99   BRepTools_Substitution theSubs;
100   BRep_Builder BB;
101
102   for (PW->InitEdgeIterator(); PW->MoreEdge(); PW->NextEdge()) {
103     const TopoDS_Edge& edg = PW->Edge();
104     mapE.Add(edg);
105     for (exp.Init(edg,TopAbs_VERTEX); exp.More(); exp.Next()) {
106       const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current());
107       if (!mapV.Contains(vtx)) {
108         if (PW->OnVertex(vtx,Vb)) {
109           mapV.Add(vtx);
110           lsubs.Clear();
111           TopoDS_Vertex vsub = TopoDS::Vertex(vtx.Oriented(TopAbs_FORWARD));
112           gp_Pnt p1 = BRep_Tool::Pnt(vsub), p2 = BRep_Tool::Pnt(Vb);
113           Standard_Real d = p1.Distance(p2);
114           d = d + BRep_Tool::Tolerance(Vb);
115           BB.UpdateVertex(vsub, d);
116           lsubs.Append(vsub);
117           theSubs.Substitute(Vb.Oriented(TopAbs_FORWARD),lsubs);
118         }
119         
120       }
121     }
122   }
123
124   theSubs.Build(myShape);
125   TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itdesc(myMap);
126   if (theSubs.IsCopied(myShape)) {
127     // on n`a fait que des substitutions de vertex. Donc chaque element
128     // est remplace par lui meme ou par un seul element du meme type.
129     for (; itdesc.More(); itdesc.Next()) {
130       if (theSubs.IsCopied(itdesc.Key())) {
131         const TopTools_ListOfShape& lsub = theSubs.Copy(itdesc.Key());
132 #ifdef DEB
133         if (lsub.Extent() != 1) {
134           Standard_ConstructionError::Raise();
135         }
136 #endif
137         myMap(itdesc.Key()).Clear(); 
138         myMap(itdesc.Key()).Append(lsub.First()); 
139       }
140     }
141   }
142
143   myRes = myMap(myShape).First();
144   LocOpe_SplitShape theCFace(myRes);
145
146   // Adds every vertices lying on an edge of the shape, and prepares 
147   // work to rebuild wires on each face
148   TopoDS_Edge Ed;
149   Standard_Real prm;
150
151   TopTools_MapOfShape theFacesWithSection;
152   for (PW->InitEdgeIterator(); PW->MoreEdge(); PW->NextEdge()) {
153     const TopoDS_Edge& edg = PW->Edge();
154     for (exp.Init(edg,TopAbs_VERTEX); exp.More(); exp.Next()) {
155       const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current());
156       if (!mapV.Contains(vtx)) {
157         mapV.Add(vtx);
158         if (PW->OnEdge(vtx,Ed,prm)) {
159           // on devrait verifier que le vtx n`existe pas deja sur l`edge
160           if(!myMap.IsBound(Ed)) continue;
161           Ed = TopoDS::Edge(myMap(Ed).First());
162           theCFace.Add(vtx,prm,Ed);
163         }
164       }
165     }
166     TopoDS_Edge Ebis;
167     if (PW->OnEdge(Ebis)) {
168       //        Ebis = TopoDS::Edge(myMap(Ebis).First());
169       EdgOnEdg.Bind(edg,Ebis);
170     }
171     else {
172       TopoDS_Face fac = PW->OnFace();
173       if(!myMap.IsBound(fac)) continue;
174       Standard_Boolean IsFaceWithSec = PW->IsFaceWithSection(fac);
175       fac = TopoDS::Face(myMap(fac).First());
176       if (IsFaceWithSec)
177         theFacesWithSection.Add(fac);
178       if (!mapFE.Contains(fac)) {
179         TopTools_ListOfShape thelist;
180         mapFE.Add(fac, thelist);
181       }
182       mapFE.ChangeFromKey(fac).Append(edg);
183     }
184   }
185
186   // Rebuilds wires on each face of the shape
187
188   TopTools_ListIteratorOfListOfShape itl;
189   for (Standard_Integer i=1; i<=mapFE.Extent(); i++) {
190     const TopoDS_Face& fac = TopoDS::Face(mapFE.FindKey(i));
191     TopTools_ListOfShape& ledges = mapFE(i);
192 //  Modified by skv - Mon May 31 12:32:54 2004 OCC5865 Begin
193 //     RebuildWires(ledges);
194     RebuildWires(ledges, PW);
195 //  Modified by skv - Mon May 31 12:32:54 2004 OCC5865 End
196     if (theFacesWithSection.Contains(fac))
197       theCFace.Add(ledges, fac);
198     else
199       for (itl.Initialize(ledges); itl.More(); itl.Next())
200         theCFace.Add(TopoDS::Wire(itl.Value()),fac);
201   }
202
203
204   // Mise a jour des descendants
205
206   for (itdesc.Reset(); itdesc.More(); itdesc.Next()) {
207     const TopoDS_Shape& sori = itdesc.Key();
208     const TopoDS_Shape& scib = itdesc.Value().First();
209     myMap(sori) = theCFace.DescendantShapes(scib);
210   }
211
212   const TopTools_ListOfShape& lres = myMap(myShape);
213
214   TopAbs_ShapeEnum typS = myShape.ShapeType();
215   if (typS == TopAbs_FACE && lres.Extent() >=2) {
216     BRep_Builder B;
217     myRes.Nullify();
218     B.MakeShell(TopoDS::Shell(myRes));
219     myRes.Orientation(TopAbs_FORWARD);
220     for (itl.Initialize(lres); itl.More(); itl.Next()) {
221       B.Add(myRes,itl.Value().Oriented(myShape.Orientation()));
222     }
223   }
224   else if (typS == TopAbs_EDGE && lres.Extent() >=2) {
225     BRep_Builder B;
226     myRes.Nullify();
227     B.MakeWire(TopoDS::Wire(myRes));
228     myRes.Orientation(TopAbs_FORWARD);
229     for (itl.Initialize(lres); itl.More(); itl.Next()) {
230       B.Add(myRes,itl.Value().Oriented(myShape.Orientation()));
231     }
232   }
233   else {
234     if (lres.Extent() != 1) {
235       return;
236     }
237     myRes = lres.First();
238   }
239
240   theSubs.Clear();
241   for (TopTools_DataMapIteratorOfDataMapOfShapeShape itee(EdgOnEdg);
242        itee.More();
243        itee.Next()) {
244     const TopoDS_Edge& e1 = TopoDS::Edge(itee.Key());
245     // on recherche dans les descendants de e2 l`edge qui correspont a e1
246
247     TopoDS_Vertex vf1,vl1,vf2,vl2;
248     TopExp::Vertices(e1,vf1,vl1);
249     lsubs.Clear();
250     for (itl.Initialize(myMap(itee.Value()));
251          itl.More();
252          itl.Next()) {
253       const TopoDS_Edge& e2 = TopoDS::Edge(itl.Value());
254       TopExp::Vertices(e2,vf2,vl2);
255
256       if (!vl1.IsSame(vf1)) {
257         if (vf1.IsSame(vf2) && vl1.IsSame(vl2)) {
258           lsubs.Append(e2.Oriented(TopAbs_FORWARD));
259           //    break;
260         }
261         else if (vf1.IsSame(vl2) && vl1.IsSame(vf2)) {
262           lsubs.Append(e2.Oriented(TopAbs_REVERSED));
263           //    break;
264         }
265       }
266       else { // discrimination sur les tangentes
267         if (vf2.IsSame(vl2) && vl2.IsSame(vl1)) { // tout au meme point
268           TopLoc_Location Loc;
269           Standard_Real f,l;
270           gp_Pnt pbid;
271           gp_Vec v1,v2;
272           Handle(Geom_Curve) C = BRep_Tool::Curve(e1,Loc,f,l);
273           C->D1(f,pbid,v1);
274           v1.Transform(Loc.Transformation());
275
276           C = BRep_Tool::Curve(e2,Loc,f,l);
277           C->D1(f,pbid,v2);
278           v2.Transform(Loc.Transformation());
279           if (v1.Dot(v2) >0.) {
280             lsubs.Append(e2.Oriented(TopAbs_FORWARD));
281           }
282           else {
283             lsubs.Append(e2.Oriented(TopAbs_REVERSED));
284           }
285         }
286       }
287
288     }
289     if (lsubs.Extent() >= 2) { // il faut faire un choix
290       Select(e1,lsubs);
291     }
292     if (lsubs.Extent() == 1) {
293       TopoDS_Shape ebase = lsubs.First();
294       lsubs.Clear();
295       lsubs.Append(e1.Oriented(ebase.Orientation()));
296       theSubs.Substitute(ebase.Oriented(TopAbs_FORWARD),lsubs);
297     }
298     else {
299 #ifdef DEB
300       cout << "Pb pour substitution" << endl;
301 #endif
302     }
303   }
304
305   theSubs.Build(myRes);
306
307   for (itdesc.Reset(); itdesc.More(); itdesc.Next()) {
308     TopTools_ListOfShape& ldesc = myMap(itdesc.Key());
309     TopTools_ListOfShape newdesc;
310     for (itl.Initialize(ldesc); itl.More(); itl.Next()) {
311       if (theSubs.IsCopied(itl.Value())) {
312         const TopTools_ListOfShape& lsub = theSubs.Copy(itl.Value());
313 #ifdef DEB
314         if (lsub.Extent() != 1) {
315           Standard_ConstructionError::Raise();
316         }
317 #endif
318         newdesc.Append(lsub.First());
319       }
320       else {
321         newdesc.Append(itl.Value());
322       }
323     }
324     myMap(itdesc.Key()) = newdesc;
325   }
326   
327   if (theSubs.IsCopied(myRes)) {
328     myRes = theSubs.Copy(myRes).First();
329   }
330
331   myDLeft.Clear();
332   myLeft.Clear();
333   mapV.Clear();
334
335   TopTools_MapIteratorOfMapOfShape itms;
336
337   for (exp.Init(myRes, TopAbs_FACE); exp.More(); exp.Next()) {
338     const TopoDS_Face& fac = TopoDS::Face(exp.Current());
339     for (exp2.Init(fac,TopAbs_EDGE); exp2.More(); exp2.Next()) {
340       const TopoDS_Edge& edg = TopoDS::Edge(exp2.Current());
341       for (itms.Initialize(mapE); 
342            itms.More(); itms.Next()) {
343         if (itms.Key().IsSame(edg) &&
344             edg.Orientation() == itms.Key().Orientation()) {
345           break;
346         }
347       }
348       if (itms.More()) {
349         break;
350       }
351     }
352     if (exp2.More()) {
353       myDLeft.Append(fac);
354       myLeft.Append(fac);
355     }
356     else {
357       mapV.Add(fac);
358     }
359   }
360
361 /* JAG : Ne peut pas marcher
362
363   Standard_Boolean full = mapV.IsEmpty();
364   while (!full) {
365     full = Standard_True;
366     itms.Initialize(mapV);
367     const TopoDS_Face& fac = TopoDS::Face(itms.Key());
368     for (exp.Init(fac,TopAbs_EDGE); exp.More(); exp.Next()) {
369       if (!mapE.Contains(exp.Current())) {
370         for (itl.Initialize(myLeft); itl.More(); itl.Next()) {
371           const TopoDS_Face& fac2 = TopoDS::Face(itl.Value());
372           for (exp2.Init(fac2,TopAbs_EDGE); exp2.More(); exp2.Next()) {
373             if (exp2.Current().IsSame(exp.Current())) {
374               myLeft.Append(fac);
375               mapV.Remove(fac);
376               full = mapV.IsEmpty();
377               break;
378             }
379           }
380           if (exp2.More()) {
381             break;
382           }
383         }
384         if (itl.More()) {
385           break;
386         }
387       }
388     }
389   }
390 */
391
392   // Map des edges ou les connexions sont possibles
393   TopTools_MapOfShape Mapebord;
394   for (itl.Initialize(myLeft); itl.More(); itl.Next()) {
395     for (exp.Init(itl.Value(),TopAbs_EDGE); exp.More(); exp.Next()) {
396       if (!mapE.Contains(exp.Current())) {
397         if (!Mapebord.Add(exp.Current())) {
398           Mapebord.Remove(exp.Current());
399         }
400       }
401     }
402   }
403
404
405   while (Mapebord.Extent() != 0) {
406     itms.Initialize(Mapebord);
407     TopoDS_Shape edg = itms.Key();
408
409     for (itms.Initialize(mapV); itms.More(); itms.Next()) {
410       const TopoDS_Shape& fac = itms.Key();
411       for (exp.Init(fac,TopAbs_EDGE); exp.More(); exp.Next()) {
412         if (exp.Current().IsSame(edg)) {
413           break;
414         }
415       }
416       if (exp.More()) {
417         break; // face a gauche
418       }
419     }
420     if (itms.More()) {
421       TopoDS_Shape fac = itms.Key();
422       for (exp.Init(fac,TopAbs_EDGE); exp.More(); exp.Next()) {
423         if (!Mapebord.Add(exp.Current())) {
424           Mapebord.Remove(exp.Current());
425         }
426       }
427       mapV.Remove(fac);
428       myLeft.Append(fac);
429     }
430     else {
431       Mapebord.Remove(edg);
432     }
433   }
434
435   myDone = Standard_True;
436 }
437
438
439 //=======================================================================
440 //function : DescendantShapes
441 //purpose  : 
442 //=======================================================================
443
444 const TopTools_ListOfShape& LocOpe_Spliter::
445    DescendantShapes(const TopoDS_Shape& F)
446 {
447   if (!myDone) {StdFail_NotDone::Raise();}
448   if (myMap.IsBound(F))
449     return myMap(F);
450   else {
451     static TopTools_ListOfShape empty;
452     return empty;
453   }
454 }
455
456
457 //=======================================================================
458 //function : DirectLeft
459 //purpose  : 
460 //=======================================================================
461
462 const TopTools_ListOfShape& LocOpe_Spliter::DirectLeft() const
463 {
464   if (!myDone) {StdFail_NotDone::Raise();}
465   return myDLeft;
466
467 }
468
469
470 //=======================================================================
471 //function : Left
472 //purpose  : 
473 //=======================================================================
474
475 const TopTools_ListOfShape& LocOpe_Spliter::Left() const
476 {
477   if (!myDone) {StdFail_NotDone::Raise();}
478   return myLeft;
479
480 }
481
482
483 //=======================================================================
484 //function : RebuildWires
485 //purpose  : 
486 //=======================================================================
487
488 //  Modified by skv - Mon May 31 12:31:39 2004 OCC5865 Begin
489 //static void RebuildWires(TopTools_ListOfShape& ledge)
490 static void RebuildWires(TopTools_ListOfShape& ledge,
491                          const Handle(LocOpe_ProjectedWires)& PW)
492 {
493   LocOpe_BuildWires theBuild(ledge, PW);
494 //  Modified by skv - Mon May 31 12:31:40 2004 OCC5865 End
495   if (!theBuild.IsDone()) {
496     Standard_ConstructionError::Raise();
497   }
498   ledge = theBuild.Result();
499
500
501 }
502
503
504
505 //=======================================================================
506 //function : Put
507 //purpose  : 
508 //=======================================================================
509
510 static void Put(const TopoDS_Shape& S,
511                 TopTools_DataMapOfShapeListOfShape& theMap)
512 {
513   if (theMap.IsBound(S)) {
514     return;
515   }
516   TopTools_ListOfShape thelist;
517   theMap.Bind(S, thelist);
518   theMap(S).Append(S);
519   for (TopoDS_Iterator it(S); it.More(); it.Next()) {
520     Put(it.Value(),theMap);
521   }
522 }
523
524
525 //=======================================================================
526 //function : Select
527 //purpose  : 
528 //=======================================================================
529
530 static void Select(const TopoDS_Edge& Ebase,
531                    TopTools_ListOfShape& lsubs)
532 {
533
534   // Choix d`un point
535
536   Handle(Geom_Curve) C;
537   TopLoc_Location Loc;
538   Standard_Real f,l,dmin = RealLast();
539   Standard_Integer i=0,imin = 0;
540
541   C = BRep_Tool::Curve(Ebase,Loc,f,l);
542
543   if (!Loc.IsIdentity()) {
544     Handle(Geom_Geometry) GG = C->Transformed(Loc.Transformation());
545     C = *((Handle(Geom_Curve)*)&GG);
546   }
547   gp_Pnt Pt(C->Value((f+l)/2.));
548
549   GeomAPI_ProjectPointOnCurve proj;
550 //  for (TopTools_ListIteratorOfListOfShape itl(lsubs);
551   TopTools_ListIteratorOfListOfShape itl(lsubs);
552   for ( ;itl.More();itl.Next()) {
553     i++;
554     const TopoDS_Edge& edg = TopoDS::Edge(itl.Value());
555     C = BRep_Tool::Curve(edg,Loc,f,l);
556     if (!Loc.IsIdentity()) {
557       Handle(Geom_Geometry) GG = C->Transformed(Loc.Transformation());
558       C = *((Handle(Geom_Curve)*)&GG);
559     }
560     proj.Init(Pt,C,f,l);
561     if (proj.NbPoints() > 0) {
562       if (proj.LowerDistance() < dmin) {
563         imin = i;
564         dmin = proj.LowerDistance();
565       }
566     }
567   }
568   if (imin == 0) {
569     lsubs.Clear();
570   }
571   else {
572     itl.Initialize(lsubs);
573     i = 1;
574     while (i < imin) {
575       lsubs.Remove(itl);
576       i++;
577     }
578     itl.Next();
579     while (itl.More()) {
580       lsubs.Remove(itl);
581     }
582   }
583 }