1 // Created on: 1999-08-24
2 // Created by: Sergei ZERTCHANINOV
3 // Copyright (c) 1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
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
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.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_Tool.hxx>
20 #include <Geom2d_BSplineCurve.hxx>
21 #include <Geom2d_Curve.hxx>
22 #include <Geom_BSplineCurve.hxx>
23 #include <Geom_Curve.hxx>
24 #include <GeomAPI.hxx>
25 #include <GeomConvert_CompCurveToBSplineCurve.hxx>
26 #include <gp_Pln.hxx>
27 #include <gp_Pnt.hxx>
28 #include <Message_Msg.hxx>
29 #include <ShapeAnalysis_Edge.hxx>
30 #include <ShapeAnalysis_TransferParametersProj.hxx>
31 #include <ShapeBuild_Edge.hxx>
32 #include <ShapeBuild_ReShape.hxx>
33 #include <ShapeConstruct.hxx>
34 #include <ShapeConstruct_Curve.hxx>
35 #include <ShapeFix.hxx>
36 #include <ShapeFix_Edge.hxx>
37 #include <ShapeFix_Wire.hxx>
38 #include <ShapeFix_Wireframe.hxx>
39 #include <Standard_ErrorHandler.hxx>
40 #include <Standard_Failure.hxx>
41 #include <Standard_Type.hxx>
42 #include <TopExp_Explorer.hxx>
43 #include <TopoDS.hxx>
44 #include <TopoDS_Compound.hxx>
45 #include <TopoDS_Edge.hxx>
46 #include <TopoDS_Face.hxx>
47 #include <TopoDS_Iterator.hxx>
48 #include <TopoDS_Shape.hxx>
49 #include <TopoDS_Vertex.hxx>
50 #include <TopTools_DataMapIteratorOfDataMapOfShapeShape.hxx>
51 #include <TopTools_DataMapOfShapeInteger.hxx>
52 #include <TopTools_DataMapOfShapeListOfShape.hxx>
53 #include <TopTools_DataMapOfShapeShape.hxx>
54 #include <TopTools_ListIteratorOfListOfShape.hxx>
55 #include <TopTools_ListOfShape.hxx>
56 #include <TopTools_MapOfShape.hxx>
57
IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Wireframe,ShapeFix_Root)58 IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_Wireframe,ShapeFix_Root)
59
60 //#include <Geom2dConvert_CompCurveToBSplineCurve.hxx>
61 //=======================================================================
62 //function : ShapeFix_Wireframe
63 //purpose :
64 //=======================================================================
65 ShapeFix_Wireframe::ShapeFix_Wireframe()
66 {
67 ClearStatuses();
68 myModeDrop = Standard_False;
69 myLimitAngle = -1;
70 }
71
72 //=======================================================================
73 //function : ShapeFix_Wireframe
74 //purpose :
75 //=======================================================================
76
ShapeFix_Wireframe(const TopoDS_Shape & shape)77 ShapeFix_Wireframe::ShapeFix_Wireframe(const TopoDS_Shape& shape)
78 {
79 ClearStatuses();
80 myShape = shape;
81 myModeDrop = Standard_False;
82 myLimitAngle = -1;
83 }
84
85 //=======================================================================
86 //function : ClearStatuses
87 //purpose :
88 //=======================================================================
89
ClearStatuses()90 void ShapeFix_Wireframe::ClearStatuses()
91 {
92 Standard_Integer emptyStatus = ShapeExtend::EncodeStatus( ShapeExtend_OK );
93
94 myStatusWireGaps = emptyStatus;
95 myStatusSmallEdges = emptyStatus;
96 }
97
98 //=======================================================================
99 //function : Load
100 //purpose :
101 //=======================================================================
102
Load(const TopoDS_Shape & shape)103 void ShapeFix_Wireframe::Load(const TopoDS_Shape& shape)
104 {
105 ClearStatuses();
106 myShape = shape;
107 }
108
109 //=======================================================================
110 //function : FixWireGaps
111 //purpose :
112 //=======================================================================
113
FixWireGaps()114 Standard_Boolean ShapeFix_Wireframe::FixWireGaps()
115 {
116 myStatusWireGaps = ShapeExtend::EncodeStatus( ShapeExtend_OK );
117 if (myShape.IsNull()) return Standard_False;
118
119 if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);
120 else
121 {
122 TopoDS_Shape shape = myShape;
123 myShape.Nullify();
124 myShape = Context()->Apply(shape);
125 }
126
127 Standard_Real prec = (Precision()>0.)? Precision() : Precision::Confusion();
128 TopTools_DataMapOfShapeShape cont;
129 if ( myShape.ShapeType() == TopAbs_COMPOUND )
130 {
131 Standard_Boolean locModified = Standard_False;
132 TopoDS_Compound C;
133 BRep_Builder B;
134 B.MakeCompound ( C );
135 TopoDS_Shape savShape = myShape;
136 for ( TopoDS_Iterator it(savShape); it.More(); it.Next() )
137 {
138 TopoDS_Shape shape1 = it.Value();
139 TopLoc_Location L = shape1.Location(),nullLoc;
140 shape1.Location ( nullLoc );
141 TopoDS_Shape res;
142 if ( cont.IsBound ( shape1 ) )
143 {
144 res = cont.Find ( shape1 ).Oriented ( shape1.Orientation() );
145 }
146 else
147 {
148 myShape = shape1;
149 FixWireGaps();
150 res = Shape();
151 cont.Bind(myShape,res);
152 }
153 if ( ! res.IsSame ( shape1 ) ) locModified = Standard_True;
154 res.Location ( L );
155 B.Add ( C, res );
156
157 }
158 if (locModified )
159 {
160 C.Orientation(savShape.Orientation());
161 Context()->Replace(savShape,C);
162 }
163 myShape = Context()->Apply(savShape);
164 return StatusWireGaps(ShapeExtend_DONE);
165 }
166 Handle(ShapeFix_Wire) sfw = new ShapeFix_Wire;
167 sfw->SetContext(Context());
168 sfw->SetPrecision(prec);
169
170 TopoDS_Face face;
171 for (TopExp_Explorer anExpf1(myShape,TopAbs_FACE); anExpf1.More(); anExpf1.Next())
172 {
173 //smh#8
174 TopoDS_Shape tmpF = Context()->Apply(anExpf1.Current());
175 face = TopoDS::Face(tmpF);
176 if (face.Orientation()==TopAbs_REVERSED) face.Orientation(TopAbs_FORWARD);
177 for (TopoDS_Iterator itw(face); itw.More(); itw.Next())
178 {
179 if(itw.Value().ShapeType() != TopAbs_WIRE)
180 continue;
181 //smh#8
182 TopoDS_Shape tmpW = Context()->Apply(itw.Value());
183 sfw->Init(TopoDS::Wire(tmpW), face, prec);
184 sfw->FixReorder();
185 sfw->FixGaps3d();
186 if (sfw->StatusGaps3d(ShapeExtend_DONE))
187 myStatusWireGaps |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
188 if (sfw->StatusGaps3d(ShapeExtend_FAIL))
189 myStatusWireGaps |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
190 sfw->FixGaps2d();
191 if (sfw->StatusGaps2d(ShapeExtend_DONE))
192 myStatusWireGaps |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
193 if (sfw->StatusGaps2d(ShapeExtend_FAIL))
194 myStatusWireGaps |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL2 );
195 if (sfw->StatusGaps3d(ShapeExtend_DONE) || sfw->StatusGaps2d(ShapeExtend_DONE))
196 SendWarning( itw.Value(), Message_Msg( "FixWireframe.FixFixWireGaps.MSG0" ));
197 }
198 }
199
200 //============================================================
201 //Author : enk
202 //Purpose: This block fixing a 3d wire which not lie on plane
203 // Part 1
204 //============================================================
205 for (TopExp_Explorer expw(myShape,TopAbs_WIRE,TopAbs_FACE); expw.More(); expw.Next())
206 {
207 TopoDS_Shape tmpW = Context()->Apply(expw.Current());
208 sfw->Load(TopoDS::Wire(tmpW));
209 sfw->SetPrecision(prec);
210 sfw->FixReorder();
211 sfw->FixGaps3d();
212 if (sfw->StatusGaps3d(ShapeExtend_DONE))
213 myStatusWireGaps |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
214 if (sfw->StatusGaps3d(ShapeExtend_FAIL))
215 myStatusWireGaps |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
216 if (sfw->StatusGaps3d(ShapeExtend_DONE))
217 SendWarning( expw.Current(), Message_Msg( "FixWireframe.FixFixWireGaps.MSG0" ));
218 }
219 //End Part1========================================================
220
221 if (StatusWireGaps(ShapeExtend_DONE))
222 {
223
224 myShape = Context()->Apply(myShape);
225
226 ShapeFix::SameParameter(myShape,Standard_False);
227
228 TopoDS_Wire wire;
229 Handle(ShapeFix_Edge) sfe = new ShapeFix_Edge;
230 for (TopExp_Explorer anExpf2(myShape,TopAbs_FACE); anExpf2.More(); anExpf2.Next())
231 {
232 face = TopoDS::Face(anExpf2.Current());
233 if (face.Orientation()==TopAbs_REVERSED) face.Orientation(TopAbs_FORWARD);
234 for (TopoDS_Iterator itw(face); itw.More(); itw.Next())
235 {
236 if(itw.Value().ShapeType() != TopAbs_WIRE)
237 continue;
238 wire = TopoDS::Wire(itw.Value());
239 sfw->Init(wire, face, prec);
240 sfw->FixReorder();
241 sfw->FixSelfIntersection();
242 for (TopoDS_Iterator ite(wire); ite.More(); ite.Next())
243 sfe->FixVertexTolerance(TopoDS::Edge(ite.Value()));
244 }
245 }
246
247 // enk Part 2
248 for (TopExp_Explorer expw2(myShape,TopAbs_WIRE,TopAbs_FACE); expw2.More(); expw2.Next())
249 {
250 wire = TopoDS::Wire(expw2.Current());
251 sfw->Load(wire);
252 sfw->SetPrecision(prec);
253 sfw->FixReorder();
254 sfw->FixSelfIntersection();
255 for (TopoDS_Iterator ite(wire); ite.More(); ite.Next())
256 sfe->FixVertexTolerance(TopoDS::Edge(ite.Value()));
257
258 }
259 // End Part 2
260
261 return Standard_True;
262 }
263
264 return Standard_False;
265 }
266
267 //=======================================================================
268 //function : JoinEdges (static)
269 //purpose : used in FixSmallEdges
270 //=======================================================================
271
JoinEdges(const TopoDS_Edge & E1,const TopoDS_Edge & E2,TopoDS_Edge & E3,const TopTools_ListOfShape & faces)272 static Standard_Boolean JoinEdges(const TopoDS_Edge& E1,
273 const TopoDS_Edge& E2,
274 TopoDS_Edge& E3,
275 const TopTools_ListOfShape& faces)
276 {
277 Standard_Boolean ReplaceFirst = Standard_True;
278 ShapeAnalysis_Edge sae;
279 Handle(Geom_Curve) c3d1,c3d2;
280 Handle(Geom2d_Curve) c2d1,c2d2; //TopTools
281 TopoDS_Edge newedge,newedge1;
282 E3 = newedge1;
283 TopoDS_Vertex V11 = sae.FirstVertex(E1);
284 TopoDS_Vertex V12 = sae.LastVertex(E1);
285 TopoDS_Vertex V21 = sae.FirstVertex(E2);
286 TopoDS_Vertex V22 = sae.LastVertex(E2);
287
288
289 Standard_Boolean isSame = (V11.IsSame(V12) || V22.IsSame(V21));
290 BRep_Builder B;
291 B.MakeEdge(newedge);
292 Standard_Real cf1,cf2,cl1,cl2,first1,first2,last1,last2;
293 newedge.Orientation(TopAbs_FORWARD);
294 try
295 {
296 OCC_CATCH_SIGNALS
297 if(!sae.Curve3d(E1,c3d1,cf1,cl1,Standard_False )) return ReplaceFirst;
298 if(!sae.Curve3d(E2,c3d2,cf2,cl2,Standard_False )) return ReplaceFirst;
299
300
301 B.Add(newedge,V11.Oriented(TopAbs_FORWARD));
302 B.Add(newedge,V22.Oriented(TopAbs_REVERSED));
303
304 Handle(Geom_Curve) CRes;
305 Standard_Boolean isRev1,isRev2;
306 // Standard_Real newf,newl;
307 if(!ShapeConstruct::JoinCurves(c3d1,c3d2,E1.Orientation(),E2.Orientation(),cf1, cl1,cf2, cl2,CRes,isRev1,isRev2))
308 return ReplaceFirst;
309 // if(isRev1 || isRev2)
310 if(!isSame && (isRev1 || isRev2))
311 return ReplaceFirst;
312 ReplaceFirst = (!isRev1);
313
314 Standard_Real newf = cf1;
315 Standard_Real newl = cl1 + cl2 - cf2;
316 TopAbs_Orientation OrEdge1 = E1.Orientation();
317 TopAbs_Orientation OrEdge2 = E2.Orientation();
318 Standard_Boolean ismanifold =(OrEdge1 == TopAbs_FORWARD || OrEdge1 == TopAbs_REVERSED);
319 Standard_Boolean ismanifold2 = (OrEdge2 == TopAbs_FORWARD || OrEdge2 == TopAbs_REVERSED);
320 if(ismanifold != ismanifold2)
321 return ReplaceFirst;
322
323 if(ismanifold) {
324
325 OrEdge1 = ( (!isRev1 && E1.Orientation() == TopAbs_FORWARD) ||
326 (isRev1 && E1.Orientation() == TopAbs_REVERSED) ? TopAbs_FORWARD :TopAbs_REVERSED);
327 OrEdge2 = ( (!isRev2 && E2.Orientation() == TopAbs_FORWARD) ||
328 (isRev2 && E2.Orientation() == TopAbs_REVERSED) ? TopAbs_FORWARD :TopAbs_REVERSED);
329 }
330 B.UpdateEdge(newedge,CRes,Max(BRep_Tool::Tolerance(E1),BRep_Tool::Tolerance(E2)));
331 Standard_Real fp= CRes->FirstParameter();
332 Standard_Real lp= CRes->LastParameter();
333 if(fp > newf) newf = fp;
334 if(lp < newl) newl = lp;
335 B.Range(newedge,newf,newl);
336
337 //merging pcurves
338 for(TopTools_ListIteratorOfListOfShape iter(faces); iter.More(); iter.Next())
339 {
340 TopoDS_Face face = TopoDS::Face(iter.Value());
341 if(!sae.PCurve ( E1, face, c2d1, first1, last1, Standard_False )) return ReplaceFirst;
342 if(!sae.PCurve ( E2, face, c2d2, first2, last2, Standard_False )) return ReplaceFirst;
343
344 Handle(Geom2d_Curve) C2dRes;
345 Standard_Boolean isRev12,isRev22;
346 if(!ShapeConstruct::JoinCurves(c2d1,c2d2,OrEdge1,OrEdge2,first1, last1,first2, last2,C2dRes,isRev12,isRev22,isSame))
347 return ReplaceFirst;
348
349 if(ismanifold && (!isSame && (isRev12 || isRev22)))
350 return ReplaceFirst;
351
352 if(isRev12)
353 ReplaceFirst = Standard_False;
354 Standard_Real fp2d = C2dRes->FirstParameter();
355 Standard_Real lp2d = C2dRes->LastParameter();
356 //B.UpdateEdge(newedge,C2dRes,face,0);
357 Standard_Real newf1 = first1;
358 Standard_Real newl1 = last1 + (last2 - first2);
359 if(fp2d > newf1) newf1 = fp2d;
360 if(lp2d < newl1) newl1 = lp2d;
361
362 // dealing with seams: the same again
363 if(sae.IsSeam(E1,face) && sae.IsSeam(E2,face))
364 {
365 Handle(Geom2d_Curve) c2d12,c2d22;
366 //smh#8
367 TopoDS_Shape tmpE1 = E1.Reversed(),
368 tmpE2 = E2.Reversed();
369 TopoDS_Edge E1t = TopoDS::Edge(tmpE1);
370 TopoDS_Edge E2t = TopoDS::Edge(tmpE2);
371 sae.PCurve ( E1t, face, c2d12, first1, last1, Standard_False );
372 sae.PCurve ( E2t, face, c2d22, first2, last2, Standard_False );
373
374 Handle(Geom2d_Curve) C2dRes2;
375 if(!ShapeConstruct::JoinCurves(c2d12,c2d22,OrEdge1,OrEdge2,first1, last1,first2, last2,C2dRes2,isRev12,isRev22,isSame))
376 return ReplaceFirst;
377 if(!isSame && (isRev1 || isRev2))
378 return ReplaceFirst;
379 B.UpdateEdge(newedge,C2dRes,C2dRes2,face,0);
380 }
381 else if(sae.IsSeam(E1,face) || sae.IsSeam(E2,face)) return ReplaceFirst;
382 else if(!sae.IsSeam(E1,face) && !sae.IsSeam(E2,face))
383 B.UpdateEdge(newedge,C2dRes,face,0);
384 B.Range(newedge,face,newf1,newl1);
385 if(!ismanifold)
386 newedge.Orientation(ReplaceFirst ? OrEdge1 :OrEdge2 );
387 }
388 B.SameRange(newedge,Standard_False);
389
390 E3 = newedge;
391 return ReplaceFirst;
392 }
393 catch ( Standard_Failure const& anException) {
394 #ifdef OCCT_DEBUG
395 std::cout<<"Error: ShapeFix_Wireframe::FixSmallEdges: JoinEdges: Exception in GeomConvert_CompCurveToBSplineCurve: ";
396 anException.Print(std::cout); std::cout<<std::endl;
397 #endif
398 (void)anException;
399 return ReplaceFirst;
400 }
401 }
402
403 //=======================================================================
404 //function : FixSmallEdges
405 //purpose :
406 //=======================================================================
407
FixSmallEdges()408 Standard_Boolean ShapeFix_Wireframe::FixSmallEdges()
409 {
410 myStatusSmallEdges = ShapeExtend::EncodeStatus( ShapeExtend_OK );
411 if (myShape.IsNull()) return Standard_False;
412
413 if (Context().IsNull()) SetContext(new ShapeBuild_ReShape);
414 else
415 {
416 TopoDS_Shape shape = myShape;
417 myShape.Nullify();
418 myShape = Context()->Apply(shape);
419 }
420 TopTools_DataMapOfShapeShape cont;
421 if ( myShape.ShapeType() == TopAbs_COMPOUND )
422 {
423 Standard_Boolean locModified = Standard_False;
424 TopoDS_Compound C;
425 BRep_Builder B;
426 B.MakeCompound ( C );
427 TopoDS_Shape savShape = myShape;
428 for ( TopoDS_Iterator it(savShape); it.More(); it.Next() )
429 {
430 TopoDS_Shape shape1 = it.Value();
431 TopLoc_Location L = shape1.Location(),nullLoc;
432 shape1.Location ( nullLoc );
433 TopoDS_Shape res;
434 if ( cont.IsBound ( shape1 ) )
435 {
436 res = cont.Find ( shape1 ).Oriented ( shape1.Orientation() );
437 }
438 else
439 {
440 myShape = shape1;
441 FixSmallEdges();
442 res = Shape();
443 cont.Bind(myShape,res);
444 }
445 if ( ! res.IsSame ( shape1 ) ) locModified = Standard_True;
446
447 //check if resulting shape if not empty
448 if( res.IsNull())
449 continue;
450
451 res.Location ( L );
452 B.Add ( C, res );
453
454 }
455 if (locModified )
456 {
457 C.Orientation(savShape.Orientation());
458 Context()->Replace(savShape,C);
459 }
460 myShape = Context()->Apply(savShape);
461 return StatusSmallEdges( ShapeExtend_DONE );
462 }
463 TopTools_MapOfShape theSmallEdges, theMultyEdges;
464 TopTools_DataMapOfShapeListOfShape theEdgeToFaces,theFaceWithSmall;
465 CheckSmallEdges ( theSmallEdges,theEdgeToFaces,theFaceWithSmall, theMultyEdges);
466 MergeSmallEdges ( theSmallEdges,theEdgeToFaces,theFaceWithSmall, theMultyEdges);
467 return StatusSmallEdges( ShapeExtend_DONE );
468 }
469
470 //=======================================================================
471 //function : CheckSmallEdges
472 //purpose :
473 //=======================================================================
474 #include <BRepBuilderAPI_MakeFace.hxx>
475 #include <TopExp.hxx>
476 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
CheckSmallEdges(TopTools_MapOfShape & theSmallEdges,TopTools_DataMapOfShapeListOfShape & theEdgeToFaces,TopTools_DataMapOfShapeListOfShape & theFaceWithSmall,TopTools_MapOfShape & theMultyEdges)477 Standard_Boolean ShapeFix_Wireframe::CheckSmallEdges(TopTools_MapOfShape& theSmallEdges,
478 TopTools_DataMapOfShapeListOfShape& theEdgeToFaces,
479 TopTools_DataMapOfShapeListOfShape& theFaceWithSmall,
480 TopTools_MapOfShape& theMultyEdges)
481 {
482 TopoDS_Face face;
483 TopoDS_Edge edge;
484 ShapeAnalysis_Wire SAW;
485
486 for (TopExp_Explorer anExpf1(myShape,TopAbs_FACE); anExpf1.More(); anExpf1.Next())
487 {
488 TopTools_ListOfShape theEdgeList;
489 TopoDS_Face facet = TopoDS::Face(anExpf1.Current());
490 face = facet;
491 if (facet.Orientation()==TopAbs_REVERSED) face = TopoDS::Face(facet.Oriented(TopAbs_FORWARD));
492 for (TopoDS_Iterator itw(face); itw.More(); itw.Next())
493 {
494 if(itw.Value().ShapeType() != TopAbs_WIRE)
495 continue;
496 TopoDS_Wire aW = TopoDS::Wire(itw.Value());
497 Handle(ShapeExtend_WireData) aswd = new ShapeExtend_WireData(aW,Standard_True,Standard_False);
498 SAW.Init(aswd,face,Precision());
499 // pnd protection on seam edges
500 TopTools_DataMapOfShapeInteger EdgeMap;
501 Standard_Integer i;
502 for (i=1; i<=SAW.NbEdges(); i++)
503 {
504 edge = SAW.WireData()->Edge(i);
505 if (EdgeMap.IsBound(edge))
506 EdgeMap.ChangeFind(edge)++;
507 else
508 EdgeMap.Bind(edge,1);
509 }
510
511 for ( i=1; i<=SAW.NbEdges(); i++)
512 {
513 edge = SAW.WireData()->Edge(i);
514 if(EdgeMap.Find(edge)!=1)
515 {
516 if(!SAW.WireData()->IsSeam(i))
517 theMultyEdges.Add(edge);
518 continue;
519 }
520 // Append current face to the list
521 if (theEdgeToFaces.IsBound(edge))
522 {
523 theEdgeToFaces(edge).Append(facet);
524 }
525 else
526 {
527 TopTools_ListOfShape theFaceList;
528 theFaceList.Append(facet);
529 theEdgeToFaces.Bind(edge,theFaceList);
530 }
531 // Check if current edge is small
532 if (theSmallEdges.Contains(edge)) theEdgeList.Append(edge);
533 else if (SAW.CheckSmall(i,Precision()))
534 {
535 theSmallEdges.Add(edge);
536 theEdgeList.Append(edge);
537 }
538 }
539 }
540 // Add current face to the map if has small edges
541 if (theEdgeList.Extent()) theFaceWithSmall.Bind(facet,theEdgeList);
542 }
543
544 //=========================================================================
545 // Author : enk
546 // Purpose: Analyzing of shape for small edges, if edge doesn't lie on face
547 //=========================================================================
548 for (TopExp_Explorer expw1(myShape,TopAbs_WIRE,TopAbs_FACE); expw1.More(); expw1.Next())
549 {
550 SAW.SetPrecision(Precision());
551 TopTools_DataMapOfShapeInteger EdgeMap;
552 Standard_Integer i;
553 TopoDS_Wire theWire=TopoDS::Wire(expw1.Current());
554 TopTools_ListOfShape theEdgeList;
555 SAW.Load(theWire);
556 if (!SAW.IsLoaded())
557 {
558 return Standard_False;
559 }
560 for (i=1; i<=SAW.NbEdges(); i++)
561 {
562 edge = SAW.WireData()->Edge(i);
563 if (EdgeMap.IsBound(edge))
564 EdgeMap.ChangeFind(edge)++;
565 else
566 EdgeMap.Bind(edge,1);
567 }
568
569 for ( i=1; i<=SAW.NbEdges(); i++)
570 {
571 edge = SAW.WireData()->Edge(i);
572 if(EdgeMap.Find(edge)!=1)
573 {
574 if(!SAW.WireData()->IsSeam(i))
575 theMultyEdges.Add(edge);
576 continue;
577 }
578
579 // Check if current edge is small
580 if (theSmallEdges.Contains(edge)) theEdgeList.Append(edge);
581 else if (SAW.CheckSmall(i,Precision()))
582 {
583 theSmallEdges.Add(edge);
584 theEdgeList.Append(edge);
585 }
586 }
587
588 }
589 return (!theSmallEdges.IsEmpty());
590
591 }
592
593 //=======================================================================
594 //function : MergeSmallEdges
595 //purpose :
596 //=======================================================================
597
MergeSmallEdges(TopTools_MapOfShape & theSmallEdges,TopTools_DataMapOfShapeListOfShape & theEdgeToFaces,TopTools_DataMapOfShapeListOfShape & theFaceWithSmall,TopTools_MapOfShape & theMultyEdges,const Standard_Boolean theModeDrop,const Standard_Real theLimitAngle)598 Standard_Boolean ShapeFix_Wireframe::MergeSmallEdges(TopTools_MapOfShape& theSmallEdges,
599 TopTools_DataMapOfShapeListOfShape& theEdgeToFaces,
600 TopTools_DataMapOfShapeListOfShape& theFaceWithSmall,
601 TopTools_MapOfShape& theMultyEdges,
602 const Standard_Boolean theModeDrop,
603 const Standard_Real theLimitAngle)
604 {
605 Standard_Boolean aModLimitAngle = (theLimitAngle >-1.0 || myLimitAngle > -1.0);
606 Standard_Real aLimitAngle = Max(theLimitAngle,myLimitAngle);
607
608 Standard_Boolean aModeDrop = theModeDrop || myModeDrop;
609 TopTools_DataMapOfShapeShape theNewVertices;
610 if (!theSmallEdges.IsEmpty())
611 {
612
613 Handle(ShapeFix_Wire) SFW = new ShapeFix_Wire;
614 SFW->SetContext(Context());
615 ShapeAnalysis_Edge SAE;
616 TopoDS_Edge edge1, edge2, edge3;
617 // Iterate on map of faces with small edges
618 TopExp_Explorer anExpf2(myShape,TopAbs_FACE);
619 for (; anExpf2.More(); anExpf2.Next())
620 {
621 if (theFaceWithSmall.IsBound(anExpf2.Current()))
622 {
623 if (theFaceWithSmall(anExpf2.Current()).Extent())
624 {
625 //smh#8
626 TopoDS_Shape tmpShape = Context()->Apply(anExpf2.Current());
627 TopoDS_Face facet = TopoDS::Face(tmpShape);
628 if(!facet.IsSame(anExpf2.Current()))
629 { //gka
630 TopExp_Explorer aExpEdge(anExpf2.Current(),TopAbs_EDGE);
631 for( ; aExpEdge.More(); aExpEdge.Next())
632 {
633 TopoDS_Shape newEdge;
634 Standard_Integer stat = Context()->Status(aExpEdge.Current(),newEdge,Standard_True);
635 if(stat > 0 )
636 {
637 if(theSmallEdges.Contains(aExpEdge.Current()))
638 {
639 theSmallEdges.Remove(aExpEdge.Current());
640 theSmallEdges.Add(newEdge);
641 }
642 if(theEdgeToFaces.IsBound(aExpEdge.Current()))
643 {
644 TopTools_ListOfShape aListFaces;
645 aListFaces = theEdgeToFaces.Find(aExpEdge.Current());
646 theEdgeToFaces.UnBind(aExpEdge.Current());
647 theEdgeToFaces.Bind(newEdge,aListFaces);
648
649 }
650 }
651 }
652 }
653 TopoDS_Face face = facet;
654 //if (face.Orientation()==TopAbs_REVERSED)
655 // face = TopoDS::Face(facet.Oriented(TopAbs_FORWARD));
656 for (TopoDS_Iterator itw(face); itw.More(); itw.Next())
657 {
658 if(itw.Value().ShapeType() != TopAbs_WIRE) continue;
659 TopoDS_Wire aWire = TopoDS::Wire(itw.Value());
660 if (face.Orientation()==TopAbs_REVERSED)
661 face = TopoDS::Face(facet.Oriented(TopAbs_FORWARD));
662 Handle(ShapeExtend_WireData) aswd = new ShapeExtend_WireData(aWire,Standard_True,Standard_False);
663 //SFW->Load(aWire);
664 SFW->Load(aswd);
665 SFW->FixReorder();
666 Standard_Integer prev, next, index = 1;
667
668 while (index <= SFW->WireData()->NbEdges() && SFW->NbEdges()>1)
669 {
670 prev = (index==1)? SFW->WireData()->NbEdges() : index-1;
671 next = (index==SFW->WireData()->NbEdges())? 1 : index+1;
672 edge1 = SFW->WireData()->Edge(prev);
673 edge2 = SFW->WireData()->Edge(index);
674 edge3 = SFW->WireData()->Edge(next);
675
676 //gka protection against joining seem edge
677 if(edge2.IsSame(edge1) || edge2.IsSame(edge3))
678 {
679 //if(BRep_Tool::IsClosed(edge2,face)) {
680 index++;
681 continue;
682 }
683
684 Standard_Boolean isSeam = SFW->WireData()->IsSeam(index);
685 Standard_Boolean isSeam1 = SFW->WireData()->IsSeam(prev);
686 Standard_Boolean isSeam2 = SFW->WireData()->IsSeam(next);
687 if (theSmallEdges.Contains(edge2))
688 {
689 // Middle edge is small - choose a pair of edges to join
690 Standard_Boolean IsAnyJoin = (edge1.IsSame(edge3));
691 Standard_Boolean take_next = IsAnyJoin; //Standard_False;
692 Standard_Boolean isLimAngle = Standard_False;
693 Handle(Geom_Curve) C1, C2, C3;
694 Standard_Real aux, last1, first2, last2, first3;
695 Standard_Real Ang1 = 0., Ang2 =0.;
696 if (SAE.Curve3d(edge1,C1,aux,last1) &&
697 SAE.Curve3d(edge2,C2,first2,last2) &&
698 SAE.Curve3d(edge3,C3,first3,aux))
699 {
700 // Compare angles between edges
701 //Standard_Real Ang1, Ang2;
702 gp_Vec Vec1, Vec2; gp_Pnt P;
703 C1->D1(last1,P,Vec1);
704 C2->D1(first2,P,Vec2);
705 if ( edge1.Orientation() == TopAbs_REVERSED ) Vec1.Reverse();
706 if ( edge2.Orientation() == TopAbs_REVERSED ) Vec2.Reverse();
707 Standard_Real tol2 = Precision::SquareConfusion();
708 if ( Vec1.SquareMagnitude() < tol2 ||
709 Vec2.SquareMagnitude() < tol2 ) Ang1 = M_PI/2.;
710 else Ang1 = Abs(Vec1.Angle(Vec2));
711 C2->D1(last2,P,Vec1);
712 C3->D1(first3,P,Vec2);
713 if ( edge2.Orientation() == TopAbs_REVERSED ) Vec1.Reverse();
714 if ( edge3.Orientation() == TopAbs_REVERSED ) Vec2.Reverse();
715 if ( Vec1.SquareMagnitude() < tol2 ||
716 Vec2.SquareMagnitude() < tol2 ) Ang2 = M_PI/2.;
717 else Ang2 = Abs(Vec1.Angle(Vec2));
718 //isLimAngle = (theLimitAngle != -1 && Min(Ang1,Ang2) > theLimitAngle);
719 //take_next = (Ang2<Ang1);
720 //if (take_next) { edge1 = edge2; edge2 = edge3; }
721 }
722 //if(theLimitAngle != -1 && Ang1 > theLimitAngle && Ang2 >theLimitAngle) {
723 // index++; continue;
724 //}
725
726 // Check if edges lay on the same faces
727 if(theMultyEdges.Contains(edge1) || theMultyEdges.Contains(edge2))
728 { //??????
729 index++;
730 continue;
731 }
732 TopTools_ListOfShape theList1,theList2,theList3;
733 if(theEdgeToFaces.IsBound(edge1))
734 theList1 = theEdgeToFaces(edge1);
735 if(theEdgeToFaces.IsBound(edge2))
736 theList2 = theEdgeToFaces(edge2);
737 if(theEdgeToFaces.IsBound(edge3))
738 theList3 = theEdgeToFaces(edge3);
739 Standard_Boolean same_set = Standard_False;
740
741 //gka protection against joining seem edges with other edges
742 Standard_Boolean same_set1 = (theList1.Extent()==theList2.Extent() &&
743 ((!isSeam && !isSeam1)|| (isSeam && isSeam1))); //gka
744 Standard_Boolean same_set2 = (theList3.Extent()==theList2.Extent() &&
745 ((!isSeam && !isSeam2)|| (isSeam && isSeam2)));
746 TopTools_MapOfShape theSetOfFaces;
747 for (TopTools_ListIteratorOfListOfShape itf1(theList2);
748 itf1.More(); itf1.Next())
749 theSetOfFaces.Add(itf1.Value());
750 if (same_set1)
751 {
752 // Add all faces of the first edge to the current set
753 for (TopTools_ListIteratorOfListOfShape itf2(theList1);
754 (itf2.More() && same_set1); itf2.Next())
755 same_set1 = theSetOfFaces.Contains(itf2.Value());
756 }
757 if (same_set2)
758 {
759 // Add all faces of the first edge to the current set
760 for (TopTools_ListIteratorOfListOfShape itf2(theList3);
761 (itf2.More() && same_set2); itf2.Next())
762 same_set2 = theSetOfFaces.Contains(itf2.Value());
763 }
764 if(same_set1 && same_set2)
765 {
766 same_set = Standard_True;
767 if(fabs(Ang2-Ang1) >Precision::Angular())
768 take_next = (Ang2<Ang1);
769 if (take_next)
770 {
771 edge1 = edge2; edge2 = edge3;
772 }
773 isLimAngle = (aModLimitAngle && Min(Ang1,Ang2) > aLimitAngle);
774 }
775 else if(same_set1 && !same_set2)
776 {
777 isLimAngle = (aModLimitAngle && Ang1 > aLimitAngle);
778 same_set = Standard_True;
779 }
780 else if(!same_set1 && same_set2)
781 {
782 same_set = Standard_True;
783 isLimAngle = (aModLimitAngle && Ang2 > aLimitAngle);
784 edge1 = edge2; edge2 = edge3;
785 take_next = Standard_True;
786 }
787 if (same_set && !isLimAngle )
788 {
789 // Merge current pair of edges
790 //gka protection against crossing seem on second face
791 Standard_Boolean isNeedJoin = Standard_True;//Standard_False;
792 for(TopTools_ListIteratorOfListOfShape aItF(theList2); aItF.More() && isNeedJoin; aItF.Next())
793 {
794 if(aItF.Value().IsSame(anExpf2.Current())) continue;
795 TopoDS_Shape aF = Context()->Apply(aItF.Value());
796 //aF = aF.Oriented(TopAbs_FORWARD);
797 for(TopoDS_Iterator aIw(aF); aIw.More(); aIw.Next())
798 {
799 if(aIw.Value().ShapeType() != TopAbs_WIRE) continue;
800 TopoDS_Wire wt = TopoDS::Wire(aIw.Value());
801 Handle(ShapeFix_Wire) SFW1 = new ShapeFix_Wire;
802 SFW1->Load(wt);
803 SFW1->FixReorder();
804 Handle(ShapeExtend_WireData) atmpswd = SFW1->WireData();
805 Standard_Integer ind1 = atmpswd->Index(edge1);
806 Standard_Integer ind2 = atmpswd->Index(edge2);
807 if(ind1 && ind2)
808 {
809 isNeedJoin = ((ind1 -ind2) ==1 || (ind2 == atmpswd->NbEdges() && ind1 ==1));
810 break;
811 }
812 }
813 }
814 Standard_Boolean ReplaceFirst = Standard_True;
815 if(isNeedJoin)
816 {
817
818 TopTools_ListOfShape aListF;
819 for(TopTools_ListIteratorOfListOfShape aItlF(theList2); aItlF.More(); aItlF.Next())
820 {
821 TopoDS_Shape tmpF = Context()->Apply(aItlF.Value());
822 aListF.Append(tmpF);
823 }
824 ReplaceFirst = JoinEdges(edge1,edge2,edge3,aListF);
825 }
826 else edge3 = TopoDS_Edge();
827 if (edge3.IsNull())
828 {
829 index++;
830 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
831 }
832 else
833 {
834 // Record vertex replacements in the map
835 TopoDS_Vertex oldV1 = SAE.FirstVertex(edge3),
836 oldV2 = SAE.LastVertex(edge3);
837 if (!theNewVertices.IsBound(oldV1))
838 //smh#8
839 {
840 TopoDS_Shape emptyCopiedV1 = oldV1.EmptyCopied();
841 theNewVertices.Bind(oldV1,TopoDS::Vertex(emptyCopiedV1));
842 }
843 if (!oldV1.IsSame(oldV2))
844 if (!theNewVertices.IsBound(oldV2))
845 //smh#8
846 {
847 TopoDS_Shape emptyCopiedV2 = oldV2.EmptyCopied();
848 theNewVertices.Bind(oldV2,TopoDS::Vertex(emptyCopiedV2));
849 }
850
851 //To keep NM vertices belonging initial edges
852 TopoDS_Iterator aItv(edge1,Standard_False);
853 for( ; aItv.More(); aItv.Next()) {
854 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
855 aItv.Value().Orientation() == TopAbs_EXTERNAL) {
856 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
857 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,edge3,edge1);
858 BRep_Builder aB;
859 aB.Add(edge3,anewV);
860 Context()->Replace(aOldV,anewV);
861 }
862 }
863
864 for(aItv.Initialize(edge2,Standard_False) ; aItv.More(); aItv.Next()) {
865 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
866 aItv.Value().Orientation() == TopAbs_EXTERNAL){
867 BRep_Builder aB;
868 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
869 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,edge3,edge2);
870 aB.Add(edge3,anewV);
871 Context()->Replace(aOldV,anewV);
872 }
873 }
874
875 // Check for small resulting edge
876 Standard_Boolean newsmall = Standard_False;
877 ShapeAnalysis_Wire SAW;
878 SAW.Init(SFW->WireData(),face,Precision());
879 // Make changes in WireData and Context
880 if(ReplaceFirst)
881 {
882 Context()->Replace(edge1,edge3);
883 Context()->Remove(edge2);
884 SendWarning( edge2, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
885 }
886 else
887 {
888 Context()->Replace(edge2,edge3);
889 Context()->Remove(edge1);
890 SendWarning( edge1, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
891 }
892 if (take_next)
893 {
894 SFW->WireData()->Set(edge3,next);
895 newsmall = SAW.CheckSmall(next,Precision());
896 }
897 else
898 {
899 SFW->WireData()->Set(edge3,prev);
900 newsmall = SAW.CheckSmall(prev,Precision());
901 }
902 SFW->WireData()->Remove(index);
903 // Process changes in maps
904 TopTools_ListOfShape theList;
905 theList.Append(theList2);
906 theEdgeToFaces.UnBind(edge1);
907 theEdgeToFaces.UnBind(edge2);
908 theEdgeToFaces.Bind(edge3,theList);
909 if (theSmallEdges.Contains(edge1)) theSmallEdges.Remove(edge1);
910 if (theSmallEdges.Contains(edge2)) theSmallEdges.Remove(edge2);
911 if (newsmall) theSmallEdges.Add(edge3);
912 for (TopTools_ListIteratorOfListOfShape itlf(theList);
913 itlf.More(); itlf.Next())
914 {
915 TopoDS_Shape curface = itlf.Value();
916 if (theFaceWithSmall.IsBound(curface))
917 {
918 TopTools_ListOfShape& theEdges = theFaceWithSmall(curface);
919 if (newsmall) theEdges.Append(edge3);
920 TopTools_ListIteratorOfListOfShape ite(theEdges);
921 while (ite.More())
922 {
923 TopoDS_Shape iedge = ite.Value();
924 if (iedge.IsSame(edge1) || iedge.IsSame(edge2))
925 theEdges.Remove(ite);
926 else ite.Next();
927 }
928 // Remove face without small edges from the map
929 if (!theEdges.Extent()) theFaceWithSmall.UnBind(curface);
930 }
931 }
932 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
933 }
934 }
935 else if(aModeDrop)
936 { //gka
937 Handle(ShapeExtend_WireData) tempWire = new ShapeExtend_WireData();
938 ShapeAnalysis_Wire tempSaw;
939 tempWire->Add(SFW->Wire());
940 TopoDS_Edge remedge;
941 if (take_next)
942 remedge = edge1;
943 else remedge = edge2;
944 tempWire->Remove (index );
945 tempSaw.Load(tempWire);
946 Standard_Integer newindex = (index <= tempSaw.NbEdges() ? index : 1);
947 tempSaw.CheckConnected(newindex,Precision());
948 if(!tempSaw.LastCheckStatus(ShapeExtend_FAIL))
949 {
950 SFW->WireData()->Remove (index );
951 TopoDS_Edge tmpedge1 = tempWire->Edge(newindex);
952 TopoDS_Edge tmpedge2 = tempWire->Edge(newindex == 1 ? tempSaw.NbEdges() : (newindex- 1));
953 TopTools_ListOfShape aL1;
954 if(theEdgeToFaces.IsBound(tmpedge1))
955 aL1 = theEdgeToFaces.Find(tmpedge1);
956 TopTools_ListOfShape aL2;
957 if(theEdgeToFaces.IsBound(tmpedge2))
958 aL2= theEdgeToFaces.Find(tmpedge2);
959 SFW->FixConnected(newindex <= SFW->NbEdges() ? newindex : 1,Precision());
960 SFW->FixDegenerated(newindex <= SFW->NbEdges() ? newindex : 1);
961 TopoDS_Shape aTmpShape = Context()->Apply(tmpedge1); //for porting
962 TopoDS_Edge anewedge1 = TopoDS::Edge(aTmpShape);
963 aTmpShape = Context()->Apply(tmpedge2);
964 TopoDS_Edge anewedge2 = TopoDS::Edge(aTmpShape);
965 Context()->Remove(remedge);
966 SendWarning( remedge, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
967 if (theSmallEdges.Contains(remedge))
968 theSmallEdges.Remove(remedge);
969 theEdgeToFaces.UnBind(remedge);
970 theEdgeToFaces.UnBind(tmpedge1);
971 theEdgeToFaces.UnBind(tmpedge2);
972 theEdgeToFaces.Bind(anewedge1,aL1);
973 theEdgeToFaces.Bind(anewedge2,aL2);
974 if (theSmallEdges.Contains(tmpedge1))
975 {
976 theSmallEdges.Remove(tmpedge1);
977 theSmallEdges.Add(anewedge1);
978 for (TopTools_ListIteratorOfListOfShape itlf(aL1);
979 itlf.More(); itlf.Next())
980 {
981 TopoDS_Shape curface = itlf.Value();
982 TopTools_ListOfShape& theEdges = theFaceWithSmall(curface);
983 TopTools_ListIteratorOfListOfShape ite(theEdges);
984 while (ite.More())
985 {
986 TopoDS_Shape iedge = ite.Value();
987 if (iedge.IsSame(tmpedge1))
988 {
989 theEdges.Remove(ite);
990 theEdges.Append(anewedge1);
991 }
992 else ite.Next();
993 }
994 }
995 }
996 if (theSmallEdges.Contains(tmpedge2))
997 {
998 theSmallEdges.Remove(tmpedge2);
999 theSmallEdges.Add(anewedge2);
1000 for (TopTools_ListIteratorOfListOfShape itlf(aL2);
1001 itlf.More(); itlf.Next())
1002 {
1003 TopoDS_Shape curface = itlf.Value();
1004 TopTools_ListOfShape& theEdges = theFaceWithSmall(curface);
1005 TopTools_ListIteratorOfListOfShape ite(theEdges);
1006 while (ite.More())
1007 {
1008 TopoDS_Shape iedge = ite.Value();
1009 if (iedge.IsSame(tmpedge2))
1010 {
1011 theEdges.Remove(ite);
1012 theEdges.Append(anewedge2);
1013 }
1014 else ite.Next();
1015 }
1016 }
1017 }
1018 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE3 );
1019 }
1020 else index++;
1021 }
1022 else
1023 {
1024 //gka protection against removing circles
1025 TopoDS_Edge ed = (take_next ? edge1 : edge2);
1026 ShapeAnalysis_Edge sae;
1027 Handle(Geom_Curve) c3d;
1028 Standard_Real f1,l1;
1029 if(sae.Curve3d(ed,c3d,f1,l1,Standard_False))
1030 {
1031 gp_Pnt p1,p2,p3;
1032 c3d->D0(f1,p1);
1033 c3d->D0(l1,p2);
1034 c3d->D0((f1 +l1)*0.5,p3);
1035
1036 if(p1.Distance(p3) > p1.Distance(p2))
1037 {
1038 index++;
1039 continue;
1040 }
1041 }
1042 if (take_next && theList2.Extent()== 1)
1043 { //gka
1044 TopoDS_Vertex V1 = SAE.FirstVertex(edge1),
1045 V2 = SAE.LastVertex(edge1);
1046 if(V1.IsSame(V2))
1047 {
1048 SFW->WireData()->Remove (index );
1049 Context()->Remove(edge1);
1050 SendWarning( edge1, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1051 if (theSmallEdges.Contains(edge1)) theSmallEdges.Remove(edge1);
1052 theEdgeToFaces.UnBind(edge1);
1053 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
1054 }
1055 else index++;
1056 }
1057 else if( !take_next && theList2.Extent()== 1)
1058 {
1059 TopoDS_Vertex V1 = SAE.FirstVertex(edge2),
1060 V2 = SAE.LastVertex(edge2);
1061 if(V1.IsSame(V2))
1062 {
1063 SFW->WireData()->Remove (index );
1064 Context()->Remove(edge2);
1065 SendWarning( edge2, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1066 if (theSmallEdges.Contains(edge2)) theSmallEdges.Remove(edge2);
1067 theEdgeToFaces.UnBind(edge2);
1068 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
1069 }
1070 else index++;
1071 }
1072 else index++;
1073 }
1074 }
1075 else index++;
1076 }
1077 if (SFW->NbEdges() == 1 && aModeDrop)
1078 {
1079 edge1 = SFW->WireData()->Edge(1);
1080 if (theSmallEdges.Contains(edge1))
1081 {
1082 SFW->WireData()->Remove(1);
1083 Context()->Remove(edge1);
1084 SendWarning( edge1, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1085 theSmallEdges.Remove(edge1);
1086 theEdgeToFaces.UnBind(edge1);
1087 Context()->Remove(aWire);
1088 SendWarning( aWire, Message_Msg("FixWireframe.FixSmallEdges.MSG1"));
1089 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
1090 }
1091 }
1092 else
1093 {
1094 SFW->FixConnected();
1095 Context()->Replace(aWire,SFW->Wire());
1096 }
1097 }
1098 face.Orientation(facet.Orientation());
1099 TopoDS_Shape anewShape = Context()->Apply(face);
1100 TopoDS_Iterator aIter(anewShape);
1101 if(!aIter.More()) {
1102 Context()->Remove(anewShape);
1103 SendWarning( face, Message_Msg("FixWireframe.FixSmallEdges.MSG2"));
1104 }
1105 }
1106 }
1107 }
1108
1109 // enk block
1110 // Iterate on map of wires which not lie on faces
1111 for (TopExp_Explorer expw1( myShape, TopAbs_WIRE, TopAbs_FACE); expw1.More(); expw1.Next())
1112 {
1113 TopoDS_Wire aWire = TopoDS::Wire(expw1.Current());
1114 SFW->Load(aWire);
1115 SFW->FixReorder();
1116 Standard_Integer prev, next, index = 1;
1117 while (index <= SFW->NbEdges() && SFW->NbEdges()>1)
1118 {
1119 prev = (index==1)? SFW->NbEdges() : index-1;
1120 next = (index==SFW->NbEdges())? 1 : index+1;
1121 edge1 = SFW->WireData()->Edge(prev);
1122 edge2 = SFW->WireData()->Edge(index);
1123 edge3 = SFW->WireData()->Edge(next);
1124
1125 //gka protection against joining seem edge
1126 if(edge2.IsSame(edge1) || edge2.IsSame(edge3))
1127 {
1128 //if(BRep_Tool::IsClosed(edge2,face)) {
1129 index++;
1130 continue;
1131 }
1132
1133 Standard_Boolean isSeam = SFW->WireData()->IsSeam(index);
1134 Standard_Boolean isSeam1 = SFW->WireData()->IsSeam(prev);
1135 Standard_Boolean isSeam2 = SFW->WireData()->IsSeam(next);
1136 if (theSmallEdges.Contains(edge2))
1137 {
1138 // Middle edge is small - choose a pair of edges to join
1139 Standard_Boolean IsAnyJoin = (edge1.IsSame(edge3));
1140 Standard_Boolean take_next = IsAnyJoin; //Standard_False;
1141 Standard_Boolean isLimAngle = Standard_False;
1142 Handle(Geom_Curve) C1, C2, C3;
1143 Standard_Real aux, last1, first2, last2, first3;
1144 Standard_Real Ang1 = 0., Ang2 =0.;
1145 if (SAE.Curve3d(edge1,C1,aux,last1) &&
1146 SAE.Curve3d(edge2,C2,first2,last2) &&
1147 SAE.Curve3d(edge3,C3,first3,aux))
1148 {
1149 // Compare angles between edges
1150 //Standard_Real Ang1, Ang2;
1151 gp_Vec Vec1, Vec2; gp_Pnt P;
1152 C1->D1(last1,P,Vec1);
1153 C2->D1(first2,P,Vec2);
1154 if ( edge1.Orientation() == TopAbs_REVERSED ) Vec1.Reverse();
1155 if ( edge2.Orientation() == TopAbs_REVERSED ) Vec2.Reverse();
1156 Standard_Real tol2 = Precision::SquareConfusion();
1157 if ( Vec1.SquareMagnitude() < tol2 ||
1158 Vec2.SquareMagnitude() < tol2 ) Ang1 = M_PI/2.;
1159 else Ang1 = Abs(Vec1.Angle(Vec2));
1160 C2->D1(last2,P,Vec1);
1161 C3->D1(first3,P,Vec2);
1162 if ( edge2.Orientation() == TopAbs_REVERSED ) Vec1.Reverse();
1163 if ( edge3.Orientation() == TopAbs_REVERSED ) Vec2.Reverse();
1164 if ( Vec1.SquareMagnitude() < tol2 ||
1165 Vec2.SquareMagnitude() < tol2 ) Ang2 = M_PI/2.;
1166 else Ang2 = Abs(Vec1.Angle(Vec2));
1167 //isLimAngle = (theLimitAngle != -1 && Min(Ang1,Ang2) > theLimitAngle);
1168 //take_next = (Ang2<Ang1);
1169 //if (take_next) { edge1 = edge2; edge2 = edge3; }
1170 }
1171 //if(theLimitAngle != -1 && Ang1 > theLimitAngle && Ang2 >theLimitAngle) {
1172 // index++; continue;
1173 //}
1174
1175 // Check if edges lay on the same faces
1176 if(theMultyEdges.Contains(edge1) || theMultyEdges.Contains(edge2))
1177 { //??????
1178 index++;
1179 continue;
1180 }
1181 TopTools_ListOfShape theList1,theList2,theList3;
1182 if(theEdgeToFaces.IsBound(edge1))
1183 theList1 = theEdgeToFaces(edge1);
1184 if(theEdgeToFaces.IsBound(edge2))
1185 theList2 = theEdgeToFaces(edge2);
1186 if(theEdgeToFaces.IsBound(edge3))
1187 theList3 = theEdgeToFaces(edge3);
1188 Standard_Boolean same_set = Standard_False;
1189
1190 //gka protection against joining seem edges with other edges
1191 Standard_Boolean same_set1 = (theList1.Extent()==theList2.Extent() &&
1192 ((!isSeam && !isSeam1)|| (isSeam && isSeam1))); //gka
1193 Standard_Boolean same_set2 = (theList3.Extent()==theList2.Extent() &&
1194 ((!isSeam && !isSeam2)|| (isSeam && isSeam2)));
1195 TopTools_MapOfShape theSetOfFaces;
1196 for (TopTools_ListIteratorOfListOfShape itf1(theList2);
1197 itf1.More(); itf1.Next())
1198 theSetOfFaces.Add(itf1.Value());
1199 if (same_set1)
1200 {
1201 // Add all faces of the first edge to the current set
1202 for (TopTools_ListIteratorOfListOfShape itf2(theList1);
1203 (itf2.More() && same_set1); itf2.Next())
1204 same_set1 = theSetOfFaces.Contains(itf2.Value());
1205 }
1206 if (same_set2)
1207 {
1208 // Add all faces of the first edge to the current set
1209 for (TopTools_ListIteratorOfListOfShape itf2(theList3);
1210 (itf2.More() && same_set2); itf2.Next())
1211 same_set2 = theSetOfFaces.Contains(itf2.Value());
1212 }
1213 if(same_set1 && same_set2)
1214 {
1215 same_set = Standard_True;
1216 if(fabs(Ang2-Ang1) >Precision::Angular())
1217 take_next = (Ang2<Ang1);
1218 if (take_next)
1219 {
1220 edge1 = edge2; edge2 = edge3;
1221 }
1222 isLimAngle = (aModLimitAngle && Min(Ang1,Ang2) > aLimitAngle);
1223 }
1224 else if(same_set1 && !same_set2)
1225 {
1226 isLimAngle = (aModLimitAngle && Ang1 > aLimitAngle);
1227 same_set = Standard_True;
1228 }
1229 else if(!same_set1 && same_set2)
1230 {
1231 same_set = Standard_True;
1232 isLimAngle = (aModLimitAngle && Ang2 > aLimitAngle);
1233 edge1 = edge2; edge2 = edge3;
1234 take_next = Standard_True;
1235 }
1236 if (same_set && !isLimAngle )
1237 {
1238 // Merge current pair of edges
1239 //gka protection against crossing seem on second face
1240 Standard_Boolean isNeedJoin = Standard_True;//Standard_False;
1241 for(TopTools_ListIteratorOfListOfShape aItF(theList2); aItF.More() && isNeedJoin; aItF.Next())
1242 {
1243 if(aItF.Value().IsSame(anExpf2.Current())) continue;
1244 TopoDS_Shape aF = Context()->Apply(aItF.Value());
1245 //aF = aF.Oriented(TopAbs_FORWARD);
1246 for(TopoDS_Iterator aIw(aF); aIw.More(); aIw.Next())
1247 {
1248 if(aIw.Value().ShapeType() != TopAbs_WIRE) continue;
1249 TopoDS_Wire wt = TopoDS::Wire(aIw.Value());
1250 Handle(ShapeFix_Wire) SFW1 = new ShapeFix_Wire;
1251 SFW1->Load(wt);
1252 SFW1->FixReorder();
1253 Handle(ShapeExtend_WireData) atmpswd = SFW1->WireData();
1254 Standard_Integer ind1 = atmpswd->Index(edge1);
1255 Standard_Integer ind2 = atmpswd->Index(edge2);
1256 if(ind1 && ind2)
1257 {
1258 isNeedJoin = ((ind1 -ind2) ==1 || (ind2 == atmpswd->NbEdges() && ind1 ==1));
1259 break;
1260 }
1261 }
1262 }
1263 Standard_Boolean ReplaceFirst = Standard_True;
1264 if(isNeedJoin)
1265 {
1266
1267 TopTools_ListOfShape aListF;
1268 for(TopTools_ListIteratorOfListOfShape aItlF(theList2); aItlF.More(); aItlF.Next())
1269 {
1270 TopoDS_Shape tmpF = Context()->Apply(aItlF.Value());
1271 aListF.Append(tmpF);
1272 }
1273 ReplaceFirst = JoinEdges(edge1,edge2,edge3,aListF);
1274 }
1275 else edge3 = TopoDS_Edge();
1276 if (edge3.IsNull())
1277 {
1278 index++;
1279 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_FAIL1 );
1280 }
1281 else
1282 {
1283 // Record vertex replacements in the map
1284 TopoDS_Vertex oldV1 = SAE.FirstVertex(edge3),
1285 oldV2 = SAE.LastVertex(edge3);
1286 if (!theNewVertices.IsBound(oldV1))
1287 //smh#8
1288 {
1289 TopoDS_Shape emptyCopiedV1 = oldV1.EmptyCopied();
1290 theNewVertices.Bind(oldV1,TopoDS::Vertex(emptyCopiedV1));
1291 }
1292 if (!oldV1.IsSame(oldV2))
1293 if (!theNewVertices.IsBound(oldV2))
1294 //smh#8
1295 {
1296 TopoDS_Shape emptyCopiedV2 = oldV2.EmptyCopied();
1297 theNewVertices.Bind(oldV2,TopoDS::Vertex(emptyCopiedV2));
1298 }
1299 //To keep NM vertices belonging initial edges
1300 TopoDS_Iterator aItv(edge1,Standard_False);
1301 for( ; aItv.More(); aItv.Next()) {
1302 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
1303 aItv.Value().Orientation() == TopAbs_EXTERNAL) {
1304 BRep_Builder aB;
1305 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
1306 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,edge3,edge1);
1307 aB.Add(edge3,anewV);
1308 Context()->Replace(aOldV,anewV);
1309 }
1310 }
1311
1312 for(aItv.Initialize(edge2,Standard_False) ; aItv.More(); aItv.Next()) {
1313 if(aItv.Value().Orientation() == TopAbs_INTERNAL ||
1314 aItv.Value().Orientation() == TopAbs_EXTERNAL){
1315 BRep_Builder aB;
1316 TopoDS_Vertex aOldV = TopoDS::Vertex(aItv.Value());
1317 TopoDS_Vertex anewV = ShapeAnalysis_TransferParametersProj::CopyNMVertex(aOldV,edge3,edge2);
1318 aB.Add(edge3,anewV);
1319 Context()->Replace(aOldV,anewV);
1320 }
1321 }
1322 // Check for small resulting edge
1323 Standard_Boolean newsmall = Standard_False;
1324 ShapeAnalysis_Wire SAW;
1325 SAW.Load(SFW->WireData());
1326 SAW.SetPrecision(Precision());
1327 // Make changes in WireData and Context
1328 if(ReplaceFirst)
1329 {
1330 Context()->Replace(edge1,edge3);
1331 Context()->Remove(edge2);
1332 SendWarning( edge2, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1333 }
1334 else
1335 {
1336 Context()->Replace(edge2,edge3);
1337 Context()->Remove(edge1);
1338 SendWarning( edge1, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1339 }
1340 if (take_next)
1341 {
1342 SFW->WireData()->Set(edge3,next);
1343 newsmall = SAW.CheckSmall(next,Precision());
1344 }
1345 else
1346 {
1347 SFW->WireData()->Set(edge3,prev);
1348 newsmall = SAW.CheckSmall(prev,Precision());
1349 }
1350 SFW->WireData()->Remove(index);
1351 // Process changes in maps
1352 TopTools_ListOfShape theList;
1353 theList.Append(theList2);
1354 theEdgeToFaces.UnBind(edge1);
1355 theEdgeToFaces.UnBind(edge2);
1356 theEdgeToFaces.Bind(edge3,theList);
1357 if (theSmallEdges.Contains(edge1)) theSmallEdges.Remove(edge1);
1358 if (theSmallEdges.Contains(edge2)) theSmallEdges.Remove(edge2);
1359 if (newsmall) theSmallEdges.Add(edge3);
1360 for (TopTools_ListIteratorOfListOfShape itlf(theList);
1361 itlf.More(); itlf.Next())
1362 {
1363 TopoDS_Shape curface = itlf.Value();
1364 if (theFaceWithSmall.IsBound(curface))
1365 {
1366 TopTools_ListOfShape& theEdges = theFaceWithSmall(curface);
1367 if (newsmall) theEdges.Append(edge3);
1368 TopTools_ListIteratorOfListOfShape ite(theEdges);
1369 while (ite.More())
1370 {
1371 TopoDS_Shape iedge = ite.Value();
1372 if (iedge.IsSame(edge1) || iedge.IsSame(edge2))
1373 theEdges.Remove(ite);
1374 else ite.Next();
1375 }
1376 // Remove face without small edges from the map
1377 if (!theEdges.Extent()) theFaceWithSmall.UnBind(curface);
1378 }
1379 }
1380 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE1 );
1381 }
1382 }
1383 else if(aModeDrop)
1384 { //gka
1385 Handle(ShapeExtend_WireData) tempWire = new ShapeExtend_WireData();
1386 ShapeAnalysis_Wire tempSaw;
1387 tempWire->Add(SFW->Wire());
1388 TopoDS_Edge remedge;
1389 if (take_next)
1390 remedge = edge1;
1391 else remedge = edge2;
1392 tempWire->Remove (index );
1393 tempSaw.Load(tempWire);
1394 Standard_Integer newindex = (index <= tempSaw.NbEdges() ? index : 1);
1395 tempSaw.CheckConnected(newindex,Precision());
1396 if(!tempSaw.LastCheckStatus(ShapeExtend_FAIL))
1397 {
1398 SFW->WireData()->Remove (index );
1399 TopoDS_Edge tmpedge1 = tempWire->Edge(newindex);
1400 TopoDS_Edge tmpedge2 = tempWire->Edge(newindex == 1 ? tempSaw.NbEdges() : (newindex- 1));
1401 TopTools_ListOfShape aL1;
1402 if(theEdgeToFaces.IsBound(tmpedge1))
1403 aL1 = theEdgeToFaces.Find(tmpedge1);
1404 TopTools_ListOfShape aL2;
1405 if(theEdgeToFaces.IsBound(tmpedge2))
1406 aL2= theEdgeToFaces.Find(tmpedge2);
1407 SFW->FixConnected(newindex <= SFW->NbEdges() ? newindex : 1,Precision());
1408 SFW->FixDegenerated(newindex <= SFW->NbEdges() ? newindex : 1);
1409 TopoDS_Shape aTmpShape = Context()->Apply(tmpedge1); //for porting
1410 TopoDS_Edge anewedge1 = TopoDS::Edge(aTmpShape);
1411 aTmpShape = Context()->Apply(tmpedge2);
1412 TopoDS_Edge anewedge2 = TopoDS::Edge(aTmpShape);
1413 Context()->Remove(remedge);
1414 SendWarning( remedge, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1415 if (theSmallEdges.Contains(remedge))
1416 theSmallEdges.Remove(remedge);
1417 theEdgeToFaces.UnBind(remedge);
1418 theEdgeToFaces.UnBind(tmpedge1);
1419 theEdgeToFaces.UnBind(tmpedge2);
1420 theEdgeToFaces.Bind(anewedge1,aL1);
1421 theEdgeToFaces.Bind(anewedge2,aL2);
1422 if (theSmallEdges.Contains(tmpedge1))
1423 {
1424 theSmallEdges.Remove(tmpedge1);
1425 theSmallEdges.Add(anewedge1);
1426 for (TopTools_ListIteratorOfListOfShape itlf(aL1);
1427 itlf.More(); itlf.Next())
1428 {
1429 TopoDS_Shape curface = itlf.Value();
1430 TopTools_ListOfShape& theEdges = theFaceWithSmall(curface);
1431 TopTools_ListIteratorOfListOfShape ite(theEdges);
1432 while (ite.More())
1433 {
1434 TopoDS_Shape iedge = ite.Value();
1435 if (iedge.IsSame(tmpedge1))
1436 {
1437 theEdges.Remove(ite);
1438 theEdges.Append(anewedge1);
1439 }
1440 else ite.Next();
1441 }
1442 }
1443 }
1444 if (theSmallEdges.Contains(tmpedge2))
1445 {
1446 theSmallEdges.Remove(tmpedge2);
1447 theSmallEdges.Add(anewedge2);
1448 for (TopTools_ListIteratorOfListOfShape itlf(aL2);
1449 itlf.More(); itlf.Next())
1450 {
1451 TopoDS_Shape curface = itlf.Value();
1452 TopTools_ListOfShape& theEdges = theFaceWithSmall(curface);
1453 TopTools_ListIteratorOfListOfShape ite(theEdges);
1454 while (ite.More())
1455 {
1456 TopoDS_Shape iedge = ite.Value();
1457 if (iedge.IsSame(tmpedge2))
1458 {
1459 theEdges.Remove(ite);
1460 theEdges.Append(anewedge2);
1461 }
1462 else ite.Next();
1463 }
1464 }
1465 }
1466 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE3 );
1467 }
1468 else index++;
1469 }
1470 else
1471 {
1472 //gka protection against removing circles
1473 TopoDS_Edge ed = (take_next ? edge1 : edge2);
1474 ShapeAnalysis_Edge sae;
1475 Handle(Geom_Curve) c3d;
1476 Standard_Real f1,l1;
1477 if(sae.Curve3d(ed,c3d,f1,l1,Standard_False))
1478 {
1479 gp_Pnt p1,p2,p3;
1480 c3d->D0(f1,p1);
1481 c3d->D0(l1,p2);
1482 c3d->D0((f1 +l1)*0.5,p3);
1483
1484 if(p1.Distance(p3) > p1.Distance(p2))
1485 {
1486 index++;
1487 continue;
1488 }
1489 }
1490 if (take_next && theList2.Extent()== 1)
1491 { //gka
1492 TopoDS_Vertex V1 = SAE.FirstVertex(edge1),
1493 V2 = SAE.LastVertex(edge1);
1494 if(V1.IsSame(V2))
1495 {
1496 SFW->WireData()->Remove (index );
1497 Context()->Remove(edge1);
1498 SendWarning( edge1, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1499 if (theSmallEdges.Contains(edge1)) theSmallEdges.Remove(edge1);
1500 theEdgeToFaces.UnBind(edge1);
1501 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
1502 }
1503 else index++;
1504 }
1505 else if( !take_next && theList2.Extent()== 1)
1506 {
1507 TopoDS_Vertex V1 = SAE.FirstVertex(edge2),
1508 V2 = SAE.LastVertex(edge2);
1509 if(V1.IsSame(V2))
1510 {
1511 SFW->WireData()->Remove (index );
1512 Context()->Remove(edge2);
1513 SendWarning( edge2, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1514 if (theSmallEdges.Contains(edge2)) theSmallEdges.Remove(edge2);
1515 theEdgeToFaces.UnBind(edge2);
1516 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
1517 }
1518 else index++;
1519 }
1520 else index++;
1521 }
1522 }
1523 else index++;
1524 }
1525 if (SFW->NbEdges() == 1 && aModeDrop)
1526 {
1527 edge1 = SFW->WireData()->Edge(1);
1528 if (theSmallEdges.Contains(edge1))
1529 {
1530 SFW->WireData()->Remove(1);
1531 Context()->Remove(edge1);
1532 SendWarning( edge1, Message_Msg("FixWireframe.FixSmallEdges.MSG0"));
1533 theSmallEdges.Remove(edge1);
1534 theEdgeToFaces.UnBind(edge1);
1535 Context()->Remove(aWire);
1536 SendWarning( aWire, Message_Msg("FixWireframe.FixSmallEdges.MSG1"));
1537 myStatusSmallEdges |= ShapeExtend::EncodeStatus( ShapeExtend_DONE2 );
1538 }
1539 }
1540 else
1541 {
1542 SFW->FixConnected();
1543 Context()->Replace(aWire,SFW->Wire());
1544 }
1545 }
1546 // end enk block
1547 // Record vertex replacements in context
1548 for (TopTools_DataMapIteratorOfDataMapOfShapeShape itv(theNewVertices);
1549 itv.More(); itv.Next()) Context()->Replace(itv.Key(),itv.Value());
1550
1551 TopoDS_Shape shape = myShape;
1552 myShape.Nullify();
1553 myShape = Context()->Apply(shape);
1554
1555 ShapeFix::SameParameter(myShape,Standard_False);
1556
1557 return StatusSmallEdges( ShapeExtend_DONE );
1558 }
1559
1560 return Standard_False;
1561 }
1562