polygon_mesher.C

00001 /*
00002  * This file is part of the "Archon" framework.
00003  * (http://files3d.sourceforge.net)
00004  *
00005  * Copyright © 2002 by Kristian Spangsege and Brian Kristiansen.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and
00008  * its documentation under the terms of the GNU General Public License is
00009  * hereby granted. No representations are made about the suitability of
00010  * this software for any purpose. It is provided "as is" without express
00011  * or implied warranty. See the GNU General Public License
00012  * (http://www.gnu.org/copyleft/gpl.html) for more details.
00013  *
00014  * The characters in this file are ISO8859-1 encoded.
00015  *
00016  * The documentation in this file is in "Doxygen" style
00017  * (http://www.doxygen.org).
00018  */
00019 
00020 #include <cmath>
00021 #include <limits>
00022 #include <algorithm>
00023 
00024 #include <archon/math/matrix.H>
00025 #include <archon/math/functions.H>
00026 
00027 #include <archon/util/polygon_mesher.H>
00028 
00029 namespace Archon
00030 {
00031   namespace Utilities
00032   {
00033     using namespace std;
00034     using namespace Math;
00035 
00036     namespace
00037     {
00038       struct PolygonException: MesherException
00039       {
00040         PolygonException(string l, string m): Utilities::Exception(l, m) {}
00041       };
00042 
00043       struct Vertex
00044       {
00045         Vector2 p;
00046         int i;
00047         Vertex() {}
00048         Vertex(const Vector2 &p, int i): p(p), i(i) {}
00049       };
00050 
00051       void splitX(const vector<Vertex> &polygon, double clip,
00052                   const Matrix3x3 &m, MesherContext *context,
00053                   vector<Vertex> &below, vector<Vertex> &above,
00054                   Vertex &reuseVertex, bool &reuse, double z)
00055       {
00056         Vertex rv = reuseVertex, v = polygon[polygon.size()-1];
00057         bool r = reuse;
00058         reuse = false;
00059         for(unsigned i=0; i<polygon.size(); ++i)
00060         {
00061           Vertex w = polygon[i];
00062           if(w.p[0] >= clip)
00063           {
00064             if(v.p[0] >= clip) above.push_back(w);
00065             else
00066             {
00067               if(!r)
00068               {
00069                 Vector2 s(clip, linInterp(clip, v.p[0], w.p[0], v.p[1], w.p[1]));
00070                 rv = Vertex(s, context->addVertex(m * Vector3(s[0], s[1], z)));
00071               }
00072               above.push_back(rv);
00073               above.push_back(w);
00074               below.push_back(rv);
00075             }
00076           }
00077           else
00078           {
00079             if(v.p[0] >= clip)
00080             {
00081               Vector2 s(clip, linInterp(clip, v.p[0], w.p[0], v.p[1], w.p[1]));
00082               Vertex t = Vertex(s, context->addVertex(m * Vector3(s[0], s[1], z)));
00083               below.push_back(t);
00084               below.push_back(w);
00085               above.push_back(t);
00086               reuseVertex = t;
00087               reuse = true;
00088             }
00089             else below.push_back(w);
00090           }
00091           v = w;
00092         }
00093       }
00094 
00095       void splitY(const vector<Vertex> &polygon, double clip,
00096                   const Matrix3x3 &m, MesherContext *context,
00097                   vector<Vertex> &below, vector<Vertex> &above,
00098                   double z)
00099       {
00100         Vertex v = polygon[polygon.size()-1];
00101         for(unsigned i=0; i<polygon.size(); ++i)
00102         {
00103           Vertex w = polygon[i];
00104           if(w.p[1] >= clip)
00105           {
00106             if(v.p[1] >= clip) above.push_back(w);
00107             else
00108             {
00109               Vector2 s(linInterp(clip, v.p[1], w.p[1], v.p[0], w.p[0]), clip);
00110               Vertex t = Vertex(s, context->addVertex(m * Vector3(s[0], s[1], z)));
00111               above.push_back(t);
00112               above.push_back(w);
00113               below.push_back(t);
00114             }
00115           }
00116           else
00117           {
00118             if(v.p[1] >= clip)
00119             {
00120               Vector2 s(linInterp(clip, v.p[1], w.p[1], v.p[0], w.p[0]), clip);
00121               Vertex t = Vertex(s, context->addVertex(m * Vector3(s[0], s[1], z)));
00122               below.push_back(t);
00123               below.push_back(w);
00124               above.push_back(t);
00125             }
00126             else below.push_back(w);
00127           }
00128           v = w;
00129         }
00130       }
00131     }
00132 
00133     void meshPolygon(const vector<Vector3> &polygon,
00134                      double maxPatchSize,
00135                      MesherContext *context)
00136     {
00137       // Determine a basis for the polygon
00138       Vector3 basisu = polygon[1] - polygon[0];
00139       Vector3 basisv = polygon[polygon.size()-1] - polygon[0];
00140 
00141       basisu.normalize();
00142       basisv.normalize();
00143 
00144       Vector3 basisw = basisu * basisv; // Normal
00145       basisv = basisw * basisu;
00146 
00147       basisv.normalize();
00148       basisw.normalize();
00149 
00150       Matrix3x3 mat(basisu, basisv, basisw);
00151 
00152       vector<Vertex> p1, p2, p3, p4;
00153       vector<Vertex> *poly = &p1, *stripe = &p2, *patch = &p3, *temp = &p4;
00154 
00155       // Transform to 2D and find AABB
00156       double
00157         minX = numeric_limits<double>::max(),
00158         minY = numeric_limits<double>::max(),
00159         maxX = numeric_limits<double>::min(),
00160         maxY = numeric_limits<double>::min();
00161 
00162       double z;    // Common z coordinate for all 2d-transformed vertices.
00163       Vector3 v;
00164       for(unsigned i=0; i<polygon.size(); ++i)
00165       {
00166         v = polygon[i] * mat;
00167         Vector2 w(v);
00168         if(i == 0) z = v[2];
00169 
00170         if(w[0] < minX) minX = w[0];
00171         if(w[0] > maxX) maxX = w[0];
00172 
00173         if(w[1] < minY) minY = w[1];
00174         if(w[1] > maxY) maxY = w[1];
00175 
00176         poly->push_back(Vertex(w, context->addVertex
00177                                (mat * Vector3(v[0], v[1], z))));
00178       }
00179 
00180       const unsigned numberOfPatchesX =
00181         static_cast<unsigned>(ceil((maxX-minX)/maxPatchSize));
00182       const unsigned numberOfPatchesY =
00183         static_cast<unsigned>(ceil((maxY-minY)/maxPatchSize));
00184 
00185       const double patchSizeX = (maxX-minX)/numberOfPatchesX;
00186       const double patchSizeY = (maxY-minY)/numberOfPatchesY;
00187 
00188       Vertex *reuseVertex = new Vertex[numberOfPatchesX-1];
00189       bool *reuse = new bool[numberOfPatchesX-1];
00190 
00191       for(unsigned i=0; i<numberOfPatchesX-1; ++i) reuse[i] = false;
00192 
00193       for(unsigned y=0; y<numberOfPatchesY; ++y)
00194       {
00195         if(y < numberOfPatchesY-1)
00196         {
00197           temp->clear();
00198           stripe->clear();
00199           splitY(*poly, minY + (y+1) * patchSizeY, mat,
00200                  context, *stripe, *temp, z);
00201           swap(poly, temp);
00202         }
00203         else swap(stripe, poly);
00204 
00205         for(unsigned x=0; x<numberOfPatchesX; ++x)
00206         {
00207           if(x < numberOfPatchesX-1)
00208           {
00209             temp->clear();
00210             patch->clear();
00211             splitX(*stripe, minX + (x+1) * patchSizeX, mat, context,
00212                    *patch, *temp, reuseVertex[x], reuse[x], z);
00213             swap(stripe, temp);
00214           }
00215           else swap(patch, stripe);
00216 
00217           if(patch->size() == 0) continue; // Patch and polygon are disjoint 
00218 
00219           if(patch->size() > 4)
00220           {
00221             int a = (*patch)[0].i;
00222             for(unsigned i=2; i<patch->size(); ++i)
00223             {
00224               vector<int> p;
00225               p.push_back(a);
00226               p.push_back((*patch)[i-1].i);
00227               p.push_back((*patch)[i].i);
00228               context->addPolygon(p);
00229             }
00230           }
00231           else
00232           {
00233             if(patch->size() < 3)
00234               ARCHON_THROW1(PolygonException, "Too few vertices");
00235             vector<int> p;
00236             p.push_back((*patch)[0].i);
00237             p.push_back((*patch)[1].i);
00238             p.push_back((*patch)[2].i);
00239             if(patch->size() == 4) p.push_back((*patch)[3].i);
00240             context->addPolygon(p);
00241           }
00242         }
00243       }
00244 
00245       delete[] reuseVertex;
00246       delete[] reuse;
00247     }
00248 
00249     namespace
00250     {
00251       struct Context: MesherContext
00252       {
00253         vector<Vector3> &vertices;
00254         vector<int> &polygons;
00255         Context(vector<Vector3> &vertices,
00256                 vector<int> &polygons):
00257           vertices(vertices), polygons(polygons) {}
00258 
00259         int addVertex(const Vector3 &v)
00260         {
00261           int i = vertices.size();
00262           vertices.push_back(v);
00263           return i;
00264         }
00265 
00266         void addPolygon(const vector<int> &p)
00267         {
00268           polygons.insert(polygons.end(), p.begin(), p.end());
00269           polygons.push_back(-1);
00270         }
00271       };
00272     }
00273 
00274     void meshPolygon(const vector<Vector3> &polygon,
00275                      double maxPatchSize,
00276                      vector<Vector3> &resultingVertices,
00277                      vector<int> &resultingPolygons)
00278     {
00279       resultingVertices.clear();
00280       resultingPolygons.clear();
00281       Context context(resultingVertices, resultingPolygons);
00282       meshPolygon(polygon, maxPatchSize, &context);
00283     }
00284   }
00285 }
00286 
00287 

Generated on Sun Jul 30 22:55:45 2006 for Archon by  doxygen 1.4.4