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