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

Revision 329, 8.1 KB checked in by mattausch, 19 years ago (diff)

worked on ray based subdivision

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
8float Polygon3::sSideTolerance = 0.002f;
9float Polygon3::sSideToleranceSqrt = 0.000004f;
10
11Polygon3::Polygon3():
12mMaterial(NULL), mParent(NULL), mPiercingRays(NULL)
13{}
14
15Polygon3::Polygon3(const VertexContainer &vertices):
16mVertices(vertices), mMaterial(NULL), mParent(NULL), mPiercingRays(NULL)
17{}
18
19Polygon3::Polygon3(MeshInstance *parent):
20mMaterial(NULL), mParent(parent), mPiercingRays(NULL)
21{}
22
23Polygon3::Polygon3(Face *face, Mesh *parentMesh):
24mMaterial(NULL), mParent(NULL), mPiercingRays(NULL)
25{       
26        VertexIndexContainer::iterator it = face->mVertexIndices.begin();
27        for (; it != face->mVertexIndices.end();  ++it)
28        {
29                mVertices.push_back(parentMesh->mVertices[*it]);
30                mMaterial = parentMesh->mMaterial;
31        }
32}
33
34Polygon3::~Polygon3()
35{
36        DEL_PTR(mPiercingRays);
37}
38
39Plane3 Polygon3::GetSupportingPlane() const
40{
41        return Plane3(mVertices[0], mVertices[1], mVertices[2]);
42}
43
44Vector3 Polygon3::GetNormal() const
45{
46    return Normalize(CrossProd(mVertices[2] - mVertices[1],
47                                                           mVertices[0] - mVertices[1]));
48}
49
50void Polygon3::Split(const Plane3 &partition,
51                                         Polygon3 &front,
52                                         Polygon3 &back,
53                                         VertexContainer &splitPts)
54{
55        Vector3 ptA = mVertices.back();
56       
57        int sideA = partition.Side(ptA, sSideTolerance);
58       
59        VertexContainer::const_iterator it;
60       
61        bool foundSplit = false;
62        // find line - plane intersections
63        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
64        {
65                Vector3 ptB = *it;
66                int sideB = partition.Side(ptB, sSideTolerance);
67       
68                // vertices on different sides => split
69            if (sideB > 0)
70                {
71                        if (sideA < 0)
72                        {
73                                //-- plane - line intersection
74                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
75                       
76                                // test if split point not too close to previous split point
77                                if (!foundSplit ||
78                                        (SqrDistance(splitPt, splitPts.back()) > sSideToleranceSqrt))
79                                {
80                                        // add vertex to both polygons
81                                        front.mVertices.push_back(splitPt);
82                                        back.mVertices.push_back(splitPt);
83                                       
84                                        splitPts.push_back(splitPt);
85                                        foundSplit = true;
86                                }
87                        }
88                        front.mVertices.push_back(ptB);
89                }
90                else if (sideB < 0)
91                {
92                        if (sideA > 0)
93                        {
94                                //-- plane - line intersection
95                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
96                                // test if split point not too close to other split point
97                                        // test if split point not too close to previous split point
98                                if (!foundSplit ||
99                                        (SqrDistance(splitPt, splitPts.back()) > sSideToleranceSqrt))
100                                {
101                                        // add vertex to both polygons
102                                        front.mVertices.push_back(splitPt);
103                                        back.mVertices.push_back(splitPt);
104
105                                        splitPts.push_back(splitPt);
106                                        foundSplit = true;
107                                }       
108                        }
109                        back.mVertices.push_back(ptB);
110                }
111                else
112                {
113                        // vertex on plane => add vertex to both polygons
114                        front.mVertices.push_back(ptB);
115                        back.mVertices.push_back(ptB);
116                }
117       
118                ptA = ptB;
119                sideA = sideB;
120        }
121}
122
123float Polygon3::GetArea() const
124{
125        Vector3 v = CrossProd(mVertices.back(), mVertices.front());
126   
127    for (int i=0; i < mVertices.size() - 1; ++i)
128                v += CrossProd(mVertices[i], mVertices[i+1]);
129   
130    //Debug << "area2: " << 0.5f * fabs(DotProd(GetNormal(), v)) << endl; 
131        return 0.5f * fabs(DotProd(GetNormal(), v));
132}
133
134int Polygon3::Side(const Plane3 &plane) const
135{
136        int classification = ClassifyPlane(plane);
137       
138        if (classification == Plane3::BACK_SIDE)
139                return -1;
140        else if (classification == Plane3::FRONT_SIDE)
141                return 1;
142
143        return 0;
144}
145
146int Polygon3::ClassifyPlane(const Plane3 &plane) const
147{
148        VertexContainer::const_iterator it;
149
150        bool onFrontSide = false;
151        bool onBackSide = false;
152       
153        int count = 0;
154        // find possible line-plane intersections
155        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
156        {
157                int side = plane.Side(*it, sSideTolerance);
158               
159                if (side > 0)
160                        onFrontSide = true;
161                else if (side < 0)
162                        onBackSide = true;
163               
164                //TODO: check if split goes through vertex
165                if (onFrontSide && onBackSide) // split
166                {
167                        return Plane3::SPLIT;
168                }
169                // 3 vertices enough to decide coincident
170                else if (((++ count) >= 3) && !onFrontSide && !onBackSide)
171                {   
172                        return Plane3::COINCIDENT;
173                }
174        }
175
176        if (onBackSide)
177        {
178                return Plane3::BACK_SIDE;
179        }
180        else if (onFrontSide)
181        {
182                return Plane3::FRONT_SIDE;
183        }
184
185        return Plane3::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        GetPiercingRays()->push_back(ray);
368}
Note: See TracBrowser for help on using the repository browser.