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