1 // Created on: 1998-11-26
2 // Created by: Jean-Michel BOULCOURT
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
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
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
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)
22 #include <BRep_Builder.hxx>
23 #include <BRep_Tool.hxx>
24 #include <BRepLib.hxx>
25 #include <BRepLib_MakeEdge.hxx>
26 #include <BRepTools_Substitution.hxx>
27 #include <BSplCLib.hxx>
30 #include <Geom2d_BoundedCurve.hxx>
31 #include <Geom2d_BSplineCurve.hxx>
32 #include <Geom2d_Curve.hxx>
33 #include <Geom2d_TrimmedCurve.hxx>
34 #include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
35 #include <Geom_BezierCurve.hxx>
36 #include <Geom_BoundedCurve.hxx>
37 #include <Geom_BSplineCurve.hxx>
38 #include <Geom_Circle.hxx>
39 #include <Geom_Curve.hxx>
40 #include <Geom_Ellipse.hxx>
41 #include <Geom_Line.hxx>
42 #include <Geom_Plane.hxx>
43 #include <Geom_TrimmedCurve.hxx>
44 #include <GeomLib.hxx>
45 #include <gp_Dir2d.hxx>
46 #include <gp_Pnt2d.hxx>
47 #include <gp_Trsf2d.hxx>
48 #include <gp_Vec2d.hxx>
49 #include <Precision.hxx>
50 #include <Standard_ConstructionError.hxx>
51 #include <Standard_NullObject.hxx>
52 #include <TColgp_Array1OfPnt.hxx>
53 #include <TColStd_Array1OfInteger.hxx>
54 #include <TColStd_Array1OfReal.hxx>
56 #include <TopExp_Explorer.hxx>
58 #include <TopoDS_Edge.hxx>
59 #include <TopoDS_Face.hxx>
60 #include <TopoDS_Shape.hxx>
61 #include <TopoDS_Vertex.hxx>
62 #include <TopOpeBRepTool_FuseEdges.hxx>
63 #include <TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape.hxx>
64 #include <TopTools_DataMapOfIntegerListOfShape.hxx>
65 #include <TopTools_ListIteratorOfListOfShape.hxx>
66 #include <TopTools_ListOfShape.hxx>
67 #include <TopTools_MapOfShape.hxx>
70 extern Standard_Boolean TopOpeBRepBuild_GettraceFE();
73 //=======================================================================
74 //function : TopOpeBRepTool_FuseEdges
76 //=======================================================================
78 TopOpeBRepTool_FuseEdges::TopOpeBRepTool_FuseEdges(const TopoDS_Shape& theShape,
79 // const Standard_Boolean PerformNow)
80 const Standard_Boolean )
81 :myShape(theShape),myShapeDone(Standard_False),myEdgesDone(Standard_False),
82 myResultEdgesDone(Standard_False),myNbConnexEdge(0)
84 // if (theShape.ShapeType() != TopAbs_SHELL && theShape.ShapeType() != TopAbs_SOLID)
85 // throw Standard_ConstructionError("FuseEdges");
86 Standard_NullObject_Raise_if(theShape.IsNull(),"FuseEdges");
91 //=======================================================================
92 //function : AvoidEdges
93 //purpose : set edges to avoid being fused
94 //=======================================================================
96 void TopOpeBRepTool_FuseEdges::AvoidEdges(const TopTools_IndexedMapOfShape& theMapEdg)
98 myAvoidEdg = theMapEdg;
101 //=======================================================================
103 //purpose : returns all the list of edges to be fused each list of the
104 // map represent a set of connex edges that can be fused.
105 //=======================================================================
107 void TopOpeBRepTool_FuseEdges::Edges(TopTools_DataMapOfIntegerListOfShape& theMapLstEdg)
114 theMapLstEdg = myMapLstEdg;
118 //=======================================================================
119 //function : ResultEdges
120 //purpose : returns all the fused edges
121 //=======================================================================
123 void TopOpeBRepTool_FuseEdges::ResultEdges(TopTools_DataMapOfIntegerShape& theMapEdg)
130 if (!myResultEdgesDone) {
131 BuildListResultEdges();
134 theMapEdg = myMapEdg;
137 //=======================================================================
139 //purpose : returns all the faces that have been modified after perform
140 //=======================================================================
142 void TopOpeBRepTool_FuseEdges::Faces(TopTools_DataMapOfShapeShape& theMapFac)
149 if (!myResultEdgesDone) {
150 BuildListResultEdges();
157 theMapFac = myMapFaces;
161 //=======================================================================
162 //function : NbVertices
164 //=======================================================================
166 Standard_Integer TopOpeBRepTool_FuseEdges::NbVertices()
169 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
170 Standard_Integer nbedges, nbvertices = 0;
176 if ((nbedges = myMapLstEdg.Extent()) > 0) {
178 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itEdg;
179 for (itEdg.Initialize(myMapLstEdg); itEdg.More(); itEdg.Next()) {
180 const Standard_Integer& iLst = itEdg.Key();
181 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
182 nbvertices += LmapEdg.Extent() - 1;
191 //=======================================================================
194 //=======================================================================
196 TopoDS_Shape& TopOpeBRepTool_FuseEdges::Shape()
198 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
204 if (!myResultEdgesDone) {
205 BuildListResultEdges();
217 //=======================================================================
218 //function : BuildListEdges
219 //purpose : Build the all the lists of edges that are to be fused
220 //=======================================================================
222 void TopOpeBRepTool_FuseEdges::BuildListEdges()
226 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
230 if (tFE) std::cout<<std::endl<<"FuseEdges : BuildListEdges "<<std::endl;
233 //--------------------------------------------------------
234 // Step One : Build the map ancestors
235 //--------------------------------------------------------
239 myMapVerLstEdg.Clear();
240 myMapEdgLstFac.Clear();
242 TopExp::MapShapesAndUniqueAncestors(myShape,TopAbs_VERTEX,TopAbs_EDGE,myMapVerLstEdg);
243 TopExp::MapShapesAndAncestors(myShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgLstFac);
245 Standard_Integer iEdg;
246 TopTools_MapOfShape mapUniqEdg;
248 // for each edge of myMapEdgLstFac
249 for (iEdg = 1; iEdg <= myMapEdgLstFac.Extent(); iEdg++) {
250 const TopoDS_Shape& edgecur = myMapEdgLstFac.FindKey(iEdg);
251 TopTools_ListOfShape LstEdg;
253 // if edge not already treated
254 if (!mapUniqEdg.Contains(edgecur)
255 && (edgecur.Orientation() == TopAbs_FORWARD ||edgecur.Orientation() == TopAbs_REVERSED) ) {
256 if (myAvoidEdg.Contains(edgecur))
257 continue; // edge is not allowed to be fused
258 BuildListConnexEdge(edgecur, mapUniqEdg, LstEdg);
259 if (LstEdg.Extent() > 1) {
261 myMapLstEdg.Bind(myNbConnexEdge,LstEdg);
266 myEdgesDone = Standard_True;
267 myResultEdgesDone = Standard_False;
271 //=======================================================================
272 //function : BuildListResultEdges
273 //purpose : Build the result fused edges
274 //=======================================================================
276 void TopOpeBRepTool_FuseEdges::BuildListResultEdges()
280 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
284 if (tFE) std::cout<<std::endl<<"FuseEdges : BuildListResultEdges "<<std::endl;
287 // if we have edges to fuse
288 if (myMapLstEdg.Extent() > 0) {
289 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
291 Handle(Geom_Curve) C;
298 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
299 const Standard_Integer& iLst = itLstEdg.Key();
300 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
302 TopTools_ListIteratorOfListOfShape itEdg;
305 const TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
307 // the first edge of the list will be replaced by the result fusion edge
308 if (OldEdge.Orientation()==TopAbs_REVERSED) {
309 VL = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
310 VF = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
313 VF = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
314 VL = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
316 C = BRep_Tool::Curve(OldEdge,loc,f,l);
318 if (!loc.IsIdentity()) {
319 C = Handle(Geom_Curve)::DownCast(C->Transformed(loc.Transformation()));
321 // if the curve is trimmed we get the basis curve to fit the new vertices
322 // otherwise the makeedge will fail.
323 if (C->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
324 C = Handle(Geom_TrimmedCurve)::DownCast (C)->BasisCurve();
328 if (tFE) std::cout<<std::endl<<"FuseEdges : Creating New Edge "<<std::endl;
331 BRepLib_MakeEdge ME(C,VF,VL);
334 // the MakeEdge has fails, one reason could be that the new Vertices are outside
335 // the curve which is not infinite and limited to old vertices
336 // we try to use ExtendCurveToPoint, then rebuild the NewEdge
339 if (tFE) std::cout<<std::endl<<"FuseEdges : MakeEdge failed. Trying to Extend Curve "<<std::endl;
341 Handle(Geom_BoundedCurve) ExtC = Handle(Geom_BoundedCurve)::DownCast(C->Copy());
342 if (!ExtC.IsNull()) {
343 gp_Pnt PF = BRep_Tool::Pnt(VF);
344 gp_Pnt PL = BRep_Tool::Pnt(VL);
345 GeomLib::ExtendCurveToPoint(ExtC,PF,1,0);
346 GeomLib::ExtendCurveToPoint(ExtC,PL,1,1);
350 throw Standard_ConstructionError("FuseEdges : Fusion failed");
353 throw Standard_ConstructionError("FuseEdges : Fusion failed");
359 if (tFE) std::cout<<std::endl<<"FuseEdges : Updating pcurve "<<std::endl;
361 if (UpdatePCurve(OldEdge,NewEdge,LmapEdg))
362 myMapEdg.Bind(iLst,NewEdge);
365 myResultEdgesDone = Standard_True;
370 //=======================================================================
373 //=======================================================================
375 void TopOpeBRepTool_FuseEdges::Perform()
379 Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
382 if (!myResultEdgesDone) {
383 BuildListResultEdges();
387 if (tFE) std::cout<<std::endl<<"FuseEdges : Perform "<<std::endl;
390 // if we have fused edges
391 if (myMapEdg.Extent() > 0) {
392 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
393 TopTools_ListOfShape EmptyList,EdgeToSubs;
394 BRepTools_Substitution Bsub;
396 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
397 const Standard_Integer& iLst = itLstEdg.Key();
398 if (!myMapEdg.IsBound(iLst))
400 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
401 TopTools_ListIteratorOfListOfShape itEdg;
404 const TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
407 EdgeToSubs.Append(myMapEdg(iLst));
408 Bsub.Substitute(OldEdge,EdgeToSubs);
410 itEdg.Initialize(LmapEdg);
412 // the other edges of the list will be removed
413 while (itEdg.More() ) {
414 if (!OldEdge.IsSame(TopoDS::Edge(itEdg.Value()))) {
415 Bsub.Substitute(itEdg.Value(),EmptyList);
422 if (tFE) std::cout<<std::endl<<"FuseEdges : Building New Shape "<<std::endl;
425 // perform the effective substitution
428 // before copying the resulting shape, map the modified faces into myMapFaces
429 TopExp_Explorer exp(myShape,TopAbs_FACE);
431 for (; exp.More(); exp.Next()) {
432 const TopoDS_Shape& facecur = exp.Current();
433 if (Bsub.IsCopied(facecur)) {
434 myMapFaces.Bind(facecur,(Bsub.Copy(facecur)).First());
438 if (Bsub.IsCopied(myShape)) {
439 myShape=(Bsub.Copy(myShape)).First();
443 if (tFE) std::cout<<std::endl<<"FuseEdges : "<< NbVertices() <<" vertices removed"<<std::endl;
450 myShapeDone = Standard_True;
455 //=======================================================================
456 //function : BuildListConnexEdge
457 //purpose : giving one edge, build the list of connex edges which have
458 // vertices that have only two connex edges. All the edges that are addes
459 // to the list must be added also to the mapUniq, in order for the caller
460 // to not treat again theses edges.
461 // This list is always oriented in the "Forward" direction.
462 //=======================================================================
464 void TopOpeBRepTool_FuseEdges::BuildListConnexEdge(const TopoDS_Shape& theEdge,
465 TopTools_MapOfShape& theMapUniq,
466 TopTools_ListOfShape& theLstEdg)
472 VL = TopExp::LastVertex(TopoDS::Edge(theEdge),Standard_True);
473 TopoDS_Shape edgeconnex;
474 TopoDS_Shape edgecur = theEdge;
476 theLstEdg.Append(edgecur);
477 theMapUniq.Add(edgecur);
478 TopAbs_Orientation ori2;
480 // we first build the list of edges connex to edgecur by looking from the last Vertex VL
481 while (NextConnexEdge(VL,edgecur,edgeconnex)) {
482 if (theMapUniq.Contains(edgeconnex)) {
485 theLstEdg.Append(edgeconnex);
486 edgecur = edgeconnex;
487 // here take care about internal or external edges. It is non-sense to build
488 // the connex list with such edges.
489 ori2 = edgecur.Orientation();
490 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
493 VL = TopExp::LastVertex(TopoDS::Edge(edgecur),Standard_True);
494 theMapUniq.Add(edgecur);
498 VF = TopExp::FirstVertex(TopoDS::Edge(theEdge),Standard_True);
500 // then we build the list of edges connex to edgecur by looking from the first Vertex VF
501 while (NextConnexEdge(VF,edgecur,edgeconnex)) {
502 if (theMapUniq.Contains(edgeconnex)) {
505 theLstEdg.Prepend(edgeconnex);
506 edgecur = edgeconnex;
507 // here take care about internal or external edges. It is non-sense to build
508 // the connex list with such edges.
509 ori2 = edgecur.Orientation();
510 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
513 VF = TopExp::FirstVertex(TopoDS::Edge(edgecur),Standard_True);
514 theMapUniq.Add(edgecur);
520 //=======================================================================
521 //function : NextConnexEdge
522 //purpose : Look for an edge connex to theEdge at theVertex.
523 // the connex edge must satisfies the following criteria :
524 // * theVertex must have exactly 2 connex edges.
525 // * the 2 connex edges must have exactly the 2 same connex faces
526 // * the 2 connex edges must lie on the same support.
527 //=======================================================================
529 Standard_Boolean TopOpeBRepTool_FuseEdges::NextConnexEdge(const TopoDS_Vertex& theVertex,
530 const TopoDS_Shape& theEdge,
531 TopoDS_Shape& theEdgeConnex) const
534 const TopTools_ListOfShape& LmapEdg = myMapVerLstEdg.FindFromKey(theVertex);
535 Standard_Boolean HasConnex = Standard_True;
536 TopTools_ListIteratorOfListOfShape itEdg,itFac1,itFac2;
539 if (LmapEdg.Extent() == 2) {
540 itEdg.Initialize(LmapEdg);
541 theEdgeConnex = itEdg.Value();
542 if (theEdge.IsSame(theEdgeConnex) ) {
544 theEdgeConnex = itEdg.Value();
547 if (myAvoidEdg.Contains(theEdgeConnex))
548 HasConnex = Standard_False; // edge is not allowed to be fused
552 const TopTools_ListOfShape& LmapFac1 = myMapEdgLstFac.FindFromKey(theEdge);
553 const TopTools_ListOfShape& LmapFac2 = myMapEdgLstFac.FindFromKey(theEdgeConnex);
555 if (LmapFac1.Extent() == LmapFac2.Extent() && LmapFac1.Extent() < 3) {
556 itFac1.Initialize(LmapFac1);
558 // for each face in LmapFac1 we look in LmapFac2 if it exists
559 while (itFac1.More() && HasConnex) {
560 const TopoDS_Shape& face1 = itFac1.Value();
561 for (itFac2.Initialize(LmapFac2); itFac2.More(); itFac2.Next()) {
562 const TopoDS_Shape& face2 = itFac2.Value();
563 HasConnex = Standard_False;
564 if (face1.IsSame(face2)) {
565 HasConnex = Standard_True;
572 // 3rd condition : same suport
574 HasConnex = SameSupport(TopoDS::Edge(theEdge),TopoDS::Edge(theEdgeConnex));
578 HasConnex = Standard_False;
582 HasConnex = Standard_False;
589 //=======================================================================
590 //function : SameSupport
591 //purpose : Edges SameSupport ou pas
592 //=======================================================================
594 Standard_Boolean TopOpeBRepTool_FuseEdges::SameSupport(const TopoDS_Edge& E1,
595 const TopoDS_Edge& E2) const
598 if (E1.IsNull() || E2.IsNull()) {
599 return Standard_False;
603 Handle(Geom_Curve) C1,C2;
605 Standard_Real f1,l1,f2,l2;
606 Handle(Standard_Type) typC1,typC2;
608 C1 = BRep_Tool::Curve(E1,loc,f1,l1);
609 //modified by NIZNHY-PKV Mon Nov 15 16:24:10 1999
610 //degenerated edges has no 3D curve
611 if(C1.IsNull()) return Standard_False;
613 if (!loc.IsIdentity()) {
614 Handle(Geom_Geometry) GG1 = C1->Transformed(loc.Transformation());
615 C1 = Handle(Geom_Curve)::DownCast (GG1);
617 C2 = BRep_Tool::Curve(E2,loc,f2,l2);
618 //modified by NIZNHY-PKV Mon Nov 15 16:24:38 1999
619 //degenerated edges has no 3D curve
620 if(C2.IsNull()) return Standard_False;
622 if (!loc.IsIdentity()) {
623 Handle(Geom_Geometry) GG2 = C2->Transformed(loc.Transformation());
624 C2 = Handle(Geom_Curve)::DownCast (GG2);
627 typC1 = C1->DynamicType();
628 typC2 = C2->DynamicType();
630 if (typC1 == STANDARD_TYPE(Geom_TrimmedCurve)) {
631 C1 = Handle(Geom_TrimmedCurve)::DownCast (C1)->BasisCurve();
632 typC1 = C1->DynamicType();
635 if (typC2 == STANDARD_TYPE(Geom_TrimmedCurve)) {
636 C2 = Handle(Geom_TrimmedCurve)::DownCast (C2)->BasisCurve();
637 typC2 = C2->DynamicType();
640 if (typC1 != typC2) {
641 return Standard_False;
644 if (typC1 != STANDARD_TYPE(Geom_Line) &&
645 typC1 != STANDARD_TYPE(Geom_Circle) &&
646 typC1 != STANDARD_TYPE(Geom_Ellipse) &&
647 typC1 != STANDARD_TYPE(Geom_BSplineCurve) &&
648 typC1 != STANDARD_TYPE(Geom_BezierCurve)) {
650 std::cout << " TopOpeBRepTool_FuseEdge : Type de Support non traite" << std::endl;
652 return Standard_False;
655 // On a presomption de confusion
656 const Standard_Real tollin = Precision::Confusion();
657 const Standard_Real tolang = Precision::Angular();
658 if (typC1 == STANDARD_TYPE(Geom_Line)) {
659 gp_Lin li1( Handle(Geom_Line)::DownCast (C1)->Lin());
660 gp_Lin li2( Handle(Geom_Line)::DownCast (C2)->Lin());
661 gp_Dir dir1(li1.Direction());
662 gp_Dir dir2(li2.Direction());
664 if ( dir1.IsParallel(dir2,tolang) ) {
665 // on verifie que l'on n'a pas de cas degenere. Par exemple E1 et E2 connexes
666 // mais bouclant l'un sur l'autre (cas tres rare)
667 gp_Pnt pf1 = BRep_Tool::Pnt(TopExp::FirstVertex(E1,Standard_True));
668 gp_Pnt pl1 = BRep_Tool::Pnt(TopExp::LastVertex(E1,Standard_True));
669 gp_Pnt pf2 = BRep_Tool::Pnt(TopExp::FirstVertex(E2,Standard_True));
670 gp_Pnt pl2 = BRep_Tool::Pnt(TopExp::LastVertex(E2,Standard_True));
671 if ( pl1.Distance(pf2) < tollin && pl2.Distance(pf1) < tollin)
672 return Standard_False;
674 return Standard_True;
676 return Standard_False;
678 else if (typC1 == STANDARD_TYPE(Geom_Circle)) {
679 gp_Circ ci1 = Handle(Geom_Circle)::DownCast (C1)->Circ();
680 gp_Circ ci2 = Handle(Geom_Circle)::DownCast (C2)->Circ();
681 if (Abs(ci1.Radius()-ci2.Radius()) <= tollin &&
682 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
683 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
684 // Point debut, calage dans periode, et detection meme sens
685 return Standard_True;
687 return Standard_False;
689 else if (typC1 == STANDARD_TYPE(Geom_Ellipse)) {
690 gp_Elips ci1 = Handle(Geom_Ellipse)::DownCast (C1)->Elips();
691 gp_Elips ci2 = Handle(Geom_Ellipse)::DownCast (C2)->Elips();
693 if (Abs(ci1.MajorRadius()-ci2.MajorRadius()) <= tollin &&
694 Abs(ci1.MinorRadius()-ci2.MinorRadius()) <= tollin &&
695 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
696 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
697 // Point debut, calage dans periode, et detection meme sens
698 return Standard_True;
700 return Standard_False;
702 else if (typC1 == STANDARD_TYPE(Geom_BSplineCurve)) {
704 // we must ensure that before fuse two bsplines, the end of one curve does not
705 // corresponds to the beginning of the second.
706 // we could add a special treatment for periodic bspline. This is not done for the moment.
707 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
708 return Standard_False;
711 Handle(Geom_BSplineCurve) B1 = Handle(Geom_BSplineCurve)::DownCast (C1);
712 Handle(Geom_BSplineCurve) B2 = Handle(Geom_BSplineCurve)::DownCast (C2);
714 Standard_Integer nbpoles = B1->NbPoles();
715 if (nbpoles != B2->NbPoles()) {
716 return Standard_False;
719 Standard_Integer nbknots = B1->NbKnots();
720 if (nbknots != B2->NbKnots()) {
721 return Standard_False;
724 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
728 Standard_Real tol3d = BRep_Tool::Tolerance(E1);
729 for (Standard_Integer p = 1; p <= nbpoles; p++) {
730 if ( (P1(p)).Distance(P2(p)) > tol3d) {
731 return Standard_False;
735 TColStd_Array1OfReal K1(1, nbknots), K2(1, nbknots);
739 TColStd_Array1OfInteger M1(1, nbknots), M2(1, nbknots);
740 B1->Multiplicities(M1);
741 B2->Multiplicities(M2);
743 for (Standard_Integer k = 1; k <= nbknots; k++) {
744 if ((K1(k)-K2(k)) > tollin) {
745 return Standard_False;
747 if (Abs(M1(k)-M2(k)) > tollin) {
748 return Standard_False;
752 if (!B1->IsRational()) {
753 if (B2->IsRational()) {
754 return Standard_False;
758 if (!B2->IsRational()) {
759 return Standard_False;
763 if (B1->IsRational()) {
764 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
768 for (Standard_Integer w = 1; w <= nbpoles; w++) {
769 if (Abs(W1(w)-W2(w)) > tollin) {
770 return Standard_False;
774 return Standard_True;
776 else if (typC1 == STANDARD_TYPE(Geom_BezierCurve)) {
778 // we must ensure that before fuse two bezier, the end of one curve does not
779 // corresponds to the beginning of the second.
780 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
781 return Standard_False;
784 Handle(Geom_BezierCurve) B1 = Handle(Geom_BezierCurve)::DownCast (C1);
785 Handle(Geom_BezierCurve) B2 = Handle(Geom_BezierCurve)::DownCast (C2);
787 Standard_Integer nbpoles = B1->NbPoles();
788 if (nbpoles != B2->NbPoles()) {
789 return Standard_False;
792 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
796 for (Standard_Integer p = 1; p <= nbpoles; p++) {
797 if ( (P1(p)).Distance(P2(p)) > tollin) {
798 return Standard_False;
802 if (!B1->IsRational()) {
803 if (B2->IsRational()) {
804 return Standard_False;
808 if (!B2->IsRational()) {
809 return Standard_False;
813 if (B1->IsRational()) {
814 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
818 for (Standard_Integer w = 1; w <= nbpoles; w++) {
819 if (Abs(W1(w)-W2(w)) > tollin) {
820 return Standard_False;
824 return Standard_True;
826 return Standard_False;
829 //=======================================================================
830 //function : UpdatePCurve
832 //=======================================================================
834 Standard_Boolean TopOpeBRepTool_FuseEdges::UpdatePCurve(const TopoDS_Edge& theOldEdge,
835 TopoDS_Edge& theNewEdge,
836 const TopTools_ListOfShape& theLstEdg) const
840 // get the pcurve of edge to substitute (theOldEdge)
841 // using CurveOnSurface with Index syntax, so we can update the pcurve
844 Handle(Geom2d_Curve) Curv2d;
845 Handle(Geom_Surface) Surf;
846 TopLoc_Location loc,locbid;
847 Standard_Real ef,el,cf,cl;
848 Standard_Integer iedg = 1;
850 // take care that we want only Pcurve that maps on the surface where the 3D edges lies.
851 const TopTools_ListOfShape& LmapFac = myMapEdgLstFac.FindFromKey(theOldEdge);
854 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
856 Standard_Boolean pcurveRebuilt = Standard_False;
858 while (!Curv2d.IsNull()) {
860 // we look for a face that contains the same surface as the one that cames
861 // from CurveOnSurface
862 Standard_Boolean SameSurf = Standard_False;
863 TopTools_ListIteratorOfListOfShape itFac;
865 for (itFac.Initialize(LmapFac); itFac.More(); itFac.Next() ) {
866 const TopoDS_Shape& face = itFac.Value();
867 Handle (Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(face),locbid);
869 SameSurf = Standard_True;
876 BRep_Tool::Range(theNewEdge,ef,el);
878 //modified by NIZNHY-PKV Mon Nov 15 14:59:48 1999 _from
879 TopoDS_Edge aFEdge = theOldEdge;
880 aFEdge.Orientation(TopAbs_FORWARD);
882 // take care if the edge is on the closing curve of a closed surface. In that case
883 // we get the second pcurve by reversing the edge and calling again CurveOnSurface method
885 BRep_Tool::CurveOnSurface(aFEdge,Curv2d,Surf,loc,cf,cl,iedg);
886 if (BRep_Tool::IsClosed(theOldEdge,Surf,loc)) {
888 TopoDS_Face aFFace = TopoDS::Face(itFac.Value());
889 aFFace.Orientation(TopAbs_FORWARD);
890 Handle(Geom2d_Curve) Curv2dR = BRep_Tool::CurveOnSurface(aFEdge,
892 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
893 Curv2d = Handle(Geom2d_TrimmedCurve)::DownCast (Curv2d)->BasisCurve();
894 if (Curv2dR->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
895 Curv2dR = Handle(Geom2d_TrimmedCurve)::DownCast (Curv2dR)->BasisCurve();
897 B.UpdateEdge (theNewEdge,Curv2d,Curv2dR,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
900 // update the new edge
901 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
902 Curv2d = Handle(Geom2d_TrimmedCurve)::DownCast (Curv2d)->BasisCurve();
904 f = Curv2d->FirstParameter();
905 l = Curv2d->LastParameter();
906 if (l-f + 2.* Epsilon(l-f) < el-ef)
908 Handle(Geom2d_BoundedCurve) bcurve = Handle(Geom2d_BoundedCurve)::DownCast(Curv2d);
910 bcurve = new Geom2d_TrimmedCurve( Curv2d, cf, cl );
911 Geom2dConvert_CompCurveToBSplineCurve Concat( bcurve );
912 TopTools_ListIteratorOfListOfShape iter( theLstEdg );
914 for (; iter.More(); iter.Next())
916 TopoDS_Edge& E = TopoDS::Edge(iter.Value());
917 Standard_Real first, last;
918 Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface( E, Surf, loc, first, last );
919 Handle(Geom2d_BoundedCurve) BC = Handle(Geom2d_BoundedCurve)::DownCast(C);
921 BC = new Geom2d_TrimmedCurve( C, first, last );
922 if (!Concat.Add( BC, Precision::PConfusion() ))
923 // cannot merge pcurves
924 return Standard_False;
926 Curv2d = Concat.BSplineCurve();
928 // check that new curve 2d is same range
929 Standard_Real first = Curv2d->FirstParameter();
930 Standard_Real last = Curv2d->LastParameter();
931 if (Abs (first - ef) > Precision::PConfusion() ||
932 Abs (last - el) > Precision::PConfusion())
934 Handle(Geom2d_BSplineCurve) bc = Handle(Geom2d_BSplineCurve)::DownCast(Curv2d);
935 TColStd_Array1OfReal Knots (1, bc->NbKnots());
937 BSplCLib::Reparametrize (ef, el, Knots);
940 pcurveRebuilt = Standard_True;
943 B.UpdateEdge (theNewEdge,Curv2d,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
946 // the old pcurve range is cf,cl. The new 3d edge range is ef,el. if we want
947 // the pcurve to be samerange we must adapt the parameter of the edge. In general
948 // cases cf=ef and cl=el expect for periodic curve if the new edge is going over
950 if (theOldEdge.Orientation()== TopAbs_REVERSED) {
951 B.Range(theNewEdge,cl-el+ef,cl);
954 B.Range(theNewEdge,cf,cf+el-ef);
960 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
965 // force same parameter
966 B.SameParameter (theNewEdge, Standard_False);
967 BRepLib::SameParameter (theNewEdge, BRep_Tool::Tolerance(theNewEdge));
970 return Standard_True;