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 <BRepLib_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>
73 #include <TopoDS_Wire.hxx>
75 #include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
76 #include <Geom2d_BSplineCurve.hxx>
77 #include <BSplCLib.hxx>
78 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
79 #include <Extrema_LocateExtPC.hxx>
80 #include <GeomAdaptor_Curve.hxx>
81 #include <GeomConvert.hxx>
84 //Standard_IMPORT Standard_Boolean TopOpeBRepBuild_GettraceFE();
87 static void BCSmoothing(Handle(Geom_BSplineCurve)& theC,
88 const Standard_Integer theCont,
89 const Standard_Real theTol)
92 Standard_Integer aNbIter = 5;
93 Standard_Boolean bContinue = Standard_True;
94 Standard_Integer iter = 1;
95 TColStd_SequenceOfInteger aKnotIndex;
96 TColStd_SequenceOfReal aKnotIns;
98 while (bContinue && iter <= aNbIter) {
100 Standard_Integer aNbKnots = theC->NbKnots();
101 TColStd_Array1OfInteger aMults(1, aNbKnots);
102 TColStd_Array1OfReal aKnots(1, aNbKnots);
104 theC->Multiplicities(aMults);
106 Standard_Integer i, m = theC->Degree();
113 for(i = 2; i < aNbKnots; i++) {
115 if(!(theC->RemoveKnot(i, m, theTol))) {
116 aKnotIndex.Append(i);
121 //Prepare knots for inserting;
123 Standard_Integer aNbAdd = aKnotIndex.Length();
125 if(aNbAdd == 0) return;
129 Standard_Real aLastKnot = aKnots(1);
130 for(i = 1; i <= aNbAdd; i++) {
132 Standard_Integer anInd = aKnotIndex(i);
134 Standard_Real aK1 = 0.5*(aKnots(anInd) + aKnots(anInd-1));
135 if(Abs(aK1 - aLastKnot) > 1.e-3) {
136 aKnotIns.Append(aK1);
140 Standard_Real aK2 = 0.5*(aKnots(anInd+1) + aKnots(anInd));
142 if(Abs(aK2 - aLastKnot) > 1.e-3) {
143 aKnotIns.Append(aK2);
149 aNbAdd = aKnotIns.Length();
151 for(i = 1; i <= aNbAdd; i++) {
152 theC->InsertKnot(aKnotIns(i), m, 1.e-3);
159 if(iter > aNbIter) BCSmoothing(theC, theCont, 1.e10);
164 static void MakeClosedCurve(Handle(Geom_Curve)& C, const gp_Pnt& PF,
165 Standard_Real& f, Standard_Real& l)
167 Handle(Geom_BSplineCurve) aBC = (*((Handle(Geom_BSplineCurve)*)&C));
168 GeomAbs_Shape aCont = aBC->Continuity();
171 Standard_Integer fk = aBC->FirstUKnotIndex();
172 Standard_Integer lk = aBC->LastUKnotIndex();
174 Standard_Real eps = Precision::Confusion();
176 Standard_Real porig = 2.*l;
177 Standard_Real dmin = 1.e100, pmin = f;
178 for(k = fk; k <= lk; k++) {
179 gp_Pnt aP = aBC->Value(aBC->Knot(k));
180 Standard_Real d = PF.SquareDistance(aP);
181 if(PF.SquareDistance(aP) > eps) {
189 porig = aBC->Knot(k);
194 GeomAdaptor_Curve aGAC(aBC);
195 Extrema_LocateExtPC aPrj(PF, aGAC, pmin, Precision::PConfusion());
197 porig = aPrj.Point().Parameter();
200 Standard_ConstructionError::Raise("FuseEdges : Projection failed for closed curve");
204 aBC->SetOrigin(porig, Precision::PConfusion());
205 f = aBC->FirstParameter();
206 l = aBC->LastParameter();
208 if(aCont > GeomAbs_C0 && aBC->Continuity() == GeomAbs_C0) {
209 BCSmoothing(aBC, 1, Precision::Confusion());
212 f = C->FirstParameter();
213 l = C->LastParameter();
218 //=======================================================================
219 //function : BRepLib_FuseEdges
221 //=======================================================================
223 BRepLib_FuseEdges::BRepLib_FuseEdges(const TopoDS_Shape& theShape,
224 // const Standard_Boolean PerformNow)
225 const Standard_Boolean )
226 :myShape(theShape),myShapeDone(Standard_False),myEdgesDone(Standard_False),
227 myResultEdgesDone(Standard_False),myNbConnexEdge(0), myConcatBSpl(Standard_False)
229 // if (theShape.ShapeType() != TopAbs_SHELL && theShape.ShapeType() != TopAbs_SOLID)
230 // Standard_ConstructionError::Raise("FuseEdges");
231 Standard_NullObject_Raise_if(theShape.IsNull(),"FuseEdges");
236 //=======================================================================
237 //function : AvoidEdges
238 //purpose : set edges to avoid being fused
239 //=======================================================================
241 void BRepLib_FuseEdges::AvoidEdges(const TopTools_IndexedMapOfShape& theMapEdg)
243 myAvoidEdg = theMapEdg;
246 //=======================================================================
247 //function : SetConcatBSpl
249 //=======================================================================
251 void BRepLib_FuseEdges::SetConcatBSpl(const Standard_Boolean theConcatBSpl)
253 myConcatBSpl = theConcatBSpl;
256 //=======================================================================
258 //purpose : returns all the list of edges to be fused each list of the
259 // map represent a set of connex edges that can be fused.
260 //=======================================================================
262 void BRepLib_FuseEdges::Edges(TopTools_DataMapOfIntegerListOfShape& theMapLstEdg)
269 theMapLstEdg = myMapLstEdg;
273 //=======================================================================
274 //function : ResultEdges
275 //purpose : returns all the fused edges
276 //=======================================================================
278 void BRepLib_FuseEdges::ResultEdges(TopTools_DataMapOfIntegerShape& theMapEdg)
285 if (!myResultEdgesDone) {
286 BuildListResultEdges();
289 theMapEdg = myMapEdg;
292 //=======================================================================
294 //purpose : returns all the faces that have been modified after perform
295 //=======================================================================
297 void BRepLib_FuseEdges::Faces(TopTools_DataMapOfShapeShape& theMapFac)
304 if (!myResultEdgesDone) {
305 BuildListResultEdges();
312 theMapFac = myMapFaces;
316 //=======================================================================
317 //function : NbVertices
319 //=======================================================================
321 const Standard_Integer BRepLib_FuseEdges::NbVertices()
324 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
325 Standard_Integer nbedges, nbvertices = 0;
331 if ((nbedges = myMapLstEdg.Extent()) > 0) {
333 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itEdg;
334 for (itEdg.Initialize(myMapLstEdg); itEdg.More(); itEdg.Next()) {
335 const Standard_Integer& iLst = itEdg.Key();
336 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
337 nbvertices += LmapEdg.Extent() - 1;
346 //=======================================================================
349 //=======================================================================
351 TopoDS_Shape& BRepLib_FuseEdges::Shape()
353 Standard_NullObject_Raise_if(myShape.IsNull(),"FuseEdges : No Shape");
359 if (!myResultEdgesDone) {
360 BuildListResultEdges();
372 //=======================================================================
373 //function : BuildListEdges
374 //purpose : Build the all the lists of edges that are to be fused
375 //=======================================================================
377 void BRepLib_FuseEdges::BuildListEdges()
381 //Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
385 //if (tFE) cout<<endl<<"FuseEdges : BuildListEdges "<<endl;
388 //--------------------------------------------------------
389 // Step One : Build the map ancestors
390 //--------------------------------------------------------
394 myMapVerLstEdg.Clear();
395 myMapEdgLstFac.Clear();
397 BuildAncestors(myShape,TopAbs_VERTEX,TopAbs_EDGE,myMapVerLstEdg);
398 TopExp::MapShapesAndAncestors(myShape,TopAbs_EDGE,TopAbs_FACE,myMapEdgLstFac);
400 Standard_Integer iEdg;
401 TopTools_MapOfShape mapUniqEdg;
403 // for each edge of myMapEdgLstFac
404 for (iEdg = 1; iEdg <= myMapEdgLstFac.Extent(); iEdg++) {
405 const TopoDS_Shape& edgecur = myMapEdgLstFac.FindKey(iEdg);
406 TopTools_ListOfShape LstEdg;
408 // if edge not already treated
409 if (!mapUniqEdg.Contains(edgecur)
410 && (edgecur.Orientation() == TopAbs_FORWARD ||edgecur.Orientation() == TopAbs_REVERSED) ) {
411 if (myAvoidEdg.Contains(edgecur))
412 continue; // edge is not allowed to be fused
413 BuildListConnexEdge(edgecur, mapUniqEdg, LstEdg);
414 if (LstEdg.Extent() > 1) {
416 myMapLstEdg.Bind(myNbConnexEdge,LstEdg);
421 myEdgesDone = Standard_True;
422 myResultEdgesDone = Standard_False;
426 //=======================================================================
427 //function : BuildListResultEdges
428 //purpose : Build the result fused edges
429 //=======================================================================
431 void BRepLib_FuseEdges::BuildListResultEdges()
435 //Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
439 //if (tFE) cout<<endl<<"FuseEdges : BuildListResultEdges "<<endl;
442 // if we have edges to fuse
443 if (myMapLstEdg.Extent() > 0) {
444 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
446 Handle(Geom_Curve) C;
453 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
454 const Standard_Integer& iLst = itLstEdg.Key();
455 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
457 TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
459 // the first edge of the list will be replaced by the result fusion edge
460 if (OldEdge.Orientation()==TopAbs_REVERSED) {
461 VL = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
462 VF = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
465 VF = TopExp::FirstVertex(TopoDS::Edge(LmapEdg.First()),Standard_True);
466 VL = TopExp::LastVertex(TopoDS::Edge(LmapEdg.Last()),Standard_True);
468 C = BRep_Tool::Curve(OldEdge,loc,f,l);
470 if (!loc.IsIdentity()) {
471 C = Handle(Geom_Curve)::DownCast(C->Transformed(loc.Transformation()));
473 // if the curve is trimmed we get the basis curve to fit the new vertices
474 // otherwise the makeedge will fail.
475 if (C->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
476 C = (*((Handle(Geom_TrimmedCurve)*)&C))->BasisCurve();
480 //Prepare common BSpline curve
481 if(C->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
482 TopTools_ListIteratorOfListOfShape anEdgIter(LmapEdg);
483 Handle(Geom_TrimmedCurve) aTC = new Geom_TrimmedCurve(C, f, l);
484 GeomConvert_CompCurveToBSplineCurve Concat( aTC );
487 for(; anEdgIter.More(); anEdgIter.Next()) {
488 Handle(Geom_Curve) aC = BRep_Tool::Curve(TopoDS::Edge(anEdgIter.Value()), f, l);
489 aTC = new Geom_TrimmedCurve(aC, f, l);
490 if (!Concat.Add(aTC, Precision::Confusion())) {
491 // cannot merge curves
492 Standard_ConstructionError::Raise("FuseEdges : Concatenation failed");
495 C = Concat.BSplineCurve();
501 //if (tFE) cout<<endl<<"FuseEdges : Creating New Edge "<<endl;
506 Standard_Boolean isBSpline = C->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve);
508 if(VF.IsSame(VL) && isBSpline) {
510 f = C->FirstParameter();
511 l = C->LastParameter();
512 gp_Pnt aPf = C->Value(f);
513 gp_Pnt aPl = C->Value(l);
514 if(aPf.Distance(aPl) > Precision::Confusion()) {
515 Standard_ConstructionError::Raise("FuseEdges : Curve must be closed");
517 gp_Pnt PF = BRep_Tool::Pnt(VF);
518 if(PF.Distance(aPf) > Precision::Confusion()) {
519 MakeClosedCurve(C, PF, f, l);
522 ME.Init(C, VF, VL, f, l);
524 Standard_ConstructionError::Raise("FuseEdges : MakeEdge failed for closed curve");
530 // BRepLib_MakeEdge ME(C,VF,VL);
533 // the MakeEdge has fails, one reason could be that the new Vertices are outside
534 // the curve which is not infinite and limited to old vertices
535 // we try to use ExtendCurveToPoint, then rebuild the NewEdge
538 //if (tFE) cout<<endl<<"FuseEdges : MakeEdge failed. Trying to Extend Curve "<<endl;
540 Handle(Geom_BoundedCurve) ExtC = Handle(Geom_BoundedCurve)::DownCast(C->Copy());
541 if (!ExtC.IsNull()) {
542 gp_Pnt PF = BRep_Tool::Pnt(VF);
543 gp_Pnt PL = BRep_Tool::Pnt(VL);
544 GeomLib::ExtendCurveToPoint(ExtC,PF,1,0);
545 GeomLib::ExtendCurveToPoint(ExtC,PL,1,1);
549 Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
552 Standard_ConstructionError::Raise("FuseEdges : Fusion failed");
558 //if (tFE) cout<<endl<<"FuseEdges : Updating pcurve "<<endl;
560 if (UpdatePCurve(OldEdge,NewEdge,LmapEdg))
561 myMapEdg.Bind(iLst,NewEdge);
564 myResultEdgesDone = Standard_True;
569 //=======================================================================
572 //=======================================================================
574 void BRepLib_FuseEdges::Perform()
578 //Standard_Boolean tFE = TopOpeBRepBuild_GettraceFE();
581 if (!myResultEdgesDone) {
582 BuildListResultEdges();
586 //if (tFE) cout<<endl<<"FuseEdges : Perform "<<endl;
589 // if we have fused edges
590 if (myMapEdg.Extent() > 0) {
591 TopTools_DataMapIteratorOfDataMapOfIntegerListOfShape itLstEdg;
592 TopTools_ListOfShape EmptyList,EdgeToSubs;
593 BRepTools_Substitution Bsub;
595 for (itLstEdg.Initialize(myMapLstEdg); itLstEdg.More(); itLstEdg.Next()) {
596 const Standard_Integer& iLst = itLstEdg.Key();
597 if (!myMapEdg.IsBound(iLst))
599 const TopTools_ListOfShape& LmapEdg = myMapLstEdg.Find(iLst);
600 TopTools_ListIteratorOfListOfShape itEdg;
603 TopoDS_Edge& OldEdge = TopoDS::Edge(LmapEdg.First());
606 EdgeToSubs.Append(myMapEdg(iLst));
607 Bsub.Substitute(OldEdge,EdgeToSubs);
609 itEdg.Initialize(LmapEdg);
611 // the other edges of the list will be removed
612 while (itEdg.More() ) {
613 if (!OldEdge.IsSame(TopoDS::Edge(itEdg.Value()))) {
614 Bsub.Substitute(itEdg.Value(),EmptyList);
621 //if (tFE) cout<<endl<<"FuseEdges : Building New Shape "<<endl;
624 // perform the effective substitution
627 // before copying the resulting shape, map the modified faces into myMapFaces
628 TopExp_Explorer exp(myShape,TopAbs_FACE);
630 for (; exp.More(); exp.Next()) {
631 const TopoDS_Shape& facecur = exp.Current();
632 if (Bsub.IsCopied(facecur)) {
633 myMapFaces.Bind(facecur,(Bsub.Copy(facecur)).First());
637 if (Bsub.IsCopied(myShape)) {
638 myShape=(Bsub.Copy(myShape)).First();
642 //if (tFE) cout<<endl<<"FuseEdges : "<< NbVertices() <<" vertices removed"<<endl;
649 myShapeDone = Standard_True;
654 //=======================================================================
655 //function : BuildListConnexEdge
656 //purpose : giving one edge, build the list of connex edges which have
657 // vertices that have only two connex edges. All the edges that are addes
658 // to the list must be added also to the mapUniq, in order for the caller
659 // to not treat again theses edges.
660 // This list is always oriented in the "Forward" direction.
661 //=======================================================================
663 void BRepLib_FuseEdges::BuildListConnexEdge(const TopoDS_Shape& theEdge,
664 TopTools_MapOfShape& theMapUniq,
665 TopTools_ListOfShape& theLstEdg)
671 VL = TopExp::LastVertex(TopoDS::Edge(theEdge),Standard_True);
672 TopoDS_Shape edgeconnex;
673 TopoDS_Shape edgecur = theEdge;
675 theLstEdg.Append(edgecur);
676 theMapUniq.Add(edgecur);
677 TopAbs_Orientation ori2;
679 // we first build the list of edges connex to edgecur by looking from the last Vertex VL
680 while (NextConnexEdge(VL,edgecur,edgeconnex)) {
681 if (theMapUniq.Contains(edgeconnex)) {
684 theLstEdg.Append(edgeconnex);
685 edgecur = edgeconnex;
686 // here take care about internal or external edges. It is non-sense to build
687 // the connex list with such edges.
688 ori2 = edgecur.Orientation();
689 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
692 VL = TopExp::LastVertex(TopoDS::Edge(edgecur),Standard_True);
693 theMapUniq.Add(edgecur);
697 VF = TopExp::FirstVertex(TopoDS::Edge(theEdge),Standard_True);
699 // then we build the list of edges connex to edgecur by looking from the first Vertex VF
700 while (NextConnexEdge(VF,edgecur,edgeconnex)) {
701 if (theMapUniq.Contains(edgeconnex)) {
704 theLstEdg.Prepend(edgeconnex);
705 edgecur = edgeconnex;
706 // here take care about internal or external edges. It is non-sense to build
707 // the connex list with such edges.
708 ori2 = edgecur.Orientation();
709 if (ori2 == TopAbs_EXTERNAL || ori2 == TopAbs_INTERNAL) {
712 VF = TopExp::FirstVertex(TopoDS::Edge(edgecur),Standard_True);
713 theMapUniq.Add(edgecur);
719 //=======================================================================
720 //function : NextConnexEdge
721 //purpose : Look for an edge connex to theEdge at theVertex.
722 // the connex edge must satisfies the following criteria :
723 // * theVertex must have exactly 2 connex edges.
724 // * the 2 connex edges must have exactly the 2 same connex faces
725 // * the 2 connex edges must lie on the same support.
726 //=======================================================================
728 Standard_Boolean BRepLib_FuseEdges::NextConnexEdge(const TopoDS_Vertex& theVertex,
729 const TopoDS_Shape& theEdge,
730 TopoDS_Shape& theEdgeConnex) const
733 const TopTools_ListOfShape& LmapEdg = myMapVerLstEdg.FindFromKey(theVertex);
734 Standard_Boolean HasConnex = Standard_True;
735 TopTools_ListIteratorOfListOfShape itEdg,itFac1,itFac2;
738 if (LmapEdg.Extent() == 2) {
739 itEdg.Initialize(LmapEdg);
740 theEdgeConnex = itEdg.Value();
741 if (theEdge.IsSame(theEdgeConnex) ) {
743 theEdgeConnex = itEdg.Value();
746 if (myAvoidEdg.Contains(theEdgeConnex))
747 HasConnex = Standard_False; // edge is not allowed to be fused
751 const TopTools_ListOfShape& LmapFac1 = myMapEdgLstFac.FindFromKey(theEdge);
752 const TopTools_ListOfShape& LmapFac2 = myMapEdgLstFac.FindFromKey(theEdgeConnex);
754 if (LmapFac1.Extent() == LmapFac2.Extent() && LmapFac1.Extent() < 3) {
755 itFac1.Initialize(LmapFac1);
757 // for each face in LmapFac1 we look in LmapFac2 if it exists
758 while (itFac1.More() && HasConnex) {
759 const TopoDS_Shape& face1 = itFac1.Value();
760 for (itFac2.Initialize(LmapFac2); itFac2.More(); itFac2.Next()) {
761 const TopoDS_Shape& face2 = itFac2.Value();
762 HasConnex = Standard_False;
763 if (face1.IsSame(face2)) {
764 HasConnex = Standard_True;
771 // 3rd condition : same suport
773 HasConnex = SameSupport(TopoDS::Edge(theEdge),TopoDS::Edge(theEdgeConnex));
777 HasConnex = Standard_False;
781 HasConnex = Standard_False;
788 //=======================================================================
789 //function : SameSupport
790 //purpose : Edges SameSupport ou pas
791 //=======================================================================
793 Standard_Boolean BRepLib_FuseEdges::SameSupport(const TopoDS_Edge& E1,
794 const TopoDS_Edge& E2) const
797 if (E1.IsNull() || E2.IsNull()) {
798 return Standard_False;
802 Handle(Geom_Curve) C1,C2;
804 Standard_Real f1,l1,f2,l2;
805 Handle(Standard_Type) typC1,typC2;
807 C1 = BRep_Tool::Curve(E1,loc,f1,l1);
808 //modified by NIZNHY-PKV Mon Nov 15 16:24:10 1999
809 //degenerated edges has no 3D curve
810 if(C1.IsNull()) return Standard_False;
812 if (!loc.IsIdentity()) {
813 Handle(Geom_Geometry) GG1 = C1->Transformed(loc.Transformation());
814 C1 = *((Handle(Geom_Curve)*)&GG1);
816 C2 = BRep_Tool::Curve(E2,loc,f2,l2);
817 //modified by NIZNHY-PKV Mon Nov 15 16:24:38 1999
818 //degenerated edges has no 3D curve
819 if(C2.IsNull()) return Standard_False;
821 if (!loc.IsIdentity()) {
822 Handle(Geom_Geometry) GG2 = C2->Transformed(loc.Transformation());
823 C2 = *((Handle(Geom_Curve)*)&GG2);
826 typC1 = C1->DynamicType();
827 typC2 = C2->DynamicType();
829 if (typC1 == STANDARD_TYPE(Geom_TrimmedCurve)) {
830 C1 = (*((Handle(Geom_TrimmedCurve)*)&C1))->BasisCurve();
831 typC1 = C1->DynamicType();
834 if (typC2 == STANDARD_TYPE(Geom_TrimmedCurve)) {
835 C2 = (*((Handle(Geom_TrimmedCurve)*)&C2))->BasisCurve();
836 typC2 = C2->DynamicType();
839 if (typC1 != typC2) {
840 return Standard_False;
843 if (typC1 != STANDARD_TYPE(Geom_Line) &&
844 typC1 != STANDARD_TYPE(Geom_Circle) &&
845 typC1 != STANDARD_TYPE(Geom_Ellipse) &&
846 typC1 != STANDARD_TYPE(Geom_BSplineCurve) &&
847 typC1 != STANDARD_TYPE(Geom_BezierCurve)) {
849 cout << " TopOpeBRepTool_FuseEdge : Type de Support non traite" << endl;
851 return Standard_False;
854 // On a presomption de confusion
855 const Standard_Real tollin = Precision::Confusion();
856 const Standard_Real tolang = Precision::Angular();
857 if (typC1 == STANDARD_TYPE(Geom_Line)) {
858 gp_Lin li1( (*((Handle(Geom_Line)*)&C1))->Lin());
859 gp_Lin li2( (*((Handle(Geom_Line)*)&C2))->Lin());
860 gp_Dir dir1(li1.Direction());
861 gp_Dir dir2(li2.Direction());
863 if ( dir1.IsParallel(dir2,tolang) ) {
864 // on verifie que l'on n'a pas de cas degenere. Par exemple E1 et E2 connexes
865 // mais bouclant l'un sur l'autre (cas tres rare)
866 gp_Pnt pf1 = BRep_Tool::Pnt(TopExp::FirstVertex(E1,Standard_True));
867 gp_Pnt pl1 = BRep_Tool::Pnt(TopExp::LastVertex(E1,Standard_True));
868 gp_Pnt pf2 = BRep_Tool::Pnt(TopExp::FirstVertex(E2,Standard_True));
869 gp_Pnt pl2 = BRep_Tool::Pnt(TopExp::LastVertex(E2,Standard_True));
870 if ( pl1.Distance(pf2) < tollin && pl2.Distance(pf1) < tollin)
871 return Standard_False;
873 return Standard_True;
875 return Standard_False;
877 else if (typC1 == STANDARD_TYPE(Geom_Circle)) {
878 gp_Circ ci1 = (*((Handle(Geom_Circle)*)&C1))->Circ();
879 gp_Circ ci2 = (*((Handle(Geom_Circle)*)&C2))->Circ();
880 if (Abs(ci1.Radius()-ci2.Radius()) <= tollin &&
881 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
882 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
883 // Point debut, calage dans periode, et detection meme sens
884 return Standard_True;
886 return Standard_False;
888 else if (typC1 == STANDARD_TYPE(Geom_Ellipse)) {
889 gp_Elips ci1 = (*((Handle(Geom_Ellipse)*)&C1))->Elips();
890 gp_Elips ci2 = (*((Handle(Geom_Ellipse)*)&C2))->Elips();
892 if (Abs(ci1.MajorRadius()-ci2.MajorRadius()) <= tollin &&
893 Abs(ci1.MinorRadius()-ci2.MinorRadius()) <= tollin &&
894 ci1.Location().SquareDistance(ci2.Location()) <= tollin*tollin &&
895 ci1.Axis().IsParallel(ci2.Axis(),tolang) ) {
896 // Point debut, calage dans periode, et detection meme sens
897 return Standard_True;
899 return Standard_False;
901 else if (typC1 == STANDARD_TYPE(Geom_BSplineCurve)) {
904 //Check G1 continuity
905 gp_Pnt aPf1, aPl1, aPf2, aPl2;
906 gp_Vec aDf1, aDl1, aDf2, aDl2;
908 C1->D1(f1, aPf1, aDf1);
909 C1->D1(l1, aPl1, aDl1);
911 C2->D1(f2, aPf2, aDf2);
912 C2->D1(l2, aPl2, aDl2);
914 if(aPl1.Distance(aPf2) <= tollin && aDl1.IsParallel(aDf2, tolang)) return Standard_True;
915 if(aPl2.Distance(aPf1) <= tollin && aDl2.IsParallel(aDf1, tolang)) return Standard_True;
916 if(aPf1.Distance(aPf2) <= tollin && aDf1.IsParallel(aDf2, tolang)) return Standard_True;
917 if(aPl1.Distance(aPl2) <= tollin && aDl1.IsParallel(aDl2, tolang)) return Standard_True;
920 // we must ensure that before fuse two bsplines, the end of one curve does not
921 // corresponds to the beginning of the second.
922 // we could add a special treatment for periodic bspline. This is not done for the moment.
923 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
924 return Standard_False;
927 Handle(Geom_BSplineCurve) B1 = *((Handle(Geom_BSplineCurve)*)&C1);
928 Handle(Geom_BSplineCurve) B2 = *((Handle(Geom_BSplineCurve)*)&C2);
930 Standard_Integer nbpoles = B1->NbPoles();
931 if (nbpoles != B2->NbPoles()) {
932 return Standard_False;
935 Standard_Integer nbknots = B1->NbKnots();
936 if (nbknots != B2->NbKnots()) {
937 return Standard_False;
940 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
944 Standard_Real tol3d = BRep_Tool::Tolerance(E1);
945 for (Standard_Integer p = 1; p <= nbpoles; p++) {
946 if ( (P1(p)).Distance(P2(p)) > tol3d) {
947 return Standard_False;
951 TColStd_Array1OfReal K1(1, nbknots), K2(1, nbknots);
955 TColStd_Array1OfInteger M1(1, nbknots), M2(1, nbknots);
956 B1->Multiplicities(M1);
957 B2->Multiplicities(M2);
959 for (Standard_Integer k = 1; k <= nbknots; k++) {
960 if ((K1(k)-K2(k)) > tollin) {
961 return Standard_False;
963 if (Abs(M1(k)-M2(k)) > tollin) {
964 return Standard_False;
968 if (!B1->IsRational()) {
969 if (B2->IsRational()) {
970 return Standard_False;
974 if (!B2->IsRational()) {
975 return Standard_False;
979 if (B1->IsRational()) {
980 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
984 for (Standard_Integer w = 1; w <= nbpoles; w++) {
985 if (Abs(W1(w)-W2(w)) > tollin) {
986 return Standard_False;
990 return Standard_True;
992 else if (typC1 == STANDARD_TYPE(Geom_BezierCurve)) {
994 // we must ensure that before fuse two bezier, the end of one curve does not
995 // corresponds to the beginning of the second.
996 if (Abs(f2-l1) > tollin && Abs(f1-l2) > tollin ) {
997 return Standard_False;
1000 Handle(Geom_BezierCurve) B1 = *((Handle(Geom_BezierCurve)*)&C1);
1001 Handle(Geom_BezierCurve) B2 = *((Handle(Geom_BezierCurve)*)&C2);
1003 Standard_Integer nbpoles = B1->NbPoles();
1004 if (nbpoles != B2->NbPoles()) {
1005 return Standard_False;
1008 TColgp_Array1OfPnt P1(1, nbpoles), P2(1, nbpoles);
1012 for (Standard_Integer p = 1; p <= nbpoles; p++) {
1013 if ( (P1(p)).Distance(P2(p)) > tollin) {
1014 return Standard_False;
1018 if (!B1->IsRational()) {
1019 if (B2->IsRational()) {
1020 return Standard_False;
1024 if (!B2->IsRational()) {
1025 return Standard_False;
1029 if (B1->IsRational()) {
1030 TColStd_Array1OfReal W1(1, nbpoles), W2(1, nbpoles);
1034 for (Standard_Integer w = 1; w <= nbpoles; w++) {
1035 if (Abs(W1(w)-W2(w)) > tollin) {
1036 return Standard_False;
1040 return Standard_True;
1042 return Standard_False;
1046 //=======================================================================
1047 //function : BuildAncestors
1048 //purpose : This function is like TopExp::MapShapesAndAncestors except
1049 // that in the list of shape we do not want duplicate shapes.
1050 // if this is useful for other purpose we should create a new method in
1052 //=======================================================================
1054 void BRepLib_FuseEdges::BuildAncestors
1055 (const TopoDS_Shape& S,
1056 const TopAbs_ShapeEnum TS,
1057 const TopAbs_ShapeEnum TA,
1058 TopTools_IndexedDataMapOfShapeListOfShape& M) const
1061 TopTools_MapOfShape mapDuplicate;
1062 TopTools_ListIteratorOfListOfShape it;
1063 Standard_Integer iSh;
1065 TopExp::MapShapesAndAncestors(S,TS,TA,M);
1067 // for each shape of M
1068 for (iSh = 1; iSh <= M.Extent(); iSh++) {
1069 TopTools_ListOfShape& Lsh = M(iSh);
1071 mapDuplicate.Clear();
1072 // we check for duplicate in the list of Shape
1074 while (it.More() ) {
1075 if (!mapDuplicate.Contains(it.Value())) {
1076 mapDuplicate.Add(it.Value());
1088 //=======================================================================
1089 //function : UpdatePCurve
1091 //=======================================================================
1093 Standard_Boolean BRepLib_FuseEdges::UpdatePCurve(const TopoDS_Edge& theOldEdge,
1094 TopoDS_Edge& theNewEdge,
1095 const TopTools_ListOfShape& theLstEdg) const
1099 // get the pcurve of edge to substitute (theOldEdge)
1100 // using CurveOnSurface with Index syntax, so we can update the pcurve
1103 Handle(Geom2d_Curve) Curv2d;
1104 Handle(Geom_Surface) Surf;
1105 TopLoc_Location loc,locbid;
1106 Standard_Real ef,el,cf,cl;
1107 Standard_Integer iedg = 1;
1109 // take care that we want only Pcurve that maps on the surface where the 3D edges lies.
1110 const TopTools_ListOfShape& LmapFac = myMapEdgLstFac.FindFromKey(theOldEdge);
1113 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
1115 Standard_Boolean pcurveRebuilt = Standard_False;
1117 while (!Curv2d.IsNull()) {
1119 // we look for a face that contains the same surface as the one that cames
1120 // from CurveOnSurface
1121 Standard_Boolean SameSurf = Standard_False;
1122 TopTools_ListIteratorOfListOfShape itFac;
1124 for (itFac.Initialize(LmapFac); itFac.More(); itFac.Next() ) {
1125 const TopoDS_Shape& face = itFac.Value();
1126 Handle (Geom_Surface) S = BRep_Tool::Surface(TopoDS::Face(face),locbid);
1128 SameSurf = Standard_True;
1135 BRep_Tool::Range(theNewEdge,ef,el);
1137 //modified by NIZNHY-PKV Mon Nov 15 14:59:48 1999 _from
1138 TopoDS_Edge aFEdge = theOldEdge;
1139 aFEdge.Orientation(TopAbs_FORWARD);
1141 // take care if the edge is on the closing curve of a closed surface. In that case
1142 // we get the second pcurve by reversing the edge and calling again CurveOnSurface method
1144 BRep_Tool::CurveOnSurface(aFEdge,Curv2d,Surf,loc,cf,cl,iedg);
1145 if (BRep_Tool::IsClosed(theOldEdge,Surf,loc)) {
1147 TopoDS_Face aFFace = TopoDS::Face(itFac.Value());
1148 aFFace.Orientation(TopAbs_FORWARD);
1149 Handle(Geom2d_Curve) Curv2dR = BRep_Tool::CurveOnSurface(aFEdge,
1151 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
1152 Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
1153 if (Curv2dR->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
1154 Curv2dR = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2dR))->BasisCurve();
1156 B.UpdateEdge (theNewEdge,Curv2d,Curv2dR,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
1159 // update the new edge
1160 if (Curv2d->DynamicType() == STANDARD_TYPE(Geom2d_TrimmedCurve))
1161 Curv2d = (*((Handle(Geom2d_TrimmedCurve)*)&Curv2d))->BasisCurve();
1163 f = Curv2d->FirstParameter();
1164 l = Curv2d->LastParameter();
1165 if (l-f + 2.* Epsilon(l-f) < el-ef)
1167 Handle(Geom2d_BoundedCurve) bcurve = Handle(Geom2d_BoundedCurve)::DownCast(Curv2d);
1168 if (bcurve.IsNull())
1169 bcurve = new Geom2d_TrimmedCurve( Curv2d, cf, cl );
1170 Geom2dConvert_CompCurveToBSplineCurve Concat( bcurve );
1171 TopTools_ListIteratorOfListOfShape iter( theLstEdg );
1173 for (; iter.More(); iter.Next())
1175 TopoDS_Edge& E = TopoDS::Edge(iter.Value());
1176 Standard_Real first, last;
1177 Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface( E, Surf, loc, first, last );
1178 Handle(Geom2d_BoundedCurve) BC = Handle(Geom2d_BoundedCurve)::DownCast(C);
1180 BC = new Geom2d_TrimmedCurve( C, first, last );
1181 if (!Concat.Add( BC, Precision::PConfusion() ))
1182 // cannot merge pcurves
1183 return Standard_False;
1185 Curv2d = Concat.BSplineCurve();
1187 // check that new curve 2d is same range
1188 Standard_Real first = Curv2d->FirstParameter();
1189 Standard_Real last = Curv2d->LastParameter();
1190 if (Abs (first - ef) > Precision::PConfusion() ||
1191 Abs (last - el) > Precision::PConfusion())
1193 Handle(Geom2d_BSplineCurve) bc = Handle(Geom2d_BSplineCurve)::DownCast(Curv2d);
1194 TColStd_Array1OfReal Knots (1, bc->NbKnots());
1196 BSplCLib::Reparametrize (ef, el, Knots);
1197 bc->SetKnots(Knots);
1199 pcurveRebuilt = Standard_True;
1202 B.UpdateEdge (theNewEdge,Curv2d,Surf,loc,BRep_Tool::Tolerance(theNewEdge));
1205 // the old pcurve range is cf,cl. The new 3d edge range is ef,el. if we want
1206 // the pcurve to be samerange we must adapt the parameter of the edge. In general
1207 // cases cf=ef and cl=el expect for periodic curve if the new edge is going over
1209 if(!pcurveRebuilt) {
1210 if (theOldEdge.Orientation()== TopAbs_REVERSED) {
1211 B.Range(theNewEdge,cl-el+ef,cl);
1214 B.Range(theNewEdge,cf,cf+el-ef);
1221 BRep_Tool::CurveOnSurface(theOldEdge,Curv2d,Surf,loc,cf,cl,iedg);
1226 // force same parameter
1227 B.SameParameter (theNewEdge, Standard_False);
1228 BRepLib::SameParameter (theNewEdge, BRep_Tool::Tolerance(theNewEdge));
1231 return Standard_True;