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

Revision 360, 9.0 KB checked in by mattausch, 19 years ago (diff)

added findneighbours method

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