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

RevLine 
[235]1#include "Polygon3.h"
2#include "Mesh.h"
[268]3#include "ViewCellBsp.h" // TODO: erase this
[308]4#include "Mesh.h"
[295]5#include "AxisAlignedBox3.h"
[314]6#include "Ray.h"
[286]7
[329]8float Polygon3::sSideTolerance = 0.002f;
9float Polygon3::sSideToleranceSqrt = 0.000004f;
10
[319]11Polygon3::Polygon3():
12mMaterial(NULL), mParent(NULL), mPiercingRays(NULL)
[235]13{}
14
[319]15Polygon3::Polygon3(const VertexContainer &vertices):
16mVertices(vertices), mMaterial(NULL), mParent(NULL), mPiercingRays(NULL)
[235]17{}
18
[319]19Polygon3::Polygon3(MeshInstance *parent):
[329]20mMaterial(NULL), mParent(parent), mPiercingRays(NULL)
[312]21{}
22
[329]23Polygon3::Polygon3(Face *face, Mesh *parentMesh):
24mMaterial(NULL), mParent(NULL), mPiercingRays(NULL)
[264]25{       
26        VertexIndexContainer::iterator it = face->mVertexIndices.begin();
27        for (; it != face->mVertexIndices.end();  ++it)
[235]28        {
[286]29                mVertices.push_back(parentMesh->mVertices[*it]);
30                mMaterial = parentMesh->mMaterial;
[235]31        }
32}
33
[319]34Polygon3::~Polygon3()
35{
36        DEL_PTR(mPiercingRays);
37}
38
[238]39Plane3 Polygon3::GetSupportingPlane() const
[235]40{
41        return Plane3(mVertices[0], mVertices[1], mVertices[2]);
42}
43
[306]44Vector3 Polygon3::GetNormal() const
45{
[321]46    return Normalize(CrossProd(mVertices[2] - mVertices[1],
47                                                           mVertices[0] - mVertices[1]));
[306]48}
49
[312]50void Polygon3::Split(const Plane3 &partition,
51                                         Polygon3 &front,
52                                         Polygon3 &back,
53                                         VertexContainer &splitPts)
[235]54{
[289]55        Vector3 ptA = mVertices.back();
[235]56       
[329]57        int sideA = partition.Side(ptA, sSideTolerance);
[235]58       
59        VertexContainer::const_iterator it;
[312]60       
[318]61        bool foundSplit = false;
[235]62        // find line - plane intersections
63        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
64        {
[289]65                Vector3 ptB = *it;
[329]66                int sideB = partition.Side(ptB, sSideTolerance);
[239]67       
[235]68                // vertices on different sides => split
[237]69            if (sideB > 0)
70                {
71                        if (sideA < 0)
72                        {
73                                //-- plane - line intersection
[312]74                                Vector3 splitPt = partition.FindIntersection(ptA, ptB);
[294]75                       
[312]76                                // test if split point not too close to previous split point
[318]77                                if (!foundSplit ||
[329]78                                        (SqrDistance(splitPt, splitPts.back()) > sSideToleranceSqrt))
[289]79                                {
80                                        // add vertex to both polygons
[312]81                                        front.mVertices.push_back(splitPt);
82                                        back.mVertices.push_back(splitPt);
83                                       
84                                        splitPts.push_back(splitPt);
[318]85                                        foundSplit = true;
[289]86                                }
[237]87                        }
[312]88                        front.mVertices.push_back(ptB);
[237]89                }
90                else if (sideB < 0)
91                {
92                        if (sideA > 0)
[235]93                        {
[237]94                                //-- plane - line intersection
[312]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
[318]98                                if (!foundSplit ||
[329]99                                        (SqrDistance(splitPt, splitPts.back()) > sSideToleranceSqrt))
[289]100                                {
101                                        // add vertex to both polygons
[312]102                                        front.mVertices.push_back(splitPt);
103                                        back.mVertices.push_back(splitPt);
[237]104
[312]105                                        splitPts.push_back(splitPt);
[318]106                                        foundSplit = true;
[294]107                                }       
[235]108                        }
[312]109                        back.mVertices.push_back(ptB);
[235]110                }
[237]111                else
[235]112                {
[237]113                        // vertex on plane => add vertex to both polygons
[312]114                        front.mVertices.push_back(ptB);
115                        back.mVertices.push_back(ptB);
[235]116                }
[237]117       
[235]118                ptA = ptB;
119                sideA = sideB;
120        }
121}
122
[298]123float Polygon3::GetArea() const
124{
[306]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));
[298]132}
133
[238]134int Polygon3::Side(const Plane3 &plane) const
[235]135{
[238]136        int classification = ClassifyPlane(plane);
137       
[327]138        if (classification == Plane3::BACK_SIDE)
[238]139                return -1;
[327]140        else if (classification == Plane3::FRONT_SIDE)
[238]141                return 1;
142
143        return 0;
144}
145
146int Polygon3::ClassifyPlane(const Plane3 &plane) const
147{
[235]148        VertexContainer::const_iterator it;
149
150        bool onFrontSide = false;
151        bool onBackSide = false;
[297]152       
[265]153        int count = 0;
[238]154        // find possible line-plane intersections
[235]155        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
156        {
[329]157                int side = plane.Side(*it, sSideTolerance);
[294]158               
[235]159                if (side > 0)
160                        onFrontSide = true;
161                else if (side < 0)
162                        onBackSide = true;
[265]163               
[264]164                //TODO: check if split goes through vertex
165                if (onFrontSide && onBackSide) // split
[235]166                {
[327]167                        return Plane3::SPLIT;
[235]168                }
[265]169                // 3 vertices enough to decide coincident
[321]170                else if (((++ count) >= 3) && !onFrontSide && !onBackSide)
171                {   
[327]172                        return Plane3::COINCIDENT;
[321]173                }
[235]174        }
175
176        if (onBackSide)
177        {
[327]178                return Plane3::BACK_SIDE;
[235]179        }
180        else if (onFrontSide)
181        {
[327]182                return Plane3::FRONT_SIDE;
[235]183        }
[322]184
[327]185        return Plane3::COINCIDENT; // plane and polygon are coincident
[235]186}
187
[256]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       
[289]197        return sum/(float)i;
[256]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}
[289]210
[299]211bool Polygon3::Valid() const
[289]212{
213        if (mVertices.size() < 3)
214                return false;
215
[299]216#if 1
217        // check if area exceeds certain size
218        if (AREA_LIMIT > GetArea())
[301]219        {
220                //Debug << "area too small: " << GetArea() << endl;
[299]221                return false;
[301]222        }
[299]223#else
[289]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        }
[299]236#endif 
[289]237        return true;
238}
[295]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));
[314]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
[319]358RayContainer *Polygon3::GetPiercingRays()
359{
360        if (!mPiercingRays)
361                mPiercingRays = new RayContainer();
362        return mPiercingRays;
363}
364
365void Polygon3::AddPiercingRay(Ray *ray)
366{
[329]367        GetPiercingRays()->push_back(ray);
[319]368}
Note: See TracBrowser for help on using the repository browser.