00001
00002
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();
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
00048 if (first.getY() < second.getY())
00049 return M_PI_2;
00050 else
00051 return -M_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
00106 return point;
00107 }
00108 }
00109
00110 double Line2D::distanceFromLineSegment(const Point2D& point) const
00111 {
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
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
00188
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
00196
00197
00198
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
00211
00212 distanceSegment = sqrt(dist1);
00213 }
00214 else
00215 {
00216
00217
00218 distanceSegment = sqrt(dist2);
00219 }
00220 }
00221
00222 return distanceSegment;
00223 }
00224
00225
00226
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;
00233 FloatT r1, r2, r3, r4;
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)
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
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 }