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