source: trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp @ 448

Revision 448, 10.3 KB checked in by mattausch, 19 years ago (diff)

fixed bug in VspBspTree?
view cells in VssPreprocessor?
bounding rays for vspkdtree

Line 
1#include "Polygon3.h"
2#include "Mesh.h"
3#include "ViewCellBsp.h" // TODO: erase this
4#include "Mesh.h"
5#include "AxisAlignedBox3.h"
6#include "Ray.h"
7
8Polygon3::Polygon3():
9mMaterial(NULL), mParent(NULL), mPiercingRays(0)
10{}
11
12Polygon3::Polygon3(const VertexContainer &vertices):
13mVertices(vertices), mMaterial(NULL), mParent(NULL), mPiercingRays(0)
14{}
15
16Polygon3::Polygon3(MeshInstance *parent):
17mMaterial(NULL), mParent(parent), mPiercingRays(0)
18{}
19
20Polygon3::Polygon3(Face *face, Mesh *parentMesh):
21mMaterial(NULL), mParent(NULL), mPiercingRays(0)
22{       
23        VertexIndexContainer::iterator it = face->mVertexIndices.begin();
24        for (; it != face->mVertexIndices.end();  ++it)
25        {
26                mVertices.push_back(parentMesh->mVertices[*it]);
27                mMaterial = parentMesh->mMaterial;
28        }
29}
30
31Plane3 Polygon3::GetSupportingPlane() const
32{
33        return Plane3(mVertices[0], mVertices[1], mVertices[2]);
34}
35
36Vector3 Polygon3::GetNormal() const
37{
38    return Normalize(CrossProd(mVertices[2] - mVertices[1],
39                                                           mVertices[0] - mVertices[1]));
40}
41
42void Polygon3::Split(const Plane3 &partition,
43                                         Polygon3 &front,
44                                         Polygon3 &back,
45                                         const float epsilon)
46{
47        Vector3 ptA = mVertices.back();
48       
49        int sideA = partition.Side(ptA, epsilon);
50       
51        VertexContainer::const_iterator it;
52       
53        Vector3 lastSplit;
54
55        bool foundSplit = false;
56
57        //-- find line - plane intersections
58        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
59        {
60                Vector3 ptB = *it;
61                int sideB = partition.Side(ptB, epsilon);
62       
63                // vertices on different sides => split
64            if (sideB > 0)
65                {
66                        if (sideA < 0)
67                        {
68                                //-- plane - line intersection
69                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
70                       
71                                // test if split point not too close to previous split point
72                                if (!foundSplit || (!EpsilonEqualV3(splitPt, lastSplit, epsilon)))
73                                {
74                                        // add vertex to both polygons
75                                        front.mVertices.push_back(splitPt);
76                                        back.mVertices.push_back(splitPt);
77                                       
78                                        lastSplit = splitPt;
79                                        foundSplit = true;
80                                }
81                        }
82                        front.mVertices.push_back(ptB);
83                }
84                else if (sideB < 0)
85                {
86                        if (sideA > 0)
87                        {
88                                //-- plane - line intersection
89                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
90                                // test if split point not too close to other split point
91                                        // test if split point not too close to previous split point
92                                if (!foundSplit || (!EpsilonEqualV3(splitPt, lastSplit, epsilon)))
93                                {
94                                        // add vertex to both polygons
95                                        front.mVertices.push_back(splitPt);
96                                        back.mVertices.push_back(splitPt);
97
98                                        lastSplit = splitPt;
99                                        foundSplit = true;
100                                }       
101                        }
102                        back.mVertices.push_back(ptB);
103                }
104                else
105                {
106                        // vertex on plane => add vertex to both polygons
107                        front.mVertices.push_back(ptB);
108                        back.mVertices.push_back(ptB);
109                }
110       
111                ptA = ptB;
112                sideA = sideB;
113        }
114}
115
116float Polygon3::GetArea() const
117{
118        Vector3 v = CrossProd(mVertices.back(), mVertices.front());
119   
120    for (int i=0; i < mVertices.size() - 1; ++i)
121                v += CrossProd(mVertices[i], mVertices[i+1]);
122   
123    //Debug << "area2: " << 0.5f * fabs(DotProd(GetNormal(), v)) << endl; 
124        return 0.5f * fabs(DotProd(GetNormal(), v));
125}
126
127int Polygon3::Side(const Plane3 &plane,
128                                   const float epsilon) const
129{
130        int classification = ClassifyPlane(plane, epsilon);
131       
132        if (classification == BACK_SIDE)
133                return -1;
134        else if (classification == FRONT_SIDE)
135                return 1;
136
137        return 0;
138}
139
140int Polygon3::ClassifyPlane(const Plane3 &plane,
141                                                        const float epsilon) const
142{
143        VertexContainer::const_iterator it;
144
145        bool onFrontSide = false;
146        bool onBackSide = false;
147       
148        int count = 0;
149        // find possible line-plane intersections
150        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
151        {
152                const int side = plane.Side(*it, epsilon);
153               
154                if (side > 0)
155                        onFrontSide = true;
156                else if (side < 0)
157                        onBackSide = true;
158               
159                //TODO: check if split goes through vertex
160                if (onFrontSide && onBackSide) // split
161                {
162                        return SPLIT;
163                }
164                // 3 vertices enough to decide coincident
165                else if (((++ count) >= 3) && !onFrontSide && !onBackSide)
166                {   
167                        return COINCIDENT;
168                }
169        }
170
171        if (onBackSide)
172        {
173                return BACK_SIDE;
174        }
175        else if (onFrontSide)
176        {
177                return FRONT_SIDE;
178        }
179       
180        return COINCIDENT; // plane and polygon are coincident
181}
182
183/*int Polygon3::ClassifyPlane(const Plane3 &plane) const
184{
185        return ClassifyPlane(plane, Limits::Small);
186}*/
187
188
189Vector3
190Polygon3::Center() const
191{
192        int i;
193        Vector3 sum = mVertices[0];
194        for (i=1; i < mVertices.size(); i++)
195                sum += mVertices[i];
196       
197        return sum/(float)i;
198}
199
200
201void
202Polygon3::Scale(const float scale)
203{
204        int i;
205        Vector3 center = Center();
206        for (i=0; i < mVertices.size(); i++) {
207                mVertices[i] = center + scale*(mVertices[i] - center);
208        }
209}
210
211bool Polygon3::Valid(const float epsilon) const
212{
213        if (mVertices.size() < 3)
214                return false;
215
216#if 1
217        // check if area exceeds certain size
218        if (AREA_LIMIT > GetArea())
219        {
220                //Debug << "area too small: " << GetArea() << endl;
221                return false;
222        }
223#else
224        Vector3 vtx = mVertices.back();
225        VertexContainer::const_iterator it, it_end = mVertices.end();
226
227        for (it = mVertices.begin(); it != it_end; ++it)
228        {
229                if (!(EpsilonEqual(vtx, *it)))
230                {
231                        //Debug << "Malformed vertices:\n" << *this << endl;
232                        return false;
233                }
234                vtx = *it;
235        }
236#endif 
237        return true;
238}
239
240void Polygon3::IncludeInBox(const PolygonContainer &polys, AxisAlignedBox3 &box)
241{
242        PolygonContainer::const_iterator it, it_end = polys.end();
243
244        for (it = polys.begin(); it != it_end; ++ it)
245                box.Include(*(*it));
246}
247
248// int_lineseg returns 1 if the given line segment intersects a 2D
249// ray travelling in the positive X direction.  This is used in the
250// Jordan curve computation for polygon intersection.
251inline int
252int_lineseg(float px,
253            float py,
254            float u1,
255            float v1,
256            float u2,
257            float v2)
258{
259        float t;
260        float ydiff;
261
262        u1 -= px; u2 -= px;       // translate line
263        v1 -= py; v2 -= py;
264
265        if ((v1 > 0 && v2 > 0) ||
266                (v1 < 0 && v2 < 0) ||
267                (u1 < 0 && u2 < 0))
268        return 0;
269
270        if (u1 > 0 && u2 > 0)
271        return 1;
272
273        ydiff = v2 - v1;
274
275        if (fabs(ydiff) < Limits::Small)
276        {         // denominator near 0
277                if (((fabs(v1) > Limits::Small) || (u1 > 0) || (u2 > 0)))
278                        return 0;
279                return 1;
280        }
281
282        t = -v1 / ydiff;                  // Compute parameter
283
284        return (u1 + t * (u2 - u1)) > 0;
285}
286
287int Polygon3::CastRay(const Ray &ray, float &t, const float nearestT)
288{
289        Plane3 plane = GetSupportingPlane();
290        float dot = DotProd(plane.mNormal, ray.GetDir());
291
292        // Watch for near-zero denominator
293        // ONLY single sided polygons!!!!!
294        if (dot > -Limits::Small)
295        //  if (fabs(dot) < Limits::Small)
296        return Ray::NO_INTERSECTION;
297
298        t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
299
300        if (t <= Limits::Small)
301        return Ray::INTERSECTION_OUT_OF_LIMITS;
302
303        if (t >= nearestT) {
304        return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
305        }
306
307        int count = 0;
308        float u, v, u1, v1, u2, v2;
309        int i;
310
311        int paxis = plane.mNormal.DrivingAxis();
312
313        // Project the intersection point onto the coordinate plane
314        // specified by which.
315        ray.Extrap(t).ExtractVerts(&u, &v, paxis);
316
317        int size = (int)mVertices.size();
318
319        mVertices.back().ExtractVerts(&u1, &v1, paxis );
320
321        if (0 && size <= 4)
322        {
323                // assume a convex face
324                for (i = 0; i < size; i++)
325                {
326                mVertices[i].ExtractVerts(&u2, &v2, paxis);
327           
328                        // line u1, v1, u2, v2
329           
330                        if ((v2 - v1)*(u1 - u) > (u2 - u1)*(v1 - v))
331                                return Ray::NO_INTERSECTION;
332
333                        u1 = u2;
334                        v1 = v2;
335        }
336
337        return Ray::INTERSECTION;
338        }
339
340        // We're stuck with the Jordan curve computation.  Count number
341        // of intersections between the line segments the polygon comprises
342        // with a ray originating at the point of intersection and
343        // travelling in the positive X direction.
344        for (i = 0; i < size; i++)
345        {
346                mVertices[i].ExtractVerts(&u2, &v2, paxis);
347
348                count += (int_lineseg(u, v, u1, v1, u2, v2) != 0);
349
350                u1 = u2;
351                v1 = v2;
352        }
353
354        // We hit polygon if number of intersections is odd.
355        return (count & 1) ? Ray::INTERSECTION : Ray::NO_INTERSECTION;
356}
357
358void Polygon3::InheritRays(Polygon3 &front_piece,
359                                               Polygon3 &back_piece) const
360{
361        if (mPiercingRays.empty())
362                return;
363
364        RayContainer::const_iterator it,
365                it_end = mPiercingRays.end();
366
367        for (it = mPiercingRays.begin(); it != it_end; ++ it)
368        {
369                switch((*it)->GetId())
370                {
371                case Ray::BACK:
372                        back_piece.mPiercingRays.push_back(*it);
373                        break;
374                case Ray::FRONT:
375                        front_piece.mPiercingRays.push_back(*it);
376                        break;
377                case Ray::FRONT_BACK:
378                        back_piece.mPiercingRays.push_back(*it);
379                        break;
380                case Ray::BACK_FRONT:
381                        front_piece.mPiercingRays.push_back(*it);
382                        break;
383                default:
384                        break;
385                }
386        }
387}
388
389int Polygon3::ClassifyPlane(const PolygonContainer &polys,
390                                                        const Plane3 &plane,
391                                                        const float epsilon)
392{
393        PolygonContainer::const_iterator it;
394
395        bool onFrontSide = false;
396        bool onBackSide = false;
397       
398        // find intersections
399        for (it = polys.begin(); it != polys.end(); ++ it)
400        {
401        const int cf = (*it)->ClassifyPlane(plane, epsilon);
402               
403        if (cf == FRONT_SIDE)
404                        onFrontSide = true;
405                else if (cf == BACK_SIDE)
406                        onBackSide = true;
407               
408                if ((cf == SPLIT) || (cf == COINCIDENT) || (onFrontSide && onBackSide))
409                {
410                        return SPLIT;
411                }
412        }
413
414        if (onBackSide)
415        {
416                return BACK_SIDE;
417        }
418        else if (onFrontSide)
419        {
420                return FRONT_SIDE;
421        }
422       
423        return SPLIT;
424}
425
426int Polygon3::ParentObjectsSize(const PolygonContainer &polys)
427{
428        int count = 0;
429
430        PolygonContainer::const_iterator it, it_end = polys.end();
431
432        MeshInstance::NewMail();
433
434        for (it = polys.begin(); it != it_end; ++ it)
435        {
436                if ((*it)->mParent && !(*it)->mParent->Mailed())
437                {
438                        ++ count;
439                        (*it)->mParent->Mail();
440                }
441        }
442        return count;
443}
444
445float Polygon3::GetArea(const PolygonContainer &cell)
446{
447        float area = 0;
448        PolygonContainer::const_iterator pit;
449
450        for (pit = cell.begin(); pit != cell.end(); ++ pit)
451        {
452                if ((*pit)->mVertices.size() < 3)
453                        Debug << "ERROR" << endl;
454
455                area += (*pit)->GetArea();
456        }
457
458        return area;
459}
460
461
462Polygon3 *Polygon3::CreateReversePolygon() const
463{
464        Polygon3 *revPoly = new Polygon3();
465
466        VertexContainer::const_reverse_iterator rit,
467                        rit_end = mVertices.rend();
468
469        for(rit = mVertices.rbegin(); rit != rit_end; ++ rit)
470                revPoly->mVertices.push_back(*rit);
471
472        return revPoly;
473}
Note: See TracBrowser for help on using the repository browser.