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

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