GME  13
ArHelper.cpp
Go to the documentation of this file.
00001 
00002 #include "stdafx.h"
00003 #include <math.h>
00004 #include "ArHelper.h"
00005 
00006 
00007 // --------------------------- CRect && CPoint
00008 
00009 CustomPathData::CustomPathData():
00010         version                                         (CONNECTIONCUSTOMIZATIONDATAVERSION),
00011         aspect                                          (0),
00012         edgeIndex                                       (0),
00013         edgeCount                                       (-1),
00014         type                                            (SimpleEdgeDisplacement),
00015         horizontalOrVerticalEdge        (true),
00016         x                                                       (0),
00017         y                                                       (0)
00018 {
00019 }
00020 
00021 CustomPathData& CustomPathData::operator=(const CustomPathData& other)
00022 {
00023         if (this != &other)
00024         {
00025                 this->version                                   = other.version;
00026                 this->aspect                                    = other.aspect;
00027                 this->edgeIndex                                 = other.edgeIndex;
00028                 this->edgeCount                                 = other.edgeCount;
00029                 this->type                                              = other.type;
00030                 this->horizontalOrVerticalEdge  = other.horizontalOrVerticalEdge;
00031                 this->x                                                 = other.x;
00032                 this->y                                                 = other.y;
00033                 this->l                                                 = other.l;
00034                 this->d                                                 = other.d;
00035         }
00036         return *this;
00037 }
00038 
00039 void CustomPathData::Serialize(CString& outChannel)
00040 {
00041         outChannel.Format(_T("%ld,%ld,%ld,%d,%ld"), GetVersion(), GetAspect(), GetEdgeIndex(),
00042                                                                                         GetEdgeCount(), GetType());
00043         CString additionalDataStr;
00044         additionalDataStr.Format(_T(",%ld,%ld,%ld,%ld"), IsHorizontalOrVertical() ? 1 : 0,
00045                                                                                                  GetX(), GetY(), GetLongDataCount());
00046         outChannel.Append(additionalDataStr);
00047         for(long i = 0; i < GetLongDataCount(); i++) {
00048                 additionalDataStr.Format(_T(",%ld"), l[i]);
00049                 outChannel.Append(additionalDataStr);
00050         }
00051         additionalDataStr.Format(_T(",%ld"), GetDoubleDataCount());
00052         outChannel.Append(additionalDataStr);
00053         for(long i = 0; i < GetDoubleDataCount(); i++) {
00054                 additionalDataStr.Format(_T(",%lf"), d[i]);
00055                 outChannel.Append(additionalDataStr);
00056         }
00057 }
00058 
00059 bool CustomPathData::Deserialize(const CString& inChannel)
00060 {
00061         TRACE(_T("\tResulting token: %s\n"), inChannel);
00062         int curSubPos = 0;
00063         CString versionStr = inChannel.Tokenize(_T(","), curSubPos);
00064         SetVersion(_tcstol(versionStr, NULL, 10));
00065         ASSERT(GetVersion() == CONNECTIONCUSTOMIZATIONDATAVERSION);
00066         if (GetVersion() != CONNECTIONCUSTOMIZATIONDATAVERSION) {
00067                 // TODO: Convert from older version to newer
00068                 return false;
00069         }
00070         CString aspectStr = inChannel.Tokenize(_T(","), curSubPos);
00071         SetAspect(_tcstol(aspectStr, NULL, 10));
00072         CString edgeIndexStr = inChannel.Tokenize(_T(","), curSubPos);
00073         SetEdgeIndex(_tcstol(edgeIndexStr, NULL, 10));
00074         CString edgeCountStr = inChannel.Tokenize(_T(","), curSubPos);
00075         SetEdgeCount(_tcstol(edgeCountStr, NULL, 10));
00076         CString edgeCustomTypeStr = inChannel.Tokenize(_T(","), curSubPos);
00077         SetType((PathCustomizationType)_tcstol(edgeCustomTypeStr, NULL, 10));
00078         TRACE(_T("\tAsp %ld, Ind %ld, Cnt %d, Typ %ld"), GetAspect(), GetEdgeIndex(), GetEdgeCount(), GetType());
00079         CString directionStr = inChannel.Tokenize(_T(","), curSubPos);
00080         SetHorizontalOrVertical(_tcstol(directionStr, NULL, 10) != 0);
00081         CString positionStr = inChannel.Tokenize(_T(","), curSubPos);
00082         SetX(_tcstol(positionStr, NULL, 10));
00083         positionStr = inChannel.Tokenize(_T(","), curSubPos);
00084         SetY(_tcstol(positionStr, NULL, 10));
00085         positionStr = inChannel.Tokenize(_T(","), curSubPos);
00086         long numOfExtraLongData = _tcstol(positionStr, NULL, 10);
00087         ASSERT(numOfExtraLongData >= 0 && numOfExtraLongData <= 4);
00088         TRACE(_T(", Dir %ld, x %ld, y %ld, num %ld"), IsHorizontalOrVertical(), GetX(), GetY(), numOfExtraLongData);
00089         for(long i = 0; i < numOfExtraLongData; i++) {
00090                 positionStr = inChannel.Tokenize(_T(","), curSubPos);
00091                 AddLongData(_tcstol(positionStr, NULL, 10));
00092                 TRACE(_T(", l%ld %ld"), i, l[i]);
00093         }
00094         TRACE(_T("\n"));
00095 
00096         positionStr = inChannel.Tokenize(_T(","), curSubPos);
00097         long numOfExtraDoubleData = _tcstol(positionStr, NULL, 10);
00098         ASSERT(numOfExtraDoubleData >= 0 && numOfExtraDoubleData <= 8);
00099         TRACE(_T(", num %ld"), numOfExtraDoubleData);
00100         for(long i = 0; i < numOfExtraDoubleData; i++) {
00101                 positionStr = inChannel.Tokenize(_T(","), curSubPos);
00102                 AddDoubleData(_ttof(positionStr));
00103                 TRACE(_T(", l%ld %lf"), i, d[i]);
00104         }
00105         TRACE(_T("\n"));
00106         return true;
00107 }
00108 
00109 long CustomPathData::GetVersion(void) const
00110 {
00111         return version;
00112 }
00113 
00114 void CustomPathData::SetVersion(long ver)
00115 {
00116         version = ver;
00117 }
00118 
00119 long CustomPathData::GetAspect(void) const
00120 {
00121         return aspect;
00122 }
00123 
00124 void CustomPathData::SetAspect(long asp)
00125 {
00126         aspect = asp;
00127 }
00128 
00129 long CustomPathData::GetEdgeIndex(void) const
00130 {
00131         return edgeIndex;
00132 }
00133 
00134 void CustomPathData::SetEdgeIndex(long index)
00135 {
00136         edgeIndex = index;
00137 }
00138 
00139 long CustomPathData::GetEdgeCount(void) const
00140 {
00141         return edgeCount;
00142 }
00143 
00144 void CustomPathData::SetEdgeCount(long count)
00145 {
00146         edgeCount = count;
00147 }
00148 
00149 PathCustomizationType CustomPathData::GetType(void) const
00150 {
00151         return type;
00152 }
00153 
00154 void CustomPathData::SetType(PathCustomizationType typ)
00155 {
00156         type = typ;
00157 }
00158 
00159 bool CustomPathData::IsHorizontalOrVertical(void) const
00160 {
00161         return horizontalOrVerticalEdge;
00162 }
00163 
00164 void CustomPathData::SetHorizontalOrVertical(bool parity)
00165 {
00166         horizontalOrVerticalEdge = parity;
00167 }
00168 
00169 long CustomPathData::GetX(void) const
00170 {
00171         return x;
00172 }
00173 
00174 void CustomPathData::SetX(long coord)
00175 {
00176         x = coord;
00177 }
00178 
00179 long CustomPathData::GetY(void) const
00180 {
00181         return y;
00182 }
00183 
00184 void CustomPathData::SetY(long coord)
00185 {
00186         y = coord;
00187 }
00188 
00189 long CustomPathData::GetLongDataCount(void) const
00190 {
00191         return (long)l.size();
00192 }
00193 
00194 long CustomPathData::GetLongData(long index) const
00195 {
00196         return l[index];
00197 }
00198 
00199 void CustomPathData::SetLongData(long index, long dat)
00200 {
00201         l[index] = dat;
00202 }
00203 
00204 void CustomPathData::AddLongData(long dat)
00205 {
00206         l.push_back(dat);
00207 }
00208 
00209 long CustomPathData::GetDoubleDataCount(void) const
00210 {
00211         return (long)d.size();
00212 }
00213 
00214 double CustomPathData::GetDoubleData(long index) const
00215 {
00216         return d[index];
00217 }
00218 
00219 void CustomPathData::SetDoubleData(long index, double dat)
00220 {
00221         d[index] = dat;
00222 }
00223 
00224 void CustomPathData::AddDoubleData(double dat)
00225 {
00226         d.push_back(dat);
00227 }
00228 
00229 
00230 // --------------------------- CRect && CPoint
00231 
00232 
00233 CRect InflatedRect(const CRect& rect, int a)
00234 {
00235         CRect r = rect;
00236         r.InflateRect(a,a); 
00237         return r; 
00238 }
00239 
00240 CRect DeflatedRect(const CRect& rect, int a) 
00241 { 
00242         CRect r = rect; 
00243         r.DeflateRect(a,a); 
00244         return r; 
00245 }
00246 
00247 bool IsPointNear(const CPoint& p1, const CPoint& p2, int nearness)
00248 {
00249         return p2.x - nearness <= p1.x && p1.x <= p2.x + nearness &&
00250                    p2.y - nearness <= p1.y && p1.y <= p2.y + nearness;
00251 }
00252 
00253 bool IsPointIn(const CPoint& point, const CRect& rect, int nearness)
00254 {
00255         CRect tmpR = rect;
00256         tmpR.InflateRect(nearness, nearness);
00257         return tmpR.PtInRect(point) == TRUE;
00258 }
00259 
00260 bool IsRectIn(const CRect& r1, const CRect& r2)
00261 {
00262         return r2.left <= r1.left && r1.right <= r2.right &&
00263                    r2.top <= r1.top && r1.bottom <= r2.bottom;
00264 }
00265 
00266 bool IsRectClip(const CRect& r1, const CRect& r2)
00267 {
00268         CRect rect;
00269         return rect.IntersectRect(&r1, &r2) == TRUE;
00270 }
00271 
00272 bool IsPointNearHLine(const CPoint& p, long x1, long x2, long y, int nearness)
00273 {
00274         ASSERT( x1 <= x2 );
00275 
00276         return x1 - nearness <= p.x && p.x <= x2 + nearness &&
00277                    y - nearness <= p.y && p.y <= y + nearness;
00278 }
00279 
00280 bool IsPointNearVLine(const CPoint& p, long y1, long y2, long x, int nearness)
00281 {
00282         ASSERT( y1 <= y2 );
00283 
00284         return y1 - nearness <= p.y && p.y <= y2 + nearness &&
00285                    x - nearness <= p.x && p.x <= x + nearness;
00286 }
00287 
00288 int DistanceFromHLine(const CPoint& p, long x1, long x2, long y)
00289 {
00290         ASSERT( x1 <= x2 );
00291 
00292         return max(abs(p.y - y), max(x1 - p.x, p.x - x2));
00293 }
00294 
00295 int DistanceFromVLine(const CPoint& p, long y1, long y2, long x)
00296 {
00297         ASSERT( y1 <= y2 );
00298 
00299         return max(abs(p.x - x), max(y1 - p.y, p.y - y2));
00300 }
00301 
00302 double DistanceSquareFromLine(const CPoint& start, const CPoint& end, const CPoint& pt)
00303 {
00304         //     |det(end-start start-pt)|
00305         // d = -------------------------
00306         //            |end-start|
00307         //
00308         double nom = abs((double)(end.x - start.x) * (start.y - pt.y) - (start.x - pt.x) * (end.y - start.y));
00309         double denom_square = (double)((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y));
00310         double d_square = nom * nom / denom_square;
00311         return d_square;
00312 }
00313 
00314 bool IsOnEdge(const CPoint& start, const CPoint& end, const CPoint& pt, int nearness)
00315 {
00316         if (start.x == end.x)                   // vertical edge, horizontal move
00317         {
00318                 if (abs(end.x - pt.x) <= nearness && pt.y <= max(end.y, start.y) + nearness && pt.y >= min(end.y, start.y) - nearness)
00319                         return true;
00320         }
00321         else if (start.y == end.y)      // horizontal line, vertical move
00322         {
00323                 if (abs(end.y - pt.y) <= nearness && pt.x <= max(end.x, start.x) + nearness && pt.x >= min(end.x, start.x) - nearness)
00324                         return true;
00325         }
00326         else
00327         {
00328                 // TODO: consider non-linear edges
00329                 //
00330                 // Is the point close to the edge?
00331                 double d_square = DistanceSquareFromLine(start, end, pt);
00332                 if (d_square <= nearness * nearness) {
00333                         // Check not just if the point is on the line, but if it is on the line segment
00334                         // point = m * start + (1 - m) * end
00335                         //
00336                         // m = (pt + end) / (start + end)
00337                         // 0.0 <= m <= 1.0
00338 
00339                         double m1 = ((double)pt.x - end.x) / (start.x - end.x);
00340                         double m2 = ((double)pt.y - end.y) / (start.y - end.y);
00341                         //ASSERT(abs(m2 - m1) < 2.0e-1);
00342                         if (m1 >= 0.0 && m1 <= 1.0 && m2 >= 0.0 && m2 <= 1.0)
00343                                 return true;
00344                 }
00345         }
00346         return false;
00347 }
00348 
00349 bool IsPointNearLine(const CPoint& point, const CPoint& start, const CPoint& end, int nearness)
00350 {
00351         ASSERT( 0 <= nearness );
00352 
00353         // begin Zolmol
00354         // the routing may create edges that have start==end
00355         // thus confusing this algorithm
00356         if( end.x == start.x && end.y == start.y)
00357                 return false;
00358         // end Zolmol
00359 
00360         CPoint point2 = point;
00361         point2 -= start;
00362         CPoint end2 = end;
00363         end2 -= start;
00364 
00365         double x = end2.x;
00366         double y = end2.y;
00367         double u = point2.x;
00368         double v = point2.y;
00369         double xuyv = x * u + y * v;
00370         double x2y2 = x * x + y * y;
00371 
00372         if(xuyv < 0 || xuyv > x2y2)
00373                 return false;
00374 
00375         double expr1 = (x * v - y * u) ;
00376         expr1 *= expr1;
00377         double expr2 = nearness * nearness * x2y2;
00378 
00379         return expr1 <= expr2;
00380 }
00381 
00382 bool IsLineMeetHLine(const CPoint& start, const CPoint& end, long x1, long x2, long y)
00383 {
00384         ASSERT( x1 <= x2 );
00385 
00386         if( !((start.y <= y && y <= end.y) || (end.y <= y && y <= start.y )) )
00387                 return false;
00388 
00389         CPoint end2 = end;
00390         end2 -= start;
00391         x1 -= start.x;
00392         x2 -= start.x;
00393         y -= start.y;
00394 
00395         if( end2.y == 0 )
00396                 return y == 0 && (( x1 <= 0 && 0 <= x2 ) || (x1 <= end2.x && end2.x <= x2));
00397 
00398         long x = (long)(((float)end2.x) / end2.y) * y;
00399         return x1 <= x && x <= x2;
00400 }
00401 
00402 bool IsLineMeetVLine(const CPoint& start, const CPoint& end, long y1, long y2, long x)
00403 {
00404         ASSERT( y1 <= y2 );
00405 
00406         if( !((start.x <= x && x <= end.x) || (end.x <= x && x <= start.x )) )
00407                 return false;
00408 
00409         CPoint end2 = end;
00410         end2 -= start;
00411         y1 -= start.y;
00412         y2 -= start.y;
00413         x -= start.x;
00414 
00415         if( end2.x == 0 )
00416                 return x == 0 && (( y1 <= 0 && 0 <= y2 ) || (y1 <= end2.y && end2.y <= y2));
00417 
00418         long y = (long)(((float)end2.y) / end2.x) * x;
00419         return y1 <= y && y <= y2;
00420 }
00421 
00422 bool IsLineClipRect(const CPoint& start, const CPoint& end, const CRect& rect)
00423 {
00424         if( rect.PtInRect(start) || rect.PtInRect(end) )
00425                 return true;
00426 
00427         return IsLineMeetHLine(start, end, rect.left, rect.right - 1, rect.top) ||
00428                    IsLineMeetHLine(start, end, rect.left, rect.right - 1, rect.bottom - 1) ||
00429                    IsLineMeetVLine(start, end, rect.top, rect.bottom - 1, rect.left) ||
00430                    IsLineMeetVLine(start, end, rect.top, rect.bottom - 1, rect.right - 1);
00431 }
00432 
00433 bool Intersect(long a1, long a2, long b1, long b2)
00434 {
00435         return min(a1,a2) <= max(b1,b2) && min(b1,b2) <= max(a1,a2);
00436 }
00437 
00438 
00439 // --------------------------- RoutingDirection
00440 
00441 
00442 bool AreInRightAngle(RoutingDirection dir1, RoutingDirection dir2)
00443 {
00444         ASSERT( IsRightAngle(dir1) && IsRightAngle(dir2) );
00445         return IsHorizontal(dir1) == IsVertical(dir2);
00446 }
00447 
00448 RoutingDirection NextClockwiseDir(RoutingDirection dir)
00449 {
00450         if( IsRightAngle(dir) )
00451                 return (RoutingDirection) ((dir+1) % 4);
00452 
00453         return dir;
00454 }
00455 
00456 RoutingDirection PrevClockwiseDir(RoutingDirection dir)
00457 {
00458         if( IsRightAngle(dir) )
00459                 return (RoutingDirection) ((dir+3) % 4);
00460 
00461         return dir;
00462 }
00463 
00464 RoutingDirection ReverseDir(RoutingDirection dir)
00465 {
00466         if( IsRightAngle(dir) )
00467                 return (RoutingDirection) ((dir+2) % 4);
00468 
00469         return dir;
00470 }
00471 
00472 CPoint StepOneInDir(const CPoint& point, RoutingDirection dir)
00473 {
00474         ASSERT( IsRightAngle(dir) );
00475         CPoint p(point);
00476 
00477         switch(dir)
00478         {
00479         case Dir_Top:
00480                 p.y--;
00481                 break;
00482 
00483         case Dir_Right:
00484                 p.x++;
00485                 break;
00486 
00487         case Dir_Bottom:
00488                 p.y++;
00489                 break;
00490 
00491         case Dir_Left:
00492                 p.x--;
00493                 break;
00494         }
00495 
00496         return p;
00497 }
00498 
00499 long& GetRectCoord(CRect& rect, RoutingDirection dir)
00500 {
00501         ASSERT( IsRightAngle(dir) );
00502 
00503         switch( dir )
00504         {
00505         case Dir_Top: 
00506                 return rect.top;
00507 
00508         case Dir_Right:
00509                 return rect.right;
00510 
00511         case Dir_Bottom:
00512                 return rect.bottom;
00513         }
00514 
00515         return rect.left;
00516 }
00517 
00518 long GetRectOuterCoord(const CRect& rect, RoutingDirection dir)
00519 {
00520         ASSERT( IsRightAngle(dir) );
00521 
00522         switch( dir )
00523         {
00524         case Dir_Top: 
00525                 return rect.top-1;
00526 
00527         case Dir_Right:
00528                 return rect.right;
00529 
00530         case Dir_Bottom:
00531                 return rect.bottom;
00532         }
00533 
00534         return rect.left-1;
00535 }
00536 
00537 //      Indexes:
00538 //                               04
00539 //                              1  5
00540 //                              3  7
00541 //                               26
00542 
00543 int GetDirTableIndex(const CSize& offset)
00544 {
00545         return (offset.cx >= 0)*4 + (offset.cy >= 0)*2 + (abs(offset.cx) >= abs(offset.cy));
00546 }
00547 
00548 RoutingDirection majordir_table[] =
00549 {
00550         Dir_Top,
00551         Dir_Left,
00552         Dir_Bottom,
00553         Dir_Left,
00554         Dir_Top,
00555         Dir_Right,
00556         Dir_Bottom,
00557         Dir_Right
00558 };
00559 
00560 RoutingDirection GetMajorDir(const CSize& offset)
00561 {
00562         return majordir_table[GetDirTableIndex(offset)];
00563 }
00564 
00565 RoutingDirection minordir_table[] =
00566 {
00567         Dir_Left,
00568         Dir_Top,
00569         Dir_Left,
00570         Dir_Bottom,
00571         Dir_Right,
00572         Dir_Top,
00573         Dir_Right,
00574         Dir_Bottom
00575 };
00576 
00577 RoutingDirection GetMinorDir(const CSize& offset)
00578 {
00579         return minordir_table[GetDirTableIndex(offset)];
00580 }
00581 
00582 //      FG123
00583 //      E   4
00584 //      D 0 5
00585 //      C   6
00586 //  BA987
00587 
00588 int ExGetDirTableIndex(const CSize& offset)
00589 {
00590         return
00591                 offset.cx > 0 ?
00592                 (
00593                         offset.cy > 0 ?
00594                         (
00595                                 offset.cx > offset.cy ?
00596                                 (
00597                                         6
00598                                 ) :
00599                                 (offset.cx < offset.cy ?
00600                                 (
00601                                         8
00602                                 ) :
00603                                 (
00604                                         7
00605                                 ))
00606                         ) :
00607                         (offset.cy < 0 ?
00608                         (
00609                                 offset.cx > -offset.cy ?
00610                                 (
00611                                         4
00612                                 ) :
00613                                 (offset.cx < -offset.cy ?
00614                                 (
00615                                         2
00616                                 ) :
00617                                 (
00618                                         3
00619                                 ))
00620                         ) :
00621                         (
00622                                 5
00623                         ))
00624                 ) :
00625                 (offset.cx < 0 ?
00626                 (
00627                         offset.cy > 0 ?
00628                         (
00629                                 -offset.cx > offset.cy ?
00630                                 (
00631                                         12
00632                                 ) :
00633                                 (-offset.cx < offset.cy ?
00634                                 (
00635                                         10
00636                                 ) :
00637                                 (
00638                                         11
00639                                 ))
00640                         ) :
00641                         (offset.cy < 0 ?
00642                         (
00643                                 offset.cx < offset.cy ?
00644                                 (
00645                                         14
00646                                 ) :
00647                                 (offset.cx > offset.cy ?
00648                                 (
00649                                         16
00650                                 ) :
00651                                 (
00652                                         15
00653                                 ))
00654                         ) :
00655                         (
00656                                 13
00657                         ))
00658                 ) :
00659                 (
00660                         offset.cy > 0 ?
00661                         (
00662                                 9
00663                         ) :
00664                         (offset.cy < 0 ?
00665                         (
00666                                 1
00667                         ) :
00668                         (
00669                                 0
00670                         ))
00671                 ));
00672 }
00673 
00674 RoutingDirection exmajordir_table[17] =
00675 {
00676         Dir_None,
00677         Dir_Top,
00678         Dir_Top,
00679         Dir_Right,
00680         Dir_Right,
00681         Dir_Right,
00682         Dir_Right,
00683         Dir_Right,
00684         Dir_Bottom,
00685         Dir_Bottom,
00686         Dir_Bottom,
00687         Dir_Left,
00688         Dir_Left,
00689         Dir_Left,
00690         Dir_Left,
00691         Dir_Left,
00692         Dir_Top
00693 };
00694 
00695 RoutingDirection ExGetMajorDir(const CSize& offset)
00696 {
00697         return exmajordir_table[ExGetDirTableIndex(offset)];
00698 }
00699 
00700 RoutingDirection exminordir_table[17] = 
00701 {
00702         Dir_None,
00703         Dir_None,
00704         Dir_Right,
00705         Dir_Top,
00706         Dir_Top,
00707         Dir_None,
00708         Dir_Bottom,
00709         Dir_Bottom,
00710         Dir_Right,
00711         Dir_None,
00712         Dir_Left,
00713         Dir_Bottom,
00714         Dir_Bottom,
00715         Dir_None,
00716         Dir_Top,
00717         Dir_Top,
00718         Dir_Left
00719 };
00720 
00721 RoutingDirection ExGetMinorDir(const CSize& offset)
00722 {
00723         return exminordir_table[ExGetDirTableIndex(offset)];
00724 }
00725 
00726 RoutingDirection GetDir(const CSize& offset, RoutingDirection nodir)
00727 {
00728         if( offset.cx == 0 )
00729         {
00730                 if( offset.cy == 0 )
00731                         return nodir;
00732 
00733                 if( offset.cy < 0 )
00734                         return Dir_Top;
00735 
00736                 return Dir_Bottom;
00737         }
00738 
00739         if( offset.cy == 0 )
00740         {
00741                 if( offset.cx > 0 )
00742                         return Dir_Right;
00743 
00744                 return Dir_Left;
00745         }
00746 
00747         return Dir_Skew;
00748 }
00749 
00750 RoutingDirection GetSkewDir(const CSize& offset, RoutingDirection nodir)
00751 {
00752         if (offset.cx == 0 || abs(offset.cy) > abs(offset.cx))
00753         {
00754                 if (offset.cy == 0)
00755                         return nodir;
00756 
00757                 if (offset.cy < 0)
00758                         return Dir_Top;
00759 
00760                 return Dir_Bottom;
00761         }
00762 
00763         if (offset.cy == 0 || abs(offset.cx) >= abs(offset.cy))
00764         {
00765                 if (offset.cx > 0)
00766                         return Dir_Right;
00767 
00768                 return Dir_Left;
00769         }
00770 
00771         ASSERT(false);
00772         return Dir_Skew;
00773 }
00774 
00775 bool IsPointInDirFrom(const CPoint& point, const CPoint& from, RoutingDirection dir)
00776 {
00777         ASSERT( IsRightAngle(dir) );
00778 
00779         switch( dir )
00780         {
00781         case Dir_Top:
00782                 return point.y <= from.y;
00783 
00784         case Dir_Right:
00785                 return point.x >= from.x;
00786 
00787         case Dir_Bottom:
00788                 return point.y >= from.y;
00789 
00790         case Dir_Left:
00791                 return point.x <= from.x;
00792         }
00793 
00794         return false;
00795 }
00796 
00797 bool IsPointInDirFrom(const CPoint& point, const CRect& rect, RoutingDirection dir)
00798 {
00799         ASSERT( IsRightAngle(dir) );
00800 
00801         switch( dir )
00802         {
00803         case Dir_Top:
00804                 return point.y < rect.top;
00805 
00806         case Dir_Right:
00807                 return point.x >= rect.right;
00808 
00809         case Dir_Bottom:
00810                 return point.y >= rect.bottom;
00811 
00812         case Dir_Left:
00813                 return point.x < rect.left;
00814         }
00815 
00816         return false;
00817 }
00818 
00819 bool IsPointBetweenSides(const CPoint& point, const CRect& rect, bool ishorizontal)
00820 {
00821         if( ishorizontal )
00822                 return rect.top <= point.y && point.y < rect.bottom;
00823 
00824         return rect.left <= point.x && point.x < rect.right;
00825 }
00826 
00827 RoutingDirection PointOnSide(const CPoint& point, const CRect& rect)
00828 {
00829         int dleft = DistanceFromVLine(point, rect.top, rect.bottom, rect.left);
00830         int dtop = DistanceFromHLine(point, rect.left, rect.right, rect.top);
00831         int dright = DistanceFromVLine(point, rect.top, rect.bottom, rect.right);
00832         int dbottom = DistanceFromHLine(point, rect.left, rect.right, rect.bottom);
00833 
00834         if (dleft < 3)
00835                 return Dir_Left;
00836         if (dtop < 3)
00837                 return Dir_Top;
00838         if (dright < 3)
00839                 return Dir_Right;
00840         if (dbottom < 3)
00841                 return Dir_Bottom;
00842 
00843         return GetSkewDir(point - rect.CenterPoint());
00844 }
00845 
00846 bool IsCoordInDirFrom(long coord, long from, RoutingDirection dir)
00847 {
00848         ASSERT( IsRightAngle(dir) );
00849 
00850         if( dir == Dir_Top || dir == Dir_Left )
00851                 return coord <= from;
00852 
00853         return coord >= from;
00854 }
00855 
00856 RoutingDirection OnWhichEdge(const CRect& rect, const CPoint& point)
00857 {
00858         if( point.y == rect.top && rect.left < point.x && point.x < rect.right - 1 )
00859                 return Dir_Top;
00860 
00861         if( point.y == rect.bottom - 1 && rect.left < point.x && point.x < rect.right - 1 )
00862                 return Dir_Bottom;
00863 
00864         if( point.x == rect.left && rect.top < point.y && point.y < rect.bottom - 1 )
00865                 return Dir_Left;
00866 
00867         if( point.x == rect.right - 1 && rect.top < point.y && point.y < rect.bottom - 1 )
00868                 return Dir_Right;
00869 
00870         return Dir_None;
00871 }
00872 
00873 
00874 // --------------------------- CArFindNearestLine
00875 
00876 
00877 bool CArFindNearestLine::HLine(int x1, int x2, int y)
00878 {
00879         ASSERT( x1 <= x2 );
00880 
00881         int d1 = DistanceFromHLine(point, x1, x2, y);
00882         int d2 = abs(point.y - y);
00883 
00884         if( d1 < dist1 || (d1 == dist1 && d2 < dist2) )
00885         {
00886                 dist1 = d1;
00887                 dist2 = d2;
00888                 return true;
00889         }
00890 
00891         return false;
00892 }
00893 
00894 bool CArFindNearestLine::VLine(int y1, int y2, int x)
00895 {
00896         ASSERT( y1 <= y2 );
00897 
00898         int d1 = DistanceFromVLine(point, y1, y2, x);
00899         int d2 = abs(point.x - x);
00900 
00901         if( d1 < dist1 || (d1 == dist1 && d2 < dist2) )
00902         {
00903                 dist1 = d1;
00904                 dist2 = d2;
00905                 return true;
00906         }
00907 
00908         return false;
00909 }
00910 
00911 
00912 // --------------------------- CPointListPath
00913 
00914 
00915 POSITION CPointListPath::GetHeadEdge(CPoint& start, CPoint& end) const
00916 {
00917         if( GetCount() < 2 )
00918                 return NULL;
00919 
00920         POSITION pos = GetHeadPosition();
00921         ASSERT( pos != NULL );
00922 
00923         start = GetNext(pos);
00924         ASSERT( pos != NULL );
00925 
00926         end = GetAt(pos);
00927 
00928         return pos;
00929 }
00930 
00931 POSITION CPointListPath::GetTailEdge(CPoint& start, CPoint& end) const
00932 {
00933         if( GetCount() < 2 )
00934                 return NULL;
00935 
00936         POSITION pos = GetTailPosition();
00937         ASSERT( pos != NULL );
00938 
00939         end = GetPrev(pos);
00940         ASSERT( pos != NULL );
00941 
00942         start = GetAt(pos);
00943 
00944         return pos;
00945 }
00946 
00947 void CPointListPath::GetNextEdge(POSITION& pos, CPoint& start, CPoint& end) const
00948 {
00949 #ifdef _DEBUG
00950         AssertValidPos(pos);
00951 #endif
00952 
00953         GetNext(pos);
00954         ASSERT( pos != NULL );
00955 
00956         POSITION p = pos;
00957         start = GetNext(p);
00958         if( p == NULL )
00959                 pos = NULL;
00960         else
00961                 end = GetAt(p);
00962 }
00963 
00964 void CPointListPath::GetPrevEdge(POSITION& pos, CPoint& start, CPoint& end) const
00965 {
00966 #ifdef _DEBUG
00967         AssertValidPos(pos);
00968 #endif
00969 
00970         end = GetPrev(pos);
00971         if( pos != NULL )
00972                 start = GetAt(pos);
00973 }
00974 
00975 void CPointListPath::GetEdge(POSITION pos, CPoint& start, CPoint& end) const
00976 {
00977 #ifdef _DEBUG
00978         AssertValidPos(pos);
00979 #endif
00980 
00981         start = GetNext(pos);
00982         ASSERT( pos != NULL );
00983 
00984         end = GetAt(pos);
00985 }
00986 
00987 POSITION CPointListPath::GetHeadEdgePtrs(CPoint*& start, CPoint*& end)
00988 {
00989         if( GetCount() < 2 )
00990                 return NULL;
00991 
00992         POSITION pos = GetHeadPosition();
00993         ASSERT( pos != NULL );
00994 
00995         start = &(GetNext(pos));
00996         ASSERT( pos != NULL );
00997 
00998         end = &(GetAt(pos));
00999 
01000         return pos;
01001 }
01002 
01003 POSITION CPointListPath::GetTailEdgePtrs(CPoint*& start, CPoint*& end)
01004 {
01005         if( GetCount() < 2 )
01006                 return NULL;
01007 
01008         POSITION pos = GetTailPosition();
01009         ASSERT( pos != NULL );
01010 
01011         end = &(GetPrev(pos));
01012         ASSERT( pos != NULL );
01013 
01014         start = &(GetAt(pos));
01015 
01016         return pos;
01017 }
01018 
01019 void CPointListPath::GetNextEdgePtrs(POSITION& pos, CPoint*& start, CPoint*& end)
01020 {
01021 #ifdef _DEBUG
01022         AssertValidPos(pos);
01023 #endif
01024 
01025         start = &(GetNext(pos));
01026         if (pos != NULL)
01027                 end = &(GetAt(pos));
01028 }
01029 
01030 void CPointListPath::GetPrevEdgePtrs(POSITION& pos, CPoint*& start, CPoint*& end)
01031 {
01032 #ifdef _DEBUG
01033         AssertValidPos(pos);
01034 #endif
01035 
01036         end = &(GetPrev(pos));
01037         if( pos != NULL )
01038                 start = &(GetAt(pos));
01039 }
01040 
01041 void CPointListPath::GetEdgePtrs(POSITION pos, CPoint*& start, CPoint*& end)
01042 {
01043 #ifdef _DEBUG
01044         AssertValidPos(pos);
01045 #endif
01046 
01047         start = &(GetNext(pos));
01048         ASSERT( pos != NULL );
01049 
01050         end = &(GetAt(pos));
01051 }
01052 
01053 CPoint* CPointListPath::GetStartPoint(POSITION pos)
01054 {
01055 #ifdef _DEBUG
01056         AssertValidPos(pos);
01057 #endif
01058 
01059         return &(GetAt(pos));
01060 }
01061 
01062 CPoint* CPointListPath::GetEndPoint(POSITION pos)
01063 {
01064 #ifdef _DEBUG
01065         AssertValidPos(pos);
01066 #endif
01067 
01068         GetNext(pos);
01069         ASSERT( pos != NULL );
01070 
01071         return &(GetAt(pos));
01072 }
01073 
01074 CPoint* CPointListPath::GetPointBeforeEdge(POSITION pos)
01075 {
01076 #ifdef _DEBUG
01077         AssertValidPos(pos);
01078 #endif
01079 
01080         GetPrev(pos);
01081         if( pos == NULL )
01082                 return NULL;
01083 
01084         return &(GetAt(pos));
01085 }
01086 
01087 CPoint* CPointListPath::GetPointAfterEdge(POSITION pos)
01088 {
01089 #ifdef _DEBUG
01090         AssertValidPos(pos);
01091 #endif
01092 
01093         GetNext(pos);
01094         ASSERT( pos != NULL );
01095 
01096         GetNext(pos);
01097         if( pos == NULL )
01098                 return NULL;
01099 
01100         return &(GetAt(pos));
01101 }
01102 
01103 POSITION CPointListPath::GetEdgePosBeforePoint(POSITION pos) const
01104 {
01105 #ifdef _DEBUG
01106         AssertValidPos(pos);
01107 #endif
01108 
01109         GetPrev(pos);
01110         return pos;
01111 }
01112 
01113 POSITION CPointListPath::GetEdgePosAfterPoint(POSITION pos) const
01114 {
01115 #ifdef _DEBUG
01116         AssertValidPos(pos);
01117 #endif
01118 
01119         POSITION p = pos;
01120         GetNext(p);
01121         if( p == NULL )
01122                 return NULL;
01123 
01124         return pos;
01125 }
01126 
01127 POSITION CPointListPath::GetEdgePosForStartPoint(const CPoint& startpoint)
01128 {
01129         POSITION pos = GetHeadPosition();
01130         while( pos != NULL )
01131         {
01132                 if( GetNext(pos) == startpoint )
01133                 {
01134                         ASSERT( pos != NULL );
01135                         GetPrev(pos);
01136                         break;
01137                 }
01138         }
01139 
01140         ASSERT( pos != NULL );
01141         return pos;
01142 }
01143 
01144 #ifdef _DEBUG
01145 
01146 void CPointListPath::AssertValidPos(POSITION pos) const
01147 {
01148         ASSERT( pos != NULL );
01149 
01150         POSITION p = GetHeadPosition();
01151         for(;;)
01152         {
01153                 ASSERT( p != NULL );
01154                 if( p == pos )
01155                         return;
01156 
01157                 GetNext(p);
01158         }
01159 }
01160 
01161 void CPointListPath::DumpPoints(const CString& msg) const
01162 {
01163         TRACE(msg);
01164         TRACE(_T(", points dump begin:\n"));
01165         POSITION pos = GetHeadPosition();
01166         int i = 0;
01167         while(pos != NULL) {
01168                 CPoint p = GetNext(pos);
01169                 TRACE(_T("%ld.: (%ld, %ld)\n"), i, p.x, p.y);
01170                 i++;
01171         }
01172         TRACE(_T("points dump end.\n"));
01173 }
01174 
01175 #endif