0029915: Porting to VC 2017 : Regressions in Modeling Algorithms on VC 2017
[occt.git] / src / ShapeFix / ShapeFix_EdgeConnect.cxx
1 // Created on: 1999-05-11
2 // Created by: Sergei ZERTCHANINOV
3 // Copyright (c) 1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <BRep_Builder.hxx>
19 #include <BRep_GCurve.hxx>
20 #include <BRep_ListIteratorOfListOfCurveRepresentation.hxx>
21 #include <BRep_TEdge.hxx>
22 #include <BRep_Tool.hxx>
23 #include <gp_Pnt.hxx>
24 #include <gp_XYZ.hxx>
25 #include <Precision.hxx>
26 #include <ShapeFix_EdgeConnect.hxx>
27 #include <TColgp_SequenceOfXYZ.hxx>
28 #include <TopExp.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TopoDS.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopoDS_Shape.hxx>
33 #include <TopoDS_Vertex.hxx>
34 #include <TopoDS_Wire.hxx>
35 #include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
36 #include <TopTools_ListIteratorOfListOfShape.hxx>
37 #include <TopTools_ListOfShape.hxx>
38
39 //#define POSITION_USES_MEAN_POINT
40 //=======================================================================
41 //function : ShapeFix_EdgeConnect
42 //=======================================================================
43 ShapeFix_EdgeConnect::ShapeFix_EdgeConnect () {}
44
45 //=======================================================================
46 //function : Add
47 //purpose  : Adds connectivity information for two edges
48 //=======================================================================
49
50 void ShapeFix_EdgeConnect::Add (const TopoDS_Edge& aFirst, const TopoDS_Edge& aSecond)
51 {
52   // Select vertices to connect
53   TopoDS_Vertex theFirstVertex = TopExp::LastVertex( aFirst, Standard_True );
54   TopoDS_Vertex theSecondVertex = TopExp::FirstVertex( aSecond, Standard_True );
55
56   // Make necessary bindings
57   if ( myVertices.IsBound( theFirstVertex ) ) {
58     // First vertex is bound - find shared vertex
59     TopoDS_Vertex theFirstShared = TopoDS::Vertex( myVertices( theFirstVertex ) );
60     if ( myVertices.IsBound( theSecondVertex ) ) {
61       // Second vertex is bound - find shared vertex
62       TopoDS_Vertex theSecondShared = TopoDS::Vertex( myVertices( theSecondVertex ) );
63       if ( !theFirstShared.IsSame(theSecondShared) ) {
64         // Concatenate lists
65         TopTools_ListOfShape& theFirstList = myLists( theFirstShared );
66         TopTools_ListOfShape& theSecondList = myLists( theSecondShared );
67         for ( TopTools_ListIteratorOfListOfShape theIterator( theSecondList );
68               theIterator.More();
69               theIterator.Next() ) {
70           // Rebind shared vertex for current one
71           myVertices( theIterator.Value() ) = theFirstShared;
72           // Skip the following edge
73           theIterator.Next();
74         }
75         // Append second list to the first one
76         theFirstList.Append( theSecondList );
77         // Unbind the second shared vertex
78         myLists.UnBind( theSecondShared );
79       }
80     }
81     else {
82       // Bind second vertex with shared vertex of the first one
83       myVertices.Bind( theSecondVertex, theFirstShared );
84       // Add second vertex and second edge to the list
85       TopTools_ListOfShape& theFirstList = myLists( theFirstShared );
86       theFirstList.Append( theSecondVertex );
87       theFirstList.Append( aSecond );
88     }
89   }
90   else {
91     if ( myVertices.IsBound( theSecondVertex ) ) {
92       // Second vertex is bound - find shared vertex
93       TopoDS_Vertex& theSecondShared = TopoDS::Vertex( myVertices( theSecondVertex ) );
94       // Bind first vertex with shared vertex of the second one
95       myVertices.Bind( theFirstVertex, theSecondShared );
96       // Add first vertex and first edge to the list
97       TopTools_ListOfShape& theSecondList = myLists( theSecondShared );
98       theSecondList.Append( theFirstVertex );
99       theSecondList.Append( aFirst );
100     }
101     else {
102       // None is bound - create new bindings
103       myVertices.Bind( theFirstVertex, theFirstVertex );
104       myVertices.Bind( theSecondVertex, theFirstVertex );
105       TopTools_ListOfShape theNewList;
106       theNewList.Append( theFirstVertex );
107       theNewList.Append( aFirst );
108       theNewList.Append( theSecondVertex );
109       theNewList.Append( aSecond );
110       myLists.Bind( theFirstVertex, theNewList );
111     }
112   }
113 }
114
115 //=======================================================================
116 //function : Add
117 //purpose  : Adds connectivity information for the whole shape
118 //=======================================================================
119
120 void ShapeFix_EdgeConnect::Add (const TopoDS_Shape& aShape)
121 {
122   for ( TopExp_Explorer expw( aShape, TopAbs_WIRE ); expw.More(); expw.Next() ) {
123     TopoDS_Wire theWire = TopoDS::Wire(expw.Current());
124     TopExp_Explorer expe( theWire, TopAbs_EDGE );
125     if (expe.More()) {
126       // Obtain the first edge and remember it
127       TopoDS_Edge theEdge = TopoDS::Edge(expe.Current());
128       TopoDS_Edge theFirst = theEdge;
129       expe.Next();
130       for (; expe.More(); expe.Next()) {
131         // Obtain second edge and connect it
132         TopoDS_Edge theNext = TopoDS::Edge(expe.Current());
133         Add( theEdge, theNext );
134         theEdge = theNext;
135       }
136       // Connect first and last edges if wire is closed
137       if (theWire.Closed()) Add( theEdge, theFirst );
138     }
139   }
140 }
141
142 //=======================================================================
143 //function : Build
144 //purpose  : Builds shared vertices
145 //=======================================================================
146
147 void ShapeFix_EdgeConnect::Build ()
148 {
149   TopTools_ListIteratorOfListOfShape theLIterator;
150   BRep_ListIteratorOfListOfCurveRepresentation theCIterator;
151
152   TColgp_SequenceOfXYZ thePositions;
153   gp_XYZ thePosition;
154   Standard_Real theMaxDev;
155   BRep_Builder theBuilder;
156
157   // Iterate on shared vertices
158   for ( TopTools_DataMapIteratorOfDataMapOfShapeListOfShape theSIterator( myLists );
159         theSIterator.More();
160         theSIterator.Next() ) {
161     TopoDS_Vertex theSharedVertex = TopoDS::Vertex( theSIterator.Key() );
162     const TopTools_ListOfShape& theList = theSIterator.Value();
163
164     thePositions.Clear();
165
166     // Iterate on edges, accumulating positions
167     for ( theLIterator.Initialize( theList );
168           theLIterator.More();
169           theLIterator.Next() ) {
170       TopoDS_Vertex& theVertex = TopoDS::Vertex( theLIterator.Value() );
171       theLIterator.Next();
172       TopoDS_Edge& theEdge = TopoDS::Edge( theLIterator.Value() );
173
174       // Determine usage of curve bound points
175       TopoDS_Vertex theStart, theEnd;
176       theEdge.Orientation(TopAbs_FORWARD);
177       TopExp::Vertices( theEdge, theStart, theEnd );
178       Standard_Boolean use_start = ( theVertex.IsSame( theStart ) );
179       Standard_Boolean use_end   = ( theVertex.IsSame( theEnd ) );
180       
181       // Iterate on edge curves, accumulating positions
182       for (theCIterator.Initialize((*((Handle(BRep_TEdge)*)&theEdge.TShape()))->ChangeCurves());
183            theCIterator.More(); theCIterator.Next()) {
184         Handle(BRep_GCurve) GC = Handle(BRep_GCurve)::DownCast(theCIterator.Value());
185         if ( GC.IsNull() ) continue;
186         // Calculate vertex position for this curve
187         Standard_Real theFParam, theLParam;
188         GC->Range( theFParam, theLParam );
189         gp_Pnt thePoint;
190         if (use_start) {
191           GC->D0( theFParam, thePoint );
192           thePositions.Append( thePoint.XYZ() );
193         }
194         if (use_end) {
195           GC->D0( theLParam, thePoint );
196           thePositions.Append( thePoint.XYZ() );
197         }
198       }
199     }
200       
201     Standard_Integer i, theNbPos = thePositions.Length();
202
203     // Calculate vertex position
204     thePosition = gp_XYZ(0.,0.,0.);
205
206 #ifdef POSITION_USES_MEAN_POINT
207 #undef POSITION_USES_MEAN_POINT
208     for ( i = 1; i <= theNbPos; i++ ) thePosition += thePositions.Value(i);
209     if ( theNbPos > 1 ) thePosition /= theNbPos;
210 #else
211     gp_XYZ theLBound(0.,0.,0.), theRBound(0.,0.,0.);
212     for ( i = 1; i <= theNbPos; i++ ) {
213       thePosition = thePositions.Value(i);
214       if ( i == 1 ) theLBound = theRBound = thePosition;
215       Standard_Real val = thePosition.X();
216       if ( val < theLBound.X() ) theLBound.SetX( val );
217       else if ( val > theRBound.X() ) theRBound.SetX( val );
218       val = thePosition.Y();
219       if ( val < theLBound.Y() ) theLBound.SetY( val );
220       else if ( val > theRBound.Y() ) theRBound.SetY( val );
221       val = thePosition.Z();
222       if ( val < theLBound.Z() ) theLBound.SetZ( val );
223       else if ( val > theRBound.Z() ) theRBound.SetZ( val );
224     }
225     if ( theNbPos > 1 ) thePosition = (theLBound + theRBound)/2.;
226 #endif    
227
228     // Calculate maximal deviation
229     theMaxDev = 0.;
230
231     for ( i = 1; i <= theNbPos; i++ ) {
232       Standard_Real theDeviation = (thePosition-thePositions.Value(i)).Modulus();
233       if ( theDeviation > theMaxDev ) theMaxDev = theDeviation;
234     }
235     theMaxDev *= 1.0001; // To avoid numerical roundings
236     if ( theMaxDev < Precision::Confusion() ) theMaxDev = Precision::Confusion();
237       
238     // Update shared vertex
239     theBuilder.UpdateVertex( theSharedVertex, gp_Pnt(thePosition), theMaxDev );
240
241     // Iterate on edges, adding shared vertex
242     for ( theLIterator.Initialize( theList );
243           theLIterator.More();
244           theLIterator.Next() ) {
245       TopoDS_Vertex& theVertex = TopoDS::Vertex( theLIterator.Value() );
246       theLIterator.Next();
247       TopoDS_Edge& theEdge = TopoDS::Edge( theLIterator.Value() );
248
249       // Determine usage of old vertices
250       TopoDS_Vertex theStart, theEnd;
251       theEdge.Orientation(TopAbs_FORWARD);
252       TopExp::Vertices( theEdge, theStart, theEnd );
253       Standard_Boolean use_start = ( theVertex.IsSame( theStart ) );
254       Standard_Boolean use_end   = ( theVertex.IsSame( theEnd ) );
255
256       // Prepare vertex to remove
257       TopoDS_Vertex theOldVertex;
258       if (use_start) theOldVertex = theStart; // start is preferred for closed edges
259       else theOldVertex = theEnd;
260
261       // Prepare vertex to add
262       TopoDS_Vertex theNewVertex;
263       //smh#8 Porting AIX
264       if (use_start) {
265         TopoDS_Shape tmpshapeFwd = theSharedVertex.Oriented(TopAbs_FORWARD);
266         theNewVertex = TopoDS::Vertex(tmpshapeFwd);
267       }
268       else {
269         TopoDS_Shape tmpshapeRev = theSharedVertex.Oriented(TopAbs_REVERSED);
270         theNewVertex = TopoDS::Vertex(tmpshapeRev);
271       }
272       if ( !theOldVertex.IsSame(theNewVertex) ) {
273         // Replace vertices
274         Standard_Boolean freeflag = theEdge.Free();
275         theEdge.Free(Standard_True); //smh
276         theBuilder.Remove( theEdge, theOldVertex );
277         theBuilder.Add( theEdge, theNewVertex );
278         if (use_start && use_end) {
279           // process special case for closed edge
280           theBuilder.Remove( theEdge, theOldVertex.Oriented(TopAbs_REVERSED) ); // remove reversed from closed edge
281           theBuilder.Add( theEdge, theNewVertex.Oriented(TopAbs_REVERSED) ); // add reversed to closed edge
282         }
283         theEdge.Free(freeflag);
284       }
285     }
286   }
287
288   // Clear maps after build
289   Clear();
290 }
291
292 //=======================================================================
293 //function : Clear
294 //purpose  : 
295 //=======================================================================
296
297 void ShapeFix_EdgeConnect::Clear ()
298 {
299   myVertices.Clear();
300   myLists.Clear();
301 }