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

Revision 1404, 12.3 KB checked in by mattausch, 18 years ago (diff)

debugging after merge

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