Geometry2D.C
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "MBARI/Geometry2D.H"
00040
00041 #include "Image/Point2D.H"
00042 #include "Util/Assert.H"
00043 #include "Util/MathFunctions.H"
00044 #include <cmath>
00045 #include <istream>
00046 #include <ostream>
00047
00048
00049
00050
00051 Vector2D::Vector2D()
00052 : itsX(0), itsY(0), valid(false)
00053 {}
00054
00055
00056 Vector2D::Vector2D(float x, float y)
00057 : itsX(x), itsY(y), valid(true)
00058 {}
00059
00060
00061 Vector2D::Vector2D(const Point2D<int>& point)
00062 : itsX(point.i), itsY(point.j), valid(true)
00063 {}
00064
00065
00066 Vector2D::Vector2D(const Point2D<double>& point)
00067 : itsX(point.i), itsY(point.j), valid(true)
00068 {}
00069
00070
00071 Vector2D::Vector2D(std::istream& is)
00072 {
00073 readFromStream(is);
00074 }
00075
00076
00077
00078 void Vector2D::reset(float x, float y)
00079 {
00080 itsX = x;
00081 itsY = y;
00082 valid = true;
00083 }
00084
00085
00086 void Vector2D::reset(const Point2D<int>& point)
00087 {
00088 itsX = point.i;
00089 itsY = point.j;
00090 valid = true;
00091 }
00092
00093
00094 void Vector2D::writeToStream(std::ostream& os) const
00095 {
00096 if (valid) os << "1\n";
00097 else os << "0\n";
00098 os << itsX << ' ' << itsY << '\n';
00099 }
00100
00101
00102 void Vector2D::readFromStream(std::istream& is)
00103 {
00104 int i; is >> i;
00105 valid = (i == 1);
00106 is >> itsX;
00107 is >> itsY;
00108 }
00109
00110
00111 float Vector2D::x() const
00112 {
00113 ASSERT(isValid());
00114 return itsX;
00115 }
00116
00117
00118 float Vector2D::y() const
00119 {
00120 ASSERT(isValid());
00121 return itsY;
00122 }
00123
00124
00125 Point2D<int> Vector2D::getPoint2D() const
00126 {
00127 ASSERT(isValid());
00128 return Point2D<int>(int(itsX + 0.5F),int(itsY + 0.5F));
00129 }
00130
00131
00132 float Vector2D::dotProduct(const Vector2D& other) const
00133 {
00134 ASSERT(isValid());
00135 ASSERT(other.isValid());
00136 return (itsX * other.x() + itsY * other.y());
00137 }
00138
00139
00140 float Vector2D::crossProduct(const Vector2D& other) const
00141 {
00142 ASSERT(isValid());
00143 ASSERT(other.isValid());
00144
00145 return (itsX * other.y() - itsY * other.x());
00146 }
00147
00148
00149
00150 float Vector2D::length() const
00151 { return sqrt(dotProduct(*this)); }
00152
00153
00154 float Vector2D::normalize()
00155 {
00156 ASSERT(isValid());
00157 float l = length();
00158 if (l != 0.0F)
00159 {
00160 itsX /= l;
00161 itsY /= l;
00162 }
00163 return l;
00164 }
00165
00166
00167 float Vector2D::distance(const Vector2D& other) const
00168 {
00169 ASSERT(isValid());
00170 ASSERT(other.isValid());
00171 Vector2D diff = *this - other;
00172 return diff.length();
00173 }
00174
00175
00176 float Vector2D::angle(const Vector2D& other) const
00177 {
00178 ASSERT(isValid());
00179 ASSERT(other.isValid());
00180 return acos(dotProduct(other)/length()/other.length())*180.0F/M_PI;
00181 }
00182
00183
00184 bool Vector2D::isCollinear(const Vector2D& other) const
00185 {
00186 ASSERT(isValid());
00187 ASSERT(other.isValid());
00188 return (fabs(angle(other)) < 0.1F);
00189 }
00190
00191
00192 bool Vector2D::isOrthogonal(const Vector2D& other) const
00193 {
00194 ASSERT(isValid());
00195 ASSERT(other.isValid());
00196 return (fabs(dotProduct(other)) < 1e-6);
00197 }
00198
00199
00200 bool Vector2D::isZero() const
00201 {
00202 ASSERT(isValid());
00203 return (fabs(itsX) < 1e-6) && (fabs(itsY) < 1e-6);
00204 }
00205
00206
00207 bool Vector2D::isValid() const
00208 { return valid; }
00209
00210
00211
00212
00213 float Vector2D::operator*(const Vector2D& v) const
00214 { return dotProduct(v); }
00215
00216
00217 Vector2D Vector2D::operator+(const Vector2D& v) const
00218 {
00219 if (!isValid() || !v.isValid()) return Vector2D();
00220 else return Vector2D(itsX + v.x(), itsY + v.y());
00221 }
00222
00223
00224 Vector2D Vector2D::operator-(const Vector2D& v) const
00225 {
00226 if (!isValid() || !v.isValid()) return Vector2D();
00227 else return Vector2D(itsX - v.x(), itsY - v.y());
00228 }
00229
00230
00231 Vector2D& Vector2D::operator+=(const Vector2D& v)
00232 {
00233 if (!isValid() || !v.isValid()) valid = false;
00234 else { itsX += v.x(); itsY += v.y(); }
00235 return *this;
00236 }
00237
00238
00239 Vector2D& Vector2D::operator-=(const Vector2D& v)
00240 {
00241 if (!isValid() || !v.isValid()) valid = false;
00242 else { itsX -= v.x(); itsY -= v.y(); }
00243 return *this;
00244 }
00245
00246
00247 Vector2D Vector2D::operator+(const float f) const
00248 {
00249 if (!isValid()) return Vector2D();
00250 else return Vector2D(itsX + f, itsY + f);
00251 }
00252
00253
00254 Vector2D Vector2D::operator-(const float f) const
00255 {
00256 if (!isValid()) return Vector2D();
00257 else return Vector2D(itsX - f, itsY - f);
00258 }
00259
00260
00261 Vector2D Vector2D::operator*(const float f) const
00262 {
00263 if (!isValid()) return Vector2D();
00264 else return Vector2D(itsX * f, itsY * f);
00265 }
00266
00267
00268 Vector2D Vector2D::operator/(const float f) const
00269 {
00270 ASSERT(f != 0.0F);
00271 if (!isValid()) return Vector2D();
00272 else return Vector2D(itsX / f, itsY / f);
00273 }
00274
00275
00276
00277 Vector2D& Vector2D::operator+=(const float f)
00278 {
00279 itsX += f; itsY += f;
00280 return *this;
00281 }
00282
00283
00284 Vector2D& Vector2D::operator-=(const float f)
00285 {
00286 itsX -= f; itsY -= f;
00287 return *this;
00288 }
00289
00290
00291 Vector2D& Vector2D::operator*=(const float f)
00292 {
00293 itsX *= f; itsY *= f;
00294 return *this;
00295 }
00296
00297
00298 Vector2D& Vector2D::operator/=(const float f)
00299 {
00300 ASSERT (f != 0.0F);
00301 itsX /= f; itsY /= f;
00302 return *this;
00303 }
00304
00305
00306
00307
00308 bool operator==(const Vector2D& v1, const Vector2D& v2)
00309 { return (v1.x() == v2.x()) && (v1.y() == v2.y()); }
00310
00311 bool operator!=(const Vector2D& v1, const Vector2D& v2)
00312 { return (v1.x() != v2.x()) || (v1.y() != v2.y()); }
00313
00314
00315
00316
00317
00318
00319 StraightLine2D::StraightLine2D()
00320 : itsPoint(), itsDir(), valid(false)
00321 {}
00322
00323
00324 StraightLine2D::StraightLine2D(const Vector2D& point,
00325 const Vector2D& direction)
00326 : itsPoint(point), itsDir(direction), valid(true)
00327 {}
00328
00329
00330 StraightLine2D::StraightLine2D(std::istream& is)
00331 {
00332 readFromStream(is);
00333 }
00334
00335
00336 void StraightLine2D::reset(const Vector2D& point,
00337 const Vector2D& direction)
00338 {
00339 itsPoint = point;
00340 itsDir = direction;
00341 valid = true;
00342 }
00343
00344 void StraightLine2D::writeToStream(std::ostream& os) const
00345 {
00346 if (valid) os << "1\n";
00347 else os << "0\n";
00348 itsPoint.writeToStream(os);
00349 itsDir.writeToStream(os);
00350 }
00351
00352
00353 void StraightLine2D::readFromStream(std::istream& is)
00354 {
00355 int i; is >> i;
00356 valid = (i == 1);
00357 itsPoint.readFromStream(is);
00358 itsDir.readFromStream(is);
00359 }
00360
00361
00362 Vector2D StraightLine2D::point(float n) const
00363 {
00364 ASSERT(isValid());
00365 return (itsPoint + itsDir * n);
00366 }
00367
00368
00369 Vector2D StraightLine2D::direction() const
00370 {
00371 ASSERT(isValid());
00372 return itsDir;
00373 }
00374
00375
00376 Vector2D StraightLine2D::intersect(const StraightLine2D& other,
00377 float&n, float&m) const
00378 {
00379 ASSERT(isValid());
00380 ASSERT(other.isValid());
00381 if (isParallel(other)) return Vector2D();
00382
00383 Vector2D dif = itsPoint - other.point();
00384 Vector2D od = other.direction();
00385 float en = (itsDir.y() * od.x() - od.y() * itsDir.x());
00386 n = (od.y() * dif.x() - od.x() * dif.y()) / en;
00387 m = (itsDir.y() * dif.x() - itsDir.x() * dif.y()) / en;
00388
00389 return point(n);
00390 }
00391
00392
00393 bool StraightLine2D::isParallel(const StraightLine2D& other) const
00394 {
00395 ASSERT(isValid());
00396 ASSERT(other.isValid());
00397 return (itsDir.isCollinear(other.direction()));
00398 }
00399
00400
00401 bool StraightLine2D::isOrthogonal(const StraightLine2D& other) const
00402 {
00403 ASSERT(isValid());
00404 ASSERT(other.isValid());
00405 return (itsDir.isOrthogonal(other.direction()));
00406 }
00407
00408
00409 bool StraightLine2D::isPointOnLine(const Vector2D& pt) const
00410 {
00411 ASSERT(isValid());
00412 ASSERT(pt.isValid());
00413
00414 float n1 = itsDir.y() * (pt.x() - itsPoint.x());
00415 float n2 = itsDir.x() * (pt.y() - itsPoint.y());
00416
00417 return (fabs(n1 - n2) < 1e-6);
00418 }
00419
00420
00421 bool StraightLine2D::isIdentical(const StraightLine2D& other) const
00422 {
00423 ASSERT(isValid());
00424 ASSERT(other.isValid());
00425
00426 return (isParallel(other) && isPointOnLine(other.point()));
00427 }
00428
00429
00430 bool StraightLine2D::isValid() const
00431 { return valid; }
00432
00433
00434
00435
00436
00437 LineSegment2D::LineSegment2D()
00438 : itsPoint1(), itsPoint2(), valid(false)
00439 {}
00440
00441
00442 LineSegment2D::LineSegment2D(const Point2D<int>& p1,
00443 const Point2D<int>& p2)
00444 : itsPoint1(p1), itsPoint2(p2), valid(p1 != p2)
00445 {}
00446
00447
00448 LineSegment2D::LineSegment2D(std::istream& is)
00449 {
00450 readFromStream(is);
00451 }
00452
00453
00454 void LineSegment2D::reset(const Point2D<int>& p1,
00455 const Point2D<int>& p2)
00456 {
00457 itsPoint1 = p1;
00458 itsPoint2 = p2;
00459
00460 if (itsPoint1 != itsPoint2) {
00461 valid = true;
00462 }
00463 else {
00464 valid = false;
00465 }
00466 }
00467
00468 void LineSegment2D::writeToStream(std::ostream& os) const
00469 {
00470 if (valid) os << "1\n";
00471 else os << "0\n";
00472 Vector2D(itsPoint1).writeToStream(os);
00473 Vector2D(itsPoint2).writeToStream(os);
00474 }
00475
00476
00477 void LineSegment2D::readFromStream(std::istream& is)
00478 {
00479 int i; is >> i;
00480 valid = (i == 1);
00481 Vector2D(itsPoint1).readFromStream(is);
00482 Vector2D(itsPoint2).readFromStream(is);
00483 }
00484
00485
00486 Point2D<int> LineSegment2D::point1() const
00487 {
00488 ASSERT(isValid());
00489 return (itsPoint1);
00490 }
00491
00492
00493 Point2D<int> LineSegment2D::point2() const
00494 {
00495 ASSERT(isValid());
00496 return (itsPoint2);
00497 }
00498
00499
00500 double LineSegment2D::angle() const
00501 {
00502 float o = (float)(point1().j - point2().j);
00503 float a = (float)(point1().i - point2().i);
00504 return atan(o/a);
00505 }
00506
00507
00508 double LineSegment2D::angleBetween(LineSegment2D &line) const
00509 {
00510 return fabs(angle() - line.angle());
00511 }
00512
00513
00514 float LineSegment2D::length() const
00515 {
00516 return (float)(point1().distance(point2()));
00517 }
00518
00519 bool LineSegment2D::isValid() const
00520 { return valid; }
00521
00522
00523
00524 bool LineSegment2D::intersects(LineSegment2D &line, double &xcoord, double &ycoord) const
00525 {
00526
00527 double Ax = point1().i;
00528 double Ay = point1().j;
00529 double Bx = point2().i;
00530 double By = point2().j;
00531 double Cx = line.point1().i;
00532 double Cy = line.point1().j;
00533 double Dx = line.point2().i;
00534 double Dy = line.point2().j;
00535
00536
00537 double x, y, distAB, theCos, theSin, newX, ABpos ;
00538
00539
00540 if ((Ax==Bx && Ay==By) || (Cx==Dx && Cy==Dy)) { return false; }
00541
00542
00543 Bx-=Ax; By-=Ay;
00544 Cx-=Ax; Cy-=Ay;
00545 Dx-=Ax; Dy-=Ay;
00546
00547
00548 distAB=sqrt(Bx*Bx+By*By);
00549
00550
00551 theCos=Bx/distAB;
00552 theSin=By/distAB;
00553 newX=Cx*theCos+Cy*theSin;
00554 Cy =Cy*theCos-Cx*theSin; Cx=newX;
00555 newX=Dx*theCos+Dy*theSin;
00556 Dy =Dy*theCos-Dx*theSin; Dx=newX;
00557
00558
00559 if (Cy==Dy) {
00560 if (distance(line.point1()) && distance(line.point2()) && line.distance(point1()) && line.distance(point2())) {
00561 return false;
00562 }
00563 }
00564
00565
00566
00567 ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy);
00568
00569
00570
00571 x=Ax+ABpos*theCos;
00572 y=Ay+ABpos*theSin;
00573
00574
00575
00576
00577
00578
00579
00580 if (point1() == line.point1() || point1() == line.point2()) {
00581 x = point1().i;
00582 y = point1().j;
00583 }
00584 if (point2() == line.point1() || point2() == line.point2()) {
00585 x = point2().i;
00586 y = point2().j;
00587 }
00588
00589 xcoord = x;
00590 ycoord = y;
00591
00592
00593
00594
00595 if (!isFinite(x) || !isFinite(y) ||
00596 distance(Point2D<double>(x, y)) > 0.000010 ||
00597 line.distance(Point2D<double>(x, y)) > 0.000010 ) {
00598
00599 return false;
00600 }
00601
00602 return true;
00603
00604
00605 }
00606
00607 double LineSegment2D::distance(Point2D<double> point) const {
00608 Vector2D A(point1());
00609 Vector2D B(point2());
00610
00611 Vector2D C(point);
00612
00613 double dist = ((B-A).crossProduct(C-A)) / sqrt((B-A)*(B-A));
00614 double dot1 = (C-B)*(B-A);
00615 if(dot1 > 0)return sqrt((B-C)*(B-C));
00616 double dot2 = (C-A)*(A-B);
00617 if(dot2 > 0)return sqrt((A-C)*(A-C));
00618 return fabs(dist);
00619 }
00620
00621
00622
00623
00624
00625
00626