00001 /*!@file MBARI/Geometry2D.C - classes for geometry in the plane 00002 */ 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2002 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Dirk Walther <walther@caltech.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/MBARI/Geometry2D.C $ 00035 // $Id: Geometry2D.C 9422 2008-03-11 07:33:57Z rjpeters $ 00036 // 00037 00038 00039 #include "MBARI/Geometry2D.H" 00040 00041 #include "Image/Point2D.H" 00042 #include "Util/Assert.H" 00043 #include "Util/MathFunctions.H" // for isFinite() 00044 #include <cmath> 00045 #include <istream> 00046 #include <ostream> 00047 00048 // ###################################################################### 00049 // ## implementation of Vector2D 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 // ## operators for Vector2D 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 // ## comparison operators for Vector2D 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 // ### Implementation of StraightLine2D 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 // ### Implementation of LineSegment2D 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 // Fail if either line is undefined. 00540 if ((Ax==Bx && Ay==By) || (Cx==Dx && Cy==Dy)) { return false; } 00541 00542 // (1) Translate the system so that point A is on the origin. 00543 Bx-=Ax; By-=Ay; 00544 Cx-=Ax; Cy-=Ay; 00545 Dx-=Ax; Dy-=Ay; 00546 00547 // Discover the length of segment A-B. 00548 distAB=sqrt(Bx*Bx+By*By); 00549 00550 // (2) Rotate the system so that point B is on the positive X axis. 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 // Fail if the lines are parallel. 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 // (3) Discover the position of the intersection point along line 00566 // A-B. 00567 ABpos=Dx+(Cx-Dx)*Dy/(Dy-Cy); 00568 00569 // (4) Apply the discovered position to line A-B in the original 00570 // coordinate system. 00571 x=Ax+ABpos*theCos; 00572 y=Ay+ABpos*theSin; 00573 00574 //Point2D<int> temp(x, y); 00575 00576 00577 // Success. 00578 00579 //in case the two lines share only an endpoint 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 //the distance from a line to a pointon the line SHOULD be 0, 00593 //however, it looks as though compounded errors from conversions to 00594 //float and double give it some leeway. 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 /* So things look consistent in everyone's emacs... */ 00624 /* Local Variables: */ 00625 /* indent-tabs-mode: nil */ 00626 /* End: */