library of assembled shared sources

http://lass.cocamware.com

line_2d.h

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 
00044 
00045 /** @class lass::prim::Line2D
00046  *  @brief 2D Line
00047  *  @author Bram de Greve [BdG]
00048  *  @date 2003
00049  *
00050  *  I assume if you look to this class, you'll wonder ... "where the heck did all the code go?"
00051  *  Hah, I'll tell ya.  There is more than one possible model to represent a line.  We can
00052  *  use a cartesian equation @c N.P+S=0, or we can use a parametric equation @c P=S+t*U.
00053  *  This class lets you choose what implementation you want: a pure cartesian model, a pure
00054  *  parametric model, or a model that combines both.  This is done by moving all code to
00055  *  implemenations impl::Line2DCartesian, impl::Line2DParametric or impl::Line2DCombined.  Line2D
00056  *  will inherit its implementation of the model you've choosen.  You can select the one you
00057  *  want by specifying the template parameter @e EquationPolicy.  You can either use Cartesian
00058  *  (which is the default), Parametric or Combined.  Each of them will model the line
00059  *  differently.  They all provide the same interface, but might have different results.  They
00060  *  might have different memory footprints, different performances, and are optimized for
00061  *  different purposes.  Cartesian will select an implementation that only uses the cartesian
00062  *  equation and will be the smallest and the fastest for most purposes (that's why it is the
00063  *  default :).  But sometimes, you might more like the Parametric model, because it has
00064  *  better support for direction vectors, but it'll have to calculate the normal on the spot if
00065  *  you need it.  Combined is the workhorse for heavy duties and implements both..
00066  *
00067  *  @section template arguments
00068  *
00069  *  - @a T: the underlying data type, the proton.
00070  *  - @a @ref EquationPolicy: chooses the model: Cartesian, Parametric or Combined
00071  *  - @a @ref NormalizingPolicy: enables automatic normalizing or not: Normalized or Unnormalized
00072  *
00073  *  @section common_interface common interface
00074  *
00075  *  Anyway, let me give you some general info on this whole Line2D thing.  Though there are
00076  *  three different implentations, they all have the same interface.  We'll explore them by this
00077  *  common interface:
00078  *
00079  *  @subsection type_definitions type definitions
00080  *
00081  *  - @c TSelf: the type of @a this
00082  *  - @c TImpl: type of implemantion, can be impl::Line2DCartesian, impl::Line2DParametric or
00083  *              impl::Line2DCombined.
00084  *  - @c TNormalizingPolicy: the type you've used as NormalizingPolicy.
00085  *  - @c TPoint: type of a afine point in space.
00086  *  - @c TVector: type of a vector in space.
00087  *  - @c TValue: same as util::CallTraits<T>::TValue.
00088  *  - @c TParam: same as util::CallTraits<T>::TParam.
00089  *  - @c TReference: same as util::CallTraits<T>::TReference.
00090  *  - @c TConstReference: same as util::CallTraits<T>::TConstReference.
00091  *  - @c TNumTraits: same as num::NumTraits<T>.
00092  *
00093  *  @subsection constructors
00094  *
00095  *  @par Line2D():
00096  *  the default constructor brings the line in an invalid state.  normal and/or direction vector
00097  *  will have zero length, which indicates for this invalid state.
00098  *
00099  *  @par Line2D(const TPoint& iSupport, const TPoint& iPoint):
00100  *  construct a line through two points.  The parametric equation @a P=S+t*U is going to
00101  *  be constructed as following: iSupport will be the support point @a S, and direction vector @a U
00102  *  will be drawn from the support point to @a iPoint: @a U = @a iPointU - @a iSupport.  The cartesian
00103  *  equation @a N.P+d==0 is constructed as following: the normal @a N=perpDot(U) and @a d is determined
00104  *  by demaning that @a N.S+d==0.
00105  *
00106  *  @par Line2D(const TPoint& iSupport, const TVector& iDirection):
00107  *  constructs a line through one support point and one direction vector (the parametric equation,
00108  *  anyone? :).  For the parametric equation @a P=S+t*U, we have @a iSupport for @a S, @a iDirection
00109  *  for @a U.  Again the cartesian equation @a N.P+d==0 is given by @a N=perpDot(U) and
00110  *  @a N.S+d==0.
00111  *
00112  *  @par Line2D(const TPoint& iSupport, const TVector& iNormal):
00113  *  constructs a line through a support point and a normal vector.  For the parametric equation
00114  *  @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
00115  *  simple, we have @a iNormal for @a N and @a d can be found by @a N.S+d==0.
00116  *
00117  *  @par Line2D(const TVector& iNormal, TParam iD):
00118  *  construct a line by a normal vector and fourth value (cartesian equation? :).  For the
00119  *  parametric equation @a P=S+t*U, all have to generated: for @a S we use the point @a -iD*iNormal
00120  *  that is the closest point of the line to the origin, @a U is given by @a U=-perpDot(N).
00121  *  For the cartesian equation @a N.P+d==0, we of course use @a N = @a iNormal and @a d = @a iD.
00122  *
00123  *  @subsection accessors
00124  *
00125  *  After construction, all vectors are normalized depending on the @a NormalizingPolicy you've
00126  *  choosen as template argument.  if the normal vector @a N is scaled, then @a d is scaled as well, so
00127  *  it still represents the same line.
00128  *
00129  *  Now, we have a series of accessors that give you access to the internal data of the line,
00130  *  including support point, direction vectors, normal vector, ...  Only Line2DCombined will be
00131  *  able to pull these directly from its internals, but the others don't have all data aboard, so
00132  *  they have to generate them.  Be carefull, because it's not always what you suspect.
00133  *
00134  *  @par const TPoint support():
00135  *  returns the support point of the line.  If you used a support point for the construction of the
00136  *  line, models Line2DParametric and Line2DCombined will give you back this original one,
00137  *  exactly till the last bit.  Line2DCartesian doesn't keep track of support points, so it has to
00138  *  create one if you ask for it.  It uses @a -d*N, the point of the line that is closest to the
00139  *  origin.  Mind you that this one probably will not be the same as the original one, totally
00140  *  different even!  Of course, if you used a cartesian equation to construct the line (without any
00141  *  support point), then all three models need to generate a support point at some point: @a -d*N.
00142  *  In that case, all three models @e will return the same support point.
00143  *
00144  *  @par const TVector direction():
00145  *  get the direction vector of the line.  almost same story as for @c support().  If you've created
00146  *  the line by a direction vector ot two points (which leads to the direction vector), then models
00147  *  Line2DParametric and Line2DCombined will give you back these originals
00148  *  (for Unnormalized lines only!  but in case of Normalized lines, they still correspond with the
00149  *  original directions).  Line2DCartesian has to regenerate them, but it will result in the same
00150  *  direction vector as the others.
00151  *
00152  *  @par void getCartesian(TVector& oNormal, TReference oD):
00153  *  gets normal vector and d-value for the cartesian equation.  Now, this is the first one
00154  *  Line2DCartesian has aboard itself.  Line2DCombined also has it, but now it's up to
00155  *  Line2DParametric to generate some stuff :)  Though, it's less worse than the other way around.
00156  *  This is because the parametric equation contains more information on the support point, and
00157  *  doesn't have to 'invent' anything like Line2DCartesian has to.  Actually, in theory, all three
00158  *  models should return the same normal and d-value.  In practice however, we have to deal with
00159  *  numerical imprecisions.  so the result of Line2DParametric can differ a little in the last bits.
00160  *  not a big difference, but enough to be inequal.
00161  *
00162  *  @par const TVector normal():
00163  *  returns only the normal vector of the cartesian equation.  For Line2DParametric we have again
00164  *  the same remark as for getDirections and getReciprocals: it uses getCartesian anyway, so that
00165  *  might be faster if you both need the normal and d-value.
00166  *
00167  *  @par TValue d():
00168  *  same as normal(), but returns only the value @a d instead of the normal vector.
00169  *
00170  *  @subsection methods_cartesian cartesian methods
00171  *
00172  *  So far the accessors.  let's get to cooler stuff.  For most of this stuff, we need the cartesian
00173  *  equation.  Line2DCartesian and Line2DCombined have it on board, but Line2DParametric will
00174  *  have to generate it each call.  Keep that in mind!
00175  *
00176  *  @par Side classify(const TPoint& iPoint):
00177  *  tells at which side of the line we can find the point iPoint: the front (sFront), the back
00178  *  (sBack), or right on the surface (sSurface). the front is the side where the normal sticks or
00179  *  points to.  The back is the other one. iPoint is exactly one the surface if @a N.iPoint+d==0.
00180  *  Since we need the parametric equation, Line2DParametric might have a performance hit here.
00181  *
00182  *  @par TValue equation(const TPoint& iPoint):
00183  *  fills in the point @a iPoint in the cartesian equation and returns the resutl.  @a N.iPoint+d will
00184  *  usually not be equal to zero (it's only zero for points on the line).  This method returns what
00185  *  it is equal to. i.e. it returns @a N.iPoint+d.  For Normalized lines this is the same as the
00186  *  distance of @a iPoint to the line, but not for Unnormalized lines, keep that in mind!  If you
00187  *  need the distance, used @c signedDistances() as described below.  Again you might have a
00188  *  performance hit for the Line2DParametric model because of the need of the cartesian equation.
00189  *
00190  *  @par TValue signedDistance(const TPoint& iPoint):
00191  *  returns the distance of the point to the line, but signed. it will be positive for points in
00192  *  front of the line, and negative for the ones in the back (also see: @c classify()).  The
00193  *  real (absolute) distances is simply the absolute value of the result.  For Normalized lines
00194  *  @c signedDistances() will be equal to @c equation().  But for Unnormalized lines
00195  *  signedDistances still divides through the normal's length Again performance hit for
00196  *  Line2DParametric because of the need of the cartesian equation.
00197  *
00198  *  @par TVector reject(const TPoint& iPoint):
00199  *  returns rejection of @a iPoint by the line.  This is a bit tricky to explain.  If you have a
00200  *  support point @a S, then this rejection is the part of @a iPoint-S that is parallel to the normal
00201  *  vector (or orthogonal to the line).  This would be the same as the rejection of @a iPoint-S
00202  *  (given by @c reject(iPoint-S), see below). But more descriptive might be: it is the vector you
00203  *  have to add to the projection of this point on the line (given by @c project(iPoint), see below),
00204  *  to get back @a iPoint: @c iPoint==project(iPoint)+reject(iPoint). Again performance hit for
00205  *  Line2DParametric because of the cartesian equation.
00206  *
00207  *  @par TVector reject(const TVector& iVector):
00208  *  returns rejection of @a iVector by the line.  This is already somewhat easier.  the rejection of
00209  *  @a iVector is that part of @a iVector that is parallel to the normal vector of the line.  You can
00210  *  also say that it is the orthogonal projection of @a iVector on the normal vector.  Or the part of
00211  *  iVector that is orthogonal to the line.   Again performance hit for Line2DParametric because
00212  *  of the cartersian equation.
00213  *
00214  *  @par TPoint project(const TPoint& iPoint):
00215  *  return the orthogonal projection of @a iPoint on the line.  It is the point on the line that is
00216  *  the closest one to @a iPoint.  If you draw a line through @a iPoint parallel to the normal vector,
00217  *  this projection is the point where this line intersects the line.  It is know that in theory
00218  *  @c iPoint==project(iPoint)+reject(iPoint).  Again performance hit for Line2DParametric because
00219  *  of the cartesian equation.
00220  *
00221  *  @par TVector project(const TVector& iVector):
00222  *  return the orthogonal projection of @a iVector on the line.  It is the part of @a iVector that is
00223  *  parallel to the line, or orthogonal to the normal vector.  It is known that in theory
00224  *  @c iVector==project(iVector)+reject(iVector).  Again performance hit for Line2DParametric because
00225  *  of the cartesian equation.
00226  *
00227  *  @par TPoint reflect(const TPoint& iPoint):
00228  *  return the reflection of @a iPoint in the line.  It is the point at the same distance of the
00229  *  line, but at the exact opposite side of the line.  If you draw a line through iPoint parallel
00230  *  to the normal vector, it's the only other point on that line that is at the same (absolute)
00231  *  distance of the line. If you walk from iPoint to the intersection point of the line and the
00232  *  line, and you walk further the same distance again, you arrive at reflection of iPoint.  It is
00233  *  known that in theory @c reflect(iPoint)==project(iPoint)-reject(iPoint).  Again performance hit
00234  *  for Line2DParametric because of the cartesian equation.
00235  *
00236  *  @par TVector reflect(const TVector& iVector):
00237  *  return the reflection of @a iVector in the line. It's the vector of which the orthogonal part to
00238  *  the line is flipped.  It is know that @c reflect(iVector)==project(iVector)-reject(iVector).
00239  *  Again performance hit for Line2DParametric because of the cartesian equation.
00240  *
00241  *  @subsection methods_parametric parametric methods
00242  *
00243  *  So far functions for the cartesian boys.  Now some stuff for parametric fellows. It's about how
00244  *  we can get a point of the line if we now its parametr @a t, and how we can find @t if we know
00245  *  the point on the line.
00246  *
00247  *  @par TPoint point(TParam iT):
00248  *  returns a point of the parametric equation @c P=S+iT*U.  In case of
00249  *  Line2DCartesian, we have the same remarks as for @a direction(): not only we have
00250  *  a performance hit, we probably also have to deal with totally different direction vectors than
00251  *  the ones we have put in the constructor.
00252  *
00253  *  @par TValue t(const TPoint& iPoint):
00254  *  returns a value @a t so that @c iPoint==S+t*U.  In theory, if you put this back in @c point(),
00255  *  you should end up with the projection of @a iPoint: @c point(t(iPoint))==project(iPoint) ?
00256  *  Well, this is not totally true. In practice, numerical imprecisions will probably give you a
00257  *  slightly different result.  You'll be very close, but the last bits will differ enough to make the
00258  *  them inequal.  But with some epsilons, you'll be alright.
00259  *
00260  *  @subsection misc_methods misc. methods
00261  *
00262  *  @par void flip():
00263  *  flips the line so that the front becomes the back and the back becomes the front.  For the
00264  *  cartesian equation, this is done by negating the normal and d: @c N=-N and @c d=-d.
00265  *  Of the parametric equation, direction vector U is flipped: @c U=-U.
00266  *
00267  *  @par bool isValid():
00268  *  returns true if the interal data represents a valid line, and false if not.  A line is valid
00269  *  if none of the direction vectors nor the normal vector are zero vectors.  And above of that,
00270  *  the direction vectors may not be colinear. Of course, we only test internal data.  We will not
00271  *  generate direction vectors (in case of Line2DCartesian), just to test the if they are valid.
00272  *  We can safely do that, because we know that if the normal vector is valid, then the generated
00273  *  directions will be too.
00274  *
00275  *  @subsection free functions
00276  *
00277  *  There are some free functions listed below: distances and intersections.
00278  *  They are common for all lines and can handle mixed equation policies (two lines with different
00279  *  equation policies).
00280  */
00281 
00282 
00283 
00284 #ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_LINE_2D_H
00285 #define LASS_GUARDIAN_OF_INCLUSION_PRIM_LINE_2D_H
00286 
00287 #include "prim_common.h"
00288 #include "point_2d.h"
00289 #include "equation_policy.h"
00290 #include "normalizing_policy.h"
00291 #include "impl/line_2d_impl.h"
00292 
00293 
00294 namespace lass
00295 {
00296 namespace prim
00297 {
00298 
00299 template
00300 <
00301     typename T,
00302     class EquationPolicy = Cartesian,
00303     class NormalizingPolicy = Normalized
00304 >
00305 class Line2D: public impl::Line2DImpl<T, EquationPolicy, NormalizingPolicy>::Type
00306 {
00307 public:
00308     typedef Line2D<T, EquationPolicy, NormalizingPolicy> TSelf;
00309     typedef typename impl::Line2DImpl<T, EquationPolicy, NormalizingPolicy>::Type TImpl;
00310 
00311     typedef typename TImpl::TPoint  TPoint;
00312     typedef typename TImpl::TVector TVector;
00313     typedef typename TImpl::TParam  TParam;
00314     typedef typename TImpl::TValue  TValue;
00315     typedef typename TImpl::TReference  TReference;
00316     typedef typename TImpl::TConstReference TConstReference;
00317     typedef typename TImpl::TNumTraits TNumTraits;
00318 
00319 
00320     template <typename U>
00321     struct Rebind
00322     {
00323         typedef Line2D<U, EquationPolicy, NormalizingPolicy> Type;
00324     };
00325 
00326     Line2D();
00327     Line2D(const TPoint& iSupport, const TPoint& iPoint);
00328     Line2D(const TPoint& iSupport, const TVector& iDir);
00329     Line2D(const TVector& iNormal, const TPoint& iSupport);
00330     Line2D(const TVector& iNormal, TParam iD);
00331 
00332     const Side classify(const TPoint& iPoint) const;
00333     const TValue signedDistance(const TPoint& iPoint) const;
00334     const TValue squaredDistance(const TPoint& iPoint) const;
00335     const Side classify(const TPoint& iPoint, TParam iRelativeTolerance) const;
00336     const TValue signedDistance(const TPoint& iPoint, TParam iRelativeTolerance) const;
00337     const TValue squaredDistance(const TPoint& iPoint, TParam iRelativeTolerance) const;
00338 
00339     /*
00340     typedef NormalizingPolicy TNormalizingPolicy;
00341 
00342     typedef Point2D<T> TPoint;
00343     typedef TPoint::TVector TVector;
00344 
00345     typedef TPoint::TValue TValue;
00346     typedef TPoint::TParam TParam;
00347     typedef TPoint::TReference TReference;
00348     typedef TPoint::TConstReference TConstReference;
00349     typedef TPoint::TNumTraits TNumTraits;
00350 
00351     enum { dimension = TPoint::dimension };
00352 
00353     const TPoint support() const;
00354     const TVector direction() const;
00355 
00356     void getCartesian(TVector& oNormal, TReference oD) const;
00357     const TVector& normal() const;
00358     TConstReference d() const;
00359 
00360     Side classify(const TPoint& iPoint) const;
00361     TValue equation(const TPoint& iPoint) const;
00362     TValue signedDistance(const TPoint& iPoint) const;
00363     TValue squaredDistance(const TPoint& iPoint) const;
00364 
00365     TVector reject(const TPoint& iPoint) const;
00366     TVector reject(const TVector& iVector) const;
00367     TPoint project(const TPoint& iPoint) const;
00368     TVector project(const TVector& iVector) const;
00369     TPoint reflect(const TPoint& iPoint) const;
00370     TVector reflect(const TVector& iVector) const;
00371 
00372     TPoint point(TParam iT) const;
00373     TValue t(const TPoint& iPoint) const;
00374 
00375     void flip();
00376     bool isValid() const;
00377     */
00378 };
00379 
00380 
00381 
00382 template <typename T, class EP, class NP>
00383 T signedDistance(const Point2D<T>& iA, const Line2D<T, EP, NP>& iB);
00384 
00385 template <typename T, class EPa, class NPa, class EPb, class NPb>
00386 T signedDistance(const Line2D<T, EPa, NPa>& iA, const Line2D<T, EPb, NPb>& iB);
00387 
00388 template <typename T, class EPa, class NPa, class EPb, class NPb>
00389 Result intersect(const Line2D<T, EPa, NPa>& iA, const Line2D<T, EPb, NPb>& iB,
00390                  T& oTa, T& oTb);
00391 
00392 template <typename T, class EPa, class NPa, class EPb, class NPb>
00393 Result intersect(const Line2D<T, EPa, NPa>& iA, const Line2D<T, EPb, NPb>& iB,
00394                  Point2D<T>& oPoint);
00395 
00396 template <typename T>
00397 io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const Line2D<T, Cartesian>& iLine);
00398 template <typename T>
00399 io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const Line2D<T, Parametric>& iLine);
00400 template <typename T>
00401 io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const Line2D<T, Combined>& iLine);
00402 
00403 
00404 
00405 }
00406 
00407 }
00408 
00409 #include "line_2d.inl"
00410 
00411 #ifdef LASS_GUARDIAN_OF_INCLUSION_PRIM_RAY_2D_H
00412 #   include "line_2d_ray_2d.h"
00413 #endif
00414 
00415 #endif
00416 
00417 // --- END OF FILE ------------------------------------------------------------------------------

Generated on Mon Nov 10 14:20:09 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo