library of assembled shared sources

http://lass.cocamware.com

simple_polygon_3d.inl

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 #ifndef LASS_GUARDIAN_OF_INCLUSION_PRIM_SIMPLE_POLYGON_3D_INL
00046 #define LASS_GUARDIAN_OF_INCLUSION_PRIM_SIMPLE_POLYGON_3D_INL
00047 
00048 #include "prim_common.h"
00049 #include "simple_polygon_3d.h"
00050 
00051 namespace lass
00052 {
00053 namespace prim
00054 {
00055 
00056 template <typename T, class EP, class NP>
00057 SimplePolygon3D<T, EP, NP>::SimplePolygon3D(const TPlane& iPlane) : plane_(iPlane)
00058 {
00059 }
00060 
00061 template <typename T, class EP, class NP>
00062 SimplePolygon3D<T, EP, NP>::SimplePolygon3D(const TPoint& iA, const TPoint& iB, const TPoint& iC) :
00063     plane_(iA,iB,iC)
00064 {
00065     add(iA);
00066     add(iB);
00067     add(iC);
00068 }
00069 
00070 
00071 /** return vertex of polygon by its index, not wrapped, no bounds check.
00072  */
00073 template <typename T, class EP, class NP>
00074 const typename SimplePolygon3D<T, EP, NP>::TPoint& 
00075 SimplePolygon3D<T, EP, NP>::operator[](size_t iIndexOfVertex) const
00076 {
00077     LASS_ASSERT(iIndexOfVertex < vertices_.size());
00078     return vertices_[iIndexOfVertex];
00079 }
00080 
00081 
00082 
00083 /** return vertex of polygon by its index, not wrapped, no bounds check.
00084  */
00085 template <typename T, class EP, class NP>
00086 typename SimplePolygon3D<T, EP, NP>::TPoint& 
00087 SimplePolygon3D<T, EP, NP>::operator[](size_t iIndexOfVertex)
00088 {
00089     LASS_ASSERT(iIndexOfVertex < vertices_.size());
00090     return vertices_[iIndexOfVertex];
00091 }
00092 
00093 
00094 
00095 /** return vertex of polygon by its index, but wrap around the bounds.
00096  *  this->at(-1) will return the same vertex as this->at(this->size() - 1);
00097  */
00098 template <typename T, class EP, class NP>
00099 const typename SimplePolygon3D<T, EP, NP>::TPoint& 
00100 SimplePolygon3D<T, EP, NP>::at(int iIndexOfVertex) const
00101 {
00102     const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00103     LASS_ASSERT(isInRange(i));
00104     return vertices_[i];
00105 }
00106 
00107 
00108 
00109 /** return vertex of polygon by its index, but wrap around the bounds.
00110  *  this->at(-1) will return the same vertex as this->at(this->size() - 1);
00111  */
00112 template <typename T, class EP, class NP>
00113 typename SimplePolygon3D<T, EP, NP>::TPoint& 
00114 SimplePolygon3D<T, EP, NP>::at(int iIndexOfVertex)
00115 {
00116     const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00117     LASS_ASSERT(isInRange(i));
00118     return vertices_[i];
00119 }
00120 
00121 
00122 
00123 /** return the edge of the polygon between vertices at(iIndex) and at(iIndex + 1).
00124  */
00125 template <typename T, class EP, class NP>
00126 const typename SimplePolygon3D<T, EP, NP>::TLineSegment 
00127 SimplePolygon3D<T, EP, NP>::edge(int iIndexOfTailVertex) const
00128 {
00129     return SimplePolygon3D<T, EP, NP>::TLineSegment(at(iIndexOfTailVertex), at(iIndexOfTailVertex + 1));
00130 }
00131 
00132 
00133 
00134 /** return the vector between vertices at(iIndex) and at(iIndex + 1)\
00135  */
00136 template <typename T, class EP, class NP>
00137 const typename SimplePolygon3D<T, EP, NP>::TVector 
00138 SimplePolygon3D<T, EP, NP>::vector(int iIndexOfTailVertex) const
00139 {
00140     return at(iIndexOfTailVertex + 1) - at(iIndexOfTailVertex);
00141 }
00142 
00143 
00144 
00145 /** return support plane of polygon.
00146  */
00147 template <typename T, class EP, class NP>
00148 const typename SimplePolygon3D<T, EP, NP>::TPlane& 
00149 SimplePolygon3D<T, EP, NP>::plane() const
00150 {
00151     return plane_;
00152 }
00153 
00154 
00155 
00156 /** access support plane of polygon.
00157  */
00158 template <typename T, class EP, class NP>
00159 typename SimplePolygon3D<T, EP, NP>::TPlane& 
00160 SimplePolygon3D<T, EP, NP>::plane()
00161 {
00162     return plane_;
00163 }
00164 
00165 
00166 
00167 /** return normal of plane
00168  */
00169 template <typename T, class EP, class NP>
00170 const typename SimplePolygon3D<T, EP, NP>::TVector 
00171 SimplePolygon3D<T, EP, NP>::normal() const
00172 {
00173     return plane_.normal();
00174 }
00175 
00176 
00177 
00178 /** determines the major axis of the normal vector.
00179  *  The major axis is the one with the largest (absolute) component value.  e.g. if the normal
00180  *  vector is (-1, 4, -8), this will be the @e z axis because abs(-8) > abs(4) > abs(-1).
00181  *  In case there's more than one major axis possible, the "highest" index is choosen.  e.g.
00182  *  if the normal vector is (1, 1, 0), then @e y axis will be choosen, because @e y has a higher
00183  *  index than @e x .
00184  */
00185 template <typename T, class EP, class NP>
00186 const XYZ SimplePolygon3D<T, EP, NP>::majorAxis() const
00187 {
00188     return plane_.majorAxis();
00189 }
00190 
00191 
00192 
00193 /** add a point at the "end" of the vertex list
00194  */
00195 template <typename T, class EP, class NP>
00196 void SimplePolygon3D<T, EP, NP>::add(const TPoint& iVertex)
00197 {
00198     vertices_.push_back(iVertex);
00199 }
00200 
00201 
00202 /** insert a vertex at iIndex (so it will sit before the current at(iIndex)).
00203  */
00204 template <typename T, class EP, class NP>
00205 void SimplePolygon3D<T, EP, NP>::insert(int iIndexOfVertex, const TPoint& iVertex)
00206 {
00207     const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00208     LASS_ASSERT(isInRange(i));
00209     vertices_.insert(i, iVertex);
00210 }
00211 
00212 
00213 
00214 /** remove the vertex at(iIndex)
00215  */
00216 template <typename T, class EP, class NP>
00217 void SimplePolygon3D<T, EP, NP>::remove(int iIndexOfVertex)
00218 {
00219     const int i = num::mod(iIndexOfVertex, static_cast<unsigned>(vertices_.size()));
00220     LASS_ASSERT(isInRange(i));
00221     vertices_.remove(i);
00222 }
00223 
00224 
00225 
00226 /** return true if polygon has no vertices
00227  */
00228 template <typename T, class EP, class NP>
00229 const bool SimplePolygon3D<T, EP, NP>::isEmpty() const
00230 {
00231     return vertices_.empty();
00232 }
00233 
00234 
00235 
00236 /** return number of vertices
00237  */
00238 template <typename T, class EP, class NP>
00239 const size_t SimplePolygon3D<T, EP, NP>::size() const
00240 {
00241     return vertices_.size();
00242 }
00243 
00244 
00245 
00246 /** return signed polygon area.
00247  *
00248  *  <i>The area of a convex polygon is defined to be positive if the points are arranged in a
00249  *  counterclockwise order, and negative if they are in clockwise order.</i>,
00250  *  Eric W. Weisstein. "Polygon Area." From MathWorld--A Wolfram Web Resource. 
00251  *  http://mathworld.wolfram.com/PolygonArea.html
00252  *
00253  *  @par Algorithm:
00254  *  comp.graphics.algorithms Frequently Asked Questions: 
00255  *  Subject 2.01: "How do I find the area of a polygon?"
00256  *  http://www.faqs.org/faqs/graphics/algorithms-faq/
00257  */
00258 template <typename T, class EP, class NP>
00259 const typename SimplePolygon3D<T, EP, NP>::TValue 
00260 SimplePolygon3D<T, EP, NP>::signedArea() const
00261 {
00262     const size_t n = size();
00263     if (size < 3)
00264     {
00265         return TNumTraits::zero;
00266     }
00267 
00268     const TVector& normal = normal().normal();
00269     const TPoint& reference = vertices_[0];
00270     TValue result = TNumTraits::zero;
00271     for (size_t prevI = 1, i = 2; i < n; prevI = i++)
00272     {
00273         const TVector a = vertices_[prevI] - reference;
00274         const TVector b = vertices_[i] - reference;
00275         result += dot(cross(a, b), normal);
00276     }
00277     return result / 2;
00278 }
00279 
00280 
00281 
00282 /** return area of the polygons surface.
00283  *
00284  *  <i>The area of a surface is the amount of material needed to "cover" it completely</i>,
00285  *  Eric W. Weisstein. "Area." From MathWorld--A Wolfram Web Resource. 
00286  *  http://mathworld.wolfram.com/Area.html
00287  */
00288 template <typename T, class EP, class NP>
00289 const typename SimplePolygon3D<T, EP, NP>::TValue 
00290 SimplePolygon3D<T, EP, NP>::area() const
00291 {
00292     return num::abs(signedArea());
00293 }
00294 
00295 
00296 
00297 /** return sum of the lengths of all edges
00298  */
00299 template <typename T, class EP, class NP>
00300 const typename SimplePolygon3D<T, EP, NP>::TValue 
00301 SimplePolygon3D<T, EP, NP>::perimeter() const
00302 {
00303     TValue result = TNumTraits::zero;
00304     for (int i = 0; i < size(); ++i)
00305     {
00306         result += distance(at(i).position, at(i + 1).position);
00307     }
00308     return result;
00309 }
00310 
00311 
00312 
00313 /** return the barycenter of all vertices.
00314  *  The barycenter is the homogenous sum of all vertices.
00315  *  @warning for non-convex polygons, it's NOT guaranteed that this center is inside the polygon.
00316  */
00317 template <typename T, class EP, class NP>
00318 const typename SimplePolygon3D<T, EP, NP>::TPointH 
00319 SimplePolygon3D<T, EP, NP>::vertexCentroid() const
00320 {
00321     TPointH result;
00322     for (size_t i = 0; i < size(); ++i)
00323     {
00324         result += vertices_[i];
00325     }
00326     return result;
00327 }
00328 
00329 
00330 
00331 /** return the centroid of the filled polygon.
00332  *
00333  *  Eric W. Weisstein. "Geometric Centroid." From MathWorld--A Wolfram Web Resource. 
00334  *  http://mathworld.wolfram.com/GeometricCentroid.html
00335  *
00336  *  @par Algorithm:
00337  *  comp.graphics.algorithms Frequently Asked Questions: 
00338  *  Subject 2.02: "How can the centroid of a polygon be computed?"
00339  *  http://www.faqs.org/faqs/graphics/algorithms-faq/
00340  *
00341  *  @warning for non-convex polygons, it's NOT guaranteed that this center is inside the polygon.
00342  */
00343 template <typename T, class EP, class NP>
00344 const typename SimplePolygon3D<T, EP, NP>::TPointH 
00345 SimplePolygon3D<T, EP, NP>::surfaceCentroid() const
00346 {
00347     const size_t n = size();
00348     if (n < 3)
00349     {
00350         return vertexCentroid();
00351     }
00352 
00353     const TVector& normal = normal().normal();
00354     const TPoint& reference = vertices_[0];
00355     TPointH result;
00356     for (size_t prevI = 1, i = 2; i < n; prevI = i++)
00357     {
00358         const TVector a = vertices_[prevI] - reference;
00359         const TVector b = vertices_[i] - reference;
00360         const TValue triangleWeight = dot(cross(a, b), normal);
00361         const TPointH triangleCentroid = a + b + reference;
00362         result += triangleWeight * triangleCentroid;
00363     }
00364 }
00365 
00366 
00367 
00368 /** return true if polygon is simple, false if not.
00369  *
00370  *  <i>A polygon P is said to be simple (or Jordan) if the only points of the plane belonging to
00371  *  two polygon edges of P are the polygon vertices of P. Such a polygon has a well defined
00372  *  interior and exterior. Simple polygons are topologically equivalent to a disk.</i>,
00373  *  Eric W. Weisstein. "Simple Polygon." From MathWorld--A Wolfram Web Resource. 
00374  *  http://mathworld.wolfram.com/SimplePolygon.html 
00375  *
00376  *  In 3D, we test if the 2D mapping on the major axis is simple.
00377  *
00378  *  @warning this is a brute force test.  we simple test for all edges if they are not intersecting
00379  *           Hence, this is O(n^2).
00380  */
00381 template <typename T, class EP, class NP>
00382 const bool SimplePolygon3D<T, EP, NP>::isSimple() const
00383 {
00384     return mapping(majorAxis()).isSimple();
00385 }
00386 
00387 
00388 
00389 /** return true if polygon is convex, false if not.
00390  *  @warning assumes polygon is simple
00391  *
00392  *  <i>A planar polygon is convex if it contains all the line segments connecting any pair of its
00393  *  points. Thus, for example, a regular pentagon is convex, while an indented pentagon is not.
00394  *  A planar polygon that is not convex is said to be a concave polygon</i>,
00395  *  Eric W. Weisstein. "Convex Polygon." From MathWorld--A Wolfram Web Resource. 
00396  *  http://mathworld.wolfram.com/ConvexPolygon.html 
00397  *
00398  *  A simple polygon is convex if all the cross products of adjacent edges will be the same sign
00399  *  (we ignore zero signs, only + or - are taken in account), a concave polygon will have a mixture
00400  *  of cross product signs.
00401  *
00402  *  A polygon with less than three vertices is always convex.  A polygon with all colinear
00403  *  vertices is considered convex (not very usefull maybe, but convex).
00404  */
00405 template <typename T, class EP, class NP>
00406 const bool SimplePolygon3D<T, EP, NP>::isConvex() const
00407 {
00408     if (size() < 3)
00409     {
00410         return true;
00411     }
00412 
00413     TValue sign = TNumTraits::zero;
00414     for (int i = 0; i < size(); ++i)
00415     {
00416         const TValue s = num::sign(perpDot(vector(i - 1), vector(i))); // Ax(-B) = BxA
00417         if (sign != s && s != TNumTraits::zero)
00418         {
00419             if (sign != TNumTraits::zero)
00420             {
00421                 return false;
00422             }
00423             else
00424             {
00425                 sign = s;
00426             }
00427         }
00428     }
00429 
00430     return true;
00431 }
00432 
00433 
00434 
00435 /** return orientation of polygon
00436  *  @warning assumes polygon is simple
00437  */
00438 template <typename T, class EP, class NP>
00439 const Orientation SimplePolygon3D<T, EP, NP>::orientation() const
00440 {
00441     const TValue area = signedArea();
00442     if (area > TNumTraits::zero)
00443     {
00444         return oCounterClockWise;
00445     }
00446     else if (area < TNumTraits::zero)
00447     {
00448         return oClockWise;
00449     }
00450     else
00451     {
00452         return oInvalid;
00453     }
00454 }
00455 
00456 
00457 
00458 /** return true if inner angle of vertex is reflex (is > 180 degrees).
00459  *  @warning assumes polygon is simple
00460  */
00461 template <typename T, class EP, class NP>
00462 const bool SimplePolygon3D<T, EP, NP>::isReflex(int iIndexOfVertex) const
00463 {
00464     return dot(cross(vector(iIndexOfVertex - 1), vector(iIndexOfVertex)), normal()) < 0;
00465 }
00466 
00467 
00468 
00469 /** maps a 3D polygon as a 2D polygon by ignoring the component along an axis.
00470  *
00471  *  if @a iAxis is @e z, then it's easy.  We ignore the @e z component and we get a polygon with
00472  *  only the @e x and @e y components.
00473  *
00474  *  if @a iAxis is @e x, then we have to keep the @e z axis while there's no @e z axis in 2D.  We
00475  *  solve this by mapping the 3D @e y axis on the 2D @e x axis, and the 3D @e z axis on the
00476  *  2D @e y axis.
00477  *
00478  *  if @a iAxis is @e y, then we have a similar problem.  This time the 3D @e z axis is mapped on
00479  *  the 2D @e x axis, and the 3D @e x axis is mapped on the 2D @e y axis.
00480  *
00481  *  You can write this in short by saying the 2D @e x axis will correspond with 3D axis (@a iAxis
00482  *  + 1) and the 2D @e y axis with 3D axis (@a iAxis + 2).
00483  *
00484  *  @todo explain this better
00485  */
00486 template <typename T, class EP, class NP>
00487 const SimplePolygon2D<T> SimplePolygon3D<T, EP, NP>::mapping(XYZ iAxis) const
00488 {
00489     const XYZ x = iAxis + 1;
00490     const XYZ y = iAxis + 2;
00491     SimplePolygon2D<T> result;
00492 
00493     const int n = size();
00494     for (int i = 0; i < n; ++i)
00495     {
00496         result.add(Point2D<T>(vertices_[i][x], vertices_[i][y]));
00497     }
00498 
00499     return result;
00500 }
00501 
00502 
00503 
00504 template <typename T, class EP, class NP>
00505 const Side SimplePolygon3D<T, EP, NP>::classify(const TPoint& iP) const
00506 {
00507     return contains(iP) ? sInside : sOutside;
00508 }
00509 
00510 
00511 
00512 /** return true if a point @a iP is inside the polygon, on condition @a iP is on the plane
00513  *
00514  *  @par Algorithm:
00515  *  comp.graphics.algorithms Frequently Asked Questions: 
00516  *  Subject 2.03: "How do I find if a point lies within a polygon?"
00517  *  http://www.faqs.org/faqs/graphics/algorithms-faq/
00518  */
00519 template <typename T, class EP, class NP>
00520 const bool SimplePolygon3D<T, EP, NP>::contains(const TPoint& iP) const
00521 {
00522     const XYZ major = majorAxis();
00523     const XYZ x = major + 1;
00524     const XYZ y = major + 2;
00525 
00526     size_t i, j;
00527     bool c = false;
00528     const size_t npol = size();
00529     for (i = 0, j = npol-1; i < npol; j = i++)
00530     {
00531         const TPoint& a = vertices_[i];
00532         const TPoint& b = vertices_[j];
00533         if ((((a[y]<=iP[y]) && (iP[y]<b[y])) ||
00534             ((b[y]<=iP[y]) && (iP[y]<a[y]))) &&
00535             (iP[x] < (b[x] - a[x]) * (iP[y] - a[y]) / (b[y] - a[y]) + a[x]))
00536         c = !c;
00537     }
00538     return c;
00539 }
00540 
00541 
00542 
00543 /** flip normal and reverse sequence of vertices
00544  */
00545 template <typename T, class EP, class NP>
00546 void SimplePolygon3D<T, EP, NP>::flip()
00547 {
00548     plane_.flip();
00549     std::reverse(vertices_.begin(), vertices_.end());
00550 }
00551 
00552 
00553 
00554 // --- private -------------------------------------------------------------------------------------
00555 
00556 /** return if index of vertex is in range of the std::vector
00557  */
00558 template <typename T, class EP, class NP>
00559 const bool SimplePolygon3D<T, EP, NP>::isInRange(int iIndexOfVertex) const
00560 {
00561     return iIndexOfVertex >= 0 && iIndexOfVertex < static_cast<int>(vertices_.size());
00562 }
00563 
00564 
00565 
00566 // --- free ----------------------------------------------------------------------------------------
00567 
00568 /** Find the intersection of a line segment and a simple polygon by their parameter t on the 
00569  *  line segment.
00570  *  @relates lass::prim::LineSegment3D
00571  *  @relates lass::prim::SimplePolygon3D
00572  *
00573  *  @param iPolygon [in] the simple polygon
00574  *  @param iSegment [in] the line segment
00575  *  @param oT [out] the parameter of the intersection point > @a iMinT.
00576  *  @param iMinT [in] the minimum t that may be returned as valid intersection.
00577  *  @return @arg rNone      no intersections with @a oT > @a iMinT found
00578  *                          @a oT is not assigned.
00579  *          @arg rOne       a intersection with @a oT > @a iMinT is found
00580  *                          @a oT is assigned.
00581  */
00582 template<typename T, class EP, class NP, class PP>
00583 Result intersect(const SimplePolygon3D<T, EP, NP>& iPolygon, 
00584                  const LineSegment3D<T, PP>& iSegment, 
00585                  T& oT, const T& iMinT)
00586 {
00587     typedef Point2D<T> TPoint;
00588     typedef typename TPoint::TValue TValue;
00589 
00590     TValue t;
00591     if (intersect(iPolygon.plane(), iSegment, t, iMinT) == rOne)
00592     {
00593         if (iPolygon.contains(iSegment.point(t)))
00594         {
00595             oT = t;
00596             return rOne;
00597         }
00598     }
00599     return rNone;
00600 }
00601 
00602 
00603 
00604 /** Clip a polygon to a plane.
00605  *  @relates lass::prim::SimplePolygon3D
00606  *  @relates lass::prim::Plane3D
00607  *
00608  *  @param iPlane [in] the plane to clip to
00609  *  @param iPolygon [in] the polygon to be clipped
00610  *  @return the clipped polygon.
00611  */
00612 template <typename T, class EP1, class NP1, class EP2, class NP2>
00613 SimplePolygon3D<T, EP2, NP2> clip(const Plane3D<T, EP1, NP1>& iPlane, 
00614                                   const SimplePolygon3D<T, EP2, NP2>& iPolygon)
00615 {
00616     typedef Plane3D<T, EP1, NP1> TPlane;
00617     typedef SimplePolygon3D<T, EP2, NP2> TPolygon;
00618     typedef Point3D<T> TPoint;
00619     typedef typename TPoint::TValue TValue;
00620     typedef typename TPoint::TNumTraits TNumTraits;
00621 
00622     const size_t size = iPolygon.size();
00623     if (size < 2)
00624     {
00625         return iPolygon;
00626     }
00627 
00628     bool allOut = true;
00629     bool allIn = true;
00630     std::vector<T> e(size);
00631     for (size_t i = 0; i < size; ++i)
00632     {
00633         e[i] = iPlane.equation(iPolygon[i]);
00634         allOut &= (e[i] <= TNumTraits::zero);
00635         allIn &= (e[i] >= TNumTraits::zero);
00636     }
00637 
00638     if (allIn)
00639     {
00640         return iPolygon;
00641     }
00642 
00643     if (allOut)
00644     {
00645         return TPolygon(iPolygon.plane());
00646     }
00647 
00648     TPolygon result(iPolygon.plane());
00649     TPoint tail = iPolygon[size - 1];
00650     TValue tailE = e[size - 1];
00651     bool tailInside = tailE >= TNumTraits::zero;
00652 
00653     for (size_t i = 0; i < size; ++i)
00654     {
00655         const TPoint& head = iPolygon[i];
00656         const TValue headE = e[i];
00657         const bool headInside = headE >= TNumTraits::zero;
00658 
00659         if (tailInside)
00660         {
00661             if (headInside)
00662             {
00663                 // both in, add this vertex
00664                 result.add(head);
00665             }
00666             else
00667             {
00668                 // going out, add intersection point
00669                 const TValue t = tailE / (tailE - headE);
00670                 LASS_ASSERT(0.0 <= t && t <= 1.0);
00671                 const TPoint p = tail + t * (head - tail);
00672                 result.add(p);
00673             }
00674         }
00675         else
00676         {
00677             if (headInside)
00678             {
00679                 // coming in, add intersection point and this vertex.
00680                 const TValue t = tailE / (tailE - headE);
00681                 LASS_ASSERT(0.0 <= t && t <= 1.0);
00682                 const TPoint p = tail + t * (head - tail);
00683                 result.add(p);
00684                 result.add(head);
00685             }
00686             else
00687             {
00688                 // both out, do nothing.
00689             }
00690         }
00691 
00692         tail = head;
00693         tailE = headE;
00694         tailInside = headInside;
00695     }
00696 
00697     return result;
00698 }       
00699 
00700 /** @relates lass::prim::SimplePolygon3D
00701  */
00702 template <typename T, class EP, class NP>
00703 io::XmlOStream& operator<<(io::XmlOStream& ioOStream, const SimplePolygon3D<T, EP, NP>& iPolygon)
00704 {
00705     const size_t n = iPolygon.size();
00706     LASS_ENFORCE_STREAM(ioOStream) << "<SimplePolygon3D>\n";
00707     for (size_t i = 0; i < n; ++i)
00708     {
00709         ioOStream << "<vertex id='" << static_cast<unsigned long>(i) << "'>" << iPolygon[i] << "</vertex>\n";
00710     }
00711     ioOStream << "<plane>" << iPolygon.plane() << "</plane>\n";
00712     ioOStream << "</SimplePolygon3D>\n";
00713     return ioOStream;
00714 }
00715 
00716 /** @relates lass::prim::SimplePolygon3D
00717  */
00718 template <typename T, class EP, class NP>
00719 std::ostream& operator<<(std::ostream& ioOStream, const SimplePolygon3D<T, EP, NP>& iPolygon)
00720 {
00721     const size_t n = iPolygon.size();
00722     LASS_ENFORCE_STREAM(ioOStream) << "{";
00723     if (n > 0)
00724     {
00725         ioOStream << iPolygon[0];
00726     }   
00727     for (size_t i = 1; i < n; ++i)
00728     {
00729         ioOStream << ", " << iPolygon[i];
00730     }
00731     ioOStream << "}";
00732     return ioOStream;
00733 }
00734 
00735 
00736 
00737 }
00738 
00739 }
00740 
00741 #endif
00742 
00743 // EOF

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