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

Revision 317, 7.8 KB checked in by mattausch, 19 years ago (diff)
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(): mMaterial(NULL), mParent(NULL)
9{}
10
11Polygon3::Polygon3(const VertexContainer &vertices): mVertices(vertices), mMaterial(NULL), mParent(NULL)
12{}
13
14Polygon3::Polygon3(MeshInstance *parent): mMaterial(NULL), mParent(parent)
15{}
16
17// creates an "infinite" polygon from this plane
18//Polygon3::Polygon3(Plane3 plane)
19//{}
20
21Polygon3::Polygon3(Face *face, Mesh *parentMesh)
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        Vector3 v1 = mVertices[0] - mVertices[1];
34        Vector3 v2 = mVertices[2] - mVertices[1];
35#ifdef _DEBUG
36        Debug << "plane spanned by " <<  v1 << ", " << v2  << endl;
37#endif
38        return Plane3(mVertices[0], mVertices[1], mVertices[2]);
39}
40
41Vector3 Polygon3::GetNormal() const
42{
43    return Normalize(CrossProd(mVertices[0] - mVertices[1],
44                                                           mVertices[2] - mVertices[1]));
45}
46
47void Polygon3::Split(const Plane3 &partition,
48                                         Polygon3 &front,
49                                         Polygon3 &back,
50                                         VertexContainer &splitPts)
51{
52        Vector3 ptA = mVertices.back();
53       
54        int sideA = partition.Side(ptA, SIDE_TOLERANCE);
55       
56        VertexContainer::const_iterator it;
57       
58        // find line - plane intersections
59        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
60        {
61                Vector3 ptB = *it;
62                int sideB = partition.Side(ptB, SIDE_TOLERANCE);
63       
64                // vertices on different sides => split
65            if (sideB > 0)
66                {
67                        if (sideA < 0)
68                        {
69                                //-- plane - line intersection
70                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
71                       
72                                // test if split point not too close to previous split point
73                                if ((splitPts.size() == 0) ||
74                                        (SqrDistance(splitPt, splitPts.back()) > SIDE_TOLERANCE_SQRD))
75                                {
76                                        // add vertex to both polygons
77                                        front.mVertices.push_back(splitPt);
78                                        back.mVertices.push_back(splitPt);
79                                       
80                                        splitPts.push_back(splitPt);
81                                }
82                        }
83                        front.mVertices.push_back(ptB);
84                }
85                else if (sideB < 0)
86                {
87                        if (sideA > 0)
88                        {
89                                //-- plane - line intersection
90                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
91                                // test if split point not too close to other split point
92                                        // test if split point not too close to previous split point
93                                if ((splitPts.size() == 0) ||
94                                        (SqrDistance(splitPt, splitPts.back()) > SIDE_TOLERANCE_SQRD))
95                                {
96                                        // add vertex to both polygons
97                                        front.mVertices.push_back(splitPt);
98                                        back.mVertices.push_back(splitPt);
99
100                                        splitPts.push_back(splitPt);
101                                }       
102                        }
103                        back.mVertices.push_back(ptB);
104                }
105                else
106                {
107                        // vertex on plane => add vertex to both polygons
108                        front.mVertices.push_back(ptB);
109                        back.mVertices.push_back(ptB);
110                }
111       
112                ptA = ptB;
113                sideA = sideB;
114        }
115}
116
117float Polygon3::GetArea() const
118{
119        Vector3 v = CrossProd(mVertices.back(), mVertices.front());
120   
121    for (int i=0; i < mVertices.size() - 1; ++i)
122                v += CrossProd(mVertices[i], mVertices[i+1]);
123   
124    //Debug << "area2: " << 0.5f * fabs(DotProd(GetNormal(), v)) << endl; 
125
126        return 0.5f * fabs(DotProd(GetNormal(), v));
127}
128
129int Polygon3::Side(const Plane3 &plane) const
130{
131        int classification = ClassifyPlane(plane);
132       
133        if (classification == BACK_SIDE)
134                return -1;
135        else if (classification == FRONT_SIDE)
136                return 1;
137
138        return 0;
139}
140
141int Polygon3::ClassifyPlane(const Plane3 &plane) const
142{
143        VertexContainer::const_iterator it;
144
145        bool onFrontSide = false;
146        bool onBackSide = false;
147       
148        int count = 0;
149        // find possible line-plane intersections
150        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
151        {
152                int side = plane.Side(*it, SIDE_TOLERANCE);
153               
154                if (side > 0)
155                        onFrontSide = true;
156                else if (side < 0)
157                        onBackSide = true;
158               
159                //TODO: check if split goes through vertex
160                if (onFrontSide && onBackSide) // split
161                {
162                        return SPLIT;
163                }
164                // 3 vertices enough to decide coincident
165                else if (((++ count) >= 3) && !onFrontSide && !onBackSide)
166                        return COINCIDENT;
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
181
182Vector3
183Polygon3::Center() const
184{
185        int i;
186        Vector3 sum = mVertices[0];
187        for (i=1; i < mVertices.size(); i++)
188                sum += mVertices[i];
189       
190        return sum/(float)i;
191}
192
193
194void
195Polygon3::Scale(const float scale)
196{
197        int i;
198        Vector3 center = Center();
199        for (i=0; i < mVertices.size(); i++) {
200                mVertices[i] = center + scale*(mVertices[i] - center);
201        }
202}
203
204bool Polygon3::Valid() const
205{
206        if (mVertices.size() < 3)
207                return false;
208
209#if 1
210        // check if area exceeds certain size
211        if (AREA_LIMIT > GetArea())
212        {
213                //Debug << "area too small: " << GetArea() << endl;
214                return false;
215        }
216#else
217        Vector3 vtx = mVertices.back();
218        VertexContainer::const_iterator it, it_end = mVertices.end();
219
220        for (it = mVertices.begin(); it != it_end; ++it)
221        {
222                if (!(SqrDistance(vtx, *it) > SIDE_TOLERANCE_SQRD))
223                {
224                        Debug << "Malformed vertices:\n" << *this << endl;
225                        return false;
226                }
227                vtx = *it;
228        }
229#endif 
230        return true;
231}
232
233void Polygon3::IncludeInBox(const PolygonContainer &polys, AxisAlignedBox3 &box)
234{
235        PolygonContainer::const_iterator it, it_end = polys.end();
236
237        for (it = polys.begin(); it != it_end; ++ it)
238                box.Include(*(*it));
239}
240
241// int_lineseg returns 1 if the given line segment intersects a 2D
242// ray travelling in the positive X direction.  This is used in the
243// Jordan curve computation for polygon intersection.
244inline int
245int_lineseg(float px,
246            float py,
247            float u1,
248            float v1,
249            float u2,
250            float v2)
251{
252        float t;
253        float ydiff;
254
255        u1 -= px; u2 -= px;       // translate line
256        v1 -= py; v2 -= py;
257
258        if ((v1 > 0 && v2 > 0) ||
259                (v1 < 0 && v2 < 0) ||
260                (u1 < 0 && u2 < 0))
261        return 0;
262
263        if (u1 > 0 && u2 > 0)
264        return 1;
265
266        ydiff = v2 - v1;
267
268        if (fabs(ydiff) < Limits::Small)
269        {         // denominator near 0
270                if (((fabs(v1) > Limits::Small) || (u1 > 0) || (u2 > 0)))
271                        return 0;
272                return 1;
273        }
274
275        t = -v1 / ydiff;                  // Compute parameter
276
277        return (u1 + t * (u2 - u1)) > 0;
278}
279
280int Polygon3::CastRay(const Ray &ray, float &t, const float nearestT)
281{
282        Plane3 plane = GetSupportingPlane();
283        float dot = DotProd(plane.mNormal, ray.GetDir());
284
285        // Watch for near-zero denominator
286        // ONLY single sided polygons!!!!!
287        if (dot > -Limits::Small)
288        //  if (fabs(dot) < Limits::Small)
289        return Ray::NO_INTERSECTION;
290
291        t = (-plane.mD - DotProd(plane.mNormal, ray.GetLoc())) / dot;
292
293        if (t <= Limits::Small)
294        return Ray::INTERSECTION_OUT_OF_LIMITS;
295
296        if (t >= nearestT) {
297        return Ray::INTERSECTION_OUT_OF_LIMITS; // no intersection was found
298        }
299
300        int count = 0;
301        float u, v, u1, v1, u2, v2;
302        int i;
303
304        int paxis = plane.mNormal.DrivingAxis();
305
306        // Project the intersection point onto the coordinate plane
307        // specified by which.
308        ray.Extrap(t).ExtractVerts(&u, &v, paxis);
309
310        int size = (int)mVertices.size();
311
312        mVertices.back().ExtractVerts(&u1, &v1, paxis );
313
314        if (0 && size <= 4)
315        {
316                // assume a convex face
317                for (i = 0; i < size; i++)
318                {
319                mVertices[i].ExtractVerts(&u2, &v2, paxis);
320           
321                        // line u1, v1, u2, v2
322           
323                        if ((v2 - v1)*(u1 - u) > (u2 - u1)*(v1 - v))
324                                return Ray::NO_INTERSECTION;
325
326                        u1 = u2;
327                        v1 = v2;
328        }
329
330        return Ray::INTERSECTION;
331        }
332
333        // We're stuck with the Jordan curve computation.  Count number
334        // of intersections between the line segments the polygon comprises
335        // with a ray originating at the point of intersection and
336        // travelling in the positive X direction.
337        for (i = 0; i < size; i++)
338        {
339                mVertices[i].ExtractVerts(&u2, &v2, paxis);
340
341                count += (int_lineseg(u, v, u1, v1, u2, v2) != 0);
342
343                u1 = u2;
344                v1 = v2;
345        }
346
347        // We hit polygon if number of intersections is odd.
348        return (count & 1) ? Ray::INTERSECTION : Ray::NO_INTERSECTION;
349}
350
Note: See TracBrowser for help on using the repository browser.