Geometry2D.C

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:05:20 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3