Vault  4.1
vgeometry.h
Go to the documentation of this file.
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 */

Copyright ©1997-2014 Trygve Isaacson. All rights reserved. This documentation was generated with Doxygen.