Commit | Line | Data |
---|---|---|
7bd071ed | 1 | // Created on: 2016-06-23 |
2 | // Copyright (c) 2016 OPEN CASCADE SAS | |
3 | // Created by: Oleg AGASHIN | |
4 | // | |
5 | // This file is part of Open CASCADE Technology software library. | |
6 | // | |
7 | // This library is free software; you can redistribute it and/or modify it under | |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published | |
9 | // by the Free Software Foundation, with special exception defined in the file | |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT | |
11 | // distribution for complete text of the license and disclaimer of any warranty. | |
12 | // | |
13 | // Alternatively, this file may be used under the terms of Open CASCADE | |
14 | // commercial license or contractual agreement. | |
15 | ||
16 | #include <BRepMesh_ModelHealer.hxx> | |
17 | #include <BRepMesh_Deflection.hxx> | |
7bd071ed | 18 | #include <BRepMesh_FaceChecker.hxx> |
19 | #include <BRepMesh_EdgeDiscret.hxx> | |
20 | #include <IMeshData_Face.hxx> | |
21 | #include <IMeshData_Wire.hxx> | |
22 | #include <IMeshData_Edge.hxx> | |
23 | #include <IMeshData_PCurve.hxx> | |
24 | #include <OSD_Parallel.hxx> | |
25 | #include <TopExp.hxx> | |
26 | #include <TopoDS_Vertex.hxx> | |
27 | ||
28 | #ifdef DEBUG_HEALER | |
29 | #include <BRepBuilderAPI_MakePolygon.hxx> | |
30 | #include <BRepTools.hxx> | |
31 | #include <BRep_Builder.hxx> | |
32 | #include <TopoDS_Compound.hxx> | |
33 | #endif | |
34 | ||
4945e8be | 35 | IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_ModelHealer, IMeshTools_ModelAlgo) |
36 | ||
7bd071ed | 37 | namespace |
38 | { | |
39 | //! Decreases deflection of the given edge and tries to update discretization. | |
40 | class EdgeAmplifier | |
41 | { | |
42 | public: | |
43 | //! Constructor. | |
44 | EdgeAmplifier(const IMeshTools_Parameters& theParameters) | |
45 | : myParameters(theParameters) | |
46 | { | |
47 | } | |
48 | ||
49 | //! Main operator. | |
50 | void operator()(const IMeshData::IEdgePtr& theDEdge) const | |
51 | { | |
52 | const IMeshData::IEdgeHandle aDEdge = theDEdge; | |
f73592ed | 53 | |
54 | Standard_Integer aPointsNb = aDEdge->GetCurve()->ParametersNb(); | |
55 | ||
7bd071ed | 56 | aDEdge->Clear(Standard_True); |
57 | aDEdge->SetDeflection(Max(aDEdge->GetDeflection() / 3., Precision::Confusion())); | |
58 | ||
f73592ed | 59 | for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb(); ++aPCurveIt) |
60 | { | |
61 | const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(aPCurveIt); | |
62 | const IMeshData::IFaceHandle aDFace = aPCurve->GetFace(); | |
63 | ||
64 | // Check that outer wire contains 2 edges or less and add an additional point. | |
65 | const IMeshData::IWireHandle& aDWire = aDFace->GetWire(0); | |
66 | if (aDWire->EdgesNb() <= 2) | |
67 | { | |
68 | ++aPointsNb; | |
69 | break; | |
70 | } | |
71 | } | |
72 | ||
7bd071ed | 73 | const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve(0); |
74 | const IMeshData::IFaceHandle aDFace = aPCurve->GetFace(); | |
75 | Handle(IMeshTools_CurveTessellator) aTessellator = | |
76 | BRepMesh_EdgeDiscret::CreateEdgeTessellator( | |
f73592ed | 77 | aDEdge, aPCurve->GetOrientation(), aDFace, |
78 | myParameters, aPointsNb); | |
7bd071ed | 79 | |
80 | BRepMesh_EdgeDiscret::Tessellate3d(aDEdge, aTessellator, Standard_False); | |
81 | BRepMesh_EdgeDiscret::Tessellate2d(aDEdge, Standard_False); | |
82 | } | |
83 | ||
84 | private: | |
85 | ||
86 | EdgeAmplifier (const EdgeAmplifier& theOther); | |
87 | ||
88 | void operator=(const EdgeAmplifier& theOther); | |
89 | ||
90 | private: | |
91 | const IMeshTools_Parameters& myParameters; | |
92 | }; | |
93 | ||
94 | //! Returns True if some of two vertcies is same with reference one. | |
4945e8be | 95 | Standard_Boolean isSameWithSomeOf( |
7bd071ed | 96 | const TopoDS_Vertex& theRefVertex, |
97 | const TopoDS_Vertex& theVertex1, | |
98 | const TopoDS_Vertex& theVertex2) | |
99 | { | |
100 | return (theRefVertex.IsSame(theVertex1) || | |
101 | theRefVertex.IsSame(theVertex2)); | |
102 | } | |
103 | ||
104 | //! Returns True if some of two vertcies is within tolerance of reference one. | |
4945e8be | 105 | Standard_Boolean isInToleranceWithSomeOf( |
7bd071ed | 106 | const gp_Pnt& theRefPoint, |
107 | const gp_Pnt& thePoint1, | |
108 | const gp_Pnt& thePoint2, | |
109 | const Standard_Real theTol) | |
110 | { | |
111 | const Standard_Real aSqTol = theTol * theTol; | |
112 | return (theRefPoint.SquareDistance(thePoint1) < aSqTol || | |
113 | theRefPoint.SquareDistance(thePoint2) < aSqTol); | |
114 | } | |
115 | } | |
116 | ||
117 | //======================================================================= | |
118 | // Function: Constructor | |
119 | // Purpose : | |
120 | //======================================================================= | |
121 | BRepMesh_ModelHealer::BRepMesh_ModelHealer() | |
122 | { | |
123 | } | |
124 | ||
125 | //======================================================================= | |
126 | // Function: Destructor | |
127 | // Purpose : | |
128 | //======================================================================= | |
129 | BRepMesh_ModelHealer::~BRepMesh_ModelHealer() | |
130 | { | |
131 | } | |
132 | ||
133 | //======================================================================= | |
134 | // Function: Perform | |
135 | // Purpose : | |
136 | //======================================================================= | |
c2a25d52 | 137 | Standard_Boolean BRepMesh_ModelHealer::performInternal( |
7bd071ed | 138 | const Handle(IMeshData_Model)& theModel, |
ce97cd97 | 139 | const IMeshTools_Parameters& theParameters, |
140 | const Message_ProgressRange& theRange) | |
7bd071ed | 141 | { |
ce97cd97 | 142 | (void )theRange; |
7bd071ed | 143 | myModel = theModel; |
144 | myParameters = theParameters; | |
145 | if (myModel.IsNull()) | |
146 | { | |
147 | return Standard_False; | |
148 | } | |
149 | ||
150 | // MinSize is made as a constant. It is connected with | |
151 | // the fact that too rude discretisation can lead to | |
152 | // self-intersecting polygon, which cannot be fixed. | |
153 | // As result the face will not be triangulated at all. | |
154 | // E.g. see "Test mesh standard_mesh C7", the face #17. | |
155 | myParameters.MinSize = Precision::Confusion(); | |
156 | ||
157 | myFaceIntersectingEdges = new IMeshData::DMapOfIFacePtrsMapOfIEdgePtrs; | |
158 | for (Standard_Integer aFaceIt = 0; aFaceIt < myModel->FacesNb(); ++aFaceIt) | |
159 | { | |
160 | myFaceIntersectingEdges->Bind(myModel->GetFace(aFaceIt).get(), Handle(IMeshData::MapOfIEdgePtr)()); | |
161 | } | |
162 | ||
163 | // TODO: Here we can process edges in order to remove close discrete points. | |
164 | OSD_Parallel::For(0, myModel->FacesNb(), *this, !isParallel()); | |
165 | amplifyEdges(); | |
166 | ||
167 | IMeshData::DMapOfIFacePtrsMapOfIEdgePtrs::Iterator aFaceIt(*myFaceIntersectingEdges); | |
168 | for (; aFaceIt.More(); aFaceIt.Next()) | |
169 | { | |
170 | if (!aFaceIt.Value().IsNull()) | |
171 | { | |
172 | const IMeshData::IFaceHandle aDFace = aFaceIt.Key(); | |
173 | aDFace->SetStatus(IMeshData_SelfIntersectingWire); | |
174 | aDFace->SetStatus(IMeshData_Failure); | |
175 | } | |
176 | } | |
177 | ||
178 | myFaceIntersectingEdges.Nullify(); | |
179 | myModel.Nullify(); // Do not hold link to model. | |
180 | return Standard_True; | |
181 | } | |
182 | ||
183 | //======================================================================= | |
184 | // Function: amplifyEdges | |
185 | // Purpose : | |
186 | //======================================================================= | |
187 | void BRepMesh_ModelHealer::amplifyEdges() | |
188 | { | |
189 | Handle(NCollection_IncAllocator) aTmpAlloc = | |
190 | new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE); | |
191 | ||
192 | Standard_Integer aAmpIt = 0; | |
193 | const Standard_Real aIterNb = 5; | |
194 | IMeshData::MapOfIEdgePtr aEdgesToUpdate(1, aTmpAlloc); | |
3326f923 DR |
195 | EdgeAmplifier anEdgeAmplifier (myParameters); |
196 | ||
7bd071ed | 197 | while (aAmpIt++ < aIterNb && popEdgesToUpdate(aEdgesToUpdate)) |
198 | { | |
199 | // Try to update discretization by decreasing deflection of problematic edges. | |
200 | OSD_Parallel::ForEach(aEdgesToUpdate.cbegin(), aEdgesToUpdate.cend(), | |
3326f923 | 201 | anEdgeAmplifier, |
7bd071ed | 202 | !(myParameters.InParallel && aEdgesToUpdate.Size() > 1), |
203 | aEdgesToUpdate.Size()); | |
204 | ||
205 | IMeshData::MapOfIFacePtr aFacesToCheck(1, aTmpAlloc); | |
206 | IMeshData::MapOfIEdgePtr::Iterator aEdgeIt(aEdgesToUpdate); | |
207 | for (; aEdgeIt.More(); aEdgeIt.Next()) | |
208 | { | |
209 | const IMeshData::IEdgeHandle aDEdge = aEdgeIt.Value(); | |
210 | for (Standard_Integer aPCurveIt = 0; aPCurveIt < aDEdge->PCurvesNb(); ++aPCurveIt) | |
211 | { | |
212 | aFacesToCheck.Add(aDEdge->GetPCurve(aPCurveIt)->GetFace()); | |
213 | } | |
214 | } | |
215 | ||
216 | OSD_Parallel::ForEach(aFacesToCheck.cbegin(), aFacesToCheck.cend(), | |
217 | *this, !(myParameters.InParallel && aFacesToCheck.Size() > 1), | |
218 | aFacesToCheck.Size()); | |
219 | ||
220 | aEdgesToUpdate.Clear(); | |
221 | aTmpAlloc->Reset(Standard_False); | |
222 | } | |
223 | } | |
224 | ||
225 | //======================================================================= | |
226 | // Function: popEdgesToUpdate | |
227 | // Purpose : | |
228 | //======================================================================= | |
229 | Standard_Boolean BRepMesh_ModelHealer::popEdgesToUpdate( | |
230 | IMeshData::MapOfIEdgePtr& theEdgesToUpdate) | |
231 | { | |
232 | IMeshData::DMapOfIFacePtrsMapOfIEdgePtrs::Iterator aFaceIt(*myFaceIntersectingEdges); | |
233 | for (; aFaceIt.More(); aFaceIt.Next()) | |
234 | { | |
235 | Handle(IMeshData::MapOfIEdgePtr)& aIntersections = aFaceIt.ChangeValue(); | |
236 | if (!aIntersections.IsNull()) | |
237 | { | |
238 | theEdgesToUpdate.Unite(*aIntersections); | |
239 | aIntersections.Nullify(); | |
240 | } | |
241 | } | |
242 | ||
243 | return !theEdgesToUpdate.IsEmpty(); | |
244 | } | |
245 | ||
246 | //======================================================================= | |
247 | // Function: process | |
248 | // Purpose : | |
249 | //======================================================================= | |
250 | void BRepMesh_ModelHealer::process(const IMeshData::IFaceHandle& theDFace) const | |
251 | { | |
c2a25d52 | 252 | try |
7bd071ed | 253 | { |
c2a25d52 | 254 | OCC_CATCH_SIGNALS |
255 | ||
256 | Handle(IMeshData::MapOfIEdgePtr)& aIntersections = myFaceIntersectingEdges->ChangeFind(theDFace.get()); | |
257 | aIntersections.Nullify(); | |
258 | ||
259 | fixFaceBoundaries(theDFace); | |
260 | ||
261 | if (!theDFace->IsSet(IMeshData_Failure)) | |
7bd071ed | 262 | { |
c2a25d52 | 263 | BRepMesh_FaceChecker aChecker(theDFace, myParameters); |
264 | if (!aChecker.Perform()) | |
265 | { | |
7bd071ed | 266 | #ifdef DEBUG_HEALER |
c2a25d52 | 267 | std::cout << "Failed : #" << aChecker.GetIntersectingEdges()->Size() << std::endl; |
7bd071ed | 268 | #endif |
c2a25d52 | 269 | aIntersections = aChecker.GetIntersectingEdges(); |
270 | } | |
8c186dad | 271 | else |
272 | { | |
273 | if (theDFace->WiresNb () == 1) | |
274 | { | |
275 | const IMeshData::IWireHandle& aDWire = theDFace->GetWire (0); | |
276 | ||
277 | if (aDWire->EdgesNb () == 2) | |
278 | { | |
279 | const IMeshData::IEdgePtr& aDEdge0 = aDWire->GetEdge (0); | |
280 | const IMeshData::IEdgePtr& aDEdge1 = aDWire->GetEdge (1); | |
281 | ||
282 | const IMeshData::IPCurveHandle& aPCurve0 = aDEdge0->GetPCurve (theDFace.get (), aDWire->GetEdgeOrientation (0)); | |
283 | const IMeshData::IPCurveHandle& aPCurve1 = aDEdge1->GetPCurve (theDFace.get (), aDWire->GetEdgeOrientation (1)); | |
284 | ||
285 | if (aPCurve0->ParametersNb () == 2 && aPCurve1->ParametersNb () == 2) | |
286 | { | |
287 | aIntersections = new IMeshData::MapOfIEdgePtr; | |
288 | // a kind of degenerated face - 1 wire, 2 edges and both edges are very small | |
289 | aIntersections->Add (aDEdge0); | |
290 | aIntersections->Add (aDEdge1); | |
291 | } | |
292 | } | |
293 | } | |
294 | } | |
7bd071ed | 295 | } |
296 | } | |
c2a25d52 | 297 | catch (Standard_Failure const&) |
298 | { | |
299 | theDFace->SetStatus (IMeshData_Failure); | |
300 | } | |
7bd071ed | 301 | } |
302 | ||
303 | //======================================================================= | |
304 | // Function: fixFaceBoundaries | |
305 | // Purpose : | |
306 | //======================================================================= | |
307 | void BRepMesh_ModelHealer::fixFaceBoundaries(const IMeshData::IFaceHandle& theDFace) const | |
308 | { | |
309 | #ifdef DEBUG_HEALER | |
310 | TopoDS_Compound aComp; | |
311 | BRep_Builder aBuilder; | |
312 | aBuilder.MakeCompound(aComp); | |
313 | #endif | |
314 | ||
315 | for (int aWireIt = 0; aWireIt < theDFace->WiresNb(); ++aWireIt) | |
316 | { | |
317 | const IMeshData::IWireHandle& aDWire = theDFace->GetWire(aWireIt); | |
318 | BRepMesh_Deflection::ComputeDeflection(aDWire, myParameters); | |
319 | for (int aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt) | |
320 | { | |
321 | const int aPrevEdgeIt = (aEdgeIt + aDWire->EdgesNb() - 1) % aDWire->EdgesNb(); | |
322 | const int aNextEdgeIt = (aEdgeIt + 1) % aDWire->EdgesNb(); | |
323 | ||
324 | const IMeshData::IEdgeHandle aPrevEdge = aDWire->GetEdge(aPrevEdgeIt); | |
325 | const IMeshData::IEdgeHandle aCurrEdge = aDWire->GetEdge(aEdgeIt); | |
326 | const IMeshData::IEdgeHandle aNextEdge = aDWire->GetEdge(aNextEdgeIt); | |
327 | ||
328 | Standard_Boolean isConnected = !getCommonVertex(aCurrEdge, aNextEdge).IsNull() && | |
329 | !getCommonVertex(aPrevEdge, aCurrEdge).IsNull(); | |
330 | ||
331 | if (isConnected) | |
332 | { | |
333 | const IMeshData::IPCurveHandle& aPrevPCurve = | |
334 | aPrevEdge->GetPCurve(theDFace.get(), aDWire->GetEdgeOrientation(aPrevEdgeIt)); | |
335 | ||
336 | const IMeshData::IPCurveHandle& aCurrPCurve = | |
337 | aCurrEdge->GetPCurve(theDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt)); | |
338 | ||
339 | const IMeshData::IPCurveHandle& aNextPCurve = | |
340 | aNextEdge->GetPCurve(theDFace.get(), aDWire->GetEdgeOrientation(aNextEdgeIt)); | |
341 | ||
342 | isConnected = connectClosestPoints(aPrevPCurve, aCurrPCurve, aNextPCurve); | |
343 | ||
344 | #ifdef DEBUG_HEALER | |
345 | BRepBuilderAPI_MakePolygon aPoly; | |
346 | for (int i = 0; i < aCurrPCurve->ParametersNb(); ++i) | |
347 | { | |
348 | const gp_Pnt2d& aPnt = aCurrPCurve->GetPoint(i); | |
349 | aPoly.Add(gp_Pnt(aPnt.X(), aPnt.Y(), 0.)); | |
350 | } | |
351 | ||
352 | if (aPoly.IsDone()) | |
353 | { | |
354 | aBuilder.Add(aComp, aPoly.Shape()); | |
355 | } | |
356 | TCollection_AsciiString aName("face_discr.brep"); | |
357 | BRepTools::Write(aComp, aName.ToCString()); | |
358 | #endif | |
359 | } | |
360 | ||
361 | if (!isConnected || aCurrEdge->IsSet(IMeshData_Outdated)) | |
362 | { | |
363 | // We have to clean face from triangulation. | |
364 | theDFace->SetStatus(IMeshData_Outdated); | |
365 | ||
366 | if (!isConnected) | |
367 | { | |
368 | // Just mark wire as open, but continue fixing other inconsistencies | |
369 | // in hope that this data could be suitable to build mesh somehow. | |
370 | aDWire->SetStatus(IMeshData_OpenWire); | |
371 | } | |
372 | } | |
373 | } | |
374 | } | |
375 | ||
376 | #ifdef DEBUG_HEALER | |
377 | TCollection_AsciiString aName ("face_discr.brep"); | |
378 | TCollection_AsciiString aFaceName("face_geom.brep"); | |
379 | BRepTools::Write(aComp, aName.ToCString()); | |
380 | BRepTools::Write(theDFace->GetFace(), aFaceName.ToCString()); | |
381 | #endif | |
382 | ||
383 | BRepMesh_Deflection::ComputeDeflection(theDFace, myParameters); | |
384 | } | |
385 | ||
386 | //======================================================================= | |
387 | // Function: hasCommonVertex | |
388 | // Purpose : | |
389 | //======================================================================= | |
390 | TopoDS_Vertex BRepMesh_ModelHealer::getCommonVertex( | |
391 | const IMeshData::IEdgeHandle& theEdge1, | |
392 | const IMeshData::IEdgeHandle& theEdge2) const | |
393 | { | |
394 | TopoDS_Vertex aVertex1_1, aVertex1_2; | |
395 | TopExp::Vertices(theEdge1->GetEdge(), aVertex1_1, aVertex1_2); | |
396 | ||
397 | //Test bugs moddata_2 bug428. | |
398 | // restore [locate_data_file OCC428.brep] rr | |
399 | // explode rr f | |
400 | // explode rr_91 w | |
401 | // explode rr_91_2 e | |
402 | // nbshapes rr_91_2_2 | |
403 | // # 0 vertices; 1 edge | |
404 | ||
405 | //This shape is invalid and can lead to exception in this code. | |
406 | ||
407 | if (aVertex1_1.IsNull() || aVertex1_2.IsNull()) | |
408 | return TopoDS_Vertex(); | |
409 | ||
410 | if (theEdge1->GetEdge().IsSame(theEdge2->GetEdge())) | |
411 | { | |
412 | return aVertex1_1.IsSame(aVertex1_2) ? aVertex1_1 : TopoDS_Vertex(); | |
413 | } | |
414 | ||
415 | TopoDS_Vertex aVertex2_1, aVertex2_2; | |
416 | TopExp::Vertices(theEdge2->GetEdge(), aVertex2_1, aVertex2_2); | |
417 | ||
418 | if (aVertex2_1.IsNull() || aVertex2_2.IsNull()) | |
419 | return TopoDS_Vertex(); | |
420 | ||
421 | if (isSameWithSomeOf(aVertex1_1, aVertex2_1, aVertex2_2)) | |
422 | { | |
423 | return aVertex1_1; | |
424 | } | |
425 | else if (isSameWithSomeOf(aVertex1_2, aVertex2_1, aVertex2_2)) | |
426 | { | |
427 | return aVertex1_2; | |
428 | } | |
429 | ||
430 | const gp_Pnt aPnt1_1 = BRep_Tool::Pnt(aVertex1_1); | |
431 | const gp_Pnt aPnt1_2 = BRep_Tool::Pnt(aVertex1_2); | |
432 | const Standard_Real aTol1_1 = BRep_Tool::Tolerance(aVertex1_1); | |
433 | const Standard_Real aTol1_2 = BRep_Tool::Tolerance(aVertex1_2); | |
434 | ||
435 | const gp_Pnt aPnt2_1 = BRep_Tool::Pnt(aVertex2_1); | |
436 | const gp_Pnt aPnt2_2 = BRep_Tool::Pnt(aVertex2_2); | |
437 | const Standard_Real aTol2_1 = BRep_Tool::Tolerance(aVertex2_1); | |
438 | const Standard_Real aTol2_2 = BRep_Tool::Tolerance(aVertex2_2); | |
439 | ||
440 | if (isInToleranceWithSomeOf(aPnt1_1, aPnt2_1, aPnt2_2, aTol1_1 + Max(aTol2_1, aTol2_2))) | |
441 | { | |
442 | return aVertex1_1; | |
443 | } | |
444 | else if (isInToleranceWithSomeOf(aPnt1_2, aPnt2_1, aPnt2_2, aTol1_2 + Max(aTol2_1, aTol2_2))) | |
445 | { | |
446 | return aVertex1_2; | |
447 | } | |
448 | ||
449 | return TopoDS_Vertex(); | |
450 | } | |
451 | ||
452 | //======================================================================= | |
453 | // Function: connectClosestPoints | |
454 | // Purpose : | |
455 | //======================================================================= | |
456 | Standard_Boolean BRepMesh_ModelHealer::connectClosestPoints( | |
457 | const IMeshData::IPCurveHandle& thePrevDEdge, | |
458 | const IMeshData::IPCurveHandle& theCurrDEdge, | |
459 | const IMeshData::IPCurveHandle& theNextDEdge) const | |
460 | { | |
461 | if (thePrevDEdge->IsInternal() || | |
462 | theCurrDEdge->IsInternal() || | |
463 | theNextDEdge->IsInternal()) | |
464 | { | |
465 | return Standard_True; | |
466 | } | |
467 | ||
468 | gp_Pnt2d& aPrevFirstUV = thePrevDEdge->GetPoint(0); | |
469 | gp_Pnt2d& aPrevLastUV = thePrevDEdge->GetPoint(thePrevDEdge->ParametersNb() - 1); | |
470 | ||
471 | if (thePrevDEdge == theCurrDEdge) | |
472 | { | |
473 | // Wire consists of a single edge. | |
474 | aPrevFirstUV = aPrevLastUV; | |
475 | return Standard_True; | |
476 | } | |
477 | ||
478 | gp_Pnt2d& aCurrFirstUV = theCurrDEdge->GetPoint(0); | |
479 | gp_Pnt2d& aCurrLastUV = theCurrDEdge->GetPoint(theCurrDEdge->ParametersNb() - 1); | |
480 | ||
481 | gp_Pnt2d *aPrevUV = NULL, *aCurrPrevUV = NULL; | |
482 | const Standard_Real aPrevSqDist = closestPoints(aPrevFirstUV, aPrevLastUV, | |
483 | aCurrFirstUV, aCurrLastUV, | |
484 | aPrevUV, aCurrPrevUV); | |
485 | ||
486 | gp_Pnt2d *aNextUV = NULL, *aCurrNextUV = NULL; | |
487 | if (thePrevDEdge == theNextDEdge) | |
488 | { | |
489 | // Wire consists of two edges. Connect both ends. | |
490 | aNextUV = (aPrevUV == &aPrevFirstUV) ? &aPrevLastUV : &aPrevFirstUV; | |
491 | aCurrNextUV = (aCurrPrevUV == &aCurrFirstUV) ? &aCurrLastUV : &aCurrFirstUV; | |
492 | ||
493 | *aNextUV = *aCurrNextUV; | |
494 | *aPrevUV = *aCurrPrevUV; | |
495 | return Standard_True; | |
496 | } | |
497 | ||
498 | gp_Pnt2d& aNextFirstUV = theNextDEdge->GetPoint(0); | |
499 | gp_Pnt2d& aNextLastUV = theNextDEdge->GetPoint(theNextDEdge->ParametersNb() - 1); | |
500 | ||
501 | const Standard_Real aNextSqDist = closestPoints(aNextFirstUV, aNextLastUV, | |
502 | aCurrFirstUV, aCurrLastUV, | |
503 | aNextUV, aCurrNextUV); | |
504 | ||
505 | #ifdef DEBUG_HEALER | |
506 | std::cout << "PrevSqDist = " << aPrevSqDist << std::endl; | |
507 | std::cout << "NextSqDist = " << aNextSqDist << std::endl; | |
508 | #endif | |
509 | ||
510 | // Connect closest points first. This can help to identify | |
511 | // which ends should be connected in case of gap. | |
512 | if (aPrevSqDist - aNextSqDist > gp::Resolution()) | |
513 | { | |
514 | adjustSamePoints(aCurrNextUV, aNextUV, aCurrPrevUV, aPrevUV, aCurrFirstUV, aCurrLastUV, aPrevFirstUV, aPrevLastUV); | |
515 | } | |
516 | else | |
517 | { | |
518 | adjustSamePoints(aCurrPrevUV, aPrevUV, aCurrNextUV, aNextUV, aCurrFirstUV, aCurrLastUV, aNextFirstUV, aNextLastUV); | |
519 | } | |
520 | ||
521 | return Standard_True; | |
522 | } |