Library of Assembled Shared Sources
line_2d.h
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
44
45/** @class lass::prim::Line2D
46 * @brief 2D Line
47 * @author Bram de Greve [BdG]
48 * @date 2003
49 *
50 * I assume if you look to this class, you'll wonder ... "where the heck did all the code go?"
51 * Hah, I'll tell ya. There is more than one possible model to represent a line. We can
52 * use a cartesian equation @c N.P+S=0, or we can use a parametric equation @c P=S+t*U.
53 * This class lets you choose what implementation you want: a pure cartesian model, a pure
54 * parametric model, or a model that combines both. This is done by moving all code to
55 * implemenations impl::Line2DCartesian, impl::Line2DParametric or impl::Line2DCombined. Line2D
56 * will inherit its implementation of the model you've choosen. You can select the one you
57 * want by specifying the template parameter @e EquationPolicy. You can either use Cartesian
58 * (which is the default), Parametric or Combined. Each of them will model the line
59 * differently. They all provide the same interface, but might have different results. They
60 * might have different memory footprints, different performances, and are optimized for
61 * different purposes. Cartesian will select an implementation that only uses the cartesian
62 * equation and will be the smallest and the fastest for most purposes (that's why it is the
63 * default :). But sometimes, you might more like the Parametric model, because it has
64 * better support for direction vectors, but it'll have to calculate the normal on the spot if
65 * you need it. Combined is the workhorse for heavy duties and implements both..
66 *
67 * @section template arguments
68 *
69 * - @a T: the underlying data type, the proton.
70 * - @a @ref EquationPolicy: chooses the model: Cartesian, Parametric or Combined
71 * - @a @ref NormalizingPolicy: enables automatic normalizing or not: Normalized or Unnormalized
72 *
73 * @section common_interface common interface
74 *
75 * Anyway, let me give you some general info on this whole Line2D thing. Though there are
76 * three different implentations, they all have the same interface. We'll explore them by this
77 * common interface:
78 *
79 * @subsection type_definitions type definitions
80 *
81 * - @c TSelf: the type of @a this
82 * - @c TImpl: type of implemantion, can be impl::Line2DCartesian, impl::Line2DParametric or
83 * impl::Line2DCombined.
84 * - @c TNormalizingPolicy: the type you've used as NormalizingPolicy.
85 * - @c TPoint: type of a afine point in space.
86 * - @c TVector: type of a vector in space.
87 * - @c TValue: same as util::CallTraits<T>::TValue.
88 * - @c TParam: same as util::CallTraits<T>::TParam.
89 * - @c TReference: same as util::CallTraits<T>::TReference.
90 * - @c TConstReference: same as util::CallTraits<T>::TConstReference.
91 * - @c TNumTraits: same as num::NumTraits<T>.
92 *
93 * @subsection constructors
94 *
95 * @par Line2D():
96 * the default constructor brings the line in an invalid state. normal and/or direction vector
97 * will have zero length, which indicates for this invalid state.
98 *
99 * @par Line2D(const TPoint& iSupport, const TPoint& iPoint):
100 * construct a line through two points. The parametric equation @a P=S+t*U is going to
101 * be constructed as following: iSupport will be the support point @a S, and direction vector @a U
102 * will be drawn from the support point to @a iPoint: @a U = @a iPointU - @a iSupport. The cartesian
103 * equation @a N.P+d==0 is constructed as following: the normal @a N=perpDot(U) and @a d is determined
104 * by demaning that @a N.S+d==0.
105 *
106 * @par Line2D(const TPoint& iSupport, const TVector& iDirection):
107 * constructs a line through one support point and one direction vector (the parametric equation,
108 * anyone? :). For the parametric equation @a P=S+t*U, we have @a iSupport for @a S, @a iDirection
109 * for @a U. Again the cartesian equation @a N.P+d==0 is given by @a N=perpDot(U) and
110 * @a N.S+d==0.
111 *
112 * @par Line2D(const TPoint& iSupport, const TVector& iNormal):
113 * constructs a line through a support point and a normal vector. For the parametric equation
114 * @a P=S+t*U, we have @a iSupport for @a S, and @a U=-perpDot(N). The cartesian @a N.P+d==0 is
115 * simple, we have @a iNormal for @a N and @a d can be found by @a N.S+d==0.
116 *
117 * @par Line2D(const TVector& iNormal, TParam iD):
118 * construct a line by a normal vector and fourth value (cartesian equation? :). For the
119 * parametric equation @a P=S+t*U, all have to generated: for @a S we use the point @a -iD*iNormal
120 * that is the closest point of the line to the origin, @a U is given by @a U=-perpDot(N).
121 * For the cartesian equation @a N.P+d==0, we of course use @a N = @a iNormal and @a d = @a iD.
122 *
123 * @subsection accessors
124 *
125 * After construction, all vectors are normalized depending on the @a NormalizingPolicy you've
126 * choosen as template argument. if the normal vector @a N is scaled, then @a d is scaled as well, so
127 * it still represents the same line.
128 *
129 * Now, we have a series of accessors that give you access to the internal data of the line,
130 * including support point, direction vectors, normal vector, ... Only Line2DCombined will be
131 * able to pull these directly from its internals, but the others don't have all data aboard, so
132 * they have to generate them. Be carefull, because it's not always what you suspect.
133 *
134 * @par const TPoint support():
135 * returns the support point of the line. If you used a support point for the construction of the
136 * line, models Line2DParametric and Line2DCombined will give you back this original one,
137 * exactly till the last bit. Line2DCartesian doesn't keep track of support points, so it has to
138 * create one if you ask for it. It uses @a -d*N, the point of the line that is closest to the
139 * origin. Mind you that this one probably will not be the same as the original one, totally
140 * different even! Of course, if you used a cartesian equation to construct the line (without any
141 * support point), then all three models need to generate a support point at some point: @a -d*N.
142 * In that case, all three models @e will return the same support point.
143 *
144 * @par const TVector direction():
145 * get the direction vector of the line. almost same story as for @c support(). If you've created
146 * the line by a direction vector ot two points (which leads to the direction vector), then models
147 * Line2DParametric and Line2DCombined will give you back these originals
148 * (for Unnormalized lines only! but in case of Normalized lines, they still correspond with the
149 * original directions). Line2DCartesian has to regenerate them, but it will result in the same
150 * direction vector as the others.
151 *
152 * @par void getCartesian(TVector& oNormal, TReference oD):
153 * gets normal vector and d-value for the cartesian equation. Now, this is the first one
154 * Line2DCartesian has aboard itself. Line2DCombined also has it, but now it's up to
155 * Line2DParametric to generate some stuff :) Though, it's less worse than the other way around.
156 * This is because the parametric equation contains more information on the support point, and
157 * doesn't have to 'invent' anything like Line2DCartesian has to. Actually, in theory, all three
158 * models should return the same normal and d-value. In practice however, we have to deal with
159 * numerical imprecisions. so the result of Line2DParametric can differ a little in the last bits.
160 * not a big difference, but enough to be inequal.
161 *
162 * @par const TVector normal():
163 * returns only the normal vector of the cartesian equation. For Line2DParametric we have again
164 * the same remark as for getDirections and getReciprocals: it uses getCartesian anyway, so that
165 * might be faster if you both need the normal and d-value.
166 *
167 * @par TValue d():
168 * same as normal(), but returns only the value @a d instead of the normal vector.
169 *
170 * @subsection methods_cartesian cartesian methods
171 *
172 * So far the accessors. let's get to cooler stuff. For most of this stuff, we need the cartesian
173 * equation. Line2DCartesian and Line2DCombined have it on board, but Line2DParametric will
174 * have to generate it each call. Keep that in mind!
175 *
176 * @par Side classify(const TPoint& iPoint):
177 * tells at which side of the line we can find the point iPoint: the front (sFront), the back
178 * (sBack), or right on the surface (sSurface). the front is the side where the normal sticks or
179 * points to. The back is the other one. iPoint is exactly one the surface if @a N.iPoint+d==0.
180 * Since we need the parametric equation, Line2DParametric might have a performance hit here.
181 *
182 * @par TValue equation(const TPoint& iPoint):
183 * fills in the point @a iPoint in the cartesian equation and returns the resutl. @a N.iPoint+d will
184 * usually not be equal to zero (it's only zero for points on the line). This method returns what
185 * it is equal to. i.e. it returns @a N.iPoint+d. For Normalized lines this is the same as the
186 * distance of @a iPoint to the line, but not for Unnormalized lines, keep that in mind! If you
187 * need the distance, used @c signedDistances() as described below. Again you might have a
188 * performance hit for the Line2DParametric model because of the need of the cartesian equation.
189 *
190 * @par TValue signedDistance(const TPoint& iPoint):
191 * returns the distance of the point to the line, but signed. it will be positive for points in
192 * front of the line, and negative for the ones in the back (also see: @c classify()). The
193 * real (absolute) distances is simply the absolute value of the result. For Normalized lines
194 * @c signedDistances() will be equal to @c equation(). But for Unnormalized lines
195 * signedDistances still divides through the normal's length Again performance hit for
196 * Line2DParametric because of the need of the cartesian equation.
197 *
198 * @par TVector reject(const TPoint& iPoint):
199 * returns rejection of @a iPoint by the line. This is a bit tricky to explain. If you have a
200 * support point @a S, then this rejection is the part of @a iPoint-S that is parallel to the normal
201 * vector (or orthogonal to the line). This would be the same as the rejection of @a iPoint-S
202 * (given by @c reject(iPoint-S), see below). But more descriptive might be: it is the vector you
203 * have to add to the projection of this point on the line (given by @c project(iPoint), see below),
204 * to get back @a iPoint: @c iPoint==project(iPoint)+reject(iPoint). Again performance hit for
205 * Line2DParametric because of the cartesian equation.
206 *
207 * @par TVector reject(const TVector& iVector):
208 * returns rejection of @a iVector by the line. This is already somewhat easier. the rejection of
209 * @a iVector is that part of @a iVector that is parallel to the normal vector of the line. You can
210 * also say that it is the orthogonal projection of @a iVector on the normal vector. Or the part of
211 * iVector that is orthogonal to the line. Again performance hit for Line2DParametric because
212 * of the cartersian equation.
213 *
214 * @par TPoint project(const TPoint& iPoint):
215 * return the orthogonal projection of @a iPoint on the line. It is the point on the line that is
216 * the closest one to @a iPoint. If you draw a line through @a iPoint parallel to the normal vector,
217 * this projection is the point where this line intersects the line. It is know that in theory
218 * @c iPoint==project(iPoint)+reject(iPoint). Again performance hit for Line2DParametric because
219 * of the cartesian equation.
220 *
221 * @par TVector project(const TVector& iVector):
222 * return the orthogonal projection of @a iVector on the line. It is the part of @a iVector that is
223 * parallel to the line, or orthogonal to the normal vector. It is known that in theory
224 * @c iVector==project(iVector)+reject(iVector). Again performance hit for Line2DParametric because
225 * of the cartesian equation.
226 *
227 * @par TPoint reflect(const TPoint& iPoint):
228 * return the reflection of @a iPoint in the line. It is the point at the same distance of the
229 * line, but at the exact opposite side of the line. If you draw a line through iPoint parallel
230 * to the normal vector, it's the only other point on that line that is at the same (absolute)
231 * distance of the line. If you walk from iPoint to the intersection point of the line and the
232 * line, and you walk further the same distance again, you arrive at reflection of iPoint. It is
233 * known that in theory @c reflect(iPoint)==project(iPoint)-reject(iPoint). Again performance hit
234 * for Line2DParametric because of the cartesian equation.
235 *
236 * @par TVector reflect(const TVector& iVector):
237 * return the reflection of @a iVector in the line. It's the vector of which the orthogonal part to
238 * the line is flipped. It is know that @c reflect(iVector)==project(iVector)-reject(iVector).
239 * Again performance hit for Line2DParametric because of the cartesian equation.
240 *
241 * @subsection methods_parametric parametric methods
242 *
243 * So far functions for the cartesian boys. Now some stuff for parametric fellows. It's about how
244 * we can get a point of the line if we now its parametr @a t, and how we can find @t if we know
245 * the point on the line.
246 *
247 * @par TPoint point(TParam iT):
248 * returns a point of the parametric equation @c P=S+iT*U. In case of
249 * Line2DCartesian, we have the same remarks as for @a direction(): not only we have
250 * a performance hit, we probably also have to deal with totally different direction vectors than
251 * the ones we have put in the constructor.
252 *
253 * @par TValue t(const TPoint& iPoint):
254 * returns a value @a t so that @c iPoint==S+t*U. In theory, if you put this back in @c point(),
255 * you should end up with the projection of @a iPoint: @c point(t(iPoint))==project(iPoint) ?
256 * Well, this is not totally true. In practice, numerical imprecisions will probably give you a
257 * slightly different result. You'll be very close, but the last bits will differ enough to make the
258 * them inequal. But with some epsilons, you'll be alright.
259 *
260 * @subsection misc_methods misc. methods
261 *
262 * @par void flip():
263 * flips the line so that the front becomes the back and the back becomes the front. For the
264 * cartesian equation, this is done by negating the normal and d: @c N=-N and @c d=-d.
265 * Of the parametric equation, direction vector U is flipped: @c U=-U.
266 *
267 * @par bool isValid():
268 * returns true if the interal data represents a valid line, and false if not. A line is valid
269 * if none of the direction vectors nor the normal vector are zero vectors. And above of that,
270 * the direction vectors may not be colinear. Of course, we only test internal data. We will not
271 * generate direction vectors (in case of Line2DCartesian), just to test the if they are valid.
272 * We can safely do that, because we know that if the normal vector is valid, then the generated
273 * directions will be too.
274 *
275 * @subsection free functions
276 *
277 * There are some free functions listed below: distances and intersections.
278 * They are common for all lines and can handle mixed equation policies (two lines with different
279 * equation policies).
280 */
281
282
283
284#ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_LINE_2D_H
285#define LASS_GUARDIAN_OF_INCLUSION_PRIM_LINE_2D_H
286
287#include "prim_common.h"
288#include "point_2d.h"
289#include "equation_policy.h"
290#include "normalizing_policy.h"
291#include "impl/line_2d_impl.h"
292
293
294namespace lass
295{
296namespace prim
297{
298
299template
300<
301 typename T,
302 class EquationPolicy = Cartesian,
303 class NormalizingPolicy = Normalized
304>
305class Line2D: public impl::Line2DImpl<T, EquationPolicy, NormalizingPolicy>::Type
306{
307public:
308 typedef Line2D<T, EquationPolicy, NormalizingPolicy> TSelf;
309 typedef typename impl::Line2DImpl<T, EquationPolicy, NormalizingPolicy>::Type TImpl;
310
311 typedef typename TImpl::TPoint TPoint;
312 typedef typename TImpl::TVector TVector;
313 typedef typename TImpl::TParam TParam;
314 typedef typename TImpl::TValue TValue;
315 typedef typename TImpl::TReference TReference;
316 typedef typename TImpl::TConstReference TConstReference;
317 typedef typename TImpl::TNumTraits TNumTraits;
318
319
320 template <typename U>
321 struct Rebind
322 {
323 typedef Line2D<U, EquationPolicy, NormalizingPolicy> Type;
324 };
325
326 Line2D();
327 Line2D(const TPoint& iSupport, const TPoint& iPoint);
328 Line2D(const TPoint& iSupport, const TVector& iDir);
329 Line2D(const TVector& iNormal, const TPoint& iSupport);
330 Line2D(const TVector& iNormal, TParam iD);
331
332 Side classify(const TPoint& iPoint) const;
333 const TValue signedDistance(const TPoint& iPoint) const;
334 const TValue squaredDistance(const TPoint& iPoint) const;
335 Side classify(const TPoint& iPoint, TParam iRelativeTolerance) const;
336 const TValue signedDistance(const TPoint& iPoint, TParam iRelativeTolerance) const;
337 const TValue squaredDistance(const TPoint& iPoint, TParam iRelativeTolerance) const;
338
339 /*
340 typedef NormalizingPolicy TNormalizingPolicy;
341
342 typedef Point2D<T> TPoint;
343 typedef TPoint::TVector TVector;
344
345 typedef TPoint::TValue TValue;
346 typedef TPoint::TParam TParam;
347 typedef TPoint::TReference TReference;
348 typedef TPoint::TConstReference TConstReference;
349 typedef TPoint::TNumTraits TNumTraits;
350
351 enum { dimension = TPoint::dimension };
352
353 const TPoint support() const;
354 const TVector direction() const;
355
356 void getCartesian(TVector& oNormal, TReference oD) const;
357 const TVector& normal() const;
358 TConstReference d() const;
359
360 Side classify(const TPoint& iPoint) const;
361 TValue equation(const TPoint& iPoint) const;
362 TValue signedDistance(const TPoint& iPoint) const;
363 TValue squaredDistance(const TPoint& iPoint) const;
364
365 TVector reject(const TPoint& iPoint) const;
366 TVector reject(const TVector& iVector) const;
367 TPoint project(const TPoint& iPoint) const;
368 TVector project(const TVector& iVector) const;
369 TPoint reflect(const TPoint& iPoint) const;
370 TVector reflect(const TVector& iVector) const;
371
372 TPoint point(TParam iT) const;
373 TValue t(const TPoint& iPoint) const;
374
375 void flip();
376 bool isValid() const;
377 */
378};
379
380
381
382template <typename T, class EP, class NP>
383T signedDistance(const Point2D<T>& iA, const Line2D<T, EP, NP>& iB);
384
385template <typename T, class EPa, class NPa, class EPb, class NPb>
386T signedDistance(const Line2D<T, EPa, NPa>& iA, const Line2D<T, EPb, NPb>& iB);
387
388template <typename T, class EPa, class NPa, class EPb, class NPb>
389Result intersect(const Line2D<T, EPa, NPa>& iA, const Line2D<T, EPb, NPb>& iB,
390 T& oTa, T& oTb);
391
392template <typename T, class EPa, class NPa, class EPb, class NPb>
393Result intersect(const Line2D<T, EPa, NPa>& iA, const Line2D<T, EPb, NPb>& iB,
394 Point2D<T>& oPoint);
395
396template <typename T>
397io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const Line2D<T, Cartesian>& iLine);
398template <typename T>
399io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const Line2D<T, Parametric>& iLine);
400template <typename T>
401io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const Line2D<T, Combined>& iLine);
402
403
404
405}
406
407}
408
409#include "line_2d.inl"
410
411#ifdef LASS_GUARDIAN_OF_INCLUSION_PRIM_RAY_2D_H
412# include "line_2d_ray_2d.h"
413#endif
414
415#endif
416
417// --- END OF FILE ------------------------------------------------------------------------------
Output stream for writing a selection of geometric primitives to XML files.
const TValue signedDistance(const TPoint &iPoint, TParam iRelativeTolerance) const
Return signed distance of point to line.
Definition line_2d.inl:153
const TValue signedDistance(const TPoint &iPoint) const
Return signed distance of point to line.
Definition line_2d.inl:118
const TValue squaredDistance(const TPoint &iPoint) const
Return signed distance of point to line.
Definition line_2d.inl:130
Side classify(const TPoint &iPoint) const
Return on what side a point is located.
Definition line_2d.inl:105
const TValue squaredDistance(const TPoint &iPoint, TParam iRelativeTolerance) const
Return signed distance of point to line.
Definition line_2d.inl:165
Side classify(const TPoint &iPoint, TParam iRelativeTolerance) const
Return on what side a point is located.
Definition line_2d.inl:140
set of geometrical primitives
Definition aabb_2d.h:81
Side
Different sides of a surface.
Definition side.h:79
Result
meta information on the result you have from an operation like an intersection ...
Definition result.h:74
Library for Assembled Shared Sources.
Definition config.h:53
policy for an implementation based on the cartesian equation.
Policy to auto-normalize normals.
binder of equation policy to lass::prim::Line2D implementation