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

kig

common.cpp

Go to the documentation of this file.
00001 
00021 #include "common.h"
00022 
00023 #include "../kig/kig_view.h"
00024 #include "../objects/object_imp.h"
00025 
00026 #include <cmath>
00027 
00028 #include <kdebug.h>
00029 #include <knumvalidator.h>
00030 #include <klocale.h>
00031 #include <kglobal.h>
00032 #include <kinputdialog.h>
00033 
00034 Coordinate calcPointOnPerpend( const LineData& l, const Coordinate& t )
00035 {
00036   return calcPointOnPerpend( l.b - l.a, t );
00037 }
00038 
00039 Coordinate calcPointOnPerpend( const Coordinate& dir, const Coordinate& t )
00040 {
00041   return t + ( dir ).orthogonal();
00042 }
00043 
00044 Coordinate calcPointOnParallel( const LineData& l, const Coordinate& t )
00045 {
00046   return calcPointOnParallel( l.b - l.a, t );
00047 }
00048 
00049 Coordinate calcPointOnParallel( const Coordinate& dir, const Coordinate& t )
00050 {
00051   return t + dir*5;
00052 }
00053 
00054 Coordinate calcIntersectionPoint( const LineData& l1, const LineData& l2 )
00055 {
00056   const Coordinate& pa = l1.a;
00057   const Coordinate& pb = l1.b;
00058   const Coordinate& pc = l2.a;
00059   const Coordinate& pd = l2.b;
00060 
00061   double
00062     xab = pb.x - pa.x,
00063     xdc = pd.x - pc.x,
00064     xac = pc.x - pa.x,
00065     yab = pb.y - pa.y,
00066     ydc = pd.y - pc.y,
00067     yac = pc.y - pa.y;
00068 
00069   double det = xab*ydc - xdc*yab;
00070   double detn = xac*ydc - xdc*yac;
00071 
00072   // test for parallelism
00073   if ( fabs (det) < 1e-6 ) return Coordinate::invalidCoord();
00074   double t = detn/det;
00075 
00076   return pa + t*(pb - pa);
00077 }
00078 
00079 void calcBorderPoints( Coordinate& p1, Coordinate& p2, const Rect& r )
00080 {
00081   calcBorderPoints( p1.x, p1.y, p2.x, p2.y, r );
00082 }
00083 
00084 const LineData calcBorderPoints( const LineData& l, const Rect& r )
00085 {
00086   LineData ret( l );
00087   calcBorderPoints( ret.a.x, ret.a.y, ret.b.x, ret.b.y, r );
00088   return ret;
00089 }
00090 
00091 void calcBorderPoints( double& xa, double& ya, double& xb, double& yb, const Rect& r )
00092 {
00093   // we calc where the line through a(xa,ya) and b(xb,yb) intersects with r:
00094   double left = (r.left()-xa)*(yb-ya)/(xb-xa)+ya;
00095   double right = (r.right()-xa)*(yb-ya)/(xb-xa)+ya;
00096   double top = (r.top()-ya)*(xb-xa)/(yb-ya)+xa;
00097   double bottom = (r.bottom()-ya)*(xb-xa)/(yb-ya)+xa;
00098 
00099   // now we go looking for valid points
00100   int novp = 0; // number of valid points we have already found
00101 
00102   if (!(top < r.left() || top > r.right())) {
00103     // the line intersects with the top side of the rect.
00104     ++novp;
00105     xa = top; ya = r.top();
00106   };
00107   if (!(left < r.bottom() || left > r.top())) {
00108     // the line intersects with the left side of the rect.
00109     if (novp++) { xb = r.left(); yb=left; }
00110     else { xa = r.left(); ya=left; };
00111   };
00112   if (!(right < r.bottom() || right > r.top())) {
00113     // the line intersects with the right side of the rect.
00114     if (novp++) { xb = r.right(); yb=right; }
00115     else { xa = r.right(); ya=right; };
00116   };
00117   if (!(bottom < r.left() || bottom > r.right())) {
00118     // the line intersects with the bottom side of the rect.
00119     ++novp;
00120     xb = bottom; yb = r.bottom();
00121   };
00122   if (novp < 2) {
00123     // line is completely outside of the window...
00124     xa = ya = xb = yb = 0;
00125   };
00126 }
00127 
00128 void calcRayBorderPoints( const Coordinate& a, Coordinate& b, const Rect& r )
00129 {
00130   calcRayBorderPoints( a.x, a.y, b.x, b.y, r );
00131 }
00132 
00133 void calcRayBorderPoints( const double xa, const double ya, double& xb,
00134                           double& yb, const Rect& r )
00135 {
00136   // we calc where the line through a(xa,ya) and b(xb,yb) intersects with r:
00137   double left = (r.left()-xa)*(yb-ya)/(xb-xa)+ya;
00138   double right = (r.right()-xa)*(yb-ya)/(xb-xa)+ya;
00139   double top = (r.top()-ya)*(xb-xa)/(yb-ya)+xa;
00140   double bottom = (r.bottom()-ya)*(xb-xa)/(yb-ya)+xa;
00141 
00142   // now we see which we can use...
00143   if(
00144     // the ray intersects with the top side of the rect..
00145     top >= r.left() && top <= r.right()
00146     // and b is above a
00147     && yb > ya )
00148   {
00149     xb = top;
00150     yb = r.top();
00151     return;
00152   };
00153   if(
00154     // the ray intersects with the left side of the rect...
00155     left >= r.bottom() && left <= r.top()
00156     // and b is on the left of a..
00157     && xb < xa )
00158   {
00159     xb = r.left();
00160     yb=left;
00161     return;
00162   };
00163   if (
00164     // the ray intersects with the right side of the rect...
00165     right >= r.bottom() && right <= r.top()
00166     // and b is to the right of a..
00167     && xb > xa )
00168   {
00169     xb = r.right();
00170     yb=right;
00171     return;
00172   };
00173   if(
00174     // the ray intersects with the bottom side of the rect...
00175     bottom >= r.left() && bottom <= r.right()
00176     // and b is under a..
00177     && yb < ya ) {
00178     xb = bottom;
00179     yb = r.bottom();
00180     return;
00181   };
00182   kError() << "damn" << endl;
00183 }
00184 
00185 bool isOnLine( const Coordinate& o, const Coordinate& a,
00186                const Coordinate& b, const double fault )
00187 {
00188   double x1 = a.x;
00189   double y1 = a.y;
00190   double x2 = b.x;
00191   double y2 = b.y;
00192 
00193   // check your math theory ( homogeneous coordinates ) for this
00194   double tmp = fabs( o.x * (y1-y2) + o.y*(x2-x1) + (x1*y2-y1*x2) );
00195   return tmp < ( fault * (b-a).length());
00196   // if o is on the line ( if the determinant of the matrix
00197   //       |---|---|---|
00198   //       | x | y | z |
00199   //       |---|---|---|
00200   //       | x1| y1| z1|
00201   //       |---|---|---|
00202   //       | x2| y2| z2|
00203   //       |---|---|---|
00204   // equals 0, then p(x,y,z) is on the line containing points
00205   // p1(x1,y1,z1) and p2 here, we're working with normal coords, no
00206   // homogeneous ones, so all z's equal 1
00207 }
00208 
00209 bool isOnSegment( const Coordinate& o, const Coordinate& a,
00210                   const Coordinate& b, const double fault )
00211 {
00212   return isOnLine( o, a, b, fault )
00213     // not too far to the right
00214     && (o.x - kigMax(a.x,b.x) < fault )
00215     // not too far to the left
00216     && ( kigMin (a.x, b.x) - o.x < fault )
00217     // not too high
00218     && ( kigMin (a.y, b.y) - o.y < fault )
00219     // not too low
00220     && ( o.y - kigMax (a.y, b.y) < fault );
00221 }
00222 
00223 bool isOnRay( const Coordinate& o, const Coordinate& a,
00224               const Coordinate& b, const double fault )
00225 {
00226   return isOnLine( o, a, b, fault )
00227     // not too far in front of a horizontally..
00228 //    && ( a.x - b.x < fault ) == ( a.x - o.x < fault )
00229     && ( ( a.x < b.x ) ? ( a.x - o.x < fault ) : ( a.x - o.x > -fault ) )
00230     // not too far in front of a vertically..
00231 //    && ( a.y - b.y < fault ) == ( a.y - o.y < fault );
00232     && ( ( a.y < b.y ) ? ( a.y - o.y < fault ) : ( a.y - o.y > -fault ) );
00233 }
00234 
00235 bool isOnArc( const Coordinate& o, const Coordinate& c, const double r,
00236               const double sa, const double a, const double fault )
00237 {
00238   if ( fabs( ( c - o ).length() - r ) > fault )
00239     return false;
00240   Coordinate d = o - c;
00241   double angle = atan2( d.y, d.x );
00242 
00243   if ( angle < sa ) angle += 2 * M_PI;
00244   return angle - sa - a < 1e-4;
00245 }
00246 
00247 const Coordinate calcMirrorPoint( const LineData& l,
00248                                   const Coordinate& p )
00249 {
00250   Coordinate m =
00251     calcIntersectionPoint( l,
00252                            LineData( p,
00253                                      calcPointOnPerpend( l, p )
00254                              )
00255       );
00256   return 2*m - p;
00257 }
00258 
00259 const Coordinate calcCircleLineIntersect( const Coordinate& c,
00260                                           const double sqr,
00261                                           const LineData& l,
00262                                           int side )
00263 {
00264   Coordinate proj = calcPointProjection( c, l );
00265   Coordinate hvec = proj - c;
00266   Coordinate lvec = -l.dir();
00267 
00268   double sqdist = hvec.squareLength();
00269   double sql = sqr - sqdist;
00270   if ( sql < 0.0 )
00271     return Coordinate::invalidCoord();
00272   else
00273   {
00274     double l = sqrt( sql );
00275     lvec = lvec.normalize( l );
00276     lvec *= side;
00277 
00278     return proj + lvec;
00279   };
00280 }
00281 
00282 const Coordinate calcArcLineIntersect( const Coordinate& c, const double sqr,
00283                                        const double sa, const double angle,
00284                                        const LineData& l, int side )
00285 {
00286   const Coordinate possiblepoint = calcCircleLineIntersect( c, sqr, l, side );
00287   if ( isOnArc( possiblepoint, c, sqrt( sqr ), sa, angle, test_threshold ) )
00288     return possiblepoint;
00289   else return Coordinate::invalidCoord();
00290 }
00291 
00292 const Coordinate calcPointProjection( const Coordinate& p,
00293                                       const LineData& l )
00294 {
00295   Coordinate orth = l.dir().orthogonal();
00296   return p + orth.normalize( calcDistancePointLine( p, l ) );
00297 }
00298 
00299 double calcDistancePointLine( const Coordinate& p,
00300                               const LineData& l )
00301 {
00302   double xa = l.a.x;
00303   double ya = l.a.y;
00304   double xb = l.b.x;
00305   double yb = l.b.y;
00306   double x = p.x;
00307   double y = p.y;
00308   double norm = l.dir().length();
00309   return ( yb * x - ya * x - xb * y + xa * y + xb * ya - yb * xa ) / norm;
00310 }
00311 
00312 Coordinate calcRotatedPoint( const Coordinate& a, const Coordinate& c, const double arc )
00313 {
00314   // we take a point p on a line through c and parallel with the
00315   // X-axis..
00316   Coordinate p( c.x + 5, c.y );
00317   // we then calc the arc that ac forms with cp...
00318   Coordinate d = a - c;
00319   d = d.normalize();
00320   double aarc = std::acos( d.x );
00321   if ( d.y < 0 ) aarc = 2*M_PI - aarc;
00322 
00323   // we now take the sum of the two arcs to find the arc between
00324   // pc and ca
00325   double asum = aarc + arc;
00326 
00327   Coordinate ret( std::cos( asum ), std::sin( asum ) );
00328   ret = ret.normalize( ( a -c ).length() );
00329   return ret + c;
00330 }
00331 
00332 Coordinate calcCircleRadicalStartPoint( const Coordinate& ca, const Coordinate& cb,
00333                                         double sqra, double sqrb )
00334 {
00335   Coordinate direc = cb - ca;
00336   Coordinate m = (ca + cb)/2;
00337 
00338   double dsq = direc.squareLength();
00339   double lambda = dsq == 0.0 ? 0.0
00340                   : (sqra - sqrb) / (2*dsq);
00341 
00342   direc *= lambda;
00343   return m + direc;
00344 }
00345 
00346 double getDoubleFromUser( const QString& caption, const QString& label, double value,
00347                           QWidget* parent, bool* ok, double min, double max, int decimals )
00348 {
00349   KDoubleValidator vtor( min, max, decimals,0 );
00350 
00351   QString input = KInputDialog::getText(
00352     caption, label, KGlobal::locale()->formatNumber( value, decimals ),
00353     ok, parent, &vtor );
00354 
00355   bool myok = true;
00356   double ret = KGlobal::locale()->readNumber( input, &myok );
00357   if ( ! myok )
00358     ret = input.toDouble( & myok );
00359   if ( ok ) *ok = myok;
00360   return ret;
00361 }
00362 
00363 const Coordinate calcCenter(
00364   const Coordinate& a, const Coordinate& b, const Coordinate& c )
00365 {
00366   // this algorithm is written by my brother, Christophe Devriese
00367   // <oelewapperke@ulyssis.org> ...
00368   // I don't get it myself :)
00369 
00370   double xdo = b.x-a.x;
00371   double ydo = b.y-a.y;
00372 
00373   double xao = c.x-a.x;
00374   double yao = c.y-a.y;
00375 
00376   double a2 = xdo*xdo + ydo*ydo;
00377   double b2 = xao*xao + yao*yao;
00378 
00379   double numerator = (xdo * yao - xao * ydo);
00380   if ( numerator == 0 )
00381   {
00382     // problem:  xdo * yao == xao * ydo <=> xdo/ydo == xao / yao
00383     // this means that the lines ac and ab have the same direction,
00384     // which means they're the same line..
00385     // FIXME: i would normally throw an error here, but KDE doesn't
00386     // use exceptions, so I'm returning a bogus point :(
00387     return a.invalidCoord();
00388     /* return (a+c)/2; */
00389   };
00390   double denominator = 0.5 / numerator;
00391 
00392   double centerx = a.x - (ydo * b2 - yao * a2) * denominator;
00393   double centery = a.y + (xdo * b2 - xao * a2) * denominator;
00394 
00395   return Coordinate(centerx, centery);
00396 }
00397 
00398 bool lineInRect( const Rect& r, const Coordinate& a, const Coordinate& b,
00399                  const int width, const ObjectImp* imp, const KigWidget& w )
00400 {
00401   double miss = w.screenInfo().normalMiss( width );
00402 
00403 //mp: the following test didn't work for vertical segments;
00404 // fortunately the ieee floating point standard allows us to avoid
00405 // the test altogether, since it would produce an infinity value that
00406 // makes the final r.contains to fail
00407 // in any case the corresponding test for a.y - b.y was missing.
00408 
00409 //  if ( fabs( a.x - b.x ) <= 1e-7 )
00410 //  {
00411 //    // too small to be useful..
00412 //    return r.contains( Coordinate( a.x, r.center().y ), miss );
00413 //  }
00414 
00415 // in case we have a segment we need also to check for the case when
00416 // the segment is entirely contained in the rect, in which case the
00417 // final tests all fail.
00418 // it is ok to just check for the midpoint in the rect since:
00419 // - if we have a segment completely contained in the rect this is true
00420 // - if the midpoint is in the rect than returning true is safe (also
00421 //   in the cases where we have a ray or a line)
00422 
00423   if ( r.contains( 0.5*( a + b ), miss ) ) return true;
00424 
00425   Coordinate dir = b - a;
00426   double m = dir.y / dir.x;
00427   double lefty = a.y + m * ( r.left() - a.x );
00428   double righty = a.y + m * ( r.right() - a.x );
00429   double minv = dir.x / dir.y;
00430   double bottomx = a.x + minv * ( r.bottom() - a.y );
00431   double topx = a.x + minv * ( r.top() - a.y );
00432 
00433   // these are the intersections between the line, and the lines
00434   // defined by the sides of the rectangle.
00435   Coordinate leftint( r.left(), lefty );
00436   Coordinate rightint( r.right(), righty );
00437   Coordinate bottomint( bottomx, r.bottom() );
00438   Coordinate topint( topx, r.top() );
00439 
00440   // For each intersection, we now check if we contain the
00441   // intersection ( this might not be the case for a segment, when the
00442   // intersection is not between the begin and end point.. ) and if
00443   // the rect contains the intersection..  If it does, we have a winner..
00444   return
00445     ( imp->contains( leftint, width, w ) && r.contains( leftint, miss ) ) ||
00446     ( imp->contains( rightint, width, w ) && r.contains( rightint, miss ) ) ||
00447     ( imp->contains( bottomint, width, w ) && r.contains( bottomint, miss ) ) ||
00448     ( imp->contains( topint, width, w ) && r.contains( topint, miss ) );
00449 }
00450 
00451 bool operator==( const LineData& l, const LineData& r )
00452 {
00453   return l.a == r.a && l.b == r.b;
00454 }
00455 
00456 bool LineData::isParallelTo( const LineData& l ) const
00457 {
00458   const Coordinate& p1 = a;
00459   const Coordinate& p2 = b;
00460   const Coordinate& p3 = l.a;
00461   const Coordinate& p4 = l.b;
00462 
00463   double dx1 = p2.x - p1.x;
00464   double dy1 = p2.y - p1.y;
00465   double dx2 = p4.x - p3.x;
00466   double dy2 = p4.y - p3.y;
00467 
00468   return isSingular( dx1, dy1, dx2, dy2 );
00469 }
00470 
00471 bool LineData::isOrthogonalTo( const LineData& l ) const
00472 {
00473   const Coordinate& p1 = a;
00474   const Coordinate& p2 = b;
00475   const Coordinate& p3 = l.a;
00476   const Coordinate& p4 = l.b;
00477 
00478   double dx1 = p2.x - p1.x;
00479   double dy1 = p2.y - p1.y;
00480   double dx2 = p4.x - p3.x;
00481   double dy2 = p4.y - p3.y;
00482 
00483   return isSingular( dx1, dy1, -dy2, dx2 );
00484 }
00485 
00486 bool areCollinear( const Coordinate& p1,
00487                    const Coordinate& p2, const Coordinate& p3 )
00488 {
00489   return isSingular( p2.x - p1.x, p2.y - p1.y, p3.x - p1.x, p3.y - p1.y );
00490 }
00491 
00492 bool isSingular( const double& a, const double& b,
00493                  const double& c, const double& d )
00494 {
00495   double det = a*d - b*c;
00496   double norm1 = std::fabs(a) + std::fabs(b);
00497   double norm2 = std::fabs(c) + std::fabs(d);
00498 
00499 /*
00500  * test must be done relative to the magnitude of the two
00501  * row (or column) vectors!
00502  */
00503   return ( std::fabs(det) < test_threshold*norm1*norm2 );
00504 }
00505 
00506 const double double_inf = HUGE_VAL;
00507 const double test_threshold = 1e-6;

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
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  •   docs
  •   src
  • parley
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