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