WFMath 0.3.11
|
00001 // polygon.h (A 2D polygon embeded in a <dim> dimensional space) 00002 // 00003 // The WorldForge Project 00004 // Copyright (C) 2002 The WorldForge Project 00005 // 00006 // This program is free software; you can redistribute it and/or modify 00007 // it under the terms of the GNU General Public License as published by 00008 // the Free Software Foundation; either version 2 of the License, or 00009 // (at your option) any later version. 00010 // 00011 // This program is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 // 00016 // You should have received a copy of the GNU General Public License 00017 // along with this program; if not, write to the Free Software 00018 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00019 // 00020 // For information about WorldForge and its authors, please contact 00021 // the Worldforge Web Site at http://www.worldforge.org. 00022 // 00023 00024 // Author: Ron Steinke 00025 00026 #ifndef WFMATH_POLYGON_H 00027 #define WFMATH_POLYGON_H 00028 00029 #include <wfmath/axisbox.h> 00030 #include <wfmath/ball.h> 00031 #include <wfmath/vector.h> 00032 #include <wfmath/point.h> 00033 #include <wfmath/quaternion.h> 00034 #include <wfmath/rotbox.h> 00035 #include <wfmath/intersect_decls.h> 00036 00037 #include <vector> 00038 00039 namespace WFMath { 00040 00041 template<const int dim> class Polygon; 00042 00043 template<const int dim> 00044 std::ostream& operator<<(std::ostream& os, const Polygon<dim>& r); 00045 template<const int dim> 00046 std::istream& operator>>(std::istream& is, Polygon<dim>& r); 00047 00049 template<> 00050 class Polygon<2> 00051 { 00052 public: 00053 Polygon() {} 00054 Polygon(const Polygon& p) : m_points(p.m_points) {} 00056 explicit Polygon(const AtlasInType& a) {fromAtlas(a);} 00057 00058 ~Polygon() {} 00059 #ifndef WFMATH_NO_CLASS_FUNCTION_SPECIALIZATION 00060 friend std::ostream& operator<< <2>(std::ostream& os, const Polygon& p); 00061 friend std::istream& operator>> <2>(std::istream& is, Polygon& p); 00062 #endif 00063 00065 AtlasOutType toAtlas() const; 00067 void fromAtlas(const AtlasInType& a); 00068 00069 Polygon& operator=(const Polygon& p) 00070 {m_points = p.m_points; return *this;} 00071 00072 bool isEqualTo(const Polygon& p, double epsilon = WFMATH_EPSILON) const; 00073 00074 bool operator==(const Polygon& p) const {return isEqualTo(p);} 00075 bool operator!=(const Polygon& p) const {return !isEqualTo(p);} 00076 00077 bool isValid() const; 00078 00079 // Descriptive characteristics 00080 00081 int numCorners() const {return m_points.size();} 00082 Point<2> getCorner(int i) const {return m_points[i];} 00083 #ifndef WFMATH_NO_TEMPLATES_AS_TEMPLATE_PARAMETERS 00084 Point<2> getCenter() const {return Barycenter(m_points);} 00085 #endif 00086 00087 // For a Polygon<2>, addCorner() and moveCorner() always succeed. 00088 // The return values are present for the sake of a unified template 00089 // interface, and the epsilon argument is ignored 00090 00091 // Add before i'th corner, zero is beginning, numCorners() is end 00092 bool addCorner(int i, const Point<2>& p, double epsilon = WFMATH_EPSILON) 00093 {m_points.insert(m_points.begin() + i, p); return true;} 00094 00095 // Remove the i'th corner 00096 void removeCorner(int i) {m_points.erase(m_points.begin() + i);} 00097 00098 // Move the i'th corner to p 00099 bool moveCorner(int i, const Point<2>& p, double epsilon = WFMATH_EPSILON) 00100 {m_points[i] = p; return true;} 00101 00102 // Remove all points 00103 void clear() {m_points.clear();} 00104 00105 const Point<2>& operator[](int i) const {return m_points[i];} 00106 Point<2>& operator[](int i) {return m_points[i];} 00107 00108 void resize(unsigned int size) {m_points.resize(size);} 00109 00110 // Movement functions 00111 00112 Polygon& shift(const Vector<2>& v); 00113 Polygon& moveCornerTo(const Point<2>& p, int corner) 00114 {return shift(p - getCorner(corner));} 00115 #ifndef WFMATH_NO_TEMPLATES_AS_TEMPLATE_PARAMETERS 00116 Polygon& moveCenterTo(const Point<2>& p) 00117 {return shift(p - getCenter());} 00118 #endif 00119 00120 Polygon& rotateCorner(const RotMatrix<2>& m, int corner) 00121 {rotatePoint(m, getCorner(corner)); return *this;} 00122 #ifndef WFMATH_NO_TEMPLATES_AS_TEMPLATE_PARAMETERS 00123 Polygon& rotateCenter(const RotMatrix<2>& m) 00124 {rotatePoint(m, getCenter()); return *this;} 00125 #endif 00126 Polygon& rotatePoint(const RotMatrix<2>& m, const Point<2>& p); 00127 00128 // Intersection functions 00129 00130 #ifndef WFMATH_NO_TEMPLATES_AS_TEMPLATE_PARAMETERS 00131 AxisBox<2> boundingBox() const {return BoundingBox(m_points);} 00132 Ball<2> boundingSphere() const {return BoundingSphere(m_points);} 00133 Ball<2> boundingSphereSloppy() const {return BoundingSphereSloppy(m_points);} 00134 #endif 00135 00136 Polygon toParentCoords(const Point<2>& origin, 00137 const RotMatrix<2>& rotation = RotMatrix<2>().identity()) const; 00138 Polygon toParentCoords(const AxisBox<2>& coords) const; 00139 Polygon toParentCoords(const RotBox<2>& coords) const; 00140 00141 // toLocal is just like toParent, expect we reverse the order of 00142 // translation and rotation and use the opposite sense of the rotation 00143 // matrix 00144 00145 Polygon toLocalCoords(const Point<2>& origin, 00146 const RotMatrix<2>& rotation = RotMatrix<2>().identity()) const; 00147 Polygon toLocalCoords(const AxisBox<2>& coords) const; 00148 Polygon toLocalCoords(const RotBox<2>& coords) const; 00149 00150 friend bool Intersect<2>(const Polygon& r, const Point<2>& p, bool proper); 00151 friend bool Contains<2>(const Point<2>& p, const Polygon& r, bool proper); 00152 00153 friend bool Intersect<2>(const Polygon& p, const AxisBox<2>& b, bool proper); 00154 friend bool Contains<2>(const Polygon& p, const AxisBox<2>& b, bool proper); 00155 friend bool Contains<2>(const AxisBox<2>& b, const Polygon& p, bool proper); 00156 00157 friend bool Intersect<2>(const Polygon& p, const Ball<2>& b, bool proper); 00158 friend bool Contains<2>(const Polygon& p, const Ball<2>& b, bool proper); 00159 friend bool Contains<2>(const Ball<2>& b, const Polygon& p, bool proper); 00160 00161 friend bool Intersect<2>(const Polygon& r, const Segment<2>& s, bool proper); 00162 friend bool Contains<2>(const Polygon& p, const Segment<2>& s, bool proper); 00163 friend bool Contains<2>(const Segment<2>& s, const Polygon& p, bool proper); 00164 00165 friend bool Intersect<2>(const Polygon& p, const RotBox<2>& r, bool proper); 00166 friend bool Contains<2>(const Polygon& p, const RotBox<2>& r, bool proper); 00167 friend bool Contains<2>(const RotBox<2>& r, const Polygon& p, bool proper); 00168 00169 friend bool Intersect<2>(const Polygon& p1, const Polygon& p2, bool proper); 00170 friend bool Contains<2>(const Polygon& outer, const Polygon& inner, bool proper); 00171 00172 private: 00173 std::vector<Point<2> > m_points; 00174 typedef std::vector<Point<2> >::iterator theIter; 00175 typedef std::vector<Point<2> >::const_iterator theConstIter; 00176 00177 }; 00178 00179 // Helper classes, to keep track of the orientation of 00180 // a 2D polygon in dim dimensions 00181 00182 typedef enum { 00183 _WFMATH_POLY2REORIENT_NONE, 00184 _WFMATH_POLY2REORIENT_CLEAR_AXIS2, 00185 _WFMATH_POLY2REORIENT_CLEAR_BOTH_AXES, 00186 _WFMATH_POLY2REORIENT_MOVE_AXIS2_TO_AXIS1, 00187 _WFMATH_POLY2REORIENT_SCALE1_CLEAR2 00188 } _Poly2ReorientType; 00189 00190 // Reorient a 2D polygon to match a change in the basis 00191 // used by _Poly2Orient 00192 class _Poly2Reorient 00193 { 00194 public: 00195 _Poly2Reorient(_Poly2ReorientType type, CoordType scale = 0.0) 00196 : m_type(type), m_scale(scale) {} 00197 ~_Poly2Reorient() {} 00198 00199 void reorient(Polygon<2>& poly, int skip = -1) const; 00200 00201 private: 00202 _Poly2ReorientType m_type; 00203 CoordType m_scale; 00204 }; 00205 00206 template<const int dim> class _Poly2Orient; 00207 00208 struct _Poly2OrientIntersectData { 00209 int dim; 00210 Point<2> p1, p2; 00211 Vector<2> v1, v2, off; 00212 bool o1_is_line, o2_is_line; 00213 }; 00214 00215 // Finds the intersection of the two planes, returns the 00216 // dimension of the intersection space, the rest of the arguments 00217 // are various information returned depending on the dimension of 00218 // the intersection 00219 template<const int dim> 00220 int _Intersect(const _Poly2Orient<dim> &, const _Poly2Orient<dim> &, 00221 _Poly2OrientIntersectData &); 00222 00223 // Keep track of the orientation of a 2D polygon in dim dimensions 00224 template<const int dim> 00225 class _Poly2Orient 00226 { 00227 public: 00228 _Poly2Orient() {} 00229 _Poly2Orient(const _Poly2Orient& p) {operator=(p);} 00230 ~_Poly2Orient() {} 00231 00232 _Poly2Orient& operator=(const _Poly2Orient& p); 00233 00234 // Convert a point in the 2D polygon to a point in dim dimensional space 00235 Point<dim> convert(const Point<2>& p) const; 00236 00237 // Try to convert a point from dim dimensions into 2D, expanding the 00238 // basis if necessary. Returns true on success. On failure, the 00239 // basis is unchanged. 00240 bool expand(const Point<dim>& pd, Point<2>& p2, double epsilon = WFMATH_EPSILON); 00241 00242 // Reduce the basis to the minimum necessary to span the points in 00243 // poly (with the exception of skip). Returns _Poly2Reorient, which needs 00244 // to be used to reorient the points to match the new basis. 00245 _Poly2Reorient reduce(const Polygon<2>& poly, int skip = -1); 00246 00247 void shift(const Vector<dim>& v) {if(m_origin.isValid()) m_origin += v;} 00248 void rotate(const RotMatrix<dim>& m, const Point<dim>& p); 00249 // Rotates about the point which corresponds to "p" in the oriented plane 00250 void rotate2(const RotMatrix<dim>& m, const Point<2>& p); 00251 00252 //3D only 00253 void rotate(const Quaternion& q, const Point<3>& p); 00254 // Rotates about the point which corresponds to "p" in the oriented plane 00255 void rotate2(const Quaternion& q, const Point<2>& p); 00256 00257 _Poly2Orient toParentCoords(const Point<dim>& origin, 00258 const RotMatrix<dim>& rotation = RotMatrix<dim>().identity()) const 00259 {_Poly2Orient p(*this); p.m_origin = m_origin.toParentCoords(origin, rotation); 00260 p.m_axes[0].rotate(rotation); p.m_axes[1].rotate(rotation); return p;} 00261 _Poly2Orient toParentCoords(const AxisBox<dim>& coords) const 00262 {_Poly2Orient p(*this); p.m_origin = m_origin.toParentCoords(coords); return p;} 00263 _Poly2Orient toParentCoords(const RotBox<dim>& coords) const 00264 {_Poly2Orient p(*this); p.m_origin = m_origin.toParentCoords(coords); 00265 p.m_axes[0].rotate(coords.orientation()); 00266 p.m_axes[1].rotate(coords.orientation()); return p;} 00267 00268 // toLocal is just like toParent, expect we reverse the order of 00269 // translation and rotation and use the opposite sense of the rotation 00270 // matrix 00271 00272 _Poly2Orient toLocalCoords(const Point<dim>& origin, 00273 const RotMatrix<dim>& rotation = RotMatrix<dim>().identity()) const 00274 {_Poly2Orient p(*this); p.m_origin = m_origin.toLocalCoords(origin, rotation); 00275 p.m_axes[0] = rotation * p.m_axes[0]; 00276 p.m_axes[1] = rotation * p.m_axes[1]; return p;} 00277 _Poly2Orient toLocalCoords(const AxisBox<dim>& coords) const 00278 {_Poly2Orient p(*this); p.m_origin = m_origin.toLocalCoords(coords); return p;} 00279 _Poly2Orient toLocalCoords(const RotBox<dim>& coords) const 00280 {_Poly2Orient p(*this); p.m_origin = m_origin.toLocalCoords(coords); 00281 p.m_axes[0] = coords.orientation() * p.m_axes[0]; 00282 p.m_axes[1] = coords.orientation() * p.m_axes[1]; return p;} 00283 00284 // 3D only 00285 _Poly2Orient<3> toParentCoords(const Point<3>& origin, const Quaternion& rotation) const 00286 {_Poly2Orient p(*this); p.m_origin = m_origin.toParentCoords(origin, rotation); 00287 p.m_axes[0].rotate(rotation); p.m_axes[0].rotate(rotation); return p;} 00288 _Poly2Orient<3> toLocalCoords(const Point<3>& origin, const Quaternion& rotation) const 00289 {_Poly2Orient p(*this); p.m_origin = m_origin.toLocalCoords(origin, rotation); 00290 p.m_axes[0].rotate(rotation.inverse()); 00291 p.m_axes[0].rotate(rotation.inverse()); return p;} 00292 00293 // Gives the offset from pd to the space spanned by 00294 // the basis, and puts the nearest point in p2. 00295 Vector<dim> offset(const Point<dim>& pd, Point<2>& p2) const; 00296 00297 // Like offset, but returns true if the point is in the plane 00298 bool checkContained(const Point<dim>& pd, Point<2> & p2) const; 00299 00300 // Check if the AxisBox intersects the spanned space, and if so 00301 // return a point in the intersection. 00302 bool checkIntersect(const AxisBox<dim>& b, Point<2>& p2, bool proper) const; 00303 00304 friend int _Intersect<dim>(const _Poly2Orient<dim> &, const _Poly2Orient<dim> &, 00305 _Poly2OrientIntersectData &); 00306 00307 private: 00308 // special case of the above when both axes are valid 00309 bool checkIntersectPlane(const AxisBox<dim>& b, Point<2>& p2, bool proper) const; 00310 00311 Point<dim> m_origin; 00312 Vector<dim> m_axes[2]; // Normalized to unit length 00313 }; 00314 00316 template<const int dim = 3> 00317 class Polygon 00318 { 00319 public: 00320 Polygon() {} 00321 Polygon(const Polygon& p) : m_orient(p.m_orient), m_poly(p.m_poly) {} 00322 00323 ~Polygon() {} 00324 00325 friend std::ostream& operator<< <dim>(std::ostream& os, const Polygon& p); 00326 friend std::istream& operator>> <dim>(std::istream& is, Polygon& p); 00327 00328 Polygon& operator=(const Polygon& p) 00329 {m_orient = p.m_orient; m_poly = p.m_poly; return *this;} 00330 00331 bool isEqualTo(const Polygon& p2, double epsilon = WFMATH_EPSILON) const; 00332 00333 bool operator==(const Polygon& p) const {return isEqualTo(p);} 00334 bool operator!=(const Polygon& p) const {return !isEqualTo(p);} 00335 00336 bool isValid() const {return m_poly.isValid();} 00337 00338 // Descriptive characteristics 00339 00340 int numCorners() const {return m_poly.numCorners();} 00341 Point<dim> getCorner(int i) const {return m_orient.convert(m_poly[i]);} 00342 Point<dim> getCenter() const {return m_orient.convert(m_poly.getCenter());} 00343 00344 // The failure of the following functions does not invalidate the 00345 // polygon, but merely leaves it unchaged. 00346 00347 // Add before i'th corner, zero is beginning, numCorners() is end 00348 // Only succeeds if p lies in a plane with all current points 00349 bool addCorner(int i, const Point<dim>& p, double epsilon = WFMATH_EPSILON); 00350 00351 // Remove the i'th corner 00352 void removeCorner(int i); 00353 00354 // Move the i'th corner to p, only succeeds if new location 00355 // lies in the same plane as all the other points. Note that, 00356 // under certain circumstances, this plane may not contain the 00357 // original location of the point. 00358 bool moveCorner(int i, const Point<dim>& p, double epsilon = WFMATH_EPSILON); 00359 00360 // Remove all points 00361 void clear() {m_poly.clear(); m_orient = _Poly2Orient<dim>();} 00362 00363 // Movement functions 00364 00365 Polygon& shift(const Vector<dim>& v) 00366 {m_orient.shift(v); return *this;} 00367 Polygon& moveCornerTo(const Point<dim>& p, int corner) 00368 {return shift(p - getCorner(corner));} 00369 Polygon& moveCenterTo(const Point<dim>& p) 00370 {return shift(p - getCenter());} 00371 00372 Polygon& rotateCorner(const RotMatrix<dim>& m, int corner) 00373 {m_orient.rotate2(m, m_poly[corner]); return *this;} 00374 Polygon& rotateCenter(const RotMatrix<dim>& m) 00375 {if(m_poly.numCorners() > 0) 00376 m_orient.rotate2(m, m_poly.getCenter()); 00377 return *this;} 00378 Polygon& rotatePoint(const RotMatrix<dim>& m, const Point<dim>& p) 00379 {m_orient.rotate(m, p); return *this;} 00380 00381 // 3D rotation functions 00382 Polygon<3>& rotateCorner(const Quaternion& q, int corner) 00383 {m_orient.rotate2(q, m_poly[corner]); return *this;} 00384 Polygon<3>& rotateCenter(const Quaternion& q) 00385 {if(m_poly.numCorners() > 0) 00386 m_orient.rotate2(q, m_poly.getCenter()); 00387 return *this;} 00388 Polygon<3>& rotatePoint(const Quaternion& q, const Point<3>& p) 00389 {m_orient.rotate(q, p); return *this;} 00390 00391 // Intersection functions 00392 00393 AxisBox<dim> boundingBox() const; 00394 Ball<dim> boundingSphere() const; 00395 Ball<dim> boundingSphereSloppy() const; 00396 00397 Polygon toParentCoords(const Point<dim>& origin, 00398 const RotMatrix<dim>& rotation = RotMatrix<dim>().identity()) const 00399 {Polygon p(*this); p.m_orient = m_orient.toParentCoords(origin, rotation); return p;} 00400 Polygon toParentCoords(const AxisBox<dim>& coords) const 00401 {Polygon p(*this); p.m_orient = m_orient.toParentCoords(coords); return p;} 00402 Polygon toParentCoords(const RotBox<dim>& coords) const 00403 {Polygon p(*this); p.m_orient = m_orient.toParentCoords(coords); return p;} 00404 00405 // toLocal is just like toParent, expect we reverse the order of 00406 // translation and rotation and use the opposite sense of the rotation 00407 // matrix 00408 00409 Polygon toLocalCoords(const Point<dim>& origin, 00410 const RotMatrix<dim>& rotation = RotMatrix<dim>().identity()) const 00411 {Polygon p(*this); p.m_orient = m_orient.toLocalCoords(origin, rotation); return p;} 00412 Polygon toLocalCoords(const AxisBox<dim>& coords) const 00413 {Polygon p(*this); p.m_orient = m_orient.toLocalCoords(coords); return p;} 00414 Polygon toLocalCoords(const RotBox<dim>& coords) const 00415 {Polygon p(*this); p.m_orient = m_orient.toLocalCoords(coords); return p;} 00416 00417 // 3D only 00418 Polygon<3> toParentCoords(const Point<3>& origin, const Quaternion& rotation) const 00419 {Polygon<3> p(*this); p.m_orient = m_orient.toParentCoords(origin, rotation); return p;} 00420 Polygon<3> toLocalCoords(const Point<3>& origin, const Quaternion& rotation) const 00421 {Polygon<3> p(*this); p.m_orient = m_orient.toLocalCoords(origin, rotation); return p;} 00422 00423 friend bool Intersect<dim>(const Polygon& r, const Point<dim>& p, bool proper); 00424 friend bool Contains<dim>(const Point<dim>& p, const Polygon& r, bool proper); 00425 00426 friend bool Intersect<dim>(const Polygon& p, const AxisBox<dim>& b, bool proper); 00427 friend bool Contains<dim>(const Polygon& p, const AxisBox<dim>& b, bool proper); 00428 friend bool Contains<dim>(const AxisBox<dim>& b, const Polygon& p, bool proper); 00429 00430 friend bool Intersect<dim>(const Polygon& p, const Ball<dim>& b, bool proper); 00431 friend bool Contains<dim>(const Polygon& p, const Ball<dim>& b, bool proper); 00432 friend bool Contains<dim>(const Ball<dim>& b, const Polygon& p, bool proper); 00433 00434 friend bool Intersect<dim>(const Polygon& r, const Segment<dim>& s, bool proper); 00435 friend bool Contains<dim>(const Polygon& p, const Segment<dim>& s, bool proper); 00436 friend bool Contains<dim>(const Segment<dim>& s, const Polygon& p, bool proper); 00437 00438 friend bool Intersect<dim>(const Polygon& p, const RotBox<dim>& r, bool proper); 00439 friend bool Contains<dim>(const Polygon& p, const RotBox<dim>& r, bool proper); 00440 friend bool Contains<dim>(const RotBox<dim>& r, const Polygon& p, bool proper); 00441 00442 friend bool Intersect<dim>(const Polygon& p1, const Polygon& p2, bool proper); 00443 friend bool Contains<dim>(const Polygon& outer, const Polygon& inner, bool proper); 00444 00445 private: 00446 00447 _Poly2Orient<dim> m_orient; 00448 Polygon<2> m_poly; 00449 }; 00450 00451 } // namespace WFMath 00452 00453 #endif // WFMATH_POLYGON_H