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

Revision 1344, 12.0 KB checked in by mattausch, 18 years ago (diff)

worked on triangle processing. logical units will be created by grouping objects
using their visibility definitions.

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