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

Revision 2944, 8.2 KB checked in by mattausch, 16 years ago (diff)

nopt not working yet

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