1 // File: LineConn2d_Model.cpp
2 // Created: 03.08.05 21:05:54
3 // Author: Alexander GRIGORIEV
4 // Copyright: Open Cascade 2005
6 #include <LineConn2dAfx.h>
8 #include <LineConn2d_Model.h>
9 #include <LineConn2d_PathIterator.h>
10 #include <LineConn2d_IntervalBuffer.h>
11 #include <NCollection_UBTreeFiller.hxx>
12 #include <Standard_ProgramError.hxx>
18 //=======================================================================
19 //function : LineConn2d_Model
20 //purpose : Empty constructor
21 //=======================================================================
23 LineConn2d_Model::LineConn2d_Model ()
24 : myAlloc (new NCollection_IncAllocator()),
25 myTree (new NCollection_IncAllocator()),
26 myTolerance (10 * Precision::Confusion()),
30 myObjects.Append (LineConn2d_Object());
31 myConnections.Append (LineConn2d_Connection());
32 myPorts.Append (LineConn2d_Port());
35 //=======================================================================
36 //function : AddObject
38 //=======================================================================
40 Standard_Integer LineConn2d_Model::AddObject ()
42 const Standard_Integer anInd = myObjects.Length();
43 myObjects.Append (LineConn2d_Object (myAlloc));
47 //=======================================================================
50 //=======================================================================
52 Standard_Integer LineConn2d_Model::AddPoort (const Standard_Integer iObj,
54 const gp_Dir2d& theDir)
56 Standard_Integer aResult (0);
57 if (iObj > 0 && iObj < myObjects.Length()) {
58 aResult = myPorts.Length();
59 myPorts.Append (LineConn2d_Port (myObjects(iObj), thePnt, theDir));
64 //=======================================================================
65 //function : AddConnection
67 //=======================================================================
69 Standard_Integer LineConn2d_Model::AddConnection (const Standard_Integer iPort1,
70 const Standard_Integer iPort2)
72 Standard_Integer aResult (0);
73 const Standard_Integer nPorts = myPorts.Length();
74 if (iPort1 > 0 && iPort1 < nPorts &&
75 iPort2 > 0 && iPort2 < nPorts) {
76 aResult = myConnections.Length();
77 myConnections.Append (LineConn2d_Connection (myAlloc,
84 //=======================================================================
87 //=======================================================================
89 void LineConn2d_Model::Update ()
92 NCollection_UBTreeFiller <const LineConn2d_Object *, LineConn2d_Box>
95 // skipping the 0th member; update the objects and fill the tree.
96 NCollection_Vector <LineConn2d_Object>::Iterator anIter (myObjects);
97 for (anIter.Next(); anIter.More(); anIter.Next()) {
98 LineConn2d_Object& anObj = anIter.ChangeValue();
100 aTreeFiller.Add (&anObj, anObj.Box());
104 _PortLen = LineConn2d::IsSmall (myPortLength)? 2 * myTolerance : myPortLength;
105 myTreeBox = myTree.Root().Bnd();
106 // Update the box with all ports in the model
107 NCollection_Vector <LineConn2d_Port>::Iterator anIterP (myPorts);
108 for (anIterP.Next(); anIterP.More(); anIterP.Next())
109 myTreeBox.Add (anIterP.Value().Location().XY() +
110 anIterP.Value().Direction().XY() * _PortLen);
111 myTreeBox.Enlarge (myTolerance + 10 * Precision::Confusion());
114 //=======================================================================
115 //function : HalfPerimeter
117 //=======================================================================
119 Standard_Real LineConn2d_Model::HalfPerimeter () const
121 const LineConn2d_Box& aBox = myTree.Root().Bnd();
122 return 2 * (aBox.HSize().X() + aBox.HSize().Y());
125 //=======================================================================
126 //function : TempAlloc
128 //=======================================================================
130 const Handle(NCollection_BaseAllocator)& LineConn2d_Model::TempAlloc () const
132 if (myTempAlloc.IsNull())
133 ((Handle(NCollection_IncAllocator)&) myTempAlloc) =
134 new NCollection_IncAllocator();
138 //=======================================================================
141 //=======================================================================
143 Standard_Boolean LineConn2d_Model::Compute ()
147 const Standard_Integer nConn = myConnections.Length();
148 for (Standard_Integer iConn = 1; iConn < nConn; iConn++) {
149 LineConn2d_Connection& aConn = myConnections(iConn);
150 const LineConn2d_Port& aPortSrc = myPorts (aConn.Port(0));
151 const LineConn2d_Port& aPortTgt = myPorts (aConn.Port(1));
152 // Check the ports if any of them is included into other objects
153 if (checkPort (aPortSrc) == Standard_False ||
154 checkPort (aPortTgt) == Standard_False)
157 _PntTgt = gp_XY (aPortTgt.Location().XY() +
158 _PortLen * aPortTgt.Direction().XY());
159 _SegTgtPort = LineConn2d_Segment (aPortTgt.Location().XY(), _PntTgt);
161 // Create the root path (a short segment from the first port)
162 LineConn2d_Path aPathRoot;
163 LineConn2d::Orient anOrient =
164 LineConn2d::Orientation (aPortSrc.Direction().XY());
165 if (!LineConn2d_Path::createPath (aPathRoot, * this,
166 aPortSrc.Location().XY(), anOrient,
169 if (aPathRoot.Delta().Modulus() < _PortLen)
171 aPathRoot.SetDelta (aPathRoot.Direction() * _PortLen);
172 aPathRoot.Evaluate (_PntTgt);
174 const Standard_Integer aMaxDepthIncr =
175 Standard_Integer (mySearchDepth * LineConn2d_Path::PriceOfBreak());
176 const Standard_Integer anUltimateDepth = aMaxDepthIncr * 3;
177 Standard_Integer aMaxDepth = aMaxDepthIncr;
179 // Create three branches near the beginning of the first Path.
180 const gp_XY aPntExt = aPathRoot.Extremity();
181 createPath (aPathRoot, aPntExt, -1);
182 createPath (aPathRoot, aPntExt, 0);
183 createPath (aPathRoot, aPntExt, 1);
186 Standard_Boolean isNewPath (Standard_True);
187 Standard_Integer aMinPrice (::IntegerLast());
188 Standard_Integer aCurPrice (::IntegerLast());
189 const LineConn2d_Path * aMinPricedPath = 0L;
192 isNewPath = Standard_False;
193 // Evaluate the minimal price over all the leaves
194 LineConn2d_PathIterator aPathIter (aPathRoot, TempAlloc());
195 while (aPathIter.More()) {
196 const LineConn2d_Path& aPath = aPathIter.Value();
197 Standard_Integer aPathPrice = aPath.Price();
198 // Correct the price for the terminating path if it makes an angle
199 // with the port direction.
200 if (aPath.IsComplete()) {
201 if (LineConn2d::IsSmall (aPath.Direction() ^
202 aPortTgt.Direction().XY()) == Standard_False)
203 aPathPrice += LineConn2d_Path::PriceOfBreak();
205 if (aPathPrice < aCurPrice)
206 aCurPrice = aPathPrice;
207 if (aPath.IsComplete() && aPathPrice < aMinPrice) {
208 aMinPrice = aPathPrice;
209 aMinPricedPath = &aPath;
214 // Create new path elements
215 aPathIter = LineConn2d_PathIterator (aPathRoot, TempAlloc());
216 aPathIter.SetDepthLimit (20);
217 while (aPathIter.More()) {
218 LineConn2d_Path& aPath = aPathIter.Value();
220 const Standard_Integer aPrice = aPath.Price();
221 if (aPrice < aMinPrice && aPrice < aCurPrice + aMaxDepth &&
222 !aPath.IsComplete ())
226 if (aPath.ProjectPoint (aProjPnt, _PntTgt)) {
227 // The target is projected on this path. Create a NEW SUB-PATH
228 // IN THE PROJECTION point. If this path does not reach the PntTgt,
229 // it is abandoned (not included).
230 if ((aProjPnt - aPath.Origin()).Modulus() > myTolerance)
231 if (createPath (aPath, aProjPnt, 100))
232 isNewPath = Standard_True;
234 if (aPath.Limitation() >= 0) {
235 // limitation front or right => create the NEW PATH TO THE LEFT
236 if (createPath (aPath, aPath.Extremity(), -1))
237 isNewPath = Standard_True;
239 if (aPath.Limitation() <= 0) {
240 // limitation front or left => create the NEW PATH TO THE RIGHT
241 if (createPath (aPath, aPath.Extremity(), 1))
242 isNewPath = Standard_True;
244 // Create the outline on both sides, find the extrema
245 gp_XY aPathDir = aPath.Direction();
246 NCollection_List<Standard_Real> lstOut (myTempAlloc);
247 for (Standard_Integer iSide = -1; iSide < 2; iSide += 2) {
248 pathOutline (lstOut, aPath, iSide);
249 NCollection_List<Standard_Real>::Iterator anIterOut (lstOut);
250 for (; anIterOut.More(); anIterOut.Next()) {
251 const gp_XY aPnt = aPath.Point (anIterOut.Value());
252 // Check against the point proximity to the path start or end
253 if ((aPnt - aPath.Origin()) * aPathDir > myTolerance * 1.2 &&
254 (aPath.Extremity() - aPnt) * aPathDir > myTolerance * 1.2)
256 if (createPath (aPath, aPnt, iSide))
257 isNewPath = Standard_True;
260 } // end for(.. iSide ..)
262 } // end while (aPathIter)
263 if (isNewPath == Standard_False && aMinPricedPath == 0L) {
264 if (aMaxDepth < anUltimateDepth) {
265 aMaxDepth += aMaxDepthIncr;
266 isNewPath = Standard_True;
270 // Copy the result to the current Connection
271 const LineConn2d_Path * aPath = aMinPricedPath;
273 aConn.ClearSegments();
274 gp_XY aPathPoint = aPath->Extremity();
275 aConn.AddSegment (LineConn2d_Segment (aPathPoint,
276 aPortTgt.Location().XY()));
277 for (; aPath; aPath = &aPath -> Parent()) {
278 aConn.PrependSegment (LineConn2d_Segment (aPath->Origin(), aPathPoint));
279 aPathPoint = aPath->Origin();
282 myTempAlloc.Nullify(); // clear the temporary data storage
284 return Standard_True; // OK
287 //=======================================================================
288 //function : pathOutline
289 //purpose : Find the maximal points on the model outline on the given
290 // side of the current path
291 //=======================================================================
293 void LineConn2d_Model::pathOutline (NCollection_List<Standard_Real>& outList,
294 const LineConn2d_Path thePath,
295 const Standard_Integer theSide)
297 const gp_XY aModelSize = 2 * Box().HSize();
298 const Standard_Real aConf (Precision::Confusion());
299 gp_XY aPntExtr = thePath.Extremity();
300 Standard_Real aRelTol (0.);
302 // Create the box for the transversal band covering the whole length
304 LineConn2d_Box anOutBox;
305 const gp_XY aCenterPath = (thePath.Origin() + aPntExtr) * 0.5;
306 switch (thePath.Orientation()) {
308 anOutBox = LineConn2d_Box (aCenterPath
309 + gp_XY (0., -theSide * aModelSize.Y()),
310 gp_XY (thePath.Delta().X() * 0.5 + aConf,
312 aRelTol = myTolerance / thePath.Delta().X();
315 anOutBox = LineConn2d_Box (aCenterPath
316 + gp_XY (0., theSide * aModelSize.Y()),
317 gp_XY (-thePath.Delta().X() * 0.5 + aConf,
319 aRelTol = -myTolerance / thePath.Delta().X();
322 anOutBox = LineConn2d_Box (aCenterPath
323 + gp_XY (theSide * aModelSize.X(), 0.),
324 gp_XY (aModelSize.X(),
325 thePath.Delta().Y() * 0.5 + aConf));
326 aRelTol = myTolerance / thePath.Delta().Y();
329 anOutBox = LineConn2d_Box (aCenterPath
330 + gp_XY (-theSide * aModelSize.X(), 0.),
331 gp_XY (aModelSize.X(),
332 -thePath.Delta().Y() * 0.5 + aConf));
333 aRelTol = -myTolerance / thePath.Delta().Y();
337 // Create the interval buffer and add there the baseline
338 LineConn2d_IntervalBuffer aZBuffer (myTempAlloc);
339 aZBuffer.Add (LineConn2d_ZInterval (-::RealLast(), 0., 1.));
341 // Select and iterate the boxes for model objects
342 LineConn2d_BoxTreeSelector aSelBox (anOutBox);
343 myTree.Select (aSelBox);
344 NCollection_List<const LineConn2d_Object *>::Iterator
345 aSelBoxIter (aSelBox.GetObjects());
346 for (; aSelBoxIter.More(); aSelBoxIter.Next()) {
347 const LineConn2d_Box& aBox = aSelBoxIter.Value() -> Box();
348 // X[0] - coordinate of box start (normalized and relative to the path)
349 // X[1] - coordinate of box start (normalized and relative to the path)
350 // X[2] - Z-coordinate to be stored in Z-buffer
351 // (nearest to the path is the greatest)
352 Standard_Real anX[3];
353 switch (thePath.Orientation()) {
355 anX[0] = (aBox.Center().X() - aBox.HSize().X()
356 - thePath.Origin().X()) / thePath.Delta().X();
357 anX[1] = (aBox.Center().X() + aBox.HSize().X()
358 - thePath.Origin().X()) / thePath.Delta().X();
359 anX[2] = theSide * aBox.Center().Y() + aBox.HSize().Y();
362 anX[0] = (aBox.Center().Y() - aBox.HSize().Y()
363 - thePath.Origin().Y()) / thePath.Delta().Y();
364 anX[1] = (aBox.Center().Y() + aBox.HSize().Y()
365 - thePath.Origin().Y()) / thePath.Delta().Y();
366 anX[2] = -theSide * aBox.Center().X() + aBox.HSize().X();
369 anX[0] = (aBox.Center().X() + aBox.HSize().X()
370 - thePath.Origin().X()) / thePath.Delta().X();
371 anX[1] = (aBox.Center().X() - aBox.HSize().X()
372 - thePath.Origin().X()) / thePath.Delta().X();
373 anX[2] = -theSide * aBox.Center().Y() + aBox.HSize().Y();
376 anX[0] = (aBox.Center().Y() + aBox.HSize().Y()
377 - thePath.Origin().Y()) / thePath.Delta().Y();
378 anX[1] = (aBox.Center().Y() - aBox.HSize().Y()
379 - thePath.Origin().Y()) / thePath.Delta().Y();
380 anX[2] = theSide * aBox.Center().X() + aBox.HSize().X();
386 if (aRelTol < Precision::Confusion() || anX[1] < anX[0])
387 Standard_ProgramError::Raise (__FILE__);
388 if (anX[0] < 0.) anX[0] = 0.;
389 if (anX[1] > 1.) anX[1] = 1.;
390 if (anX[1] - anX[0] < aRelTol)
393 aZBuffer.Add (LineConn2d_ZInterval (anX[2], anX[0], anX[1]));
394 } // end iteration on the model selected boxes
395 aZBuffer.CheckBuffer();
396 aZBuffer.GetMinima (outList, aRelTol);
399 // if (aFileBuf.open("LineConn2d_Path.trace", ios::out|ios::app))
400 // aZBuffer.Dump (ostream(&aFileBuf), aRelTol);
404 //=======================================================================
405 //function : createPath
407 //=======================================================================
409 Standard_Boolean LineConn2d_Model::createPath
410 (LineConn2d_Path& thePath,
411 const gp_XY& theStart,
412 const Standard_Integer iSide) const
414 // Compute the orientation for the new path, taking into account the Side
415 LineConn2d::Orient anOrient;
416 Standard_Boolean isSearchTerm (Standard_False);
417 if (iSide > -2 && iSide < 2)
418 anOrient = thePath.Orientation (iSide);
420 // the orientation is not on the side, it is directed to the target
421 isSearchTerm = Standard_True;
422 anOrient = LineConn2d::Orientation (_PntTgt - theStart);
425 LineConn2d_Path aNewPath;
426 const Standard_Boolean aResult =
427 LineConn2d_Path::createPath (aNewPath, * this, theStart, anOrient,
431 if (aNewPath.ProjectPoint (aProjPnt, _PntTgt))
432 if ((aProjPnt - _PntTgt).SquareModulus() < Precision::Confusion())
433 aNewPath.SetExtremity (aProjPnt);
436 return Standard_False;
437 // Check that the created path does not intersect the target port
438 // segment; if so, abandon the path.
439 Standard_Real bidAlpha[2];
440 if (_SegTgtPort.IsIntersect (aNewPath, bidAlpha))
441 return Standard_False;
443 thePath.AddBranch (aNewPath, _PntTgt);
446 static FILE * ff = NULL;
448 ff = fopen ("LineConn2d_Path.trace",ff ? "at" : "wt");
450 const gp_XY anExtr = aNewPath.Extremity();
451 const LineConn2d_Path * aPath = &thePath;
452 Standard_Integer aDepth (0);
453 for (; aPath; aPath = &aPath->Parent())
455 const gp_XY anExP = thePath.Extremity();
457 fprintf (ff, "2dprofile pp%d F %.7g %.7g TT %.7g %.7g W # %c%5d\n",
458 ++ccc ,aNewPath.Origin().X(),aNewPath.Origin().Y(),
459 anExtr.X(),anExtr.Y(), aNewPath.IsComplete() ? 'C' : '.',
462 // "=> (%6.1f %6.1f) - (%6.1f %6.1f), Lim %3d, Depth %3d, Price%4d\n",
463 // aNewPath.Origin().X(),aNewPath.Origin().Y(),anExtr.X(),anExtr.Y(),
464 // aNewPath.Limitation(), aDepth, aNewPath.Price());
467 // " [%6.1f %6.1f] - [%6.1f %6.1f], Lim %3d, Price%4d\n",
468 // thePath.Origin().X(), thePath.Origin().Y(), anExP.X(),anExP.Y(),
469 // thePath.Limitation(), thePath.Price());
477 //=======================================================================
478 //function : checkPort
480 //=======================================================================
482 Standard_Boolean LineConn2d_Model::checkPort
483 (const LineConn2d_Port& thePort) const
485 Standard_Boolean aResult (Standard_True);
486 const gp_XY aPnt [2] = {
487 thePort.Location().XY(),
488 thePort.Location().XY() + _PortLen * thePort.Direction().XY()
491 for (Standard_Integer i = 1; i < myObjects.Length(); i++) {
492 const LineConn2d_Object& anObj = myObjects(i);
493 if (&anObj == &thePort.Object()) // skip checking the self
495 if (anObj.IsOut (aPnt[1], myTolerance) == Standard_False) {
496 aResult = Standard_False;