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