source: trunk/VUT/GtpVisibilityPreprocessor/src/Polygon3.cpp @ 436

Revision 436, 10.2 KB checked in by mattausch, 19 years ago (diff)

bsptree view cells working in VssPreprocessor?

Line 
1#include "Polygon3.h"
2#include "Mesh.h"
3#include "ViewCellBsp.h" // TODO: erase this
4#include "Mesh.h"
5#include "AxisAlignedBox3.h"
6#include "Ray.h"
7
8Polygon3::Polygon3():
9mMaterial(NULL), mParent(NULL), mPiercingRays(0)
10{}
11
12Polygon3::Polygon3(const VertexContainer &vertices):
13mVertices(vertices), mMaterial(NULL), mParent(NULL), mPiercingRays(0)
14{}
15
16Polygon3::Polygon3(MeshInstance *parent):
17mMaterial(NULL), mParent(parent), mPiercingRays(0)
18{}
19
20Polygon3::Polygon3(Face *face, Mesh *parentMesh):
21mMaterial(NULL), mParent(NULL), mPiercingRays(0)
22{       
23        VertexIndexContainer::iterator it = face->mVertexIndices.begin();
24        for (; it != face->mVertexIndices.end();  ++it)
25        {
26                mVertices.push_back(parentMesh->mVertices[*it]);
27                mMaterial = parentMesh->mMaterial;
28        }
29}
30
31Plane3 Polygon3::GetSupportingPlane() const
32{
33        return Plane3(mVertices[0], mVertices[1], mVertices[2]);
34}
35
36Vector3 Polygon3::GetNormal() const
37{
38    return Normalize(CrossProd(mVertices[2] - mVertices[1],
39                                                           mVertices[0] - mVertices[1]));
40}
41
42void Polygon3::Split(const Plane3 &partition,
43                                         Polygon3 &front,
44                                         Polygon3 &back)
45{
46        Vector3 ptA = mVertices.back();
47       
48        int sideA = partition.Side(ptA, Vector3::sDistTolerance);
49       
50        VertexContainer::const_iterator it;
51       
52        Vector3 lastSplit;
53
54        bool foundSplit = false;
55        // find line - plane intersections
56        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
57        {
58                Vector3 ptB = *it;
59                int sideB = partition.Side(ptB, Vector3::sDistTolerance);
60       
61                // vertices on different sides => split
62            if (sideB > 0)
63                {
64                        if (sideA < 0)
65                        {
66                                //-- plane - line intersection
67                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
68                       
69                                // test if split point not too close to previous split point
70                                if (!foundSplit ||
71                                        (SqrDistance(splitPt, lastSplit) > Vector3::sDistToleranceSqrt))
72                                {
73                                        // add vertex to both polygons
74                                        front.mVertices.push_back(splitPt);
75                                        back.mVertices.push_back(splitPt);
76                                       
77                                        lastSplit = splitPt;
78                                        foundSplit = true;
79                                }
80                        }
81                        front.mVertices.push_back(ptB);
82                }
83                else if (sideB < 0)
84                {
85                        if (sideA > 0)
86                        {
87                                //-- plane - line intersection
88                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
89                                // test if split point not too close to other split point
90                                        // test if split point not too close to previous split point
91                                if (!foundSplit ||
92                                        (SqrDistance(splitPt, lastSplit) > Vector3::sDistToleranceSqrt))
93                                {
94                                        // add vertex to both polygons
95                                        front.mVertices.push_back(splitPt);
96                                        back.mVertices.push_back(splitPt);
97
98                                        lastSplit = splitPt;
99                                        foundSplit = true;
100                                }       
101                        }
102                        back.mVertices.push_back(ptB);
103                }
104                else
105                {
106                        // vertex on plane => add vertex to both polygons
107                        front.mVertices.push_back(ptB);
108                        back.mVertices.push_back(ptB);
109                }
110       
111                ptA = ptB;
112                sideA = sideB;
113        }
114}
115
116float Polygon3::GetArea() const
117{
118        Vector3 v = CrossProd(mVertices.back(), mVertices.front());
119   
120    for (int i=0; i < mVertices.size() - 1; ++i)
121                v += CrossProd(mVertices[i], mVertices[i+1]);
122   
123    //Debug << "area2: " << 0.5f * fabs(DotProd(GetNormal(), v)) << endl; 
124        return 0.5f * fabs(DotProd(GetNormal(), v));
125}
126
127int Polygon3::Side(const Plane3 &plane) const
128{
129        int classification = ClassifyPlane(plane);
130       
131        if (classification == BACK_SIDE)
132                return -1;
133        else if (classification == FRONT_SIDE)
134                return 1;
135
136        return 0;
137}
138
139int Polygon3::ClassifyPlane(const Plane3 &plane, const float tolerance) const
140{
141        VertexContainer::const_iterator it;
142
143        bool onFrontSide = false;
144        bool onBackSide = false;
145       
146        int count = 0;
147        // find possible line-plane intersections
148        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
149        {
150                const int side = plane.Side(*it, tolerance);
151               
152                if (side > 0)
153                        onFrontSide = true;
154                else if (side < 0)
155                        onBackSide = true;
156               
157                //TODO: check if split goes through vertex
158                if (onFrontSide && onBackSide) // split
159                {
160                        return SPLIT;
161                }
162                // 3 vertices enough to decide coincident
163                else if (((++ count) >= 3) && !onFrontSide && !onBackSide)
164                {   
165                        return COINCIDENT;
166                }
167        }
168
169        if (onBackSide)
170        {
171                return BACK_SIDE;
172        }
173        else if (onFrontSide)
174        {
175                return FRONT_SIDE;
176        }
177       
178        return COINCIDENT; // plane and polygon are coincident
179}
180
181int Polygon3::ClassifyPlane(const Plane3 &plane) const
182{
183        return ClassifyPlane(plane, Vector3::sDistTolerance);
184}
185
186
187Vector3
188Polygon3::Center() const
189{
190        int i;
191        Vector3 sum = mVertices[0];
192        for (i=1; i < mVertices.size(); i++)
193                sum += mVertices[i];
194       
195        return sum/(float)i;
196}
197
198
199void
200Polygon3::Scale(const float scale)
201{
202        int i;
203        Vector3 center = Center();
204        for (i=0; i < mVertices.size(); i++) {
205                mVertices[i] = center + scale*(mVertices[i] - center);
206        }
207}
208
209bool Polygon3::Valid() const
210{
211        if (mVertices.size() < 3)
212                return false;
213
214#if 1
215        // check if area exceeds certain size
216        if (AREA_LIMIT > GetArea())
217        {
218                //Debug << "area too small: " << GetArea() << endl;
219                return false;
220        }
221#else
222        Vector3 vtx = mVertices.back();
223        VertexContainer::const_iterator it, it_end = mVertices.end();
224
225        for (it = mVertices.begin(); it != it_end; ++it)
226        {
227                if (!(SqrDistance(vtx, *it) > sDistToleranceSqrt))
228                {
229                        Debug << "Malformed vertices:\n" << *this << endl;
230                        return false;
231                }
232                vtx = *it;
233        }
234#endif 
235        return true;
236}
237
238void Polygon3::IncludeInBox(const PolygonContainer &polys, AxisAlignedBox3 &box)
239{
240        PolygonContainer::const_iterator it, it_end = polys.end();
241
242        for (it = polys.begin(); it != it_end; ++ it)
243                box.Include(*(*it));
244}
245
246// int_lineseg returns 1 if the given line segment intersects a 2D
247// ray travelling in the positive X direction.  This is used in the
248// Jordan curve computation for polygon intersection.
249inline int
250int_lineseg(float px,
251            float py,
252            float u1,
253            float v1,
254            float u2,
255            float v2)
256{
257        float t;
258        float ydiff;
259
260        u1 -= px; u2 -= px;       // translate line
261        v1 -= py; v2 -= py;
262
263        if ((v1 > 0 && v2 > 0) ||
264                (v1 < 0 && v2 < 0) ||
265                (u1 < 0 && u2 < 0))
266        return 0;
267
268        if (u1 > 0 && u2 > 0)
269        return 1;
270
271        ydiff = v2 - v1;
272
273        if (fabs(ydiff) < Limits::Small)
274        {         // denominator near 0
275                if (((fabs(v1) > Limits::Small) || (u1 > 0) || (u2 > 0)))
276                        return 0;
277                return 1;
278        }
279
280        t = -v1 / ydiff;                  // Compute parameter
281
282        return (u1 + t * (u2 - u1)) > 0;
283}
284
285int Polygon3::CastRay(const Ray &ray, float &t, const float nearestT)
286{
287        Plane3 plane = GetSupportingPlane();
288        float dot = DotProd(plane.mNormal, ray.GetDir());
289
290        // Watch for near-zero denominator
291        // ONLY single sided polygons!!!!!
292        if (dot > -Limits::Small)
293        //  if (fabs(dot) < Limits::Small)
294        return Ray::NO_INTERSECTION;
295
296        t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
297
298        if (t <= Limits::Small)
299        return Ray::INTERSECTION_OUT_OF_LIMITS;
300
301        if (t >= nearestT) {
302        return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
303        }
304
305        int count = 0;
306        float u, v, u1, v1, u2, v2;
307        int i;
308
309        int paxis = plane.mNormal.DrivingAxis();
310
311        // Project the intersection point onto the coordinate plane
312        // specified by which.
313        ray.Extrap(t).ExtractVerts(&u, &v, paxis);
314
315        int size = (int)mVertices.size();
316
317        mVertices.back().ExtractVerts(&u1, &v1, paxis );
318
319        if (0 && size <= 4)
320        {
321                // assume a convex face
322                for (i = 0; i < size; i++)
323                {
324                mVertices[i].ExtractVerts(&u2, &v2, paxis);
325           
326                        // line u1, v1, u2, v2
327           
328                        if ((v2 - v1)*(u1 - u) > (u2 - u1)*(v1 - v))
329                                return Ray::NO_INTERSECTION;
330
331                        u1 = u2;
332                        v1 = v2;
333        }
334
335        return Ray::INTERSECTION;
336        }
337
338        // We're stuck with the Jordan curve computation.  Count number
339        // of intersections between the line segments the polygon comprises
340        // with a ray originating at the point of intersection and
341        // travelling in the positive X direction.
342        for (i = 0; i < size; i++)
343        {
344                mVertices[i].ExtractVerts(&u2, &v2, paxis);
345
346                count += (int_lineseg(u, v, u1, v1, u2, v2) != 0);
347
348                u1 = u2;
349                v1 = v2;
350        }
351
352        // We hit polygon if number of intersections is odd.
353        return (count & 1) ? Ray::INTERSECTION : Ray::NO_INTERSECTION;
354}
355
356void Polygon3::InheritRays(Polygon3 &front_piece,
357                                               Polygon3 &back_piece) const
358{
359        if (mPiercingRays.empty())
360                return;
361
362        RayContainer::const_iterator it,
363                it_end = mPiercingRays.end();
364
365        for (it = mPiercingRays.begin(); it != it_end; ++ it)
366        {
367                switch((*it)->GetId())
368                {
369                case Ray::BACK:
370                        back_piece.mPiercingRays.push_back(*it);
371                        break;
372                case Ray::FRONT:
373                        front_piece.mPiercingRays.push_back(*it);
374                        break;
375                case Ray::FRONT_BACK:
376                        back_piece.mPiercingRays.push_back(*it);
377                        break;
378                case Ray::BACK_FRONT:
379                        front_piece.mPiercingRays.push_back(*it);
380                        break;
381                default:
382                        break;
383                }
384        }
385}
386
387int Polygon3::ClassifyPlane(const PolygonContainer &polys, const Plane3 &plane)
388{
389        PolygonContainer::const_iterator it;
390
391        bool onFrontSide = false;
392        bool onBackSide = false;
393       
394        // find intersections
395        for (it = polys.begin(); it != polys.end(); ++ it)
396        {
397        const int cf = (*it)->ClassifyPlane(plane);
398               
399        if (cf == FRONT_SIDE)
400                        onFrontSide = true;
401                else if (cf == BACK_SIDE)
402                        onBackSide = true;
403               
404                if ((cf == SPLIT) || (cf == COINCIDENT) || (onFrontSide && onBackSide))
405                {
406                        return SPLIT;
407                }
408        }
409
410        if (onBackSide)
411        {
412                return BACK_SIDE;
413        }
414        else if (onFrontSide)
415        {
416                return FRONT_SIDE;
417        }
418       
419        return SPLIT;
420}
421
422int Polygon3::ParentObjectsSize(const PolygonContainer &polys)
423{
424        int count = 0;
425
426        PolygonContainer::const_iterator it, it_end = polys.end();
427
428        MeshInstance::NewMail();
429
430        for (it = polys.begin(); it != it_end; ++ it)
431        {
432                if ((*it)->mParent && !(*it)->mParent->Mailed())
433                {
434                        ++ count;
435                        (*it)->mParent->Mail();
436                }
437        }
438        return count;
439}
440
441float Polygon3::GetArea(const PolygonContainer &cell)
442{
443        float area = 0;
444        PolygonContainer::const_iterator pit;
445
446        for (pit = cell.begin(); pit != cell.end(); ++ pit)
447                area += (*pit)->GetArea();
448
449        return area;
450}
451
452
453Polygon3 *Polygon3::CreateReversePolygon() const
454{
455        Polygon3 *revPoly = new Polygon3();
456
457        VertexContainer::const_reverse_iterator rit,
458                        rit_end = mVertices.rend();
459
460        for(rit = mVertices.rbegin(); rit != rit_end; ++ rit)
461                revPoly->mVertices.push_back(*rit);
462
463        return revPoly;
464}
Note: See TracBrowser for help on using the repository browser.