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

Revision 683, 11.7 KB checked in by mattausch, 18 years ago (diff)

fixed a bsp node geometry problem (debug code)

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