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