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

Revision 3021, 8.4 KB checked in by mattausch, 16 years ago (diff)

removed leaks. added class for shaders

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