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