1 // File: LineConn2d_Path.cpp
2 // Created: 11.08.05 15:16:13
3 // Author: Alexander GRIGORIEV
4 // Copyright: Open Cascade 2005
7 #include <LineConn2dAfx.h>
9 #include <LineConn2d_Path.h>
10 #include <LineConn2d_Model.h>
11 #include <LineConn2d_SegmentIterator.h>
13 //=======================================================================
14 //function : LineConn2d_Path
15 //purpose : Empty constructor
16 //=======================================================================
18 LineConn2d_Path::LineConn2d_Path ()
24 myOrient (LineConn2d::Indefinite),
25 myIsComplete (Standard_False) {}
27 //=======================================================================
28 //function : LineConn2d_Path()
29 //purpose : Constructor
30 //=======================================================================
32 LineConn2d_Path::LineConn2d_Path (const gp_XY& theStart,
34 const LineConn2d_Model& theModel,
35 const LineConn2d::Orient theOri)
36 : LineConn2d_Segment (theStart, theEnd),
39 myBranches (theModel.TempAlloc()),
44 myIsComplete (Standard_False)
46 if (theOri == LineConn2d::Indefinite)
47 myOrient = LineConn2d::Orientation (Delta());
50 //=======================================================================
53 //=======================================================================
55 Standard_Real LineConn2d_Path::Width () const
57 return (myModel ? myModel -> Tolerance() : 0.);
60 //=======================================================================
61 //function : AddBranch
63 //=======================================================================
65 void LineConn2d_Path::AddBranch (LineConn2d_Path& theBranch,
68 theBranch.myParent = this;
69 theBranch.Evaluate (theTgt);
70 myBranches.Append (theBranch);
73 //=======================================================================
76 //=======================================================================
78 Standard_Integer LineConn2d_Path::Evaluate (const gp_XY& theTarget)
80 const Standard_Real aHalfPerimeterNorm (myModel->HalfPerimeter() / 1000.);
81 const Standard_Real aHalfPerimeterNorm1 (aHalfPerimeterNorm * 10.);
83 // Calculate the price due to the distance
84 const gp_XY aDistVector (theTarget - Extremity());
85 // ... distance from the extremity to the target
86 const Standard_Real aDist =
87 LineConn2d_FABS(aDistVector.X()) + LineConn2d_FABS(aDistVector.Y());
88 // ... deflection from the shortest way
89 gp_XY aV = theTarget - Origin();
90 Standard_Real aDist1 = (Delta() ^ aV);
91 aDist1 = ::sqrt((aDist1 * aDist1) / (aV * aV));
93 if (aDist < Precision::Confusion())
94 myIsComplete = Standard_True;
96 myPriceDist = Standard_Integer ((aDist + 0.2 * aDist1) / aHalfPerimeterNorm);
98 // Calculate the price due to length.
99 myPriceLen = Standard_Integer (Delta().Modulus() / aHalfPerimeterNorm1);
101 // Take into account the additive from the parent
102 if (myParent != 0L) {
103 if (myParent -> Orientation() != myOrient)
104 myPriceLen += PriceOfBreak();
105 myPriceLen += (myParent -> myPriceLen -
106 (Origin() - myParent->Extremity()).Modulus()
107 / aHalfPerimeterNorm1);
109 return myPriceLen + myPriceDist;
112 //=======================================================================
113 //function : createPath
115 //=======================================================================
117 Standard_Boolean LineConn2d_Path::createPath
118 (LineConn2d_Path& thePath,
119 const LineConn2d_Model& theModel,
120 const gp_XY& theStart,
121 const LineConn2d::Orient theOrient,
122 const Standard_Boolean isRoot)
124 Standard_Boolean aResult (Standard_False);
125 const Standard_Real aTol = theModel.Tolerance();
126 // Create a long box extending in the direction theOrient (till the boundary)
127 LineConn2d_Box aPathBox;
128 const LineConn2d_Box& aModelBox = theModel.Box();
129 Standard_Real aPathBoxLen (0.);
130 gp_XY aPathDir (0., 0.);
131 // Four segments forming the PathBox:
132 // 0 - the transversal segment containing theStart
135 // 3 - the right side
136 LineConn2d_Segment aSeg[4];
139 aPathBoxLen = aModelBox.Center().X() + aModelBox.HSize().X() - theStart.X();
140 aPathBox = LineConn2d_Box (theStart + gp_XY (0.5 * aPathBoxLen, 0.),
141 gp_XY (0.5 * aPathBoxLen, aTol));
143 aSeg[0] = LineConn2d_Segment (theStart + gp_XY (0., -aTol),
144 theStart + gp_XY (0., aTol));
145 aSeg[1] = LineConn2d_Segment (theStart + gp_XY (0., aTol),
146 theStart + gp_XY (aPathBoxLen, aTol));
147 aSeg[2] = LineConn2d_Segment (theStart + gp_XY (aPathBoxLen, aTol),
148 theStart + gp_XY (aPathBoxLen, -aTol));
149 aSeg[3] = LineConn2d_Segment (theStart + gp_XY (0., -aTol),
150 theStart + gp_XY (aPathBoxLen, -aTol));
153 aPathBoxLen = aModelBox.Center().Y() + aModelBox.HSize().Y() - theStart.Y();
154 aPathBox = LineConn2d_Box (theStart + gp_XY (0., 0.5 * aPathBoxLen),
155 gp_XY (aTol, 0.5 * aPathBoxLen));
157 aSeg[0] = LineConn2d_Segment (theStart + gp_XY (aTol, 0.),
158 theStart + gp_XY (-aTol, 0.));
159 aSeg[1] = LineConn2d_Segment (theStart + gp_XY (-aTol, 0),
160 theStart + gp_XY (-aTol, aPathBoxLen));
161 aSeg[2] = LineConn2d_Segment (theStart + gp_XY (-aTol, aPathBoxLen),
162 theStart + gp_XY (aTol, aPathBoxLen));
163 aSeg[3] = LineConn2d_Segment (theStart + gp_XY (aTol, 0.),
164 theStart + gp_XY (aTol, aPathBoxLen));
167 aPathBoxLen= -aModelBox.Center().X() + aModelBox.HSize().X() + theStart.X();
168 aPathBox = LineConn2d_Box (theStart - gp_XY (0.5 * aPathBoxLen, 0.),
169 gp_XY (0.5 * aPathBoxLen, aTol));
171 aSeg[0] = LineConn2d_Segment (theStart - gp_XY (0., -aTol),
172 theStart - gp_XY (0., aTol));
173 aSeg[1] = LineConn2d_Segment (theStart - gp_XY (0., aTol),
174 theStart - gp_XY (aPathBoxLen, aTol));
175 aSeg[2] = LineConn2d_Segment (theStart - gp_XY (aPathBoxLen, aTol),
176 theStart - gp_XY (aPathBoxLen, -aTol));
177 aSeg[3] = LineConn2d_Segment (theStart - gp_XY (0., -aTol),
178 theStart - gp_XY (aPathBoxLen, -aTol));
181 aPathBoxLen= -aModelBox.Center().Y() + aModelBox.HSize().Y() + theStart.Y();
182 aPathBox = LineConn2d_Box (theStart - gp_XY (0., 0.5 * aPathBoxLen),
183 gp_XY (aTol, 0.5 * aPathBoxLen));
185 aSeg[0] = LineConn2d_Segment (theStart - gp_XY (aTol, 0.),
186 theStart - gp_XY (-aTol, 0.));
187 aSeg[1] = LineConn2d_Segment (theStart - gp_XY (-aTol, 0),
188 theStart - gp_XY (-aTol, aPathBoxLen));
189 aSeg[2] = LineConn2d_Segment (theStart - gp_XY (-aTol, aPathBoxLen),
190 theStart - gp_XY (aTol, aPathBoxLen));
191 aSeg[3] = LineConn2d_Segment (theStart - gp_XY (aTol, 0.),
192 theStart - gp_XY (aTol, aPathBoxLen));
196 // Find intersections between aPathBox and the model Objects
197 Standard_Real aMinInterDistance (aPathBoxLen);
198 Standard_Integer anInterSide (0);
200 aPathBox.Enlarge (4 * Precision::Confusion());
201 LineConn2d_BoxTreeSelector aSelBox (aPathBox);
202 theModel.GetTree().Select (aSelBox);
203 NCollection_List<const LineConn2d_Object *>::Iterator
204 aSelBoxIter (aSelBox.GetObjects());
205 for (; aSelBoxIter.More(); aSelBoxIter.Next()) {
206 LineConn2d_SegmentIterator anIter (* aSelBoxIter.Value());
207 Standard_Real aMinDistance (aMinInterDistance);
208 // Loop on the segments of the Object
209 for (; anIter.More(); anIter.Next()) {
210 const LineConn2d_Segment& aSegment = anIter.Value();
211 Standard_Real anAlpha[2];
212 // intersection box - segment
213 if (aPathBox.IsOut (aSegment) == Standard_False) {
214 if (aSeg[0].IsIntersect (aSegment, anAlpha)) // intersect with the rear
216 // cancel intersection test, the rear intersection means the
217 // intersection with the own object
218 aMinDistance = (isRoot ? ::RealLast() : 0.);
221 if (aSeg[1].IsIntersect (aSegment, anAlpha)) // intersect with the Left
223 const Standard_Real aDist = anAlpha[0] * aPathBoxLen;
224 if (aDist < aMinDistance) {
225 aMinDistance = aDist;
229 if (aSeg[3].IsIntersect (aSegment, anAlpha)) // intersect with the Right
231 const Standard_Real aDist = anAlpha[0] * aPathBoxLen;
232 if (aDist < aMinDistance) {
233 aMinDistance = aDist;
237 if (aPathBox.IsOut (aSegment.Origin()) == Standard_False) {
238 const Standard_Real aDist = (aSegment.Origin() - theStart) * aPathDir;
239 if (aDist < aMinDistance) {
240 aMinDistance = aDist;
246 if (aMinDistance < aMinInterDistance)
247 aMinInterDistance = aMinDistance;
250 // The PathLine segment is the medial segment of the PathBox prolongated
251 // by the Tolerance (i.e., by the half-width of the PathBox). Find the
252 // intersection with this PathLine. This intersection also delimits the Path.
253 if (aMinInterDistance > aTol) {
254 Standard_Real aPathLineDist = aTol + aMinInterDistance + 2 * Precision::Confusion();
255 if (aPathLineDist > aPathBoxLen)
256 aPathLineDist = aPathBoxLen;
257 const LineConn2d_Segment aPathLine
258 (theStart, theStart + aPathDir * aPathLineDist);
260 LineConn2d_BoxTreeSelector aSelSeg (aPathLine);
261 theModel.GetTree().Select (aSelSeg);
262 NCollection_List<const LineConn2d_Object *>::Iterator
263 aSelSegIter (aSelSeg.GetObjects());
264 for (; aSelSegIter.More(); aSelSegIter.Next()) {
265 LineConn2d_SegmentIterator anIter (* aSelSegIter.Value());
266 for (; anIter.More(); anIter.Next()) {
267 const LineConn2d_Segment& aSegment = anIter.Value();
268 Standard_Real anAlpha[2];
269 // intersection pathline - segment
270 if (aPathLine.IsIntersect (aSegment, anAlpha)) {
271 const Standard_Real aDist = anAlpha[0] * aPathLineDist - aTol;
272 if (aDist < aMinInterDistance && aDist > 0)
273 aMinInterDistance = aDist;
279 if (aMinInterDistance > aTol) {
280 thePath = LineConn2d_Path (theStart, theStart + aMinInterDistance*aPathDir,
281 theModel, theOrient);
282 thePath.myLimitation = anInterSide;
283 aResult = Standard_True;
288 //=======================================================================
289 //function : Orientation
291 //=======================================================================
293 LineConn2d::Orient LineConn2d_Path::Orientation
294 (const Standard_Integer theSide) const
296 LineConn2d::Orient aResult (myOrient);
299 ((Standard_Integer&)aResult) --;
300 if (aResult == LineConn2d::Indefinite)
301 aResult = LineConn2d::S;
304 ((Standard_Integer&)aResult) ++;
305 if (aResult == LineConn2d::Indefinite1)
306 aResult = LineConn2d::E;
313 //=======================================================================
314 //function : Direction
316 //=======================================================================
318 gp_XY LineConn2d_Path::Direction (const Standard_Integer theSide) const
320 gp_XY aResult (0., 0.);
324 case LineConn2d::E : aResult.SetY (1.); break;
325 case LineConn2d::N : aResult.SetX (-1.); break;
326 case LineConn2d::W : aResult.SetY (-1.); break;
327 case LineConn2d::S : aResult.SetX (1.); break;
332 case LineConn2d::E : aResult.SetX (1.); break;
333 case LineConn2d::N : aResult.SetY (1.); break;
334 case LineConn2d::W : aResult.SetX (-1.); break;
335 case LineConn2d::S : aResult.SetY (-1.); break;
340 case LineConn2d::E : aResult.SetY (-1.); break;
341 case LineConn2d::N : aResult.SetX (1.); break;
342 case LineConn2d::W : aResult.SetY (1.); break;
343 case LineConn2d::S : aResult.SetX (-1.); break;
350 //=======================================================================
351 //function : ProjectPoint
353 //=======================================================================
355 Standard_Boolean LineConn2d_Path::ProjectPoint (gp_XY& theProj,
356 const gp_XY& thePoint) const
358 Standard_Boolean aResult (Standard_False);
361 if (LineConn2d::IsInside (thePoint.X(),
365 aResult = Standard_True;
366 theProj.SetCoord (thePoint.X(), Origin().Y());
370 if (LineConn2d::IsInside (thePoint.X(),
374 aResult = Standard_True;
375 theProj.SetCoord (thePoint.X(), Origin().Y());
379 if (LineConn2d::IsInside (thePoint.Y(),
383 aResult = Standard_True;
384 theProj.SetCoord (Origin().X(), thePoint.Y());
388 if (LineConn2d::IsInside (thePoint.Y(),
392 aResult = Standard_True;
393 theProj.SetCoord (Origin().X(), thePoint.Y());