Saga3D API Documentation  1.0-RC4
line2d.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #ifndef __IRR_LINE_2D_H_INCLUDED__
6 #define __IRR_LINE_2D_H_INCLUDED__
7 
8 #include "vector2d.h"
9 
10 namespace saga
11 {
12 namespace core
13 {
14 
16 template <class T>
17 class line2d
18 {
19  public:
21  line2d() : start(0,0), end(1,1) {}
23  line2d(T xa, T ya, T xb, T yb) : start(xa, ya), end(xb, yb) {}
25  line2d(const vector2d<T>& start, const vector2d<T>& end) : start(start), end(end) {}
27  line2d(const line2d<T>& other) : start(other.start), end(other.end) {}
28 
29  // operators
30 
31  line2d<T> operator+(const vector2d<T>& point) const { return line2d<T>(start + point, end + point); }
32  line2d<T>& operator+=(const vector2d<T>& point) { start += point; end += point; return *this; }
33 
34  line2d<T> operator-(const vector2d<T>& point) const { return line2d<T>(start - point, end - point); }
35  line2d<T>& operator-=(const vector2d<T>& point) { start -= point; end -= point; return *this; }
36 
37  bool operator==(const line2d<T>& other) const
38  { return (start==other.start && end==other.end) || (end==other.start && start==other.end);}
39  bool operator!=(const line2d<T>& other) const
40  { return !(start==other.start && end==other.end) || (end==other.start && start==other.end);}
41 
42  // functions
44  void setLine(const T& xa, const T& ya, const T& xb, const T& yb){start.set(xa, ya); end.set(xb, yb);}
46  void setLine(const vector2d<T>& nstart, const vector2d<T>& nend){start.set(nstart); end.set(nend);}
48  void setLine(const line2d<T>& line){start.set(line.start); end.set(line.end);}
49 
51 
52  T getLength() const { return start.getDistanceFrom(end); }
53 
55 
56  T getLengthSQ() const { return start.getDistanceFromSQ(end); }
57 
59 
60  vector2d<T> getMiddle() const
61  {
62  return (start + end)/(T)2;
63  }
64 
66 
67  vector2d<T> getVector() const { return vector2d<T>(end.X - start.X, end.Y - start.Y); }
68 
71  bool intersectAsSegments(const line2d<T>& other) const
72  {
73  // Taken from:
74  // http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
75 
76  // Find the four orientations needed for general and
77  // special cases
78  std::int32_t o1 = start.checkOrientation(end, other.start);
79  std::int32_t o2 = start.checkOrientation(end, other.end);
80  std::int32_t o3 = other.start.checkOrientation(other.end, start);
81  std::int32_t o4 = other.start.checkOrientation(other.end, end);
82 
83  // General case
84  if (o1 != o2 && o3 != o4)
85  return true;
86 
87  // Special Cases to check if segments are coolinear
88  if (o1 == 0 && isBetweenPoints(other.start, start, end)) return true;
89  if (o2 == 0 && isBetweenPoints(other.end, start, end)) return true;
90  if (o3 == 0 && isBetweenPoints(start, other.start, other.end)) return true;
91  if (o4 == 0 && isBetweenPoints(end, other.start, other.end)) return true;
92 
93  return false; // Doesn't fall in any of the above cases
94  }
95 
97  bool incidentSegments(const line2d<T>& other) const
98  {
99  return
100  start.checkOrientation(end, other.start) != start.checkOrientation(end, other.end)
101  && other.start.checkOrientation(other.end, start) != other.start.checkOrientation(other.end, end);
102  }
103 
105  bool nearlyParallel(const line2d<T>& line, const T factor = relativeErrorFactor<T>()) const
106  {
107  const vector2d<T> a = getVector();
108  const vector2d<T> b = line.getVector();
109 
110  return a.nearlyParallel(b, factor);
111  }
112 
117  vector2d<T> fastLinesIntersection(const line2d<T>& l) const
118  {
119  const float commonDenominator = (float)((l.end.Y - l.start.Y)*(end.X - start.X) -
120  (l.end.X - l.start.X)*(end.Y - start.Y));
121 
122  if (commonDenominator != 0.f)
123  {
124  const float numeratorA = (float)((l.end.X - l.start.X)*(start.Y - l.start.Y) -
125  (l.end.Y - l.start.Y)*(start.X - l.start.X));
126 
127  const float uA = numeratorA / commonDenominator;
128 
129  // Calculate the intersection point.
130  return vector2d<T> (
131  (T)(start.X + uA * (end.X - start.X)),
132  (T)(start.Y + uA * (end.Y - start.Y))
133  );
134  }
135  else
136  return l.start;
137  }
138 
140  bool lineIntersectSegment(const line2d<T>& segment, vector2d<T> & out) const
141  {
142  if (nearlyParallel(segment))
143  return false;
144 
145  out = fastLinesIntersection(segment);
146 
147  return isBetweenPoints(out, segment.start, segment.end);
148  }
149 
151 
159  bool intersectWith(const line2d<T>& l, vector2d<T>& out, bool checkOnlySegments=true, bool ignoreCoincidentLines=false) const
160  {
161  // Uses the method given at:
162  // http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/
163  const float commonDenominator = (float)((l.end.Y - l.start.Y)*(end.X - start.X) -
164  (l.end.X - l.start.X)*(end.Y - start.Y));
165 
166  const float numeratorA = (float)((l.end.X - l.start.X)*(start.Y - l.start.Y) -
167  (l.end.Y - l.start.Y)*(start.X -l.start.X));
168 
169  const float numeratorB = (float)((end.X - start.X)*(start.Y - l.start.Y) -
170  (end.Y - start.Y)*(start.X -l.start.X));
171 
172  if(equals(commonDenominator, 0.f))
173  {
174  // The lines are either coincident or parallel
175  // if both numerators are 0, the lines are coincident
176  if(!ignoreCoincidentLines && equals(numeratorA, 0.f) && equals(numeratorB, 0.f))
177  {
178  // Try and find a common endpoint
179  if(l.start == start || l.end == start)
180  out = start;
181  else if(l.end == end || l.start == end)
182  out = end;
183  // now check if the two segments are disjunct
184  else if (l.start.X>start.X && l.end.X>start.X && l.start.X>end.X && l.end.X>end.X)
185  return false;
186  else if (l.start.Y>start.Y && l.end.Y>start.Y && l.start.Y>end.Y && l.end.Y>end.Y)
187  return false;
188  else if (l.start.X<start.X && l.end.X<start.X && l.start.X<end.X && l.end.X<end.X)
189  return false;
190  else if (l.start.Y<start.Y && l.end.Y<start.Y && l.start.Y<end.Y && l.end.Y<end.Y)
191  return false;
192  // else the lines are overlapping to some extent
193  else
194  {
195  // find the points which are not contributing to the
196  // common part
197  vector2d<T> maxp;
198  vector2d<T> minp;
199  if ((start.X>l.start.X && start.X>l.end.X && start.X>end.X) || (start.Y>l.start.Y && start.Y>l.end.Y && start.Y>end.Y))
200  maxp=start;
201  else if ((end.X>l.start.X && end.X>l.end.X && end.X>start.X) || (end.Y>l.start.Y && end.Y>l.end.Y && end.Y>start.Y))
202  maxp=end;
203  else if ((l.start.X>start.X && l.start.X>l.end.X && l.start.X>end.X) || (l.start.Y>start.Y && l.start.Y>l.end.Y && l.start.Y>end.Y))
204  maxp=l.start;
205  else
206  maxp=l.end;
207  if (maxp != start && ((start.X<l.start.X && start.X<l.end.X && start.X<end.X) || (start.Y<l.start.Y && start.Y<l.end.Y && start.Y<end.Y)))
208  minp=start;
209  else if (maxp != end && ((end.X<l.start.X && end.X<l.end.X && end.X<start.X) || (end.Y<l.start.Y && end.Y<l.end.Y && end.Y<start.Y)))
210  minp=end;
211  else if (maxp != l.start && ((l.start.X<start.X && l.start.X<l.end.X && l.start.X<end.X) || (l.start.Y<start.Y && l.start.Y<l.end.Y && l.start.Y<end.Y)))
212  minp=l.start;
213  else
214  minp=l.end;
215 
216  // one line is contained in the other. Pick the center
217  // of the remaining points, which overlap for sure
218  out = core::vector2d<T>();
219  if (start != maxp && start != minp)
220  out += start;
221  if (end != maxp && end != minp)
222  out += end;
223  if (l.start != maxp && l.start != minp)
224  out += l.start;
225  if (l.end != maxp && l.end != minp)
226  out += l.end;
227  out.X = (T)(out.X/2);
228  out.Y = (T)(out.Y/2);
229  }
230 
231  return true; // coincident
232  }
233 
234  return false; // parallel
235  }
236 
237  // Get the point of intersection on this line, checking that
238  // it is within the line segment.
239  const float uA = numeratorA / commonDenominator;
240  if (checkOnlySegments)
241  {
242  if(uA < 0.f || uA > 1.f)
243  return false; // Outside the line segment
244 
245  const float uB = numeratorB / commonDenominator;
246  if(uB < 0.f || uB > 1.f)
247  return false; // Outside the line segment
248  }
249 
250  // Calculate the intersection point.
251  out.X = (T)(start.X + uA * (end.X - start.X));
252  out.Y = (T)(start.Y + uA * (end.Y - start.Y));
253  return true;
254  }
255 
257 
258  vector2d<T> getUnitVector() const
259  {
260  T len = (T)(1.0 / getLength());
261  return vector2d<T>((end.X - start.X) * len, (end.Y - start.Y) * len);
262  }
263 
265 
267  double getAngleWith(const line2d<T>& l) const
268  {
269  vector2d<T> vect = getVector();
270  vector2d<T> vect2 = l.getVector();
271  return vect.getAngleWith(vect2);
272  }
273 
275 
277  T getPointOrientation(const vector2d<T>& point) const
278  {
279  return ((end.X - start.X) * (point.Y - start.Y) -
280  (point.X - start.X) * (end.Y - start.Y));
281  }
282 
284 
285  bool isPointOnLine(const vector2d<T>& point) const
286  {
287  T d = getPointOrientation(point);
288  return (d == 0 && isBetweenPoints(point, start, end));
289  }
290 
292 
293  bool isPointBetweenStartAndEnd(const vector2d<T>& point) const
294  {
295  return isBetweenPoints(point, start, end);
296  }
297 
299 
301  vector2d<T> getClosestPoint(const vector2d<T>& point, bool checkOnlySegments=true) const
302  {
303  vector2d<double> c((double)(point.X-start.X), (double)(point.Y- start.Y));
304  vector2d<double> v((double)(end.X-start.X), (double)(end.Y-start.Y));
305  double d = v.getLength();
306  if (d == 0) // can't tell much when the line is just a single point
307  return start;
308  v /= d;
309  double t = v.dotProduct(c);
310 
311  if (checkOnlySegments)
312  {
313  if (t < 0) return vector2d<T>((T)start.X, (T)start.Y);
314  if (t > d) return vector2d<T>((T)end.X, (T)end.Y);
315  }
316 
317  v *= t;
318  return vector2d<T>((T)(start.X + v.X), (T)(start.Y + v.Y));
319  }
320 
322  vector2d<T> start;
324  vector2d<T> end;
325 };
326 
327  // partial specialization to optimize <float> lines (avoiding casts)
328  template <>
329  inline vector2df line2d<float>::getClosestPoint(const vector2df& point, bool checkOnlySegments) const
330  {
331  vector2df c = point - start;
332  vector2df v = end - start;
333  float d = (float)v.getLength();
334  if (d == 0) // can't tell much when the line is just a single point
335  return start;
336  v /= d;
337  float t = v.dotProduct(c);
338 
339  if (checkOnlySegments)
340  {
341  if (t < 0) return start;
342  if (t > d) return end;
343  }
344 
345  v *= t;
346  return start + v;
347  }
348 
349 
354 
355 } // namespace core
356 } // namespace saga
357 
358 #endif
359 
saga::core::line2d::operator-
line2d< T > operator-(const vector2d< T > &point) const
Definition: line2d.h:34
saga::core::line2d::intersectAsSegments
bool intersectAsSegments(const line2d< T > &other) const
Definition: line2d.h:71
saga::core::line2d::operator==
bool operator==(const line2d< T > &other) const
Definition: line2d.h:37
saga::core::line2d::operator!=
bool operator!=(const line2d< T > &other) const
Definition: line2d.h:39
saga::core::line2d::fastLinesIntersection
vector2d< T > fastLinesIntersection(const line2d< T > &l) const
Definition: line2d.h:117
saga::core::line2d::incidentSegments
bool incidentSegments(const line2d< T > &other) const
Definition: line2d.h:97
saga::core::line2d::line2d
line2d()
Default constructor for line going from (0,0) to (1,1).
Definition: line2d.h:21
saga::core::line2d::lineIntersectSegment
bool lineIntersectSegment(const line2d< T > &segment, vector2d< T > &out) const
Definition: line2d.h:140
saga::core::line2d::setLine
void setLine(const T &xa, const T &ya, const T &xb, const T &yb)
Set this line to new line going through the two points.
Definition: line2d.h:44
saga::core::line2d::getUnitVector
vector2d< T > getUnitVector() const
Get unit vector of the line.
Definition: line2d.h:258
saga::core::line2d::getVector
vector2d< T > getVector() const
Get the vector of the line.
Definition: line2d.h:67
saga::core::line2d::getLengthSQ
T getLengthSQ() const
Get squared length of the line.
Definition: line2d.h:56
saga::core::line2d::operator-=
line2d< T > & operator-=(const vector2d< T > &point)
Definition: line2d.h:35
saga::core::line2d::isPointBetweenStartAndEnd
bool isPointBetweenStartAndEnd(const vector2d< T > &point) const
Check if the given point is between start and end of the line.
Definition: line2d.h:293
saga::core::equals
bool equals(const T a, const T b, const T tolerance=roundingError< T >())
returns if a equals b, taking possible rounding errors into account
Definition: irrMath.h:285
saga::core::line2df
line2d< float > line2df
Typedef for an float line.
Definition: line2d.h:351
saga::core::line2d::nearlyParallel
bool nearlyParallel(const line2d< T > &line, const T factor=relativeErrorFactor< T >()) const
Definition: line2d.h:105
saga::core::isBetweenPoints
bool isBetweenPoints(const glm::vec3 &point, const glm::vec3 &begin, const glm::vec3 &end)
Definition: irrMath.h:65
saga::core::line2d::isPointOnLine
bool isPointOnLine(const vector2d< T > &point) const
Check if the given point is a member of the line.
Definition: line2d.h:285
saga::core::line2d::intersectWith
bool intersectWith(const line2d< T > &l, vector2d< T > &out, bool checkOnlySegments=true, bool ignoreCoincidentLines=false) const
Tests if this line intersects with another line.
Definition: line2d.h:159
saga::core::line2d::getLength
T getLength() const
Get length of line.
Definition: line2d.h:52
saga::core::line2d::getClosestPoint
vector2d< T > getClosestPoint(const vector2d< T > &point, bool checkOnlySegments=true) const
Get the closest point on this line to a point.
Definition: line2d.h:301
saga::core::line2d::line2d
line2d(T xa, T ya, T xb, T yb)
Constructor for line between the two points.
Definition: line2d.h:23
saga::core::line2d::getPointOrientation
T getPointOrientation(const vector2d< T > &point) const
Tells us if the given point lies to the left, right, or on the line.
Definition: line2d.h:277
saga::core::line2d::line2d
line2d(const line2d< T > &other)
Copy constructor.
Definition: line2d.h:27
saga::core::line2d::line2d
line2d(const vector2d< T > &start, const vector2d< T > &end)
Constructor for line between the two points given as vectors.
Definition: line2d.h:25
saga::core::line2d::setLine
void setLine(const line2d< T > &line)
Set this line to new line given as parameter.
Definition: line2d.h:48
saga::core::line2d::setLine
void setLine(const vector2d< T > &nstart, const vector2d< T > &nend)
Set this line to new line going through the two points.
Definition: line2d.h:46
saga::core::line2d::start
vector2d< T > start
Start point of the line.
Definition: line2d.h:322
saga::core::line2d::operator+
line2d< T > operator+(const vector2d< T > &point) const
Definition: line2d.h:31
saga::core::line2d
2D line between two points with intersection methods.
Definition: line2d.h:17
saga::core::line2di
line2d< std::int32_t > line2di
Typedef for an integer line.
Definition: line2d.h:353
saga::core::line2d::getAngleWith
double getAngleWith(const line2d< T > &l) const
Get angle between this line and given line.
Definition: line2d.h:267
saga::core::line2d::operator+=
line2d< T > & operator+=(const vector2d< T > &point)
Definition: line2d.h:32
saga::core::line2d::end
vector2d< T > end
End point of the line.
Definition: line2d.h:324
saga
Definition: aabbox3d.h:11
saga::core::line2d::getMiddle
vector2d< T > getMiddle() const
Get middle of the line.
Definition: line2d.h:60