1
0
Fork 0

add --force option to hgtfit.

This option will ignore when loading, and replace when writing the
.fit.gz files.  Very useful when experimenting with different levels of detail.
This commit is contained in:
Peter Sadrozinski 2012-10-18 20:38:52 -04:00
parent 165f7e2481
commit 2dd32d2839

View file

@ -27,6 +27,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdio.h>
#include <errno.h> #include <errno.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -82,11 +83,11 @@ public:
} }
depth=32; depth=32;
} }
virtual Terra::real eval(int i, int j) { virtual Terra::real eval(int i, int j) {
return (Terra::real)array.get_array_elev(i,j); return (Terra::real)array.get_array_elev(i,j);
} }
/* No direct reading of .arr.gz files */ /* No direct reading of .arr.gz files */
virtual void rawRead(istream&) { virtual void rawRead(istream&) {
} }
@ -108,14 +109,15 @@ Terra::ImportMask *MASK=&default_mask;
Terra::real error_threshold=40.0; Terra::real error_threshold=40.0;
unsigned int min_points=50; unsigned int min_points=50;
unsigned int point_limit=1000; unsigned int point_limit=1000;
bool force=false;
inline int goal_not_met(Terra::GreedySubdivision* mesh) inline int goal_not_met(Terra::GreedySubdivision* mesh)
{ {
return return
( mesh->maxError() > error_threshold && ( mesh->maxError() > error_threshold &&
mesh->pointCount() < point_limit ) || mesh->pointCount() < point_limit ) ||
mesh->pointCount() < min_points; mesh->pointCount() < min_points;
} }
static void announce_goal(Terra::GreedySubdivision* mesh) static void announce_goal(Terra::GreedySubdivision* mesh)
@ -130,69 +132,78 @@ void greedy_insertion(Terra::GreedySubdivision* mesh)
while( goal_not_met(mesh) ) while( goal_not_met(mesh) )
{ {
if( !mesh->greedyInsert() ) if( !mesh->greedyInsert() )
break; break;
} }
announce_goal(mesh); announce_goal(mesh);
} }
bool endswith(const std::string& s1, const std::string& suffix) { bool endswith(const std::string& s1, const std::string& suffix) {
size_t s1len=s1.size(); size_t s1len=s1.size();
size_t sufflen=suffix.size(); size_t sufflen=suffix.size();
if (s1len<sufflen)
return false; if (s1len<sufflen) {
return s1.compare(s1len-sufflen,sufflen,suffix)==0; return false;
}
return s1.compare(s1len-sufflen,sufflen,suffix)==0;
} }
void fit_file(const SGPath& path) { void fit_file(const SGPath& path) {
SG_LOG(SG_GENERAL, SG_INFO,"Working on file '" << path << "'");
SG_LOG(SG_GENERAL, SG_INFO,"Working on file '" << path << "'");
SGPath outPath(path.dir());
SGPath outPath(path.dir()); outPath.append(path.file_base() + ".fit.gz");
outPath.append(path.file_base() + ".fit.gz");
if (!force) {
if (outPath.exists() && (path.modTime() < outPath.modTime())) { if (outPath.exists() && (path.modTime() < outPath.modTime())) {
SG_LOG(SG_GENERAL, SG_INFO ,"Skipping " << outPath << ", source " << path << " is older"); SG_LOG(SG_GENERAL, SG_INFO ,"Skipping " << outPath << ", source " << path << " is older");
return; return;
} }
} else {
SGBucket bucket(0,0); // dummy bucket if ( outPath.exists() ) {
TGArray inarray(path.dir() + "/" + path.file_base()); unlink( outPath.c_str() );
inarray.parse(bucket);
inarray.close();
ArrayMap *DEM=new ArrayMap(inarray);
Terra::GreedySubdivision *mesh;
mesh=new Terra::GreedySubdivision(DEM);
greedy_insertion(mesh);
gzFile fp;
if ( (fp = gzopen( outPath.c_str(), "wb9" )) == NULL ) {
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: opening " << outPath << " for writing!");
return;
} }
}
gzprintf(fp,"%d\n",mesh->pointCount());
SGBucket bucket(0,0); // dummy bucket
for (int x=0;x<DEM->width;x++) { TGArray inarray(path.dir() + "/" + path.file_base());
for (int y=0;y<DEM->height;y++) { inarray.parse(bucket);
if (mesh->is_used(x,y) != DATA_POINT_USED) inarray.close();
continue;
double vx,vy,vz; ArrayMap *DEM=new ArrayMap(inarray);
vx=(inarray.get_originx()+x*inarray.get_col_step())/3600.0;
vy=(inarray.get_originy()+y*inarray.get_row_step())/3600.0; Terra::GreedySubdivision *mesh;
vz=DEM->eval(x,y);
gzprintf(fp,"%+03.8f %+02.8f %0.2f\n",vx,vy,vz); mesh=new Terra::GreedySubdivision(DEM);
}
greedy_insertion(mesh);
gzFile fp;
if ( (fp = gzopen( outPath.c_str(), "wb9" )) == NULL ) {
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: opening " << outPath << " for writing!");
return;
}
gzprintf(fp,"%d\n",mesh->pointCount());
for (int x=0;x<DEM->width;x++) {
for (int y=0;y<DEM->height;y++) {
if (mesh->is_used(x,y) != DATA_POINT_USED)
continue;
double vx,vy,vz;
vx=(inarray.get_originx()+x*inarray.get_col_step())/3600.0;
vy=(inarray.get_originy()+y*inarray.get_row_step())/3600.0;
vz=DEM->eval(x,y);
gzprintf(fp,"%+03.8f %+02.8f %0.2f\n",vx,vy,vz);
} }
delete mesh; }
delete DEM;
delete mesh;
gzclose(fp); delete DEM;
gzclose(fp);
} }
void walk_path(const SGPath& path) { void walk_path(const SGPath& path) {
@ -214,80 +225,91 @@ void walk_path(const SGPath& path) {
} }
void usage(char* progname, const std::string& msg) { void usage(char* progname, const std::string& msg) {
if (msg.size()!=0) if (msg.size()!=0) {
SG_LOG(SG_GENERAL,SG_ALERT, msg); SG_LOG(SG_GENERAL,SG_ALERT, msg);
SG_LOG(SG_GENERAL,SG_INFO, "Usage: " << progname << " [options] <file | path to walk>"); }
SG_LOG(SG_GENERAL,SG_INFO, "\t -h | --help ");
SG_LOG(SG_GENERAL,SG_INFO, "\t -m | --minnodes 50"); SG_LOG(SG_GENERAL,SG_INFO, "Usage: " << progname << " [options] <file | path to walk>");
SG_LOG(SG_GENERAL,SG_INFO, "\t -x | --maxnodes 1000"); SG_LOG(SG_GENERAL,SG_INFO, "\t -h | --help ");
SG_LOG(SG_GENERAL,SG_INFO, "\t -e | --maxerror 40"); SG_LOG(SG_GENERAL,SG_INFO, "\t -m | --minnodes 50");
SG_LOG(SG_GENERAL,SG_INFO, "\t -v | --version"); SG_LOG(SG_GENERAL,SG_INFO, "\t -x | --maxnodes 1000");
SG_LOG(SG_GENERAL,SG_INFO, ""); SG_LOG(SG_GENERAL,SG_INFO, "\t -e | --maxerror 40");
SG_LOG(SG_GENERAL,SG_INFO, "Algorithm will produce at least <minnodes> fitted nodes, but no"); SG_LOG(SG_GENERAL,SG_INFO, "\t -f | --force");
SG_LOG(SG_GENERAL,SG_INFO, "more than <maxnodes>. Within that range, the algorithm will stop"); SG_LOG(SG_GENERAL,SG_INFO, "\t -v | --version");
SG_LOG(SG_GENERAL,SG_INFO, "if the maximum elevation error for any remaining point"); SG_LOG(SG_GENERAL,SG_INFO, "");
SG_LOG(SG_GENERAL,SG_INFO, "drops below <maxerror> meters."); SG_LOG(SG_GENERAL,SG_INFO, "Algorithm will produce at least <minnodes> fitted nodes, but no");
SG_LOG(SG_GENERAL,SG_INFO, ""); SG_LOG(SG_GENERAL,SG_INFO, "more than <maxnodes>. Within that range, the algorithm will stop");
SG_LOG(SG_GENERAL,SG_INFO, "Increasing the maxnodes value and/or decreasing maxerror"); SG_LOG(SG_GENERAL,SG_INFO, "if the maximum elevation error for any remaining point");
SG_LOG(SG_GENERAL,SG_INFO, "will produce a better surface approximation."); SG_LOG(SG_GENERAL,SG_INFO, "drops below <maxerror> meters.");
SG_LOG(SG_GENERAL,SG_INFO, ""); SG_LOG(SG_GENERAL,SG_INFO, "");
SG_LOG(SG_GENERAL,SG_INFO, "The input file must be a .arr.gz file such as that produced"); SG_LOG(SG_GENERAL,SG_INFO, "Increasing the maxnodes value and/or decreasing maxerror");
SG_LOG(SG_GENERAL,SG_INFO, "by demchop or hgtchop utils."); SG_LOG(SG_GENERAL,SG_INFO, "will produce a better surface approximation.");
SG_LOG(SG_GENERAL,SG_INFO, ""); SG_LOG(SG_GENERAL,SG_INFO, "");
SG_LOG(SG_GENERAL,SG_INFO, "**** NOTE ****:"); SG_LOG(SG_GENERAL,SG_INFO, "The input file must be a .arr.gz file such as that produced");
SG_LOG(SG_GENERAL,SG_INFO, "If a directory is input all .arr.gz files in directory will be"); SG_LOG(SG_GENERAL,SG_INFO, "by demchop or hgtchop utils.");
SG_LOG(SG_GENERAL,SG_INFO, "processed recursively."); SG_LOG(SG_GENERAL,SG_INFO, "");
SG_LOG(SG_GENERAL,SG_INFO, ""); SG_LOG(SG_GENERAL,SG_INFO, "Force will overwrite existing .arr.gz files, even if the input is older");
SG_LOG(SG_GENERAL,SG_INFO, "The output file(s) is/are called .fit.gz and is simply a list of"); SG_LOG(SG_GENERAL,SG_INFO, "");
SG_LOG(SG_GENERAL,SG_INFO, "from the resulting fitted surface nodes. The user of the"); SG_LOG(SG_GENERAL,SG_INFO, "**** NOTE ****:");
SG_LOG(SG_GENERAL,SG_INFO, ".fit.gz file will need to retriangulate the surface."); SG_LOG(SG_GENERAL,SG_INFO, "If a directory is input all .arr.gz files in directory will be");
SG_LOG(SG_GENERAL,SG_INFO, "processed recursively.");
SG_LOG(SG_GENERAL,SG_INFO, "");
SG_LOG(SG_GENERAL,SG_INFO, "The output file(s) is/are called .fit.gz and is simply a list of");
SG_LOG(SG_GENERAL,SG_INFO, "from the resulting fitted surface nodes. The user of the");
SG_LOG(SG_GENERAL,SG_INFO, ".fit.gz file will need to retriangulate the surface.");
} }
struct option options[]={ struct option options[]={
{"help",no_argument,NULL,'h'}, {"help",no_argument,NULL,'h'},
{"minnodes",required_argument,NULL,'m'}, {"minnodes",required_argument,NULL,'m'},
{"maxnodes",required_argument,NULL,'x'}, {"maxnodes",required_argument,NULL,'x'},
{"maxerror",required_argument,NULL,'e'}, {"maxerror",required_argument,NULL,'e'},
{"version",no_argument,NULL,'v'}, {"force",no_argument,NULL,'f'},
{NULL,0,NULL,0} {"version",no_argument,NULL,'v'},
{NULL,0,NULL,0}
}; };
int main(int argc, char** argv) { int main(int argc, char** argv) {
sglog().setLogLevels( SG_ALL, SG_DEBUG ); sglog().setLogLevels( SG_ALL, SG_DEBUG );
int option; int option;
while ((option=getopt_long(argc,argv,"hm:x:e:v",options,NULL))!=-1) { while ((option=getopt_long(argc,argv,"hm:x:e:v",options,NULL))!=-1) {
switch (option) { switch (option) {
case 'h': case 'h':
usage(argv[0],""); usage(argv[0],"");
break; break;
case 'm': case 'm':
min_points=atoi(optarg); min_points=atoi(optarg);
break; break;
case 'x': case 'x':
point_limit=atoi(optarg); point_limit=atoi(optarg);
break; break;
case 'e': case 'e':
error_threshold=atof(optarg); error_threshold=atof(optarg);
break; break;
case 'v': case 'f':
SG_LOG(SG_GENERAL,SG_INFO,argv[0] << " Version 1.0"); force=true;
exit(0); break;
break; case 'v':
case '?': SG_LOG(SG_GENERAL,SG_INFO,argv[0] << " Version 1.0");
usage(argv[0],std::string("Unknown option:")+(char)optopt); exit(0);
exit(1); break;
} case '?':
} usage(argv[0],std::string("Unknown option:")+(char)optopt);
SG_LOG(SG_GENERAL, SG_INFO, "Min points = " << min_points);
SG_LOG(SG_GENERAL, SG_INFO, "Max points = " << point_limit);
SG_LOG(SG_GENERAL, SG_INFO, "Max error = " << error_threshold);
if (optind<argc) {
while (optind<argc) {
walk_path(SGPath(argv[optind++]));
}
} else {
SG_LOG(SG_GENERAL, SG_INFO, "Use 'terrafit --help' for commands");
exit(1); exit(1);
} }
}
SG_LOG(SG_GENERAL, SG_INFO, "Min points = " << min_points);
SG_LOG(SG_GENERAL, SG_INFO, "Max points = " << point_limit);
SG_LOG(SG_GENERAL, SG_INFO, "Max error = " << error_threshold);
if (optind<argc) {
while (optind<argc) {
walk_path(SGPath(argv[optind++]));
}
} else {
SG_LOG(SG_GENERAL, SG_INFO, "Use 'terrafit --help' for commands");
exit(1);
}
} }