- Test a different approach for assigning land cover attributes to "default'
cover" areas. Rather than artificially cut in polygon areas, just lookup a land cover type for unassigned triangles. I think this has potential, but it needs more work to eliminate some odd artifacts. - Revove --min-angle= option. - Don't re-fit() triangle array to try to achieve a particular range of node quantities ... this is all pre-computed with a much smarter, much more efficient algorithm.
This commit is contained in:
parent
f5f961b8c0
commit
730c454320
1 changed files with 66 additions and 95 deletions
|
@ -243,24 +243,23 @@ static AreaType get_area_type (const LandCover &cover,
|
||||||
int cover_value = cover.getValue(xpos, ypos);
|
int cover_value = cover.getValue(xpos, ypos);
|
||||||
AreaType area = translateUSGSCover(cover_value);
|
AreaType area = translateUSGSCover(cover_value);
|
||||||
|
|
||||||
// Non-default area is fine.
|
|
||||||
if (area != DefaultArea) {
|
if (area != DefaultArea) {
|
||||||
return area;
|
// Non-default area is fine.
|
||||||
}
|
return area;
|
||||||
|
} else {
|
||||||
// If we're stuck with the default area,
|
// If we're stuck with the default area, try to borrow from a
|
||||||
// try to borrow from a neighbour.
|
// neighbour.
|
||||||
else {
|
for (double x = xpos - dx; x <= xpos + dx; x += dx) {
|
||||||
for (double x = xpos - dx; x <= xpos + dx; x += dx) {
|
for (double y = ypos - dy; y < ypos + dx; y += dy) {
|
||||||
for (double y = ypos - dy; y < ypos + dx; y += dy) {
|
if (x != xpos || y != ypos) {
|
||||||
if (x != xpos || y != ypos) {
|
cover_value = cover.getValue(x, y);
|
||||||
cover_value = cover.getValue(x, y);
|
area = translateUSGSCover(cover_value);
|
||||||
area = translateUSGSCover(cover_value);
|
if (area != DefaultArea) {
|
||||||
if (area != DefaultArea)
|
return area;
|
||||||
return area;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OK, give up and return default
|
// OK, give up and return default
|
||||||
|
@ -288,7 +287,7 @@ static void make_area( const LandCover &cover, TGPolygon *polys,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Generate polygons from la and-cover raster. Horizontally- or
|
// Generate polygons from land-cover raster. Horizontally- or
|
||||||
// vertically-adjacent polygons will be merged automatically.
|
// vertically-adjacent polygons will be merged automatically.
|
||||||
static int actual_load_landcover ( TGConstruct & c,
|
static int actual_load_landcover ( TGConstruct & c,
|
||||||
TGClipper &clipper ) {
|
TGClipper &clipper ) {
|
||||||
|
@ -389,10 +388,15 @@ static int load_polys( TGConstruct& c ) {
|
||||||
cout << " loaded " << count << " total polys" << endl;
|
cout << " loaded " << count << " total polys" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// now we are trying an idea of taking all unassigned land mass
|
||||||
|
// polygons (i.e. default cover type) and assigning them to the
|
||||||
|
// nearest cover type
|
||||||
|
#if 0
|
||||||
// Load the land use polygons if the --cover option was specified
|
// Load the land use polygons if the --cover option was specified
|
||||||
if ( c.get_cover().size() > 0 ) {
|
if ( c.get_cover().size() > 0 ) {
|
||||||
count += actual_load_landcover (c, clipper);
|
count += actual_load_landcover (c, clipper);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
point2d min, max;
|
point2d min, max;
|
||||||
min.x = c.get_bucket().get_center_lon() - 0.5 * c.get_bucket().get_width();
|
min.x = c.get_bucket().get_center_lon() - 0.5 * c.get_bucket().get_width();
|
||||||
|
@ -434,6 +438,7 @@ static bool load_array( TGConstruct& c, TGArray& array) {
|
||||||
|
|
||||||
SGBucket b = c.get_bucket();
|
SGBucket b = c.get_bucket();
|
||||||
array.parse( b );
|
array.parse( b );
|
||||||
|
array.remove_voids();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +459,7 @@ static void first_triangulate( TGConstruct& c, const TGArray& array,
|
||||||
cout << "done building node list and polygons" << endl;
|
cout << "done building node list and polygons" << endl;
|
||||||
|
|
||||||
cout << "ready to do triangulation" << endl;
|
cout << "ready to do triangulation" << endl;
|
||||||
t.run_triangulate( c.get_angle(), 1 );
|
t.run_triangulate( 0.0, 1 );
|
||||||
cout << "finished triangulation" << endl;
|
cout << "finished triangulation" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,7 +475,7 @@ static void second_triangulate( TGConstruct& c, TGTriangle& t ) {
|
||||||
cout << " (pre) nodes = " << c.get_tri_nodes().size() << endl;
|
cout << " (pre) nodes = " << c.get_tri_nodes().size() << endl;
|
||||||
cout << " (pre) normals = " << c.get_point_normals().size() << endl;
|
cout << " (pre) normals = " << c.get_point_normals().size() << endl;
|
||||||
|
|
||||||
t.run_triangulate( c.get_angle(), 2 );
|
t.run_triangulate( 0.0, 2 );
|
||||||
|
|
||||||
cout << " (post) nodes = " << t.get_out_nodes().size() << endl;
|
cout << " (post) nodes = " << t.get_out_nodes().size() << endl;
|
||||||
|
|
||||||
|
@ -596,6 +601,39 @@ static void fix_point_heights( TGConstruct& c, const TGArray& array )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// For each triangle assigned to the "default" area type, see if we
|
||||||
|
// can lookup a better land cover type from the 1km data structure.
|
||||||
|
static void fix_land_cover_assignments( TGConstruct& c ) {
|
||||||
|
cout << "Fixing up default land cover types" << endl;
|
||||||
|
// the list of node locations
|
||||||
|
TGTriNodes trinodes = c.get_tri_nodes();
|
||||||
|
point_list geod_nodes = trinodes.get_node_list();
|
||||||
|
|
||||||
|
// the list of triangles (with area type attribute)
|
||||||
|
triele_list tri_elements = c.get_tri_elements();
|
||||||
|
|
||||||
|
// traverse the triangle element groups
|
||||||
|
cout << " Total Nodes = " << geod_nodes.size() << endl;
|
||||||
|
cout << " Total triangles = " << tri_elements.size() << endl;
|
||||||
|
for ( unsigned int i = 0; i < tri_elements.size(); ++i ) {
|
||||||
|
TGTriEle t = tri_elements[i];
|
||||||
|
if ( t.get_attribute() == DefaultArea ) {
|
||||||
|
Point3D average = ( geod_nodes[t.get_n1()]
|
||||||
|
+ geod_nodes[t.get_n2()]
|
||||||
|
+ geod_nodes[t.get_n3()] ) / 3.0;
|
||||||
|
cout << " average triangle center = " << average;
|
||||||
|
AreaType a = get_area_type ( c.get_cover(),
|
||||||
|
average.x(), average.y(),
|
||||||
|
1.0 / 120.0, 1.0 / 120.0 );
|
||||||
|
cout << " new attrib = " << get_area_name( a ) << endl;
|
||||||
|
|
||||||
|
// update the actual structure
|
||||||
|
c.set_tri_attribute( i, a );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// build the wgs-84 point list
|
// build the wgs-84 point list
|
||||||
static void build_wgs_84_point_list( TGConstruct& c, const TGArray& array ) {
|
static void build_wgs_84_point_list( TGConstruct& c, const TGArray& array ) {
|
||||||
point_list geod_nodes;
|
point_list geod_nodes;
|
||||||
|
@ -867,13 +905,6 @@ static void construct_tile( TGConstruct& c ) {
|
||||||
// 80% of max nodes. We should really have the sim end handle
|
// 80% of max nodes. We should really have the sim end handle
|
||||||
// arbitrarily complex tiles.
|
// arbitrarily complex tiles.
|
||||||
|
|
||||||
bool acceptable = false;
|
|
||||||
bool growing = false;
|
|
||||||
bool shrinking = false;
|
|
||||||
|
|
||||||
double error = 200.0;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
// load and clip 2d polygon data
|
// load and clip 2d polygon data
|
||||||
if ( load_polys( c ) == 0 ) {
|
if ( load_polys( c ) == 0 ) {
|
||||||
// don't build the tile if there is no 2d data ... it *must*
|
// don't build the tile if there is no 2d data ... it *must*
|
||||||
|
@ -887,69 +918,10 @@ static void construct_tile( TGConstruct& c ) {
|
||||||
|
|
||||||
TGTriangle t;
|
TGTriangle t;
|
||||||
|
|
||||||
while ( ! acceptable ) {
|
// triangulate the data for each polygon
|
||||||
// do a least squares fit of the (array) data with the given
|
first_triangulate( c, array, t );
|
||||||
// error tolerance
|
|
||||||
array.fit( error );
|
|
||||||
|
|
||||||
// triangulate the data for each polygon
|
cout << "number of fitted nodes = " << t.get_out_nodes_size() << endl;
|
||||||
first_triangulate( c, array, t );
|
|
||||||
|
|
||||||
acceptable = true;
|
|
||||||
|
|
||||||
count = t.get_out_nodes_size();
|
|
||||||
|
|
||||||
if ( (count < c.get_min_nodes()) && (error >= 25.0) ) {
|
|
||||||
// reduce error tolerance until number of points exceeds the
|
|
||||||
// minimum threshold
|
|
||||||
cout << "produced too few nodes ..." << endl;
|
|
||||||
|
|
||||||
acceptable = false;
|
|
||||||
growing = true;
|
|
||||||
|
|
||||||
if ( shrinking ) {
|
|
||||||
error /= 1.25;
|
|
||||||
shrinking = false;
|
|
||||||
} else {
|
|
||||||
error /= 1.5;
|
|
||||||
}
|
|
||||||
cout << "Setting error to " << error << " and retrying fit."
|
|
||||||
<< endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( count > c.get_max_nodes() ) {
|
|
||||||
if ( error <= 1000.0 ) {
|
|
||||||
// increase error tolerance until number of points drops below
|
|
||||||
// the maximum threshold
|
|
||||||
cout << "produced too many nodes ..." << endl;
|
|
||||||
|
|
||||||
acceptable = false;
|
|
||||||
shrinking = true;
|
|
||||||
|
|
||||||
if ( growing ) {
|
|
||||||
error *= 1.25;
|
|
||||||
growing = false;
|
|
||||||
} else {
|
|
||||||
error *= 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "Setting error to " << error << " and retrying fit."
|
|
||||||
<< endl;
|
|
||||||
} else {
|
|
||||||
// we tried, but can't seem to get down to a
|
|
||||||
// reasonable number of points even with a huge error
|
|
||||||
// tolerance. This could be related to the triangle()
|
|
||||||
// call which might be having trouble with our input
|
|
||||||
// set. Let's just die hope that our parent can try
|
|
||||||
// again with a smaller interior triangle angle.
|
|
||||||
cout << "Error: Too many nodes." << endl;
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "finished fit with error = " << error << " node count = "
|
|
||||||
<< count << endl;
|
|
||||||
|
|
||||||
// save the results of the triangulation
|
// save the results of the triangulation
|
||||||
c.set_tri_nodes( t.get_out_nodes() );
|
c.set_tri_nodes( t.get_out_nodes() );
|
||||||
|
@ -1001,6 +973,11 @@ static void construct_tile( TGConstruct& c ) {
|
||||||
c.set_point_normals( normals );
|
c.set_point_normals( normals );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now for all the remaining "default" land cover polygons, assign
|
||||||
|
// each one it's proper type from the land use/land cover
|
||||||
|
// database.
|
||||||
|
fix_land_cover_assignments( c );
|
||||||
|
|
||||||
// calculate wgs84 (cartesian) form of node list
|
// calculate wgs84 (cartesian) form of node list
|
||||||
build_wgs_84_point_list( c, array );
|
build_wgs_84_point_list( c, array );
|
||||||
|
|
||||||
|
@ -1021,7 +998,6 @@ static void usage( const string name ) {
|
||||||
cout << "[ --output-dir=<directory>" << endl;
|
cout << "[ --output-dir=<directory>" << endl;
|
||||||
cout << " --work-dir=<directory>" << endl;
|
cout << " --work-dir=<directory>" << endl;
|
||||||
cout << " --cover=<path to land-cover raster>" << endl;
|
cout << " --cover=<path to land-cover raster>" << endl;
|
||||||
cout << " --min-angle=<angle>" << endl;
|
|
||||||
cout << " --tile-id=<id>" << endl;
|
cout << " --tile-id=<id>" << endl;
|
||||||
cout << " --lon=<degrees>" << endl;
|
cout << " --lon=<degrees>" << endl;
|
||||||
cout << " --lat=<degrees>" << endl;
|
cout << " --lat=<degrees>" << endl;
|
||||||
|
@ -1036,7 +1012,6 @@ static void usage( const string name ) {
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
string output_dir = ".";
|
string output_dir = ".";
|
||||||
string work_dir = ".";
|
string work_dir = ".";
|
||||||
string min_angle = "10";
|
|
||||||
string cover = "";
|
string cover = "";
|
||||||
double lon = -110.664244; // P13
|
double lon = -110.664244; // P13
|
||||||
double lat = 33.352890;
|
double lat = 33.352890;
|
||||||
|
@ -1061,8 +1036,6 @@ int main(int argc, char **argv) {
|
||||||
output_dir = arg.substr(13);
|
output_dir = arg.substr(13);
|
||||||
} else if (arg.find("--work-dir=") == 0) {
|
} else if (arg.find("--work-dir=") == 0) {
|
||||||
work_dir = arg.substr(11);
|
work_dir = arg.substr(11);
|
||||||
} else if (arg.find("--min-angle=") == 0) {
|
|
||||||
min_angle = arg.substr(12);
|
|
||||||
} else if (arg.find("--tile-id=") == 0) {
|
} else if (arg.find("--tile-id=") == 0) {
|
||||||
tile_id = atol(arg.substr(10).c_str());
|
tile_id = atol(arg.substr(10).c_str());
|
||||||
} else if (arg.find("--lon=") == 0) {
|
} else if (arg.find("--lon=") == 0) {
|
||||||
|
@ -1086,7 +1059,6 @@ int main(int argc, char **argv) {
|
||||||
|
|
||||||
cout << "Output directory is " << output_dir << endl;
|
cout << "Output directory is " << output_dir << endl;
|
||||||
cout << "Working directory is " << work_dir << endl;
|
cout << "Working directory is " << work_dir << endl;
|
||||||
cout << "Minimum angle is " << min_angle << endl;
|
|
||||||
cout << "Tile id is " << tile_id << endl;
|
cout << "Tile id is " << tile_id << endl;
|
||||||
cout << "Center longitude is " << lon << endl;
|
cout << "Center longitude is " << lon << endl;
|
||||||
cout << "Center latitude is " << lat << endl;
|
cout << "Center latitude is " << lat << endl;
|
||||||
|
@ -1132,7 +1104,6 @@ int main(int argc, char **argv) {
|
||||||
// main construction data management class
|
// main construction data management class
|
||||||
TGConstruct c;
|
TGConstruct c;
|
||||||
|
|
||||||
c.set_angle( min_angle );
|
|
||||||
c.set_cover( cover );
|
c.set_cover( cover );
|
||||||
c.set_work_base( work_dir );
|
c.set_work_base( work_dir );
|
||||||
c.set_output_base( output_dir );
|
c.set_output_base( output_dir );
|
||||||
|
|
Loading…
Reference in a new issue