00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "a2dprec.h"
00013
00014 #include <math.h>
00015
00016 #include <stdlib.h>
00017 #include <float.h>
00018
00019 #include "wx/artbase/liner.h"
00020
00021 a2dLine::a2dLine( double x1, double y1, double x2, double y2 )
00022 {
00023 m_AA = 0.0;
00024 m_BB = 0.0;
00025 m_CC = 0.0;
00026
00027 m_a = a2dPoint2D( x1, y1 );
00028 m_b = a2dPoint2D( x2, y2 );
00029
00030 m_valid_parameters = false;
00031 CalculateLineParameters();
00032 }
00033
00034 a2dLine::a2dLine( const a2dPoint2D& a, const a2dPoint2D& b )
00035 {
00036 m_a = a;
00037 m_b = b;
00038 m_valid_parameters = false;
00039 CalculateLineParameters();
00040 }
00041
00042 a2dLine::a2dLine( const a2dLine& other )
00043 {
00044 m_AA = other.m_AA;
00045 m_BB = other.m_BB;
00046 m_CC = other.m_CC;
00047
00048 m_a = other.m_a;
00049 m_b = other.m_b;
00050 m_valid_parameters = other.m_valid_parameters;
00051 CalculateLineParameters();
00052 }
00053
00054 a2dLine::~a2dLine()
00055 {}
00056
00057
00058
00059 a2dLine& a2dLine::operator=( const a2dLine& a_line )
00060 {
00061 m_AA = a_line.m_AA;
00062 m_BB = a_line.m_BB;
00063 m_CC = a_line.m_CC;
00064
00065 m_a = a_line.m_a;
00066 m_b = a_line.m_b;
00067 m_valid_parameters = a_line.m_valid_parameters;
00068 CalculateLineParameters();
00069 return *this;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 int a2dLine::ActionOnTable1( R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint ) const
00089 {
00090
00091 if (
00092 ( Result_beginPoint == R_IN_AREA )
00093 &&
00094 ( Result_endPoint == R_IN_AREA )
00095 )
00096 return 4;
00097
00098 if (
00099 (
00100 ( Result_beginPoint == R_LEFT_SIDE )
00101 &&
00102 ( Result_endPoint == R_LEFT_SIDE )
00103 )
00104 ||
00105 (
00106 ( Result_beginPoint == R_RIGHT_SIDE )
00107 &&
00108 ( Result_endPoint == R_RIGHT_SIDE )
00109 )
00110 )
00111 return 0;
00112
00113 if (
00114 (
00115 ( Result_beginPoint == R_LEFT_SIDE )
00116 &&
00117 (
00118 ( Result_endPoint == R_RIGHT_SIDE )
00119 ||
00120 ( Result_endPoint == R_ON_AREA )
00121 )
00122 )
00123 ||
00124 (
00125 ( Result_beginPoint == R_RIGHT_SIDE )
00126 &&
00127 (
00128 ( Result_endPoint == R_LEFT_SIDE )
00129 ||
00130 ( Result_endPoint == R_ON_AREA )
00131 )
00132 )
00133 ||
00134 (
00135 ( Result_beginPoint == R_ON_AREA )
00136 &&
00137 (
00138 ( Result_endPoint == R_LEFT_SIDE )
00139 ||
00140 ( Result_endPoint == R_RIGHT_SIDE )
00141 ||
00142 ( Result_endPoint == R_ON_AREA )
00143 )
00144 )
00145 )
00146 return 1;
00147
00148 if (
00149 (
00150 ( Result_beginPoint == R_LEFT_SIDE )
00151 ||
00152 ( Result_beginPoint == R_RIGHT_SIDE )
00153 )
00154 &&
00155 ( Result_endPoint == R_IN_AREA )
00156 )
00157 return 2;
00158
00159 if (
00160 ( Result_beginPoint == R_IN_AREA )
00161 &&
00162 (
00163 ( Result_endPoint == R_LEFT_SIDE )
00164 ||
00165 ( Result_endPoint == R_RIGHT_SIDE )
00166 )
00167 )
00168 return 3;
00169
00170 if (
00171 ( Result_beginPoint == R_IN_AREA )
00172 &&
00173 ( Result_endPoint == R_ON_AREA )
00174 )
00175 return 5;
00176
00177 if (
00178 ( Result_beginPoint == R_ON_AREA )
00179 &&
00180 ( Result_endPoint == R_IN_AREA )
00181 )
00182 return 6;
00183
00184 return -1;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204 int a2dLine::ActionOnTable2( R_PointStatus Result_beginPoint, R_PointStatus Result_endPoint ) const
00205 {
00206
00207 if (
00208 ( Result_beginPoint == R_IN_AREA )
00209 &&
00210 ( Result_endPoint == R_IN_AREA )
00211 )
00212 return 4;
00213
00214 if (
00215 (
00216 ( Result_beginPoint == R_LEFT_SIDE )
00217 &&
00218 (
00219 ( Result_endPoint == R_LEFT_SIDE )
00220 ||
00221 ( Result_endPoint == R_ON_AREA )
00222 )
00223 )
00224 ||
00225 (
00226 ( Result_beginPoint == R_RIGHT_SIDE )
00227 &&
00228 (
00229 ( Result_endPoint == R_RIGHT_SIDE )
00230 ||
00231 ( Result_endPoint == R_ON_AREA )
00232 )
00233 )
00234 ||
00235 (
00236 ( Result_beginPoint == R_ON_AREA )
00237 &&
00238 (
00239 ( Result_endPoint == R_LEFT_SIDE )
00240 ||
00241 ( Result_endPoint == R_RIGHT_SIDE )
00242 ||
00243 ( Result_endPoint == R_ON_AREA )
00244 )
00245 )
00246 )
00247 return 0;
00248
00249 if (
00250 (
00251 ( Result_beginPoint == R_LEFT_SIDE )
00252 &&
00253 ( Result_endPoint == R_RIGHT_SIDE )
00254 )
00255 ||
00256 (
00257 ( Result_beginPoint == R_RIGHT_SIDE )
00258 &&
00259 ( Result_endPoint == R_LEFT_SIDE )
00260 )
00261 )
00262 return 1;
00263
00264 if (
00265 (
00266 ( Result_beginPoint == R_LEFT_SIDE )
00267 ||
00268 ( Result_beginPoint == R_RIGHT_SIDE )
00269 ||
00270 ( Result_beginPoint == R_ON_AREA )
00271 )
00272 &&
00273 ( Result_endPoint == R_IN_AREA )
00274 )
00275 return 2;
00276
00277 if (
00278 ( Result_beginPoint == R_IN_AREA )
00279 &&
00280 (
00281 ( Result_endPoint == R_LEFT_SIDE )
00282 ||
00283 ( Result_endPoint == R_RIGHT_SIDE )
00284 ||
00285 ( Result_endPoint == R_ON_AREA )
00286 )
00287 )
00288 return 3;
00289
00290 return -1;
00291 }
00292
00293
00294 double a2dLine::Calculate_Y( double X ) const
00295 {
00296 assert( m_valid_parameters );
00297 if ( m_AA != 0 )
00298 return -( m_AA * X + m_CC ) / m_BB;
00299 else
00300
00301 return m_a.m_y;
00302 }
00303
00304 void a2dLine::Virtual_Point( a2dPoint2D& a_point, double distance ) const
00305 {
00306 assert( m_valid_parameters );
00307
00308
00309
00310
00311 a_point.m_y = a_point.m_y + ( distance * -m_BB );
00312 a_point.m_x = a_point.m_x - ( distance * m_AA );
00313 }
00314
00315 a2dPoint2D a2dLine::DistancePoint( double distance, bool begin ) const
00316 {
00317 assert( m_valid_parameters );
00318 a2dPoint2D a_point;
00319
00320 if ( begin )
00321 {
00322 a_point.m_y = m_a.m_y + ( distance * m_AA );
00323 a_point.m_x = m_a.m_x + ( distance * -m_BB );
00324 }
00325 else
00326 {
00327 a_point.m_y = m_b.m_y + ( distance * m_AA );
00328 a_point.m_x = m_b.m_x + ( distance * -m_BB );
00329 }
00330 return a_point;
00331 }
00332
00333 a2dLine* a2dLine::CreatePerpendicularLineAt( const a2dPoint2D& a_point ) const
00334 {
00335 assert( m_valid_parameters );
00336
00337 double distance = GetLength() * 2;
00338 a2dPoint2D begin, end;
00339
00340 begin.m_y = a_point.m_y + ( distance * -m_BB );
00341 begin.m_x = a_point.m_x - ( distance * m_AA );
00342
00343 end.m_y = a_point.m_y - ( distance * -m_BB );
00344 end.m_x = a_point.m_x + ( distance * m_AA );
00345
00346 return new a2dLine( begin, end );
00347 }
00348
00349 double a2dLine::GetLength() const
00350 {
00351 return sqrt( wxSqr( m_b.m_y - m_a.m_y ) + wxSqr( m_a.m_x - m_b.m_x ) );
00352 }
00353
00354
00355 void a2dLine::CalculateLineParameters()
00356 {
00357
00358 if ( !m_valid_parameters )
00359 {
00360 double length;
00361
00362
00363 if ( m_a == m_b )
00364 {
00365
00366 m_AA = 0;
00367 m_BB = -1e-12;
00368
00369 }
00370 else
00371 {
00372 m_AA = ( m_b.m_y - m_a.m_y );
00373 m_BB = ( m_a.m_x - m_b.m_x );
00374 }
00375
00376
00377 length = sqrt( m_AA * m_AA + m_BB * m_BB );
00378
00379 assert( length != 0 );
00380
00381 m_AA = ( m_AA / length );
00382 m_BB = ( m_BB / length );
00383
00384 m_CC = -( ( m_AA * m_a.m_x ) + ( m_a.m_y * m_BB ) );
00385
00386 m_valid_parameters = true;
00387 }
00388 }
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399 bool a2dLine::CheckIntersect ( a2dLine& lijn, double Marge ) const
00400 {
00401 double distance = 0;
00402
00403
00404 if ( m_a == m_b )
00405 assert ( 0 );
00406
00407 int Take_Action1, Take_Action2;
00408 bool Total_Result = false;
00409 R_PointStatus Result_beginPoint, Result_endPoint;
00410
00411 Result_beginPoint = PointInLine( lijn.m_a, distance, Marge );
00412 Result_endPoint = PointInLine( lijn.m_b, distance, Marge );
00413 Take_Action1 = ActionOnTable1( Result_beginPoint, Result_endPoint );
00414 switch ( Take_Action1 )
00415 {
00416 case 0: Total_Result = false ; break;
00417 case 1:
00418 {
00419 Result_beginPoint = lijn.PointInLine( m_a, distance, Marge );
00420 Result_endPoint = lijn.PointInLine( m_b, distance, Marge );
00421 Take_Action2 = ActionOnTable2( Result_beginPoint, Result_endPoint );
00422 switch ( Take_Action2 )
00423 {
00424 case 0: Total_Result = false; break;
00425 case 1: case 2: case 3: case 4: Total_Result = true; break;
00426 }
00427 }
00428 ; break;
00429 case 2: case 3: case 4: case 5: case 6: Total_Result = true; break;
00430 }
00431 return Total_Result;
00432 }
00433
00434
00435
00436
00437 a2dPoint2D a2dLine::GetBeginPoint() const
00438 {
00439 return m_a;
00440 }
00441
00442
00443
00444
00445
00446 a2dPoint2D a2dLine::GetEndPoint() const
00447 {
00448 return m_b;
00449 }
00450
00451 int a2dLine::Intersect( a2dLine& lijn, a2dPoint2D& c1 , a2dPoint2D& c2 , double Marge ) const
00452 {
00453 double distance = 0;
00454
00455
00456 if ( m_a == m_b )
00457 assert ( 0 );
00458
00459 R_PointStatus Result_beginPoint, Result_endPoint;
00460 int Take_Action1, Take_Action2, Number_of_Crossings = 0;
00461
00462 Result_beginPoint = PointInLine( lijn.m_a, distance, Marge );
00463 Result_endPoint = PointInLine( lijn.m_b, distance, Marge );
00464
00465 Take_Action1 = ActionOnTable1( Result_beginPoint, Result_endPoint );
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 switch ( Take_Action1 )
00476 {
00477 case 2: case 6: c1 = lijn.m_b;
00478 Number_of_Crossings = 1;
00479 break;
00480 case 3: case 5: c1 = lijn.m_a;
00481 Number_of_Crossings = 1;
00482 break;
00483 case 4: c1 = lijn.m_a;
00484 c2 = lijn.m_b;
00485 Number_of_Crossings = 2;
00486 break;
00487 default:
00488 break;
00489 }
00490
00491
00492
00493
00494
00495 switch ( Take_Action1 )
00496 {
00497 case 1: case 5: case 6:
00498 {
00499 Result_beginPoint = lijn.PointInLine( m_a, distance, Marge );
00500 Result_endPoint = lijn.PointInLine( m_b, distance, Marge );
00501 Take_Action2 = ActionOnTable2( Result_beginPoint, Result_endPoint );
00502
00503
00504
00505
00506
00507
00508 switch ( Take_Action2 )
00509 {
00510
00511 case 1:
00512 {
00513 double X, Y, Denominator;
00514 assert( m_valid_parameters );
00515 Denominator = ( m_AA * lijn.m_BB ) - ( lijn.m_AA * m_BB );
00516
00517 assert( Denominator != 0.0 );
00518
00519 X = ( ( m_BB * lijn.m_CC ) - ( lijn.m_BB * m_CC ) ) / Denominator;
00520 Y = ( ( lijn.m_AA * m_CC ) - ( m_AA * lijn.m_CC ) ) / Denominator;
00521
00522 c1.m_x = X;
00523 c1.m_y = Y;
00524 }
00525 Number_of_Crossings++;
00526 break;
00527 case 2: c2 = m_a;
00528 Number_of_Crossings++;
00529 break;
00530 case 3: c2 = m_b;
00531 Number_of_Crossings++;
00532 break;
00533 case 4: c1 = m_a;
00534 c2 = m_b;
00535 Number_of_Crossings = 2;
00536 break;
00537 }
00538 };
00539 break;
00540 default:
00541 break;
00542 }
00543 return Number_of_Crossings;
00544 }
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559 R_PointStatus a2dLine::PointInLine( const a2dPoint2D& a_Point, double& Distance, double Marge ) const
00560 {
00561 Distance = 0;
00562
00563 int Result_ofm_BBox = false;
00564 R_PointStatus Result_of_Online;
00565
00566
00567 if ( a_Point == m_a || a_Point == m_b )
00568 return R_IN_AREA;
00569
00570
00571 if( m_a == m_b )
00572 {
00573 if (
00574 a_Point.m_x >= ( m_a.m_x - Marge ) && a_Point.m_x <= ( m_a.m_x + Marge ) &&
00575 a_Point.m_y >= ( m_a.m_y - Marge ) && a_Point.m_y <= ( m_a.m_y + Marge )
00576 )
00577 return R_IN_AREA;
00578 else
00579 return R_LEFT_SIDE;
00580 }
00581
00582
00583 double xmin = wxMin( m_a.m_x, m_b.m_x );
00584 double xmax = wxMax( m_a.m_x, m_b.m_x );
00585 double ymin = wxMin( m_a.m_y, m_b.m_y );
00586 double ymax = wxMax( m_a.m_y, m_b.m_y );
00587
00588 if ( a_Point.m_x >= ( xmin - Marge ) && a_Point.m_x <= ( xmax + Marge ) &&
00589 a_Point.m_y >= ( ymin - Marge ) && a_Point.m_y <= ( ymax + Marge ) )
00590 Result_ofm_BBox = true;
00591
00592
00593 Result_of_Online = PointOnLine( a_Point, Distance, Marge );
00594
00595
00596 if ( ( Result_ofm_BBox ) && ( Result_of_Online == R_ON_AREA ) )
00597 return R_IN_AREA;
00598 else
00599 return Result_of_Online;
00600 }
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 R_PointStatus a2dLine::PointOnLine( const a2dPoint2D& a_Point, double& Distance, double Marge ) const
00614 {
00615 Distance = 0;
00616
00617 assert( m_a != m_b );
00618
00619
00620 if ( a_Point == m_a || a_Point == m_b )
00621 return R_ON_AREA;
00622
00623 assert( m_valid_parameters );
00624
00625 Distance = ( m_AA * a_Point.m_x ) + ( m_BB * a_Point.m_y ) + m_CC;
00626
00627 if ( Distance < -Marge )
00628 return R_LEFT_SIDE;
00629 else
00630 {
00631 if ( Distance > Marge )
00632 return R_RIGHT_SIDE;
00633 else
00634 return R_ON_AREA;
00635 }
00636 }
00637
00638 a2dPoint2D a2dLine::ProjectedPoint( const a2dPoint2D& p ) const
00639 {
00640 double dx12 = double( m_b.m_x ) - double( m_a.m_x );
00641 double dy12 = double( m_b.m_y ) - double( m_a.m_y );
00642
00643 double dx1p = double( p.m_x ) - double( m_a.m_x );
00644 double dy1p = double( p.m_y ) - double( m_a.m_y );
00645
00646 double length = dx12 * dx12 + dy12 * dy12;
00647 double projection = dx12 * dx1p + dy12 * dy1p;
00648
00649
00650
00651
00652 projection /= length;
00653 return a2dPoint2D( m_a.m_x + projection * dx12, m_a.m_y + projection * dy12 );
00654 }
00655
00656 double a2dLine::PointDistance( const a2dPoint2D& p, a2dPoint2D *nearest ) const
00657 {
00658 double dx12 = double( m_b.m_x ) - double( m_a.m_x );
00659 double dy12 = double( m_b.m_y ) - double( m_a.m_y );
00660
00661 double dx1p = double( p.m_x ) - double( m_a.m_x );
00662 double dy1p = double( p.m_y ) - double( m_a.m_y );
00663
00664 double length = dx12 * dx12 + dy12 * dy12;
00665 double projection = dx12 * dx1p + dy12 * dy1p;
00666
00667 if( projection <= 0 || length == 0 )
00668 {
00669
00670 if( nearest ) * nearest = m_a;
00671 return sqrt( dx1p * dx1p + dy1p * dy1p );
00672 }
00673 else if( projection >= length )
00674 {
00675
00676 if( nearest ) * nearest = m_b;
00677 double dx2p = double( p.m_x ) - double( m_b.m_x );
00678 double dy2p = double( p.m_y ) - double( m_b.m_y );
00679 return sqrt( dx2p * dx2p + dy2p * dy2p );
00680 }
00681 else
00682 {
00683
00684
00685
00686 if( !nearest )
00687 {
00688 if( dx12 == 0 )
00689 return fabs( dx1p );
00690 if( dy12 == 0 )
00691 return fabs( dy1p );
00692 }
00693
00694
00695
00696
00697 projection /= length;
00698 if( nearest ) * nearest = a2dPoint2D( m_a.m_x + projection * dx12, m_a.m_y + projection * dy12 );
00699
00700 dx1p -= projection * dx12;
00701 dy1p -= projection * dy12;
00702 return sqrt( dx1p * dx1p + dy1p * dy1p );
00703 }
00704 }
00705
00706 double a2dLine::PointDistanceOrhto( const a2dPoint2D& p, a2dPoint2D *nearest ) const
00707 {
00708 double dx12 = double( m_b.m_x ) - double( m_a.m_x );
00709 double dy12 = double( m_b.m_y ) - double( m_a.m_y );
00710
00711 double dx1p = double( p.m_x ) - double( m_a.m_x );
00712 double dy1p = double( p.m_y ) - double( m_a.m_y );
00713
00714 if( dx12 == 0 && dy12 == 0 )
00715 {
00716 if( nearest )
00717 * nearest = m_a;
00718 return DBL_MAX;
00719 }
00720 else if( fabs( dx12 ) < fabs( dy12 ) )
00721 {
00722
00723 if( p.m_y < wxMin( m_a.m_y, m_b.m_y ) || p.m_y > wxMax( m_a.m_y, m_b.m_y ) )
00724 {
00725 if( nearest )
00726 * nearest = p;
00727 return DBL_MAX;
00728 }
00729 else
00730 {
00731 double y = p.m_y;
00732 double x = dy1p * dx12 / dy12 + m_a.m_x;
00733 if( nearest )
00734 {
00735 nearest->m_x = x;
00736 nearest->m_y = y;
00737 }
00738 return fabs( p.m_x - x );
00739 }
00740 }
00741 else
00742 {
00743
00744 if( p.m_x < wxMin( m_a.m_x, m_b.m_x ) || p.m_x > wxMax( m_a.m_x, m_b.m_x ) )
00745 {
00746 if( nearest )
00747 * nearest = p;
00748 return DBL_MAX;
00749 }
00750 else
00751 {
00752 double x = p.m_x;
00753 double y = dx1p * dy12 / dx12 + m_a.m_y;
00754 if( nearest )
00755 {
00756 nearest->m_x = x;
00757 nearest->m_y = y;
00758 }
00759 return fabs( p.m_y - y );
00760 }
00761 }
00762 }
00763
00764 void a2dLine::OffsetContour( const a2dLine& nextline, double factor, a2dPoint2D& offsetpoint ) const
00765 {
00766 a2dPoint2D offs_begin( m_a );
00767 a2dPoint2D offs_end( m_b );
00768
00769 a2dPoint2D offs_bgn_next( nextline.m_a );
00770 a2dPoint2D offs_end_next( nextline.m_b );
00771
00772
00773 Virtual_Point( offs_begin, factor );
00774 Virtual_Point( offs_end, factor );
00775 a2dLine offs_currentline( offs_begin, offs_end );
00776
00777 nextline.Virtual_Point( offs_bgn_next, factor );
00778 nextline.Virtual_Point( offs_end_next, factor );
00779 a2dLine offs_nextline( offs_bgn_next, offs_end_next );
00780
00781 offs_nextline.CalculateLineParameters();
00782 offs_currentline.CalculateLineParameters();
00783 offs_currentline.Intersect( offs_nextline, offsetpoint );
00784 }
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 OUTPRODUCT a2dLine::OutProduct( const a2dLine& two, double accur ) const
00795 {
00796 R_PointStatus uitp;
00797 double distance;
00798 if ( two.m_a == two.m_b )
00799 assert( 0 );
00800 if ( m_a == m_b )
00801 assert( 0 );
00802
00803 uitp = PointOnLine( two.m_b, distance, accur );
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813 if ( uitp == R_LEFT_SIDE )
00814 return R_IS_LEFT;
00815 if ( uitp == R_RIGHT_SIDE )
00816 return R_IS_RIGHT;
00817 return R_IS_ON;
00818 }
00819
00820
00821
00822 bool a2dLine::Intersect( a2dLine& lijn, a2dPoint2D& crossing ) const
00823 {
00824
00825 assert( m_valid_parameters );
00826 assert( lijn.m_valid_parameters );
00827
00828 double X, Y, Denominator;
00829 Denominator = ( m_AA * lijn.m_BB ) - ( lijn.m_AA * m_BB );
00830
00831 if ( Denominator == 0.0 )
00832 return false;
00833
00834 X = ( ( m_BB * lijn.m_CC ) - ( lijn.m_BB * m_CC ) ) / Denominator;
00835 Y = ( ( lijn.m_AA * m_CC ) - ( m_AA * lijn.m_CC ) ) / Denominator;
00836
00837 crossing.m_x = X;
00838 crossing.m_y = Y;
00839 return true;
00840 }
00841