Line2D.cpp
Go to the documentation of this file.
00001 //
00002 // Line2D.cpp
00003 //
00004 
00005 #include <cmath>
00006 
00007 #include "Line2D.hpp"
00008 
00009 #include "Point2D.hpp"
00010 #include "Polygon2D.hpp"
00011 
00012 
00013 namespace datatypes
00014 {
00015         
00016 
00017 Polygon2D Line2D::toPolygon2D() const
00018 {
00019         return Polygon2D(first, second);
00020 }
00021 
00022 Polygon2D Line2D::toPolygon2D(unsigned samplePoints) const
00023 {
00024         assert(samplePoints > 1);
00025         if (samplePoints <= 1)
00026                 return Polygon2D(); // sanity check for when NDEBUG disables the assert() check
00027 
00028         Polygon2D result;
00029         result.resize(samplePoints);
00030         result.front() = first;
00031         result.back() = second;
00032 
00033         Point2D step = getDiff() / double(samplePoints - 1);
00034         for (unsigned k = 1; k < samplePoints - 1; ++k)
00035         {
00036                 result[k] = first + step * double(k);
00037         }
00038 
00039         return result;
00040 }
00041 
00042 double Line2D::getInclination() const
00043 {
00044         Point2D diff = getDiff();
00045         if (fuzzyCompare(diff.getX(), 0.0))
00046         {
00047                 // vertical line
00048                 if (first.getY() < second.getY())
00049                         return M_PI_2; // pi/2
00050                 else
00051                         return -M_PI_2; // -pi/2
00052         }
00053         return atan2(diff.getY(), diff.getX());
00054 }
00055 
00056 Line2D Line2D::getUnitVector() const
00057 {
00058         Point2D diff = getDiff();
00059         double thislength = getLength();
00060 
00061         return Line2D(first,
00062                                   Point2D(first.getX() + diff.getX() / thislength,
00063                                                   first.getY() + diff.getY() / thislength));
00064 }
00065 
00066 std::string Line2D::toString()
00067 {
00068         std::string text;
00069         
00070         text = "[" + getP1().toString() + " -> " +getP2().toString() + "]";
00071         
00072         return text;
00073 }
00074 
00075 bool Line2D::containsPoint(const Point2D& point) const
00076 {
00077         double d = distanceFromLineSegment(point);
00078         return fuzzyCompare(d, 0.0);
00079 }
00080 
00081 double Line2D::distanceToPoint(const Point2D& point) const
00082 {
00083         Point2D diff = point - projectOntoLine(point);
00084         return hypot(diff.getX(), diff.getY());
00085 }
00086 
00087 double dot_product(const Point2D& p1, const Point2D& p2)
00088 {
00089         return p1.getX() * p2.getX() + p1.getY() * p2.getY();
00090 }
00091 Point2D Line2D::projectOntoLine(const Point2D& point) const
00092 {
00093         Point2D line_vec = getDiff();
00094         double line_length = length();
00095         if (!fuzzyCompare(line_length, 0.0))
00096         {
00097                 Point2D line_unitvec = line_vec / line_length;
00098                 Point2D vec_to_point = point - first;
00099                 double length_of_projection =
00100                         dot_product(line_unitvec, vec_to_point);
00101                 return first + line_unitvec * length_of_projection;
00102         }
00103         else
00104         {
00105                 // Zero-length line; what should we do?
00106                 return point;
00107         }
00108 }
00109 
00110 double Line2D::distanceFromLineSegment(const Point2D& point) const
00111 {
00112 // How do I find the distance from a point to a line?
00113 //
00114 //    Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).
00115 //    Let P be the point of perpendicular projection of C on AB.  The parameter
00116 //    r, which indicates P's position along AB, is computed by the dot product
00117 //    of AC and AB divided by the square of the length of AB:
00118 //
00119 //    (1)     AC dot AB
00120 //        r = ---------
00121 //            ||AB||^2
00122 //
00123 //    r has the following meaning:
00124 //
00125 //        r=0      P = A
00126 //        r=1      P = B
00127 //        r<0      P is on the backward extension of AB
00128 //        r>1      P is on the forward extension of AB
00129 //        0<r<1    P is interior to AB
00130 //
00131 //    The length of a line segment in d dimensions, AB is computed by:
00132 //
00133 //        L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 + ... + (Bd-Ad)^2)
00134 //
00135 //    so in 2D:
00136 //
00137 //        L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )
00138 //
00139 //    and the dot product of two vectors in d dimensions, U dot V is computed:
00140 //
00141 //        D = (Ux * Vx) + (Uy * Vy) + ... + (Ud * Vd)
00142 //
00143 //    so in 2D:
00144 //
00145 //        D = (Ux * Vx) + (Uy * Vy)
00146 //
00147 //    So (1) expands to:
00148 //
00149 //            (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
00150 //        r = -------------------------------
00151 //                          L^2
00152 //
00153 //    The point P can then be found:
00154 //
00155 //        Px = Ax + r(Bx-Ax)
00156 //        Py = Ay + r(By-Ay)
00157 //
00158 //    And the distance from A to P = r*L.
00159 //
00160 //    Use another parameter s to indicate the location along PC, with the
00161 //    following meaning:
00162 //           s<0      C is left of AB
00163 //           s>0      C is right of AB
00164 //           s=0      C is on AB
00165 //
00166 //    Compute s as follows:
00167 //
00168 //            (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
00169 //        s = -----------------------------
00170 //                        L^2
00171 //
00172 //
00173 //    Then the distance from C to P = |s|*L.
00174 
00175         const double cx = point.getX();
00176         const double cy = point.getY();
00177 
00178         const double ax = getP1().getX();
00179         const double ay = getP1().getY();
00180         const double bx = getP2().getX();
00181         const double by = getP2().getY();
00182 
00183         const double r_numerator = (cx - ax) * (bx - ax) + (cy - ay) * (by - ay);
00184         const double r_denomenator = (bx - ax) * (bx - ax) + (by - ay) * (by - ay);
00185         const double r = r_numerator / r_denomenator;
00186 
00187 //      const double px = ax + r * (bx - ax);
00188 //      const double py = ay + r * (by - ay);
00189 
00190         const double s =  ((ay - cy) * (bx - ax) - (ax - cx) * (by - ay) ) / r_denomenator;
00191 
00192         const double distanceLine = std::abs(s) * sqrt(r_denomenator);
00193         double distanceSegment = -1.0;
00194 
00195         // (xx,yy) is the point on the lineSegment closest to (cx,cy)
00196 
00197 //      double xx = px;
00198 //      double yy = py;
00199 
00200         if ( (r >= 0) && (r <= 1) )
00201         {
00202                 distanceSegment = distanceLine;
00203         }
00204         else
00205         {
00206                 double dist1 = (cx - ax) * (cx - ax) + (cy - ay) * (cy - ay);
00207                 double dist2 = (cx - bx) * (cx - bx) + (cy - by) * (cy - by);
00208                 if (dist1 < dist2)
00209                 {
00210 //                      xx = ax;
00211 //                      yy = ay;
00212                         distanceSegment = sqrt(dist1);
00213                 }
00214                 else
00215                 {
00216 //                      xx = bx;
00217 //                      yy = by;
00218                         distanceSegment = sqrt(dist2);
00219                 }
00220         }
00221 
00222         return distanceSegment;
00223 }
00224 
00225 
00226 // Line intersection algorithm, copied from Graphics Gems II
00227 #define SAME_SIGNS(a, b) ((a) * (b) >= 0)
00228 template<typename FloatT>
00229 static bool line2d_intersect(FloatT x1, FloatT y1, FloatT x2, FloatT y2,
00230                                                          FloatT x3, FloatT y3, FloatT x4, FloatT y4)
00231 {
00232         FloatT a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns. */
00233         FloatT r1, r2, r3, r4;         /* 'Sign' values */
00234 
00235         a1 = y2 - y1;
00236         b1 = x1 - x2;
00237         c1 = x2 * y1 - x1 * y2;
00238 
00239         r3 = a1 * x3 + b1 * y3 + c1;
00240         r4 = a1 * x4 + b1 * y4 + c1;
00241 
00242         if ( r3 != 0 && r4 != 0 && SAME_SIGNS( r3, r4 ))
00243                 return false;
00244 
00245         a2 = y4 - y3;
00246         b2 = x3 - x4;
00247         c2 = x4 * y3 - x3 * y4;
00248 
00249         r1 = a2 * x1 + b2 * y1 + c2;
00250         r2 = a2 * x2 + b2 * y2 + c2;
00251 
00252         if ( r1 != 0 && r2 != 0 && SAME_SIGNS( r1, r2 ))
00253                 return false;
00254 
00255         return true;
00256 }
00257 
00258 Line2D::IntersectingType Line2D::isIntersecting(const Line2D& other, Point2D* point) const
00259 {
00260         if (isZero() || other.isZero())
00261                 return NotIntersecting;
00262 
00263         bool has_inside_intersection =
00264                 line2d_intersect(first.getX(), first.getY(),
00265                                                  second.getX(), second.getY(),
00266                                                  other.first.getX(), other.first.getY(),
00267                                                  other.second.getX(), other.second.getY());
00268 
00269         bool is_vertical = fuzzyCompare(getDiff().getX(), 0.0);
00270         bool other_is_vertical = fuzzyCompare(other.getDiff().getX(), 0.0);
00271         IntersectingType result =
00272                 has_inside_intersection ? LineIntersecting : OutsideIntersecting;
00273         Point2D intersectPoint;
00274 
00275         if (is_vertical && other_is_vertical)
00276                 result = NotIntersecting;
00277         else if (is_vertical)
00278         {
00279                 Point2D otherdiff = other.getDiff();
00280                 double oa = otherdiff.getY() / otherdiff.getX();
00281                 intersectPoint.setXY(first.getX(),
00282                                                          oa * first.getX() + other.first.getY() - oa * other.first.getX());
00283         }
00284         else if (other_is_vertical)
00285         {
00286                 Point2D diff = getDiff();
00287                 double a = diff.getY() / diff.getX();
00288                 intersectPoint.setXY(other.first.getX(),
00289                                                          a * other.first.getX() + first.getY() - a * first.getX());
00290         }
00291         else
00292         {
00293                 Point2D otherdiff = other.getDiff();
00294                 double oa = otherdiff.getY() / otherdiff.getX();
00295                 Point2D diff = getDiff();
00296                 double ta = diff.getY() / diff.getX();
00297                 if (oa == ta) // parallel lines
00298                         return NotIntersecting;
00299                 double x = ( - other.first.getY() + oa * other.first.getX()
00300                                         + first.getY() - ta * first.getX() ) / (oa - ta);
00301                 intersectPoint.setXY(x, ta * (x - first.getX()) + first.getY());
00302         }
00303 
00304         if (point)
00305                 *point = intersectPoint;
00306         return result;
00307 }
00308 
00309 Line2D Line2D::fromLinearRegression(const Polygon2D &points)
00310 {
00311         if (points.size() >= 2)
00312         {
00313                 // y = a + b*x
00314 
00315                 const Point2D mean(points.getCenterOfGravity());
00316 
00317                 double SSxy = 0;
00318                 double SSxx = 0;
00319                 double minX = points.front().getX();
00320                 double maxX = minX;
00321 
00322                 for (Polygon2D::const_iterator point = points.begin(); point != points.end(); ++point)
00323                 {
00324                         minX = std::min(minX, double(point->getX()));
00325                         maxX = std::max(maxX, double(point->getX()));
00326                         SSxy += (point->getX() - mean.getX()) * (point->getY() - mean.getY());
00327                         SSxx += (point->getX() - mean.getX()) * (point->getX() - mean.getX());
00328                 }
00329 
00330                 const double b(SSxy / SSxx);
00331                 const double a(mean.getY() - b * mean.getX());
00332 
00333                 return Line2D(Point2D(minX, a + b * minX), Point2D(maxX, a + b * maxX));
00334         }
00335 
00336         return Line2D();
00337 }
00338 
00339 Point2D Line2D::getCenterPoint() const
00340 {
00341         return getP1() + (0.5  * getDiff());
00342 }
00343 
00344 }       // namespace datatypes


libsick_ldmrs
Author(s): SICK AG , Martin Günther , Jochen Sprickerhof
autogenerated on Wed Jun 14 2017 04:04:50