0024947: Redesign OCCT legacy type system
[occt.git] / src / TopOpeBRepTool / TopOpeBRepTool_FuseEdges.cxx
CommitLineData
b311480e 1// Created on: 1998-11-26
2// Created by: Jean-Michel BOULCOURT
3// Copyright (c) 1998-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 8// This library is free software; you can redistribute it and/or modify it under
9// the terms of the GNU Lesser General Public License version 2.1 as published
973c2be1 10// by the Free Software Foundation, with special exception defined in the file
11// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12// distribution for complete text of the license and disclaimer of any warranty.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
b311480e 16
7fd59977 17// Modif : Wed Jan 20 15:40:50 1999. In BuildListResultEdges, we
18// in UpdatePcurve, problem with location of pcurve (mix between loc and locbid)
19// Modif : Thu Jan 21 11:40:20 1999. Add trace context #if DEB
20// add test to avoid loop while in NextConnexEdge (in case of a closed connex wire)
21
22
23#include <TopOpeBRepTool_FuseEdges.ixx>
24
25#include <TopTools_ListOfShape.hxx>
26#include <TopTools_ListIteratorOfListOfShape.hxx>
27
28#include <TopTools_MapOfShape.hxx>
29
30#include <TopTools_DataMapOfIntegerListOfShape.hxx>
31#include <TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape.hxx>
32
33#include <TopExp.hxx>
34#include <TopExp_Explorer.hxx>
35
36#include <TopoDS.hxx>
37
38#include <BRep_Tool.hxx>
39#include <BRep_Builder.hxx>
40
41
42#include <GeomLib.hxx>
43#include <Geom2d_Curve.hxx>
44#include <Geom_Curve.hxx>
45#include <Geom_BoundedCurve.hxx>
46#include <Geom_Plane.hxx>
47#include <Geom2d_TrimmedCurve.hxx>
48#include <Geom_TrimmedCurve.hxx>
49#include <Geom_Line.hxx>
50#include <Geom_Circle.hxx>
51#include <Geom_Ellipse.hxx>
52#include <Geom_BSplineCurve.hxx>
53#include <Geom_BezierCurve.hxx>
54#include <TColgp_Array1OfPnt.hxx>
55#include <TColStd_Array1OfReal.hxx>
56#include <TColStd_Array1OfInteger.hxx>
57#include <ElCLib.hxx>
58#include <ElSLib.hxx>
59#include <Precision.hxx>
60#include <gp_Pnt2d.hxx>
61#include <gp_Dir2d.hxx>
62#include <gp_Vec2d.hxx>
63#include <gp_Trsf2d.hxx>
64
65#include <BRepTools_Substitution.hxx>
66#include <BRepLib_MakeEdge.hxx>
67#include <BRepLib.hxx>
68#include <TopoDS_Face.hxx>
69
70#include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
71#include <Geom2d_BSplineCurve.hxx>
72#include <BSplCLib.hxx>
73
0797d9d3 74#ifdef OCCT_DEBUG
1d0a9d4d 75extern Standard_Boolean TopOpeBRepBuild_GettraceFE();
7fd59977 76#endif
77
78//=======================================================================
79//function : TopOpeBRepTool_FuseEdges
80//purpose :
81//=======================================================================
82
83TopOpeBRepTool_FuseEdges::TopOpeBRepTool_FuseEdges(const TopoDS_Shape& theShape,
84// const Standard_Boolean PerformNow)
85 const Standard_Boolean )
86:myShape(theShape),myShapeDone(Standard_False),myEdgesDone(Standard_False),
87 myResultEdgesDone(Standard_False),myNbConnexEdge(0)
88{
89// if (theShape.ShapeType() != TopAbs_SHELL && theShape.ShapeType() != TopAbs_SOLID)
90// Standard_ConstructionError::Raise("FuseEdges");
91 Standard_NullObject_Raise_if(theShape.IsNull(),"FuseEdges");
92 myMapFaces.Clear();
93
94}
95
96//=======================================================================
97//function : AvoidEdges
98//purpose : set edges to avoid being fused
99//=======================================================================
100
101void TopOpeBRepTool_FuseEdges::AvoidEdges(const TopTools_IndexedMapOfShape& theMapEdg)
102{
103 myAvoidEdg = theMapEdg;
104}
105
106//=======================================================================
107//function : Edges
108//purpose : returns all the list of edges to be fused each list of the
109// map represent a set of connex edges that can be fused.
110//=======================================================================
111
112void TopOpeBRepTool_FuseEdges::Edges(TopTools_DataMapOfIntegerListOfShape& theMapLstEdg)
113{
114
115 if (!myEdgesDone) {
116 BuildListEdges();
117 }
118
119 theMapLstEdg = myMapLstEdg;
120}
121
122
123//=======================================================================
124//function : ResultEdges
125//purpose : returns all the fused edges
126//=======================================================================
127
128void TopOpeBRepTool_FuseEdges::ResultEdges(TopTools_DataMapOfIntegerShape& theMapEdg)
129{
130
131 if (!myEdgesDone) {
132 BuildListEdges();
133 }
134
135 if (!myResultEdgesDone) {
136 BuildListResultEdges();
137 }
138
139 theMapEdg = myMapEdg;
140}
141
142//=======================================================================
143//function : Faces
144//purpose : returns all the faces that have been modified after perform
145//=======================================================================
146
147void TopOpeBRepTool_FuseEdges::Faces(TopTools_DataMapOfShapeShape& theMapFac)
148{
149
150 if (!myEdgesDone) {
151 BuildListEdges();
152 }
153
154 if (!myResultEdgesDone) {
155 BuildListResultEdges();
156 }
157
158 if (!myShapeDone) {
159 Perform();
160 }
161
162 theMapFac = myMapFaces;
163}
164
165
166//=======================================================================
167//function : NbVertices
168//purpose :
169//=======================================================================
170
171const Standard_Integer TopOpeBRepTool_FuseEdges::NbVertices()
172{
173
174 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
175 Standard_Integer nbedges, nbvertices = 0;
176
177 if (!myEdgesDone) {
178 BuildListEdges();
179 }
180
181 if ((nbedges = myMapLstEdg.Extent()) > 0) {
182
183 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itEdg;
184 for (itEdg.Initialize(myMapLstEdg); itEdg.More(); itEdg.Next()) {
185 const Standard_Integer& iLst = itEdg.Key();
186 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
187 nbvertices += LmapEdg.Extent() - 1;
188 }
189 }
190
191 return nbvertices;
192
193}
194
195
196//=======================================================================
197//function : Shape
198//purpose :
199//=======================================================================
200
201TopoDS_Shape& TopOpeBRepTool_FuseEdges::Shape()
202{
203 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
204
205 if (!myEdgesDone) {
206 BuildListEdges();
207 }
208
209 if (!myResultEdgesDone) {
210 BuildListResultEdges();
211 }
212
213 if (!myShapeDone) {
214 Perform();
215 }
216
217 return myShape;
218}
219
220
221
222//=======================================================================
223//function : BuildListEdges
224//purpose : Build the all the lists of edges that are to be fused
225//=======================================================================
226
227void TopOpeBRepTool_FuseEdges::BuildListEdges()
228{
229
0797d9d3 230#ifdef OCCT_DEBUG
7fd59977 231 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
232#endif
233
0797d9d3 234#ifdef OCCT_DEBUG
7fd59977 235 if (tFE) cout<<endl<<"FuseEdges : BuildListEdges "<<endl;
236#endif
237
238 //--------------------------------------------------------
239 // Step One : Build the map ancestors
240 //--------------------------------------------------------
241
242 // Clear the maps
243 myMapLstEdg.Clear();
244 myMapVerLstEdg.Clear();
245 myMapEdgLstFac.Clear();
246
247 BuildAncestors(myShape,TopAbs_VERTEX,TopAbs_EDGE,myMapVerLstEdg);
248 TopExp::MapShapesAndAncestors(myShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgLstFac);
249
250 Standard_Integer iEdg;
251 TopTools_MapOfShape mapUniqEdg;
252
253 // for each edge of myMapEdgLstFac
254 for (iEdg = 1; iEdg <= myMapEdgLstFac.Extent(); iEdg++) {
255 const TopoDS_Shape& edgecur = myMapEdgLstFac.FindKey(iEdg);
256 TopTools_ListOfShape LstEdg;
257
258 // if edge not already treated
259 if (!mapUniqEdg.Contains(edgecur)
260 && (edgecur.Orientation() == TopAbs_FORWARD ||edgecur.Orientation() == TopAbs_REVERSED) ) {
261 if (myAvoidEdg.Contains(edgecur))
262 continue; // edge is not allowed to be fused
263 BuildListConnexEdge(edgecur, mapUniqEdg, LstEdg);
264 if (LstEdg.Extent() > 1) {
265 myNbConnexEdge++;
266 myMapLstEdg.Bind(myNbConnexEdge,LstEdg);
267 }
268 }
269 }
270
271 myEdgesDone = Standard_True;
272 myResultEdgesDone = Standard_False;
273}
274
275
276//=======================================================================
277//function : BuildListResultEdges
278//purpose : Build the result fused edges
279//=======================================================================
280
281void TopOpeBRepTool_FuseEdges::BuildListResultEdges()
282{
283
0797d9d3 284#ifdef OCCT_DEBUG
7fd59977 285 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
286#endif
287
0797d9d3 288#ifdef OCCT_DEBUG
7fd59977 289 if (tFE) cout<<endl<<"FuseEdges : BuildListResultEdges "<<endl;
290#endif
291
292 // if we have edges to fuse
293 if (myMapLstEdg.Extent() > 0) {
294 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
295 TopoDS_Vertex VF,VL;
296 Handle(Geom_Curve) C;
297 TopLoc_Location loc;
298 Standard_Real f,l;
299 TopoDS_Edge NewEdge;
300
301 myMapEdg.Clear();
302
303 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
304 const Standard_Integer& iLst = itLstEdg.Key();
305 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
0797d9d3 306#ifdef OCCT_DEBUG
7fd59977 307 TopTools_ListIteratorOfListOfShape itEdg;
308#endif
309
310 TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
311
312 // the first edge of the list will be replaced by the result fusion edge
313 if (OldEdge.Orientation()==TopAbs_REVERSED) {
314 VL = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
315 VF = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
316 }
317 else {
318 VF = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
319 VL = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
320 }
321 C = BRep_Tool::Curve(OldEdge,loc,f,l);
322
323 if (!loc.IsIdentity()) {
324 C = Handle(Geom_Curve)::DownCast(C->Transformed(loc.Transformation()));
325 }
326 // if the curve is trimmed we get the basis curve to fit the new vertices
327 // otherwise the makeedge will fail.
328 if (C->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
329 C = (*((Handle(Geom_TrimmedCurve)*)&C))->BasisCurve();
330 }
331
0797d9d3 332#ifdef OCCT_DEBUG
7fd59977 333 if (tFE) cout<<endl<<"FuseEdges : Creating New Edge "<<endl;
334#endif
335
336 BRepLib_MakeEdge ME(C,VF,VL);
337
338 if (!ME.IsDone()) {
339 // the MakeEdge has fails, one reason could be that the new Vertices are outside
340 // the curve which is not infinite and limited to old vertices
341 // we try to use ExtendCurveToPoint, then rebuild the NewEdge
342
0797d9d3 343#ifdef OCCT_DEBUG
7fd59977 344 if (tFE) cout<<endl<<"FuseEdges : MakeEdge failed. Trying to Extend Curve "<<endl;
345#endif
346 Handle(Geom_BoundedCurve) ExtC = Handle(Geom_BoundedCurve)::DownCast(C->Copy());
347 if (!ExtC.IsNull()) {
348 gp_Pnt PF = BRep_Tool::Pnt(VF);
349 gp_Pnt PL = BRep_Tool::Pnt(VL);
350 GeomLib::ExtendCurveToPoint(ExtC,PF,1,0);
351 GeomLib::ExtendCurveToPoint(ExtC,PL,1,1);
352
353 ME.Init(ExtC,VF,VL);
354 if (!ME.IsDone())
355 Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
356 }
357 else
358 Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
359 }
360
361 NewEdge = ME.Edge();
362
0797d9d3 363#ifdef OCCT_DEBUG
7fd59977 364 if (tFE) cout<<endl<<"FuseEdges : Updating pcurve "<<endl;
365#endif
366 if (UpdatePCurve(OldEdge,NewEdge,LmapEdg))
367 myMapEdg.Bind(iLst,NewEdge);
368 }
369
370 myResultEdgesDone = Standard_True;
371
372 }
373}
374
375//=======================================================================
376//function : Perform
377//purpose :
378//=======================================================================
379
380void TopOpeBRepTool_FuseEdges::Perform()
381{
382
0797d9d3 383#ifdef OCCT_DEBUG
7fd59977 384 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
385#endif
386
387 if (!myResultEdgesDone) {
388 BuildListResultEdges();
389 }
390
0797d9d3 391#ifdef OCCT_DEBUG
7fd59977 392 if (tFE) cout<<endl<<"FuseEdges : Perform "<<endl;
393#endif
394
395 // if we have fused edges
396 if (myMapEdg.Extent() > 0) {
397 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
398 TopTools_ListOfShape EmptyList,EdgeToSubs;
399 BRepTools_Substitution Bsub;
400
401 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
402 const Standard_Integer& iLst = itLstEdg.Key();
403 if (!myMapEdg.IsBound(iLst))
404 continue;
405 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
406 TopTools_ListIteratorOfListOfShape itEdg;
407
408 EdgeToSubs.Clear();
409 TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
410
411
412 EdgeToSubs.Append(myMapEdg(iLst));
413 Bsub.Substitute(OldEdge,EdgeToSubs);
414
415 itEdg.Initialize(LmapEdg);
416
417 // the other edges of the list will be removed
418 while (itEdg.More() ) {
419 if (!OldEdge.IsSame(TopoDS::Edge(itEdg.Value()))) {
420 Bsub.Substitute(itEdg.Value(),EmptyList);
421 }
422 itEdg.Next();
423 }
424 }
425
0797d9d3 426#ifdef OCCT_DEBUG
7fd59977 427 if (tFE) cout<<endl<<"FuseEdges : Building New Shape "<<endl;
428#endif
429
430 // perform the effective substitution
431 Bsub.Build(myShape);
432
433 // before copying the resulting shape, map the modified faces into myMapFaces
434 TopExp_Explorer exp(myShape,TopAbs_FACE);
435
436 for (; exp.More(); exp.Next()) {
437 const TopoDS_Shape& facecur = exp.Current();
438 if (Bsub.IsCopied(facecur)) {
439 myMapFaces.Bind(facecur,(Bsub.Copy(facecur)).First());
440 }
441 }
442
443 if (Bsub.IsCopied(myShape)) {
444 myShape=(Bsub.Copy(myShape)).First();
445 }
446
0797d9d3 447#ifdef OCCT_DEBUG
7fd59977 448 if (tFE) cout<<endl<<"FuseEdges : "<< NbVertices() <<" vertices removed"<<endl;
449#endif
450
451
452 }
453
454
455 myShapeDone = Standard_True;
456}
457
458
459
460//=======================================================================
461//function : BuildListConnexEdge
462//purpose : giving one edge, build the list of connex edges which have
463// vertices that have only two connex edges. All the edges that are addes
464// to the list must be added also to the mapUniq, in order for the caller
465// to not treat again theses edges.
466// This list is always oriented in the "Forward" direction.
467//=======================================================================
468
469void TopOpeBRepTool_FuseEdges::BuildListConnexEdge(const TopoDS_Shape& theEdge,
470 TopTools_MapOfShape& theMapUniq,
471 TopTools_ListOfShape& theLstEdg)
472{
473
474 TopoDS_Vertex VF,VL;
475
476
477 VL = TopExp::LastVertex(TopoDS::Edge(theEdge),Standard_True);
478 TopoDS_Shape edgeconnex;
479 TopoDS_Shape edgecur = theEdge;
480 theLstEdg.Clear();
481 theLstEdg.Append(edgecur);
482 theMapUniq.Add(edgecur);
483 TopAbs_Orientation ori2;
484
485 // we first build the list of edges connex to edgecur by looking from the last Vertex VL
486 while (NextConnexEdge(VL,edgecur,edgeconnex)) {
487 if (theMapUniq.Contains(edgeconnex)) {
488 break;
489 }
490 theLstEdg.Append(edgeconnex);
491 edgecur = edgeconnex;
492 // here take care about internal or external edges. It is non-sense to build
493 // the connex list with such edges.
494 ori2 = edgecur.Orientation();
495 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
496 break;
497 }
498 VL = TopExp::LastVertex(TopoDS::Edge(edgecur),Standard_True);
499 theMapUniq.Add(edgecur);
500 }
501
502 edgecur = theEdge;
503 VF = TopExp::FirstVertex(TopoDS::Edge(theEdge),Standard_True);
504
505 // then we build the list of edges connex to edgecur by looking from the first Vertex VF
506 while (NextConnexEdge(VF,edgecur,edgeconnex)) {
507 if (theMapUniq.Contains(edgeconnex)) {
508 break;
509 }
510 theLstEdg.Prepend(edgeconnex);
511 edgecur = edgeconnex;
512 // here take care about internal or external edges. It is non-sense to build
513 // the connex list with such edges.
514 ori2 = edgecur.Orientation();
515 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
516 break;
517 }
518 VF = TopExp::FirstVertex(TopoDS::Edge(edgecur),Standard_True);
519 theMapUniq.Add(edgecur);
520 }
521
522}
523
524
525//=======================================================================
526//function : NextConnexEdge
527//purpose : Look for an edge connex to theEdge at theVertex.
528// the connex edge must satisfies the following criteria :
529// * theVertex must have exactly 2 connex edges.
530// * the 2 connex edges must have exactly the 2 same connex faces
531// * the 2 connex edges must lie on the same support.
532//=======================================================================
533
534Standard_Boolean TopOpeBRepTool_FuseEdges::NextConnexEdge(const TopoDS_Vertex& theVertex,
535 const TopoDS_Shape& theEdge,
536 TopoDS_Shape& theEdgeConnex) const
537{
538
539 const TopTools_ListOfShape& LmapEdg = myMapVerLstEdg.FindFromKey(theVertex);
540 Standard_Boolean HasConnex = Standard_True;
541 TopTools_ListIteratorOfListOfShape itEdg,itFac1,itFac2;
542
543 // 1st condition
544 if (LmapEdg.Extent() == 2) {
545 itEdg.Initialize(LmapEdg);
546 theEdgeConnex = itEdg.Value();
547 if (theEdge.IsSame(theEdgeConnex) ) {
548 itEdg.Next();
549 theEdgeConnex = itEdg.Value();
550 }
551
552 if (myAvoidEdg.Contains(theEdgeConnex))
553 HasConnex = Standard_False; // edge is not allowed to be fused
554
555 // 2nd condition
556 if (HasConnex) {
557 const TopTools_ListOfShape& LmapFac1 = myMapEdgLstFac.FindFromKey(theEdge);
558 const TopTools_ListOfShape& LmapFac2 = myMapEdgLstFac.FindFromKey(theEdgeConnex);
559
560 if (LmapFac1.Extent() == LmapFac2.Extent() && LmapFac1.Extent() < 3) {
561 itFac1.Initialize(LmapFac1);
562
563 // for each face in LmapFac1 we look in LmapFac2 if it exists
564 while (itFac1.More() && HasConnex) {
565 const TopoDS_Shape& face1 = itFac1.Value();
566 for (itFac2.Initialize(LmapFac2); itFac2.More(); itFac2.Next()) {
567 const TopoDS_Shape& face2 = itFac2.Value();
568 HasConnex = Standard_False;
569 if (face1.IsSame(face2)) {
570 HasConnex = Standard_True;
571 break;
572 }
573 }
574 itFac1.Next();
575 }
576
577 // 3rd condition : same suport
578 if (HasConnex) {
579 HasConnex = SameSupport(TopoDS::Edge(theEdge),TopoDS::Edge(theEdgeConnex));
580 }
581 }
582 else
583 HasConnex = Standard_False;
584 }
585 }
586 else
587 HasConnex = Standard_False;
588
589 return HasConnex;
590}
591
592
593
594//=======================================================================
595//function : SameSupport
596//purpose : Edges SameSupport ou pas
597//=======================================================================
598
599Standard_Boolean TopOpeBRepTool_FuseEdges::SameSupport(const TopoDS_Edge& E1,
600 const TopoDS_Edge& E2) const
601{
602
603 if (E1.IsNull() || E2.IsNull()) {
604 return Standard_False;
605 }
606
607
608 Handle(Geom_Curve) C1,C2;
609 TopLoc_Location loc;
610 Standard_Real f1,l1,f2,l2;
611 Handle(Standard_Type) typC1,typC2;
612
613 C1 = BRep_Tool::Curve(E1,loc,f1,l1);
614 //modified by NIZNHY-PKV Mon Nov 15 16:24:10 1999
615 //degenerated edges has no 3D curve
616 if(C1.IsNull()) return Standard_False;
617
618 if (!loc.IsIdentity()) {
619 Handle(Geom_Geometry) GG1 = C1->Transformed(loc.Transformation());
620 C1 = *((Handle(Geom_Curve)*)&GG1);
621 }
622 C2 = BRep_Tool::Curve(E2,loc,f2,l2);
623 //modified by NIZNHY-PKV Mon Nov 15 16:24:38 1999
624 //degenerated edges has no 3D curve
625 if(C2.IsNull()) return Standard_False;
626
627 if (!loc.IsIdentity()) {
628 Handle(Geom_Geometry) GG2 = C2->Transformed(loc.Transformation());
629 C2 = *((Handle(Geom_Curve)*)&GG2);
630 }
631
632 typC1 = C1->DynamicType();
633 typC2 = C2->DynamicType();
634
635 if (typC1 == STANDARD_TYPE(Geom_TrimmedCurve)) {
636 C1 = (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();
637 typC1 = C1->DynamicType();
638 }
639
640 if (typC2 == STANDARD_TYPE(Geom_TrimmedCurve)) {
641 C2 = (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();
642 typC2 = C2->DynamicType();
643 }
644
645 if (typC1 != typC2) {
646 return Standard_False;
647 }
648
649 if (typC1 != STANDARD_TYPE(Geom_Line) &&
650 typC1 != STANDARD_TYPE(Geom_Circle) &&
651 typC1 != STANDARD_TYPE(Geom_Ellipse) &&
652 typC1 != STANDARD_TYPE(Geom_BSplineCurve) &&
653 typC1 != STANDARD_TYPE(Geom_BezierCurve)) {
0797d9d3 654#ifdef OCCT_DEBUG
7fd59977 655 cout << " TopOpeBRepTool_FuseEdge : Type de Support non traite" << endl;
656#endif
657 return Standard_False;
658 }
659
660 // On a presomption de confusion
661 const Standard_Real tollin = Precision::Confusion();
662 const Standard_Real tolang = Precision::Angular();
663 if (typC1 == STANDARD_TYPE(Geom_Line)) {
664 gp_Lin li1( (*((Handle(Geom_Line)*)&C1))->Lin());
665 gp_Lin li2( (*((Handle(Geom_Line)*)&C2))->Lin());
666 gp_Dir dir1(li1.Direction());
667 gp_Dir dir2(li2.Direction());
668
669 if ( dir1.IsParallel(dir2,tolang) ) {
670 // on verifie que l'on n'a pas de cas degenere. Par exemple E1 et E2 connexes
671 // mais bouclant l'un sur l'autre (cas tres rare)
672 gp_Pnt pf1 = BRep_Tool::Pnt(TopExp::FirstVertex(E1,Standard_True));
673 gp_Pnt pl1 = BRep_Tool::Pnt(TopExp::LastVertex(E1,Standard_True));
674 gp_Pnt pf2 = BRep_Tool::Pnt(TopExp::FirstVertex(E2,Standard_True));
675 gp_Pnt pl2 = BRep_Tool::Pnt(TopExp::LastVertex(E2,Standard_True));
676 if ( pl1.Distance(pf2) < tollin && pl2.Distance(pf1) < tollin)
677 return Standard_False;
678 else
679 return Standard_True;
680 }
681 return Standard_False;
682 }
683 else if (typC1 == STANDARD_TYPE(Geom_Circle)) {
684 gp_Circ ci1 = (*((Handle(Geom_Circle)*)&C1))->Circ();
685 gp_Circ ci2 = (*((Handle(Geom_Circle)*)&C2))->Circ();
686 if (Abs(ci1.Radius()-ci2.Radius()) <= tollin &&
687 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
688 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
689 // Point debut, calage dans periode, et detection meme sens
690 return Standard_True;
691 }
692 return Standard_False;
693 }
694 else if (typC1 == STANDARD_TYPE(Geom_Ellipse)) {
695 gp_Elips ci1 = (*((Handle(Geom_Ellipse)*)&C1))->Elips();
696 gp_Elips ci2 = (*((Handle(Geom_Ellipse)*)&C2))->Elips();
697
698 if (Abs(ci1.MajorRadius()-ci2.MajorRadius()) <= tollin &&
699 Abs(ci1.MinorRadius()-ci2.MinorRadius()) <= tollin &&
700 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
701 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
702 // Point debut, calage dans periode, et detection meme sens
703 return Standard_True;
704 }
705 return Standard_False;
706 }
707 else if (typC1 == STANDARD_TYPE(Geom_BSplineCurve)) {
708
709 // we must ensure that before fuse two bsplines, the end of one curve does not
710 // corresponds to the beginning of the second.
711 // we could add a special treatment for periodic bspline. This is not done for the moment.
712 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
713 return Standard_False;
714 }
715
716 Handle(Geom_BSplineCurve) B1 = *((Handle(Geom_BSplineCurve)*)&C1);
717 Handle(Geom_BSplineCurve) B2 = *((Handle(Geom_BSplineCurve)*)&C2);
718
719 Standard_Integer nbpoles = B1->NbPoles();
720 if (nbpoles != B2->NbPoles()) {
721 return Standard_False;
722 }
723
724 Standard_Integer nbknots = B1->NbKnots();
725 if (nbknots != B2->NbKnots()) {
726 return Standard_False;
727 }
728
729 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
730 B1->Poles(P1);
731 B2->Poles(P2);
732
733 Standard_Real tol3d = BRep_Tool::Tolerance(E1);
734 for (Standard_Integer p = 1; p <= nbpoles; p++) {
735 if ( (P1(p)).Distance(P2(p)) > tol3d) {
736 return Standard_False;
737 }
738 }
739
740 TColStd_Array1OfReal K1(1, nbknots), K2(1, nbknots);
741 B1->Knots(K1);
742 B2->Knots(K2);
743
744 TColStd_Array1OfInteger M1(1, nbknots), M2(1, nbknots);
745 B1->Multiplicities(M1);
746 B2->Multiplicities(M2);
747
748 for (Standard_Integer k = 1; k <= nbknots; k++) {
749 if ((K1(k)-K2(k)) > tollin) {
750 return Standard_False;
751 }
752 if (Abs(M1(k)-M2(k)) > tollin) {
753 return Standard_False;
754 }
755 }
756
757 if (!B1->IsRational()) {
758 if (B2->IsRational()) {
759 return Standard_False;
760 }
761 }
762 else {
763 if (!B2->IsRational()) {
764 return Standard_False;
765 }
766 }
767
768 if (B1->IsRational()) {
769 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
770 B1->Weights(W1);
771 B2->Weights(W2);
772
773 for (Standard_Integer w = 1; w <= nbpoles; w++) {
774 if (Abs(W1(w)-W2(w)) > tollin) {
775 return Standard_False;
776 }
777 }
778 }
779 return Standard_True;
780 }
781 else if (typC1 == STANDARD_TYPE(Geom_BezierCurve)) {
782
783 // we must ensure that before fuse two bezier, the end of one curve does not
784 // corresponds to the beginning of the second.
785 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
786 return Standard_False;
787 }
788
789 Handle(Geom_BezierCurve) B1 = *((Handle(Geom_BezierCurve)*)&C1);
790 Handle(Geom_BezierCurve) B2 = *((Handle(Geom_BezierCurve)*)&C2);
791
792 Standard_Integer nbpoles = B1->NbPoles();
793 if (nbpoles != B2->NbPoles()) {
794 return Standard_False;
795 }
796
797 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
798 B1->Poles(P1);
799 B2->Poles(P2);
800
801 for (Standard_Integer p = 1; p <= nbpoles; p++) {
802 if ( (P1(p)).Distance(P2(p)) > tollin) {
803 return Standard_False;
804 }
805 }
806
807 if (!B1->IsRational()) {
808 if (B2->IsRational()) {
809 return Standard_False;
810 }
811 }
812 else {
813 if (!B2->IsRational()) {
814 return Standard_False;
815 }
816 }
817
818 if (B1->IsRational()) {
819 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
820 B1->Weights(W1);
821 B2->Weights(W2);
822
823 for (Standard_Integer w = 1; w <= nbpoles; w++) {
824 if (Abs(W1(w)-W2(w)) > tollin) {
825 return Standard_False;
826 }
827 }
828 }
829 return Standard_True;
830 }
831 return Standard_False;
832}
833
834
835//=======================================================================
836//function : BuildAncestors
837//purpose : This function is like TopExp::MapShapesAndAncestors except
838// that in the list of shape we do not want duplicate shapes.
839// if this is useful for other purpose we should create a new method in
840// TopExp
841//=======================================================================
842
843void TopOpeBRepTool_FuseEdges::BuildAncestors
844 (const TopoDS_Shape& S,
845 const TopAbs_ShapeEnum TS,
846 const TopAbs_ShapeEnum TA,
847 TopTools_IndexedDataMapOfShapeListOfShape& M) const
848{
849
850 TopTools_MapOfShape mapDuplicate;
851 TopTools_ListIteratorOfListOfShape it;
852 Standard_Integer iSh;
853
854 TopExp::MapShapesAndAncestors(S,TS,TA,M);
855
856 // for each shape of M
857 for (iSh = 1; iSh <= M.Extent(); iSh++) {
858 TopTools_ListOfShape& Lsh = M(iSh);
859
860 mapDuplicate.Clear();
861 // we check for duplicate in the list of Shape
862 it.Initialize(Lsh);
863 while (it.More() ) {
864 if (!mapDuplicate.Contains(it.Value())) {
865 mapDuplicate.Add(it.Value());
866 it.Next();
867 }
868 else {
869 Lsh.Remove(it);
870 }
871 }
872 }
873
874}
875
876
877//=======================================================================
878//function : UpdatePCurve
879//purpose :
880//=======================================================================
881
882Standard_Boolean TopOpeBRepTool_FuseEdges::UpdatePCurve(const TopoDS_Edge& theOldEdge,
883 TopoDS_Edge& theNewEdge,
884 const TopTools_ListOfShape& theLstEdg) const
885{
886
887
888// get the pcurve of edge to substitute (theOldEdge)
889// using CurveOnSurface with Index syntax, so we can update the pcurve
890// on all the faces
891 BRep_Builder B;
892 Handle(Geom2d_Curve) Curv2d;
893 Handle(Geom_Surface) Surf;
894 TopLoc_Location loc,locbid;
895 Standard_Real ef,el,cf,cl;
896 Standard_Integer iedg = 1;
897
898 // take care that we want only Pcurve that maps on the surface where the 3D edges lies.
899 const TopTools_ListOfShape& LmapFac = myMapEdgLstFac.FindFromKey(theOldEdge);
900
901
902 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
903
904 Standard_Boolean pcurveRebuilt = Standard_False;
905
906 while (!Curv2d.IsNull()) {
907
908 // we look for a face that contains the same surface as the one that cames
909 // from CurveOnSurface
910 Standard_Boolean SameSurf = Standard_False;
911 TopTools_ListIteratorOfListOfShape itFac;
912
913 for (itFac.Initialize(LmapFac); itFac.More(); itFac.Next() ) {
914 const TopoDS_Shape& face = itFac.Value();
915 Handle (Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(face),locbid);
916 if (S == Surf) {
917 SameSurf = Standard_True;
918 break;
919 }
920 }
921
922 if (SameSurf) {
923
924 BRep_Tool::Range(theNewEdge,ef,el);
925
926 //modified by NIZNHY-PKV Mon Nov 15 14:59:48 1999 _from
927 TopoDS_Edge aFEdge = theOldEdge;
928 aFEdge.Orientation(TopAbs_FORWARD);
929
930 // take care if the edge is on the closing curve of a closed surface. In that case
931 // we get the second pcurve by reversing the edge and calling again CurveOnSurface method
932
933 BRep_Tool::CurveOnSurface(aFEdge,Curv2d,Surf,loc,cf,cl,iedg);
934 if (BRep_Tool::IsClosed(theOldEdge,Surf,loc)) {
935 aFEdge.Reverse();
936 TopoDS_Face aFFace = TopoDS::Face(itFac.Value());
937 aFFace.Orientation(TopAbs_FORWARD);
938 Handle(Geom2d_Curve) Curv2dR = BRep_Tool::CurveOnSurface(aFEdge,
939 aFFace,cf,cl);
940 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
941 Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
942 if (Curv2dR->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
943 Curv2dR = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2dR))->BasisCurve();
944
945 B.UpdateEdge (theNewEdge,Curv2d,Curv2dR,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
946 }
947 else {
948 // update the new edge
949 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
950 Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
951 Standard_Real f, l;
952 f = Curv2d->FirstParameter();
953 l = Curv2d->LastParameter();
954 if (l-f + 2.* Epsilon(l-f) < el-ef)
955 {
956 Handle(Geom2d_BoundedCurve) bcurve = Handle(Geom2d_BoundedCurve)::DownCast(Curv2d);
957 if (bcurve.IsNull())
958 bcurve = new Geom2d_TrimmedCurve( Curv2d, cf, cl );
959 Geom2dConvert_CompCurveToBSplineCurve Concat( bcurve );
960 TopTools_ListIteratorOfListOfShape iter( theLstEdg );
961 iter.Next();
962 for (; iter.More(); iter.Next())
963 {
964 TopoDS_Edge& E = TopoDS::Edge(iter.Value());
965 Standard_Real first, last;
966 Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface( E, Surf, loc, first, last );
967 Handle(Geom2d_BoundedCurve) BC = Handle(Geom2d_BoundedCurve)::DownCast(C);
968 if (BC.IsNull())
969 BC = new Geom2d_TrimmedCurve( C, first, last );
970 if (!Concat.Add( BC, Precision::PConfusion() ))
971 // cannot merge pcurves
972 return Standard_False;
973 }
974 Curv2d = Concat.BSplineCurve();
975
976 // check that new curve 2d is same range
977 Standard_Real first = Curv2d->FirstParameter();
978 Standard_Real last = Curv2d->LastParameter();
979 if (Abs (first - ef) > Precision::PConfusion() ||
980 Abs (last - el) > Precision::PConfusion())
981 {
982 Handle(Geom2d_BSplineCurve) bc = Handle(Geom2d_BSplineCurve)::DownCast(Curv2d);
983 TColStd_Array1OfReal Knots (1, bc->NbKnots());
984 bc->Knots(Knots);
985 BSplCLib::Reparametrize (ef, el, Knots);
986 bc->SetKnots(Knots);
987 }
988 pcurveRebuilt = Standard_True;
989 }
990
991 B.UpdateEdge (theNewEdge,Curv2d,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
992 }
993
994 // the old pcurve range is cf,cl. The new 3d edge range is ef,el. if we want
995 // the pcurve to be samerange we must adapt the parameter of the edge. In general
996 // cases cf=ef and cl=el expect for periodic curve if the new edge is going over
997 // the value 0.
998 if (theOldEdge.Orientation()== TopAbs_REVERSED) {
999 B.Range(theNewEdge,cl-el+ef,cl);
1000 }
1001 else {
1002 B.Range(theNewEdge,cf,cf+el-ef);
1003 }
1004 }
1005
1006 // get next pcurve
1007 iedg++;
1008 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
1009 }
1010
1011 if (pcurveRebuilt)
1012 {
1013 // force same parameter
1014 B.SameParameter (theNewEdge, Standard_False);
1015 BRepLib::SameParameter (theNewEdge, BRep_Tool::Tolerance(theNewEdge));
1016 }
1017
1018 return Standard_True;
1019}
1020
1021