Vault
4.1
|
00001 /* 00002 Copyright c1997-2014 Trygve Isaacson. All rights reserved. 00003 This file is part of the Code Vault version 4.1 00004 http://www.bombaydigital.com/ 00005 License: MIT. See LICENSE.md in the Vault top level directory. 00006 */ 00007 00008 #ifndef vgeometry_h 00009 #define vgeometry_h 00010 00013 #include "vtypes.h" 00014 00015 #include "vexception.h" 00016 #include "vbinaryiostream.h" 00017 00018 #ifdef VAULT_QT_SUPPORT 00019 #include <QSize> 00020 #include <QSizeF> 00021 #include <QPoint> 00022 #include <QPointF> 00023 #include <QLine> 00024 #include <QLineF> 00025 #include <QRect> 00026 #include <QRectF> 00027 #include <QPolygon> 00028 #include <QPolygonF> 00029 #endif 00030 00031 namespace VGeometry { 00032 /* 00033 When using VDouble types, tests for equality and inequality are of dubious use, because 00034 fine precision can be lost even in the simplest calculations, rendering unexpected results. 00035 (For example, 5.9 + 2.3 may not "==" 8.2 .) 00036 The equal() and notEqual() functions let you test for approximate equality within 0.000001. 00037 In order for the templates to work with both VDouble and int, we define int versions, 00038 too, and those do an exact test. 00039 */ 00040 extern bool equal(VDouble a, VDouble b); 00041 extern bool notEqual(VDouble a, VDouble b); 00042 extern bool equal(int a, int b); 00043 extern bool notEqual(int a, int b); 00044 extern void writePairToStream(VBinaryIOStream& stream, VDouble item1, VDouble item2); 00045 extern void readPairFromStream(VBinaryIOStream& stream, VDouble& item1, VDouble& item2); 00046 extern void writePairToStream(VBinaryIOStream& stream, int item1, int item2); 00047 extern void readPairFromStream(VBinaryIOStream& stream, int& item1, int& item2); 00048 extern void writeTripletToStream(VBinaryIOStream& stream, VDouble item1, VDouble item2, VDouble item3); 00049 extern void readTripletFromStream(VBinaryIOStream& stream, VDouble& item1, VDouble& item2, VDouble& item3); 00050 extern void writeTripletToStream(VBinaryIOStream& stream, int item1, int item2, int item3); 00051 extern void readTripletFromStream(VBinaryIOStream& stream, int& item1, int& item2, int& item3); 00052 extern VDouble getDistance(VDouble dx, VDouble dy); 00053 extern VDouble getDistance(int dx, int dy); 00054 } 00055 00056 /* 00057 These types are define as templates, simply in order to allow each to be used with 00058 both "int" and "VDouble" coordinates, without requiring complete duplicated implementations. 00059 Because they are templates, all functions must be coded inline here; no separating 00060 the declaration here from an implementation in the .cpp file. Wherever there is a short 00061 function I just put it on the same line as the function name; otherwise I break it out 00062 into a multi-line code block kind of like a normal implementation. 00063 */ 00064 00065 template <typename T> class VSizeT; 00066 template <typename T> bool operator== (const VSizeT<T>& s1, const VSizeT<T>& s2); 00067 template <typename T> bool operator!= (const VSizeT<T>& s1, const VSizeT<T>& s2); 00068 template <typename T> VSizeT<T> operator+ (const VSizeT<T>& s1, const VSizeT<T>& s2); 00069 template <typename T> VSizeT<T> operator- (const VSizeT<T>& s1, const VSizeT<T>& s2); 00070 template <typename T> VSizeT<T> operator*(const VSizeT<T>& x, T scale); 00071 template <typename T> VSizeT<T> operator*(T scale, const VSizeT<T>& x); 00072 template <typename T> VSizeT<T> operator/ (const VSizeT<T>& x, T divisor); 00073 00077 template <typename T> 00078 class VSizeT { 00079 public: 00080 00081 VSizeT() : mWidth(0), mHeight(0) {} 00082 VSizeT(T width, T height) : mWidth(width), mHeight(height) {} 00083 VSizeT(VBinaryIOStream& stream) : mWidth(0), mHeight(0) { VGeometry::readPairFromStream(stream, mWidth, mHeight); } 00084 ~VSizeT() {} 00085 00086 #ifdef VAULT_QT_SUPPORT 00087 VSizeT(const QSize& s) : mWidth(s.width()), mHeight(s.height()) {} 00088 VSizeT(const QSizeF& s) : mWidth(static_cast<T>(s.width())), mHeight(static_cast<T>(s.height())) {} 00089 #endif 00090 00091 void readFromStream(VBinaryIOStream& stream) { VGeometry::readPairFromStream(stream, mWidth, mHeight); } 00092 void writeToStream(VBinaryIOStream& stream) const { VGeometry::writePairToStream(stream, mWidth, mHeight); } 00093 00094 T getWidth() const { return mWidth; } 00095 T getHeight() const { return mHeight; } 00096 void setWidth(T width) { mWidth = width; } 00097 void setHeight(T height) { mHeight = height; } 00098 T& rWidth() { return mWidth; } 00099 T& rHeight() { return mHeight; } 00100 00101 VSizeT<T>& operator+=(const VSizeT<T>& x) { mWidth += x.mWidth; mHeight += x.mHeight; return *this; } 00102 VSizeT<T>& operator-=(const VSizeT<T>& x) { mWidth -= x.mWidth; mHeight -= x.mHeight; return *this; } 00103 VSizeT<T>& operator*=(T scale) { mWidth *= scale; mHeight *= scale; return *this; } 00104 VSizeT<T>& operator/=(T divisor) { if (divisor == 0) throw VRangeException("VSizeT divide by zero."); mWidth /= divisor; mHeight /= divisor; return *this; } 00105 00106 // These use "approximate" equality by testing for a difference >= 0.000001. 00107 static bool equal(const VSizeT<T>& s1, const VSizeT<T>& s2) { 00108 return VGeometry::equal(s1.mWidth, s2.mWidth) && VGeometry::equal(s1.mHeight, s2.mHeight); 00109 } 00110 00111 static bool notEqual(const VSizeT<T>& s1, const VSizeT<T>& s2) { 00112 return VGeometry::notEqual(s1.mWidth, s2.mWidth) || VGeometry::notEqual(s1.mHeight, s2.mHeight); 00113 } 00114 00115 friend bool operator== <>(const VSizeT<T>& s1, const VSizeT<T>& s2); // exact equality 00116 friend bool operator!= <>(const VSizeT<T>& s1, const VSizeT<T>& s2); // exact inequality 00117 friend VSizeT<T> operator+ <>(const VSizeT<T>& s1, const VSizeT<T>& s2); // addition 00118 friend VSizeT<T> operator- <>(const VSizeT<T>& s1, const VSizeT<T>& s2); // subtraction 00119 friend VSizeT<T> operator* <>(const VSizeT<T>& x, T scale); // multiplication p*n 00120 friend VSizeT<T> operator* <>(T scale, const VSizeT<T>& x); // multiplication n*p 00121 friend VSizeT<T> operator/ <>(const VSizeT<T>& x, T divisor); // division 00122 00123 #ifdef VAULT_QT_SUPPORT 00124 void setQSize(const QSize& s) { mWidth = s.width(); mHeight = s.height(); } 00125 QSize getQSize() const { return QSize(static_cast<int>(mWidth), static_cast<int>(mHeight)); } 00126 void setQSizeF(const QSizeF& s) { mWidth = static_cast<T>(s.width()); mHeight = static_cast<T>(s.height()); } 00127 QSizeF getQSizeF() const { return QSizeF(mWidth, mHeight); } 00128 #endif 00129 00130 private: 00131 00132 T mWidth; 00133 T mHeight; 00134 }; 00135 00136 template<typename T> bool operator==(const VSizeT<T>& s1, const VSizeT<T>& s2) { return s1.mWidth == s2.mWidth && s1.mHeight == s2.mHeight; } 00137 template<typename T> bool operator!=(const VSizeT<T>& s1, const VSizeT<T>& s2) { return s1.mWidth != s2.mWidth || s1.mHeight != s2.mHeight; } 00138 template<typename T> VSizeT<T> operator+(const VSizeT<T>& s1, const VSizeT<T>& s2) { return VSizeT<T>(s1.mWidth + s2.mWidth, s1.mHeight + s2.mHeight); } 00139 template<typename T> VSizeT<T> operator-(const VSizeT<T>& s1, const VSizeT<T>& s2) { return VSizeT<T>(s1.mWidth - s2.mWidth, s1.mHeight - s2.mHeight); } 00140 template<typename T> VSizeT<T> operator*(const VSizeT<T>& x, T scale) { return VSizeT<T>(x.mWidth * scale, x.mHeight * scale); } 00141 template<typename T> VSizeT<T> operator*(T scale, const VSizeT<T>& x) { return VSizeT<T>(x.mWidth * scale, x.mHeight * scale); } 00142 template<typename T> VSizeT<T> operator/(const VSizeT<T>& x, T divisor) { if (divisor == 0) throw VRangeException("VSizeT divide by zero."); return VSizeT<T>(x.mWidth / divisor, x.mHeight / divisor); } 00143 00144 typedef VSizeT<VDouble> VSize; 00145 typedef VSizeT<int> VISize; 00146 00147 template <typename T> class VPointT; 00148 template <typename T> bool operator== (const VPointT<T>& p1, const VPointT<T>& p2); 00149 template <typename T> bool operator!= (const VPointT<T>& p1, const VPointT<T>& p2); 00150 template <typename T> VPointT<T> operator+ (const VPointT<T>& p1, const VPointT<T>& p2); 00151 template <typename T> VPointT<T> operator+ (const VPointT<T>& p, const VSizeT<T>& s); 00152 template <typename T> VPointT<T> operator- (const VPointT<T>& p1, const VPointT<T>& p2); 00153 template <typename T> VPointT<T> operator- (const VPointT<T>& p, const VSizeT<T>& s); 00154 template <typename T> VPointT<T> operator- (const VPointT<T>& p); 00155 template <typename T> VPointT<T> operator*(const VPointT<T>& p, T scale); 00156 template <typename T> VPointT<T> operator*(T scale, const VPointT<T>& p); 00157 template <typename T> VPointT<T> operator/ (const VPointT<T>& p, T divisor); 00158 00162 template <typename T> 00163 class VPointT { 00164 public: 00165 00167 static VDouble getDistance(const VPointT<T>& p1, const VPointT<T>& p2) { return VGeometry::getDistance(p2.getX() - p1.getX(), p2.getY() - p1.getY()); } 00168 00169 VPointT() : mX(0), mY(0) {} 00170 VPointT(T x, T y) : mX(x), mY(y) {} 00171 VPointT(VBinaryIOStream& stream) : mX(0), mY(0) { VGeometry::readPairFromStream(stream, mX, mY); } 00172 ~VPointT() {} 00173 00174 #ifdef VAULT_QT_SUPPORT 00175 VPointT(const QPoint& p) : mX(p.x()), mY(p.y()) {} 00176 VPointT(const QPointF& p) : mX(static_cast<T>(p.x())), mY(static_cast<T>(p.y())) {} 00177 #endif 00178 00179 void readFromStream(VBinaryIOStream& stream) { VGeometry::readPairFromStream(stream, mX, mY); } 00180 void writeToStream(VBinaryIOStream& stream) const { VGeometry::writePairToStream(stream, mX, mY); } 00181 00182 T getX() const { return mX; } 00183 T getY() const { return mY; } 00184 void setX(T x) { mX = x; } 00185 void setY(T y) { mY = y; } 00186 T& rX() { return mX; } 00187 T& rY() { return mY; } 00188 00189 VPointT<T>& operator+=(const VPointT<T>& p) { mX += p.mX; mY += p.mY; return *this; } 00190 VPointT<T>& operator-=(const VPointT<T>& p) { mX -= p.mX; mY -= p.mY; return *this; } 00191 VPointT<T>& operator*=(T scale) { mX *= scale; mY *= scale; return *this; } 00192 VPointT<T>& operator/=(T divisor) { if (divisor == 0) throw VRangeException("VPointT divide by zero."); mX /= divisor; mY /= divisor; return *this; } 00193 00194 // These use "approximate" equality by testing for a difference >= 0.000001. 00195 static bool equal(const VPointT<T>& p1, const VPointT<T>& p2) { 00196 return VGeometry::equal(p1.mX, p2.mX) && VGeometry::equal(p1.mY, p2.mY); 00197 } 00198 00199 static bool notEqual(const VPointT<T>& p1, const VPointT<T>& p2) { 00200 return VGeometry::notEqual(p1.mX, p2.mX) || VGeometry::notEqual(p1.mY, p2.mY); 00201 } 00202 00203 friend bool operator== <>(const VPointT<T>& p1, const VPointT<T>& p2); // exact equality 00204 friend bool operator!= <>(const VPointT<T>& p1, const VPointT<T>& p2); // exact inequality 00205 friend VPointT<T> operator+ <>(const VPointT<T>& p1, const VPointT<T>& p2); // addition 00206 friend VPointT<T> operator+ <>(const VPointT<T>& p, const VSizeT<T>& s); // addition 00207 friend VPointT<T> operator- <>(const VPointT<T>& p1, const VPointT<T>& p2); // subtraction 00208 friend VPointT<T> operator- <>(const VPointT<T>& p, const VSizeT<T>& s); // subtraction 00209 friend VPointT<T> operator- <>(const VPointT<T>& p); // negation 00210 friend VPointT<T> operator* <>(const VPointT<T>& p, T scale); // multiplication p*n 00211 friend VPointT<T> operator* <>(T scale, const VPointT<T>& p); // multiplication n*p 00212 friend VPointT<T> operator/ <>(const VPointT<T>& p, T divisor); // division 00213 00214 #ifdef VAULT_QT_SUPPORT 00215 void setQPoint(const QPoint& p) { mX = p.x(); mY = p.y(); } 00216 QPoint getQPoint() const { return QPoint(static_cast<int>(mX), static_cast<int>(mY)); } 00217 void setQPointF(const QPointF& p) { mX = static_cast<T>(p.x()); mY = static_cast<T>(p.y()); } 00218 QPointF getQPointF() const { return QPointF(mX, mY); } 00219 #endif 00220 00221 private: 00222 00223 T mX; 00224 T mY; 00225 }; 00226 00227 template<typename T> bool operator==(const VPointT<T>& p1, const VPointT<T>& p2) { return p1.mX == p2.mX && p1.mY == p2.mY; } 00228 template<typename T> bool operator!=(const VPointT<T>& p1, const VPointT<T>& p2) { return p1.mX != p2.mX || p1.mY != p2.mY; } 00229 template<typename T> VPointT<T> operator+(const VPointT<T>& p1, const VPointT<T>& p2) { return VPointT<T>(p1.mX + p2.mX, p1.mY + p2.mY); } 00230 template<typename T> VPointT<T> operator+(const VPointT<T>& p, const VSizeT<T>& s) { return VPointT<T>(p.mX + s.getWidth(), p.mY + s.getHeight()); } 00231 template<typename T> VPointT<T> operator-(const VPointT<T>& p1, const VPointT<T>& p2) { return VPointT<T>(p1.mX - p2.mX, p1.mY - p2.mY); } 00232 template<typename T> VPointT<T> operator-(const VPointT<T>& p, const VSizeT<T>& s) { return VPointT<T>(p.mX - s.getWidth(), p.mY - s.getHeight()); } 00233 template<typename T> VPointT<T> operator-(const VPointT<T>& p) { return VPointT<T>(-p.mX, -p.mY); } 00234 template<typename T> VPointT<T> operator*(const VPointT<T>& p, T scale) { return VPointT<T>(p.mX * scale, p.mY * scale); } 00235 template<typename T> VPointT<T> operator*(T scale, const VPointT<T>& p) { return VPointT<T>(p.mX * scale, p.mY * scale); } 00236 template<typename T> VPointT<T> operator/(const VPointT<T>& p, T divisor) { if (divisor == 0) throw VRangeException("VPointT divide by zero."); return VPointT<T>(p.mX / divisor, p.mY / divisor); } 00237 00238 typedef VPointT<VDouble> VPoint; 00239 typedef VPointT<int> VIPoint; 00240 00241 typedef std::vector<VPoint> VPointVector; 00242 typedef std::vector<VIPoint> VIPointVector; 00243 00244 template <typename T> class VPoint3DT; 00245 template <typename T> bool operator== (const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); 00246 template <typename T> bool operator!= (const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); 00247 template <typename T> VPoint3DT<T> operator+ (const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); 00248 template <typename T> VPoint3DT<T> operator- (const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); 00249 template <typename T> VPoint3DT<T> operator- (const VPoint3DT<T>& p); 00250 template <typename T> VPoint3DT<T> operator*(const VPoint3DT<T>& p, T scale); 00251 template <typename T> VPoint3DT<T> operator*(T scale, const VPoint3DT<T>& p); 00252 template <typename T> VPoint3DT<T> operator/ (const VPoint3DT<T>& p, T divisor); 00253 00257 template <typename T> 00258 class VPoint3DT { 00259 public: 00260 00261 VPoint3DT() : mX(0), mY(0), mZ(0) {} 00262 VPoint3DT(T x, T y, T z) : mX(x), mY(y), mZ(z) {} 00263 VPoint3DT(VBinaryIOStream& stream) : mX(0), mY(0), mZ(0) { VGeometry::readTripletFromStream(stream, mX, mY, mZ); } 00264 ~VPoint3DT() {} 00265 00266 void readFromStream(VBinaryIOStream& stream) { VGeometry::readTripletFromStream(stream, mX, mY, mZ); } 00267 void writeToStream(VBinaryIOStream& stream) const { VGeometry::writeTripletToStream(stream, mX, mY, mZ); } 00268 00269 T getX() const { return mX; } 00270 T getY() const { return mY; } 00271 T getZ() const { return mZ; } 00272 void setX(T x) { mX = x; } 00273 void setY(T y) { mY = y; } 00274 void setZ(T z) { mZ = z; } 00275 T& rX() { return mX; } 00276 T& rY() { return mY; } 00277 T& rZ() { return mZ; } 00278 void setNull() { setX(0); setY(0); setZ(0); } 00279 VPoint3DT<T>& operator+=(const VPoint3DT<T>& p) { mX += p.mX; mY += p.mY; mZ += p.mZ; return *this; } 00280 VPoint3DT<T>& operator-=(const VPoint3DT<T>& p) { mX -= p.mX; mY -= p.mY; mZ -= p.mZ; return *this; } 00281 VPoint3DT<T>& operator*=(T scale) { mX *= scale; mY *= scale; mZ *= scale; return *this; } 00282 VPoint3DT<T>& operator/=(T divisor) { if (divisor == 0) throw VRangeException("VPoint3DT divide by zero."); mX /= divisor; mY /= divisor; mZ /= divisor; return *this; } 00283 00284 // These use "approximate" equality by testing for a difference >= 0.000001. 00285 static bool equal(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2) { 00286 return VGeometry::equal(p1.mX, p2.mX) && VGeometry::equal(p1.mY, p2.mY) && VGeometry::equal(p1.mZ, p2.mZ); 00287 } 00288 00289 static bool notEqual(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2) { 00290 return VGeometry::notEqual(p1.mX, p2.mX) || VGeometry::notEqual(p1.mY, p2.mY) || VGeometry::notEqual(p1.mZ, p2.mZ); 00291 } 00292 00293 friend bool operator== <>(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); // exact equality 00294 friend bool operator!= <>(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); // exact inequality 00295 friend VPoint3DT<T> operator+ <>(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); // addition 00296 friend VPoint3DT<T> operator- <>(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2); // subtraction 00297 friend VPoint3DT<T> operator- <>(const VPoint3DT<T>& p); // negation 00298 friend VPoint3DT<T> operator* <>(const VPoint3DT<T>& p, T scale); // multiplication p*n 00299 friend VPoint3DT<T> operator* <>(T scale, const VPoint3DT<T>& p); // multiplication n*p 00300 friend VPoint3DT<T> operator/ <>(const VPoint3DT<T>& p, T divisor); // division 00301 00302 private: 00303 00304 T mX; 00305 T mY; 00306 T mZ; 00307 }; 00308 00309 template<typename T> bool operator==(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2) { return p1.mX == p2.mX && p1.mY == p2.mY && p1.mZ == p2.mZ; } 00310 template<typename T> bool operator!=(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2) { return p1.mX != p2.mX || p1.mY != p2.mY || p1.mZ != p2.mZ; } 00311 template<typename T> VPoint3DT<T> operator+(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2) { return VPoint3DT<T>(p1.mX + p2.mX, p1.mY + p2.mY, p1.mZ + p2.mZ); } 00312 template<typename T> VPoint3DT<T> operator-(const VPoint3DT<T>& p1, const VPoint3DT<T>& p2) { return VPoint3DT<T>(p1.mX - p2.mX, p1.mY - p2.mY, p1.mZ - p2.mZ); } 00313 template<typename T> VPoint3DT<T> operator-(const VPoint3DT<T>& p) { return VPoint3DT<T>(-p.mX, -p.mY, -p.mZ); } 00314 template<typename T> VPoint3DT<T> operator*(const VPoint3DT<T>& p, T scale) { return VPoint3DT<T>(p.mX * scale, p.mY * scale, p.mZ * scale); } 00315 template<typename T> VPoint3DT<T> operator*(T scale, const VPoint3DT<T>& p) { return VPoint3DT<T>(p.mX * scale, p.mY * scale, p.mZ * scale); } 00316 template<typename T> VPoint3DT<T> operator/(const VPoint3DT<T>& p, T divisor) { if (divisor == 0) throw VRangeException("VPoint3DT divide by zero."); return VPoint3DT<T>(p.mX / divisor, p.mY / divisor, p.mZ / divisor); } 00317 00318 typedef VPoint3DT<VDouble> VPoint3D; 00319 typedef VPoint3DT<int> VIPoint3D; 00320 00321 template <typename T> class VLineT; 00322 template <typename T> bool operator== (const VLineT<T>& line1, const VLineT<T>& line2); // equality of start and end 00323 template <typename T> bool operator!= (const VLineT<T>& line1, const VLineT<T>& line2); // inequality of start or end 00324 00330 template <typename T> 00331 class VLineT { 00332 public: 00333 00334 VLineT() : mP1(), mP2() {} 00335 VLineT(VPointT<T> start, VPointT<T> end) : mP1(start), mP2(end) {} 00336 VLineT(VPointT<T> start, VSizeT<T> vec) : mP1(start), mP2(start + vec) {} 00337 VLineT(T x1, T y1, T x2, T y2) : mP1(x1, y1), mP2(x2, y2) {} 00338 VLineT(T x1, T y1, VSizeT<T> vec) : mP1(x1, y1), mP2(VPointT<T>(x1, y1) + vec) {} 00339 VLineT(VBinaryIOStream& stream) : mP1(), mP2() { mP1.readFromStream(stream); mP2.readFromStream(stream); } 00340 ~VLineT() {} 00341 00342 #ifdef VAULT_QT_SUPPORT 00343 VLineT(const QLine& line) : mP1(line.p1()), mP2(line.p2()) {} 00344 VLineT(const QLineF& line) : mP1(line.p1()), mP2(line.p2()) {} 00345 #endif 00346 00347 void readFromStream(VBinaryIOStream& stream) { mP1.readFromStream(stream); mP2.readFromStream(stream); } 00348 void writeToStream(VBinaryIOStream& stream) const { mP1.writeToStream(stream); mP2.writeToStream(stream); } 00349 00350 VPointT<T> getP1() const { return mP1; } 00351 VPointT<T> getP2() const { return mP2; } 00352 void setP1(VPointT<T> p) { mP1 = p; } 00353 void setP2(VPointT<T> p) { mP2 = p; } 00354 void setPoints(VPointT<T> p1, VPointT<T> p2) { mP1 = p1; mP2 = p2; } 00355 VPointT<T>& rP1() { return mP1; } 00356 VPointT<T>& rP2() { return mP2; } 00357 00358 VSizeT<T> getSize() const { return VSizeT<T>(this->getDX(), this->getDY()); } 00359 T getDX() const { return mP2.getX() - mP1.getX(); } 00360 T getDY() const { return mP2.getY() - mP1.getY(); } 00361 VDouble getLength() const { return VGeometry::getDistance(this->getDX(), this->getDY()); } 00362 00363 void translate(const VPointT<T>& delta) { mP1 += delta; mP2 += delta; } 00364 void translate(T deltaX, T deltaY) { this->translate(VPointT<T>(deltaX, deltaY)); } 00365 VLineT<T> translated(const VPointT<T>& delta) const { VLineT<T> line(*this); line.translate(delta); return line; } 00366 VLineT<T> translated(T deltaX, T deltaY) const { return this->translated(VPointT<T>(deltaX, deltaY)); } 00367 00374 VLineT<T> normalized() const { 00375 if (mP1.getX() < mP2.getX()) { 00376 return *this; 00377 } else if (mP1.getX() > mP2.getX()) { 00378 return VLineT<T>(mP2, mP1); 00379 } else if (mP1.getY() < mP2.getY()) { 00380 return *this; 00381 } 00382 00383 return VLineT<T>(mP2, mP1); 00384 } 00385 00386 VLineT<T> reversed() const { return VLineT<T>(mP2, mP1); } 00387 00392 VLineT<VDouble> getUnitVector() const { 00393 VDouble length = this->getLength(); 00394 if (length == 0.0) 00395 return VLineT<T>(); 00396 00397 return VLineT<T>(mP1, (this->getSize() / length)); 00398 } 00399 00400 // These use "approximate" equality by testing for a difference >= 0.000001. 00401 static bool equal(const VLineT<T>& line1, const VLineT<T>& line2) { 00402 return VPointT<T>::equal(line1.mP1, line2.mP1) && VPointT<T>::equal(line1.mP2, line2.mP2); 00403 } 00404 00405 static bool notEqual(const VLineT<T>& line1, const VLineT<T>& line2) { 00406 return VPointT<T>::notEqual(line1.mP1, line2.mP1) || VPointT<T>::notEqual(line1.mP2, line2.mP2); 00407 } 00408 00415 static bool same(const VLineT<T>& line1, const VLineT<T>& line2) { 00416 return VLineT<T>::equal(line1.normalized(), line2.normalized()); 00417 } 00418 00419 friend bool operator== <>(const VLineT<T>& line1, const VLineT<T>& line2); // exact equality 00420 friend bool operator!= <>(const VLineT<T>& line1, const VLineT<T>& line2); // exact inequality 00421 00422 #ifdef VAULT_QT_SUPPORT 00423 void setQLine(const QLine& line) { mP1 = line.p1(); mP2 = line.p2(); } 00424 QLine getQLine() const { return QLine(mP1.getQPoint(), mP2.getQPoint()); } 00425 void setQLineF(const QLineF& line) { mP1.setQPointF(line.p1()); mP2.setQPointF(line.p2()); } 00426 QLineF getQLineF() const { return QLineF(mP1, mP2); } 00427 #endif 00428 00439 VPoint getNearestPoint(const VPoint& C, bool restrictToSegment) const { 00440 // Name shortcuts for readability. 00441 const VDouble cx = C.getX(); 00442 const VDouble cy = C.getY(); 00443 const VDouble ax = mP1.getX(); 00444 const VDouble ay = mP1.getY(); 00445 const VDouble bx = mP2.getX(); 00446 const VDouble by = mP2.getY(); 00447 00448 const VDouble ratioABNumerator = (cx - ax) * (bx - ax) + (cy - ay) * (by - ay); 00449 const VDouble ratioABDenomenator = (bx - ax) * (bx - ax) + (by - ay) * (by - ay); 00450 const VDouble ratioAB = ratioABNumerator / ratioABDenomenator; // how far along the segment A->B is nearest point (0.0 = @A, 1.0 = @B) 00451 00452 // P is the result. We may need to restrict it to the segment ( next. 00453 VPoint P(ax + (ratioAB*(bx - ax)), ay + (ratioAB*(by - ay))); 00454 00455 // You can uncomment these if needed for debugging. 00456 // const VDouble s = ((ay-cy)*(bx-ax)-(ax-cx)*(by-ay) ) / ratioABDenomenator; 00457 // const VDouble distanceToLine = V_FABS(s) * sqrt(ratioABDenomenator); 00458 // VDouble distanceToSegment = 0.0; 00459 00460 if (((ratioAB >= 0.0) && (ratioAB <= 1.0)) || !restrictToSegment) { // nearest point is inside segment, or we don't care that it's outside 00461 // distanceToSegment = distanceToLine; 00462 } else { 00463 // Select the nearest endpoint of the segment. 00464 // Avoid calling sqrt until needed. 00465 const VDouble P1_distance_squared = (cx - ax) * (cx - ax) + (cy - ay) * (cy - ay); 00466 const VDouble P2_distance_squared = (cx - bx) * (cx - bx) + (cy - by) * (cy - by); 00467 if (P1_distance_squared < P2_distance_squared) { 00468 P = mP1; 00469 // distanceToSegment = sqrt(P1_distance_squared); 00470 } else { 00471 P = mP2; 00472 // distanceToSegment = sqrt(P2_distance_squared); 00473 } 00474 } 00475 00476 return P; 00477 } 00478 00479 VDouble getDistanceToPoint(const VPoint& p, bool restrictToSegment) const { 00480 VPoint nearestPointOnLine = this->getNearestPoint(p, restrictToSegment); 00481 return VPoint::getDistance(p, nearestPointOnLine); 00482 } 00483 00484 private: 00485 00486 VPointT<T> mP1; 00487 VPointT<T> mP2; 00488 }; 00489 00490 template<typename T> bool operator==(const VLineT<T>& line1, const VLineT<T>& line2) { return line1.mP1 == line2.mP1 && line1.mP2 == line2.mP2; } 00491 template<typename T> bool operator!=(const VLineT<T>& line1, const VLineT<T>& line2) { return line1.mP1 != line2.mP1 || line1.mP2 != line2.mP2; } 00492 00493 typedef VLineT<VDouble> VLine; 00494 typedef VLineT<int> VILine; 00495 00496 template <typename T> class VPolygonT; // forward declaration for use by VRectT 00497 00498 template <typename T> class VRectT; 00499 template <typename T> bool operator== (const VRectT<T>& p1, const VRectT<T>& p2); 00500 template <typename T> bool operator!= (const VRectT<T>& p1, const VRectT<T>& p2); 00501 00505 template <typename T> 00506 class VRectT { 00507 public: 00508 00509 VRectT() : mLeftTop(), mSize() {} 00510 VRectT(const VPointT<T>& leftTop, const VSizeT<T>& size) : mLeftTop(leftTop), mSize(size) {} 00511 VRectT(const VPointT<T>& leftTop, const VPointT<T>& rightBottom) : mLeftTop(leftTop), mSize(rightBottom.getX() - leftTop.getX(), rightBottom.getY() - leftTop.getY()) {} 00512 VRectT(VBinaryIOStream& stream) : mLeftTop(stream), mSize(stream) {} 00513 VRectT(T left, T top, T width, T height) : mLeftTop(left, top), mSize(width, height) {} 00514 ~VRectT() {} 00515 00516 #ifdef VAULT_QT_SUPPORT 00517 VRectT(const QRect& r) : mLeftTop(r.topLeft()), mSize(r.size()) {} 00518 VRectT(const QRectF& r) : mLeftTop(static_cast<VPointT<T> >(r.topLeft())), mSize(static_cast<VSizeT<T> >(r.size())) {} 00519 #endif 00520 00521 void readFromStream(VBinaryIOStream& stream) { mLeftTop.readFromStream(stream); mSize.readFromStream(stream); } 00522 void writeToStream(VBinaryIOStream& stream) const { mLeftTop.writeToStream(stream); mSize.writeToStream(stream); } 00523 00524 VPointT<T> getLeftTop() const { return mLeftTop; } 00525 VPointT<T> getRightBottom() const { return VPointT<T>(mLeftTop + mSize); } 00526 VPointT<T> getRightTop() const { return VPointT<T>(mLeftTop + VSizeT<T>(mSize.getWidth(), 0)); } 00527 VPointT<T> getLeftBottom() const { return VPointT<T>(mLeftTop + VSizeT<T>(0, mSize.getHeight())); } 00528 VSizeT<T> getSize() const { return mSize; } 00529 T getLeft() const { return mLeftTop.getX(); } 00530 T getTop() const { return mLeftTop.getY(); } 00531 T getRight() const { return mLeftTop.getX() + mSize.getWidth(); } 00532 T getBottom() const { return mLeftTop.getY() + mSize.getHeight(); } 00533 T getWidth() const { return mSize.getWidth(); } 00534 T getHeight() const { return mSize.getHeight(); } 00535 VPointT<T> getCenter() const { return VPointT<T>(mLeftTop.getX() + (mSize.getWidth() / 2), mLeftTop.getY() + (mSize.getHeight() / 2)); } 00537 VLineT<T> getTopSide() const { return VLineT<T>(this->getLeftTop(), this->getRightTop()).normalized(); } 00538 VLineT<T> getRightSide() const { return VLineT<T>(this->getRightTop(), this->getRightBottom()).normalized(); } 00539 VLineT<T> getBottomSide() const { return VLineT<T>(this->getRightBottom(), this->getLeftBottom()).normalized(); } 00540 VLineT<T> getLeftSide() const { return VLineT<T>(this->getLeftBottom(), this->getLeftTop()).normalized(); } 00541 00542 VRectT<T> normalized() const { 00543 VPointT<T> p(mLeftTop); 00544 VSizeT<T> s(mSize); 00545 00546 T width = s.getWidth(); 00547 if (width < 0) { 00548 s.setWidth(-width); 00549 p.rX() += width; // width is negative at this point 00550 } 00551 00552 T height = s.getHeight(); 00553 if (height < 0) { 00554 s.setHeight(-height); 00555 p.rY() += height; // height is negative at this point 00556 } 00557 00558 return VRectT<T>(p, s); 00559 } 00560 00561 void moveTo(const VPointT<T>& leftTop) { mLeftTop = leftTop; } 00562 void translate(T dx, T dy) { mLeftTop += VPointT<T>(dx, dy); } 00563 void translate(const VPointT<T>& offset) { mLeftTop += offset; } 00564 void setSize(const VSizeT<T>& size) { mSize = size; } 00565 void setWidth(T width) { mSize.setWidth(width); } 00566 void setHeight(T height) { mSize.setHeight(height); } 00567 void setBounds(T left, T top, T right, T bottom) { mLeftTop.setX(left); mLeftTop.setY(top); mSize.setWidth(right - left); mSize.setHeight(bottom - top); } 00568 void setLeft(T left) { mLeftTop.setX(left); } 00569 void setTop(T top) { mLeftTop.setY(top); } 00570 void setRight(T right) { mSize.setWidth(right - this->getLeft()); } 00571 void setBottom(T bottom) { mSize.setHeight(bottom - this->getTop()); } 00572 00573 bool contains(const VPointT<T>& p) const { 00574 VPointT<T> rightBottom = this->getRightBottom(); 00575 00576 return p.getX() >= mLeftTop.getX() && p.getX() < rightBottom.getX() && 00577 p.getY() >= mLeftTop.getY() && p.getY() < rightBottom.getY(); 00578 } 00579 00580 void expandTo(const VPointT<T>& p) { 00581 if (! this->contains(p)) { 00582 T leftDX = mLeftTop.getX() - p.getX(); 00583 if (leftDX > 0) { 00584 mLeftTop.rX() -= leftDX; 00585 mSize.rWidth() += leftDX; 00586 } else { 00587 T rightDX = p.getX() - this->getRight(); 00588 if (rightDX > 0) { 00589 mSize.rWidth() += rightDX; 00590 } 00591 } 00592 00593 T topDY = mLeftTop.getY() - p.getY(); 00594 if (topDY > 0) { 00595 mLeftTop.rY() -= topDY; 00596 mSize.rHeight() += topDY; 00597 } else { 00598 T bottomDY = p.getY() - this->getBottom(); 00599 if (bottomDY > 0) { 00600 mSize.rHeight() += bottomDY; 00601 } 00602 } 00603 00604 } 00605 } 00606 00607 VRectT<T> united(const VRectT<T>& r) const { 00608 VRectT<T> result(mLeftTop, mSize); 00609 result.expandTo(r.getLeftTop()); 00610 result.expandTo(r.getRightBottom()); 00611 00612 return result; 00613 } 00614 00615 VRectT<T> intersected(const VRectT<T>& r) const { 00616 T left = V_MAX(this->getLeft(), r.getLeft()); 00617 T top = V_MAX(this->getTop(), r.getTop()); 00618 T right = V_MIN(this->getRight(), r.getRight()); 00619 T bottom = V_MIN(this->getBottom(), r.getBottom()); 00620 T width = right - left; 00621 T height = bottom - top; 00622 00623 if ((width >= 0) && (height >= 0)) { 00624 return VRectT<T>(left, top, width, height); 00625 } 00626 00627 return VRectT<T>(); 00628 } 00629 00635 VPointT<T> getNearestVertex(const VPointT<T>& testPoint) const { 00636 VPolygonT<T> polygon(*this); 00637 int nearestVertex = polygon.getNearestVertex(testPoint); 00638 return polygon.getPoint(nearestVertex); 00639 } 00640 00649 VLineT<T> getNearestSide(const VPointT<T>& testPoint) const { 00650 VPointT<T> unused; 00651 return this->getNearestSide(testPoint, unused); 00652 } 00653 00665 VLineT<T> getNearestSide(const VPointT<T>& testPoint, VPoint& nearestPoint) const { 00666 VPolygonT<T> polygon(*this); 00667 int nearestSide = polygon.getNearestSide(testPoint, nearestPoint); 00668 return polygon.getSide(nearestSide); 00669 } 00670 00671 // These use "approximate" equality by testing for a difference >= 0.000001. 00672 static bool equal(const VRectT<T>& r1, const VRectT<T>& r2) { 00673 return VPointT<T>::equal(r1.mLeftTop, r2.mLeftTop) && VSizeT<T>::equal(r1.mSize, r2.mSize); 00674 } 00675 00676 static bool notEqual(const VRectT<T>& r1, const VRectT<T>& r2) { 00677 return VPointT<T>::notEqual(r1.mLeftTop, r2.mLeftTop) || VSizeT<T>::notEqual(r1.mSize, r2.mSize); 00678 } 00679 00680 friend bool operator== <>(const VRectT<T>& r1, const VRectT<T>& r2); // exact equality 00681 friend bool operator!= <>(const VRectT<T>& r1, const VRectT<T>& r2); // exact inequality 00682 00683 #ifdef VAULT_QT_SUPPORT 00684 void setQRect(const QRect& r) { mLeftTop = r.topLeft(); mSize = r.size(); } 00685 QRect getQRect() const { return QRect(static_cast<int>(mLeftTop.getX()), static_cast<int>(mLeftTop.getY()), static_cast<int>(mSize.getWidth()), static_cast<int>(mSize.getHeight())); } 00686 void setQRectF(const QRectF& r) { mLeftTop = static_cast<T>(r.topLeft()); mSize = static_cast<T>(r.size()); } 00687 QRectF getQRectF() const { return QRectF(mLeftTop, mSize); } 00688 #endif 00689 00690 private: 00691 00692 VPointT<T> mLeftTop; 00693 VSizeT<T> mSize; 00694 }; 00695 00696 template<typename T> bool operator==(const VRectT<T>& r1, const VRectT<T>& r2) { return r1.mLeftTop == r2.mLeftTop && r1.mSize == r2.mSize; } 00697 template<typename T> bool operator!=(const VRectT<T>& r1, const VRectT<T>& r2) { return r1.mLeftTop != r2.mLeftTop || r1.mSize != r2.mSize; } 00698 00699 typedef VRectT<VDouble> VRect; 00700 typedef VRectT<int> VIRect; 00701 00702 template <typename T> class VPolygonT; 00703 template <typename T> bool operator== (const VPolygonT<T>& p1, const VPolygonT<T>& p2); 00704 template <typename T> bool operator!= (const VPolygonT<T>& p1, const VPolygonT<T>& p2); 00705 00709 template <typename T> 00710 class VPolygonT { 00711 public: 00712 00713 VPolygonT() : mPoints() {} 00714 VPolygonT(const std::vector<VPointT<T> >& points) : mPoints(points) {} 00715 VPolygonT(VBinaryIOStream& stream) : mPoints() { this->readFromStream(stream); } 00716 VPolygonT(const VRectT<T>& rect) : 00717 mPoints() { 00718 this->add(rect.getLeftTop()); 00719 this->add(rect.getRightTop()); 00720 this->add(rect.getRightBottom()); 00721 this->add(rect.getLeftBottom()); 00722 } 00723 00724 ~VPolygonT() {} 00725 00726 #ifdef VAULT_QT_SUPPORT 00727 VPolygonT(const QPolygon& p) { 00728 for (QPolygon::const_iterator i = p.begin(); i != p.end(); ++i) { 00729 this->add(VPointT<T>(static_cast<T>(i->x()), static_cast<T>(i->y()))); 00730 } 00731 } 00732 00733 VPolygonT(const QPolygonF& p) { 00734 for (QPolygonF::const_iterator i = p.begin(); i != p.end(); ++i) { 00735 this->add(VPointT<T>(i->x(), i->y())); 00736 } 00737 } 00738 #endif 00739 00740 void readFromStream(VBinaryIOStream& stream) { 00741 this->eraseAll(); 00742 int numPoints = static_cast<int>(stream.readS32()); 00743 for (int i = 0; i < numPoints; ++i) { 00744 VPointT<T> point; 00745 point.readFromStream(stream); 00746 this->add(point); 00747 } 00748 } 00749 00750 void writeToStream(VBinaryIOStream& stream) const { 00751 int numPoints = this->getNumPoints(); 00752 stream.writeInt32(numPoints); 00753 for (int i = 0; i < numPoints; ++i) { 00754 mPoints[i].writeToStream(stream); 00755 } 00756 } 00757 00758 void add(VPointT<T> p) { mPoints.push_back(p); } 00759 void insert(int beforeIndex, VPointT<T> p) { mPoints.insert(mPoints.begin() + beforeIndex, p); } 00760 int getNumPoints() const { return static_cast<int>(mPoints.size()); } 00761 size_t size() const { return mPoints.size(); } 00762 const std::vector<VPointT<T> >& getPoints() const { return mPoints; } 00763 VPointT<T> getPoint(int index) const { if (index >= this->getNumPoints()) { throw VRangeException(VSTRING_FORMAT("getPoint: Invalid index %d into %d-point polygon.", index, this->getNumPoints())); } return mPoints[index]; } 00764 void setPoint(int index, VPointT<T> p) { if (index >= this->getNumPoints()) { throw VRangeException(VSTRING_FORMAT("setPoint: Invalid index %d into %d-point polygon.", index, this->getNumPoints())); } mPoints[index] = p; } 00765 VPointT<T>& operator[](int index) { return mPoints[index]; } // Note that operator[] by definition does no range checking. 00766 VPointT<T> operator[](int index) const { return mPoints[index]; } // Note that operator[] by definition does no range checking. 00767 00768 VRectT<T> getBounds() const { 00769 VRectT<T> bounds; // defaults to a zero rect 00770 int numPoints = this->getNumPoints(); 00771 00772 if (numPoints > 0) { 00773 bounds.moveTo(mPoints[0]); 00774 00775 for (int i = 1; i < numPoints; ++i) { 00776 bounds.expandTo(mPoints[i]); 00777 } 00778 00779 } 00780 00781 return bounds; 00782 } 00783 00784 void remove(int index) { mPoints.erase(mPoints.begin() + index); } 00785 void eraseAll() { mPoints.erase(mPoints.begin(), mPoints.end()); } 00786 void translate(VPointT<T> offset) { 00787 int numPoints = static_cast<int>(mPoints.size()); 00788 for (int i = 0; i < numPoints; ++i) { 00789 mPoints[i] += offset; 00790 } 00791 } 00792 00793 VLineT<T> getSide(int index) const { 00794 int maxValidIndex = this->getNumPoints() - 1; 00795 if (index > maxValidIndex) { 00796 throw VRangeException(VSTRING_FORMAT("getSide: Invalid index %d into %d-point polygon.", index, this->getNumPoints())); 00797 } 00798 00799 int index2 = (index == maxValidIndex) ? 0 : index + 1; 00800 return VLineT<T>(mPoints[index], mPoints[index2]); 00801 } 00802 00808 int getNearestVertex(const VPointT<T>& testPoint) const { 00809 int nearestVertexIndex = -1; 00810 VDouble nearestVertexDistance = -1.0; 00811 int numPoints = static_cast<int>(mPoints.size()); 00812 for (int i = 0; i < numPoints; ++i) { 00813 VDouble distanceToVertex = VPoint::getDistance(testPoint, mPoints[i]); 00814 if ((nearestVertexIndex < 0) || (distanceToVertex < nearestVertexDistance)) { 00815 nearestVertexIndex = i; 00816 nearestVertexDistance = distanceToVertex; 00817 } 00818 } 00819 00820 return nearestVertexIndex; 00821 } 00822 00831 int getNearestSide(const VPointT<T>& testPoint) const { 00832 VPointT<T> unused; 00833 return this->getNearestSide(testPoint, unused); 00834 } 00835 00847 int getNearestSide(const VPointT<T>& testPoint, VPoint& nearestPoint) const { 00848 int nearestSideIndex = -1; 00849 VDouble nearestSideDistance = -1.0; 00850 VPoint nearestSidePoint; 00851 int numSides = static_cast<int>(mPoints.size()); 00852 for (int i = 0; i < numSides; ++i) { 00853 VLine side = this->getSide(i); 00854 VPoint p = side.getNearestPoint(testPoint, true); 00855 VDouble distanceToSide = VPoint::getDistance(testPoint, p); 00856 if ((nearestSideIndex < 0) || (distanceToSide < nearestSideDistance)) { 00857 nearestSideIndex = i; 00858 nearestSidePoint = p; 00859 nearestSideDistance = distanceToSide; 00860 } 00861 } 00862 00863 nearestPoint = nearestSidePoint; 00864 return nearestSideIndex; 00865 } 00866 00867 // These use "approximate" equality by testing for a coordinate difference >= 0.000001. 00868 static bool equal(const VPolygonT<T>& p1, const VPolygonT<T>& p2) { 00869 if (p1.mPoints.size() != p2.mPoints.size()) 00870 return false; 00871 00872 int numPoints = static_cast<int>(p1.mPoints.size()); 00873 for (int i = 0; i < numPoints; ++i) { 00874 if (VPointT<T>::notEqual(p1.mPoints[i], p2.mPoints[i])) { 00875 return false; 00876 } 00877 } 00878 00879 return true; 00880 } 00881 00882 static bool notEqual(const VPolygonT<T>& p1, const VPolygonT<T>& p2) { 00883 if (p1.mPoints.size() == p2.mPoints.size()) 00884 return false; 00885 00886 int numPoints = static_cast<int>(p1.mPoints.size()); 00887 for (int i = 0; i < numPoints; ++i) { 00888 if (VPointT<T>::equal(p1.mPoints[i], p2.mPoints[i])) { 00889 return false; 00890 } 00891 } 00892 00893 return true; 00894 } 00895 00896 friend bool operator== <>(const VPolygonT<T>& p1, const VPolygonT<T>& p2); // exact equality 00897 friend bool operator!= <>(const VPolygonT<T>& p1, const VPolygonT<T>& p2); // exact inequality 00898 00899 #ifdef VAULT_QT_SUPPORT 00900 void setQPolygon(const QPolygon& p) { 00901 this->eraseAll(); 00902 for (QPolygon::const_iterator i = p.begin(); i != p.end(); ++i) { 00903 this->add(VPointT<T>(static_cast<T>(i->x()), static_cast<T>(i->y()))); 00904 } 00905 } 00906 00907 QPolygon getQPolygon() const { 00908 QPolygon p; 00909 int numPoints = static_cast<int>(mPoints.size()); 00910 for (int i = 0; i < numPoints; ++i) { 00911 p.push_back(mPoints[i].getQPoint()); 00912 } 00913 return p; 00914 } 00915 00916 void setQPolygonF(const QPolygonF& p) { 00917 this->eraseAll(); 00918 for (QPolygonF::const_iterator i = p.begin(); i != p.end(); ++i) { 00919 this->add(VPointT<T>(i->x(), i->y())); 00920 } 00921 } 00922 00923 QPolygonF getQPolygonF() const { 00924 QPolygonF p; 00925 int numPoints = static_cast<int>(mPoints.size()); 00926 for (int i = 0; i < numPoints; ++i) { 00927 p.push_back(mPoints[i].getQPointF()); 00928 } 00929 return p; 00930 } 00931 #endif 00932 00933 private: 00934 00935 std::vector<VPointT<T> > mPoints; 00936 }; 00937 00938 template<typename T> bool operator==(const VPolygonT<T>& p1, const VPolygonT<T>& p2) { return p1.mPoints == p2.mPoints; } 00939 template<typename T> bool operator!=(const VPolygonT<T>& p1, const VPolygonT<T>& p2) { return p1.mPoints != p2.mPoints; } 00940 00941 typedef VPolygonT<VDouble> VPolygon; 00942 typedef VPolygonT<int> VIPolygon; 00943 00944 /* 00945 Comments about "dead zones": 00946 00947 There are several functions in VRectT and VPolygonT that locate the "nearest" side of 00948 the rectangle or polygon to a particular point in 2D space. There are some cases where 00949 the point is in a "dead zone", such that the answer is ambiguous. I have a diagram 00950 showing this at the following URL: 00951 <http://www.bombaydigital.com/software/vault/images/deadzone.png> 00952 00953 The basic problem is that if the nearest point on the edge of the rectangle or polygon 00954 is a vertex (a corner), then it is not clear which of the two sides attached at the vertex 00955 should be considered "nearest" to the point. The current implementation makes no guarantee 00956 about which of the two sides will be chosen in this case. If you ask which vertex is nearest, 00957 the answer is unambiguous. It's the "nearest side" question that has an ambigous answer. 00958 Fortunately, the use cases I can think of don't care which side is returned because they 00959 are really trying to get the nearest point on that side, which is the same for either side. 00960 */ 00961 00962 #endif /* vgeometry_h */