Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

triangulator.cpp

Go to the documentation of this file.
00001 /*
00002     Sheep - A Rigid Body Dynamics Engine
00003     Copyright (C) 2001-2004 Francois Beaune
00004     Contact: http://toxicengine.sourceforge.net/
00005 
00006     This file is part of Sheep.
00007 
00008     Sheep is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     Sheep is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License
00019     along with Sheep; if not, write to the Free Software
00020     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00023 // Code for the ComputePolygonOrientation2() function comes from:
00024 // http://geometryalgorithms.com/Archive/algorithm_0101/#orientation2D_triangle()
00025 // Copyright 2000, softSurfer (www.softsurfer.com)
00026 // This code may be freely used and modified for any purpose
00027 // providing that this copyright notice is included with it.
00028 // SoftSurfer makes no warranty for this code, and cannot be held
00029 // liable for any real or imagined damage resulting from its use.
00030 // Users of this code must verify correctness for their application.
00031 
00032 // Code for the ComputePolygonArea2() and ComputePolygonNormal3() functions
00033 // comes from a paper entitled "Fast Polygon Area and Newell Normal Computation",
00034 // Daniel Sunday, journal of graphics tools, 7(2):9-13, 2002.
00035 // http://www.acm.org/jgt/papers/Sunday02/FastArea.html
00036 
00037 #include "triangulator.h"   // include first
00038 #include "common/math/build_basis.h"
00039 #include "common/math/point2.h"
00040 #include "common/math/point3.h"
00041 #include "common/math/real.h"
00042 #include "common/math/vector2.h"
00043 #include "common/math/vector3.h"
00044 
00045 #include <cassert>
00046 #include <list>
00047 
00048 using namespace sheep;
00049 using namespace std;
00050 
00051 namespace {
00052     //! Computes the normal to the plane containing the specified 3D triangle.
00053     //! Computed vector *is not* unit length.
00054     Vector3 ComputeTrianglePlane3(const Point3 &v0,
00055                                   const Point3 &v1,
00056                                   const Point3 &v2)
00057     {
00058         const Vector3 e0 = v1 - v0;
00059         const Vector3 e1 = v2 - v0;
00060 
00061         assert(e0.SquareNorm() > 0.0);
00062         assert(e1.SquareNorm() > 0.0);
00063 
00064         return e0 ^ e1;
00065     }
00066 
00067     //! Returns the signed area of a 2D polygon.
00068     Real ComputePolygonArea2(vector<Point2> input) {
00069         const int n = input.size();
00070 
00071         // Duplicate the first two vertices at the end of the input vector.
00072         input.push_back(input[0]);
00073         input.push_back(input[1]);
00074 
00075         Real area = 0.0;
00076 
00077         for(int i = 1, j = 2, k = 0; i <= n; ++i, ++j, ++k) {
00078             area += input[i].m_x * (input[j].m_y - input[k].m_y);
00079         }
00080 
00081         return 0.5 * area;
00082     }
00083 
00084     // Outputs the approximate unit normal of a 3D nearly planar polygon.
00085     // Returns the area of the polygon.
00086     Real ComputePolygonNormal3(vector<Point3> input, Vector3 *normal) {
00087         assert(normal);
00088 
00089         const int n = input.size();
00090 
00091         // Duplicate the first two vertices at the end of the input vector.
00092         input.push_back(input[0]);
00093         input.push_back(input[1]);
00094 
00095         normal->m_x = normal->m_y = normal->m_z = 0.0;
00096 
00097         // Get the Newell normal.
00098         for(int i = 1, j = 2, k = 0; i <= n; ++i, ++j, ++k) {
00099             normal->m_x += input[i].m_y * (input[j].m_z - input[k].m_z);
00100             normal->m_y += input[i].m_z * (input[j].m_x - input[k].m_x);
00101             normal->m_z += input[i].m_x * (input[j].m_y - input[k].m_y);
00102         }
00103 
00104         // Area of polygon = length of Newell normal.
00105         const Real area = normal->Norm();
00106 
00107         // Normalize the polygon normal.
00108         assert(area > 0.0);
00109         *normal /= area;
00110 
00111         return area;
00112     }
00113 
00114     //! Projects an approximatly planar 3D polygon to a plane.
00115     void ProjectPlanarPolygon3(const vector<Point3> &input,
00116                                vector<Point2> *output)
00117     {
00118         assert(input.size() >= 3);
00119         assert(output);
00120 
00121         // Compute normal to the plane containing the polygon.
00122         Vector3 n;
00123         ComputePolygonNormal3(input, &n);
00124 
00125         // Build an orthonormal basis around the normal.
00126         Vector3 u, v;
00127         build_basis(n, &u, &v);
00128 
00129         // Project the 3D polygon to the plane.
00130         for(vector<Point3>::const_iterator i = input.begin(), e = input.end(); i != e; ++i) {
00131             const Point3 &p = *i;
00132             output->push_back(Point2(p * u, p * v));
00133         }
00134 
00135 /*      
00136         assert(input.size() >= 3);
00137         assert(output);
00138 
00139         // Compute normal to the plane containing the polygon.
00140         Vector3 n;
00141         ComputePolygonNormal3(input, &n);
00142 
00143         const Real nx = fabs(n.m_x);
00144         const Real ny = fabs(n.m_y);
00145         const Real nz = fabs(n.m_z);
00146 
00147         enum { X, Y, Z } ignore;
00148 
00149         // Search the largest coordinate (in absolute value) of the normal vector.
00150         if(nx > ny) {
00151             if(nx > nz)
00152                 ignore = X;
00153             else ignore = Z;
00154         } else {
00155             if(ny > nz)
00156                 ignore = Y;
00157             else ignore = Z;
00158         }
00159 
00160         output->reserve(input.size());
00161 
00162         switch(ignore) {
00163         case X:
00164             assert(nx > 0.0);
00165             for(vector<Point3>::const_iterator i = input.begin(), e = input.end(); i != e; ++i)
00166                 output->push_back(Point2(i->m_y, i->m_z));
00167             break;
00168         case Y:
00169             assert(ny > 0.0);
00170             for(vector<Point3>::const_iterator i = input.begin(), e = input.end(); i != e; ++i)
00171                 output->push_back(Point2(i->m_x, i->m_z));
00172             break;
00173         case Z:
00174             assert(nz > 0.0);
00175             for(vector<Point3>::const_iterator i = input.begin(), e = input.end(); i != e; ++i)
00176                 output->push_back(Point2(i->m_x, i->m_y));
00177             break;
00178         }*/
00179     }
00180 
00181     enum Orientation { CCW, CW };
00182 
00183     //! Computes the orientation of a 2D triangle.
00184     Orientation ComputeTriangleOrientation2(const Point2 &v0,
00185                                             const Point2 &v1,
00186                                             const Point2 &v2)
00187     {
00188         const Vector2 v0v1 = v1 - v0;
00189         const Vector2 v0v2 = v2 - v0;
00190         const Real cp = v0v1.m_x * v0v2.m_y - v0v2.m_x * v0v1.m_y;
00191 
00192         // Make sure the triangle is not degenerate.
00193 //      assert(cp != 0.0);
00194 
00195         return cp > 0.0 ? CCW : CW;
00196     }
00197 
00198     //! Computes the orientation of a 2D polygon.
00199     Orientation ComputePolygonOrientation2(const vector<Point2> &vertices) {
00200         assert(vertices.size() >= 3);
00201 
00202         const int n = vertices.size();
00203 
00204         // First find rightmost lowest vertex of the polygon.
00205         int rmin = 0;
00206         Real xmin = vertices[0].m_x;
00207         Real ymin = vertices[0].m_y;
00208 
00209         for(int i = 1; i < n; ++i) {
00210             const Point2 &v = vertices[i];
00211 
00212             if(v.m_y > ymin)
00213                 continue;
00214 
00215             if(v.m_y == ymin) {     // just as low
00216                 if(v.m_x < xmin)    // and to left
00217                     continue;
00218             }
00219 
00220             rmin = i;   // a new rightmost lowest vertex
00221             xmin = v.m_x;
00222             ymin = v.m_y;
00223         }
00224 
00225         if(rmin == 0)
00226             return ComputeTriangleOrientation2(
00227                 vertices[n - 1],
00228                 vertices[0],
00229                 vertices[1]);
00230         else if(rmin == n - 1)
00231             return ComputeTriangleOrientation2(
00232                 vertices[n - 2],
00233                 vertices[n - 1],
00234                 vertices[0]);
00235         else
00236             return ComputeTriangleOrientation2(
00237                 vertices[rmin - 1],
00238                 vertices[rmin],
00239                 vertices[rmin + 1]);
00240     }
00241 
00242     //! Returns true if point 'p' is inside the triangle (v0, v1, v2).
00243     //! Triangle vertices must be given in counter-clockwise order.
00244     bool IsPointInsideTriangle2(const Point2 &v0,
00245                                 const Point2 &v1,
00246                                 const Point2 &v2,
00247                                 const Point2 &p)
00248     {
00249         assert(ComputeTriangleOrientation2(v0, v1, v2) == CCW);
00250 
00251         const Vector2 v0p = p - v0;
00252         const Vector2 v0v1 = v1 - v0;
00253 
00254         if(v0p.m_x * v0v1.m_y - v0v1.m_x * v0p.m_y > 0.0)
00255             return false;
00256 
00257         const Vector2 v1p = p - v1;
00258         const Vector2 v1v2 = v2 - v1;
00259 
00260         if(v1p.m_x * v1v2.m_y - v1v2.m_x * v1p.m_y > 0.0)
00261             return false;
00262 
00263         const Vector2 v2p = p - v2;
00264         const Vector2 v2v0 = v0 - v2;
00265 
00266         if(v2p.m_x * v2v0.m_y - v2v0.m_x * v2p.m_y > 0.0)
00267             return false;
00268 
00269         return true;
00270     }
00271 
00272     bool IsAnEar(const vector<Point2> &vertices,
00273                  const list<int> &active,
00274                  list<int>::const_iterator prev,
00275                  list<int>::const_iterator cur,
00276                  list<int>::const_iterator next)
00277     {
00278         const Point2 &v0 = vertices[*prev];
00279         const Point2 &v1 = vertices[*cur];
00280         const Point2 &v2 = vertices[*next];
00281 
00282         if(ComputeTriangleOrientation2(v0, v1, v2) != CCW)
00283             return false;
00284 
00285         for(list<int>::const_iterator i = active.begin(), e = active.end(); i != e; ++i) {
00286             if(i == prev || i == cur || i == next)
00287                 continue;
00288 
00289             if(IsPointInsideTriangle2(v0, v1, v2, vertices[*i]))
00290                 return false;
00291         }
00292 
00293         return true;
00294     }
00295 
00296     template<typename Iterator> inline
00297     Iterator succ(Iterator i) {
00298         return ++i;
00299     }
00300 }
00301 
00302 bool sheep::TriangulatePolygon3(const vector<Point3> &vertices,
00303                                 vector<int> *triangles)
00304 {
00305     assert(vertices.size() >= 3);
00306     assert(triangles);
00307 
00308     vector<Point2> vertices2;
00309     ProjectPlanarPolygon3(vertices, &vertices2);
00310 
00311     const int n = vertices2.size();
00312 
00313     list<int> active;
00314 
00315     switch(ComputePolygonOrientation2(vertices2)) {
00316     case CCW:
00317         // Keep vertices order.
00318         for(int i = 0; i < n; ++i)
00319             active.push_back(i);
00320         break;
00321     case CW:
00322         // Reverse vertices order.
00323         for(int i = n - 1; i >= 0; --i)
00324             active.push_back(i);
00325         break;
00326     }
00327 
00328     triangles->reserve(3 * (n - 2));
00329 
00330     list<int>::iterator prev = active.begin(), cur = succ(prev), next = succ(cur);
00331     int iter = 0;
00332 
00333     while(active.size() > 2) {
00334         if(IsAnEar(vertices2, active, prev, cur, next)) {
00335             // Create a new triangle.
00336             triangles->push_back(*prev);
00337             triangles->push_back(*cur);
00338             triangles->push_back(*next);
00339 
00340             // Remove the current vertex from the active list and
00341             // update 'cur' iterator.
00342             cur = active.erase(cur);
00343             if(cur == active.end())
00344                 cur = active.begin();
00345 
00346             // Update 'next' iterator.
00347             next = succ(cur);
00348             if(next == active.end())
00349                 next = active.begin();
00350 
00351             // Reset the iteration counter.
00352             iter = 0;
00353         } else {
00354             // Update all three iterators.
00355             prev = cur;
00356             cur = next;
00357             next = succ(next);
00358             if(next == active.end())
00359                 next = active.begin();
00360 
00361             // Update the iteration counter and detect infinite loop.
00362             if(++iter > 2 * n)  // weak
00363                 return false;
00364         }
00365     }
00366 
00367     return true;
00368 }

Generated on Tue May 11 01:31:52 2004 for toxic by doxygen 1.3.6