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