• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdeedu
  • Sitemap
  • Contact Us
 

kig

coordinate_system.cpp

Go to the documentation of this file.
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     // strip the eventual '°'
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     // where is the second ';'
00120     int i = input.indexOf( ';' );
00121     i = input.indexOf( ';', i );
00122     input = input.left( i );
00123   };
00124   // now the string has at most one semicolon left..
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   // i used to use the widget size here, but that's no good idea,
00153   // since an object isn't asked to recalc every time the widget size
00154   // changes..  might be a good idea to do that, but well, maybe some
00155   // other time :)
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   // this instruction in not necessary, but there is a little
00218   // optimization when there are no grid and no axes.
00219   if ( !( showgrid || showaxes ) )
00220     return;
00221 
00222   // this function is inspired upon ( public domain ) code from the
00223   // first Graphics Gems book.  Credits to Paul S. Heckbert, who wrote
00224   // the "Nice number for graph labels" gem.
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   // the number of intervals we would like to have:
00232   // we try to have one of them per 40 pixels or so..
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   /****** the grid lines ******/
00254   if ( showgrid )
00255   {
00256     p.setPen( QPen( Qt::lightGray, 0, Qt::DotLine ) );
00257     // vertical lines...
00258     for ( double i = hgraphmin; i <= hgraphmax + hd/2; i += hd )
00259       p.drawSegment( Coordinate( i, vgraphmin ),
00260                      Coordinate( i, vgraphmax ) );
00261     // horizontal lines...
00262     for ( double i = vgraphmin; i <= vgraphmax + vd/2; i += vd )
00263       p.drawSegment( Coordinate( hgraphmin, i ),
00264                      Coordinate( hgraphmax, i ) );
00265   }
00266 
00267   /****** the axes ******/
00268   if ( showaxes )
00269   {
00270     p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00271     // x axis
00272     p.drawSegment( Coordinate( hmin, 0 ), Coordinate( hmax, 0 ) );
00273     // y axis
00274     p.drawSegment( Coordinate( 0, vmin ), Coordinate( 0, vmax ) );
00275 
00276     /****** the numbers ******/
00277 
00278     // x axis
00279     for( double i = hgraphmin; i <= hgraphmax + hd / 2; i += hd )
00280     {
00281       // we skip 0 since that would look stupid... (the axes going
00282       // through the 0 etc. )
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     // y axis...
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     // arrows on the ends of the axes...
00301     p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00302     p.setBrush( QBrush( Qt::gray ) );
00303     std::vector<Coordinate> a;
00304 
00305     // the arrow on the right end of the X axis...
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 //    p.drawPolygon( a, true );
00313 
00314     // the arrow on the top end of the Y axis...
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 //    p.drawPolygon( a, true );
00322   }; // if( showaxes )
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   // \xCE\xB8 is utf8 for the greek theta sign..
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   // \xCE\xB8 is utf8 for the greek theta sign..
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   // this instruction in not necessary, but there is a little
00412   // optimization when there are no grid and no axes.
00413   if ( !( showgrid || showaxes ) )
00414     return;
00415 
00416   // we multiply by sqrt( 2 ) cause we don't want to miss circles in
00417   // the corners, that intersect with the axes outside of the
00418   // screen..
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   // the intervals:
00426   // we try to have one of them per 40 pixels or so..
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   /****** the grid lines ******/
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     // we also want the circles that don't fit entirely in the
00455     // screen..
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   /****** the axes ******/
00463   if ( showaxes )
00464   {
00465     p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00466     // x axis
00467     p.drawSegment( Coordinate( hmin, 0 ), Coordinate( hmax, 0 ) );
00468     // y axis
00469     p.drawSegment( Coordinate( 0, vmin ), Coordinate( 0, vmax ) );
00470 
00471     /****** the numbers ******/
00472 
00473     // x axis
00474     for( double i = hgraphmin; i <= hgraphmax + hd / 2; i += hd )
00475     {
00476       // we skip 0 since that would look stupid... (the axes going
00477       // through the 0 etc. )
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     // y axis...
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     // arrows on the ends of the axes...
00497     p.setPen( QPen( Qt::gray, 1, Qt::SolidLine ) );
00498     p.setBrush( QBrush( Qt::gray ) );
00499     std::vector<Coordinate> a;
00500 
00501     // the arrow on the right end of the X axis...
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 //    p.drawPolygon( a, true );
00508     p.drawArea( a );
00509 
00510     // the arrow on the top end of the Y axis...
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 //    p.drawPolygon( a, true );
00517     p.drawArea( a );
00518   }; // if( showaxes )
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   // we recalc the interval stuff since there is no way to cache it..
00599 
00600   // this function is again inspired upon ( public domain ) code from
00601   // the first Graphics Gems book.  Credits to Paul S. Heckbert, who
00602   // wrote the "Nice number for graph labels" gem.
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   // the number of intervals we would like to have:
00610   // we try to have one of them per 40 pixels or so..
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   // we reuse the drawGrid code to find
00632 
00633   // we multiply by sqrt( 2 ) cause we don't want to miss circles in
00634   // the corners, that intersect with the axes outside of the
00635   // screen..
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   // the intervals:
00645   // we try to have one of them per 40 pixels or so..
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 }

kig

Skip menu "kig"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdeedu

Skip menu "kdeedu"
  • kalzium
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
  •   stepcore
Generated for kdeedu by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal