00001
00021 #include "coordinate_system.h"
00022
00023 #include "../kig/kig_document.h"
00024 #include "../kig/kig_view.h"
00025
00026 #include "common.h"
00027 #include "coordinate.h"
00028 #include "goniometry.h"
00029 #include "kigpainter.h"
00030
00031 #include <qpainter.h>
00032 #include <qregexp.h>
00033
00034 #include <kdebug.h>
00035 #include <kglobal.h>
00036 #include <klocale.h>
00037 #include <knumvalidator.h>
00038
00039 #include <string>
00040 #include <math.h>
00041
00042 static QString withoutSpaces( const QString& str )
00043 {
00044 QString newstr;
00045 int s = str.size();
00046 for ( int i = 0; i < s; ++i )
00047 if ( !str.at( i ).isSpace() )
00048 newstr.append( str.at( i ) );
00049 return newstr;
00050 }
00051
00052
00053 class CoordinateValidator
00054 : public QValidator
00055 {
00056 bool mpolar;
00057 KDoubleValidator mdv;
00058 mutable QRegExp mre;
00059 public:
00060 static const char reEuclidean[];
00061 static const char rePolar[];
00062
00063 CoordinateValidator( bool polar );
00064 ~CoordinateValidator();
00065 State validate ( QString & input, int & pos ) const;
00066 void fixup ( QString & input ) const;
00067 };
00068
00069 const char CoordinateValidator::reEuclidean[] = "\\s*\\(?\\s*([0-9.,+-]+)\\s*;\\s*([0-9.,+-]+)\\s*\\)?\\s*";
00070 const char CoordinateValidator::rePolar[] = "\\s*\\(?\\s*([0-9.,+-]+)\\s*;\\s*([0-9.,+-]+) ?°?\\s*\\)?\\s*";
00071
00072 CoordinateValidator::CoordinateValidator( bool polar )
00073 : QValidator( 0L ), mpolar( polar ), mdv( 0L ),
00074 mre( QString::fromUtf8( polar ? rePolar : reEuclidean ) )
00075 {
00076 }
00077
00078 CoordinateValidator::~CoordinateValidator()
00079 {
00080 }
00081
00082 QValidator::State CoordinateValidator::validate( QString & input, int & pos ) const
00083 {
00084 QString tinput = withoutSpaces( input );
00085 if ( tinput.isEmpty() )
00086 return Invalid;
00087 if ( tinput.at( tinput.length() - 1 ) == ')' ) tinput.truncate( tinput.length() - 1 );
00088 if ( mpolar )
00089 {
00090
00091 if ( !tinput.isEmpty() && tinput.at( tinput.length() - 1 ).unicode() == 176 )
00092 tinput.truncate( tinput.length() - 1 );
00093 };
00094 if ( tinput[0] == '(' ) tinput = tinput.mid( 1 );
00095 int scp = tinput.indexOf( ';' );
00096 if ( scp == -1 ) return mdv.validate( tinput, pos ) == Invalid ? Invalid : Intermediate;
00097 else
00098 {
00099 QString p1 = tinput.left( scp );
00100 QString p2 = tinput.mid( scp + 1 );
00101
00102 State ret = Acceptable;
00103
00104 int boguspos = 0;
00105 ret = kigMin( ret, mdv.validate( p1, boguspos ) );
00106
00107 boguspos = 0;
00108 ret = kigMin( ret, mdv.validate( p2, boguspos ) );
00109
00110 return ret;
00111 };
00112 }
00113
00114 void CoordinateValidator::fixup( QString & input ) const
00115 {
00116 int nsc = input.count( ';' );
00117 if ( nsc > 1 )
00118 {
00119
00120 int i = input.indexOf( ';' );
00121 i = input.indexOf( ';', i );
00122 input = input.left( i );
00123 };
00124
00125 int sc = input.indexOf( ';' );
00126 if ( sc == -1 )
00127 {
00128 sc = input.length();
00129 KLocale* l = KGlobal::locale();
00130 if ( mpolar )
00131 input.append( QString::fromLatin1( ";" ) + l->positiveSign() +
00132 QString::fromLatin1( "0" ) );
00133 else
00134 input.append( QString::fromLatin1( ";" ) + l->positiveSign() +
00135 QString::fromLatin1( "0" ) + l->decimalSymbol() +
00136 QString::fromLatin1( "0" ) );
00137 };
00138 mre.exactMatch( input );
00139 QString ds1 = mre.cap( 1 );
00140 mdv.fixup( ds1 );
00141 QString ds2 = mre.cap( 2 );
00142 mdv.fixup( ds2 );
00143 input = ds1 + QString::fromLatin1( "; " ) + ds2;
00144 }
00145
00146 EuclideanCoords::EuclideanCoords()
00147 {
00148 }
00149
00150 QString EuclideanCoords::fromScreen( const Coordinate& p, const KigDocument& d ) const
00151 {
00152
00153
00154
00155
00156 Rect sr = d.suggestedRect();
00157 double m = kigMax( sr.width(), sr.height() );
00158 int l = kigMax( 0, (int) ( 3 - log10( m ) ) );
00159 QString xs = KGlobal::locale()->formatNumber( p.x, l );
00160 QString ys = KGlobal::locale()->formatNumber( p.y, l );
00161 return QString::fromLatin1( "( %1; %2 )" ).arg( xs ).arg( ys );
00162 }
00163
00164 Coordinate EuclideanCoords::toScreen(const QString& s, bool& ok) const
00165 {
00166 QRegExp r( QString::fromUtf8( CoordinateValidator::reEuclidean ) );
00167 ok = ( r.indexIn(s) == 0 );
00168 if (ok)
00169 {
00170 QString xs = r.cap(1);
00171 QString ys = r.cap(2);
00172 KLocale* l = KGlobal::locale();
00173 double x = l->readNumber( xs, &ok );
00174 if ( ! ok ) x = xs.toDouble( &ok );
00175 if ( ! ok ) return Coordinate();
00176 double y = l->readNumber( ys, &ok );
00177 if ( ! ok ) y = ys.toDouble( &ok );
00178 if ( ! ok ) return Coordinate();
00179 return Coordinate( x, y );
00180 }
00181 return Coordinate();
00182 }
00183
00191 static double nicenum( double x, bool round )
00192 {
00193 int exp = (int) log10( x );
00194 double f = x/pow( 10., exp );
00195 double nf;
00196 if ( round )
00197 {
00198 if ( f < 1.5 ) nf = 1.;
00199 else if ( f < 3. ) nf = 2.;
00200 else if ( f < 7. ) nf = 5.;
00201 else nf = 10.;
00202 }
00203 else
00204 {
00205 if ( f <= 1. ) nf = 1.;
00206 else if ( f <= 2. ) nf = 2.;
00207 else if ( f <= 5. ) nf = 5.;
00208 else nf = 10.;
00209 };
00210 return nf * pow( 10., exp );
00211 }
00212
00213 void EuclideanCoords::drawGrid( KigPainter& p, bool showgrid, bool showaxes ) const
00214 {
00215 p.setWholeWinOverlay();
00216
00217
00218
00219 if ( !( showgrid || showaxes ) )
00220 return;
00221
00222
00223
00224
00225
00226 const double hmax = ceil( p.window().right() );
00227 const double hmin = floor( p.window().left() );
00228 const double vmax = ceil( p.window().top() );
00229 const double vmin = floor( p.window().bottom() );
00230
00231
00232
00233 const int ntick = static_cast<int>(
00234 kigMax( hmax - hmin, vmax - vmin ) / p.pixelWidth() / 40. ) + 1;
00235
00236 double hrange = nicenum( hmax - hmin, false );
00237 double vrange = nicenum( vmax - vmin, false );
00238 const double newrange = kigMin( hrange, vrange );
00239 hrange = newrange;
00240 vrange = newrange;
00241
00242 const double hd = nicenum( hrange / ( ntick - 1 ), true );
00243 const double vd = nicenum( vrange / ( ntick - 1 ), true );
00244
00245 const double hgraphmin = ceil( hmin / hd) * hd;
00246 const double hgraphmax = floor( hmax / hd ) * hd;
00247 const double vgraphmin = ceil( vmin / vd ) * vd;
00248 const double vgraphmax = floor( vmax / vd ) * vd;
00249
00250 const int hnfrac = kigMax( (int) - floor( log10( hd ) ), 0 );
00251 const int vnfrac = kigMax( (int) - floor( log10( vd ) ), 0 );
00252
00253
00254 if ( showgrid )
00255 {
00256 p.setPen( QPen( Qt::lightGray, 0, Qt::DotLine ) );
00257
00258 for ( double i = hgraphmin; i <= hgraphmax + hd/2; i += hd )
00259 p.drawSegment( Coordinate( i, vgraphmin ),
00260 Coordinate( i, vgraphmax ) );
00261
00262 for ( double i = vgraphmin; i <= vgraphmax + vd/2; i += vd )
00263 p.drawSegment( Coordinate( hgraphmin, i ),
00264 Coordinate( hgraphmax, i ) );
00265 }
00266
00267
00268 if ( showaxes )
00269 {
00270 p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00271
00272 p.drawSegment( Coordinate( hmin, 0 ), Coordinate( hmax, 0 ) );
00273
00274 p.drawSegment( Coordinate( 0, vmin ), Coordinate( 0, vmax ) );
00275
00276
00277
00278
00279 for( double i = hgraphmin; i <= hgraphmax + hd / 2; i += hd )
00280 {
00281
00282
00283 if( fabs( i ) < 1e-8 ) continue;
00284
00285 p.drawText(
00286 Rect( Coordinate( i, 0 ), hd, -2*vd ).normalized(),
00287 KGlobal::locale()->formatNumber( i, hnfrac ),
00288 Qt::AlignLeft | Qt::AlignTop
00289 );
00290 };
00291
00292 for ( double i = vgraphmin; i <= vgraphmax + vd/2; i += vd )
00293 {
00294 if( fabs( i ) < 1e-8 ) continue;
00295 p.drawText ( Rect( Coordinate( 0, i ), 2*hd, vd ).normalized(),
00296 KGlobal::locale()->formatNumber( i, vnfrac ),
00297 Qt::AlignBottom | Qt::AlignLeft
00298 );
00299 };
00300
00301 p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00302 p.setBrush( QBrush( Qt::gray ) );
00303 std::vector<Coordinate> a;
00304
00305
00306 a.reserve( 3 );
00307 double u = p.pixelWidth();
00308 a.push_back( Coordinate( hmax - 6 * u, -3 * u) );
00309 a.push_back( Coordinate( hmax, 0 ) );
00310 a.push_back( Coordinate( hmax - 6 * u, 3 * u ) );
00311 p.drawArea( a );
00312
00313
00314
00315 a.clear();
00316 a.reserve( 3 );
00317 a.push_back( Coordinate( 3 * u, vmax - 6 * u ) );
00318 a.push_back( Coordinate( 0, vmax ) );
00319 a.push_back( Coordinate( -3 * u, vmax - 6 * u ) );
00320 p.drawArea( a );
00321
00322 };
00323 }
00324
00325 QString EuclideanCoords::coordinateFormatNotice() const
00326 {
00327 return i18n( "Enter coordinates in the following format: \"x;y\",\n"
00328 "where x is the x coordinate, and y is the y coordinate." );
00329 }
00330
00331 QString EuclideanCoords::coordinateFormatNoticeMarkup() const
00332 {
00333 return i18n( "Enter coordinates in the following format: <b>\"x;y\"</b>,<br />"
00334 "where x is the x coordinate, and y is the y coordinate." );
00335 }
00336
00337 EuclideanCoords::~EuclideanCoords()
00338 {
00339 }
00340
00341 CoordinateSystem::~CoordinateSystem()
00342 {
00343 }
00344
00345 CoordinateSystem::CoordinateSystem()
00346 {
00347 }
00348
00349 PolarCoords::PolarCoords()
00350 {
00351 }
00352
00353 PolarCoords::~PolarCoords()
00354 {
00355 }
00356
00357 QString PolarCoords::fromScreen( const Coordinate& pt, const KigDocument& d ) const
00358 {
00359 Rect sr = d.suggestedRect();
00360 double m = kigMax( sr.width(), sr.height() );
00361 int l = kigMax( 0, (int) ( 3 - log10( m ) ) );
00362
00363 double r = pt.length();
00364 double theta = Goniometry::convert( atan2( pt.y, pt.x ), Goniometry::Rad, Goniometry::Deg );
00365
00366 QString rs = KGlobal::locale()->formatNumber( r, l );
00367 QString ts = KGlobal::locale()->formatNumber( theta, 0 );
00368
00369 return QString::fromLatin1("( %1; %2 )").arg( rs ).arg( ts );
00370 }
00371
00372 QString PolarCoords::coordinateFormatNotice() const
00373 {
00374
00375 return i18n( "Enter coordinates in the following format: \"r; \xCE\xB8°\",\n"
00376 "where r and \xCE\xB8 are the polar coordinates." );
00377 }
00378
00379 QString PolarCoords::coordinateFormatNoticeMarkup() const
00380 {
00381
00382 return i18n( "Enter coordinates in the following format: <b>\"r; \xCE\xB8°\"</b>,<br />"
00383 "where r and \xCE\xB8 are the polar coordinates." );
00384 }
00385
00386 Coordinate PolarCoords::toScreen(const QString& s, bool& ok) const
00387 {
00388 QRegExp regexp( QString::fromUtf8( CoordinateValidator::rePolar ) );
00389 ok = ( regexp.indexIn( s ) == 0 );
00390 if (ok)
00391 {
00392 QString rs = regexp.cap( 1 );
00393 double r = KGlobal::locale()->readNumber( rs, &ok );
00394 if ( ! ok ) r = rs.toDouble( &ok );
00395 if ( ! ok ) return Coordinate();
00396 QString ts = regexp.cap( 2 );
00397 double theta = KGlobal::locale()->readNumber( ts, &ok );
00398 if ( ! ok ) theta = ts.toDouble( &ok );
00399 if ( ! ok ) return Coordinate();
00400 theta *= M_PI;
00401 theta /= 180;
00402 return Coordinate( cos( theta ) * r, sin( theta ) * r );
00403 }
00404 else return Coordinate();
00405 }
00406
00407 void PolarCoords::drawGrid( KigPainter& p, bool showgrid, bool showaxes ) const
00408 {
00409 p.setWholeWinOverlay();
00410
00411
00412
00413 if ( !( showgrid || showaxes ) )
00414 return;
00415
00416
00417
00418
00419
00420 const double hmax = M_SQRT2*p.window().right();
00421 const double hmin = M_SQRT2*p.window().left();
00422 const double vmax = M_SQRT2*p.window().top();
00423 const double vmin = M_SQRT2*p.window().bottom();
00424
00425
00426
00427 const int ntick = static_cast<int>(
00428 kigMax( hmax - hmin, vmax - vmin ) / p.pixelWidth() / 40 ) + 1;
00429
00430 const double hrange = nicenum( hmax - hmin, false );
00431 const double vrange = nicenum( vmax - vmin, false );
00432
00433 const double hd = nicenum( hrange / ( ntick - 1 ), true );
00434 const double vd = nicenum( vrange / ( ntick - 1 ), true );
00435
00436 const double hgraphmin = floor( hmin / hd) * hd;
00437 const double hgraphmax = ceil( hmax / hd ) * hd;
00438 const double vgraphmin = floor( vmin / vd ) * vd;
00439 const double vgraphmax = ceil( vmax / vd ) * vd;
00440
00441 const int hnfrac = kigMax( (int) - floor( log10( hd ) ), 0 );
00442 const int vnfrac = kigMax( (int) - floor( log10( vd ) ), 0 );
00443 const int nfrac = kigMax( hnfrac, vnfrac );
00444
00445
00446 if ( showgrid )
00447 {
00448 double d = kigMin( hd, vd );
00449 double begin = kigMin( kigAbs( hgraphmin ), kigAbs( vgraphmin ) );
00450 if ( kigSgn( hgraphmin ) != kigSgn( hgraphmax ) && kigSgn( vgraphmin ) != kigSgn( vgraphmax ) )
00451 begin = d;
00452 double end = kigMax( hgraphmax, vgraphmax );
00453
00454
00455
00456 Coordinate c( 0, 0 );
00457 p.setPen( QPen( Qt::lightGray, 0, Qt::DotLine ) );
00458 for ( double i = begin; i <= end + d / 2; i += d )
00459 drawGridLine( p, c, fabs( i ) );
00460 }
00461
00462
00463 if ( showaxes )
00464 {
00465 p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00466
00467 p.drawSegment( Coordinate( hmin, 0 ), Coordinate( hmax, 0 ) );
00468
00469 p.drawSegment( Coordinate( 0, vmin ), Coordinate( 0, vmax ) );
00470
00471
00472
00473
00474 for( double i = hgraphmin; i <= hgraphmax + hd / 2; i += hd )
00475 {
00476
00477
00478 if( fabs( i ) < 1e-8 ) continue;
00479
00480 QString is = KGlobal::locale()->formatNumber( fabs( i ), nfrac );
00481 p.drawText(
00482 Rect( Coordinate( i, 0 ), hd, -2*vd ).normalized(),
00483 is, Qt::AlignLeft | Qt::AlignTop );
00484 };
00485
00486 for ( double i = vgraphmin; i <= vgraphmax + vd / 2; i += vd )
00487 {
00488 if( fabs( i ) < 1e-8 ) continue;
00489
00490 QString is = KGlobal::locale()->formatNumber( fabs( i ), nfrac );
00491
00492 p.drawText ( Rect( Coordinate( 0, i ), hd, vd ).normalized(),
00493 is, Qt::AlignBottom | Qt::AlignLeft
00494 );
00495 };
00496
00497 p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00498 p.setBrush( QBrush( Qt::gray ) );
00499 std::vector<Coordinate> a;
00500
00501
00502 a.reserve( 3 );
00503 double u = p.pixelWidth();
00504 a.push_back( Coordinate( hmax - 6 * u, -3 * u) );
00505 a.push_back( Coordinate( hmax, 0 ) );
00506 a.push_back( Coordinate( hmax - 6 * u, 3 * u ) );
00507
00508 p.drawArea( a );
00509
00510
00511 a.clear();
00512 a.reserve( 3 );
00513 a.push_back( Coordinate( 3 * u, vmax - 6 * u ) );
00514 a.push_back( Coordinate( 0, vmax ) );
00515 a.push_back( Coordinate( -3 * u, vmax - 6 * u ) );
00516
00517 p.drawArea( a );
00518 };
00519 }
00520
00521 QValidator* EuclideanCoords::coordinateValidator() const
00522 {
00523 return new CoordinateValidator( false );
00524 }
00525
00526 QValidator* PolarCoords::coordinateValidator() const
00527 {
00528 return new CoordinateValidator( true );
00529 }
00530
00531 QStringList CoordinateSystemFactory::names()
00532 {
00533 QStringList ret;
00534 ret << i18n( "&Euclidean" )
00535 << i18n( "&Polar" );
00536 return ret;
00537 }
00538
00539 CoordinateSystem* CoordinateSystemFactory::build( int which )
00540 {
00541 if ( which == Euclidean )
00542 return new EuclideanCoords;
00543 else if ( which == Polar )
00544 return new PolarCoords;
00545 else return 0;
00546 }
00547
00548 static const char euclideanTypeString[] = "Euclidean";
00549 static const char polarTypeString[] = "Polar";
00550
00551 CoordinateSystem* CoordinateSystemFactory::build( const char* type )
00552 {
00553 if ( std::string( euclideanTypeString ) == type )
00554 return new EuclideanCoords;
00555 if ( std::string( polarTypeString ) == type )
00556 return new PolarCoords;
00557 else return 0;
00558 }
00559
00560 const char* EuclideanCoords::type() const
00561 {
00562 return euclideanTypeString;
00563 }
00564
00565 const char* PolarCoords::type() const
00566 {
00567 return polarTypeString;
00568 }
00569
00570 int EuclideanCoords::id() const
00571 {
00572 return CoordinateSystemFactory::Euclidean;
00573 }
00574
00575 int PolarCoords::id() const
00576 {
00577 return CoordinateSystemFactory::Polar;
00578 }
00579
00580 QString CoordinateSystemFactory::setCoordinateSystemStatement( int id )
00581 {
00582 switch( id )
00583 {
00584 case Euclidean:
00585 return i18n( "Set Euclidean Coordinate System" );
00586 case Polar:
00587 return i18n( "Set Polar Coordinate System" );
00588 default:
00589 assert( false );
00590 return QString();
00591 }
00592 }
00593
00594 Coordinate EuclideanCoords::snapToGrid( const Coordinate& c,
00595 const KigWidget& w ) const
00596 {
00597 Rect rect = w.showingRect();
00598
00599
00600
00601
00602
00603
00604 const double hmax = rect.right();
00605 const double hmin = rect.left();
00606 const double vmax = rect.top();
00607 const double vmin = rect.bottom();
00608
00609
00610
00611 const int ntick = static_cast<int>(
00612 kigMax( hmax - hmin, vmax - vmin ) / w.pixelWidth() / 40. ) + 1;
00613
00614 const double hrange = nicenum( hmax - hmin, false );
00615 const double vrange = nicenum( vmax - vmin, false );
00616
00617 const double hd = nicenum( hrange / ( ntick - 1 ), true );
00618 const double vd = nicenum( vrange / ( ntick - 1 ), true );
00619
00620 const double hgraphmin = ceil( hmin / hd) * hd;
00621 const double vgraphmin = ceil( vmin / vd ) * vd;
00622
00623 const double nx = qRound( ( c.x - hgraphmin ) / hd ) * hd + hgraphmin;
00624 const double ny = qRound( ( c.y - vgraphmin ) / vd ) * vd + vgraphmin;
00625 return Coordinate( nx, ny );
00626 }
00627
00628 Coordinate PolarCoords::snapToGrid( const Coordinate& c,
00629 const KigWidget& w ) const
00630 {
00631
00632
00633
00634
00635
00636
00637 Rect r = w.showingRect();
00638
00639 const double hmax = M_SQRT2 * r.right();
00640 const double hmin = M_SQRT2 * r.left();
00641 const double vmax = M_SQRT2 * r.top();
00642 const double vmin = M_SQRT2 * r.bottom();
00643
00644
00645
00646 const int ntick = static_cast<int>(
00647 kigMax( hmax - hmin, vmax - vmin ) / w.pixelWidth() / 40 ) + 1;
00648
00649 const double hrange = nicenum( hmax - hmin, false );
00650 const double vrange = nicenum( vmax - vmin, false );
00651
00652 const double hd = nicenum( hrange / ( ntick - 1 ), true );
00653 const double vd = nicenum( vrange / ( ntick - 1 ), true );
00654
00655 double d = kigMin( hd, vd );
00656
00657 double dist = c.length();
00658 double ndist = qRound( dist / d ) * d;
00659 return c.normalize( ndist );
00660 }
00661
00662 void PolarCoords::drawGridLine( KigPainter& p, const Coordinate& c,
00663 double r ) const
00664 {
00665 #ifdef KIG_TESSELLATE_POLAR_GRID_CIRCLE
00666 Rect rect = p.window();
00667
00668 struct iterdata_t
00669 {
00670 int xd;
00671 int yd;
00672 Coordinate ( Rect::*point )() const;
00673 Coordinate ( Rect::*oppositepoint )() const;
00674 double horizAngle;
00675 double vertAngle;
00676 };
00677
00678 static const iterdata_t iterdata[] =
00679 {
00680 { +1, +1, &Rect::topRight, &Rect::bottomLeft, 0, M_PI/2 },
00681 { -1, +1, &Rect::topLeft, &Rect::bottomRight, M_PI, M_PI / 2 },
00682 { -1, -1, &Rect::bottomLeft, &Rect::topRight, M_PI, 3*M_PI/2 },
00683 { +1, -1, &Rect::bottomRight, &Rect::topLeft, 2*M_PI, 3*M_PI/2 }
00684 };
00685 for ( int i = 0; i < 4; ++i )
00686 {
00687 int xd = iterdata[i].xd;
00688 int yd = iterdata[i].yd;
00689 Coordinate point = ( rect.*iterdata[i].point )();
00690 Coordinate opppoint = ( rect.*iterdata[i].oppositepoint )();
00691 double horizangle = iterdata[i].horizAngle;
00692 double vertangle = iterdata[i].vertAngle;
00693
00694 if ( ( c.x - point.x )*xd > 0 || ( c.y - point.y )*yd > 0 )
00695 continue;
00696 if ( ( c.x - opppoint.x )*-xd > r || ( c.y - opppoint.y )*-yd > r )
00697 continue;
00698
00699 int posdir = xd*yd;
00700 double hd = ( point.x - c.x )*xd;
00701 assert( hd >= 0 );
00702 if ( hd < r )
00703 {
00704 double anglediff = acos( hd/r );
00705 horizangle += posdir * anglediff;
00706 }
00707
00708 hd = ( c.x - opppoint.x )*-xd;
00709 if ( hd >= 0 )
00710 {
00711 double anglediff = asin( hd/r );
00712 vertangle -= posdir * anglediff;
00713 }
00714
00715 double vd = ( point.y - c.y )*yd;
00716 assert( vd >= 0 );
00717 if ( vd < r )
00718 {
00719 double anglediff = acos( vd/r );
00720 vertangle -= posdir * anglediff;
00721 }
00722
00723 vd = ( c.y - opppoint.y ) * -xd;
00724 if ( vd >= 0 )
00725 {
00726 double anglediff = asin( hd/r );
00727 horizangle += posdir * anglediff;
00728 }
00729
00730 p.drawArc( c, r, kigMin( horizangle, vertangle ), kigMax( horizangle, vertangle ) );
00731 }
00732 #else
00733 p.drawCircle( c, r );
00734 #endif
00735 }