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
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
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
00100 int novp = 0;
00101
00102 if (!(top < r.left() || top > r.right())) {
00103
00104 ++novp;
00105 xa = top; ya = r.top();
00106 };
00107 if (!(left < r.bottom() || left > r.top())) {
00108
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
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
00119 ++novp;
00120 xb = bottom; yb = r.bottom();
00121 };
00122 if (novp < 2) {
00123
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
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
00143 if(
00144
00145 top >= r.left() && top <= r.right()
00146
00147 && yb > ya )
00148 {
00149 xb = top;
00150 yb = r.top();
00151 return;
00152 };
00153 if(
00154
00155 left >= r.bottom() && left <= r.top()
00156
00157 && xb < xa )
00158 {
00159 xb = r.left();
00160 yb=left;
00161 return;
00162 };
00163 if (
00164
00165 right >= r.bottom() && right <= r.top()
00166
00167 && xb > xa )
00168 {
00169 xb = r.right();
00170 yb=right;
00171 return;
00172 };
00173 if(
00174
00175 bottom >= r.left() && bottom <= r.right()
00176
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
00194 double tmp = fabs( o.x * (y1-y2) + o.y*(x2-x1) + (x1*y2-y1*x2) );
00195 return tmp < ( fault * (b-a).length());
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
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
00214 && (o.x - kigMax(a.x,b.x) < fault )
00215
00216 && ( kigMin (a.x, b.x) - o.x < fault )
00217
00218 && ( kigMin (a.y, b.y) - o.y < fault )
00219
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
00228
00229 && ( ( a.x < b.x ) ? ( a.x - o.x < fault ) : ( a.x - o.x > -fault ) )
00230
00231
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
00315
00316 Coordinate p( c.x + 5, c.y );
00317
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
00324
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
00367
00368
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
00383
00384
00385
00386
00387 return a.invalidCoord();
00388
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
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
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
00434
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
00441
00442
00443
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
00501
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;