1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 Copyright (c) 2006 Matthias Fink, netAllied GmbH <matthias.fink@web.de> 9 10 Permission is hereby granted, free of charge, to any person obtaining a copy 11 of this software and associated documentation files (the "Software"), to deal 12 in the Software without restriction, including without limitation the rights 13 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 copies of the Software, and to permit persons to whom the Software is 15 furnished to do so, subject to the following conditions: 16 17 The above copyright notice and this permission notice shall be included in 18 all copies or substantial portions of the Software. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 THE SOFTWARE. 27 ----------------------------------------------------------------------------- 28 */ 29 #include "OgreStableHeaders.h" 30 #include "OgrePolygon.h" 31 32 namespace Ogre 33 { 34 35 //----------------------------------------------------------------------- Polygon()36 Polygon::Polygon() 37 : mNormal( Vector3::ZERO ) 38 , mIsNormalSet(false) 39 { 40 // reserve space for 6 vertices to reduce allocation cost 41 mVertexList.reserve(6); 42 } 43 //----------------------------------------------------------------------- ~Polygon()44 Polygon::~Polygon() 45 { 46 } 47 //----------------------------------------------------------------------- Polygon(const Polygon & cpy)48 Polygon::Polygon( const Polygon& cpy ) 49 { 50 mVertexList = cpy.mVertexList; 51 mNormal = cpy.mNormal; 52 mIsNormalSet = cpy.mIsNormalSet; 53 } 54 //----------------------------------------------------------------------- insertVertex(const Vector3 & vdata,size_t vertex)55 void Polygon::insertVertex(const Vector3& vdata, size_t vertex ) 56 { 57 // TODO: optional: check planarity 58 OgreAssertDbg(vertex <= getVertexCount(), "Insert position out of range" ); 59 60 VertexList::iterator it = mVertexList.begin(); 61 62 std::advance(it, vertex); 63 mVertexList.insert(it, vdata); 64 65 } 66 //----------------------------------------------------------------------- insertVertex(const Vector3 & vdata)67 void Polygon::insertVertex(const Vector3& vdata) 68 { 69 mVertexList.push_back(vdata); 70 } 71 //----------------------------------------------------------------------- getVertex(size_t vertex) const72 const Vector3& Polygon::getVertex( size_t vertex ) const 73 { 74 OgreAssertDbg(vertex < getVertexCount(), "Search position out of range"); 75 76 return mVertexList[vertex]; 77 } 78 //----------------------------------------------------------------------- setVertex(const Vector3 & vdata,size_t vertex)79 void Polygon::setVertex(const Vector3& vdata, size_t vertex ) 80 { 81 // TODO: optional: check planarity 82 OgreAssertDbg(vertex < getVertexCount(), "Search position out of range" ); 83 84 // set new vertex 85 mVertexList[ vertex ] = vdata; 86 } 87 //----------------------------------------------------------------------- removeDuplicates(void)88 void Polygon::removeDuplicates( void ) 89 { 90 for ( size_t i = 0; i < getVertexCount(); ++i ) 91 { 92 const Vector3& a = getVertex( i ); 93 const Vector3& b = getVertex( (i + 1)%getVertexCount() ); 94 95 if (a.positionEquals(b)) 96 { 97 deleteVertex(i); 98 --i; 99 } 100 } 101 } 102 //----------------------------------------------------------------------- getVertexCount(void) const103 size_t Polygon::getVertexCount( void ) const 104 { 105 return mVertexList.size(); 106 } 107 //----------------------------------------------------------------------- getNormal(void) const108 const Vector3& Polygon::getNormal( void ) const 109 { 110 updateNormal(); 111 112 return mNormal; 113 } 114 //----------------------------------------------------------------------- updateNormal(void) const115 void Polygon::updateNormal( void ) const 116 { 117 OgreAssertDbg( getVertexCount() >= 3, "Insufficient vertex count!" ); 118 119 if (mIsNormalSet) 120 return; 121 122 // vertex order is ccw 123 const Vector3& a = getVertex( 0 ); 124 const Vector3& b = getVertex( 1 ); 125 const Vector3& c = getVertex( 2 ); 126 127 // used method: Newell 128 mNormal.x = 0.5f * ( (a.y - b.y) * (a.z + b.z) + 129 (b.y - c.y) * (b.z + c.z) + 130 (c.y - a.y) * (c.z + a.z)); 131 132 mNormal.y = 0.5f * ( (a.z - b.z) * (a.x + b.x) + 133 (b.z - c.z) * (b.x + c.x) + 134 (c.z - a.z) * (c.x + a.x)); 135 136 mNormal.z = 0.5f * ( (a.x - b.x) * (a.y + b.y) + 137 (b.x - c.x) * (b.y + c.y) + 138 (c.x - a.x) * (c.y + a.y)); 139 140 mNormal.normalise(); 141 142 mIsNormalSet = true; 143 144 } 145 //----------------------------------------------------------------------- deleteVertex(size_t vertex)146 void Polygon::deleteVertex( size_t vertex ) 147 { 148 OgreAssertDbg( vertex < getVertexCount(), "Search position out of range" ); 149 150 VertexList::iterator it = mVertexList.begin(); 151 std::advance(it, vertex); 152 153 mVertexList.erase( it ); 154 } 155 //----------------------------------------------------------------------- storeEdges(Polygon::EdgeMap * edgeMap) const156 void Polygon::storeEdges( Polygon::EdgeMap *edgeMap ) const 157 { 158 OgreAssert( edgeMap != NULL, "EdgeMap ptr is NULL" ); 159 160 size_t vertexCount = getVertexCount(); 161 162 for ( size_t i = 0; i < vertexCount; ++i ) 163 { 164 edgeMap->insert( Edge( getVertex( i ), getVertex( ( i + 1 ) % vertexCount ) ) ); 165 } 166 } 167 //----------------------------------------------------------------------- reset(void)168 void Polygon::reset( void ) 169 { 170 // could use swap() to free memory here, but assume most may be reused so avoid realloc 171 mVertexList.clear(); 172 173 mIsNormalSet = false; 174 } 175 //----------------------------------------------------------------------- operator ==(const Polygon & rhs) const176 bool Polygon::operator == (const Polygon& rhs) const 177 { 178 if ( getVertexCount() != rhs.getVertexCount() ) 179 return false; 180 181 // Compare vertices. They may differ in its starting position. 182 // find start 183 size_t start = 0; 184 bool foundStart = false; 185 for (size_t i = 0; i < getVertexCount(); ++i ) 186 { 187 if (getVertex(0).positionEquals(rhs.getVertex(i))) 188 { 189 start = i; 190 foundStart = true; 191 break; 192 } 193 } 194 195 if (!foundStart) 196 return false; 197 198 for (size_t i = 0; i < getVertexCount(); ++i ) 199 { 200 const Vector3& vA = getVertex( i ); 201 const Vector3& vB = rhs.getVertex( ( i + start) % getVertexCount() ); 202 203 if (!vA.positionEquals(vB)) 204 return false; 205 } 206 207 return true; 208 } 209 //----------------------------------------------------------------------- operator <<(std::ostream & strm,const Polygon & poly)210 std::ostream& operator<< ( std::ostream& strm, const Polygon& poly ) 211 { 212 strm << "NUM VERTICES: " << poly.getVertexCount() << std::endl; 213 214 for (size_t j = 0; j < poly.getVertexCount(); ++j ) 215 { 216 strm << "VERTEX " << j << ": " << poly.getVertex( j ) << std::endl; 217 } 218 219 return strm; 220 } 221 //----------------------------------------------------------------------- isPointInside(const Vector3 & point) const222 bool Polygon::isPointInside(const Vector3& point) const 223 { 224 // sum the angles 225 Real anglesum = 0; 226 size_t n = getVertexCount(); 227 for (size_t i = 0; i < n; i++) 228 { 229 const Vector3& p1 = getVertex(i); 230 const Vector3& p2 = getVertex((i + 1) % n); 231 232 Vector3 v1 = p1 - point; 233 Vector3 v2 = p2 - point; 234 235 Real len1 = v1.length(); 236 Real len2 = v2.length(); 237 238 if (Math::RealEqual(len1 * len2, 0.0f, 1e-4f)) 239 { 240 // We are on a vertex so consider this inside 241 return true; 242 } 243 else 244 { 245 Real costheta = v1.dotProduct(v2) / (len1 * len2); 246 anglesum += std::acos(costheta); 247 } 248 } 249 250 // result should be 2*PI if point is inside poly 251 return Math::RealEqual(anglesum, Math::TWO_PI, 1e-4f); 252 253 } 254 } 255