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

Revision 319, 8.2 KB checked in by mattausch, 19 years ago (diff)

changed the from rays construction (not finished yet)

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