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

Revision 2912, 6.8 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
85float Polyhedron::GetVolume() const
86{
87        // computes volume by tetrahedralization of the geometry
88        // We just compute the sum of the tetrahedron volumes
89        float volume = 0;
90        const float f = 1.0f / 6.0f;
91
92        PolygonContainer::const_iterator pit, pit_end = mPolygons.end();
93
94        // note: can take arbitrary point, e.g., the origin. However,
95        // we rather take the center of mass to prevents precision errors
96        const Vector3 center = CenterOfMass();
97
98        for (pit = mPolygons.begin(); pit != pit_end; ++ pit)
99        {
100                Polygon3 *poly = *pit;
101                const Vector3 v0 = poly->mVertices[0] - center;
102
103                for (int i = 1; i < (int)poly->mVertices.size() - 1; ++ i)
104                {
105                        const Vector3 v1 = poly->mVertices[i] - center;
106                        const Vector3 v2 = poly->mVertices[i + 1] - center;
107
108                        // more robust version using abs and the center of mass
109                        volume += fabs (f * (DotProd(v0, CrossProd(v1, v2))));
110                }
111        }
112
113        return volume;
114}
115
116
117AxisAlignedBox3 Polyhedron::GetBoundingBox() const
118{
119        return mBox;
120}
121
122
123int Polyhedron::Side(const Plane3 &plane) const
124{
125        int boxSide = mBox.Side(plane);
126        // plane does not intersect bounding box
127        if (boxSide != 0) return boxSide;
128
129        PolygonContainer::const_iterator it, it_end = mPolygons.end();
130
131        int s = 0;
132
133        for (it = mPolygons.begin(); it != it_end; ++ it)
134        {
135        const int side = (*it)->Side(plane, epsilon);
136
137                if (side != 0)
138                {
139                        if (side == -s)
140                                return 0; // sign changed => intersects
141
142                        s = side;
143                }
144        }
145
146        return s;
147}
148
149
150Vector3 Polyhedron::CenterOfMass() const
151{
152        int n = 0;
153
154        Vector3 center(0,0,0);
155
156        PolygonContainer::const_iterator pit, pit_end = mPolygons.end();
157
158        for (pit = mPolygons.begin(); pit != pit_end; ++ pit)
159        {
160                Polygon3 *poly = *pit;
161               
162                VertexArray::const_iterator vit, vit_end = poly->mVertices.end();
163
164                for(vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
165                {
166                        center += *vit;
167                        ++ n;
168                }
169        }
170
171        return center / (float)n;
172}
173
174
175bool Polyhedron::Valid() const
176{
177        // polyhedron is degenerated
178        if (mPolygons.size() < 3)
179                return false;
180        else
181                return true;
182}
183
184
185Polyhedron *Polyhedron::CalcIntersection(const Plane3 &splitPlane) const
186{       
187        // first test plane intersection with geometry
188        const int intersect = Side(splitPlane);
189       
190        if (intersect == 1)
191                // on the other side of the plane, the intersection is empty
192                return NULL;
193        else if (intersect == -1)
194                return NULL;
195                // does not intersect, just return a copy
196                //return new Polyhedron(*this);
197
198
199        //////////
200        //-- finally, create and add new polygon to close polyhedron
201
202        // get cross section of new polygon
203        Polygon3 *planePoly = mBox.CrossSection(splitPlane);
204
205        // create new face: split polygon with all other polygons
206        planePoly = SplitPolygon(planePoly);
207
208        // something is wrong, probably some numerical error: just bail out
209        if (!planePoly)
210        {
211                cerr << "should not happen" << endl;
212                return NULL;//new Polyhedron(*this);
213        }
214
215        Polyhedron *clippedPolyhedron = new Polyhedron();
216
217        // add the new polygon to the polyhedron
218        clippedPolyhedron->Add(planePoly);
219
220
221
222        /////////////
223        //-- plane splits all polygons
224
225        for (int i = 0; i < (int)mPolygons.size(); ++ i)
226        {
227                Polygon3 *poly = mPolygons[i];
228
229                const int cf = mPolygons[i]->ClassifyPlane(splitPlane, epsilon);
230                       
231                switch (cf)
232                {
233                        // split case: split polygon and add it
234                        case Polygon3::SPLIT:
235                                {
236                                        Polygon3 *poly = mPolygons[i];
237
238                                        Polygon3 *frontPoly = new Polygon3();
239                                        Polygon3 *backPoly = new Polygon3();
240                               
241                                        poly->Split(splitPlane, *frontPoly, *backPoly, epsilon);
242
243                                        // we are only interested in the polytope behind the plane
244                                        DEL_PTR(frontPoly);
245
246                                        if (backPoly->Valid(epsilon))
247                                                clippedPolyhedron->Add(backPoly);
248                                        else
249                                                DEL_PTR(backPoly);
250                                }
251                               
252                                break;
253                        case Polygon3::BACK_SIDE:
254                        case Polygon3::COINCIDENT:
255                                clippedPolyhedron->Add(new Polygon3(mPolygons[i]->mVertices));
256                                break;
257                        default:
258                                // polygon is not in intersection
259                                break;
260                }
261        }
262       
263
264        return clippedPolyhedron;
265}
266
267
268Polygon3 *Polyhedron::SplitPolygon(Polygon3 *polygon) const
269{
270        if (!polygon->Valid(epsilon)) DEL_PTR(polygon);
271
272        // polygon is split by all other planes
273        for (size_t i = 0; (i < mPolygons.size()) && polygon; ++ i)
274        {
275                const Plane3 plane = mPolygons[i]->GetSupportingPlane();
276
277                int cf = polygon->ClassifyPlane(plane, epsilon);
278
279                // split new polygon with all previous planes
280                switch (cf)
281                {
282                        case Polygon3::SPLIT:
283                                {
284                                        Polygon3 *frontPoly = new Polygon3();
285                                        Polygon3 *backPoly = new Polygon3();
286
287                                        polygon->Split(plane, *frontPoly, *backPoly, epsilon);
288                                       
289                                        // don't need these anymore
290                                        DEL_PTR(frontPoly);
291                                        DEL_PTR(polygon);
292
293                                        // back polygon belongs to geometry
294                                        if (backPoly->Valid(epsilon))
295                                                polygon = backPoly;
296                                        else
297                                                DEL_PTR(backPoly);
298                                }
299                                break;
300                        case Polygon3::FRONT_SIDE:
301                                cerr << "SplitPolygon: should not come here" << endl;
302                                DEL_PTR(polygon);
303                break;
304                        // polygon is taken as it is
305                        case Polygon3::BACK_SIDE:
306                        case Polygon3::COINCIDENT:
307                        default:
308                                break;
309                }
310        }
311
312        return polygon;
313}
314
315
316void Polyhedron::CollectVertices(VertexArray &vertices) const
317{
318        PolygonContainer::const_iterator it, it_end = mPolygons.end();
319
320        for (it = mPolygons.begin(); it != it_end; ++ it)
321        {
322                Polygon3 *poly = *it;
323
324                VertexArray::const_iterator vit, vit_end = poly->mVertices.end();
325
326                for (vit = poly->mVertices.begin(); vit != vit_end; ++ vit)
327                {
328                        vertices.push_back(*vit);
329                }
330        }
331}
332
333
334}
Note: See TracBrowser for help on using the repository browser.