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

Revision 301, 5.3 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 "Intersectable.h"
5#include "AxisAlignedBox3.h"
6
7// tolerance value for side relation
8#define SIDE_TOLERANCE 0.002f // TODO: Test different values
9#define SIDE_TOLERANCE_SQRD 0.000004f
10#define AREA_LIMIT 0.0001f
11
12Polygon3::Polygon3(): mMaterial(NULL), mParent(NULL)
13{}
14
15Polygon3::Polygon3(const VertexContainer &vertices): mVertices(vertices), mMaterial(NULL), mParent(NULL)
16{}
17
18Polygon3::Polygon3(Intersectable *parent): mMaterial(NULL), mParent(parent)
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
41void Polygon3::Split(Plane3 *partition, Polygon3 *front, Polygon3 *back)
42{
43        Vector3 ptA = mVertices.back();
44       
45        int sideA = partition->Side(ptA, SIDE_TOLERANCE);
46       
47        VertexContainer::const_iterator it;
48        bool foundSplit = false;
49
50        Vector3 prevSplitPt(ptA);
51
52        // find line - plane intersections
53        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
54        {
55                Vector3 ptB = *it;
56                int sideB = partition->Side(ptB, SIDE_TOLERANCE);
57       
58                // vertices on different sides => split
59            if (sideB > 0)
60                {
61                        if (sideA < 0)
62                        {
63                                //-- plane - line intersection
64                                Vector3 splitPt = partition->FindIntersection(ptA, ptB);
65                       
66                                if (!foundSplit || (SqrDistance(splitPt, prevSplitPt) > SIDE_TOLERANCE_SQRD))
67                                {
68                                        // add vertex to both polygons
69                                        front->mVertices.push_back(splitPt);
70                                        back->mVertices.push_back(splitPt);
71
72                                        foundSplit = true;
73                                        prevSplitPt = splitPt;
74                                }
75                        }
76                        front->mVertices.push_back(ptB);
77                }
78                else if (sideB < 0)
79                {
80                        if (sideA > 0)
81                        {
82                                //-- plane - line intersection
83                                Vector3 splitPt = partition->FindIntersection(ptA, ptB);
84                       
85                                if (!foundSplit || (SqrDistance(splitPt, prevSplitPt) > SIDE_TOLERANCE_SQRD))
86                                {
87                                        // add vertex to both polygons
88                                        front->mVertices.push_back(splitPt);
89                                        back->mVertices.push_back(splitPt);
90
91                                        foundSplit = true;
92                                        prevSplitPt = splitPt;
93                                }       
94                        }
95                        back->mVertices.push_back(ptB);
96                }
97                else
98                {
99                        // vertex on plane => add vertex to both polygons
100                        front->mVertices.push_back(ptB);
101                        back->mVertices.push_back(ptB);
102                }
103       
104                ptA = ptB;
105                sideA = sideB;
106        }
107}
108
109float Polygon3::GetArea() const
110{
111        VertexContainer vtx;
112
113        //-- rotate polygon to lie in xy plane
114        Vector3 v1 = mVertices[0] - mVertices[1];
115        Vector3 v2 = mVertices[2] - mVertices[1];
116        Vector3 n = Normalize(CrossProd(v2,v1));
117
118        Matrix4x4 rot = GenRotation(v1, v2, n);
119
120        VertexContainer::const_iterator it, it_end = mVertices.end();
121
122        for (it = mVertices.begin(); it != it_end; ++it)
123                vtx.push_back(rot * (*it));
124
125        //-- compute area
126        Vector3 last = vtx.back();
127
128        float area = 0.0f;
129        for (it = vtx.begin(); it != vtx.end(); ++it)
130        {
131                area += last.y * (*it).x - last.x * (*it).y;
132
133                last = *it;
134        }
135        //Debug << "area: " << area * 0.5 << endl;
136        return area * 0.5f;
137}
138
139int Polygon3::Side(const Plane3 &plane) const
140{
141        int classification = ClassifyPlane(plane);
142       
143        if (classification == BACK_SIDE)
144                return -1;
145        else if (classification == FRONT_SIDE)
146                return 1;
147
148        return 0;
149}
150
151int Polygon3::ClassifyPlane(const Plane3 &plane) const
152{
153        VertexContainer::const_iterator it;
154
155        bool onFrontSide = false;
156        bool onBackSide = false;
157       
158        int count = 0;
159        // find possible line-plane intersections
160        for (it = mVertices.begin(); it != mVertices.end(); ++ it)
161        {
162                int side = plane.Side(*it, SIDE_TOLERANCE);
163               
164                if (side > 0)
165                        onFrontSide = true;
166                else if (side < 0)
167                        onBackSide = true;
168               
169                //TODO: check if split goes through vertex
170                if (onFrontSide && onBackSide) // split
171                {
172                        return SPLIT;
173                }
174                // 3 vertices enough to decide coincident
175                else if (((++ count) >= 3) && !onFrontSide && !onBackSide)
176                        return COINCIDENT;
177        }
178
179        if (onBackSide)
180        {
181                return BACK_SIDE;
182        }
183        else if (onFrontSide)
184        {
185                return FRONT_SIDE;
186        }
187
188        return COINCIDENT; // plane and polygon are coincident
189}
190
191
192Vector3
193Polygon3::Center() const
194{
195        int i;
196        Vector3 sum = mVertices[0];
197        for (i=1; i < mVertices.size(); i++)
198                sum += mVertices[i];
199       
200        return sum/(float)i;
201}
202
203
204void
205Polygon3::Scale(const float scale)
206{
207        int i;
208        Vector3 center = Center();
209        for (i=0; i < mVertices.size(); i++) {
210                mVertices[i] = center + scale*(mVertices[i] - center);
211        }
212}
213
214bool Polygon3::Valid() const
215{
216        if (mVertices.size() < 3)
217                return false;
218
219#if 1
220        // check if area exceeds certain size
221        if (AREA_LIMIT > GetArea())
222        {
223                //Debug << "area too small: " << GetArea() << endl;
224                return false;
225        }
226#else
227        Vector3 vtx = mVertices.back();
228        VertexContainer::const_iterator it, it_end = mVertices.end();
229
230        for (it = mVertices.begin(); it != it_end; ++it)
231        {
232                if (!(SqrDistance(vtx, *it) > SIDE_TOLERANCE_SQRD))
233                {
234                        Debug << "Malformed vertices:\n" << *this << endl;
235                        return false;
236                }
237                vtx = *it;
238        }
239#endif 
240        return true;
241}
242
243void Polygon3::IncludeInBox(const PolygonContainer &polys, AxisAlignedBox3 &box)
244{
245        PolygonContainer::const_iterator it, it_end = polys.end();
246
247        for (it = polys.begin(); it != it_end; ++ it)
248                box.Include(*(*it));
249}
Note: See TracBrowser for help on using the repository browser.