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

Revision 2053, 12.6 KB checked in by mattausch, 18 years ago (diff)
RevLine 
[235]1#include "Polygon3.h"
2#include "Mesh.h"
[372]3#include "AxisAlignedBox3.h"
4#include "Ray.h"
[503]5#include "Triangle3.h"
[372]6
[860]7
[863]8namespace GtpVisibilityPreprocessor {
[860]9
10
[372]11Polygon3::Polygon3():
[1344]12mMaterial(NULL),
13mParent(NULL),
14mPiercingRays(0)
[1076]15, mPlane(NULL)
[574]16{
17}
[372]18
19Polygon3::Polygon3(const VertexContainer &vertices):
[1344]20mMaterial(NULL),
21mParent(NULL),
22mPiercingRays(0)
[1076]23, mPlane(NULL)
[574]24{
25        mVertices.reserve(vertices.size());
26        mVertices = vertices;
27}
[372]28
[574]29
[372]30Polygon3::Polygon3(MeshInstance *parent):
[1344]31mMaterial(NULL),
32mParent(parent),
33mPiercingRays(0)
[1076]34, mPlane(NULL)
[372]35{}
36
[574]37
[372]38Polygon3::Polygon3(Face *face, Mesh *parentMesh):
[1344]39mMaterial(NULL),
40mParent(NULL),
41mPiercingRays(0),
42mPlane(NULL)
[372]43{       
[574]44        mVertices.reserve(face->mVertexIndices.size());
[1344]45        VertexIndexContainer::iterator it, it_end = face->mVertexIndices.end();
46
[1420]47        for (it = face->mVertexIndices.begin(); it != it_end; ++ it)
[372]48        {
49                mVertices.push_back(parentMesh->mVertices[*it]);
50        }
[574]51
52        mMaterial = parentMesh->mMaterial;
[372]53}
54
[574]55
[1404]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
[1076]70Plane3 Polygon3::GetSupportingPlane()// const
[372]71{
[1076]72#if 0
[372]73        return Plane3(mVertices[0], mVertices[1], mVertices[2]);
[1076]74#else
75        if (!mPlane)
[1344]76        {
[1076]77                mPlane = new Plane3(mVertices[0], mVertices[1], mVertices[2]);
[1344]78        }
79
[1076]80        return *mPlane;
81#endif
[372]82}
83
[574]84
[306]85Vector3 Polygon3::GetNormal() const
86{
[321]87    return Normalize(CrossProd(mVertices[2] - mVertices[1],
88                                                           mVertices[0] - mVertices[1]));
[372]89}
90
[1344]91
[372]92void Polygon3::Split(const Plane3 &partition,
93                                         Polygon3 &front,
[448]94                                         Polygon3 &back,
95                                         const float epsilon)
[372]96{
97        Vector3 ptA = mVertices.back();
[448]98        int sideA = partition.Side(ptA, epsilon);
[372]99        bool foundSplit = false;
[1344]100    Vector3 lastSplit;
101               
[2053]102        /////////////
[1344]103        //-- find line - plane intersections
[448]104
[1344]105        VertexContainer::const_iterator it, it_end = mVertices.end();
106
107        for (it = mVertices.begin(); it != it_end; ++ it)
[372]108        {
109                Vector3 ptB = *it;
[448]110                int sideB = partition.Side(ptB, epsilon);
[372]111       
112                // vertices on different sides => split
[237]113            if (sideB > 0)
114                {
115                        if (sideA < 0)
[372]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
[448]121                                if (!foundSplit || (!EpsilonEqualV3(splitPt, lastSplit, epsilon)))
[372]122                                {
123                                        // add vertex to both polygons
124                                        front.mVertices.push_back(splitPt);
125                                        back.mVertices.push_back(splitPt);
126                                       
[436]127                                        lastSplit = splitPt;
[372]128                                        foundSplit = true;
129                                }
130                        }
131                        front.mVertices.push_back(ptB);
132                }
[237]133                else if (sideB < 0)
134                {
135                        if (sideA > 0)
[372]136                        {
[2053]137                                ////////////
[372]138                                //-- plane - line intersection
[2053]139
[372]140                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
[2053]141                               
142                                // test if split point not too close to previous split point
[448]143                                if (!foundSplit || (!EpsilonEqualV3(splitPt, lastSplit, epsilon)))
[372]144                                {
145                                        // add vertex to both polygons
146                                        front.mVertices.push_back(splitPt);
147                                        back.mVertices.push_back(splitPt);
148
[436]149                                        lastSplit = splitPt;
[372]150                                        foundSplit = true;
151                                }       
152                        }
[2053]153
[372]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
[574]168
[372]169float Polygon3::GetArea() const
170{
[306]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   
[544]176    return 0.5f * fabs(DotProd(GetNormal(), v));
[372]177}
[235]178
[574]179
[448]180int Polygon3::Side(const Plane3 &plane,
181                                   const float epsilon) const
[372]182{
[448]183        int classification = ClassifyPlane(plane, epsilon);
[372]184       
185        if (classification == BACK_SIDE)
186                return -1;
187        else if (classification == FRONT_SIDE)
188                return 1;
[538]189        // plane splits polygon
[372]190        return 0;
191}
192
[574]193
[448]194int Polygon3::ClassifyPlane(const Plane3 &plane,
195                                                        const float epsilon) const
[372]196{
[574]197        VertexContainer::const_iterator it, it_end = mVertices.end();
[372]198
199        bool onFrontSide = false;
200        bool onBackSide = false;
201       
202        int count = 0;
203        // find possible line-plane intersections
[574]204        for (it = mVertices.begin(); it != it_end; ++ it)
[372]205        {
[448]206                const int side = plane.Side(*it, epsilon);
[372]207               
208                if (side > 0)
[683]209                {
[372]210                        onFrontSide = true;
[683]211                }
[372]212                else if (side < 0)
[683]213                {
[372]214                        onBackSide = true;
[683]215                }
216
[372]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       
[2053]250        return sum / (float)i;
[372]251}
252
253
254void
255Polygon3::Scale(const float scale)
256{
257        int i;
258        Vector3 center = Center();
[2053]259       
260        for (i=0; i < mVertices.size(); i++)
261        {
262                mVertices[i] = center + scale * (mVertices[i] - center);
[372]263        }
264}
265
[1420]266
[448]267bool Polygon3::Valid(const float epsilon) const
[372]268{
[1571]269        if ((int)mVertices.size() < 3)
[372]270                return false;
271
[1420]272        // matt: removed for performance issues
273#if _DEBUG
274        if (0)
[372]275        {
[574]276                // check if area exceeds certain size
277                if (GetArea() < AREA_LIMIT)
278                {
279                        Debug << "area too small: " << GetArea() << endl;
280                        return false;
281                }
[372]282        }
[645]283       
284        if (1)
[574]285        {
286                Vector3 vtx = mVertices.back();
287                VertexContainer::const_iterator it, it_end = mVertices.end();
[372]288
[574]289                for (it = mVertices.begin(); it != it_end; ++it)
[372]290                {
[1420]291                        if (EpsilonEqualV3(vtx, *it, epsilon))
[574]292                        {
[1420]293                                //cout << "Malformed vertices:\n" << *this << endl;
[574]294                                return false;
295                        }
296                        vtx = *it;
[372]297                }
298        }
[574]299#endif
300
[372]301        return true;
302}
303
[574]304
[314]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
[574]344
[314]345int Polygon3::CastRay(const Ray &ray, float &t, const float nearestT)
346{
[1328]347        const Plane3 plane = GetSupportingPlane();
348        const float dot = DotProd(plane.mNormal, ray.GetDir());
[314]349
350        // Watch for near-zero denominator
351        // ONLY single sided polygons!!!!!
352        if (dot > -Limits::Small)
[1328]353        {
354                //  if (fabs(dot) < Limits::Small)
355                return Ray::NO_INTERSECTION;
356        }
[314]357
358        t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
359
360        if (t <= Limits::Small)
[1328]361        {
362                return Ray::INTERSECTION_OUT_OF_LIMITS;
363        }
[314]364
[1328]365        if (t >= nearestT)
366        {
367                return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
[314]368        }
369
370        int count = 0;
371        float u, v, u1, v1, u2, v2;
372        int i;
373
[1328]374        const int paxis = plane.mNormal.DrivingAxis();
[314]375
376        // Project the intersection point onto the coordinate plane
377        // specified by which.
378        ray.Extrap(t).ExtractVerts(&u, &v, paxis);
379
[1328]380        const int size = (int)mVertices.size();
[314]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);
[1328]390           
[314]391                        // line u1, v1, u2, v2
[1328]392                        if ((v2 - v1) * (u1 - u) > (u2 - u1)*(v1 - v))
[314]393                                return Ray::NO_INTERSECTION;
394
395                        u1 = u2;
396                        v1 = v2;
[1328]397                }
398               
399                return Ray::INTERSECTION;
[314]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
[574]420
[372]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
[574]452
[448]453int Polygon3::ClassifyPlane(const PolygonContainer &polys,
454                                                        const Plane3 &plane,
455                                                        const float epsilon)
[372]456{
[683]457        bool onFrontSide = false;
458        bool onBackSide = false;
[372]459        PolygonContainer::const_iterator it;
460
461        // find intersections
462        for (it = polys.begin(); it != polys.end(); ++ it)
463        {
[448]464        const int cf = (*it)->ClassifyPlane(plane, epsilon);
[372]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
[574]489
[375]490int Polygon3::ParentObjectsSize(const PolygonContainer &polys)
[372]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;
[384]507}
508
[574]509
[384]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)
[448]516        {
[384]517                area += (*pit)->GetArea();
[448]518        }
[396]519
[384]520        return area;
[396]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)
[448]532                revPoly->mVertices.push_back(*rit);
533
534        return revPoly;
[503]535}
536
537
[840]538void Polygon3::Triangulate(vector<Triangle3> &triangles) const
[503]539{
540        int i = 1;
541        int j = 0;
[508]542        int k = (int)mVertices.size() - 1;
[503]543        int count = 0;
544
545        while (i < k)
546        {
[1418]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]));
[503]551
552                if ((count ++) % 2)
553                        j = i ++;
554                else
555                        j = k --;
556        }
557}
[508]558
559
[840]560void Polygon3::Triangulate(VertexIndexContainer &indices) const
[508]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)
[1328]575                {
[508]576                        j = i ++;
[1328]577                }
[508]578                else
[1328]579                {
[508]580                        j = k --;
[1328]581                }
[508]582        }
583}
584
585
[840]586void IncludePolyInMesh(const Polygon3 &poly, Mesh &mesh)
[508]587{
588        const int n = (int)mesh.mVertices.size();
589
[1420]590
[1419]591        /////////////
592    //-- add the vertices to the mesh
593
[840]594    VertexContainer::const_iterator vit, vit_end = poly.mVertices.end();
595        for (vit = poly.mVertices.begin(); vit != vit_end; ++ vit)
[508]596        {
597                mesh.mVertices.push_back(*vit);
598        }
599
600        // one quad => no triangulation necessary
[840]601        if (poly.mVertices.size() == 4)
[508]602        {
603                mesh.AddFace(new Face(n, n + 1, n + 2, n + 3));
[840]604                return;
[508]605        }
[840]606       
607        VertexIndexContainer indices;
608        poly.Triangulate(indices);
[508]609
[1420]610        //if (indices.size() < 3) return; // something is wrong
611       
[840]612        // add indices of triangle strip
[1420]613        for (int i = 0; i < (int)indices.size(); i += 3)
[840]614        {
[1420]615                Face *face = new Face(indices[i] + n,
616                                                          indices[i + 1] + n,
617                                                          indices[i + 2] + n);
[840]618                mesh.AddFace(face);
[508]619        }
[860]620}
621
[1328]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
[508]639}
Note: See TracBrowser for help on using the repository browser.