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

Revision 645, 11.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
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 1
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       
237        if (1)
238        {
239                Vector3 vtx = mVertices.back();
240                VertexContainer::const_iterator it, it_end = mVertices.end();
241
242                for (it = mVertices.begin(); it != it_end; ++it)
243                {
244                        if (EpsilonEqualV3(vtx, *it, 0.0001))
245                        {
246                                //Debug << "Malformed vertices:\n" << *this << endl;
247                                return false;
248                        }
249                        vtx = *it;
250                }
251        }
252#endif
253
254        return true;
255}
256
257
258void Polygon3::IncludeInBox(const PolygonContainer &polys, AxisAlignedBox3 &box)
259{
260        PolygonContainer::const_iterator it, it_end = polys.end();
261
262        for (it = polys.begin(); it != it_end; ++ it)
263                box.Include(*(*it));
264}
265
266
267// int_lineseg returns 1 if the given line segment intersects a 2D
268// ray travelling in the positive X direction.  This is used in the
269// Jordan curve computation for polygon intersection.
270inline int
271int_lineseg(float px,
272            float py,
273            float u1,
274            float v1,
275            float u2,
276            float v2)
277{
278        float t;
279        float ydiff;
280
281        u1 -= px; u2 -= px;       // translate line
282        v1 -= py; v2 -= py;
283
284        if ((v1 > 0 && v2 > 0) ||
285                (v1 < 0 && v2 < 0) ||
286                (u1 < 0 && u2 < 0))
287        return 0;
288
289        if (u1 > 0 && u2 > 0)
290        return 1;
291
292        ydiff = v2 - v1;
293
294        if (fabs(ydiff) < Limits::Small)
295        {         // denominator near 0
296                if (((fabs(v1) > Limits::Small) || (u1 > 0) || (u2 > 0)))
297                        return 0;
298                return 1;
299        }
300
301        t = -v1 / ydiff;                  // Compute parameter
302
303        return (u1 + t * (u2 - u1)) > 0;
304}
305
306
307int Polygon3::CastRay(const Ray &ray, float &t, const float nearestT)
308{
309        Plane3 plane = GetSupportingPlane();
310        float dot = DotProd(plane.mNormal, ray.GetDir());
311
312        // Watch for near-zero denominator
313        // ONLY single sided polygons!!!!!
314        if (dot > -Limits::Small)
315        //  if (fabs(dot) < Limits::Small)
316        return Ray::NO_INTERSECTION;
317
318        t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
319
320        if (t <= Limits::Small)
321        return Ray::INTERSECTION_OUT_OF_LIMITS;
322
323        if (t >= nearestT) {
324        return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
325        }
326
327        int count = 0;
328        float u, v, u1, v1, u2, v2;
329        int i;
330
331        int paxis = plane.mNormal.DrivingAxis();
332
333        // Project the intersection point onto the coordinate plane
334        // specified by which.
335        ray.Extrap(t).ExtractVerts(&u, &v, paxis);
336
337        int size = (int)mVertices.size();
338
339        mVertices.back().ExtractVerts(&u1, &v1, paxis );
340
341        if (0 && size <= 4)
342        {
343                // assume a convex face
344                for (i = 0; i < size; i++)
345                {
346                mVertices[i].ExtractVerts(&u2, &v2, paxis);
347           
348                        // line u1, v1, u2, v2
349           
350                        if ((v2 - v1)*(u1 - u) > (u2 - u1)*(v1 - v))
351                                return Ray::NO_INTERSECTION;
352
353                        u1 = u2;
354                        v1 = v2;
355        }
356
357        return Ray::INTERSECTION;
358        }
359
360        // We're stuck with the Jordan curve computation.  Count number
361        // of intersections between the line segments the polygon comprises
362        // with a ray originating at the point of intersection and
363        // travelling in the positive X direction.
364        for (i = 0; i < size; i++)
365        {
366                mVertices[i].ExtractVerts(&u2, &v2, paxis);
367
368                count += (int_lineseg(u, v, u1, v1, u2, v2) != 0);
369
370                u1 = u2;
371                v1 = v2;
372        }
373
374        // We hit polygon if number of intersections is odd.
375        return (count & 1) ? Ray::INTERSECTION : Ray::NO_INTERSECTION;
376}
377
378
379void Polygon3::InheritRays(Polygon3 &front_piece,
380                                               Polygon3 &back_piece) const
381{
382        if (mPiercingRays.empty())
383                return;
384
385        RayContainer::const_iterator it,
386                it_end = mPiercingRays.end();
387
388        for (it = mPiercingRays.begin(); it != it_end; ++ it)
389        {
390                switch((*it)->GetId())
391                {
392                case Ray::BACK:
393                        back_piece.mPiercingRays.push_back(*it);
394                        break;
395                case Ray::FRONT:
396                        front_piece.mPiercingRays.push_back(*it);
397                        break;
398                case Ray::FRONT_BACK:
399                        back_piece.mPiercingRays.push_back(*it);
400                        break;
401                case Ray::BACK_FRONT:
402                        front_piece.mPiercingRays.push_back(*it);
403                        break;
404                default:
405                        break;
406                }
407        }
408}
409
410
411int Polygon3::ClassifyPlane(const PolygonContainer &polys,
412                                                        const Plane3 &plane,
413                                                        const float epsilon)
414{
415        PolygonContainer::const_iterator it;
416
417        bool onFrontSide = false;
418        bool onBackSide = false;
419       
420        // find intersections
421        for (it = polys.begin(); it != polys.end(); ++ it)
422        {
423        const int cf = (*it)->ClassifyPlane(plane, epsilon);
424               
425        if (cf == FRONT_SIDE)
426                        onFrontSide = true;
427                else if (cf == BACK_SIDE)
428                        onBackSide = true;
429               
430                if ((cf == SPLIT) || (cf == COINCIDENT) || (onFrontSide && onBackSide))
431                {
432                        return SPLIT;
433                }
434        }
435
436        if (onBackSide)
437        {
438                return BACK_SIDE;
439        }
440        else if (onFrontSide)
441        {
442                return FRONT_SIDE;
443        }
444       
445        return SPLIT;
446}
447
448
449int Polygon3::ParentObjectsSize(const PolygonContainer &polys)
450{
451        int count = 0;
452
453        PolygonContainer::const_iterator it, it_end = polys.end();
454
455        MeshInstance::NewMail();
456
457        for (it = polys.begin(); it != it_end; ++ it)
458        {
459                if ((*it)->mParent && !(*it)->mParent->Mailed())
460                {
461                        ++ count;
462                        (*it)->mParent->Mail();
463                }
464        }
465        return count;
466}
467
468
469float Polygon3::GetArea(const PolygonContainer &cell)
470{
471        float area = 0;
472        PolygonContainer::const_iterator pit;
473
474        for (pit = cell.begin(); pit != cell.end(); ++ pit)
475        {
476                area += (*pit)->GetArea();
477        }
478
479        return area;
480}
481
482
483Polygon3 *Polygon3::CreateReversePolygon() const
484{
485        Polygon3 *revPoly = new Polygon3();
486
487        VertexContainer::const_reverse_iterator rit,
488                        rit_end = mVertices.rend();
489
490        for(rit = mVertices.rbegin(); rit != rit_end; ++ rit)
491                revPoly->mVertices.push_back(*rit);
492
493        return revPoly;
494}
495
496
497void Polygon3::Triangulate(vector<Triangle3> &triangles)
498{
499        int i = 1;
500        int j = 0;
501        int k = (int)mVertices.size() - 1;
502        int count = 0;
503
504        while (i < k)
505        {
506                triangles.push_back(Triangle3(mVertices[i], mVertices[j], mVertices[k]));
507
508                if ((count ++) % 2)
509                        j = i ++;
510                else
511                        j = k --;
512        }
513}
514
515
516void Polygon3::Triangulate(VertexIndexContainer &indices)
517{
518        int i = 1;
519        int j = 0;
520        int k = (int)mVertices.size() - 1;
521
522        int count = 0;
523
524        while (i < k)
525        {
526                indices.push_back(k);
527                indices.push_back(j);
528                indices.push_back(i);
529
530                if ((count ++) % 2)
531                        j = i ++;
532                else
533                        j = k --;
534        }
535}
536
537
538void Polygon3::AddToMesh(Mesh &mesh)
539{
540        const int n = (int)mesh.mVertices.size();
541
542    //-- add the vertices
543    VertexContainer::const_iterator vit, vit_end = mVertices.end();
544        for (vit = mVertices.begin(); vit != vit_end; ++ vit)
545        {
546                mesh.mVertices.push_back(*vit);
547        }
548
549        // one quad => no triangulation necessary
550        if ((int)mVertices.size() == 4)
551        {
552                mesh.AddFace(new Face(n, n + 1, n + 2, n + 3));
553        }
554        else
555        {
556                VertexIndexContainer indices;
557                Triangulate(indices);
558
559                // add indices of triangle strip
560                for (int i = 0; i < (int)indices.size(); i += 3)
561                {
562                        Face *face = new Face(n + indices[i],
563                                                                  n + indices[i + 1],
564                                                                  n + indices[i + 2]);
565                        mesh.AddFace(face);
566                }
567        }
568}
Note: See TracBrowser for help on using the repository browser.