54 printf(
"Usage: %s\n" , ex );
55 printf(
"\t --%s <input polygon mesh>\n" ,
In.
name );
56 printf(
"\t[--%s <ouput polygon mesh>]\n" ,
Out.
name );
58 printf(
"\t[--%s <trimming value>]\n" ,
Trim.
name );
65 if( key1<key2 )
return ( ( (
long long)key1 )<<32 ) | ( (
long long)key2 );
66 else return ( ( (
long long)key2 )<<32 ) | ( (
long long)key1 );
69 template<
class Real ,
class Vertex >
72 typename Vertex::Wrapper _v1(v1) , _v2(v2);
73 if( _v1.value==_v2.value )
return Vertex( (_v1+_v2)/Real(2.) );
75 Real dx = ( _v1.value-value ) / ( _v1.value-_v2.value );
76 return Vertex( _v1*(1.f-dx) + _v2*dx );
78 template<
class Real ,
class Vertex >
79 void SmoothValues( std::vector< Vertex >& vertices ,
const std::vector< std::vector< int > >& polygons )
81 std::vector< int >
count( vertices.size() );
82 std::vector< Real > sums( vertices.size() , 0 );
83 for(
size_t i=0 ; i<polygons.size() ; i++ )
85 int sz = int(polygons[i].
size());
86 for(
int j=0 ; j<sz ; j++ )
88 int j1 = j , j2 = (j+1)%sz;
89 int v1 = polygons[i][j1] , v2 = polygons[i][j2];
91 sums[v1] += vertices[v2].value , sums[v2] += vertices[v1].value;
94 for(
size_t i=0 ; i<vertices.size() ; i++ ) vertices[i].value = ( sums[i] + vertices[i].value ) / (
count[i] + 1 );
96 template<
class Real ,
class Vertex >
99 const std::vector< int >&
polygon ,
100 std::vector< Vertex >& vertices ,
101 std::vector< std::vector< int > >* ltPolygons , std::vector< std::vector< int > >* gtPolygons ,
102 std::vector< bool >* ltFlags , std::vector< bool >* gtFlags ,
103 hash_map< long long , int >& vertexTable ,
107 int sz = int(
polygon.size() );
108 std::vector< bool > gt( sz );
110 for(
int j=0 ; j<sz ; j++ )
112 gt[j] = ( vertices[
polygon[j] ].value>trimValue );
113 if( gt[j] ) gtCount++;
115 if ( gtCount==sz ){
if( gtPolygons ) gtPolygons->push_back(
polygon ) ;
if( gtFlags ) gtFlags->push_back(
false ); }
116 else if( gtCount==0 ){
if( ltPolygons ) ltPolygons->push_back(
polygon ) ;
if( ltFlags ) ltFlags->push_back(
false ); }
120 for( start=0 ; start<sz ; start++ )
if( gt[start] && !gt[(start+sz-1)%sz] )
break;
123 std::vector< int > poly;
127 int j1 = (start+int(sz)-1)%sz , j2 = start;
130 hash_map< long long , int >::iterator iter = vertexTable.find(
EdgeKey( v1 , v2 ) );
131 if( iter==vertexTable.end() )
133 vertexTable[
EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() );
136 else vIdx = iter->second;
137 poly.push_back( vIdx );
140 for(
int _j=0 ; _j<=sz ; _j++ )
142 int j1 = (_j+start+sz-1)%sz , j2 = (_j+start)%sz;
144 if( gt[j2]==gtFlag ) poly.push_back( v2 );
148 hash_map< long long , int >::iterator iter = vertexTable.find(
EdgeKey( v1 , v2 ) );
149 if( iter==vertexTable.end() )
151 vertexTable[
EdgeKey( v1 , v2 ) ] = vIdx = int( vertices.size() );
154 else vIdx = iter->second;
155 poly.push_back( vIdx );
156 if( gtFlag ){
if( gtPolygons ) gtPolygons->push_back( poly ) ;
if( ltFlags ) ltFlags->push_back(
true ); }
157 else {
if( ltPolygons ) ltPolygons->push_back( poly ) ;
if( gtFlags ) gtFlags->push_back(
true ); }
158 poly.clear() , poly.push_back( vIdx ) , poly.push_back( v2 );
164 template<
class Real ,
class Vertex >
165 void Triangulate(
const std::vector< Vertex >& vertices ,
const std::vector< std::vector< int > >& polygons , std::vector< std::vector< int > >& triangles )
168 for(
size_t i=0 ; i<polygons.size() ; i++ )
169 if( polygons.size()>3 )
172 std::vector< Point3D< Real > > _vertices( polygons[i].
size() );
173 std::vector< TriangleIndex > _triangles;
174 for(
int j=0 ; j<int( polygons[i].
size() ) ; j++ ) _vertices[j] = vertices[ polygons[i][j] ].
point;
175 mat.GetTriangulation( _vertices , _triangles );
178 size_t idx = triangles.size();
179 triangles.resize( idx+_triangles.size() );
180 for(
int j=0 ; j<int(_triangles.size()) ; j++ )
182 triangles[idx+j].resize(3);
183 for(
int k=0 ; k<3 ; k++ ) triangles[idx+j][k] = polygons[i][ _triangles[j].idx[k] ];
186 else if( polygons[i].
size()==3 ) triangles.push_back( polygons[i] );
188 template<
class Real ,
class Vertex >
191 if(
polygon.size()<3 )
return 0.;
197 center /= Real(
polygon.size() );
204 template<
class Vertex >
207 hash_map< int , int > vMap;
208 std::vector< bool > vertexFlags( vertices.size() ,
false );
209 for(
size_t i=0 ; i<polygons.size() ; i++ )
for(
size_t j=0 ; j<polygons[i].size() ; j++ ) vertexFlags[ polygons[i][j] ] =
true;
211 for(
int i=0 ; i<int(vertices.size()) ; i++ )
if( vertexFlags[i] ) vMap[i] = vCount++;
212 for(
size_t i=0 ; i<polygons.size() ; i++ )
for(
size_t j=0 ; j<polygons[i].size() ; j++ ) polygons[i][j] = vMap[ polygons[i][j] ];
214 std::vector< Vertex > _vertices( vCount );
215 for(
int i=0 ; i<int(vertices.size()) ; i++ )
if( vertexFlags[i] ) _vertices[ vMap[i] ] = vertices[i];
216 vertices = _vertices;
218 void SetConnectedComponents(
const std::vector< std::vector< int > >& polygons , std::vector< std::vector< int > >& components )
220 std::vector< int > polygonRoots( polygons.size() );
221 for(
size_t i=0 ; i<polygons.size() ; i++ ) polygonRoots[i] =
int(i);
222 hash_map< long long , int > edgeTable;
223 for(
size_t i=0 ; i<polygons.size() ; i++ )
225 int sz = int( polygons[i].
size() );
226 for(
int j=0 ; j<sz ; j++ )
228 int j1 = j , j2 = (j+1)%sz;
229 int v1 = polygons[i][j1] , v2 = polygons[i][j2];
230 long long eKey =
EdgeKey( v1 , v2 );
231 hash_map< long long , int >::iterator iter = edgeTable.find( eKey );
232 if( iter==edgeTable.end() ) edgeTable[ eKey ] = int(i);
235 int p = iter->second;
236 while( polygonRoots[p]!=p )
238 int temp = polygonRoots[p];
239 polygonRoots[p] = int(i);
242 polygonRoots[p] = int(i);
246 for(
size_t i=0 ; i<polygonRoots.size() ; i++ )
249 while( polygonRoots[p]!=p ) p = polygonRoots[p];
252 while( polygonRoots[p]!=p )
254 int temp = polygonRoots[p];
255 polygonRoots[p] = root;
260 hash_map< int , int > vMap;
261 for(
int i= 0 ; i<int(polygonRoots.size()) ; i++ )
if( polygonRoots[i]==i ) vMap[i] = cCount++;
262 components.resize( cCount );
263 for(
int i=0 ; i<int(polygonRoots.size()) ; i++ ) components[ vMap[ polygonRoots[i] ] ].push_back(i);
265 template<
class Real >
267 template<
class Real >
271 return sqrt( n[0]*n[0] + n[1]*n[1] + n[2]*n[2] ) / 2.;
273 template<
class Vertex >
278 std::vector< Vertex > vertices;
279 std::vector< std::vector< int > > polygons;
281 int ft , commentNum = paramNum+2;
283 PlyReadPolygons(
In.
value , vertices , polygons , Vertex::ReadProperties , Vertex::ReadComponents , ft , &comments , &commentNum );
284 for(
int i=0 ; i<
Smooth.
value ; i++ ) SmoothValues< float , Vertex >( vertices , polygons );
285 min =
max = vertices[0].value;
286 for(
size_t i=0 ; i<vertices.size() ; i++ )
min = std::min< float >(
min , vertices[i].value ) ,
max = std::max< float >(
max , vertices[i].value );
287 printf(
"Value Range: [%f,%f]\n" ,
min ,
max );
290 hash_map< long long , int > vertexTable;
291 std::vector< std::vector< int > > ltPolygons , gtPolygons;
292 std::vector< bool > ltFlags , gtFlags;
294 for(
int i=0 ; i<paramNum+2 ; i++ ) comments[i+commentNum]=
new char[1024];
295 sprintf( comments[commentNum++] ,
"Running Surface Trimmer (V5)" );
304 for(
size_t i=0 ; i<polygons.size() ; i++ )
SplitPolygon( polygons[i] , vertices , <Polygons , >Polygons , <Flags , >Flags , vertexTable ,
Trim.
value );
307 std::vector< std::vector< int > > _ltPolygons , _gtPolygons;
308 std::vector< std::vector< int > > ltComponents , gtComponents;
311 std::vector< double > ltAreas( ltComponents.size() , 0. ) , gtAreas( gtComponents.size() , 0. );
312 std::vector< bool > ltComponentFlags( ltComponents.size() ,
false ) , gtComponentFlags( gtComponents.size() ,
false );
314 for(
size_t i=0 ; i<ltComponents.size() ; i++ )
316 for(
size_t j=0 ; j<ltComponents[i].size() ; j++ )
318 ltAreas[i] += PolygonArea< float , Vertex >( vertices , ltPolygons[ ltComponents[i][j] ] );
319 ltComponentFlags[i] = ( ltComponentFlags[i] || ltFlags[ ltComponents[i][j] ] );
323 for(
size_t i=0 ; i<gtComponents.size() ; i++ )
325 for(
size_t j=0 ; j<gtComponents[i].size() ; j++ )
327 gtAreas[i] += PolygonArea< float , Vertex >( vertices , gtPolygons[ gtComponents[i][j] ] );
328 gtComponentFlags[i] = ( gtComponentFlags[i] || gtFlags[ gtComponents[i][j] ] );
332 for(
size_t i=0 ; i<ltComponents.size() ; i++ )
334 if( ltAreas[i]<area*
IslandAreaRatio.
value && ltComponentFlags[i] )
for(
size_t j=0 ; j<ltComponents[i].size() ; j++ ) _gtPolygons.push_back( ltPolygons[ ltComponents[i][j] ] );
335 else for(
size_t j=0 ; j<ltComponents[i].size() ; j++ ) _ltPolygons.push_back( ltPolygons[ ltComponents[i][j] ] );
337 for(
size_t i=0 ; i<gtComponents.size() ; i++ )
339 if( gtAreas[i]<area*
IslandAreaRatio.
value && gtComponentFlags[i] )
for(
size_t j=0 ; j<gtComponents[i].size() ; j++ ) _ltPolygons.push_back( gtPolygons[ gtComponents[i][j] ] );
340 else for(
size_t j=0 ; j<gtComponents[i].size() ; j++ ) _gtPolygons.push_back( gtPolygons[ gtComponents[i][j] ] );
342 ltPolygons = _ltPolygons , gtPolygons = _gtPolygons;
347 std::vector< std::vector< int > > polys = ltPolygons;
348 Triangulate< float , Vertex >( vertices , ltPolygons , polys ) , ltPolygons = polys;
351 std::vector< std::vector< int > > polys = gtPolygons;
352 Triangulate< float , Vertex >( vertices , gtPolygons , polys ) , gtPolygons = polys;
357 sprintf( comments[commentNum++] ,
"#Trimmed In: %9.1f (s)" ,
Time()-t );
358 if(
Out.
set )
PlyWritePolygons(
Out.
value , vertices , gtPolygons , Vertex::WriteProperties , Vertex::WriteComponents , ft , comments , commentNum );
375 bool hasValue = readFlags[3];
376 bool hasColor = ( readFlags[4] || readFlags[7] ) && ( readFlags[5] || readFlags[8] ) && ( readFlags[6] || readFlags[9] );
378 if( !hasValue ) fprintf( stderr ,
"[ERROR] Ply file does not contain values\n" ) , exit( 0 );
379 if( hasColor )
return Execute< PlyColorAndValueVertex< float > >();
380 else return Execute< PlyValueVertex< float > >();
void cmdLineParse(int argc, char **argv, int num, cmdLineReadable **readable, int dumpError)
int PlyReadPolygons(char *fileName, std::vector< Vertex > &vertices, std::vector< std::vector< int > > &polygons, PlyProperty *properties, int propertyNum, int &file_type, char ***comments=NULL, int *commentNum=NULL, bool *readFlags=NULL)
int PlyWritePolygons(char *fileName, CoredMeshData< Vertex > *mesh, int file_type, const Point3D< float > &translate, float scale, char **comments=NULL, int commentNum=0, XForm4x4< Real > xForm=XForm4x4< Real >::Identity())
bool PlyReadHeader(char *fileName, PlyProperty *properties, int propertyNum, bool *readFlags, int &file_type)
void SmoothValues(std::vector< Vertex > &vertices, const std::vector< std::vector< int > > &polygons)
cmdLineReadable * params[]
void SplitPolygon(const std::vector< int > &polygon, std::vector< Vertex > &vertices, std::vector< std::vector< int > > *ltPolygons, std::vector< std::vector< int > > *gtPolygons, std::vector< bool > *ltFlags, std::vector< bool > *gtFlags, std::unordered_map< long long, int > &vertexTable, Real trimValue)
cmdLineFloat IslandAreaRatio("aRatio", 0.001f)
Point3D< Real > CrossProduct(Point3D< Real > p1, Point3D< Real > p2)
void SetConnectedComponents(const std::vector< std::vector< int > > &polygons, std::vector< std::vector< int > > &components)
double PolygonArea(const std::vector< Vertex > &vertices, const std::vector< int > &polygon)
void Triangulate(const std::vector< Vertex > &vertices, const std::vector< std::vector< int > > &polygons, std::vector< std::vector< int > > &triangles)
cmdLineFloat Trim("trim")
cmdLineInt Smooth("smooth", 5)
double TriangleArea(Point3D< Real > v1, Point3D< Real > v2, Point3D< Real > v3)
int SurfaceTrimmer(int argc, char *argv[])
void RemoveHangingVertices(std::vector< Vertex > &vertices, std::vector< std::vector< int > > &polygons)
Vertex InterpolateVertices(const Vertex &v1, const Vertex &v2, Real value)
cmdLineReadable PolygonMesh("polygonMesh")
long long EdgeKey(int key1, int key2)
boost::geometry::model::polygon< point_xy > polygon