1 // Created on: 1998-11-26
2 // Created by: Jean-Michel BOULCOURT
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2012 OPEN CASCADE SAS
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.
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.
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.
21 // Modif : Wed Jan 20 15:40:50 1999. In BuildListResultEdges, we
22 // in UpdatePcurve, problem with location of pcurve (mix between loc and locbid)
23 // Modif : Thu Jan 21 11:40:20 1999. Add trace context #if DEB
24 // add test to avoid loop while in NextConnexEdge (in case of a closed connex wire)
27 #include <TopOpeBRepTool_FuseEdges.ixx>
29 #include <TopTools_ListOfShape.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx>
32 #include <TopTools_MapOfShape.hxx>
34 #include <TopTools_DataMapOfIntegerListOfShape.hxx>
35 #include <TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape.hxx>
38 #include <TopExp_Explorer.hxx>
42 #include <BRep_Tool.hxx>
43 #include <BRep_Builder.hxx>
46 #include <GeomLib.hxx>
47 #include <Geom2d_Curve.hxx>
48 #include <Geom_Curve.hxx>
49 #include <Geom_BoundedCurve.hxx>
50 #include <Geom_Plane.hxx>
51 #include <Geom2d_TrimmedCurve.hxx>
52 #include <Geom_TrimmedCurve.hxx>
53 #include <Geom_Line.hxx>
54 #include <Geom_Circle.hxx>
55 #include <Geom_Ellipse.hxx>
56 #include <Geom_BSplineCurve.hxx>
57 #include <Geom_BezierCurve.hxx>
58 #include <TColgp_Array1OfPnt.hxx>
59 #include <TColStd_Array1OfReal.hxx>
60 #include <TColStd_Array1OfInteger.hxx>
63 #include <Precision.hxx>
64 #include <gp_Pnt2d.hxx>
65 #include <gp_Dir2d.hxx>
66 #include <gp_Vec2d.hxx>
67 #include <gp_Trsf2d.hxx>
69 #include <BRepTools_Substitution.hxx>
70 #include <BRepLib_MakeEdge.hxx>
71 #include <BRepLib.hxx>
72 #include <TopoDS_Face.hxx>
74 #include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
75 #include <Geom2d_BSplineCurve.hxx>
76 #include <BSplCLib.hxx>
79 extern Standard_Boolean TopOpeBRepBuild_GettraceFE();
82 //=======================================================================
83 //function : TopOpeBRepTool_FuseEdges
85 //=======================================================================
87 TopOpeBRepTool_FuseEdges::TopOpeBRepTool_FuseEdges(const TopoDS_Shape& theShape,
88 // const Standard_Boolean PerformNow)
89 const Standard_Boolean )
90 :myShape(theShape),myShapeDone(Standard_False),myEdgesDone(Standard_False),
91 myResultEdgesDone(Standard_False),myNbConnexEdge(0)
93 // if (theShape.ShapeType() != TopAbs_SHELL && theShape.ShapeType() != TopAbs_SOLID)
94 // Standard_ConstructionError::Raise("FuseEdges");
95 Standard_NullObject_Raise_if(theShape.IsNull(),"FuseEdges");
100 //=======================================================================
101 //function : AvoidEdges
102 //purpose : set edges to avoid being fused
103 //=======================================================================
105 void TopOpeBRepTool_FuseEdges::AvoidEdges(const TopTools_IndexedMapOfShape& theMapEdg)
107 myAvoidEdg = theMapEdg;
110 //=======================================================================
112 //purpose : returns all the list of edges to be fused each list of the
113 // map represent a set of connex edges that can be fused.
114 //=======================================================================
116 void TopOpeBRepTool_FuseEdges::Edges(TopTools_DataMapOfIntegerListOfShape& theMapLstEdg)
123 theMapLstEdg = myMapLstEdg;
127 //=======================================================================
128 //function : ResultEdges
129 //purpose : returns all the fused edges
130 //=======================================================================
132 void TopOpeBRepTool_FuseEdges::ResultEdges(TopTools_DataMapOfIntegerShape& theMapEdg)
139 if (!myResultEdgesDone) {
140 BuildListResultEdges();
143 theMapEdg = myMapEdg;
146 //=======================================================================
148 //purpose : returns all the faces that have been modified after perform
149 //=======================================================================
151 void TopOpeBRepTool_FuseEdges::Faces(TopTools_DataMapOfShapeShape& theMapFac)
158 if (!myResultEdgesDone) {
159 BuildListResultEdges();
166 theMapFac = myMapFaces;
170 //=======================================================================
171 //function : NbVertices
173 //=======================================================================
175 const Standard_Integer TopOpeBRepTool_FuseEdges::NbVertices()
178 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
179 Standard_Integer nbedges, nbvertices = 0;
185 if ((nbedges = myMapLstEdg.Extent()) > 0) {
187 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itEdg;
188 for (itEdg.Initialize(myMapLstEdg); itEdg.More(); itEdg.Next()) {
189 const Standard_Integer& iLst = itEdg.Key();
190 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
191 nbvertices += LmapEdg.Extent() - 1;
200 //=======================================================================
203 //=======================================================================
205 TopoDS_Shape& TopOpeBRepTool_FuseEdges::Shape()
207 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
213 if (!myResultEdgesDone) {
214 BuildListResultEdges();
226 //=======================================================================
227 //function : BuildListEdges
228 //purpose : Build the all the lists of edges that are to be fused
229 //=======================================================================
231 void TopOpeBRepTool_FuseEdges::BuildListEdges()
235 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
239 if (tFE) cout<<endl<<"FuseEdges : BuildListEdges "<<endl;
242 //--------------------------------------------------------
243 // Step One : Build the map ancestors
244 //--------------------------------------------------------
248 myMapVerLstEdg.Clear();
249 myMapEdgLstFac.Clear();
251 BuildAncestors(myShape,TopAbs_VERTEX,TopAbs_EDGE,myMapVerLstEdg);
252 TopExp::MapShapesAndAncestors(myShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgLstFac);
254 Standard_Integer iEdg;
255 TopTools_MapOfShape mapUniqEdg;
257 // for each edge of myMapEdgLstFac
258 for (iEdg = 1; iEdg <= myMapEdgLstFac.Extent(); iEdg++) {
259 const TopoDS_Shape& edgecur = myMapEdgLstFac.FindKey(iEdg);
260 TopTools_ListOfShape LstEdg;
262 // if edge not already treated
263 if (!mapUniqEdg.Contains(edgecur)
264 && (edgecur.Orientation() == TopAbs_FORWARD ||edgecur.Orientation() == TopAbs_REVERSED) ) {
265 if (myAvoidEdg.Contains(edgecur))
266 continue; // edge is not allowed to be fused
267 BuildListConnexEdge(edgecur, mapUniqEdg, LstEdg);
268 if (LstEdg.Extent() > 1) {
270 myMapLstEdg.Bind(myNbConnexEdge,LstEdg);
275 myEdgesDone = Standard_True;
276 myResultEdgesDone = Standard_False;
280 //=======================================================================
281 //function : BuildListResultEdges
282 //purpose : Build the result fused edges
283 //=======================================================================
285 void TopOpeBRepTool_FuseEdges::BuildListResultEdges()
289 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
293 if (tFE) cout<<endl<<"FuseEdges : BuildListResultEdges "<<endl;
296 // if we have edges to fuse
297 if (myMapLstEdg.Extent() > 0) {
298 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
300 Handle(Geom_Curve) C;
307 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
308 const Standard_Integer& iLst = itLstEdg.Key();
309 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
311 TopTools_ListIteratorOfListOfShape itEdg;
314 TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
316 // the first edge of the list will be replaced by the result fusion edge
317 if (OldEdge.Orientation()==TopAbs_REVERSED) {
318 VL = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
319 VF = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
322 VF = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
323 VL = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
325 C = BRep_Tool::Curve(OldEdge,loc,f,l);
327 if (!loc.IsIdentity()) {
328 C = Handle(Geom_Curve)::DownCast(C->Transformed(loc.Transformation()));
330 // if the curve is trimmed we get the basis curve to fit the new vertices
331 // otherwise the makeedge will fail.
332 if (C->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
333 C = (*((Handle(Geom_TrimmedCurve)*)&C))->BasisCurve();
337 if (tFE) cout<<endl<<"FuseEdges : Creating New Edge "<<endl;
340 BRepLib_MakeEdge ME(C,VF,VL);
343 // the MakeEdge has fails, one reason could be that the new Vertices are outside
344 // the curve which is not infinite and limited to old vertices
345 // we try to use ExtendCurveToPoint, then rebuild the NewEdge
348 if (tFE) cout<<endl<<"FuseEdges : MakeEdge failed. Trying to Extend Curve "<<endl;
350 Handle(Geom_BoundedCurve) ExtC = Handle(Geom_BoundedCurve)::DownCast(C->Copy());
351 if (!ExtC.IsNull()) {
352 gp_Pnt PF = BRep_Tool::Pnt(VF);
353 gp_Pnt PL = BRep_Tool::Pnt(VL);
354 GeomLib::ExtendCurveToPoint(ExtC,PF,1,0);
355 GeomLib::ExtendCurveToPoint(ExtC,PL,1,1);
359 Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
362 Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
368 if (tFE) cout<<endl<<"FuseEdges : Updating pcurve "<<endl;
370 if (UpdatePCurve(OldEdge,NewEdge,LmapEdg))
371 myMapEdg.Bind(iLst,NewEdge);
374 myResultEdgesDone = Standard_True;
379 //=======================================================================
382 //=======================================================================
384 void TopOpeBRepTool_FuseEdges::Perform()
388 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
391 if (!myResultEdgesDone) {
392 BuildListResultEdges();
396 if (tFE) cout<<endl<<"FuseEdges : Perform "<<endl;
399 // if we have fused edges
400 if (myMapEdg.Extent() > 0) {
401 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
402 TopTools_ListOfShape EmptyList,EdgeToSubs;
403 BRepTools_Substitution Bsub;
405 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
406 const Standard_Integer& iLst = itLstEdg.Key();
407 if (!myMapEdg.IsBound(iLst))
409 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
410 TopTools_ListIteratorOfListOfShape itEdg;
413 TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
416 EdgeToSubs.Append(myMapEdg(iLst));
417 Bsub.Substitute(OldEdge,EdgeToSubs);
419 itEdg.Initialize(LmapEdg);
421 // the other edges of the list will be removed
422 while (itEdg.More() ) {
423 if (!OldEdge.IsSame(TopoDS::Edge(itEdg.Value()))) {
424 Bsub.Substitute(itEdg.Value(),EmptyList);
431 if (tFE) cout<<endl<<"FuseEdges : Building New Shape "<<endl;
434 // perform the effective substitution
437 // before copying the resulting shape, map the modified faces into myMapFaces
438 TopExp_Explorer exp(myShape,TopAbs_FACE);
440 for (; exp.More(); exp.Next()) {
441 const TopoDS_Shape& facecur = exp.Current();
442 if (Bsub.IsCopied(facecur)) {
443 myMapFaces.Bind(facecur,(Bsub.Copy(facecur)).First());
447 if (Bsub.IsCopied(myShape)) {
448 myShape=(Bsub.Copy(myShape)).First();
452 if (tFE) cout<<endl<<"FuseEdges : "<< NbVertices() <<" vertices removed"<<endl;
459 myShapeDone = Standard_True;
464 //=======================================================================
465 //function : BuildListConnexEdge
466 //purpose : giving one edge, build the list of connex edges which have
467 // vertices that have only two connex edges. All the edges that are addes
468 // to the list must be added also to the mapUniq, in order for the caller
469 // to not treat again theses edges.
470 // This list is always oriented in the "Forward" direction.
471 //=======================================================================
473 void TopOpeBRepTool_FuseEdges::BuildListConnexEdge(const TopoDS_Shape& theEdge,
474 TopTools_MapOfShape& theMapUniq,
475 TopTools_ListOfShape& theLstEdg)
481 VL = TopExp::LastVertex(TopoDS::Edge(theEdge),Standard_True);
482 TopoDS_Shape edgeconnex;
483 TopoDS_Shape edgecur = theEdge;
485 theLstEdg.Append(edgecur);
486 theMapUniq.Add(edgecur);
487 TopAbs_Orientation ori2;
489 // we first build the list of edges connex to edgecur by looking from the last Vertex VL
490 while (NextConnexEdge(VL,edgecur,edgeconnex)) {
491 if (theMapUniq.Contains(edgeconnex)) {
494 theLstEdg.Append(edgeconnex);
495 edgecur = edgeconnex;
496 // here take care about internal or external edges. It is non-sense to build
497 // the connex list with such edges.
498 ori2 = edgecur.Orientation();
499 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
502 VL = TopExp::LastVertex(TopoDS::Edge(edgecur),Standard_True);
503 theMapUniq.Add(edgecur);
507 VF = TopExp::FirstVertex(TopoDS::Edge(theEdge),Standard_True);
509 // then we build the list of edges connex to edgecur by looking from the first Vertex VF
510 while (NextConnexEdge(VF,edgecur,edgeconnex)) {
511 if (theMapUniq.Contains(edgeconnex)) {
514 theLstEdg.Prepend(edgeconnex);
515 edgecur = edgeconnex;
516 // here take care about internal or external edges. It is non-sense to build
517 // the connex list with such edges.
518 ori2 = edgecur.Orientation();
519 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
522 VF = TopExp::FirstVertex(TopoDS::Edge(edgecur),Standard_True);
523 theMapUniq.Add(edgecur);
529 //=======================================================================
530 //function : NextConnexEdge
531 //purpose : Look for an edge connex to theEdge at theVertex.
532 // the connex edge must satisfies the following criteria :
533 // * theVertex must have exactly 2 connex edges.
534 // * the 2 connex edges must have exactly the 2 same connex faces
535 // * the 2 connex edges must lie on the same support.
536 //=======================================================================
538 Standard_Boolean TopOpeBRepTool_FuseEdges::NextConnexEdge(const TopoDS_Vertex& theVertex,
539 const TopoDS_Shape& theEdge,
540 TopoDS_Shape& theEdgeConnex) const
543 const TopTools_ListOfShape& LmapEdg = myMapVerLstEdg.FindFromKey(theVertex);
544 Standard_Boolean HasConnex = Standard_True;
545 TopTools_ListIteratorOfListOfShape itEdg,itFac1,itFac2;
548 if (LmapEdg.Extent() == 2) {
549 itEdg.Initialize(LmapEdg);
550 theEdgeConnex = itEdg.Value();
551 if (theEdge.IsSame(theEdgeConnex) ) {
553 theEdgeConnex = itEdg.Value();
556 if (myAvoidEdg.Contains(theEdgeConnex))
557 HasConnex = Standard_False; // edge is not allowed to be fused
561 const TopTools_ListOfShape& LmapFac1 = myMapEdgLstFac.FindFromKey(theEdge);
562 const TopTools_ListOfShape& LmapFac2 = myMapEdgLstFac.FindFromKey(theEdgeConnex);
564 if (LmapFac1.Extent() == LmapFac2.Extent() && LmapFac1.Extent() < 3) {
565 itFac1.Initialize(LmapFac1);
567 // for each face in LmapFac1 we look in LmapFac2 if it exists
568 while (itFac1.More() && HasConnex) {
569 const TopoDS_Shape& face1 = itFac1.Value();
570 for (itFac2.Initialize(LmapFac2); itFac2.More(); itFac2.Next()) {
571 const TopoDS_Shape& face2 = itFac2.Value();
572 HasConnex = Standard_False;
573 if (face1.IsSame(face2)) {
574 HasConnex = Standard_True;
581 // 3rd condition : same suport
583 HasConnex = SameSupport(TopoDS::Edge(theEdge),TopoDS::Edge(theEdgeConnex));
587 HasConnex = Standard_False;
591 HasConnex = Standard_False;
598 //=======================================================================
599 //function : SameSupport
600 //purpose : Edges SameSupport ou pas
601 //=======================================================================
603 Standard_Boolean TopOpeBRepTool_FuseEdges::SameSupport(const TopoDS_Edge& E1,
604 const TopoDS_Edge& E2) const
607 if (E1.IsNull() || E2.IsNull()) {
608 return Standard_False;
612 Handle(Geom_Curve) C1,C2;
614 Standard_Real f1,l1,f2,l2;
615 Handle(Standard_Type) typC1,typC2;
617 C1 = BRep_Tool::Curve(E1,loc,f1,l1);
618 //modified by NIZNHY-PKV Mon Nov 15 16:24:10 1999
619 //degenerated edges has no 3D curve
620 if(C1.IsNull()) return Standard_False;
622 if (!loc.IsIdentity()) {
623 Handle(Geom_Geometry) GG1 = C1->Transformed(loc.Transformation());
624 C1 = *((Handle(Geom_Curve)*)&GG1);
626 C2 = BRep_Tool::Curve(E2,loc,f2,l2);
627 //modified by NIZNHY-PKV Mon Nov 15 16:24:38 1999
628 //degenerated edges has no 3D curve
629 if(C2.IsNull()) return Standard_False;
631 if (!loc.IsIdentity()) {
632 Handle(Geom_Geometry) GG2 = C2->Transformed(loc.Transformation());
633 C2 = *((Handle(Geom_Curve)*)&GG2);
636 typC1 = C1->DynamicType();
637 typC2 = C2->DynamicType();
639 if (typC1 == STANDARD_TYPE(Geom_TrimmedCurve)) {
640 C1 = (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();
641 typC1 = C1->DynamicType();
644 if (typC2 == STANDARD_TYPE(Geom_TrimmedCurve)) {
645 C2 = (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();
646 typC2 = C2->DynamicType();
649 if (typC1 != typC2) {
650 return Standard_False;
653 if (typC1 != STANDARD_TYPE(Geom_Line) &&
654 typC1 != STANDARD_TYPE(Geom_Circle) &&
655 typC1 != STANDARD_TYPE(Geom_Ellipse) &&
656 typC1 != STANDARD_TYPE(Geom_BSplineCurve) &&
657 typC1 != STANDARD_TYPE(Geom_BezierCurve)) {
659 cout << " TopOpeBRepTool_FuseEdge : Type de Support non traite" << endl;
661 return Standard_False;
664 // On a presomption de confusion
665 const Standard_Real tollin = Precision::Confusion();
666 const Standard_Real tolang = Precision::Angular();
667 if (typC1 == STANDARD_TYPE(Geom_Line)) {
668 gp_Lin li1( (*((Handle(Geom_Line)*)&C1))->Lin());
669 gp_Lin li2( (*((Handle(Geom_Line)*)&C2))->Lin());
670 gp_Dir dir1(li1.Direction());
671 gp_Dir dir2(li2.Direction());
673 if ( dir1.IsParallel(dir2,tolang) ) {
674 // on verifie que l'on n'a pas de cas degenere. Par exemple E1 et E2 connexes
675 // mais bouclant l'un sur l'autre (cas tres rare)
676 gp_Pnt pf1 = BRep_Tool::Pnt(TopExp::FirstVertex(E1,Standard_True));
677 gp_Pnt pl1 = BRep_Tool::Pnt(TopExp::LastVertex(E1,Standard_True));
678 gp_Pnt pf2 = BRep_Tool::Pnt(TopExp::FirstVertex(E2,Standard_True));
679 gp_Pnt pl2 = BRep_Tool::Pnt(TopExp::LastVertex(E2,Standard_True));
680 if ( pl1.Distance(pf2) < tollin && pl2.Distance(pf1) < tollin)
681 return Standard_False;
683 return Standard_True;
685 return Standard_False;
687 else if (typC1 == STANDARD_TYPE(Geom_Circle)) {
688 gp_Circ ci1 = (*((Handle(Geom_Circle)*)&C1))->Circ();
689 gp_Circ ci2 = (*((Handle(Geom_Circle)*)&C2))->Circ();
690 if (Abs(ci1.Radius()-ci2.Radius()) <= tollin &&
691 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
692 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
693 // Point debut, calage dans periode, et detection meme sens
694 return Standard_True;
696 return Standard_False;
698 else if (typC1 == STANDARD_TYPE(Geom_Ellipse)) {
699 gp_Elips ci1 = (*((Handle(Geom_Ellipse)*)&C1))->Elips();
700 gp_Elips ci2 = (*((Handle(Geom_Ellipse)*)&C2))->Elips();
702 if (Abs(ci1.MajorRadius()-ci2.MajorRadius()) <= tollin &&
703 Abs(ci1.MinorRadius()-ci2.MinorRadius()) <= tollin &&
704 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
705 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
706 // Point debut, calage dans periode, et detection meme sens
707 return Standard_True;
709 return Standard_False;
711 else if (typC1 == STANDARD_TYPE(Geom_BSplineCurve)) {
713 // we must ensure that before fuse two bsplines, the end of one curve does not
714 // corresponds to the beginning of the second.
715 // we could add a special treatment for periodic bspline. This is not done for the moment.
716 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
717 return Standard_False;
720 Handle(Geom_BSplineCurve) B1 = *((Handle(Geom_BSplineCurve)*)&C1);
721 Handle(Geom_BSplineCurve) B2 = *((Handle(Geom_BSplineCurve)*)&C2);
723 Standard_Integer nbpoles = B1->NbPoles();
724 if (nbpoles != B2->NbPoles()) {
725 return Standard_False;
728 Standard_Integer nbknots = B1->NbKnots();
729 if (nbknots != B2->NbKnots()) {
730 return Standard_False;
733 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
737 Standard_Real tol3d = BRep_Tool::Tolerance(E1);
738 for (Standard_Integer p = 1; p <= nbpoles; p++) {
739 if ( (P1(p)).Distance(P2(p)) > tol3d) {
740 return Standard_False;
744 TColStd_Array1OfReal K1(1, nbknots), K2(1, nbknots);
748 TColStd_Array1OfInteger M1(1, nbknots), M2(1, nbknots);
749 B1->Multiplicities(M1);
750 B2->Multiplicities(M2);
752 for (Standard_Integer k = 1; k <= nbknots; k++) {
753 if ((K1(k)-K2(k)) > tollin) {
754 return Standard_False;
756 if (Abs(M1(k)-M2(k)) > tollin) {
757 return Standard_False;
761 if (!B1->IsRational()) {
762 if (B2->IsRational()) {
763 return Standard_False;
767 if (!B2->IsRational()) {
768 return Standard_False;
772 if (B1->IsRational()) {
773 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
777 for (Standard_Integer w = 1; w <= nbpoles; w++) {
778 if (Abs(W1(w)-W2(w)) > tollin) {
779 return Standard_False;
783 return Standard_True;
785 else if (typC1 == STANDARD_TYPE(Geom_BezierCurve)) {
787 // we must ensure that before fuse two bezier, the end of one curve does not
788 // corresponds to the beginning of the second.
789 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
790 return Standard_False;
793 Handle(Geom_BezierCurve) B1 = *((Handle(Geom_BezierCurve)*)&C1);
794 Handle(Geom_BezierCurve) B2 = *((Handle(Geom_BezierCurve)*)&C2);
796 Standard_Integer nbpoles = B1->NbPoles();
797 if (nbpoles != B2->NbPoles()) {
798 return Standard_False;
801 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
805 for (Standard_Integer p = 1; p <= nbpoles; p++) {
806 if ( (P1(p)).Distance(P2(p)) > tollin) {
807 return Standard_False;
811 if (!B1->IsRational()) {
812 if (B2->IsRational()) {
813 return Standard_False;
817 if (!B2->IsRational()) {
818 return Standard_False;
822 if (B1->IsRational()) {
823 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
827 for (Standard_Integer w = 1; w <= nbpoles; w++) {
828 if (Abs(W1(w)-W2(w)) > tollin) {
829 return Standard_False;
833 return Standard_True;
835 return Standard_False;
839 //=======================================================================
840 //function : BuildAncestors
841 //purpose : This function is like TopExp::MapShapesAndAncestors except
842 // that in the list of shape we do not want duplicate shapes.
843 // if this is useful for other purpose we should create a new method in
845 //=======================================================================
847 void TopOpeBRepTool_FuseEdges::BuildAncestors
848 (const TopoDS_Shape& S,
849 const TopAbs_ShapeEnum TS,
850 const TopAbs_ShapeEnum TA,
851 TopTools_IndexedDataMapOfShapeListOfShape& M) const
854 TopTools_MapOfShape mapDuplicate;
855 TopTools_ListIteratorOfListOfShape it;
856 Standard_Integer iSh;
858 TopExp::MapShapesAndAncestors(S,TS,TA,M);
860 // for each shape of M
861 for (iSh = 1; iSh <= M.Extent(); iSh++) {
862 TopTools_ListOfShape& Lsh = M(iSh);
864 mapDuplicate.Clear();
865 // we check for duplicate in the list of Shape
868 if (!mapDuplicate.Contains(it.Value())) {
869 mapDuplicate.Add(it.Value());
881 //=======================================================================
882 //function : UpdatePCurve
884 //=======================================================================
886 Standard_Boolean TopOpeBRepTool_FuseEdges::UpdatePCurve(const TopoDS_Edge& theOldEdge,
887 TopoDS_Edge& theNewEdge,
888 const TopTools_ListOfShape& theLstEdg) const
892 // get the pcurve of edge to substitute (theOldEdge)
893 // using CurveOnSurface with Index syntax, so we can update the pcurve
896 Handle(Geom2d_Curve) Curv2d;
897 Handle(Geom_Surface) Surf;
898 TopLoc_Location loc,locbid;
899 Standard_Real ef,el,cf,cl;
900 Standard_Integer iedg = 1;
902 // take care that we want only Pcurve that maps on the surface where the 3D edges lies.
903 const TopTools_ListOfShape& LmapFac = myMapEdgLstFac.FindFromKey(theOldEdge);
906 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
908 Standard_Boolean pcurveRebuilt = Standard_False;
910 while (!Curv2d.IsNull()) {
912 // we look for a face that contains the same surface as the one that cames
913 // from CurveOnSurface
914 Standard_Boolean SameSurf = Standard_False;
915 TopTools_ListIteratorOfListOfShape itFac;
917 for (itFac.Initialize(LmapFac); itFac.More(); itFac.Next() ) {
918 const TopoDS_Shape& face = itFac.Value();
919 Handle (Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(face),locbid);
921 SameSurf = Standard_True;
928 BRep_Tool::Range(theNewEdge,ef,el);
930 //modified by NIZNHY-PKV Mon Nov 15 14:59:48 1999 _from
931 TopoDS_Edge aFEdge = theOldEdge;
932 aFEdge.Orientation(TopAbs_FORWARD);
934 // take care if the edge is on the closing curve of a closed surface. In that case
935 // we get the second pcurve by reversing the edge and calling again CurveOnSurface method
937 BRep_Tool::CurveOnSurface(aFEdge,Curv2d,Surf,loc,cf,cl,iedg);
938 if (BRep_Tool::IsClosed(theOldEdge,Surf,loc)) {
940 TopoDS_Face aFFace = TopoDS::Face(itFac.Value());
941 aFFace.Orientation(TopAbs_FORWARD);
942 Handle(Geom2d_Curve) Curv2dR = BRep_Tool::CurveOnSurface(aFEdge,
944 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
945 Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
946 if (Curv2dR->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
947 Curv2dR = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2dR))->BasisCurve();
949 B.UpdateEdge (theNewEdge,Curv2d,Curv2dR,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
952 // update the new edge
953 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
954 Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
956 f = Curv2d->FirstParameter();
957 l = Curv2d->LastParameter();
958 if (l-f + 2.* Epsilon(l-f) < el-ef)
960 Handle(Geom2d_BoundedCurve) bcurve = Handle(Geom2d_BoundedCurve)::DownCast(Curv2d);
962 bcurve = new Geom2d_TrimmedCurve( Curv2d, cf, cl );
963 Geom2dConvert_CompCurveToBSplineCurve Concat( bcurve );
964 TopTools_ListIteratorOfListOfShape iter( theLstEdg );
966 for (; iter.More(); iter.Next())
968 TopoDS_Edge& E = TopoDS::Edge(iter.Value());
969 Standard_Real first, last;
970 Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface( E, Surf, loc, first, last );
971 Handle(Geom2d_BoundedCurve) BC = Handle(Geom2d_BoundedCurve)::DownCast(C);
973 BC = new Geom2d_TrimmedCurve( C, first, last );
974 if (!Concat.Add( BC, Precision::PConfusion() ))
975 // cannot merge pcurves
976 return Standard_False;
978 Curv2d = Concat.BSplineCurve();
980 // check that new curve 2d is same range
981 Standard_Real first = Curv2d->FirstParameter();
982 Standard_Real last = Curv2d->LastParameter();
983 if (Abs (first - ef) > Precision::PConfusion() ||
984 Abs (last - el) > Precision::PConfusion())
986 Handle(Geom2d_BSplineCurve) bc = Handle(Geom2d_BSplineCurve)::DownCast(Curv2d);
987 TColStd_Array1OfReal Knots (1, bc->NbKnots());
989 BSplCLib::Reparametrize (ef, el, Knots);
992 pcurveRebuilt = Standard_True;
995 B.UpdateEdge (theNewEdge,Curv2d,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
998 // the old pcurve range is cf,cl. The new 3d edge range is ef,el. if we want
999 // the pcurve to be samerange we must adapt the parameter of the edge. In general
1000 // cases cf=ef and cl=el expect for periodic curve if the new edge is going over
1002 if (theOldEdge.Orientation()== TopAbs_REVERSED) {
1003 B.Range(theNewEdge,cl-el+ef,cl);
1006 B.Range(theNewEdge,cf,cf+el-ef);
1012 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
1017 // force same parameter
1018 B.SameParameter (theNewEdge, Standard_False);
1019 BRepLib::SameParameter (theNewEdge, BRep_Tool::Tolerance(theNewEdge));
1022 return Standard_True;