Library of Assembled Shared Sources
line_segment_2d.inl
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_LINE_SEGMENT_2D_INL
44#define LASS_GUARDIAN_OF_INCLUSION_PRIM_LINE_SEGMENT_2D_INL
45
46#include "line_segment_2d.h"
47#include "point_2dh.h"
49
50namespace lass
51{
52namespace prim
53{
54
55template <typename T, class PP>
56LineSegment2D<T, PP>::LineSegment2D():
57 tail_(),
58 head_()
59{
60 LASS_ASSERT(tail_.isZero());
61 LASS_ASSERT(head_.isZero());
62}
63
64
65
66template <typename T, class PP>
67LineSegment2D<T, PP>::LineSegment2D(const TPoint& tail, const TPoint& head):
68 tail_(tail),
69 head_(head)
70{
71}
72
73
74
75template <typename T, class PP> inline
76const typename LineSegment2D<T, PP>::TPoint&
77LineSegment2D<T, PP>::tail() const
78{
79 return tail_;
80}
81
82
83
84template <typename T, class PP> inline
85typename LineSegment2D<T, PP>::TPoint&
86LineSegment2D<T, PP>::tail()
87{
88 return tail_;
89}
90
91
92
93template <typename T, class PP> inline
94const typename LineSegment2D<T, PP>::TPoint&
95LineSegment2D<T, PP>::head() const
96{
97 return head_;
98}
99
100
101
102template <typename T, class PP> inline
103typename LineSegment2D<T, PP>::TPoint&
104LineSegment2D<T, PP>::head()
105{
106 return head_;
111/** Return point on ray by it's parameter.
112 * @return origin + t * direction
113 */
114template <typename T, class PP>
115const typename LineSegment2D<T, PP>::TPoint
117{
118 TParameterPolicy::enforceRange(t, TNumTraits::zero, TNumTraits::one);
119 return tail_ + t * vector();
120}
121
122
123
124/** Return parameter of @e projection of @a iPoint on line segment.
125 * @warning the result can be out of bound [0, 1] regardless the parameter policy used.
126 */
127template <typename T, class PP>
128const typename LineSegment2D<T, PP>::TValue
129LineSegment2D<T, PP>::t(const TPoint& point) const
130{
131 const TVector v = vector();
132 const TValue t1 = dot(point - tail_, v);
133 const TValue t2 = -dot(point - head_, v);
134 const TValue t = std::max(t1,t2) / (t1 + t2);
135 return t1 > t2 ? t : TNumTraits::one - t;
136}
137
138
139
140/** Return vector from tail to head.
141 */
142template <typename T, class PP>
143const typename LineSegment2D<T, PP>::TVector
145{
146 return head_ - tail_;
147}
148
149
150
151/** Return length of line segment.
152 */
153template <typename T, class PP>
154const typename LineSegment2D<T, PP>::TValue
156{
157 const TVector v = vector();
158 return v.norm();
159}
160
161
162
163template <typename T, class PP>
164T squaredDistance(const LineSegment2D<T, PP>& segment, const Point2D<T>& point)
165{
166 typedef typename LineSegment2D<T, PP>::TVector TVector;
167 typedef typename LineSegment2D<T, PP>::TValue TValue;
168
169 const TVector edge = segment.vector();
170 const TVector v = point - segment.tail();
171 const TValue t = dot(v, edge);
172 const TValue tMax = dot(edge, edge);
173 if (t <= 0)
174 {
175 return v.squaredNorm();
176 }
177 if (t >= tMax)
178 {
179 return squaredDistance(segment.head(), point);
180 }
181 return (v - edge * (t / tMax)).squaredNorm();
182}
183
184
185
186template <typename T, class PP>
187T distance(const LineSegment2D<T, PP>& segment, const Point2D<T>& point)
188{
189 return num::sqrt(squaredDistance(segment, point));
190}
191
192
193
194/** intersection of two line segments
195 * @relates LineSegment2D
196 * @param a [in] line segment A
197 * @param b [in] line segment B
198 * @param aT [out] parameter of intersection point on line segment A
199 * @param bT [out] parameter of intersection point on line segment B
200 * @return @arg rNone the line segments don't intersect, they have no points in common.
201 * @a tA and @a tB are not assigned.
202 * @arg rOne both line segments have exactly one point in common.
203 * @a tA and @a tB contain parameters of intersection point.
204 * @arg rInfinite the line segments have more than one point in common, they overlap.
205 * @a tA and @a tB are not assigned.
206 */
207template <typename T, class PPa, class PPb>
208Result intersect(const LineSegment2D<T, PPa>& a, const LineSegment2D<T, PPb>& b, T& tA, T& tB)
209{
210 typedef typename LineSegment2D<T, PPa>::TVector TVector;
211 typedef typename LineSegment2D<T, PPa>::TValue TValue;
212 typedef typename LineSegment2D<T, PPa>::TNumTraits TNumTraits;
213 typedef num::Consistent<TValue> TConsistent;
214
215 const TVector dirA(a.vector());
216 const TVector dirB(b.vector());
217
218 const TValue denominator = -perpDot(dirA, dirB);
219 if (denominator == TNumTraits::zero)
220 {
221 const TValue tTail = a.t(b.tail());
222 const TValue tHead = b.t(b.head());
223 if ((tTail < TNumTraits::zero && tHead < TNumTraits::zero) ||
224 (tTail > TNumTraits::one && tHead > TNumTraits::one))
225 {
226 return rNone; // complete seperated along axis
227 }
228 else
229 {
230 // overlapping on axis, yet, they can lay on "different" axes.
231 //
232 if (doubleTriangleArea(a.tail(), a.head(), b.tail()) == TNumTraits::zero)
233 {
234 return rInfinite; // coincident axes
235 }
236 else
237 {
238 return rNone; // parallel
239 }
240 }
241 }
242 else
243 {
244 const TVector difference = b.tail() - a.tail();
245 const TConsistent candidateA = -perpDot(difference, dirB) / denominator;
246 const TConsistent candidateB = perpDot(dirA, difference) / denominator;
247 if (candidateA < TNumTraits::zero || candidateA > TNumTraits::one ||
248 candidateB < TNumTraits::zero || candidateB > TNumTraits::one)
249 {
250 return rNone;
251 }
252 else
253 {
254 tA = candidateA.value();
255 tB = candidateB.value();
256 return rOne;
257 }
258 }
259}
260
261
262
263/** intersection of two line segments
264 * @relates Line2D
265 * @param a [in] line segment A
266 * @param b [in] line segment B
267 * @param point [out] intersection point
268 * @return @arg rNone the line segments don't intersect, they have no points in common.
269 * @a point is not assigned.
270 * @arg rOne both line segments have exactly one point in common.
271 * @a point contains intersection point.
272 * @arg rInfinite the line segments have more than one point in common, they overlap.
273 * @a point is not assigned.
274 */
275template <typename T, class PPa, class PPb>
277{
278 T tA;
279 T tB;
280 const Result result = intersect(a, b, tA, tB);
281 if (result == rOne)
282 {
283 Point2DH<T> intersection(a.point(tA));
284 intersection += b.point(tB);
285 point = intersection.affine(); // take average for more stable point.
286 }
287 return result;
288}
289
290template <typename T, class PPa, class PPb>
291bool intersects(const LineSegment2D<T, PPa>& a, const LineSegment2D<T, PPb>& b)
292{
293 T tA;
294 T tB;
295 return intersect(a, b, tA, tB) != rNone;
296}
297
298/** @relates lass::prim::LineSegment2D
299 */
300template <typename T, class PPa, class PPb> bool operator==(const LineSegment2D<T, PPa>& a, const LineSegment2D<T, PPb>& b)
301{
302 return a.tail()==b.tail() && a.head()==b.head();
303}
304
305/** @relates lass::prim::LineSegment2D
306 */
307template <typename T, class PPa, class PPb> bool operator!=(const LineSegment2D<T, PPa>& a, const LineSegment2D<T, PPb>& b)
308{
309 return !(a==b);
310}
311
312
313/** @relates lass::prim::LineSegment2D
314 */
315template<typename T, class PP>
316std::ostream& operator<<(std::ostream& stream, const LineSegment2D<T, PP>& segment)
317{
318 LASS_ENFORCE_STREAM(stream) << "{T=" << segment.tail() << ", H=" << segment.head() << "}";
319 return stream;
320}
321
322
323
324/** @relates lass::prim::LineSegment2D
325 */
326template<typename T, class PP>
327io::XmlOStream& operator<<(io::XmlOStream& stream, const LineSegment2D<T, PP>& segment)
328{
329 LASS_ENFORCE_STREAM(stream)
330 << "<LineSegment2D>\n"
331 << "<tail>" << segment.tail() << "</tail>\n"
332 << "<head>" << segment.head() << "</head>\n"
333 << "</LineSegment2D>\n";
334
335 return stream;
336}
337
338
339/** @relates lass::prim::LineSegment2D
340 */
341template<typename T, class PP>
342lass::io::MatlabOStream& operator<<(lass::io::MatlabOStream& stream, const LineSegment2D<T, PP>& segment)
343{
344 LASS_ENFORCE_STREAM(stream) << "lasthandle = line(";
345 stream << "[" << segment.tail().x << "," << segment.head().x << "],";
346 stream << "[" << segment.tail().y << "," << segment.head().y << "],";
347 stream << "'Color'," << stream.color() << ");\n";
348 return stream;
349}
350
351
352}
353
354}
355
356#endif
Output stream for writing a selection of geometric primitives to matlab M files.
Result intersect(const LineSegment2D< T, PPa > &a, const LineSegment2D< T, PPb > &b, Point2D< T > &point)
intersection of two line segments
Result intersect(const Line2D< T, EPa, NPa > &iA, const Line2D< T, EPb, NPb > &iB, T &oTa, T &oTb)
Definition line_2d.inl:235
const TVector vector() const
Return vector from tail to head.
const TPoint point(TParam t) const
Return point on ray by it's parameter.
const TValue length() const
Return length of line segment.
const TValue t(const TPoint &point) const
Return parameter of projection of iPoint on line segment.
Result intersect(const LineSegment2D< T, PPa > &a, const LineSegment2D< T, PPb > &b, T &tA, T &tB)
intersection of two line segments
set of geometrical primitives
Definition aabb_2d.h:81
Result
meta information on the result you have from an operation like an intersection ...
Definition result.h:74
@ rInfinite
there are infinite many solutions, output arguments are meaningless
Definition result.h:79
@ rNone
operation has no answer, output arguments are meaningless
Definition result.h:76
@ rOne
there's exactly one answer, 1 output argument contains the answer
Definition result.h:77
Library for Assembled Shared Sources.
Definition config.h:53
homogenous 2D Point
Definition point_2dh.h:63
const Point2D< T > affine() const
Return rescaled version of point with weight = 1.
const TValue norm() const
Return norm of vector.