source: GTP/trunk/Lib/Vis/Preprocessing/src/Polygon3.cpp @ 2053

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