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

Revision 574, 11.6 KB checked in by mattausch, 18 years ago (diff)

finished function for view cell construction
removed bsp rays from vspbspmanager

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