/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCGLIB_PLANAR_POLYGON_TESSELLATOR #define __VCGLIB_PLANAR_POLYGON_TESSELLATOR #include #include #include namespace vcg { /** \addtogroup space */ /*@{*/ /** A very simple earcut tessellation of planar 2D polygon. Input: a vector or Point2<> Output: a vector of faces as a triple of indices to the input vector */ template bool Cross( const Point2 & p00, const Point2 & p01, const Point2 & p10, const Point2 & p11) { Point2 vec0 = p01-p00; Point2 vec1 = p11-p10; if ( ( vec0^ (p11-p00)) * ( vec0^ (p10 - p00)) >=0) return false; if ( ( vec1^ (p01-p10)) * ( vec1^ (p00 - p10)) >=0) return false; return true; } template bool Intersect(int cur , int v2, std::vector & next, std::vector > & points2){ for(int i = 0; i < points2.size();++i) if( (next[i]!=-1) && (i!=cur)) if( Cross(points2[cur], points2[v2],points2[i],points2[next[i]])) return true; return false; } template void TessellatePlanarPolygon2( POINT_CONTAINER & points2, std::vector & output){ typedef typename POINT_CONTAINER::value_type Point2x; typedef typename Point2x::ScalarType S; // tessellate // first very inefficient implementation std::vector next,prev; for(int i = 0; i < points2.size(); ++i) next.push_back((i+1)%points2.size()); for(int i = 0; i < points2.size(); ++i) prev.push_back((i+points2.size()-1)%points2.size()); int v1,v2; // check orientation S orient = 0.0; for(int i = 0 ; i < points2.size(); ++i){ v1 = next[i]; v2 = next[v1]; orient+= (points2[v1] - points2[0]) ^ (points2[v2] - points2[0]); } orient = (orient>0)? 1.0:-1.0; int cur = 0; while(output.size()<3*(points2.size()-2)){ v1 = next[cur]; v2 = next[v1]; if( ( (orient*((points2[v1] - points2[cur]) ^ (points2[v2] - points2[cur]))) >= 0.0) && !Intersect(cur, v2,next,points2)) { // output the face output.push_back(cur); output.push_back(v1); output.push_back(v2); // readjust the topology next[cur] = v2; prev[v2] = cur; prev[v1] = -1;//unnecessary next[v1] = -1;//unnecessary } else do{cur = (cur+1)%points2.size();} while(next[cur]==-1); } } /** A very simple earcut tessellation of planar 2D polygon. Input: a vector or Point3<> Output: a vector of faces as a triple of indices to the input vector */ template void TessellatePlanarPolygon3( POINT_CONTAINER & points, std::vector & output){ typedef typename POINT_CONTAINER::value_type Point3x; typedef typename Point3x::ScalarType S; Point3x n; math::SubtractiveRingRNG rg; int i12[2]; S bestsn = -1.0; Point3x bestn,u,v; for(int i =0; i < points.size();++i){ for(int j = 0; j < 2; ++j){ i12[j] = i; while(i12[j]==i) i12[j] = rg.generate(points.size()-1);} n = (points[i12[0]]-points[i])^(points[i12[1]]-points[i]); S sn = n.SquaredNorm(); if(sn > bestsn){ bestsn = sn; bestn = n;} } GetUV(n,u,v); // project the coordinates std::vector > points2; for(int i = 0; i < points.size(); ++i){ Point3x & p = points[i]; points2.push_back(Point2(p*u,p*v)); } TessellatePlanarPolygon2( points2,output); } /*@}*/ } // end namespace #endif