source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/Polyhedron.cpp @ 2913

Revision 2913, 7.3 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include "Polyhedron.h"
2#include "common.h"
3#include "Polygon3.h"
4#include "Plane3.h"
5
6
7using namespace std;
8
9
10namespace CHCDemoEngine
11{
12
13static const float epsilon = 1e-6f;
14
15/**********************************************************/
16/*             class Polyhedron Implementation             */
17/**********************************************************/
18
19
20Polyhedron::Polyhedron()
21{
22        mBox.Initialize();
23}
24
25
26Polyhedron::Polyhedron(const PolygonContainer &polys)
27{
28        mPolygons = polys;
29
30        mBox.Initialize();
31        mBox.Include(mPolygons);
32}
33
34
35Polyhedron::Polyhedron(const Polyhedron &rhs)
36{
37        mPolygons.reserve(rhs.mPolygons.size());
38        mBox = rhs.mBox;
39
40        PolygonContainer::const_iterator it, it_end = rhs.mPolygons.end();
41
42        for (it = rhs.mPolygons.begin(); it != it_end; ++ it)
43                Add(new Polygon3(*(*it)));
44}
45
46
47Polyhedron::~Polyhedron()
48{
49        CLEAR_CONTAINER(mPolygons);
50}
51
52
53int Polyhedron::NumPolygons() const
54{
55        return (int)mPolygons.size();
56}
57
58
59void Polyhedron::Add(Polygon3 *p)
60{
61    mPolygons.push_back(p);
62        mBox.Include(*p);
63}
64
65
66const PolygonContainer &Polyhedron::GetPolygons() const
67{
68        return mPolygons;
69}
70
71
72float Polyhedron::GetArea() const
73{
74        float area = 0;
75
76        for (size_t i = 0; i < mPolygons.size(); ++ i)
77        {
78                area += mPolygons[i]->GetArea();
79        }
80
81        return area;
82}
83
84
85
86float Polyhedron::GetVolume() const
87{
88        // computes volume by tetrahedralization of the geometry
89        // We just compute the sum of the tetrahedron volumes
90        float volume = 0;
91        const float f = 1.0f / 6.0f;
92
93        PolygonContainer::const_iterator pit, pit_end = mPolygons.end();
94
95        // note: can take arbitrary point, e.g., the origin. However,
96        // we rather take the center of mass to prevents precision errors
97        const Vector3 center = CenterOfMass();
98
99        for (pit = mPolygons.begin(); pit != pit_end; ++ pit)
100        {
101                Polygon3 *poly = *pit;
102                const Vector3 v0 = poly->mVertices[0] - center;
103
104                for (int i = 1; i < (int)poly->mVertices.size() - 1; ++ i)
105                {
106                        const Vector3 v1 = poly->mVertices[i] - center;
107                        const Vector3 v2 = poly->mVertices[i + 1] - center;
108
109                        // more robust version using abs and the center of mass
110                        volume += fabs (f * (DotProd(v0, CrossProd(v1, v2))));
111                }
112        }
113
114        return volume;
115}
116
117
118AxisAlignedBox3 Polyhedron::GetBoundingBox() const
119{
120        return mBox;
121}
122
123
124int Polyhedron::Side(const Plane3 &plane) const
125{
126        int boxSide = mBox.Side(plane);
127
128        // plane does not intersect bounding box
129        if (boxSide != 0) return boxSide;
130
131        PolygonContainer::const_iterator it, it_end = mPolygons.end();
132
133        int s = 0;
134
135        for (it = mPolygons.begin(); it != it_end; ++ it)
136        {
137        const int side = (*it)->Side(plane, epsilon);
138
139                if (side == 0) // intersects polygon => intersects
140                        return 0;
141                else if (side != 0)
142                {
143                        if (side == -s)
144                                return 0; // sign changed => intersects
145
146                        s = side;
147                }
148        }
149
150        return s;
151}
152
153
154Vector3 Polyhedron::CenterOfMass() const
155{
156        int n = 0;
157
158        Vector3 center(0,0,0);
159
160        PolygonContainer::const_iterator pit, pit_end = mPolygons.end();
161
162        for (pit = mPolygons.begin(); pit != pit_end; ++ pit)
163        {
164                Polygon3 *poly = *pit;
165               
166                VertexArray::const_iterator vit, vit_end = poly->mVertices.end();
167
168                for(vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
169                {
170                        center += *vit;
171                        ++ n;
172                }
173        }
174
175        return center / (float)n;
176}
177
178
179bool Polyhedron::Valid() const
180{
181        // polyhedron is degenerated
182        if (mPolygons.size() < 3)
183                return false;
184       
185        const Vector3 center = CenterOfMass();
186
187        PolygonContainer::const_iterator pit, pit_end = mPolygons.end();
188
189        for (pit = mPolygons.begin(); pit != pit_end; ++ pit)
190        {
191                Polygon3 *poly = *pit;
192                Plane3 plane = poly->GetSupportingPlane();
193
194                float dist = plane.Distance(center);
195                //cout << "dist: " << dist<< endl;
196                if (dist > 0)
197                        return false;
198        }
199        return true;
200}
201
202
203Polyhedron *Polyhedron::CalcIntersection(const Plane3 &splitPlane) const
204{       
205        // first test plane intersection with geometry
206        const int intersect = Side(splitPlane);
207       
208        if (intersect == 1)
209        {
210                // on the other side of the plane, the intersection is empty
211                return NULL;
212        }
213        else if (intersect == -1)
214        {
215                // does not intersect, just return a copy
216                return new Polyhedron(*this);
217        }
218
219        // polyhedron is intersected: create new polyhedron
220        Polyhedron *clippedPolyhedron = new Polyhedron();
221
222
223        //////////
224        //-- create and add new polygon to close polyhedron
225
226        // get cross section of new polygon
227        Polygon3 *planePoly = mBox.CrossSection(splitPlane);
228
229        // create new face: split polygon with all other polygons
230        planePoly = SplitPolygon(planePoly);
231
232        // something is wrong, probably some numerical error
233        if (!planePoly)
234        {
235                cerr << "should not happen" << endl;
236                return new Polyhedron(*this);
237        }
238
239        // add the new polygon to the polyhedron
240        clippedPolyhedron->Add(planePoly);
241
242
243
244        /////////////
245        //-- clip polyhedron: plane splits all polygons
246
247        for (int i = 0; i < (int)mPolygons.size(); ++ i)
248        {
249                Polygon3 *poly = mPolygons[i];
250
251                const int cf = mPolygons[i]->ClassifyPlane(splitPlane, epsilon);
252                       
253                switch (cf)
254                {
255                        // split case: split polygon and add it
256                        case Polygon3::SPLIT:
257                                {
258                                        Polygon3 *poly = mPolygons[i];
259
260                                        Polygon3 *frontPoly = new Polygon3();
261                                        Polygon3 *backPoly = new Polygon3();
262                               
263                                        poly->Split(splitPlane, *frontPoly, *backPoly, epsilon);
264
265                                        // we are only interested in the polytope behind the plane
266                                        DEL_PTR(frontPoly);
267
268                                        if (backPoly->Valid(epsilon))
269                                                clippedPolyhedron->Add(backPoly);
270                                        else
271                                                DEL_PTR(backPoly);
272                                }
273                               
274                                break;
275                        case Polygon3::BACK_SIDE:
276                        case Polygon3::COINCIDENT:
277                                clippedPolyhedron->Add(new Polygon3(mPolygons[i]->mVertices));
278                                break;
279                        default:
280                                // polygon is not in intersection
281                                break;
282                }
283        }
284
285        return clippedPolyhedron;
286}
287
288
289Polygon3 *Polyhedron::SplitPolygon(Polygon3 *polygon) const
290{
291        if (!polygon->Valid(epsilon)) DEL_PTR(polygon);
292
293        // polygon is split by all other planes
294        for (size_t i = 0; (i < mPolygons.size()) && polygon; ++ i)
295        {
296                const Plane3 plane = mPolygons[i]->GetSupportingPlane();
297
298                int cf = polygon->ClassifyPlane(plane, epsilon);
299
300                // split new polygon with all previous planes
301                switch (cf)
302                {
303                        case Polygon3::SPLIT:
304                                {
305                                        Polygon3 *frontPoly = new Polygon3();
306                                        Polygon3 *backPoly = new Polygon3();
307
308                                        polygon->Split(plane, *frontPoly, *backPoly, epsilon);
309                                       
310                                        // don't need these anymore
311                                        DEL_PTR(frontPoly);
312                                        DEL_PTR(polygon);
313
314                                        // back polygon belongs to geometry
315                                        if (backPoly->Valid(epsilon))
316                                                polygon = backPoly;
317                                        else
318                                                DEL_PTR(backPoly);
319                                }
320                                break;
321                        case Polygon3::FRONT_SIDE:
322                                cerr << "SplitPolygon: should not come here" << endl;
323                                DEL_PTR(polygon);
324                break;
325                        // polygon is taken as it is
326                        case Polygon3::BACK_SIDE:
327                        case Polygon3::COINCIDENT:
328                        default:
329                                break;
330                }
331        }
332
333        return polygon;
334}
335
336
337void Polyhedron::CollectVertices(VertexArray &vertices) const
338{
339        PolygonContainer::const_iterator it, it_end = mPolygons.end();
340
341        for (it = mPolygons.begin(); it != it_end; ++ it)
342        {
343                Polygon3 *poly = *it;
344
345                VertexArray::const_iterator vit, vit_end = poly->mVertices.end();
346
347                for (vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
348                {
349                        vertices.push_back(*vit);
350                }
351        }
352}
353
354
355}
Note: See TracBrowser for help on using the repository browser.