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

Revision 3214, 8.3 KB checked in by mattausch, 16 years ago (diff)

worked on lense flare

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               
245                if (dist > 0) return false;
246        }
247        return true;
248}
249
250
251Polyhedron *Polyhedron::CalcIntersection(const Plane3 &splitPlane) const
252{       
253        // first test plane intersection with geometry
254        const int intersect = Side(splitPlane);
255       
256        if (intersect == 1)
257        {
258                // on the other side of the plane, the intersection is empty
259                return NULL;
260        }
261        else if (intersect == -1)
262        {
263                // does not intersect, just return a copy
264                return new Polyhedron(*this);
265        }
266
267        // polyhedron is intersected: create new polyhedron
268        Polyhedron *clippedPolyhedron = new Polyhedron();
269
270
271        //////////
272        //-- create and add new polygon to close polyhedron
273
274        // get cross section of new polygon
275        Polygon3 *planePoly = mBox.CrossSection(splitPlane);
276
277        // create new face: split polygon with all other polygons
278        planePoly = SplitPolygon(planePoly);
279
280        if (planePoly)
281        {
282                // we can now savely add the new polygon
283                clippedPolyhedron->Add(planePoly);
284        }
285        else if (0)
286        {
287                // something is wrong, probably some numerical error
288                cerr << "no polygon: should not happen" << endl;
289                return new Polyhedron(*this);
290        }
291       
292
293        /////////////
294        //-- clip polyhedron: plane splits all polygons
295
296        for (size_t i = 0; i < mPolygons.size(); ++ i)
297        {
298                Polygon3 *poly = mPolygons[i];
299
300                const int cf = mPolygons[i]->ClassifyPlane(splitPlane, epsilon);
301                       
302                switch (cf)
303                {
304                        // split case: split polygon and add it
305                        case Polygon3::SPLIT:
306                                {
307                                        Polygon3 *poly = mPolygons[i];
308
309                                        Polygon3 *frontPoly = new Polygon3();
310                                        Polygon3 *backPoly = new Polygon3();
311                               
312                                        poly->Split(splitPlane, *frontPoly, *backPoly, epsilon);
313
314                                        // we are only interested in the polytope behind the plane
315                                        DEL_PTR(frontPoly);
316
317                                        if (backPoly->Valid(epsilon))
318                                                clippedPolyhedron->Add(backPoly);
319                                        else
320                                                DEL_PTR(backPoly);
321                                }
322                               
323                                break;
324                        case Polygon3::BACK_SIDE:
325                        case Polygon3::COINCIDENT:
326                                clippedPolyhedron->Add(new Polygon3(mPolygons[i]->mVertices));
327                                break;
328                        default:
329                                // polygon is not in intersection
330                                break;
331                }
332        }
333
334        return clippedPolyhedron;
335}
336
337
338Polygon3 *Polyhedron::SplitPolygon(Polygon3 *polygon) const
339{
340        if (!polygon->Valid(epsilon)) DEL_PTR(polygon);
341
342        // polygon is split by all other planes
343        for (size_t i = 0; (i < mPolygons.size()) && polygon; ++ i)
344        {
345                const Plane3 plane = mPolygons[i]->GetSupportingPlane();
346
347                int cf = polygon->ClassifyPlane(plane, epsilon);
348
349                // split new polygon with all previous planes
350                switch (cf)
351                {
352                        case Polygon3::SPLIT:
353                                {
354                                        Polygon3 *frontPoly = new Polygon3();
355                                        Polygon3 *backPoly = new Polygon3();
356
357                                        polygon->Split(plane, *frontPoly, *backPoly, epsilon);
358                                       
359                                        // don't need these anymore
360                                        DEL_PTR(frontPoly);
361                                        DEL_PTR(polygon);
362
363                                        // back polygon belongs to geometry
364                                        if (backPoly->Valid(epsilon))
365                                                polygon = backPoly;
366                                        else
367                                                DEL_PTR(backPoly);
368                                }
369                                break;
370                        case Polygon3::FRONT_SIDE:
371                                //cerr << "SplitPolygon: should not come here" << endl;
372                                DEL_PTR(polygon);
373                break;
374                        // polygon is taken as it is
375                        case Polygon3::BACK_SIDE:
376                        case Polygon3::COINCIDENT:
377                        default:
378                                break;
379                }
380        }
381
382        return polygon;
383}
384
385
386void Polyhedron::CollectVertices(VertexArray &vertices) const
387{
388        PolygonContainer::const_iterator it, it_end = mPolygons.end();
389
390        for (it = mPolygons.begin(); it != it_end; ++ it)
391        {
392                Polygon3 *poly = *it;
393
394                VertexArray::const_iterator vit, vit_end = poly->mVertices.end();
395
396                for (vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
397                {
398                        vertices.push_back(*vit);
399                }
400        }
401}
402
403
404}
Note: See TracBrowser for help on using the repository browser.