00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "a2dprec.h"
00012
00013 #ifdef __BORLANDC__
00014 #pragma hdrstop
00015 #endif
00016
00017 #ifndef WX_PRECOMP
00018 #include "wx/wx.h"
00019 #endif
00020
00021
00022 #include <float.h>
00023 #include "wx/general/gen.h"
00024 #include "wx/general/id.h"
00025 #include "wx/artbase/polyver.h"
00026 #include "wx/artbase/liner.h"
00027 #include "wx/artbase/artglob.h"
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 a2dHit a2dHit::stock_nohit
00091 ( a2dHit::hit_none, a2dHit::stroke1_none, a2dHit::stroke2_none, 0, 0 );
00092 a2dHit a2dHit::stock_fill
00093 ( a2dHit::hit_fill, a2dHit::stroke1_none, a2dHit::stroke2_none, 0, 0 );
00094 a2dHit a2dHit::stock_strokeoutside
00095 ( a2dHit::hit_stroke, a2dHit::stroke1_outside, a2dHit::stroke2_edgeother, 0, 0 );
00096 a2dHit a2dHit::stock_strokeinside
00097 ( a2dHit::hit_stroke, a2dHit::stroke1_inside, a2dHit::stroke2_edgeother, 0, 0 );
00098
00099
00100
00101
00102
00103 double ClclDistSqrPntLine( const a2dPoint2D& p, const a2dPoint2D& p1, const a2dPoint2D& p2 )
00104 {
00105 double dx12 = double( p2.m_x ) - double( p1.m_x );
00106 double dy12 = double( p2.m_y ) - double( p1.m_y );
00107
00108 double dx1p = double( p.m_x ) - double( p1.m_x );
00109 double dy1p = double( p.m_y ) - double( p1.m_y );
00110
00111
00112 double length = dx12 * dx12 + dy12 * dy12;
00113
00114 double projection = dx12 * dx1p + dy12 * dy1p;
00115
00116 if( projection <= 0 || length == 0 )
00117 {
00118
00119 return DBL_MAX;
00120 }
00121 else if( projection >= length )
00122 {
00123
00124
00125
00126 return DBL_MAX;
00127 }
00128 else
00129 {
00130
00131
00132
00133 if( dx12 == 0 )
00134 return dx1p * dx1p;
00135 if( dy12 == 0 )
00136 return dy1p * dy1p;
00137
00138
00139
00140
00141 projection /= length;
00142 dx1p -= projection * dx12;
00143 dy1p -= projection * dy12;
00144 return dx1p*dx1p + dy1p*dy1p;
00145 }
00146 }
00147
00148 A2DARTBASEDLLEXP bool InArc( double angle, double start, double end, bool clockwise )
00149 {
00150
00151
00152
00153
00154
00155 double mr,er;
00156 mr = angle - start;
00157 er = end - start;
00158
00159
00160 if ( mr<0 ) mr += 2.0*M_PI;
00161 if ( er<0 ) er += 2.0*M_PI;
00162 if ( mr>2.0*M_PI ) mr -= 2.0*M_PI;
00163 if ( er>2.0*M_PI ) er -= 2.0*M_PI;
00164
00165
00166 if ( mr < er )
00167 {
00168 if ( clockwise )
00169 return false;
00170 return true;
00171 }
00172 else
00173 {
00174 if ( clockwise )
00175 return true;
00176 return false;
00177 }
00178 }
00179
00180
00181
00182
00183 static void gds_quadratic_spline( a2dVertexList*org, double a1, double b1, double a2, double b2,
00184 double a3, double b3, double a4, double b4, double aber );
00185 static void gds_clear_stack();
00186 static int gds_spline_pop( double *x1, double *y1, double *x2, double *y2, double *x3,
00187 double *y3, double *x4, double *y4 );
00188 static void gds_spline_push( double x1, double y1, double x2, double y2, double x3, double y3,
00189 double x4, double y4 );
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 #ifdef CLASS_MEM_MANAGEMENT
00200 a2dMemManager a2dLineSegment::sm_memManager( wxT( "a2dLineSegment memory manager" ) );
00201 #endif //CLASS_MEM_MANAGEMENT
00202
00203 a2dLineSegment::a2dLineSegment( double x, double y )
00204 {
00205 m_x = x;
00206 m_y = y;
00207 m_arc = false;
00208 m_pntCnt = 1;
00209 m_refcount = 0;
00210 m_segtype = a2dNORMAL_SEG;
00211 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
00212 m_ownerlist = 0;
00213 #endif
00214 }
00215
00216 a2dLineSegment::a2dLineSegment( const a2dPoint2D& point )
00217 {
00218 m_x = point.m_x;
00219 m_y = point.m_y;
00220 m_arc = false;
00221 m_pntCnt = 1;
00222 m_refcount = 0;
00223 m_segtype = a2dNORMAL_SEG;
00224 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
00225 m_ownerlist = 0;
00226 #endif
00227 }
00228
00229 a2dLineSegment::a2dLineSegment( const a2dLineSegment &other )
00230 {
00231 m_x = other.m_x;
00232 m_y = other.m_y;
00233 m_arc = other.m_arc;
00234 m_pntCnt = other.m_pntCnt;
00235 m_refcount = 0;
00236 m_segtype = other.m_segtype;
00237 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
00238 m_ownerlist = 0;
00239 #endif
00240 }
00241
00242 a2dLineSegment::~a2dLineSegment()
00243 {
00244 wxASSERT_MSG( m_refcount == 0, wxT( "deleting a2dLineSegment while referenced" ) );
00245 }
00246
00247 a2dLineSegment* a2dLineSegment::Clone()
00248 {
00249 a2dLineSegment * a = new a2dLineSegment( m_x, m_y );
00250 return a;
00251 }
00252
00253 double a2dLineSegment::Length( const a2dLineSegment& prev )
00254 {
00255 return sqrt( pow( prev.m_x -m_x, 2 ) + pow( prev.m_y - m_y, 2 ) );
00256 }
00257
00258 a2dBoundingBox a2dLineSegment::GetBbox( const a2dLineSegment& prev, const a2dAffineMatrix& WXUNUSED( lworld ) )
00259 {
00260 a2dBoundingBox bbox;
00261 bbox.Expand( prev.m_x, prev.m_y );
00262 bbox.Expand( m_x, m_y );
00263 return bbox;
00264 }
00265
00266 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
00267
00268 void a2dLineSegment::DumpOwners()
00269 {
00270 wxLogDebug( _T( "Owner list (%d) for (a2dLineSegment*)0x%p" ), m_refcount, this );
00271 for( a2dLineSegmentPtr * crnt = m_ownerlist; crnt; crnt = crnt->m_next )
00272 {
00273 if( crnt->m_owner )
00274 {
00275 switch( crnt->m_ownertype )
00276 {
00277 case a2dSmrtPtr<a2dLineSegment>::owner_none:
00278 wxLogDebug( _T( "SmrtPtr @ 0x%p in unknown %p" ), crnt, crnt->m_owner );
00279 break;
00280 case a2dSmrtPtr<a2dLineSegment>::owner_wxobject:
00281 wxLogDebug( _T( "SmrtPtr @ 0x%p in (%s*)0x%p offs=0x%x" ), crnt, ( ( wxObject* )crnt->m_owner )->GetClassInfo()->GetClassName(), crnt->m_owner, ( char* )crnt - ( char* )crnt->m_owner );
00282 break;
00283 case a2dSmrtPtr<a2dLineSegment>::owner_smartpointerlist:
00284 wxLogDebug( _T( "SmrtPtr @ 0x%p in (wxSmrtPtrNode<a2dLineSegment>*)0x%p offs=0x%x" ), crnt, crnt->m_owner, ( char* )crnt - ( char* )crnt->m_owner );
00285 break;
00286 }
00287 }
00288 else
00289 wxLogDebug( _T( "SmrtPtr @ 0x%p in unknown" ), crnt );
00290 }
00291 }
00292
00293 #endif
00294
00295
00296
00297
00298
00299 a2dArcSegment::a2dArcSegment( double x1, double y1, double x2, double y2 )
00300 : a2dLineSegment( x1, y1 )
00301 {
00302 m_arc = true;
00303 m_x2 = x2;
00304 m_y2 = y2;
00305 }
00306
00307 a2dArcSegment::a2dArcSegment( const a2dLineSegment& prev, double xc, double yc, double angle )
00308 : a2dLineSegment( 0, 0 )
00309 {
00310 m_arc = true;
00311
00312 double radius = sqrt( pow( prev.m_x - xc, 2 ) + pow( prev.m_y - yc, 2 ) );
00313
00314 double endrad = atan2( prev.m_y - yc, prev.m_x - xc ) + wxDegToRad( angle );
00315
00316 m_x = xc + radius * cos( endrad );
00317 m_y = yc + radius * sin( endrad );
00318
00319 double midrad = atan2( prev.m_y - yc, prev.m_x - xc ) + wxDegToRad( angle / 2.0 );
00320
00321 m_x2 = xc + radius * cos( midrad );
00322 m_y2 = yc + radius * sin( midrad );
00323 }
00324
00325 a2dArcSegment::a2dArcSegment( const a2dLineSegment& prev, double xc, double yc, double x1, double y1, double x2, double y2 )
00326 : a2dLineSegment( x1, y1 )
00327 {
00328 m_arc = true;
00329
00330 double radius = sqrt( pow( prev.m_x - xc, 2 ) + pow( prev.m_y - yc, 2 ) );
00331
00332 double endrad = atan2( m_y - yc, m_x - xc );
00333
00334 m_x = xc + radius * cos( endrad );
00335 m_y = yc + radius * sin( endrad );
00336
00337 double midrad = atan2( y2 - yc, x2 - xc );
00338
00339 m_x2 = xc + radius * cos( midrad );
00340 m_y2 = yc + radius * sin( midrad );
00341 }
00342
00343 a2dArcSegment::a2dArcSegment( const a2dArcSegment &other ): a2dLineSegment( other )
00344 {
00345 m_x2 = other.m_x2;
00346 m_y2 = other.m_y2;
00347 m_arc = true;
00348 }
00349
00350 a2dArcSegment::~a2dArcSegment()
00351 {}
00352
00353 a2dLineSegment* a2dArcSegment::Clone()
00354 {
00355 a2dArcSegment * a = new a2dArcSegment( m_x, m_y, m_x2, m_y2 );
00356 return a;
00357 }
00358
00359 void a2dArcSegment::SetMidPoint( const a2dLineSegment& prev, double xm, double ym )
00360 {
00361 a2dPoint2D middleOrProj = a2dPoint2D( ( prev.m_x + m_x ) * 0.5, ( prev.m_y + m_y ) * 0.5 );
00362 a2dLine line( prev.m_x, prev.m_y, m_x, m_y );
00363 line.CalculateLineParameters();
00364 a2dLine* middleLine = line.CreatePerpendicularLineAt( middleOrProj );
00365 middleOrProj = a2dPoint2D( xm, ym );
00366 middleOrProj = middleLine->ProjectedPoint( middleOrProj );
00367 delete middleLine;
00368 m_x2 = middleOrProj.m_x;
00369 m_y2 = middleOrProj.m_y;
00370 }
00371
00372 double a2dArcSegment::Length( const a2dLineSegment& prev )
00373 {
00374 double len, radius, center_x, center_y, beginrad, midrad, endrad, phit;
00375
00376 if ( CalcR( prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
00377 {
00378 len = phit * radius;
00379 }
00380 else
00381 len = sqrt( pow( prev.m_x - m_x, 2 ) + pow( prev.m_y - m_y, 2 ) );
00382
00383 return len;
00384 }
00385
00386 void a2dArcSegment::CalcMidPoint( const a2dLineSegment& prev, double center_x, double center_y, double radius, bool clockwise )
00387 {
00388 double start = atan2( prev.m_y - center_y, prev.m_x - center_x );
00389 double end = atan2( m_y - center_y, m_x - center_x );
00390
00391 double b = ( prev.m_x - m_x );
00392 double a = ( prev.m_y - m_y );
00393 double l = sqrt( a * a + b * b );
00394 a /= l; b /= l;
00395
00396 m_x2 = center_x - radius * b;
00397 m_y2 = center_y - radius * a;
00398
00399 double mid = atan2( m_y2 - center_y, m_x2 - center_x );
00400
00401 if ( InArc( mid, start, end, clockwise ) )
00402 return;
00403
00404 m_x2 = center_x + radius * b;
00405 m_y2 = center_y + radius * a;
00406 }
00407
00408 bool a2dArcSegment::CalcR( const a2dLineSegment& prev, double& radius, double& center_x, double& center_y, double& beginrad, double& midrad, double& endrad, double& phit ) const
00409 {
00410 return ::CalcR( prev.m_x, prev.m_y, m_x2, m_y2, m_x, m_y,
00411 radius, center_x, center_y, beginrad, midrad, endrad, phit );
00412 }
00413
00414 double a2dArcSegment::GetOx( const a2dLineSegment& prev ) const
00415 {
00416 double ax, ay, bx, by, cx, cy;
00417 double ax2, ay2, bx2, by2, cx2, cy2;
00418 double d;
00419 bool straight = false;
00420
00421 ax = prev.m_x; ay = prev.m_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
00422 bx = m_x2; by = m_y2; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
00423 cx = m_x; cy = m_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
00424
00425 if ( ax == cx && ay == cy )
00426 {
00427
00428 return (bx + ax) / 2.0;
00429 }
00430 else
00431 {
00432 d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
00433
00434 if ( fabs( d ) < a2dACCUR )
00435 {
00436 d = a2dACCUR;
00437 straight = true;
00438 }
00439
00440 return ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
00441 + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
00442 ) / d;
00443 }
00444 }
00445
00446 double a2dArcSegment::GetOy( const a2dLineSegment& prev ) const
00447 {
00448 double ax, ay, bx, by, cx, cy;
00449 double ax2, ay2, bx2, by2, cx2, cy2;
00450 double d;
00451 bool straight = false;
00452
00453 ax = prev.m_x; ay = prev.m_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
00454 bx = m_x2; by = m_y2; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
00455 cx = m_x; cy = m_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
00456
00457 if ( ax == cx && ay == cy )
00458 {
00459
00460 return (by + ay) / 2.0;
00461 }
00462 else
00463 {
00464 d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
00465
00466 if ( fabs( d ) < a2dACCUR )
00467 {
00468 d = a2dACCUR;
00469 straight = true;
00470 }
00471
00472 return ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
00473 - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
00474 ) / d ;
00475 }
00476 }
00477
00478 a2dPoint2D a2dArcSegment::GetOrigin( const a2dLineSegment& prev ) const
00479 {
00480 double ax, ay, bx, by, cx, cy;
00481 double ax2, ay2, bx2, by2, cx2, cy2;
00482 double d;
00483 bool straight = false;
00484
00485 ax = prev.m_x; ay = prev.m_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
00486 bx = m_x2; by = m_y2; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
00487 cx = m_x; cy = m_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
00488
00489 if ( ax == cx && ay == cy )
00490 {
00491
00492 return a2dPoint2D( (bx + ax) / 2.0, (by + ay) / 2.0 );
00493 }
00494 else
00495 {
00496 d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
00497
00498 if ( fabs( d ) < a2dACCUR )
00499 {
00500 d = a2dACCUR;
00501 straight = true;
00502 }
00503
00504 double x = ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
00505 + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
00506 ) / d;
00507
00508 double y = ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
00509 - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
00510 ) / d ;
00511 return a2dPoint2D( x, y );
00512 }
00513 }
00514
00515 a2dBoundingBox a2dArcSegment::GetBbox( const a2dLineSegment& prev, const a2dAffineMatrix& lworld ) const
00516 {
00517 a2dBoundingBox bbox;
00518 double radius, centerx, centery, start, mid, end, phit;
00519
00520 if ( ! CalcR( prev, radius, centerx, centery, start, mid, end, phit ) )
00521 {
00522 bbox.Expand( prev.m_x, prev.m_y );
00523 bbox.Expand( m_x, m_y );
00524 return bbox;
00525 }
00526
00527 if ( !lworld.IsIdentity() )
00528 {
00529 double alphax = atan2( lworld.GetValue( 1, 0 ), lworld.GetValue( 0, 0 ) );
00530 double alphay = atan2( lworld.GetValue( 1, 1 ), lworld.GetValue( 0, 1 ) );
00531
00532 double x, y;
00533
00534
00535 lworld.TransformPoint( centerx + radius * cos ( start ), centery + radius * sin ( start ), x, y );
00536 bbox.Expand( x, y );
00537
00538 lworld.TransformPoint( centerx + radius * cos ( end ), centery + radius * sin ( end ), x, y );
00539 bbox.Expand( x, y );
00540
00541
00542 if ( InArc( alphax, start, end, phit < 0 ) )
00543 {
00544 lworld.TransformPoint( centerx + radius * cos ( alphax ), centery + radius * sin ( alphax ), x, y );
00545 bbox.Expand( x, y );
00546 }
00547 alphax += wxPI;
00548 if ( InArc( alphax, start, end, phit < 0 ) )
00549 {
00550 lworld.TransformPoint( centerx + radius * cos ( alphax ), centery + radius * sin ( alphax ), x, y );
00551 bbox.Expand( x, y );
00552 }
00553 alphax -= 2 * wxPI;
00554 if ( InArc( alphax, start, end, phit < 0 ) )
00555 {
00556 lworld.TransformPoint( centerx + radius * cos ( alphax ), centery + radius * sin ( alphax ), x, y );
00557 bbox.Expand( x, y );
00558 }
00559 if ( InArc( alphay, start, end, phit < 0 ) )
00560 {
00561 lworld.TransformPoint( centerx + radius * cos ( alphay ), centery + radius * sin ( alphay ), x, y );
00562 bbox.Expand( x, y );
00563 }
00564 alphay += wxPI;
00565 if ( InArc( alphay, start, end, phit < 0 ) )
00566 {
00567 lworld.TransformPoint( centerx + radius * cos ( alphay ), centery + radius * sin ( alphay ), x, y );
00568 bbox.Expand( x, y );
00569 }
00570 alphay -= 2 * wxPI;
00571 if ( InArc( alphay, start, end, phit < 0 ) )
00572 {
00573 lworld.TransformPoint( centerx + radius * cos ( alphay ), centery + radius * sin ( alphay ), x, y );
00574 bbox.Expand( x, y );
00575 }
00576 }
00577 else
00578 {
00579
00580 bbox.Expand( centerx + radius * cos ( start ), centery + radius * sin ( start ) );
00581
00582 bbox.Expand( centerx + radius * cos ( end ), centery + radius * sin ( end ) );
00583
00584
00585 if ( InArc( wxPI, start, end, phit < 0 ) )
00586 bbox.Expand( centerx - radius, centery );
00587 if ( InArc( 1.5 * wxPI, start, end, phit < 0 ) )
00588 bbox.Expand( centerx, centery - radius );
00589 if ( InArc( 0, start, end, phit < 0 ) )
00590 bbox.Expand( centerx + radius, 0 );
00591 if ( InArc( wxPI / 2, start, end, phit < 0 ) )
00592 bbox.Expand( centerx, centery + radius );
00593 }
00594 return bbox;
00595 }
00596
00597
00598
00599
00600
00601 a2dVertexArray::a2dVertexArray()
00602 {}
00603
00604 a2dVertexArray::a2dVertexArray( const a2dVertexArray &other )
00605 {
00606 *this = other;
00607 }
00608
00609 a2dVertexArray::a2dVertexArray( const a2dVertexList &other )
00610 {
00611 clear();
00612 for( a2dVertexList::const_iterator iter = other.begin(); iter != other.end(); ++iter )
00613 {
00614 a2dLineSegmentPtr seg = (*iter)->Clone();
00615 push_back( seg );
00616 }
00617 }
00618
00619 a2dVertexArray::~a2dVertexArray()
00620 {}
00621
00622 void a2dVertexArray::RemoveAt(size_t index)
00623 {
00624 size_t i = 0;
00625 for( a2dVertexArray::iterator iter = begin(); iter != end(); ++iter )
00626 {
00627 if ( i == index )
00628 {
00629 erase( iter );
00630 break;
00631 }
00632 i++;
00633 }
00634 }
00635
00636 void a2dVertexArray::Insert( a2dLineSegment* segment, size_t index )
00637 {
00638 size_t i = 0;
00639 for( a2dVertexArray::iterator iter = begin(); iter != end(); ++iter )
00640 {
00641 if ( i == index )
00642 {
00643 insert( iter, segment );
00644 break;
00645 }
00646 i++;
00647 }
00648 }
00649
00650 a2dVertexArray& a2dVertexArray::operator=( const a2dVertexArray &other )
00651 {
00652 clear();
00653 for( a2dVertexArray::const_iterator iter = other.begin(); iter != other.end(); ++iter )
00654 {
00655 a2dLineSegmentPtr seg = (*iter)->Clone();
00656 push_back( seg );
00657 }
00658
00659 return *this;
00660 }
00661
00662 a2dVertexArray& a2dVertexArray::operator=( const a2dVertexList &other )
00663 {
00664 clear();
00665 for( a2dVertexList::const_iterator iter = other.begin(); iter != other.end(); ++iter )
00666 {
00667 a2dLineSegmentPtr seg = (*iter)->Clone();
00668 push_back( seg );
00669 }
00670 return *this;
00671 }
00672
00673 a2dLineSegmentPtr a2dVertexArray::GetPreviousAround( wxUint32 index ) const
00674 {
00675 if ( index == 0 )
00676 return Item( size() );
00677 return Item( index -1 );
00678 }
00679
00680 a2dLineSegmentPtr a2dVertexArray::GetNextAround( wxUint32 index ) const
00681 {
00682 if ( index == size() )
00683 return Item( 0 );
00684 return Item( index + 1 );
00685 }
00686
00687 bool a2dVertexArray::HasArcs() const
00688 {
00689 unsigned int i;
00690 for ( i = 0; i < size();i++ )
00691 {
00692 if ( Item( i )->GetArc() )
00693 return true;
00694 }
00695 return false;
00696 }
00697
00698 double a2dVertexArray::Length() const
00699 {
00700 double len = 0;
00701 unsigned int i;
00702 for ( i = 1; i < size();i++ )
00703 {
00704 len = len + Item( i )->Length( *(Item( i - 1 )) );
00705 }
00706
00707 return len;
00708 }
00709
00710
00711 void a2dVertexArray::AddPoint( const a2dPoint2D& point, bool atEnd )
00712 {
00713 if ( atEnd )
00714 push_back( new a2dLineSegment( point.m_x, point.m_y ) );
00715 else
00716 insert( begin(), new a2dLineSegment( point.m_x, point.m_y ) );
00717 }
00718
00719 void a2dVertexArray::AddPoint( double x, double y, bool atEnd )
00720 {
00721 if ( atEnd )
00722 push_back( new a2dLineSegment( x, y ) );
00723 else
00724 insert( begin(), new a2dLineSegment( x, y ) );
00725 }
00726
00727 void a2dVertexArray::SetPointAdjustArcs( unsigned int n, double x, double y, bool polygon )
00728 {
00729 Item( n )->m_x = x;
00730 Item( n )->m_y = y;
00731
00732 if ( Item( n )->GetArc() )
00733 {
00734 a2dArcSegment* cseg = ( a2dArcSegment* ) Item( n ).Get();
00735
00736 a2dLineSegmentPtr prev;
00737 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
00738 if ( polygon )
00739 {
00740 prev = Item( ( n - 1 ) % size() );
00741
00742 if ( cseg->CalcR( *prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
00743 cseg->CalcMidPoint( *prev, center_x, center_y, radius, phit < 0 );
00744 }
00745 else
00746 {
00747 if ( n > 1 )
00748 {
00749 prev = Item( n - 1 );
00750 if ( cseg->CalcR( *prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
00751 cseg->CalcMidPoint( *prev, center_x, center_y, radius, phit < 0 );
00752 }
00753 }
00754 }
00755
00756 a2dLineSegmentPtr next;
00757 if ( polygon )
00758 next = Item( ( n + 1 ) % size() );
00759 else
00760 {
00761 if ( n < size() - 1 )
00762 next = Item( n + 1 );
00763 else
00764 return;
00765 }
00766
00767 if ( next->GetArc() )
00768 {
00769 a2dArcSegment* cseg = ( a2dArcSegment* ) next->GetArc();
00770
00771 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
00772
00773 if ( cseg->CalcR( *(Item( n )), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
00774 cseg->CalcMidPoint( *(Item( n )), center_x, center_y, radius, phit < 0 );
00775 }
00776 }
00777
00778 double a2dVertexArray::CalcArea() const
00779 {
00780 if ( size() < 3 )
00781 return 0.0;
00782
00783 double area = 0.0;
00784
00785 a2dVertexArray* workOn = const_cast<a2dVertexArray*>( this );
00786 double miny = workOn->Item(0)->m_y;
00787 bool hasarcs = HasArcs();
00788 if ( hasarcs )
00789 {
00790 workOn = new a2dVertexArray(*this );
00791 workOn->ConvertToLines();
00792 }
00793
00794 a2dLineSegmentPtr seg;
00795 unsigned int i;
00796 for ( i = 0; i < size();i++ )
00797 {
00798 seg = workOn->Item( i );
00799 if ( seg->m_y < miny )
00800 miny = seg->m_y;
00801 }
00802 if ( miny > 0 )
00803 miny=0;
00804
00805 for ( int i=0; i < workOn->size(); i++ )
00806 {
00807 double x = workOn->Item(i)->m_x;
00808 double y = workOn->Item(i)->m_y - miny;
00809 seg = Item( i + 1 != workOn->size() ? i + 1 : 0 );
00810 area += ( seg->m_y - miny ) * x;
00811 area -= seg->m_x * y;
00812 }
00813
00814 if ( hasarcs )
00815 delete workOn;
00816
00817 return fabs(area / 2.0);
00818 }
00819
00820 void a2dVertexArray::Transform( const a2dAffineMatrix& cworld )
00821 {
00822 if ( !cworld.IsIdentity() )
00823 {
00824 if ( !cworld.IsTranslate() )
00825 ConvertToLines();
00826
00827 unsigned int i;
00828 for ( i = 0; i < size();i++ )
00829 {
00830 a2dLineSegmentPtr seg = Item( i );
00831 if ( seg->GetArc() )
00832 {
00833 a2dArcSegment* cseg = (a2dArcSegment*) seg.Get();
00834 cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
00835 }
00836 cworld.TransformPoint( seg->m_x, seg->m_y, seg->m_x, seg->m_y );
00837 }
00838 }
00839 }
00840
00841 a2dBoundingBox a2dVertexArray::GetBbox( const a2dAffineMatrix& lworld )
00842 {
00843 a2dBoundingBox bbox;
00844
00845 double x, y;
00846 lworld.TransformPoint( 0, 0, x, y );
00847 if ( !size() )
00848 bbox.Expand( x, y );
00849 unsigned int i;
00850 for ( i = 0; i < size();i++ )
00851 {
00852 a2dLineSegmentPtr seg = Item( i );
00853 if ( seg->GetArc() )
00854 bbox.Expand( seg->GetBbox( *(Item( i ? i - 1 : 0 )), lworld ) );
00855 else
00856 {
00857 lworld.TransformPoint( seg->m_x, seg->m_y, x, y );
00858 bbox.Expand( x, y );
00859 }
00860 }
00861 return bbox;
00862 }
00863
00864 void a2dVertexArray::ConvertToLines( double aberation )
00865 {
00866 double xw, yw;
00867 a2dLineSegmentPtr segn;
00868
00869 a2dVertexArray::iterator iterp = end();
00870 a2dVertexArray::iterator iter = begin();
00871 while ( iter != end() )
00872 {
00873 a2dLineSegment * seg = *iter;
00874 if ( seg->GetArc() )
00875 {
00876 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
00877
00878 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
00879
00880 if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
00881 {
00882 double dphi;
00883 unsigned int segments;
00884 if ( aberation == 0 )
00885 Aberration( radius/200, phit, radius , dphi, segments );
00886
00887 else
00888 Aberration( aberation, phit, radius , dphi, segments );
00889
00890 double theta = beginrad;
00891 unsigned int step;
00892
00893 for ( step = 0; step < segments + 1; step++ )
00894 {
00895 xw = center_x + radius * cos ( theta );
00896 yw = center_y + radius * sin ( theta );
00897 segn = new a2dLineSegment( xw, yw );
00898
00899 iter = insert( iter, segn );
00900 iter++;
00901 theta = theta + dphi;
00902 }
00903 }
00904 else
00905 {
00906 segn = new a2dLineSegment( cseg->m_x, cseg->m_y );
00907 iter = insert( iter, segn );
00908 iter++;
00909 }
00910
00911 iter--;
00912 iterp = iter;
00913 iter++;
00914 iter = erase( iter );
00915 }
00916 else
00917 {
00918 iterp = iter;
00919 iter++;
00920 }
00921 }
00922 }
00923
00924 a2dVpath* a2dVertexArray::ConvertToVpath( bool arc, bool closed )
00925 {
00926 a2dVpath* vpathsegments = new a2dVpath();
00927
00928 double xw, yw;
00929 unsigned int i;
00930
00931 for ( i = 0; i < size(); i++ )
00932 {
00933 a2dLineSegmentPtr seg = Item( i );
00934 if ( seg->GetArc() )
00935 {
00936 a2dArcSegment* cseg = ( a2dArcSegment* ) seg.Get();
00937 if ( arc )
00938 {
00939 a2dVpathArcSegment* arcseg;
00940 if ( i == 0 )
00941 {
00942 a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y, a2dPATHSEG_MOVETO );
00943 vpathsegments->Add(segn);
00944 arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO );
00945 }
00946 else if ( i == size()-1 )
00947 arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO, closed ? a2dPATHSEG_END_CLOSED: a2dPATHSEG_END_OPEN );
00948 else
00949 arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO );
00950 vpathsegments->Add( arcseg );
00951 }
00952 else
00953 {
00954 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
00955
00956 if ( cseg->CalcR( *(Item( i ? i - 1 : 0 )), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
00957 {
00958 double dphi;
00959 unsigned int segments;
00960 Aberration( radius/200, phit, radius , dphi, segments );
00961
00962
00963 double theta = beginrad;
00964 unsigned int step;
00965
00966 for ( step = 0; step < segments + 1; step++ )
00967 {
00968 xw = center_x + radius * cos ( theta );
00969 yw = center_y + radius * sin ( theta );
00970 a2dVpathSegment* lineseg = new a2dVpathSegment( xw, yw );
00971 vpathsegments->Add( lineseg );
00972 theta = theta + dphi;
00973 }
00974 }
00975 else
00976 {
00977 a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y );
00978 vpathsegments->Add(segn);
00979 }
00980 }
00981 }
00982 else
00983 {
00984 a2dVpathSegment* lineseg;
00985 if ( i == 0 )
00986 lineseg = new a2dVpathSegment( seg->m_x, seg->m_y , a2dPATHSEG_MOVETO );
00987 else if ( i == size()-1 )
00988 lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO, closed ? a2dPATHSEG_END_CLOSED: a2dPATHSEG_END_OPEN );
00989 else
00990 lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO );
00991 vpathsegments->Add(lineseg);
00992 }
00993 }
00994 return vpathsegments;
00995 }
00996
00997 a2dVertexArray* a2dVertexArray::Contour( double distance, a2dPATH_END_TYPE pathtype )
00998 {
00999 a2dVertexArray * converted = new a2dVertexArray();
01000 a2dPoint2D _first;
01001 a2dPoint2D _middle;
01002 a2dPoint2D _end;
01003 a2dPoint2D offsetpointleft;
01004 a2dPoint2D offsetpointright;
01005
01006 unsigned int insertAt = converted->size();
01007 a2dVertexArray::iterator insertHere = end();
01008 unsigned int segments = size();
01009
01010
01011 a2dLineSegmentPtr seg = Item( 0 );
01012 if ( segments == 1 )
01013 {
01014 converted->push_back( new a2dLineSegment( seg->m_x - distance, seg->m_y ) );
01015 switch ( pathtype )
01016 {
01017 case a2dPATH_END_SQAURE:
01018 {
01019
01020 }
01021 break;
01022 case a2dPATH_END_ROUND:
01023 {
01024 converted->push_back( new a2dArcSegment( seg->m_x + distance, seg->m_y, seg->m_x - distance, seg->m_y ) );
01025 }
01026 break;
01027 case a2dPATH_END_SQAURE_EXT:
01028 {
01029
01030 }
01031 break;
01032 default:
01033 break;
01034 }
01035 return converted;
01036 }
01037 else
01038 {
01039
01040 _first = a2dPoint2D( seg->m_x, seg->m_y );
01041 a2dLineSegmentPtr segnext = Item( 1 );
01042 _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
01043 a2dLine line1( _first, _middle );
01044 line1.CalculateLineParameters();
01045 offsetpointleft = _first;
01046 offsetpointright = _first;
01047 line1.Virtual_Point( offsetpointleft, distance );
01048 line1.Virtual_Point( offsetpointright, -distance );
01049
01050 switch ( pathtype )
01051 {
01052 case a2dPATH_END_SQAURE:
01053 {
01054 converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
01055 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01056 }
01057 break;
01058 case a2dPATH_END_ROUND:
01059 {
01060 a2dLine lineoffset( offsetpointright, offsetpointleft );
01061 lineoffset.CalculateLineParameters();
01062 a2dPoint2D offsetpointfirst;
01063
01064 offsetpointfirst = _first;
01065 lineoffset.Virtual_Point( offsetpointfirst, distance );
01066 converted->push_back( new a2dArcSegment( offsetpointleft.m_x, offsetpointleft.m_y,
01067 offsetpointfirst.m_x, offsetpointfirst.m_y ) );
01068 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01069 break;
01070 }
01071 case a2dPATH_END_SQAURE_EXT:
01072 {
01073 a2dLine lineoffset( offsetpointright, offsetpointleft );
01074 lineoffset.CalculateLineParameters();
01075 lineoffset.Virtual_Point( offsetpointleft, distance );
01076 lineoffset.Virtual_Point( offsetpointright, distance );
01077
01078 converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
01079 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01080 break;
01081 }
01082 default:
01083 break;
01084 }
01085
01086 }
01087
01088
01089 unsigned int i;
01090 for ( i = 1; i < segments - 1; i++ )
01091 {
01092 a2dLineSegmentPtr seg = Item( i - 1 );
01093 _first = a2dPoint2D( seg->m_x, seg->m_y );
01094 a2dLineSegmentPtr segnext = Item( i );
01095 _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
01096 a2dLine line1( _first, _middle );
01097 a2dLineSegmentPtr segend = Item( i + 1 );
01098 _end = a2dPoint2D( segend->m_x, segend->m_y );
01099 a2dLine line2( _middle, _end );
01100 line1.CalculateLineParameters();
01101 line2.CalculateLineParameters();
01102
01103 OUTPRODUCT _outproduct;
01104 _outproduct = line1.OutProduct( line2, 1e-9 );
01105
01106 switch ( _outproduct )
01107 {
01108
01109 case R_IS_RIGHT :
01110 {
01111 line1.OffsetContour( line2, distance, offsetpointleft );
01112 line1.OffsetContour( line2, -distance, offsetpointright );
01113 }
01114 break;
01115 case R_IS_LEFT :
01116 {
01117 line1.OffsetContour( line2, distance, offsetpointleft );
01118 line1.OffsetContour( line2, -distance, offsetpointright );
01119 }
01120 break;
01121
01122 case R_IS_ON :
01123 {
01124 offsetpointleft = _middle;
01125 offsetpointright = _middle;
01126 line1.Virtual_Point( offsetpointleft, distance );
01127 line1.Virtual_Point( offsetpointright, -distance );
01128 }
01129 break;
01130 default:
01131 wxFAIL_MSG( wxT( "wrong line code" ) );
01132 break;
01133 }
01134
01135 converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
01136 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01137 }
01138
01139 seg = Item( i - 1 );
01140
01141
01142 _first = a2dPoint2D( seg->m_x, seg->m_y );
01143 a2dLineSegmentPtr segnext = Item( i );
01144 _end = a2dPoint2D( segnext->m_x, segnext->m_y );
01145 a2dLine line1( _first, _end );
01146 line1.CalculateLineParameters();
01147 offsetpointleft = _end;
01148 offsetpointright = _end;
01149 line1.Virtual_Point( offsetpointleft, distance );
01150 line1.Virtual_Point( offsetpointright, -distance );
01151
01152 switch ( pathtype )
01153 {
01154 case a2dPATH_END_SQAURE:
01155 {
01156 converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
01157 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01158 }
01159 break;
01160 case a2dPATH_END_ROUND:
01161 {
01162 a2dLine lineoffset( offsetpointleft, offsetpointright );
01163 lineoffset.CalculateLineParameters();
01164 a2dPoint2D offsetpointend;
01165
01166 offsetpointend = _end;
01167 lineoffset.Virtual_Point( offsetpointend, distance );
01168 converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
01169 converted->push_back( new a2dArcSegment( offsetpointright.m_x, offsetpointright.m_y,
01170 offsetpointend.m_x, offsetpointend.m_y ) );
01171 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01172 break;
01173 }
01174 case a2dPATH_END_SQAURE_EXT:
01175 {
01176 a2dLine lineoffset( offsetpointright, offsetpointleft );
01177 lineoffset.CalculateLineParameters();
01178 lineoffset.Virtual_Point( offsetpointleft, -distance );
01179 lineoffset.Virtual_Point( offsetpointright, -distance );
01180
01181 converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
01182 insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
01183 break;
01184 }
01185 default:
01186 break;
01187 }
01188
01189 return converted;
01190 }
01191
01192 a2dVertexArray* a2dVertexArray::ConvertSplinedPolygon( double Aber ) const
01193 {
01194 a2dVertexList h;
01195 unsigned int i;
01196 for ( i = 0; i < size(); i++ )
01197 {
01198 h.push_back( Item( i )->Clone() );
01199 }
01200
01201
01202 h.ConvertIntoSplinedPolygon( Aber );
01203
01204 unsigned int n = h.size();
01205 a2dVertexArray* spoints = new a2dVertexArray;
01206
01207 a2dVertexList::iterator iter = h.begin();
01208 for ( i = 0; i < n; i++ )
01209 {
01210 spoints->push_back( ( *iter ) );
01211 iter = h.erase( iter );
01212 }
01213
01214 return spoints;
01215 }
01216
01217 a2dVertexArray* a2dVertexArray::ConvertSplinedPolyline( double Aber ) const
01218 {
01219 a2dVertexList h;
01220 unsigned int i;
01221 for ( i = 0; i < size(); i++ )
01222 {
01223 h.push_back( Item( i )->Clone() );
01224 }
01225
01226
01227 h.ConvertIntoSplinedPolyline( Aber );
01228
01229 unsigned int n = h.size();
01230 a2dVertexArray* spoints = new a2dVertexArray;
01231
01232 a2dVertexList::iterator iter = h.begin();
01233 for ( i = 0; i < n; i++ )
01234 {
01235 spoints->push_back( ( *iter )->Clone() );
01236 iter = h.erase( iter );
01237 }
01238 return spoints;
01239 }
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250 a2dHit a2dVertexArray::HitTestPolygon( const a2dPoint2D& ptest, double margin )
01251 {
01252 wxASSERT( margin >= 0 );
01253
01254 a2dPoint2D p1, p2, pm;
01255
01256 double minDistSqrVertex = margin * margin;
01257 double minDistSqrStroke = margin * margin;
01258 bool vertexhit = false;
01259 int intersection_count = 0;
01260 a2dHit rslt;
01261
01262
01263 unsigned int i;
01264 for ( i = 0; i < size(); i++ )
01265 {
01266
01267 p1 = Item( i )->GetPoint();
01268 if ( i == size() - 1 )
01269 p2 = Item( 0 )->GetPoint();
01270 else
01271 p2 = Item( i + 1 )->GetPoint();
01272
01273
01274
01275
01276
01277
01278
01279 double xmin;
01280 double xmax;
01281 int direction;
01282
01283
01284 if( p1.m_x < p2.m_x )
01285 {
01286 xmin = p1.m_x;
01287 xmax = p2.m_x;
01288 direction = 1;
01289 }
01290 else
01291 {
01292 xmin = p2.m_x;
01293 xmax = p1.m_x;
01294 direction = -1;
01295 }
01296
01297 if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
01298 continue;
01299
01300
01301 double ymin;
01302 double ymax;
01303 if( p1.m_y < p2.m_y )
01304 {
01305 ymin = p1.m_y;
01306 ymax = p2.m_y;
01307 }
01308 else
01309 {
01310 ymin = p2.m_y;
01311 ymax = p1.m_y;
01312 }
01313
01314
01315
01316 if( ptest.m_y < ymin - margin )
01317 {
01318
01319
01320
01321 if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
01322 {
01323 intersection_count += direction;
01324 }
01325 }
01326 else if( ptest.m_y <= ymax + margin )
01327 {
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346 double distSqr = ClclDistSqrPntPnt( ptest, p1 );
01347
01348 if( distSqr < minDistSqrVertex )
01349 {
01350 minDistSqrVertex = distSqr;
01351 rslt.m_hit = a2dHit::hit_stroke;
01352 rslt.m_index = i;
01353 rslt.m_stroke2 = a2dHit::stroke2_vertex;
01354 vertexhit = true;
01355 }
01356
01357
01358
01359
01360
01361 pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
01362 distSqr = ClclDistSqrPntPnt( ptest, pm );
01363 if( distSqr < minDistSqrVertex )
01364 {
01365 minDistSqrVertex = distSqr;
01366 rslt.m_hit = a2dHit::hit_stroke;
01367 rslt.m_index = i;
01368 if( p1.m_x == p2.m_x )
01369 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
01370 else if( p1.m_y == p2.m_y )
01371 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
01372 else
01373 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
01374 vertexhit = true;
01375 }
01376
01377
01378
01379
01380
01381
01382
01383 distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
01384
01385 if( distSqr < minDistSqrStroke )
01386 {
01387 minDistSqrStroke = distSqr;
01388 if( !vertexhit )
01389 {
01390 rslt.m_hit = a2dHit::hit_stroke;
01391 rslt.m_index = i;
01392 if( p1.m_x == p2.m_x )
01393 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
01394 else if( p1.m_y == p2.m_y )
01395 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
01396 else
01397 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
01398 }
01399 }
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409 if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
01410 {
01411 if( p1.m_y == p2.m_y )
01412 {
01413 if( ptest.m_y <= p1.m_y )
01414 intersection_count += direction;
01415 }
01416 else
01417 {
01418 double y = ( ptest.m_x - p1.m_x ) * ( p2.m_y - p1.m_y ) / ( p2.m_x - p1.m_x ) + p1.m_y;
01419 if( ptest.m_y <= y )
01420 intersection_count += direction;
01421 }
01422 }
01423 }
01424 }
01425
01426 if( rslt.m_hit == a2dHit::hit_stroke )
01427 {
01428 if( intersection_count )
01429 rslt.m_stroke1 = a2dHit::stroke1_inside;
01430 else
01431 rslt.m_stroke1 = a2dHit::stroke1_outside;
01432
01433 if( vertexhit )
01434 rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
01435 else
01436 rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
01437 }
01438 else
01439 {
01440 if( intersection_count )
01441 rslt.m_hit = a2dHit::hit_fill;
01442 else
01443 rslt.m_hit = a2dHit::hit_none;
01444 }
01445
01446 return rslt;
01447 }
01448
01449 a2dHit a2dVertexArray::HitTestPolyline( const a2dPoint2D& ptest, double margin )
01450 {
01451 wxASSERT( margin >= 0 );
01452
01453 a2dPoint2D p1, p2, pm;
01454
01455 double minDistSqrVertex = margin * margin;
01456 double minDistSqrStroke = margin * margin;
01457 bool vertexhit = false;
01458 bool lastpoint = false;
01459 a2dHit rslt;
01460
01461
01462 unsigned int i;
01463 for ( i = 0; i < size(); i++ )
01464 {
01465
01466 p1 = Item( i )->GetPoint();
01467 if( i < size() - 1 )
01468 p2 = Item( i + 1 )->GetPoint();
01469 else
01470 lastpoint = true;
01471
01472
01473
01474
01475
01476
01477
01478 double xmin;
01479 double xmax;
01480
01481 if( p1.m_x < p2.m_x )
01482 {
01483 xmin = p1.m_x;
01484 xmax = p2.m_x;
01485 }
01486 else
01487 {
01488 xmin = p2.m_x;
01489 xmax = p1.m_x;
01490 }
01491
01492 if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
01493 continue;
01494
01495
01496 double ymin;
01497 double ymax;
01498 if( p1.m_y < p2.m_y )
01499 {
01500 ymin = p1.m_y;
01501 ymax = p2.m_y;
01502 }
01503 else
01504 {
01505 ymin = p2.m_y;
01506 ymax = p1.m_y;
01507 }
01508
01509 if( ptest.m_y < ymin - margin || ptest.m_y > ymax + margin )
01510 continue;
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530 double distSqr = ClclDistSqrPntPnt( ptest, p1 );
01531
01532 if( distSqr < minDistSqrVertex )
01533 {
01534 minDistSqrVertex = distSqr;
01535 rslt.m_hit = a2dHit::hit_stroke;
01536 rslt.m_index = i;
01537 rslt.m_stroke2 = a2dHit::stroke2_vertex;
01538 vertexhit = true;
01539 }
01540
01541 if( lastpoint )
01542 break;
01543
01544
01545
01546
01547
01548 pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
01549 distSqr = ClclDistSqrPntPnt( ptest, pm );
01550 if( distSqr < minDistSqrVertex )
01551 {
01552 minDistSqrVertex = distSqr;
01553 rslt.m_hit = a2dHit::hit_stroke;
01554 rslt.m_index = i;
01555 if( p1.m_x == p2.m_x )
01556 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
01557 else if( p1.m_y == p2.m_y )
01558 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
01559 else
01560 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
01561 vertexhit = true;
01562 }
01563
01564
01565
01566
01567
01568
01569
01570 distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
01571
01572 if( distSqr < minDistSqrStroke )
01573 {
01574 minDistSqrStroke = distSqr;
01575 if( !vertexhit )
01576 {
01577 rslt.m_hit = a2dHit::hit_stroke;
01578 rslt.m_index = i;
01579 if( p1.m_x == p2.m_x )
01580 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
01581 else if( p1.m_y == p2.m_y )
01582 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
01583 else
01584 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
01585 }
01586 }
01587 }
01588
01589 if( rslt.m_hit == a2dHit::hit_stroke )
01590 {
01591 rslt.m_stroke1 = a2dHit::stroke1_outside;
01592 if( vertexhit )
01593 rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
01594 else
01595 rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
01596 }
01597
01598 return rslt;
01599 }
01600
01601 bool a2dVertexArray::RemoveRedundant( bool polygon )
01602 {
01603 bool did = false;
01604 a2dLineSegmentPtr segprev = NULL;
01605 a2dLineSegmentPtr seg = NULL;
01606 unsigned int i;
01607 for ( i = 0; i < size(); i++ )
01608 {
01609 seg = Item( i );
01610 if ( !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
01611 {
01612 RemoveAt( i );
01613 i--;
01614 did = true;
01615 }
01616 else
01617 segprev = seg;
01618 }
01619 seg = Item( 0 );
01620 if ( polygon && !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
01621 {
01622 RemoveAt( size()-1 );
01623 did = true;
01624 }
01625 return did;
01626 }
01627
01628 a2dVertexList* a2dVertexArray::GetRedundant( bool polygon, double smallest )
01629
01630 {
01631 a2dVertexList* redunDant = new a2dVertexList();
01632 a2dLineSegmentPtr segprev = NULL;
01633 a2dLineSegmentPtr seg = NULL;
01634 unsigned int i;
01635 for ( i = 0; i < size(); i++ )
01636 {
01637 seg = Item( i );
01638 if ( !seg->GetArc() && segprev &&
01639 ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
01640
01641 {
01642 redunDant->push_back( seg->Clone() );
01643 }
01644 segprev = seg;
01645 }
01646 seg = Item( 0 );
01647 if ( polygon && !seg->GetArc() && segprev &&
01648 ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
01649
01650 redunDant->push_back( seg->Clone() );
01651
01652 if ( redunDant->empty() )
01653 {
01654 delete redunDant;
01655 redunDant = NULL;
01656 }
01657 return redunDant;
01658 }
01659
01660
01661
01662
01663
01664
01665 a2dVertexList::a2dVertexList()
01666 {
01667 m_refcount = 0;
01668 }
01669
01670 a2dVertexList::a2dVertexList( const a2dVertexList &other )
01671 {
01672 m_refcount = 0;
01673 *this = other;
01674 }
01675
01676 a2dVertexList::a2dVertexList( const a2dVertexArray &other )
01677 {
01678 m_refcount = 0;
01679 clear();
01680 for( a2dVertexArray::const_iterator iter = other.begin(); iter != other.end(); ++iter )
01681 {
01682 a2dLineSegmentPtr seg = ( *iter )->Clone();
01683 push_back( seg );
01684 }
01685 }
01686
01687 a2dVertexList::~a2dVertexList()
01688 {
01689 wxASSERT_MSG( m_refcount == 0, wxT( "deleting a2dLineSegment while referenced" ) );
01690 clear();
01691 }
01692
01693 a2dVertexList& a2dVertexList::operator=( const a2dVertexList &other )
01694 {
01695 clear();
01696
01697 for( a2dVertexList::const_iterator iter = other.begin(); iter != other.end(); ++iter )
01698 {
01699 a2dLineSegment* seg = ( *iter )->Clone();
01700 push_back( seg );
01701 }
01702
01703 return *this;
01704 }
01705
01706 a2dVertexList& a2dVertexList::operator=( const a2dVertexArray &other )
01707 {
01708 clear();
01709 for( a2dVertexArray::const_iterator iter = other.begin(); iter != other.end(); ++iter )
01710 {
01711 a2dLineSegment* seg = ( *iter )->Clone();
01712 push_back( seg );
01713 }
01714 return *this;
01715 }
01716
01717 a2dVertexList::iterator a2dVertexList::GetPreviousAround( a2dVertexList::iterator iter )
01718 {
01719 if ( iter == begin() )
01720 return --end();
01721 return --iter;
01722 }
01723
01724 a2dVertexList::iterator a2dVertexList::GetNextAround( a2dVertexList::iterator iter )
01725 {
01726 if ( iter == --end() )
01727 return begin();
01728 return ++iter;
01729 }
01730
01731 a2dVertexList::const_iterator a2dVertexList::GetPreviousAround( a2dVertexList::const_iterator iter ) const
01732 {
01733 if ( iter == begin() )
01734 return --end();
01735 return --iter;
01736 }
01737
01738 a2dVertexList::const_iterator a2dVertexList::GetNextAround( a2dVertexList::const_iterator iter ) const
01739 {
01740 if ( iter == --end() )
01741 return begin();
01742 return ++iter;
01743 }
01744
01745 void a2dVertexList::MakeBegin( a2dVertexList::iterator iter )
01746 {
01747 a2dVertexList::iterator iterr = begin();
01748 while( iterr != iter )
01749 {
01750 a2dLineSegmentPtr seg = *iterr;
01751 ++iterr;
01752 pop_front();
01753 push_back( seg );
01754 }
01755 }
01756
01757 bool a2dVertexList::HasArcs() const
01758 {
01759 for( a2dVertexList::const_iterator iter = begin(); iter != end(); ++iter )
01760 {
01761 a2dLineSegment* seg = *iter;
01762 if ( seg->GetArc() )
01763 return true;
01764 }
01765 return false;
01766 }
01767
01768 double a2dVertexList::Length()
01769 {
01770 double len = 0;
01771
01772 a2dVertexList::iterator iterp = begin();
01773 a2dVertexList::iterator iter = ++iterp;
01774 while ( iter != end() )
01775 {
01776 len = len + ( *iter )->Length( *( *iterp ) );
01777 iterp = iter++;
01778 }
01779
01780 return len;
01781 }
01782
01783 int a2dVertexList::IndexOf( a2dLineSegment* object ) const
01784 {
01785 int i = 0;
01786 for( a2dVertexList::const_iterator iter = begin(); iter != end(); ++iter )
01787 {
01788 if( *iter == object )
01789 return i;
01790 i++;
01791 }
01792 return -1;
01793 }
01794
01795 void a2dVertexList::Insert( unsigned int index, a2dLineSegmentPtr segin )
01796 {
01797 int i = 0;
01798 a2dVertexList::iterator iter;
01799 for( iter = begin(); iter != end(); ++iter )
01800 {
01801 if( i == index )
01802 {
01803 insert( iter, segin );
01804 break;
01805 }
01806 i++;
01807 }
01808 if( iter == end() && i == index )
01809 insert( iter, segin );
01810 wxASSERT_MSG( i <= size() , wxT( "index higher than list size" ) );
01811 }
01812
01813 void a2dVertexList::AddPoint( const a2dPoint2D& point, bool atEnd )
01814 {
01815 if ( atEnd )
01816 push_back( new a2dLineSegment( point.m_x, point.m_y ) );
01817 else
01818 push_front( new a2dLineSegment( point.m_x, point.m_y ) );
01819 }
01820
01821 void a2dVertexList::AddPoint( double x, double y, bool atEnd )
01822 {
01823 if ( atEnd )
01824 push_back( new a2dLineSegment( x, y ) );
01825 else
01826 push_front( new a2dLineSegment( x, y ) );
01827 }
01828
01829 void a2dVertexList::SetPointAdjustArcs( a2dLineSegmentPtr segin, double x, double y, bool polygon )
01830 {
01831 a2dVertexList::iterator iter = begin();
01832 a2dVertexList::iterator prev = end();
01833 prev--;
01834 a2dLineSegment* seg;
01835 while ( iter != end() )
01836 {
01837 seg = *iter;
01838 if ( seg == segin )
01839 {
01840 seg->m_x = x;
01841 seg->m_y = y;
01842
01843 if ( seg->GetArc() )
01844 {
01845 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
01846 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01847 if ( prev != end() )
01848 {
01849 if ( cseg->CalcR( *( *prev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01850 cseg->CalcMidPoint( *( *prev ), center_x, center_y, radius, phit < 0 );
01851 }
01852 }
01853
01854 a2dVertexList::iterator next = iter;
01855 next++;
01856 if ( next == end() && polygon )
01857 next = begin();
01858
01859 if ( next != end() && ( *next )->GetArc() )
01860 {
01861 a2dArcSegment * cseg = ( a2dArcSegment* ) ( *next ).Get();
01862 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01863
01864 if ( cseg->CalcR( *( *iter ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01865 cseg->CalcMidPoint( *( *iter ), center_x, center_y, radius, phit < 0 );
01866 }
01867 break;
01868 }
01869 prev = iter;
01870 iter++;
01871 }
01872 }
01873
01874 void a2dVertexList::SetPointAdjustArcs( unsigned int n, double x, double y, bool polygon )
01875 {
01876 unsigned int i;
01877
01878 a2dVertexList::iterator iter = begin();
01879 a2dVertexList::iterator prev = end();
01880 prev--;
01881 a2dLineSegment* seg;
01882 i = 0;
01883 while ( iter != end() )
01884 {
01885 seg = *iter;
01886 if ( i == n )
01887 {
01888 seg->m_x = x;
01889 seg->m_y = y;
01890
01891 if ( seg->GetArc() )
01892 {
01893 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
01894 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01895 if ( prev != end() )
01896 {
01897 if ( cseg->CalcR( *( *prev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01898 cseg->CalcMidPoint( *( *prev ), center_x, center_y, radius, phit < 0 );
01899 }
01900 }
01901
01902 a2dVertexList::iterator next = iter;
01903 next++;
01904 if ( next == end() && polygon )
01905 next = begin();
01906
01907 if ( next != end() && ( *next )->GetArc() )
01908 {
01909 a2dArcSegment * cseg = ( a2dArcSegment* ) ( *next ).Get();
01910 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01911
01912 if ( cseg->CalcR( *( *iter ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01913 cseg->CalcMidPoint( *( *iter ), center_x, center_y, radius, phit < 0 );
01914 }
01915 break;
01916 }
01917 i++;
01918 prev = iter;
01919 iter++;
01920 }
01921 }
01922
01923 void a2dVertexList::Transform( const a2dAffineMatrix& cworld )
01924 {
01925 if ( !cworld.IsIdentity() )
01926 {
01927 if ( !cworld.IsTranslate() )
01928 ConvertToLines();
01929
01930 for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter )
01931 {
01932 a2dLineSegment* seg = *iter;
01933 if ( seg->GetArc() )
01934 {
01935 a2dArcSegment* cseg = (a2dArcSegment*) seg;
01936 cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
01937 }
01938 cworld.TransformPoint( seg->m_x, seg->m_y, seg->m_x, seg->m_y );
01939 }
01940 }
01941 }
01942
01943 void a2dVertexList::ConvertToLines( double aberation )
01944 {
01945 double xw, yw;
01946 a2dLineSegment* segn;
01947
01948 a2dVertexList::iterator iterp = end();
01949 a2dVertexList::iterator iter = begin();
01950 while ( iter != end() )
01951 {
01952 a2dLineSegment * seg = *iter;
01953 if ( seg->GetArc() )
01954 {
01955 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
01956
01957 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
01958
01959 if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
01960 {
01961 double dphi;
01962 unsigned int segments;
01963 if ( aberation == 0 )
01964 Aberration( radius/200, phit, radius , dphi, segments );
01965
01966 else
01967 Aberration( aberation, phit, radius , dphi, segments );
01968
01969 double theta = beginrad;
01970 unsigned int step;
01971
01972 for ( step = 0; step < segments + 1; step++ )
01973 {
01974 xw = center_x + radius * cos ( theta );
01975 yw = center_y + radius * sin ( theta );
01976 segn = new a2dLineSegment( xw, yw );
01977
01978 iter = insert( iter, segn );
01979 iter++;
01980 theta = theta + dphi;
01981 }
01982 }
01983 else
01984 {
01985 segn = new a2dLineSegment( cseg->m_x, cseg->m_y );
01986 iter = insert( iter, segn );
01987 iter++;
01988 }
01989
01990 iter--;
01991 iterp = iter;
01992 iter++;
01993 iter = erase( iter );
01994 }
01995 else
01996 {
01997 iterp = iter;
01998 iter++;
01999 }
02000 }
02001 }
02002
02003 void a2dVertexList::ConvertToLines( double dphi, int minseg )
02004 {
02005
02006 dphi = dphi* M_PI/180.0;
02007
02008 double xw, yw;
02009 a2dLineSegment* segn;
02010
02011 a2dVertexList::iterator iterp = end();
02012 a2dVertexList::iterator iter = begin();
02013 while ( iter != end() )
02014 {
02015 a2dLineSegment * seg = *iter;
02016 if ( seg->GetArc() )
02017 {
02018 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
02019
02020 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
02021 if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
02022 {
02023 unsigned int segments;
02024 segments = (unsigned int) ( ceil(phit/dphi) < minseg ? minseg : ceil(phit/dphi) );
02025
02026 dphi=phit/(segments);
02027 if (midrad > endrad) dphi=-dphi;
02028
02029 double theta = beginrad;
02030 unsigned int step;
02031
02032 for ( step = 0; step < segments + 1; step++ )
02033 {
02034 xw = center_x + radius * cos ( theta );
02035 yw = center_y + radius * sin ( theta );
02036 segn = new a2dLineSegment( xw, yw );
02037
02038 iter = insert( iterp, segn );
02039 iter++;
02040 theta = theta + dphi;
02041 }
02042 }
02043 else
02044 {
02045 segn = new a2dLineSegment( cseg->m_x, cseg->m_y );
02046 iter = insert( iterp, segn );
02047 iter++;
02048 }
02049
02050 iter--;
02051 iterp = iter;
02052 iter++;
02053 iter = erase( iter );
02054 }
02055 else
02056 {
02057 iterp = iter;
02058 iter++;
02059 }
02060 }
02061 }
02062
02063 a2dVpath* a2dVertexList::ConvertToVpath( bool arc, bool closed )
02064 {
02065 a2dVpath* vpathsegments = new a2dVpath();
02066
02067 double xw, yw;
02068
02069 a2dVertexList::iterator iterp = end();
02070 a2dVertexList::iterator iter = begin();
02071 while ( iter != end() )
02072 {
02073 a2dLineSegment * seg = *iter;
02074 if ( seg->GetArc() )
02075 {
02076 a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
02077 if ( arc )
02078 {
02079 a2dVpathArcSegment* arcseg;
02080 a2dVertexList::iterator iternext = iter;
02081 iternext++;
02082 if ( iter == begin() )
02083 {
02084 a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y, a2dPATHSEG_MOVETO );
02085 vpathsegments->Add(segn);
02086 arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_MOVETO );
02087 }
02088 else if ( iternext == end() )
02089 arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO, closed ? a2dPATHSEG_END_CLOSED: a2dPATHSEG_END_OPEN );
02090 else
02091 arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO );
02092 vpathsegments->Add( arcseg );
02093 }
02094 else
02095 {
02096 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
02097
02098 if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
02099 {
02100 double dphi;
02101 unsigned int segments;
02102 Aberration( radius/200, phit, radius , dphi, segments );
02103
02104
02105 double theta = beginrad;
02106 unsigned int step;
02107
02108 for ( step = 0; step < segments + 1; step++ )
02109 {
02110 xw = center_x + radius * cos ( theta );
02111 yw = center_y + radius * sin ( theta );
02112 a2dVpathSegment* lineseg = new a2dVpathSegment( xw, yw );
02113 vpathsegments->Add( lineseg );
02114 theta = theta + dphi;
02115 }
02116 }
02117 else
02118 {
02119 a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y );
02120 vpathsegments->Add(segn);
02121 }
02122 }
02123 }
02124 else
02125 {
02126 a2dVpathSegment* lineseg;
02127 a2dVertexList::iterator iternext = iter;
02128 iternext++;
02129 if ( iter == begin() )
02130 lineseg = new a2dVpathSegment( seg->m_x, seg->m_y , a2dPATHSEG_MOVETO );
02131 else if ( iternext == end() )
02132 lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO, closed ? a2dPATHSEG_END_CLOSED: a2dPATHSEG_END_OPEN );
02133 else
02134 lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO );
02135 vpathsegments->Add(lineseg);
02136 }
02137
02138 iterp = iter;
02139 iter++;
02140 }
02141 return vpathsegments;
02142 }
02143
02144
02145 double a2dVertexList::CalcArea() const
02146 {
02147 if ( size() < 3 )
02148 return 0.0;
02149
02150 double area = 0.0;
02151
02152 a2dVertexList* workOn = const_cast<a2dVertexList*>( this );
02153 double miny = (*workOn->begin())->m_y;
02154 bool hasarcs = HasArcs();
02155 if ( hasarcs )
02156 {
02157 workOn = new a2dVertexList(*this );
02158 workOn->ConvertToLines( 10, 3 );
02159 }
02160
02161 a2dVertexList::const_iterator iter;
02162 for( iter = workOn->begin(); iter != workOn->end(); ++iter )
02163 {
02164 a2dLineSegment* seg = *iter;
02165 if ( seg->m_y < miny )
02166 miny = seg->m_y;
02167 }
02168 if ( miny > 0 )
02169 miny=0;
02170
02171 iter = workOn->begin();
02172 for ( int i=0; i <= workOn->size(); i++ )
02173 {
02174 double x = (*iter)->m_x;
02175 double y = (*iter)->m_y - miny;
02176 iter = workOn->GetNextAround( iter );
02177 area += ( (*iter)->m_y - miny ) * x;
02178 area -= (*iter)->m_x * y;
02179 }
02180
02181 if ( hasarcs )
02182 delete workOn;
02183
02184 return fabs(area / 2.0);
02185 }
02186
02187 bool a2dVertexList::DirectionIsClockWise()
02188 {
02189 return (bool)(CalcArea()< 0.0);
02190 }
02191
02192 void a2dVertexList::InsertArc( a2dVertexList::iterator& iter, int n, double center_x, double center_y )
02193 {
02194 a2dPoint2D begin_p,middle_p;
02195 int middlepoint,i;
02196
02197 middlepoint= n/2;
02198
02199
02200 begin_p.m_x = (*iter)->m_x;
02201 begin_p.m_y = (*iter)->m_y;
02202
02203
02204 iter = GetNextAround( iter );
02205
02206
02207 for (i=1;i<middlepoint-1;i++)
02208 iter = erase( iter );
02209
02210 middle_p.m_x = (*iter)->m_x;
02211 middle_p.m_y = (*iter)->m_y;
02212
02213 for ( i = middlepoint; i<n; i++ )
02214 iter = erase( iter );
02215
02216 if ( (*iter)->m_x == begin_p.m_x && (*iter)->m_y == begin_p.m_y )
02217 {
02218 double dx = center_x - begin_p.m_x;
02219 double dy = center_y - begin_p.m_y;
02220
02221
02222
02223
02224 a2dArcSegment* aseg = new a2dArcSegment( begin_p.m_x, begin_p.m_y, center_x + dx, center_y + dy );
02225 insert( iter, aseg );
02226 }
02227 else
02228 {
02229 a2dArcSegment* aseg = new a2dArcSegment( (*iter)->m_x, (*iter)->m_y, middle_p.m_x, middle_p.m_y );
02230 insert( iter, aseg );
02231
02232 }
02233 iter = erase( iter );
02234 }
02235
02236 bool a2dVertexList::CheckForOneCircle( a2dPoint2D& middle, double& radius )
02237 {
02238 a2dVertexList::iterator iter = begin();
02239 a2dLineSegment * seg = *iter;
02240 if ( size() == 1 && seg->GetArc() )
02241 {
02242 iter = GetPreviousAround( iter );
02243 double x = (*iter)->m_x;
02244 double y = (*iter)->m_y;
02245 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
02246 middle.m_x = cseg->GetOx(*seg);
02247 middle.m_y = cseg->GetOy(*seg);
02248 radius = sqrt( pow(x-middle.m_x,2.0) + pow(y-middle.m_y,2.0) );
02249
02250
02251 if ( x == seg->m_x && y == seg->m_y )
02252 return true;
02253 }
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280
02281
02282
02283
02284
02285 return false;
02286 }
02287
02288 void a2dVertexList::ConvertPolygonToArc(double aber,double Rmin,double Rmax)
02289 {
02290 int n,minimum_points;
02291
02292 a2dPoint2D center_p;
02293 minimum_points = 3;
02294
02295 a2dLineSegment* lsegn;
02296 if ( size() )
02297 {
02298 lsegn = new a2dLineSegment( front()->m_x, front()->m_y );
02299 push_back(lsegn);
02300 }
02301 else
02302 return;
02303
02304
02305 RemoveRedundant( false );
02306
02307 if ( size() > minimum_points)
02308 {
02309
02310
02311
02312
02313
02314
02315
02316
02317 a2dVertexList::iterator iter = begin();
02318 for (int count=0;count < size();count++)
02319 {
02320 n = TestArc( iter, aber, Rmin, Rmax, center_p );
02321
02322 if (n < size() && n > minimum_points)
02323 {
02324 for (int t=1; t < n; t++ ) iter++;
02325
02326 pop_back();
02327 MakeBegin( iter );
02328 lsegn = new a2dLineSegment((*iter)->m_x, (*iter)->m_y );
02329 push_back(lsegn);
02330
02331 break;
02332 }
02333 else if (n > minimum_points)
02334 {
02335 iter = begin();
02336
02337 double dx = center_p.m_x - (*iter)->m_x;
02338 double dy = center_p.m_y - (*iter)->m_y;
02339 a2dArcSegment* aseg = new a2dArcSegment( (*iter)->m_x, (*iter)->m_y, center_p.m_x + dx, center_p.m_y + dy );
02340 clear();
02341 push_back( aseg );
02342
02343
02344 return;
02345 }
02346
02347 iter++;
02348 pop_back();
02349 MakeBegin( iter );
02350 lsegn = new a2dLineSegment( (*iter)->m_x, (*iter)->m_y );
02351 push_back(lsegn);
02352 }
02353
02354 ConvertPolylineToArc(aber,Rmin,Rmax);
02355 }
02356
02357
02358
02359 if ( !back()->GetArc() )
02360 pop_back();
02361 }
02362
02363 void a2dVertexList::ConvertPolylineToArc(double aber,double Rmin,double Rmax)
02364 {
02365 int n,minimum_points;
02366
02367 a2dPoint2D center_p;
02368
02369 minimum_points = 3;
02370
02371 RemoveRedundant( false );
02372
02373 a2dVertexList::iterator iter = begin();
02374 if ( size() > minimum_points)
02375 {
02376 iter++;
02377 iter++;
02378 iter++;
02379 while( iter != end() )
02380 {
02381 iter--;
02382 iter--;
02383 iter--;
02384 a2dLineSegment* seg = *iter;
02385 n = TestArc(iter,aber,Rmin,Rmax,center_p);
02386 if (n > minimum_points )
02387 InsertArc(iter,n,center_p.m_x,center_p.m_y);
02388 else
02389 iter++;
02390
02391 if ( iter != end() ) iter++;
02392 if ( iter != end() ) iter++;
02393 if ( iter != end() ) iter++;
02394 }
02395 }
02396 }
02397
02398 #define KLEIN 1.0e-30
02399 #define GROOT 1.0e30
02400 #define PHI_MARGE 0.3 //must be lager than 0, 0.3 -> 30% (graden)
02401 #define SEG_MARGE 0.3 //must be lager than 0, 0.3 -> 30%
02402
02403 int a2dVertexList::TestArc( a2dVertexList::iterator& iter, double aber, double Rmin, double Rmax , a2dPoint2D& center_p_old )
02404 {
02405 a2dPoint2D begin_p,middle_p, test_p, end_p,center_p ;
02406
02407 a2dVertexList::iterator middle = iter;
02408 a2dVertexList::iterator test = iter;
02409 a2dVertexList::iterator endc = iter;
02410
02411 double error1, error2, Radius,Radius_old;
02412 double x_between, y_between, dx, dy, x_prev, y_prev;
02413 double inp,phi,phi_old,phi_fac,a,b,lseg,lseg_old,seg_fac;
02414 double t_inp;
02415 lseg = 0;
02416 int i, j,ii,minimum_points;
02417
02418 Radius = GROOT;
02419 error1 = GROOT;
02420 error2 = GROOT;
02421 phi = 0.0;
02422 lseg_old = 0.0;
02423 phi_old = 0.0;
02424
02425 if (aber < KLEIN)
02426 {
02427 phi_fac = 1 + PHI_MARGE;
02428 seg_fac = 1 + SEG_MARGE;
02429
02430 if (aber < 0.0)
02431 aber = -aber;
02432 else
02433 aber = GROOT;
02434 }
02435 else
02436 {
02437 phi_fac = GROOT;
02438 seg_fac = GROOT;
02439 }
02440
02441 minimum_points = 3;
02442
02443 begin_p.m_x = (*iter)->m_x;
02444 begin_p.m_y = (*iter)->m_y;
02445
02446 for (ii = 1;ii <= minimum_points;ii++)
02447 {
02448 if ( !(*endc)->GetArc() )
02449 endc++;
02450 else
02451 return (0);
02452 }
02453
02454 middle++;
02455
02456 i = minimum_points;
02457
02458 do
02459 {
02460 i++;
02461 if (i % 2 != 0)
02462 middle++;
02463
02464 end_p.m_x = (*endc)->m_x;
02465 end_p.m_y = (*endc)->m_y;
02466
02467 middle_p.m_x = (*middle)->m_x;
02468 middle_p.m_y = (*middle)->m_y;
02469
02470 Radius_old = Radius;
02471 center_p_old = center_p;
02472
02473
02474
02475 if ( !( (fabs(end_p.m_x - begin_p.m_x) < a2dACCUR ) && (fabs(end_p.m_y - begin_p.m_y)< a2dACCUR )))
02476 CalcR( begin_p.m_x, begin_p.m_y, middle_p.m_x, middle_p.m_y, end_p.m_x, end_p.m_y,
02477 Radius, center_p );
02478
02479 test = iter;
02480
02481 j=1;
02482
02483 test_p.m_x = (*test)->m_x;
02484 test_p.m_y = (*test)->m_y;
02485
02486 while ( j<i )
02487 {
02488 j++;
02489 x_prev = test_p.m_x;
02490 y_prev = test_p.m_y;
02491
02492 test++;
02493
02494 test_p.m_x = (*test)->m_x;
02495 test_p.m_y = (*test)->m_y;
02496
02497 dx = center_p.m_x - test_p.m_x;
02498 dy = center_p.m_y - test_p.m_y;
02499
02500 error1 = fabs(Radius - sqrt(pow(dx,2)+pow(dy,2)));
02501
02502 x_between = (test_p.m_x + x_prev)/2.0;
02503 y_between = (test_p.m_y + y_prev)/2.0;
02504
02505 dx = center_p.m_x - x_between;
02506 dy = center_p.m_y - y_between;
02507
02508 error2 = fabs(Radius - sqrt(pow(dx,2)+pow(dy,2)));
02509
02510 inp = (center_p.m_x - x_prev)*(test_p.m_y - center_p.m_y) -
02511 (center_p.m_y - y_prev)*(test_p.m_x - center_p.m_x);
02512
02513 a = sqrt( pow((center_p.m_x - x_prev),2) + pow((center_p.m_y - y_prev),2) );
02514 b = sqrt( pow((center_p.m_x - test_p.m_x),2) + pow((center_p.m_y - test_p.m_y),2) );
02515
02516 phi_old = phi;
02517
02518 t_inp = inp/(a*b);
02519
02520 if (t_inp > 1.0)
02521 t_inp = 1.0;
02522 else if (t_inp < -1.0)
02523 t_inp = -1.0;
02524
02525 phi = 180.0*asin(t_inp)/M_PI;
02526
02527 lseg_old = lseg;
02528
02529 lseg = sqrt(pow((test_p.m_x - x_prev),2)+pow((test_p.m_y - y_prev),2));
02530
02531 if (j == 2)
02532 {
02533 phi_old = phi;
02534 lseg_old = lseg;
02535 }
02536
02537 if ( error1 > aber ||
02538 error2 > aber ||
02539 fabs(phi) > fabs(phi_old)*phi_fac ||
02540 fabs(phi) < fabs(phi_old)/phi_fac ||
02541 phi*phi_old < 0.0 ||
02542 lseg > lseg_old*seg_fac ||
02543 lseg < lseg_old/seg_fac)
02544 {
02545 if (Radius_old > Rmin && Radius_old < Rmax)
02546
02547
02548 return (i-1);
02549
02550 else
02551 return (0);
02552 }
02553 }
02554
02555
02556 if ( (*endc)->GetArc() )
02557 break;
02558
02559 endc++;
02560 } while( endc != end() );
02561
02562 if (Radius > Rmin && Radius < Rmax)
02563 {
02564 center_p_old = center_p;
02565 return (i);
02566 }
02567 else
02568 return (0);
02569 }
02570
02571 a2dBoundingBox a2dVertexList::GetBbox( const a2dAffineMatrix& lworld )
02572 {
02573 a2dBoundingBox bbox;
02574
02575 double x, y;
02576 lworld.TransformPoint( 0, 0, x, y );
02577 if ( !size() )
02578 bbox.Expand( x, y );
02579
02580 a2dLineSegment* segprev = NULL;
02581 if ( size() )
02582 segprev = back();
02583 for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter )
02584 {
02585 a2dLineSegment* seg = *iter;
02586 if ( seg->GetArc() && segprev )
02587 bbox.Expand( seg->GetBbox( *segprev, lworld ) );
02588 else
02589 {
02590 lworld.TransformPoint( seg->m_x, seg->m_y, x, y );
02591 bbox.Expand( x, y );
02592 }
02593 segprev = ( *iter );
02594 }
02595 return bbox;
02596 }
02597
02598 a2dVertexList* a2dVertexList::ConvertToContour( double distance, a2dPATH_END_TYPE pathtype, bool asPolygon )
02599 {
02600 a2dVertexList * converted = new a2dVertexList();
02601 *converted = *this;
02602 converted->RemoveRedundant( asPolygon );
02603
02604 converted->Contour( distance, pathtype, asPolygon );
02605 return converted;
02606 }
02607
02608 void a2dVertexList::Contour( double distance, a2dPATH_END_TYPE pathtype, bool asPolygon )
02609 {
02610 bool rounded = true;
02611
02612 a2dPoint2D _first;
02613 a2dPoint2D _middle;
02614 a2dPoint2D _end;
02615 a2dPoint2D offsetpointleft;
02616 a2dPoint2D offsetpointright;
02617
02618 if ( asPolygon )
02619 push_front( new a2dLineSegment( back()->m_x, back()->m_y ) );
02620
02621 unsigned int size = this->size();
02622 a2dVertexList::iterator iter = begin();
02623 a2dLineSegment* seg = *iter;
02624 a2dVertexList::iterator prev = iter;
02625
02626
02627 if ( size == 1 )
02628 {
02629 a2dLineSegment * seg = *iter;
02630 push_back( new a2dLineSegment( seg->m_x - distance, seg->m_y ) );
02631 switch ( pathtype )
02632 {
02633 case a2dPATH_END_SQAURE:
02634 {
02635
02636 }
02637 break;
02638 case a2dPATH_END_ROUND:
02639 {
02640 push_back( new a2dArcSegment( seg->m_x + distance, seg->m_y, seg->m_x - distance, seg->m_y ) );
02641 }
02642 break;
02643 case a2dPATH_END_SQAURE_EXT:
02644 {
02645
02646 }
02647 break;
02648 default:
02649 break;
02650 }
02651 return;
02652 }
02653
02654
02655
02656
02657 _first = a2dPoint2D( seg->m_x, seg->m_y );
02658 iter++;
02659 a2dLineSegment* segnext = *iter;
02660
02661 _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
02662 a2dLine line1( _first, _middle );
02663 line1.CalculateLineParameters();
02664 offsetpointleft = _first;
02665 offsetpointright = _first;
02666 line1.Virtual_Point( offsetpointleft, distance );
02667 line1.Virtual_Point( offsetpointright, -distance );
02668
02669 switch ( pathtype )
02670 {
02671 case a2dPATH_END_SQAURE:
02672 {
02673 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02674 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02675 }
02676 break;
02677 case a2dPATH_END_ROUND:
02678 {
02679 a2dLine lineoffset( offsetpointright, offsetpointleft );
02680 lineoffset.CalculateLineParameters();
02681 a2dPoint2D offsetpointfirst;
02682
02683 offsetpointfirst = _first;
02684 lineoffset.Virtual_Point( offsetpointfirst, distance );
02685 push_back( new a2dArcSegment( offsetpointleft.m_x, offsetpointleft.m_y,
02686 offsetpointfirst.m_x, offsetpointfirst.m_y ) );
02687 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02688 break;
02689 }
02690 case a2dPATH_END_SQAURE_EXT:
02691 {
02692 a2dLine lineoffset( offsetpointright, offsetpointleft );
02693 lineoffset.CalculateLineParameters();
02694 lineoffset.Virtual_Point( offsetpointleft, distance );
02695 lineoffset.Virtual_Point( offsetpointright, distance );
02696
02697 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02698 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02699 break;
02700 }
02701 default:
02702 break;
02703 }
02704
02705 size--;
02706 size--;
02707 while ( size )
02708 {
02709 a2dLineSegment * seg = *prev;
02710 _first = a2dPoint2D( seg->m_x, seg->m_y );
02711 a2dLineSegment* segnext = *iter;
02712 _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
02713 a2dLine line1( _first, _middle );
02714 erase( prev );
02715 prev = iter;
02716 iter++;
02717 a2dLineSegment* segend = *iter;
02718 _end = a2dPoint2D( segend->m_x, segend->m_y );
02719 a2dLine line2( _middle, _end );
02720 line1.CalculateLineParameters();
02721 line2.CalculateLineParameters();
02722
02723 OUTPRODUCT _outproduct;
02724 _outproduct = line1.OutProduct( line2, 1e-9 );
02725
02726 switch ( _outproduct )
02727 {
02728
02729 case R_IS_RIGHT :
02730 {
02731 if ( !rounded )
02732 {
02733 line1.OffsetContour( line2, distance, offsetpointleft );
02734 line1.OffsetContour( line2, -distance, offsetpointright );
02735 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02736 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02737 }
02738 else
02739 {
02740 OffsetContour_rounded( line1, line2, distance, false );
02741 line1.OffsetContour( line2, -distance, offsetpointright );
02742 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02743 }
02744 }
02745 break;
02746 case R_IS_LEFT :
02747 {
02748 if ( !rounded )
02749 {
02750 line1.OffsetContour( line2, distance, offsetpointleft );
02751 line1.OffsetContour( line2, -distance, offsetpointright );
02752 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02753 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02754 }
02755 else
02756 {
02757 line1.OffsetContour( line2, distance, offsetpointleft );
02758 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02759 OffsetContour_rounded( line1, line2, -distance, true );
02760 }
02761 }
02762 break;
02763
02764 case R_IS_ON :
02765 {
02766 offsetpointleft = _middle;
02767 offsetpointright = _middle;
02768 line1.Virtual_Point( offsetpointleft, distance );
02769 line1.Virtual_Point( offsetpointright, -distance );
02770 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02771 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02772 }
02773 break;
02774 default:
02775 wxFAIL_MSG( wxT( "wrong line code" ) );
02776 break;
02777 }
02778
02779 size--;
02780 }
02781
02782 seg = *prev;
02783
02784
02785 _first = a2dPoint2D( seg->m_x, seg->m_y );
02786 segnext = *iter;
02787 _end = a2dPoint2D( segnext->m_x, segnext->m_y );
02788 a2dLine line2( _first, _end );
02789 line2.CalculateLineParameters();
02790 offsetpointleft = _end;
02791 offsetpointright = _end;
02792 line2.Virtual_Point( offsetpointleft, distance );
02793 line2.Virtual_Point( offsetpointright, -distance );
02794
02795 prev = erase( prev );
02796 prev = erase( prev );
02797
02798 switch ( pathtype )
02799 {
02800 case a2dPATH_END_SQAURE:
02801 {
02802 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02803 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02804 }
02805 break;
02806 case a2dPATH_END_ROUND:
02807 {
02808 a2dLine lineoffset( offsetpointleft, offsetpointright );
02809 lineoffset.CalculateLineParameters();
02810 a2dPoint2D offsetpointend;
02811
02812 offsetpointend = _end;
02813 lineoffset.Virtual_Point( offsetpointend, distance );
02814 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02815 push_back( new a2dArcSegment( offsetpointright.m_x, offsetpointright.m_y,
02816 offsetpointend.m_x, offsetpointend.m_y ) );
02817 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02818 break;
02819 }
02820 case a2dPATH_END_SQAURE_EXT:
02821 {
02822 a2dLine lineoffset( offsetpointright, offsetpointleft );
02823 lineoffset.CalculateLineParameters();
02824 lineoffset.Virtual_Point( offsetpointleft, -distance );
02825 lineoffset.Virtual_Point( offsetpointright, -distance );
02826
02827 push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
02828 push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
02829 break;
02830 }
02831 default:
02832 break;
02833 }
02834 }
02835
02836 a2dVertexList* a2dVertexList::ConvertSplinedPolygon( double Aber ) const
02837 {
02838 a2dVertexList * h = new a2dVertexList();
02839
02840 *h = *this;
02841
02842
02843 h->ConvertIntoSplinedPolygon( Aber );
02844
02845 return h;
02846 }
02847
02848 a2dVertexList* a2dVertexList::ConvertSplinedPolyline( double Aber ) const
02849 {
02850 a2dVertexList * h = new a2dVertexList();
02851
02852 *h = *this;
02853
02854 h->ConvertIntoSplinedPolyline( Aber );
02855
02856 return h;
02857 }
02858
02859 void a2dVertexList::ConvertIntoSplinedPolygon( double Aber )
02860 {
02861
02862 ConvertToLines();
02863
02864 a2dLineSegment* point;
02865 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
02866 double x1, y1, x2, y2;
02867
02868 if ( size() < 2 )
02869 return;
02870
02871 a2dVertexList::iterator iter = --end();
02872 x1 = ( *iter )->m_x;
02873 y1 = ( *iter )->m_y;
02874
02875 iter = begin();
02876 x2 = ( *iter )->m_x;
02877 y2 = ( *iter )->m_y;
02878
02879 point = new a2dLineSegment( x2, y2 );
02880 push_back( point );
02881
02882 cx1 = ( x1 + x2 ) / 2.0;
02883 cy1 = ( y1 + y2 ) / 2.0;
02884 cx2 = ( cx1 + x2 ) / 2.0;
02885 cy2 = ( cy1 + y2 ) / 2.0;
02886
02887 iter = erase( iter );
02888 iter = begin();
02889 x1 = ( *iter )->m_x;
02890 y1 = ( *iter )->m_y;
02891 point = new a2dLineSegment( x1, y1 );
02892 push_back( point );
02893
02894 unsigned int i = 1;
02895 unsigned int count = size();
02896 while ( i < count )
02897 {
02898 x1 = x2;
02899 y1 = y2;
02900 x2 = ( *iter )->m_x;
02901 y2 = ( *iter )->m_y;
02902 cx4 = ( x1 + x2 ) / 2.0;
02903 cy4 = ( y1 + y2 ) / 2.0;
02904 cx3 = ( x1 + cx4 ) / 2.0;
02905 cy3 = ( y1 + cy4 ) / 2.0;
02906
02907 gds_quadratic_spline( this, cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, Aber );
02908
02909 cx1 = cx4;
02910 cy1 = cy4;
02911 cx2 = ( cx1 + x2 ) / 2.0;
02912 cy2 = ( cy1 + y2 ) / 2.0;
02913 iter = erase( iter );
02914 iter = begin();
02915 i++;
02916 }
02917
02918 iter = begin();
02919 erase( iter );
02920 }
02921
02922 void a2dVertexList::ConvertIntoSplinedPolyline( double Aber )
02923 {
02924 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
02925 double x1, y1, x2, y2;
02926
02927
02928 if ( size() < 2 )
02929 return;
02930
02931 a2dVertexList::iterator iter = begin();
02932
02933 x1 = ( *iter )->m_x;
02934 y1 = ( *iter )->m_y;
02935
02936 iter = erase( iter );
02937 iter = begin();
02938 x2 = ( *iter )->m_x;
02939 y2 = ( *iter )->m_y;
02940 cx1 = ( x1 + x2 ) / 2.0;
02941 cy1 = ( y1 + y2 ) / 2.0;
02942 cx2 = ( cx1 + x2 ) / 2.0;
02943 cy2 = ( cy1 + y2 ) / 2.0;
02944
02945 a2dLineSegment* point = new a2dLineSegment( x1, y1 );
02946 push_back( point );
02947
02948 iter = erase( iter );
02949
02950 unsigned int i = 1;
02951 unsigned int count = size();
02952 while ( i < count )
02953 {
02954 x1 = x2;
02955 y1 = y2;
02956 x2 = ( *iter )->m_x;
02957 y2 = ( *iter )->m_y;
02958 cx4 = ( x1 + x2 ) / 2.0;
02959 cy4 = ( y1 + y2 ) / 2.0;
02960 cx3 = ( x1 + cx4 ) / 2.0;
02961 cy3 = ( y1 + cy4 ) / 2.0;
02962
02963 gds_quadratic_spline( this, cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, Aber );
02964
02965 cx1 = cx4;
02966 cy1 = cy4;
02967 cx2 = ( cx1 + x2 ) / 2.0;
02968 cy2 = ( cy1 + y2 ) / 2.0;
02969 iter = erase( iter );
02970 i++;
02971 }
02972
02973 point = new a2dLineSegment( cx1, cy1 );
02974 push_back( point );
02975
02976 point = new a2dLineSegment( x2, y2 );
02977 push_back( point );
02978 }
02979
02980 bool a2dVertexList::RemoveRedundant( bool polygon )
02981 {
02982 bool did = false;
02983 a2dLineSegment* segprev = NULL;
02984 a2dLineSegment * seg = NULL;
02985 a2dVertexList::iterator iter = begin();
02986 while( iter != end() )
02987 {
02988 seg = *iter;
02989 if ( !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
02990 {
02991 iter = erase( iter );
02992 did = true;
02993 }
02994 else
02995 {
02996 segprev = seg;
02997 iter++;
02998 }
02999 }
03000 iter = begin();
03001 seg = *iter;
03002 if ( polygon && !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
03003 {
03004 iter = erase( iter );
03005 did = true;
03006 }
03007 return did;
03008 }
03009
03010 a2dVertexList* a2dVertexList::GetRedundant( bool polygon, double smallest )
03011 {
03012 smallest = smallest*smallest;
03013 a2dVertexList* redunDant = new a2dVertexList();
03014 a2dLineSegment* segprev = NULL;
03015 a2dLineSegmentPtr seg;
03016 a2dVertexList::iterator iter = begin();
03017 while( iter != end() )
03018 {
03019 seg = *iter;
03020 if ( !seg->GetArc() && segprev &&
03021 ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
03022 redunDant->push_back( seg->Clone() );
03023 segprev = seg;
03024 iter++;
03025 }
03026 iter = begin();
03027 seg = *iter;
03028 if ( polygon && !seg->GetArc() && segprev &&
03029 ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
03030 redunDant->push_back( seg->Clone() );
03031
03032 if ( redunDant->empty() )
03033 {
03034 delete redunDant;
03035 redunDant = NULL;
03036 }
03037 return redunDant;
03038 }
03039
03040 a2dHit a2dVertexList::HitTestPolygon( const a2dPoint2D& ptest, double margin )
03041 {
03042 wxASSERT( margin >= 0 );
03043
03044 a2dPoint2D p1, p2, pm;
03045
03046 double minDistSqrVertex = margin * margin;
03047 double minDistSqrStroke = margin * margin;
03048 bool vertexhit = false;
03049 int intersection_count = 0;
03050 a2dHit rslt;
03051
03052 int i = 0;
03053 for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter, i++ )
03054 {
03055 a2dLineSegment* seg = *iter;
03056 p1 = seg->GetPoint();
03057 if ( iter == --end() )
03058 {
03059 p2 = front()->GetPoint();
03060 }
03061 else
03062 {
03063 iter++;
03064 p2 = ( *iter )->GetPoint();
03065 iter--;
03066 }
03067
03068
03069
03070
03071
03072
03073
03074 double xmin;
03075 double xmax;
03076 int direction;
03077
03078
03079 if( p1.m_x < p2.m_x )
03080 {
03081 xmin = p1.m_x;
03082 xmax = p2.m_x;
03083 direction = 1;
03084 }
03085 else
03086 {
03087 xmin = p2.m_x;
03088 xmax = p1.m_x;
03089 direction = -1;
03090 }
03091
03092 if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
03093 continue;
03094
03095
03096 double ymin;
03097 double ymax;
03098 if( p1.m_y < p2.m_y )
03099 {
03100 ymin = p1.m_y;
03101 ymax = p2.m_y;
03102 }
03103 else
03104 {
03105 ymin = p2.m_y;
03106 ymax = p1.m_y;
03107 }
03108
03109
03110
03111 if( ptest.m_y < ymin - margin )
03112 {
03113
03114
03115
03116 if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
03117 {
03118 intersection_count += direction;
03119 }
03120 }
03121 else if( ptest.m_y <= ymax + margin )
03122 {
03123
03124
03125
03126
03127
03128
03129
03130
03131
03132
03133
03134
03135
03136
03137
03138
03139
03140
03141 double distSqr = ClclDistSqrPntPnt( ptest, p1 );
03142
03143 if( distSqr < minDistSqrVertex )
03144 {
03145 minDistSqrVertex = distSqr;
03146 rslt.m_hit = a2dHit::hit_stroke;
03147 rslt.m_index = i;
03148 rslt.m_stroke2 = a2dHit::stroke2_vertex;
03149 vertexhit = true;
03150 }
03151
03152
03153
03154
03155
03156 pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
03157 distSqr = ClclDistSqrPntPnt( ptest, pm );
03158 if( distSqr < minDistSqrVertex )
03159 {
03160 minDistSqrVertex = distSqr;
03161 rslt.m_hit = a2dHit::hit_stroke;
03162 rslt.m_index = i;
03163 if( p1.m_x == p2.m_x )
03164 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
03165 else if( p1.m_y == p2.m_y )
03166 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
03167 else
03168 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
03169 vertexhit = true;
03170 }
03171
03172
03173
03174
03175
03176
03177
03178 distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
03179
03180 if( distSqr < minDistSqrStroke )
03181 {
03182 minDistSqrStroke = distSqr;
03183 if( !vertexhit )
03184 {
03185 rslt.m_hit = a2dHit::hit_stroke;
03186 rslt.m_index = i;
03187 if( p1.m_x == p2.m_x )
03188 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
03189 else if( p1.m_y == p2.m_y )
03190 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
03191 else
03192 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
03193 }
03194 }
03195
03196
03197
03198
03199
03200
03201 if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
03202 {
03203 if( p1.m_y == p2.m_y )
03204 {
03205 if( ptest.m_y <= p1.m_y )
03206 intersection_count += direction;
03207 }
03208 else
03209 {
03210 double y = ( ptest.m_x - p1.m_x ) * ( p2.m_y - p1.m_y ) / ( p2.m_x - p1.m_x ) + p1.m_y;
03211 if( ptest.m_y <= y )
03212 intersection_count += direction;
03213 }
03214 }
03215 }
03216 }
03217
03218 if( rslt.m_hit == a2dHit::hit_stroke )
03219 {
03220 if( intersection_count )
03221 rslt.m_stroke1 = a2dHit::stroke1_inside;
03222 else
03223 rslt.m_stroke1 = a2dHit::stroke1_outside;
03224
03225 if( vertexhit )
03226 rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
03227 else
03228 rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
03229 }
03230 else
03231 {
03232 if( intersection_count )
03233 rslt.m_hit = a2dHit::hit_fill;
03234 else
03235 rslt.m_hit = a2dHit::hit_none;
03236 }
03237
03238 return rslt;
03239 }
03240
03241 a2dHit a2dVertexList::HitTestPolyline( const a2dPoint2D& ptest, double margin )
03242 {
03243 wxASSERT( margin >= 0 );
03244
03245 a2dPoint2D p1, p2, pm;
03246
03247 double minDistSqrVertex = margin * margin;
03248 double minDistSqrStroke = margin * margin;
03249 bool vertexhit = false;
03250 bool lastpoint = false;
03251 a2dHit rslt;
03252
03253 int i = 0;
03254 for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter, i++ )
03255 {
03256 a2dLineSegment* seg = *iter;
03257 p1 = seg->GetPoint();
03258
03259 if( iter != --end() )
03260 {
03261 iter++;
03262 p2 = ( *iter )->GetPoint();
03263 iter--;
03264 }
03265 else
03266 lastpoint = true;
03267
03268
03269
03270
03271
03272
03273
03274 double xmin;
03275 double xmax;
03276
03277 if( p1.m_x < p2.m_x )
03278 {
03279 xmin = p1.m_x;
03280 xmax = p2.m_x;
03281 }
03282 else
03283 {
03284 xmin = p2.m_x;
03285 xmax = p1.m_x;
03286 }
03287
03288 if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
03289 continue;
03290
03291
03292 double ymin;
03293 double ymax;
03294 if( p1.m_y < p2.m_y )
03295 {
03296 ymin = p1.m_y;
03297 ymax = p2.m_y;
03298 }
03299 else
03300 {
03301 ymin = p2.m_y;
03302 ymax = p1.m_y;
03303 }
03304
03305 if( ptest.m_y < ymin - margin || ptest.m_y > ymax + margin )
03306 continue;
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326 double distSqr = ClclDistSqrPntPnt( ptest, p1 );
03327
03328 if( distSqr < minDistSqrVertex )
03329 {
03330 minDistSqrVertex = distSqr;
03331 rslt.m_hit = a2dHit::hit_stroke;
03332 rslt.m_index = i;
03333 rslt.m_stroke2 = a2dHit::stroke2_vertex;
03334 vertexhit = true;
03335 }
03336
03337 if( lastpoint )
03338 break;
03339
03340
03341
03342
03343
03344 pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
03345 distSqr = ClclDistSqrPntPnt( ptest, pm );
03346 if( distSqr < minDistSqrVertex )
03347 {
03348 minDistSqrVertex = distSqr;
03349 rslt.m_hit = a2dHit::hit_stroke;
03350 rslt.m_index = i;
03351 if( p1.m_x == p2.m_x )
03352 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
03353 else if( p1.m_y == p2.m_y )
03354 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
03355 else
03356 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
03357 vertexhit = true;
03358 }
03359
03360
03361
03362
03363
03364
03365
03366 distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
03367
03368 if( distSqr < minDistSqrStroke )
03369 {
03370 minDistSqrStroke = distSqr;
03371 if( !vertexhit )
03372 {
03373 rslt.m_hit = a2dHit::hit_stroke;
03374 rslt.m_index = i;
03375 if( p1.m_x == p2.m_x )
03376 rslt.m_stroke2 = a2dHit::stroke2_edgevert;
03377 else if( p1.m_y == p2.m_y )
03378 rslt.m_stroke2 = a2dHit::stroke2_edgehor;
03379 else
03380 rslt.m_stroke2 = a2dHit::stroke2_edgeother;
03381 }
03382 }
03383 }
03384
03385 if( rslt.m_hit == a2dHit::hit_stroke )
03386 {
03387 rslt.m_stroke1 = a2dHit::stroke1_outside;
03388 if( vertexhit )
03389 rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
03390 else
03391 rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
03392 }
03393
03394 return rslt;
03395 }
03396
03397 void a2dVertexList::CreateArc( const a2dPoint2D& center, const a2dPoint2D& begin, const a2dPoint2D& end, double radius, bool clock, double aber, bool addAtFront )
03398 {
03399 double phi, dphi, dx, dy;
03400 int Segments;
03401 int i;
03402 double ang1, ang2, phit;
03403
03404 dx = begin.m_x - center.m_x;
03405 dy = begin.m_y - center.m_y;
03406 ang1 = atan2( dy, dx );
03407 if ( ang1 < 0 ) ang1 += 2.0 * M_PI;
03408 dx = end.m_x - center.m_x;
03409 dy = end.m_y - center.m_y;
03410 ang2 = atan2( dy, dx );
03411 if ( ang2 < 0 ) ang2 += 2.0 * M_PI;
03412
03413 if ( clock )
03414 {
03415 if ( ang2 > ang1 )
03416 phit = 2.0 * M_PI - ang2 + ang1;
03417 else
03418 phit = ang1 - ang2;
03419 }
03420 else
03421 {
03422 if ( ang1 > ang2 )
03423 phit = -( 2.0 * M_PI - ang1 + ang2 );
03424 else
03425 phit = -( ang2 - ang1 );
03426 }
03427
03428
03429 dphi = 2 * acos( ( radius - aber ) / radius );
03430
03431
03432 if ( phit > 0 )
03433 Segments = ( int )ceil( phit / dphi );
03434 else
03435 Segments = ( int )ceil( -phit / dphi );
03436
03437 if ( Segments <= 1 )
03438 Segments = 1;
03439 if ( Segments > 6 )
03440 Segments = 6;
03441
03442 dphi = phit / ( Segments );
03443
03444 dx = begin.m_x - center.m_x;
03445 dy = begin.m_y - center.m_y;
03446 phi = atan2( dy, dx );
03447
03448
03449 for ( i = 0; i <= Segments; i++ )
03450 {
03451 if ( addAtFront )
03452 push_front( new a2dLineSegment( center.m_x + radius * cos( phi ), center.m_y + radius * sin( phi ) ) );
03453 else
03454 push_back( new a2dLineSegment( center.m_x + radius * cos( phi ), center.m_y + radius * sin( phi ) ) );
03455 phi -= dphi;
03456 }
03457 }
03458
03459 void a2dVertexList::CreateArc( const a2dPoint2D& center, const a2dLine& incoming, const a2dPoint2D& end, double radius, double aber, bool addAtFront )
03460 {
03461 double distance = 0;
03462 if ( incoming.PointOnLine( center, distance, a2dACCUR ) == R_RIGHT_SIDE )
03463 CreateArc( center, incoming.GetEndPoint(), end, radius, true, aber, addAtFront );
03464 else
03465 CreateArc( center, incoming.GetEndPoint(), end, radius, false, aber, addAtFront );
03466 }
03467
03468 void a2dVertexList::OffsetContour_rounded( const a2dLine& currentline, const a2dLine& nextline, double factor, bool addAtFront )
03469 {
03470 a2dPoint2D offs_begin;
03471 a2dPoint2D offs_end;
03472 a2dPoint2D medial_axes_point;
03473 a2dPoint2D offs_bgn_next;
03474 a2dPoint2D offs_end_next;
03475
03476
03477 offs_end = currentline.GetEndPoint();
03478 offs_begin = currentline.GetBeginPoint();
03479 currentline.Virtual_Point( offs_begin, factor );
03480 currentline.Virtual_Point( offs_end, factor );
03481 a2dLine offs_currentline( offs_begin, offs_end );
03482
03483 offs_bgn_next = nextline.GetBeginPoint();
03484 offs_end_next = nextline.GetEndPoint();
03485 nextline.Virtual_Point( offs_bgn_next, factor );
03486 nextline.Virtual_Point( offs_end_next, factor );
03487
03488 a2dLine offs_nextline( offs_bgn_next, offs_end_next );
03489
03490 offs_currentline.CalculateLineParameters();
03491 offs_nextline.CalculateLineParameters();
03492 offs_currentline.Intersect( offs_nextline, medial_axes_point );
03493
03494 double result_offs = sqrt( pow( currentline.GetEndPoint().m_x - medial_axes_point.m_x, 2 ) +
03495 pow( currentline.GetEndPoint().m_y - medial_axes_point.m_y, 2 ) );
03496
03497 double roundFactor = a2dGlobals->GetRoundFactor();
03498 if ( result_offs < fabs( roundFactor * factor ) )
03499 {
03500 if ( addAtFront )
03501 push_front( new a2dLineSegment( medial_axes_point ) );
03502 else
03503 push_back( new a2dLineSegment( medial_axes_point ) );
03504 }
03505 else
03506 {
03507 CreateArc( currentline.GetEndPoint(), offs_currentline, offs_nextline.GetBeginPoint(), fabs( factor ),
03508 a2dGlobals->GetAberArcToPoly(), addAtFront );
03509 }
03510 }
03511
03512
03513
03514
03515 const int VPATHSPLINE_STEP = 20;
03516
03517
03518 a2dVpathSegment::a2dVpathSegment( double x, double y, a2dPATHSEG type, a2dPATHSEG_END close )
03519 {
03520 m_type = type;
03521 m_close = close;
03522 m_x1 = x;
03523 m_y1 = y;
03524 }
03525
03526 a2dVpathSegment::a2dVpathSegment( const a2dVpathSegment &other )
03527 {
03528 m_type = other.m_type;
03529 m_close = other.m_close;
03530 m_x1 = other.m_x1;
03531 m_y1 = other.m_y1;
03532 }
03533
03534 a2dVpathSegment::~a2dVpathSegment()
03535 {}
03536
03537 a2dVpathSegment* a2dVpathSegment::Clone()
03538 {
03539 a2dVpathSegment * a = new a2dVpathSegment( m_x1, m_y1, m_type, m_close );
03540 return a;
03541 }
03542
03543 double a2dVpathSegment::Length( const a2dVpathSegment& prev )
03544 {
03545 return sqrt( pow( prev.m_x1 -m_x1, 2 ) + pow( prev.m_y1 - m_y1, 2 ) );
03546 }
03547
03548
03549 a2dVpathQBCurveSegment::a2dVpathQBCurveSegment( double x1, double y1, double x2, double y2, a2dPATHSEG type, a2dPATHSEG_END close )
03550 : a2dVpathSegment( x1, y1 )
03551 {
03552 m_type = type;
03553 wxASSERT_MSG( a2dPATHSEG_QBCURVETO == m_type || a2dPATHSEG_QBCURVETO_NOSTROKE == m_type , wxT( "wrong type" ) );
03554
03555 m_close = close;
03556
03557 m_x2 = x2;
03558 m_y2 = y2;
03559 }
03560
03561 a2dVpathQBCurveSegment::a2dVpathQBCurveSegment( const a2dVpathSegment& prev, double x1, double y1, a2dPATHSEG type, a2dPATHSEG_END close )
03562 : a2dVpathSegment( x1, y1 )
03563 {
03564 m_type = type;
03565 wxASSERT_MSG( a2dPATHSEG_QBCURVETO == m_type || a2dPATHSEG_QBCURVETO_NOSTROKE == m_type , wxT( "wrong type" ) );
03566 m_close = close;
03567
03568 switch ( prev.GetType() )
03569 {
03570 case a2dPATHSEG_QBCURVETO:
03571 case a2dPATHSEG_QBCURVETO_NOSTROKE:
03572 {
03573 a2dVpathQBCurveSegment & cseg = ( a2dVpathQBCurveSegment& ) prev;
03574 m_x2 = prev.m_x1 + ( cseg.m_x1 - cseg.m_x2 );
03575 m_y2 = prev.m_y1 + ( cseg.m_y1 - cseg.m_y2 );
03576 break;
03577 }
03578 default:
03579 {
03580 m_x2 = prev.m_x1;
03581 m_y2 = prev.m_y1;
03582 }
03583 }
03584 }
03585
03586
03587
03588 a2dVpathQBCurveSegment::a2dVpathQBCurveSegment( const a2dVpathQBCurveSegment& other ): a2dVpathSegment( other )
03589 {
03590 m_x2 = other.m_x2;
03591 m_y2 = other.m_y2;
03592 }
03593
03594 a2dVpathQBCurveSegment::~a2dVpathQBCurveSegment()
03595 {}
03596
03597 a2dVpathSegment* a2dVpathQBCurveSegment::Clone()
03598 {
03599 a2dVpathQBCurveSegment * a = new a2dVpathQBCurveSegment( m_x1, m_y1, m_x2, m_y2, m_type, m_close );
03600 return a;
03601 }
03602
03603 double a2dVpathQBCurveSegment::Length( const a2dVpathSegment& prev )
03604 {
03605 int step;
03606 double t = 0;
03607 double len = 0;
03608 double xwl = prev.m_x1;
03609 double ywl = prev.m_y1;
03610 double xt, yt;
03611
03612 for ( step = 1; step <= VPATHSPLINE_STEP; step++ )
03613 {
03614 PositionAt( prev, t, xt, yt );
03615 len = len + sqrt( pow( xwl - xt, 2 ) + pow( ywl - yt, 2 ) );
03616 t = t + 1 / ( double )VPATHSPLINE_STEP;
03617 xwl = xt;
03618 ywl = yt;
03619
03620 }
03621 return len;
03622 }
03623
03624 void a2dVpathQBCurveSegment::PositionAt( const a2dVpathSegment& prev, double t, double& xt, double& yt )
03625 {
03626 xt = prev.m_x1 * pow( 1 - t, 2 ) + m_x2 * ( 1 - t ) * t * 2 + m_x1 * pow( t, 2 );
03627 yt = prev.m_y1 * pow( 1 - t, 2 ) + m_y2 * ( 1 - t ) * t * 2 + m_y1 * pow( t, 2 );
03628 }
03629
03630 a2dVpathCBCurveSegment::a2dVpathCBCurveSegment( double x1, double y1, double x2, double y2, double x3, double y3, a2dPATHSEG type, a2dPATHSEG_END close )
03631 : a2dVpathSegment( x1, y1 )
03632 {
03633 m_type = type;
03634 wxASSERT_MSG( ( a2dPATHSEG_CBCURVETO == m_type || a2dPATHSEG_CBCURVETO_NOSTROKE == m_type ) , wxT( "wrong type" ) );
03635
03636 m_close = close;
03637
03638 m_x2 = x2;
03639 m_y2 = y2;
03640
03641 m_x3 = x3;
03642 m_y3 = y3;
03643 }
03644
03645 a2dVpathCBCurveSegment::a2dVpathCBCurveSegment( const a2dVpathSegment& prev, double x1, double y1, double x3, double y3, a2dPATHSEG type, a2dPATHSEG_END close )
03646 : a2dVpathSegment( x1, y1 )
03647 {
03648 m_type = type;
03649 wxASSERT_MSG( ( a2dPATHSEG_CBCURVETO == m_type || a2dPATHSEG_CBCURVETO_NOSTROKE == m_type ) , wxT( "wrong type" ) );
03650
03651 m_close = close;
03652
03653 switch ( prev.GetType() )
03654 {
03655 case a2dPATHSEG_CBCURVETO:
03656 case a2dPATHSEG_CBCURVETO_NOSTROKE:
03657 {
03658 a2dVpathCBCurveSegment & cseg = ( a2dVpathCBCurveSegment& ) prev;
03659 m_x2 = prev.m_x1 + ( cseg.m_x1 - cseg.m_x3 );
03660 m_y2 = prev.m_y1 + ( cseg.m_y1 - cseg.m_y3 );
03661 break;
03662 }
03663 default:
03664 {
03665 m_x2 = prev.m_x1;
03666 m_y2 = prev.m_y1;
03667 }
03668 }
03669
03670 m_x3 = x3;
03671 m_y3 = y3;
03672 }
03673
03674 a2dVpathCBCurveSegment::a2dVpathCBCurveSegment( const a2dVpathCBCurveSegment &other ): a2dVpathSegment( other )
03675 {
03676 m_x2 = other.m_x2;
03677 m_y2 = other.m_y2;
03678
03679 m_x3 = other.m_x3;
03680 m_y3 = other.m_y3;
03681
03682 }
03683
03684 a2dVpathCBCurveSegment::~a2dVpathCBCurveSegment()
03685 {}
03686
03687 a2dVpathSegment* a2dVpathCBCurveSegment::Clone()
03688 {
03689 a2dVpathCBCurveSegment * a = new a2dVpathCBCurveSegment( m_x1, m_y1, m_x2, m_y2, m_x3, m_y3, m_type, m_close );
03690 return a;
03691 }
03692
03693 double a2dVpathCBCurveSegment::Length( const a2dVpathSegment& prev )
03694 {
03695 int step;
03696 double t = 0;
03697 double len = 0;
03698 double xwl = prev.m_x1;
03699 double ywl = prev.m_y1;
03700 double xt, yt;
03701
03702 for ( step = 1; step <= VPATHSPLINE_STEP; step++ )
03703 {
03704 PositionAt( prev, t, xt, yt );
03705 len = len + sqrt( pow( xwl - xt, 2 ) + pow( ywl - yt, 2 ) );
03706 t = t + 1 / ( double )VPATHSPLINE_STEP;
03707 xwl = xt;
03708 ywl = yt;
03709
03710 }
03711 return len;
03712 }
03713
03714 void a2dVpathCBCurveSegment::PositionAt( const a2dVpathSegment& prev, double t, double& xt, double& yt )
03715 {
03716 xt = prev.m_x1 * pow( 1 - t, 3 ) + m_x2 * pow( 1 - t, 2 ) * t * 3 + m_x3 * ( 1 - t ) * t * t * 3 + m_x1 * pow( t, 3 );
03717 yt = prev.m_y1 * pow( 1 - t, 3 ) + m_y2 * pow( 1 - t, 2 ) * t * 3 + m_y3 * ( 1 - t ) * t * t * 3 + m_y1 * pow( t, 3 );
03718 }
03719
03720 a2dVpathArcSegment::a2dVpathArcSegment( double x1, double y1, double x2, double y2, a2dPATHSEG type, a2dPATHSEG_END close )
03721 : a2dVpathSegment( x1, y1 )
03722 {
03723 m_type = type;
03724 wxASSERT_MSG( a2dPATHSEG_ARCTO == m_type || a2dPATHSEG_ARCTO_NOSTROKE == m_type , wxT( "wrong type" ) );
03725
03726 m_close = close;
03727
03728 m_x2 = x2;
03729 m_y2 = y2;
03730 }
03731
03732 a2dVpathArcSegment::a2dVpathArcSegment( const a2dVpathSegment& prev, double xc, double yc, double angle, a2dPATHSEG type, a2dPATHSEG_END close )
03733 : a2dVpathSegment( 0, 0 )
03734 {
03735 m_type = type;
03736 wxASSERT_MSG( a2dPATHSEG_ARCTO == m_type || a2dPATHSEG_ARCTO_NOSTROKE == m_type , wxT( "wrong type" ) );
03737
03738 m_close = close;
03739
03740 double radius = sqrt( pow( prev.m_x1 - xc, 2 ) + pow( prev.m_y1 - yc, 2 ) );
03741
03742 double endrad = atan2( prev.m_y1 - yc, prev.m_x1 - xc ) + wxDegToRad( angle );
03743
03744 m_x1 = xc + radius * cos( endrad );
03745 m_y1 = yc + radius * sin( endrad );
03746
03747 double midrad = atan2( prev.m_y1 - yc, prev.m_x1 - xc ) + wxDegToRad( angle / 2.0 );
03748
03749 m_x2 = xc + radius * cos( midrad );
03750 m_y2 = yc + radius * sin( midrad );
03751 }
03752
03753 a2dVpathArcSegment::a2dVpathArcSegment( const a2dVpathSegment& prev, double xc, double yc, double x1, double y1, double x2, double y2, a2dPATHSEG type, a2dPATHSEG_END close )
03754 : a2dVpathSegment( x1, y1 )
03755 {
03756 m_type = type;
03757 wxASSERT_MSG( a2dPATHSEG_ARCTO == m_type || a2dPATHSEG_ARCTO_NOSTROKE == m_type , wxT( "wrong type" ) );
03758
03759 m_close = close;
03760
03761 double radius = sqrt( pow( prev.m_x1 - xc, 2 ) + pow( prev.m_y1 - yc, 2 ) );
03762
03763 double endrad = atan2( m_y1 - yc, m_x1 - xc );
03764
03765 m_x1 = xc + radius * cos( endrad );
03766 m_y1 = yc + radius * sin( endrad );
03767
03768 double midrad = atan2( y2 - yc, x2 - xc );
03769
03770 m_x2 = xc + radius * cos( midrad );
03771 m_y2 = yc + radius * sin( midrad );
03772 }
03773
03774 a2dVpathArcSegment::a2dVpathArcSegment( const a2dVpathArcSegment &other ): a2dVpathSegment( other )
03775 {
03776 m_x2 = other.m_x2;
03777 m_y2 = other.m_y2;
03778 }
03779
03780 a2dVpathArcSegment::~a2dVpathArcSegment()
03781 {}
03782
03783 a2dVpathSegment* a2dVpathArcSegment::Clone()
03784 {
03785 a2dVpathArcSegment * a = new a2dVpathArcSegment( m_x1, m_y1, m_x2, m_y2, m_type, m_close );
03786 return a;
03787 }
03788
03789 double a2dVpathArcSegment::Length( const a2dVpathSegment& prev )
03790 {
03791 double len, radius, center_x, center_y, beginrad, midrad, endrad, phit;
03792
03793 if ( CalcR( prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
03794 {
03795 len = fabs(phit * radius);
03796 }
03797 else
03798 len = sqrt( pow( prev.m_x1 - m_x1, 2 ) + pow( prev.m_y1 - m_y1, 2 ) );
03799
03800 return len;
03801 }
03802
03803 bool a2dVpathArcSegment::CalcR( const a2dVpathSegment& prev, double& radius, double& center_x, double& center_y, double& beginrad, double& midrad, double& endrad, double& phit )
03804 {
03805 return ::CalcR( prev.m_x1, prev.m_y1, m_x2, m_y2, m_x1, m_y1,
03806 radius, center_x, center_y, beginrad, midrad, endrad, phit );
03807 }
03808
03809
03810
03811
03812
03813 #include <wx/arrimpl.cpp>
03814 WX_DEFINE_OBJARRAY( a2dVpathArray );
03815
03816
03817 a2dVpath::a2dVpath()
03818 {}
03819
03820 a2dVpath::a2dVpath( a2dVertexArray& vertexArray, bool moveToFirst, bool closeLast )
03821 {
03822 Add( vertexArray, moveToFirst, closeLast );
03823 }
03824
03825 a2dVpath::a2dVpath( a2dVertexList& vertexList, bool moveToFirst, bool closeLast )
03826 {
03827 Add( vertexList, moveToFirst, closeLast );
03828 }
03829
03830 a2dVpath::~a2dVpath()
03831 {}
03832
03833 a2dVpath& a2dVpath::operator=( const a2dVpath &other )
03834 {
03835 a2dVpathArray::Empty();
03836 unsigned int i;
03837 for ( i = 0; i < other.size();i++ )
03838 {
03839 a2dVpathSegment* seg = ( &( other.Item( i ) ) )->Clone();
03840 Add( seg );
03841 }
03842
03843 return *this;
03844 }
03845
03846 void a2dVpath::Add( a2dVertexArray& vertexArray, bool moveToFirst, bool closeLast )
03847 {
03848 unsigned int i;
03849 for ( i = 0; i < vertexArray.size();i++ )
03850 {
03851 a2dLineSegmentPtr seg = vertexArray.Item( i );
03852 a2dPATHSEG_END close = a2dPATHSEG_END_OPEN;
03853 if ( i == vertexArray.size() - 1 && closeLast )
03854 close = a2dPATHSEG_END_CLOSED;
03855 if ( seg->GetArc() )
03856 {
03857 a2dArcSegment* cseg = ( a2dArcSegment* ) seg.Get();
03858 a2dVpathArcSegment* segn = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, ( moveToFirst && i == 0 ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_ARCTO, close );
03859 push_back( segn );
03860 }
03861 else
03862 {
03863 a2dVpathSegment* segn = new a2dVpathSegment( seg->m_x, seg->m_y, ( moveToFirst && i == 0 ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_LINETO, close );
03864 push_back( segn );
03865 }
03866 }
03867 }
03868
03869 void a2dVpath::Add( a2dVertexList& vertexList, bool moveToFirst, bool closeLast )
03870 {
03871 for( a2dVertexList::iterator iter = vertexList.begin(); iter != vertexList.end(); ++iter )
03872 {
03873 a2dLineSegment* seg = *iter;
03874 a2dPATHSEG_END close = a2dPATHSEG_END_OPEN;
03875 if ( *iter == vertexList.back() && closeLast )
03876 close = a2dPATHSEG_END_CLOSED;
03877 if ( seg->GetArc() )
03878 {
03879 a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
03880 a2dVpathArcSegment* segn = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, ( moveToFirst && iter == vertexList.begin() ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_ARCTO, close );
03881 push_back( segn );
03882 }
03883 else
03884 {
03885 a2dVpathSegment* segn = new a2dVpathSegment( seg->m_x, seg->m_y, ( moveToFirst && iter == vertexList.begin() ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_LINETO, close );
03886 push_back( segn );
03887 }
03888 }
03889 }
03890
03891 void a2dVpath::MoveTo( double x, double y )
03892 {
03893 a2dVpathSegment * seg = new a2dVpathSegment( x, y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN );
03894 Add( seg );
03895 }
03896
03897 void a2dVpath::LineTo( double x, double y, bool withStroke )
03898 {
03899 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_LINETO : a2dPATHSEG_LINETO_NOSTROKE;
03900 a2dVpathSegment *seg = new a2dVpathSegment( x, y, cmd );
03901 Add( seg );
03902 }
03903
03904 void a2dVpath::QBCurveTo( double x1, double y1, double x2, double y2, bool withStroke )
03905 {
03906 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_QBCURVETO : a2dPATHSEG_QBCURVETO_NOSTROKE;
03907 a2dVpathQBCurveSegment *seg =
03908 new a2dVpathQBCurveSegment( x1, y1, x2, y2, cmd );
03909 Add( seg );
03910 }
03911
03912 void a2dVpath::QBCurveTo( double x1, double y1, bool withStroke )
03913 {
03914 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_QBCURVETO : a2dPATHSEG_QBCURVETO_NOSTROKE;
03915 a2dVpathQBCurveSegment *seg = new a2dVpathQBCurveSegment(
03916 Last(), x1, y1, cmd );
03917 Add( seg );
03918 }
03919
03920 void a2dVpath::CBCurveTo( double x1, double y1, double x2, double y2, double x3, double y3, bool withStroke )
03921 {
03922 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_CBCURVETO : a2dPATHSEG_CBCURVETO_NOSTROKE;
03923 a2dVpathCBCurveSegment *seg = new a2dVpathCBCurveSegment(
03924 x1, y1, x2, y2, x3, y3, cmd );
03925 Add( seg );
03926 }
03927
03928 void a2dVpath::CBCurveTo( double x1, double y1, double x3, double y3, bool withStroke )
03929 {
03930 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_CBCURVETO : a2dPATHSEG_CBCURVETO_NOSTROKE;
03931 a2dVpathCBCurveSegment *seg = new a2dVpathCBCurveSegment(
03932 Last(), x1, y1, x3, y3, cmd );
03933 Add( seg );
03934 }
03935
03936 void a2dVpath::ArcTo( double x1, double y1, double x2, double y2, bool withStroke )
03937 {
03938 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_ARCTO : a2dPATHSEG_ARCTO_NOSTROKE;
03939 a2dVpathArcSegment *seg = new a2dVpathArcSegment(
03940 x1, y1, x2, y2, cmd );
03941 Add( seg );
03942 }
03943
03944 void a2dVpath::ArcTo( double xc, double yc, double angle, bool withStroke )
03945 {
03946 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_ARCTO : a2dPATHSEG_ARCTO_NOSTROKE;
03947 a2dVpathArcSegment *seg = new a2dVpathArcSegment(
03948 Last(), xc, yc, angle, cmd );
03949 Add( seg );
03950 }
03951
03952 void a2dVpath::ArcTo( double xc, double yc, double x1, double y1, double x2, double y2, bool withStroke )
03953 {
03954 a2dPATHSEG cmd = withStroke ? a2dPATHSEG_ARCTO : a2dPATHSEG_ARCTO_NOSTROKE;
03955 a2dVpathArcSegment *seg = new a2dVpathArcSegment(
03956 Last(), xc, yc, x1, y1, x2, y2, cmd );
03957 Add( seg );
03958 }
03959
03960 void a2dVpath::Close( bool withStroke )
03961 {
03962 if ( !GetCount() )
03963 {
03964 return;
03965 }
03966 Last().SetClose( withStroke ? a2dPATHSEG_END_CLOSED : a2dPATHSEG_END_CLOSED_NOSTROKE );
03967 }
03968
03969
03970 double a2dVpath::Length()
03971 {
03972 double len = 0;
03973 unsigned int i;
03974 for ( i = 1; i < size();i++ )
03975 {
03976 len = len + Item( i ).Length( Item( i - 1 ) );
03977 }
03978
03979 return len;
03980 }
03981
03982 bool a2dVpath::IsPolygon( bool allowArc )
03983 {
03984 if ( GetCount() && Item( GetCount()-1 ).GetClose() != a2dPATHSEG_END_CLOSED )
03985 return false;
03986 unsigned int i;
03987 for (i = 0; i < GetCount(); i++)
03988 {
03989 a2dVpathSegment& seg = Item(i);
03990 switch ( seg.GetType() )
03991 {
03992 case a2dPATHSEG_MOVETO:
03993 if ( i != 0 )
03994 return false;
03995 case a2dPATHSEG_LINETO:
03996 case a2dPATHSEG_ARCTO:
03997 if ( !allowArc )
03998 return false;
03999 break;
04000 default:
04001 return false;
04002 }
04003 }
04004 return true;
04005 }
04006
04007 bool a2dVpath::IsPolyline( bool allowArc )
04008 {
04009 if ( GetCount() && Item( GetCount()-1 ).GetClose() != a2dPATHSEG_END_OPEN )
04010 return false;
04011 unsigned int i;
04012 for (i = 0; i < GetCount(); i++)
04013 {
04014 a2dVpathSegment& seg = Item(i);
04015 switch ( seg.GetType() )
04016 {
04017 case a2dPATHSEG_MOVETO:
04018 if ( i != 0 )
04019 return false;
04020 case a2dPATHSEG_LINETO:
04021 case a2dPATHSEG_ARCTO:
04022 if ( !allowArc )
04023 return false;
04024 break;
04025 default:
04026 return false;
04027 }
04028 }
04029 return true;
04030 }
04031
04032 void a2dVpath::Transform( const a2dAffineMatrix& cworld )
04033 {
04034 if ( !cworld.IsIdentity() )
04035 {
04036 if ( !cworld.IsTranslate() )
04037 ConvertToLines();
04038
04039 unsigned int i;
04040 for ( i = 0; i < size();i++ )
04041 {
04042 a2dVpathSegment& seg = Item( i );
04043 switch ( seg.GetType() )
04044 {
04045 case a2dPATHSEG_CBCURVETO_NOSTROKE:
04046 case a2dPATHSEG_CBCURVETO:
04047 {
04048 a2dVpathCBCurveSegment & cseg = ( a2dVpathCBCurveSegment& ) seg;
04049 cworld.TransformPoint( cseg.m_x2, cseg.m_y2, cseg.m_x2, cseg.m_y2 );
04050 cworld.TransformPoint( cseg.m_x3, cseg.m_y3, cseg.m_x3, cseg.m_y3 );
04051 }
04052 break;
04053
04054 case a2dPATHSEG_QBCURVETO_NOSTROKE:
04055 case a2dPATHSEG_QBCURVETO:
04056 {
04057 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
04058 cworld.TransformPoint( cseg.m_x2, cseg.m_y2, cseg.m_x2, cseg.m_y2 );
04059 }
04060 break;
04061
04062 case a2dPATHSEG_ARCTO_NOSTROKE:
04063 case a2dPATHSEG_ARCTO:
04064 {
04065 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
04066 cworld.TransformPoint( cseg.m_x2, cseg.m_y2, cseg.m_x2, cseg.m_y2 );
04067 }
04068 break;
04069 default:
04070 break;
04071 }
04072
04073 cworld.TransformPoint( seg.m_x1, seg.m_y1, seg.m_x1, seg.m_y1 );
04074 }
04075 }
04076 }
04077
04078 a2dBoundingBox a2dVpath::GetBbox( const a2dAffineMatrix& lworld )
04079 {
04080 a2dBoundingBox bbox;
04081 double x,y;
04082 unsigned int i;
04083 for (i=0; i < GetCount();i++)
04084 {
04085 a2dVpathSegment& seg = Item(i);
04086 switch ( seg.GetType() )
04087 {
04088 case a2dPATHSEG_CBCURVETO:
04089 case a2dPATHSEG_CBCURVETO_NOSTROKE:
04090 {
04091 a2dVpathCBCurveSegment& cseg = (a2dVpathCBCurveSegment&) seg;
04092 lworld.TransformPoint( cseg.m_x2, cseg.m_y2, x, y );
04093 bbox.Expand( x, y );
04094 lworld.TransformPoint( cseg.m_x3, cseg.m_y3, x, y );
04095 bbox.Expand( x, y );
04096 }
04097 break;
04098
04099 case a2dPATHSEG_QBCURVETO:
04100 case a2dPATHSEG_QBCURVETO_NOSTROKE:
04101 {
04102 a2dVpathQBCurveSegment& cseg = (a2dVpathQBCurveSegment&) seg;
04103 lworld.TransformPoint( cseg.m_x2, cseg.m_y2, x, y );
04104 bbox.Expand( x, y );
04105 }
04106 break;
04107
04108 case a2dPATHSEG_ARCTO:
04109 case a2dPATHSEG_ARCTO_NOSTROKE:
04110 {
04111 a2dVpathArcSegment& cseg = (a2dVpathArcSegment&) seg;
04112
04113 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
04114
04115
04116 if ( cseg.CalcR( Item(i? i-1: 0), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
04117 {
04118 lworld.TransformPoint( center_x + radius , center_y + radius, x, y );
04119 bbox.Expand( x, y );
04120 lworld.TransformPoint( center_x + radius , center_y - radius, x, y );
04121 bbox.Expand( x, y );
04122 lworld.TransformPoint( center_x - radius , center_y + radius, x, y );
04123 bbox.Expand( x, y );
04124 lworld.TransformPoint( center_x - radius , center_y - radius, x, y );
04125 bbox.Expand( x, y );
04126 }
04127
04128 lworld.TransformPoint( cseg.m_x2, cseg.m_y2, x, y );
04129 bbox.Expand( x, y );
04130 }
04131 break;
04132 default:
04133 break;
04134 }
04135 lworld.TransformPoint( Item(i).m_x1, Item(i).m_y1, x, y );
04136 bbox.Expand( x, y );
04137 }
04138 return bbox;
04139 }
04140
04141 void a2dVpath::ConvertToLines()
04142 {
04143 double xw, yw;
04144 bool nostroke = false;
04145 unsigned int i;
04146 a2dVpathSegment* segn;
04147 double tstep = 1 / ( double ) VPATHSPLINE_STEP;
04148
04149 for ( i = 0; i < size(); i++ )
04150 {
04151 a2dVpathSegment& seg = Item( i );
04152 switch ( seg.GetType() )
04153 {
04154 case a2dPATHSEG_CBCURVETO_NOSTROKE:
04155 nostroke = true;
04156 case a2dPATHSEG_CBCURVETO:
04157 {
04158 double xw, yw;
04159
04160 double xwl = Item( i ? i - 1 : 0 ).m_x1;
04161 double ywl = Item( i ? i - 1 : 0 ).m_y1;
04162 a2dVpathCBCurveSegment& cseg = ( a2dVpathCBCurveSegment& ) seg;
04163
04164 int step;
04165 double t = 0;
04166 for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
04167 {
04168 xw = xwl * pow( 1 - t, 3 ) + cseg.m_x2 * pow( 1 - t, 2 ) * t * 3 + cseg.m_x3 * ( 1 - t ) * t * t * 3 + cseg.m_x1 * pow( t, 3 );
04169 yw = ywl * pow( 1 - t, 3 ) + cseg.m_y2 * pow( 1 - t, 2 ) * t * 3 + cseg.m_y3 * ( 1 - t ) * t * t * 3 + cseg.m_y1 * pow( t, 3 );
04170 if ( !nostroke )
04171 segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO );
04172 else
04173 segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO_NOSTROKE );
04174
04175 if ( step == VPATHSPLINE_STEP )
04176 segn->m_close = seg.m_close;
04177
04178 Insert( segn, i++ );
04179 t = t + tstep;
04180 }
04181 RemoveAt( i-- );
04182 }
04183 break;
04184
04185 case a2dPATHSEG_QBCURVETO_NOSTROKE:
04186 nostroke = true;
04187 case a2dPATHSEG_QBCURVETO:
04188 {
04189 double xw, yw;
04190
04191 double xwl = Item( i ? i - 1 : 0 ).m_x1;
04192 double ywl = Item( i ? i - 1 : 0 ).m_y1;
04193 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
04194
04195 int step;
04196 double t = 0;
04197 for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
04198 {
04199 xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
04200 yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
04201 if ( !nostroke )
04202 segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO );
04203 else
04204 segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO_NOSTROKE );
04205
04206 if ( step == VPATHSPLINE_STEP )
04207 segn->m_close = seg.m_close;
04208
04209 Insert( segn, i++ );
04210 t = t + tstep;
04211 }
04212 RemoveAt( i-- );
04213 }
04214 break;
04215
04216 case a2dPATHSEG_ARCTO_NOSTROKE:
04217 nostroke = true;
04218 case a2dPATHSEG_ARCTO:
04219 {
04220 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
04221
04222 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
04223
04224 if ( cseg.CalcR( Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
04225 {
04226 double dphi;
04227 unsigned int segments;
04228 Aberration( radius/200, phit, radius , dphi, segments );
04229
04230
04231 double theta = beginrad;
04232 unsigned int step;
04233
04234 for ( step = 0; step < segments + 1; step++ )
04235 {
04236 xw = center_x + radius * cos ( theta );
04237 yw = center_y + radius * sin ( theta );
04238 if ( !nostroke )
04239 segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO );
04240 else
04241 segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO_NOSTROKE );
04242
04243 if ( step == segments )
04244 segn->m_close = seg.m_close;
04245
04246 Insert( segn, i++ );
04247 theta = theta + dphi;
04248 }
04249 }
04250 else
04251 {
04252 if ( !nostroke )
04253 segn = new a2dVpathSegment( cseg.m_x1, cseg.m_y1, a2dPATHSEG_LINETO );
04254 else
04255 segn = new a2dVpathSegment( cseg.m_x1, cseg.m_y1, a2dPATHSEG_LINETO_NOSTROKE );
04256
04257 segn->m_close = seg.m_close;
04258 Insert( segn, i++ );
04259 }
04260 RemoveAt( i-- );
04261 }
04262 break;
04263 default:
04264 break;
04265 }
04266 nostroke = false;
04267 }
04268 }
04269
04270 void a2dVpath::ConvertToPolygon( a2dListOfa2dVertexList& addTo, bool arc )
04271 {
04272 double xw, yw;
04273 bool nostroke = false;
04274 unsigned int i;
04275 double tstep = 1 / ( double ) VPATHSPLINE_STEP;
04276 a2dVertexList* result = NULL;
04277
04278 for ( i = 0; i < size(); i++ )
04279 {
04280 a2dVpathSegment& seg = Item( i );
04281 switch ( seg.GetType() )
04282 {
04283 case a2dPATHSEG_MOVETO:
04284 {
04285 result = new a2dVertexList();
04286 addTo.push_back( result );
04287
04288 result->push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
04289 break;
04290 }
04291 case a2dPATHSEG_LINETO:
04292 nostroke = true;
04293 case a2dPATHSEG_LINETO_NOSTROKE:
04294 {
04295 result->push_back( new a2dLineSegment( seg.m_x1, seg.m_y1 ) );
04296 }
04297 break;
04298 case a2dPATHSEG_CBCURVETO_NOSTROKE:
04299 nostroke = true;
04300 case a2dPATHSEG_CBCURVETO:
04301 {
04302 double xw, yw;
04303
04304 double xwl = Item( i ? i - 1 : 0 ).m_x1;
04305 double ywl = Item( i ? i - 1 : 0 ).m_y1;
04306 a2dVpathCBCurveSegment& cseg = ( a2dVpathCBCurveSegment& ) seg;
04307
04308 int step;
04309 double t = 0;
04310 for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
04311 {
04312 xw = xwl * pow( 1 - t, 3 ) + cseg.m_x2 * pow( 1 - t, 2 ) * t * 3 + cseg.m_x3 * ( 1 - t ) * t * t * 3 + cseg.m_x1 * pow( t, 3 );
04313 yw = ywl * pow( 1 - t, 3 ) + cseg.m_y2 * pow( 1 - t, 2 ) * t * 3 + cseg.m_y3 * ( 1 - t ) * t * t * 3 + cseg.m_y1 * pow( t, 3 );
04314 result->push_back( new a2dLineSegment( xw, yw ) );
04315 t = t + tstep;
04316 }
04317 }
04318 break;
04319
04320 case a2dPATHSEG_QBCURVETO_NOSTROKE:
04321 nostroke = true;
04322 case a2dPATHSEG_QBCURVETO:
04323 {
04324 double xw, yw;
04325
04326 double xwl = Item( i ? i - 1 : 0 ).m_x1;
04327 double ywl = Item( i ? i - 1 : 0 ).m_y1;
04328 a2dVpathQBCurveSegment& cseg = ( a2dVpathQBCurveSegment& ) seg;
04329
04330 int step;
04331 double t = 0;
04332 for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
04333 {
04334 xw = xwl * pow( 1 - t, 2 ) + cseg.m_x2 * ( 1 - t ) * t * 2 + cseg.m_x1 * pow( t, 2 );
04335 yw = ywl * pow( 1 - t, 2 ) + cseg.m_y2 * ( 1 - t ) * t * 2 + cseg.m_y1 * pow( t, 2 );
04336 result->push_back( new a2dLineSegment( xw, yw ) );
04337 t = t + tstep;
04338 }
04339 }
04340 break;
04341
04342 case a2dPATHSEG_ARCTO_NOSTROKE:
04343 nostroke = true;
04344 case a2dPATHSEG_ARCTO:
04345 {
04346 a2dVpathArcSegment& cseg = ( a2dVpathArcSegment& ) seg;
04347
04348 if ( arc )
04349 {
04350 double radius, center_x, center_y, beginrad, midrad, endrad, phit;
04351
04352 if ( cseg.CalcR( Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
04353 {
04354 double dphi;
04355 unsigned int segments;
04356 Aberration( radius/200, phit, radius , dphi, segments );
04357
04358
04359 double theta = beginrad;
04360 unsigned int step;
04361
04362 for ( step = 0; step < segments + 1; step++ )
04363 {
04364 xw = center_x + radius * cos ( theta );
04365 yw = center_y + radius * sin ( theta );
04366 result->push_back( new a2dLineSegment( xw, yw ) );
04367 theta = theta + dphi;
04368 }
04369 }
04370 else
04371 {
04372 result->push_back( new a2dLineSegment( cseg.m_x1, cseg.m_y1 ) );
04373 }
04374 }
04375 else
04376 result->push_back( new a2dArcSegment( cseg.m_x1, cseg.m_y1, cseg.m_x2, cseg.m_y2 ) );
04377 }
04378 break;
04379 default:
04380 break;
04381 }
04382 nostroke = false;
04383 }
04384 }
04385
04386 void a2dVpath::Contour( double distance, a2dPATH_END_TYPE pathtype )
04387 {
04388 ConvertToLines();
04389
04390 a2dVpath totalconverted;
04391 bool move = false;
04392
04393 if ( distance )
04394 {
04395 unsigned int i = 0;
04396 int subpartstart = 0;
04397 int subpartLength = 0;
04398 while ( i < size() )
04399 {
04400 a2dVpathSegment & seg = Item( i );
04401 switch ( seg.GetType() )
04402 {
04403 case a2dPATHSEG_MOVETO:
04404 {
04405 if ( i == 0 )
04406 subpartLength++;
04407 else
04408 move = true;
04409 break;
04410 }
04411 case a2dPATHSEG_LINETO:
04412 case a2dPATHSEG_LINETO_NOSTROKE:
04413 subpartLength++;
04414 break;
04415 default:
04416 break;
04417 }
04418
04419 if ( move )
04420 {
04421 SingleContour( totalconverted, subpartstart, subpartLength, distance, pathtype );
04422 move = false;
04423 subpartLength = 1;
04424 subpartstart = i;
04425 }
04426 i++;
04427 }
04428
04429 if ( subpartLength )
04430 {
04431 SingleContour( totalconverted, subpartstart, subpartLength, distance, pathtype );
04432 }
04433
04434 *this = totalconverted;
04435 }
04436 }
04437
04438 void a2dVpath::SingleContour( a2dVpath& converted, unsigned int start, unsigned int segments, double distance, a2dPATH_END_TYPE pathtype )
04439 {
04440
04441 a2dPoint2D _first;
04442 a2dPoint2D _middle;
04443 a2dPoint2D _end;
04444 a2dPoint2D offsetpointleft;
04445 a2dPoint2D offsetpointright;
04446
04447 unsigned int insertAt = converted.size();
04448
04449
04450 a2dVpathSegment seg = Item( start );
04451 if ( segments == 1 )
04452 {
04453 converted.Add( new a2dVpathSegment( seg.m_x1 - distance, seg.m_y1 , a2dPATHSEG_MOVETO, seg.GetClose() ) );
04454 switch ( pathtype )
04455 {
04456 case a2dPATH_END_SQAURE:
04457 {
04458
04459 }
04460 break;
04461 case a2dPATH_END_ROUND:
04462 {
04463 a2dVpathSegment* segn = new a2dVpathArcSegment( seg.m_x1 + distance, seg.m_y1,
04464 seg.m_x1 - distance, seg.m_y1, a2dPATHSEG_ARCTO, a2dPATHSEG_END_OPEN );
04465
04466 converted.Add( segn );
04467 }
04468 break;
04469 case a2dPATH_END_SQAURE_EXT:
04470 {
04471
04472 }
04473 break;
04474 default:
04475 break;
04476 }
04477 return;
04478 }
04479 else
04480 {
04481
04482 _first = a2dPoint2D( seg.m_x1, seg.m_y1 );
04483 a2dVpathSegment& segnext = Item( start + 1 );
04484 _middle = a2dPoint2D( segnext.m_x1, segnext.m_y1 );
04485 a2dLine line1( _first, _middle );
04486 line1.CalculateLineParameters();
04487 offsetpointleft = _first;
04488 offsetpointright = _first;
04489 line1.Virtual_Point( offsetpointleft, distance );
04490 line1.Virtual_Point( offsetpointright, -distance );
04491
04492 switch ( pathtype )
04493 {
04494 case a2dPATH_END_SQAURE:
04495 {
04496 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
04497 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
04498 }
04499 break;
04500 case a2dPATH_END_ROUND:
04501 {
04502 a2dLine lineoffset( offsetpointright, offsetpointleft );
04503 lineoffset.CalculateLineParameters();
04504 a2dPoint2D offsetpointfirst;
04505
04506 offsetpointfirst = _first;
04507 lineoffset.Virtual_Point( offsetpointfirst, distance );
04508 converted.Add( new a2dVpathArcSegment( offsetpointleft.m_x, offsetpointleft.m_y,
04509 offsetpointfirst.m_x, offsetpointfirst.m_y,
04510 a2dPATHSEG_ARCTO, a2dPATHSEG_END_OPEN ) );
04511 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
04512 break;
04513 }
04514 case a2dPATH_END_SQAURE_EXT:
04515 {
04516 a2dLine lineoffset( offsetpointright, offsetpointleft );
04517 lineoffset.CalculateLineParameters();
04518 lineoffset.Virtual_Point( offsetpointleft, distance );
04519 lineoffset.Virtual_Point( offsetpointright, distance );
04520
04521 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
04522 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
04523 break;
04524 }
04525 default:
04526 break;
04527 }
04528
04529 }
04530
04531
04532 unsigned int i;
04533 for ( i = start + 1; i < start + segments - 1; i++ )
04534 {
04535 a2dVpathSegment& seg = Item( i - 1 );
04536 _first = a2dPoint2D( seg.m_x1, seg.m_y1 );
04537 a2dVpathSegment& segnext = Item( i );
04538 _middle = a2dPoint2D( segnext.m_x1, segnext.m_y1 );
04539 a2dLine line1( _first, _middle );
04540 a2dVpathSegment& segend = Item( i + 1 );
04541 _end = a2dPoint2D( segend.m_x1, segend.m_y1 );
04542 a2dLine line2( _middle, _end );
04543 line1.CalculateLineParameters();
04544 line2.CalculateLineParameters();
04545
04546 OUTPRODUCT _outproduct;
04547 _outproduct = line1.OutProduct( line2, 1e-9 );
04548
04549 switch ( _outproduct )
04550 {
04551
04552 case R_IS_RIGHT :
04553 {
04554 line1.OffsetContour( line2, distance, offsetpointleft );
04555 line1.OffsetContour( line2, -distance, offsetpointright );
04556 }
04557 break;
04558 case R_IS_LEFT :
04559 {
04560 line1.OffsetContour( line2, distance, offsetpointleft );
04561 line1.OffsetContour( line2, -distance, offsetpointright );
04562 }
04563 break;
04564
04565 case R_IS_ON :
04566 {
04567 offsetpointleft = _middle;
04568 offsetpointright = _middle;
04569 line1.Virtual_Point( offsetpointleft, distance );
04570 line1.Virtual_Point( offsetpointright, -distance );
04571 }
04572 break;
04573 default:
04574 wxFAIL_MSG( wxT( "wrong line code" ) );
04575 break;
04576 }
04577
04578 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
04579 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
04580 }
04581
04582 seg = Item( i - 1 );
04583 a2dVpathSegment segnext = Item( i );
04584
04585 if ( segnext.GetClose() == a2dPATHSEG_END_CLOSED )
04586 {
04587 _first = a2dPoint2D( seg.m_x1, seg.m_y1 );
04588 _middle = a2dPoint2D( segnext.m_x1, segnext.m_y1 );
04589 a2dLine line1( _first, _middle );
04590 a2dVpathSegment segend = Item( i - segments + 1 );
04591 _end = a2dPoint2D( segend.m_x1, segend.m_y1 );
04592 a2dLine line2( _middle, _end );
04593 line1.CalculateLineParameters();
04594 line2.CalculateLineParameters();
04595
04596 OUTPRODUCT _outproduct;
04597 _outproduct = line1.OutProduct( line2, 1e-9 );
04598
04599 switch ( _outproduct )
04600 {
04601
04602 case R_IS_RIGHT :
04603 {
04604 line1.OffsetContour( line2, distance, offsetpointleft );
04605 line1.OffsetContour( line2, -distance, offsetpointright );
04606 }
04607 break;
04608 case R_IS_LEFT :
04609 {
04610 line1.OffsetContour( line2, distance, offsetpointleft );
04611 line1.OffsetContour( line2, -distance, offsetpointright );
04612 }
04613 break;
04614
04615 case R_IS_ON :
04616 {
04617 offsetpointleft = _middle;
04618 offsetpointright = _middle;
04619 line1.Virtual_Point( offsetpointleft, distance );
04620 line1.Virtual_Point( offsetpointright, -distance );
04621 }
04622 break;
04623 default:
04624 wxFAIL_MSG( wxT( "wrong line code" ) );
04625 break;
04626 }
04627
04628 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
04629 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
04630
04631 seg = Item( i );
04632 segnext = Item( i - segments + 1 );
04633 }
04634
04635
04636
04637 {
04638
04639 _first = a2dPoint2D( seg.m_x1, seg.m_y1 );
04640 _end = a2dPoint2D( segnext.m_x1, segnext.m_y1 );
04641 a2dLine line1( _first, _end );
04642 line1.CalculateLineParameters();
04643 offsetpointleft = _end;
04644 offsetpointright = _end;
04645 line1.Virtual_Point( offsetpointleft, distance );
04646 line1.Virtual_Point( offsetpointright, -distance );
04647
04648 switch ( pathtype )
04649 {
04650 case a2dPATH_END_SQAURE:
04651 {
04652 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED ) );
04653 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN ), insertAt );
04654 }
04655 break;
04656 case a2dPATH_END_ROUND:
04657 {
04658 a2dLine lineoffset( offsetpointleft, offsetpointright );
04659 lineoffset.CalculateLineParameters();
04660 a2dPoint2D offsetpointend;
04661
04662 offsetpointend = _end;
04663 lineoffset.Virtual_Point( offsetpointend, distance );
04664 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
04665 converted.Add( new a2dVpathArcSegment( offsetpointright.m_x, offsetpointright.m_y,
04666 offsetpointend.m_x, offsetpointend.m_y,
04667 a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED ) );
04668 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN ), insertAt );
04669 break;
04670 }
04671 case a2dPATH_END_SQAURE_EXT:
04672 {
04673 a2dLine lineoffset( offsetpointright, offsetpointleft );
04674 lineoffset.CalculateLineParameters();
04675 lineoffset.Virtual_Point( offsetpointleft, -distance );
04676 lineoffset.Virtual_Point( offsetpointright, -distance );
04677
04678 converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED ) );
04679 converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN ), insertAt );
04680 break;
04681 }
04682 default:
04683 break;
04684 }
04685 }
04686 }
04687
04688
04689
04690
04691
04692
04693
04694
04695
04696
04697
04698
04699
04700
04701
04702
04703
04704
04705 #define half(z1, z2) ((z1+z2)/2.0)
04706
04707
04708
04709 static void gds_quadratic_spline( a2dVertexList*org, double a1, double b1, double a2, double b2, double a3, double b3, double a4,
04710 double b4, double Aber )
04711 {
04712 register double xmid, ymid;
04713 double x1, y1, x2, y2, x3, y3, x4, y4;
04714 a2dLineSegment* point;
04715
04716 gds_clear_stack();
04717 gds_spline_push( a1, b1, a2, b2, a3, b3, a4, b4 );
04718
04719 while ( gds_spline_pop( &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4 ) )
04720 {
04721 xmid = half( x2, x3 );
04722 ymid = half( y2, y3 );
04723 if ( fabs( x1 - xmid ) < Aber && fabs( y1 - ymid ) < Aber &&
04724 fabs( xmid - x4 ) < Aber && fabs( ymid - y4 ) < Aber )
04725 {
04726 point = new a2dLineSegment( x1, y1 );
04727 org->push_back( point );
04728 point = new a2dLineSegment( xmid, ymid );
04729 org->push_back( point );
04730 }
04731 else
04732 {
04733 gds_spline_push( xmid, ymid, half( xmid, x3 ), half( ymid, y3 ),
04734 half( x3, x4 ), half( y3, y4 ), x4, y4 );
04735 gds_spline_push( x1, y1, half( x1, x2 ), half( y1, y2 ),
04736 half( x2, xmid ), half( y2, ymid ), xmid, ymid );
04737 }
04738 }
04739 }
04740
04741 bool CalcR( double begin_x, double begin_y, double middle_x, double middle_y, double end_x, double end_y,
04742 double& radius, a2dPoint2D& center_p )
04743 {
04744 double center_x,center_y, beginrad, midrad, endrad, phit;
04745 bool ret = CalcR( begin_x, begin_y, middle_x, middle_y, end_x, end_y,
04746 radius, center_x, center_y, beginrad, midrad, endrad, phit );
04747 center_p.m_x = center_x;
04748 center_p.m_y = center_y;
04749 return ret;
04750 }
04751
04752 bool CalcR( double begin_x, double begin_y, double middle_x, double middle_y, double end_x, double end_y,
04753 double& radius, double& center_x, double& center_y, double& beginrad, double& midrad, double& endrad, double& phit )
04754 {
04755 double ax, ay, bx, by, cx, cy;
04756 double ax2, ay2, bx2, by2, cx2, cy2;
04757 double d;
04758 bool straight = false;
04759
04760 ax = begin_x; ay = begin_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
04761 bx = middle_x; by = middle_y; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
04762 cx = end_x; cy = end_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
04763
04764 if ( fabs(ax - cx) < a2dACCUR && fabs(ay - cy) < a2dACCUR )
04765 {
04766
04767 center_x = (bx + ax) / 2.0;
04768 center_y = (by + ay) / 2.0;
04769 radius = sqrt( pow( bx - ax, 2 ) + pow( by - ay, 2 ) )/2.0;
04770 }
04771 else
04772 {
04773 d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
04774
04775 if ( fabs( d ) < a2dACCUR )
04776 {
04777 d = a2dACCUR;
04778 straight = true;
04779 }
04780
04781 center_x = ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
04782 + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
04783 ) / d;
04784
04785 center_y = ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
04786 - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
04787 ) / d ;
04788
04789 radius = sqrt( pow( ax - center_x, 2 ) + pow( ay - center_y, 2 ) );
04790 }
04791
04792 if ( radius )
04793 {
04794
04795 beginrad = atan2( begin_y - center_y, begin_x - center_x );
04796 midrad = atan2( middle_y - center_y, middle_x - center_x );
04797 endrad = atan2( end_y - center_y, end_x - center_x );
04798
04799 double mr,er;
04800
04801
04802
04803
04804
04805 mr = midrad - beginrad;
04806 er = endrad - beginrad;
04807
04808
04809 if ( mr<=0 ) mr += 2.0*M_PI;
04810 if ( er<=0 ) er += 2.0*M_PI;
04811 if ( mr>=2.0*M_PI ) mr -= 2.0*M_PI;
04812 if ( er>=2.0*M_PI ) er -= 2.0*M_PI;
04813
04814 bool counterclock;
04815
04816
04817 if (mr < er)
04818 {
04819 phit = er;
04820 counterclock = true;
04821 }
04822 else
04823 {
04824 phit = -( 2.0*M_PI - er );
04825 counterclock = false;
04826 }
04827 }
04828 else
04829 {
04830 beginrad = 0;
04831 midrad = 0;
04832 endrad = 0;
04833 }
04834
04835 return !straight;
04836 }
04837
04838
04839
04840
04841 typedef struct gds_spline_stack_struct
04842 {
04843 double x1, y1, x2, y2, x3, y3, x4, y4;
04844 }
04845 Stack;
04846
04847 #define SPLINE_STACK_DEPTH 20
04848 static Stack gds_spline_stack[SPLINE_STACK_DEPTH];
04849 static Stack *gds_stack_top;
04850 static int gds_stack_count;
04851
04852 static void gds_clear_stack()
04853 {
04854 gds_stack_top = gds_spline_stack;
04855 gds_stack_count = 0;
04856 }
04857
04858 static void gds_spline_push( double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4 )
04859 {
04860 gds_stack_top->x1 = x1;
04861 gds_stack_top->y1 = y1;
04862 gds_stack_top->x2 = x2;
04863 gds_stack_top->y2 = y2;
04864 gds_stack_top->x3 = x3;
04865 gds_stack_top->y3 = y3;
04866 gds_stack_top->x4 = x4;
04867 gds_stack_top->y4 = y4;
04868 gds_stack_top++;
04869 gds_stack_count++;
04870 }
04871
04872 static int gds_spline_pop( double *x1, double *y1, double *x2, double *y2,
04873 double *x3, double *y3, double *x4, double *y4 )
04874 {
04875 if ( gds_stack_count == 0 )
04876 return ( 0 );
04877 gds_stack_top--;
04878 gds_stack_count--;
04879 *x1 = gds_stack_top->x1;
04880 *y1 = gds_stack_top->y1;
04881 *x2 = gds_stack_top->x2;
04882 *y2 = gds_stack_top->y2;
04883 *x3 = gds_stack_top->x3;
04884 *y3 = gds_stack_top->y3;
04885 *x4 = gds_stack_top->x4;
04886 *y4 = gds_stack_top->y4;
04887 return ( 1 );
04888 }