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

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