1
0
Fork 0

Updates from David Megginson to support the USGS global land use/cover raster

data.
This commit is contained in:
curt 2000-11-02 21:21:49 +00:00
parent 25034ea180
commit 5619a6b473
10 changed files with 310 additions and 115 deletions

View file

@ -303,6 +303,7 @@ AC_OUTPUT( \
src/Lib/Array/Makefile \
src/Lib/DEM/Makefile \
src/Lib/Geometry/Makefile \
src/Lib/landcover/Makefile \
src/Lib/Optimize/Makefile \
src/Lib/Polygon/Makefile \
src/Lib/poly2tri/Makefile \

View file

@ -10,6 +10,7 @@ testclipper_LDADD = \
$(top_builddir)/src/Construct/Clipper/libClipper.a \
$(top_builddir)/src/Construct/Triangulate/libTriangulate.a \
$(top_builddir)/src/Lib/Polygon/libPolygon.a \
$(top_builddir)/src/Lib/landcover/liblandcover.a \
$(top_builddir)/src/Lib/poly2tri/libpoly2tri.a \
-lsgdebug -lsgmisc -lz -lgpc

View file

@ -146,13 +146,7 @@ bool FGClipper::load_polys(const string& path) {
// TEST - Ignore
// } else
if ( area < FG_MAX_AREA_TYPES ) {
polys_in.polys[area].push_back(poly);
} else {
FG_LOG( FG_CLIPPER, FG_ALERT, "Polygon type out of range = "
<< (int)poly_type);
exit(-1);
}
add_poly(area, poly);
// FILE *ofp= fopen("outfile", "w");
// gpc_write_polygon(ofp, &polys.landuse);
@ -161,6 +155,18 @@ bool FGClipper::load_polys(const string& path) {
}
void FGClipper::add_poly (int area, const FGPolygon &poly)
{
if ( area < FG_MAX_AREA_TYPES ) {
polys_in.polys[area].push_back(poly);
} else {
FG_LOG( FG_CLIPPER, FG_ALERT, "Polygon type out of range = "
<< area);
exit(-1);
}
}
// remove any slivers from in polygon and move them to out polygon.
void FGClipper::move_slivers( FGPolygon& in, FGPolygon& out ) {
cout << "Begin move slivers" << endl;
@ -300,11 +306,28 @@ bool FGClipper::clip_all(const point2d& min, const point2d& max) {
// best representation of land vs. ocean. If we have other less
// accurate data that spills out into the ocean, we want to just
// clip it.
FGPolygon mask;
mask.erase();
FGPolygon land_mask;
land_mask.erase();
for ( int i = 0; i < (int)polys_in.polys[DefaultArea].size(); ++i ) {
result_union = polygon_union( mask, polys_in.polys[DefaultArea][i] );
mask = result_union;
result_union =
polygon_union( land_mask, polys_in.polys[DefaultArea][i] );
land_mask = result_union;
}
// set up island mask, for cutting holes in lakes
FGPolygon island_mask;
island_mask.erase();
for ( int i = 0; i < (int)polys_in.polys[IslandArea].size(); ++i ) {
island_mask =
polygon_union( island_mask, polys_in.polys[IslandArea][i] );
}
// set up pond mask, for cutting holes in islands
FGPolygon pond_mask;
pond_mask.erase();
for ( int i = 0; i < (int)polys_in.polys[PondArea].size(); ++i ) {
pond_mask =
polygon_union( pond_mask, polys_in.polys[PondArea][i] );
}
// int count = 0;
@ -322,11 +345,19 @@ bool FGClipper::clip_all(const point2d& min, const point2d& max) {
if ( i > HoleArea ) {
// clip to land mask
tmp = polygon_int( current, mask );
tmp = polygon_int( current, land_mask );
} else {
tmp = current;
}
if ( i == LakeArea ) {
// clip against island mask
tmp = polygon_diff( tmp, island_mask );
} else if ( i == IslandArea ) {
// clip to pond mask
tmp = polygon_diff( tmp, pond_mask );
}
// clip current polygon against previous higher priority
// stuff

View file

@ -50,7 +50,8 @@ FG_USING_STD(vector);
// typedef gpcpoly_container::const_iterator const_gpcpoly_iterator;
#define FG_MAX_AREA_TYPES 20
#define FG_MAX_AREA_TYPES 40 // FIXME also defined in
// MergerClipper/clipper.hxx
#define EXTRA_SAFETY_CLIP
// #define FG_MAX_VERTICES 100000
@ -84,6 +85,9 @@ public:
// Load a polygon definition file
bool load_polys(const string& path);
// Add a polygon.
void add_poly(int area, const FGPolygon &poly);
// remove any slivers from in polygon and move them to out
// polygon.
void move_slivers( FGPolygon& in, FGPolygon& out );

View file

@ -13,6 +13,7 @@ fgfs_construct_LDADD = \
$(top_builddir)/src/Lib/Geometry/libGeometry.a \
$(top_builddir)/src/Lib/Optimize/libOptimize.a \
$(top_builddir)/src/Lib/Polygon/libPolygon.a \
$(top_builddir)/src/Lib/landcover/liblandcover.a \
$(top_builddir)/src/Lib/poly2tri/libpoly2tri.a \
$(top_builddir)/src/Lib/TriangleJRS/libTriangleJRS.a \
-lsgbucket -lsgmath -lsgmisc -lsgdebug -lplibsg -lz -lgpc

View file

@ -51,6 +51,7 @@
#include <GenOutput/genobj.hxx>
#include <Match/match.hxx>
#include <Triangulate/triangle.hxx>
#include <landcover/landcover.hxx>
#include "construct.hxx"
@ -62,8 +63,73 @@ FG_USING_STD(vector);
vector<string> load_dirs;
/**
* Translate USGS land cover into TerraGear.
*/
static AreaType translateUSGSCover (int usgs_value)
{
switch (usgs_value) {
case 1: // Urban and Built-Up Land
return BuiltUpCover;
case 2: // Dryland Cropland and Pasture
return DryCropPastureCover;
case 3: // Irrigated Cropland and Pasture
return IrrCropPastureCover;
case 4: // Mixed Dryland/Irrigated Cropland and Pasture
return MixedCropPastureCover;
case 5: // Cropland/Grassland Mosaic
return CropGrassCover;
case 6: // Cropland/Woodland Mosaic
return CropWoodCover;
case 7: // Grassland
return GrassCover;
case 8: // Shrubland
return ShrubCover;
case 9: // Mixed Shrubland/Grassland
return ShrubGrassCover;
case 10: // Savanna
return SavannaCover;
case 11: // Deciduous Broadleaf Forest
return DeciduousBroadCover;
case 12: // Deciduous Needleleaf Forest
return DeciduousNeedleCover;
case 13: // Evergreen Broadleaf Forest
return EvergreenBroadCover;
case 14: // Evergreen Needleleaf Forest
return EvergreenNeedleCover;
case 15: // Mixed Forest
return MixedForestCover;
case 16: // Water Bodies
// FIXME: use the type of an adjoining area if possible
// return WaterBodyCover;
return DefaultArea;
case 17: // Herbaceous Wetland
return HerbWetlandCover;
case 18: // Wooded Wetland
return WoodedWetlandCover;
case 19: // Barren or Sparsely Vegetated
return BarrenCover;
case 20: // Herbaceous Tundra
return HerbTundraCover;
case 21: // Wooded Tundra
return WoodedTundraCover;
case 22: // Mixed Tundra
return MixedTundraCover;
case 23: // Bare Ground Tundra
return BareTundraCover;
case 24: // Snow or Ice
return SnowCover;
default: // Unknown
return DefaultArea;
}
}
// do actual scan of directory and loading of files
int actual_load_polys( const string& dir, FGConstruct& c, FGClipper& clipper ) {
static int actual_load_polys( const string& dir,
FGConstruct& c,
FGClipper& clipper ) {
int counter = 0;
string base = c.get_bucket().gen_base_path();
string tile_str = c.get_bucket().gen_index_str();
@ -105,9 +171,56 @@ int actual_load_polys( const string& dir, FGConstruct& c, FGClipper& clipper ) {
}
// generate polygons from land-cover raster.
static int actual_load_landcover ( LandCover &cover, FGConstruct & c,
FGClipper &clipper ) {
int count = 0;
double lon, lat;
FGPolygon poly;
// Get the top corner of the tile
lon =
c.get_bucket().get_center_lon() - (0.5 * c.get_bucket().get_width());
lat =
c.get_bucket().get_center_lat() - (0.5 * c.get_bucket().get_height());
cout << "DPM: tile at " << lon << ',' << lat << endl;
// FIXME: this may still be wrong
int x_span = int(120 * bucket_span(lat)); // arcsecs of longitude
int y_span = int(120 * FG_BUCKET_SPAN); // arcsecs of latitude
for (int x = 0; x < x_span; x++) {
for (int y = 0; y < y_span; y++) {
double x1 = lon + (x * (1.0/120.0));
double y1 = lat + (y * (1.0/120.0));
double x2 = x1 + (1.0/120.0);
double y2 = y1 + (1.0/120.0);
int cover_value = cover.getValue(x1 + (1.0/240.0), y1 + (1.0/240.0));
cout << " position: " << x1 << ',' << y1 << ','
<< cover.getDescUSGS(cover_value) << endl;
AreaType area = translateUSGSCover(cover_value);
if (area != DefaultArea) {
poly.erase();
poly.add_node(0, Point3D(x1, y1, 0.0));
poly.add_node(0, Point3D(x1, y2, 0.0));
poly.add_node(0, Point3D(x2, y2, 0.0));
poly.add_node(0, Point3D(x2, y1, 0.0));
clipper.add_poly(area, poly);
count++;
}
}
}
return count;
}
// load all 2d polygons matching the specified base path and clip
// against each other to resolve any overlaps
int load_polys( FGConstruct& c ) {
static int load_polys( FGConstruct& c ) {
string glc = c.get_work_base();
glc += "/LC-Global/gusgs2_0ll.img";
LandCover cover( glc );
FGClipper clipper;
string base = c.get_bucket().gen_base_path();
@ -125,6 +238,9 @@ int load_polys( FGConstruct& c ) {
cout << " loaded " << count << " total polys" << endl;
}
// Load the land use polygons
count += actual_load_landcover ( cover, c, clipper );
point2d min, max;
min.x = c.get_bucket().get_center_lon() - 0.5 * c.get_bucket().get_width();
min.y = c.get_bucket().get_center_lat() - 0.5 * c.get_bucket().get_height();
@ -144,7 +260,7 @@ int load_polys( FGConstruct& c ) {
// load regular grid of elevation data (dem based), return list of
// fitted nodes
int load_dem( FGConstruct& c, FGArray& array) {
static int load_dem( FGConstruct& c, FGArray& array) {
point_list result;
string base = c.get_bucket().gen_base_path();
@ -169,14 +285,14 @@ int load_dem( FGConstruct& c, FGArray& array) {
// fit dem nodes, return number of fitted nodes
int fit_dem(FGArray& array, int error) {
static int fit_dem(FGArray& array, int error) {
return array.fit( error );
}
// triangulate the data for each polygon ( first time before splitting )
void first_triangulate( FGConstruct& c, const FGArray& array,
FGTriangle& t ) {
static void first_triangulate( FGConstruct& c, const FGArray& array,
FGTriangle& t ) {
// first we need to consolidate the points of the DEM fit list and
// all the polygons into a more "Triangle" friendly format
@ -196,7 +312,7 @@ void first_triangulate( FGConstruct& c, const FGArray& array,
// triangulate the data for each polygon ( second time after splitting
// and reassembling )
void second_triangulate( FGConstruct& c, FGTriangle& t ) {
static void second_triangulate( FGConstruct& c, FGTriangle& t ) {
t.rebuild( c );
cout << "done re building node list and polygons" << endl;
@ -463,14 +579,14 @@ static point_list gen_point_normals( FGConstruct& c ) {
// generate the flight gear scenery file
void do_output( FGConstruct& c, FGGenOutput& output ) {
static void do_output( FGConstruct& c, FGGenOutput& output ) {
output.build( c );
output.write( c );
}
// collect custom objects and move to scenery area
void do_custom_objects( const FGConstruct& c ) {
static void do_custom_objects( const FGConstruct& c ) {
FGBucket b = c.get_bucket();
for (int i = 0; i < load_dirs.size(); i++) {
@ -515,7 +631,7 @@ void do_custom_objects( const FGConstruct& c ) {
}
// master construction routine
void construct_tile( FGConstruct& c ) {
static void construct_tile( FGConstruct& c ) {
cout << "Construct tile, bucket = " << c.get_bucket() << endl;
// fit with ever increasing error tolerance until we produce <=
@ -655,7 +771,7 @@ void construct_tile( FGConstruct& c ) {
// display usage and exit
void usage( const string name ) {
static void usage( const string name ) {
cout << "Usage: " << name << endl;
cout << "[ --output-dir=<directory>" << endl;
cout << " --work-dir=<directory>" << endl;

View file

@ -2,6 +2,7 @@ SUBDIRS = \
Array \
DEM \
Geometry \
landcover \
Optimize \
Polygon \
poly2tri \

View file

@ -21,59 +21,100 @@
// $Id$
#include <simgear/compiler.h>
#include <map>
#include STL_IOSTREAM
#include STL_STRING
#include "names.hxx"
FG_USING_STD(string);
FG_USING_STD(map);
FG_USING_STD(cout);
FG_USING_STD(endl);
typedef map<AreaType, string> area_type_map;
typedef map<string, AreaType> area_name_map;
static area_type_map area_types;
static area_name_map area_names;
inline static void set_area (const string &name, AreaType type)
{
area_types[type] = name;
area_names[name] = type;
}
static bool _initialized = false;
inline static void init ()
{
if (_initialized)
return;
set_area("SomeSort", SomeSortOfArea);
set_area("Hole", HoleArea);
set_area("Island", IslandArea);
set_area("Pond", PondArea);
set_area("Swamp or Marsh", MarshArea);
set_area("Marsh", MarshArea);
set_area("Lake", LakeArea);
set_area("Lake Dry", DryLakeArea);
set_area("DryLake", DryLakeArea);
set_area("Lake Intermittent", IntLakeArea);
set_area("IntermittentLake", IntLakeArea);
set_area("Reservoir", ReservoirArea);
set_area("Reservoir Intermittent", IntReservoirArea);
set_area("IntermittentReservoir", IntReservoirArea);
set_area("Stream", StreamArea);
set_area("Canal", CanalArea);
set_area("Glacier", GlacierArea);
set_area("Urban", UrbanArea);
set_area("BuiltUpCover", BuiltUpCover);
set_area("DryCropPastureCover", DryCropPastureCover);
set_area("IrrCropPastureCover", IrrCropPastureCover);
set_area("MixedCropPastureCover", MixedCropPastureCover);
set_area("CropGrassCover", CropGrassCover);
set_area("CropWoodCover", CropWoodCover);
set_area("GrassCover", GrassCover);
set_area("ShrubCover", ShrubCover);
set_area("ShrubGrassCover", ShrubGrassCover);
set_area("SavannaCover", SavannaCover);
set_area("DeciduousBroadCover", DeciduousBroadCover);
set_area("DeciduousNeedleCover", DeciduousNeedleCover);
set_area("EvergreenBroadCover", EvergreenBroadCover);
set_area("EvergreenNeedleCover", EvergreenNeedleCover);
set_area("MixedForestCover", MixedForestCover);
set_area("WaterBodyCover", WaterBodyCover);
set_area("HerbWetlandCover", HerbWetlandCover);
set_area("WoodedWetlandCover", WoodedWetlandCover);
set_area("BarrenCover", BarrenCover);
set_area("HerbTundraCover", HerbTundraCover);
set_area("WoodedTundraCover", WoodedTundraCover);
set_area("MixedTundraCover", MixedTundraCover);
set_area("BareTundraCover", BareTundraCover);
set_area("SnowCover", SnowCover);
set_area("Default", DefaultArea);
set_area("Bay Estuary or Ocean", OceanArea);
set_area("Ocean", OceanArea);
set_area("Void Area", VoidArea);
set_area("Null", NullArea);
_initialized = true;
}
// return area type from text name
AreaType get_area_type( string area ) {
if ( area == "SomeSort" ) {
return SomeSortOfArea;
} else if ( area == "Hole" ) {
return HoleArea;
} else if ( area == "Island" ) {
return IslandArea;
} else if ( area == "Pond" ) {
return PondArea;
} else if ( (area == "Swamp or Marsh")
|| (area == "Marsh") ) {
return MarshArea;
} else if ( area == "Lake" ) {
return LakeArea;
} else if ( (area == "Lake Dry")
|| (area == "DryLake") ) {
return DryLakeArea;
} else if ( (area == "Lake Intermittent")
|| (area == "IntermittentLake") ) {
return IntLakeArea;
} else if ( area == "Reservoir" ) {
return ReservoirArea;
} else if ( (area == "Reservoir Intermittent")
|| (area == "IntermittentReservoir") ) {
return IntReservoirArea;
} else if ( area == "Stream" ) {
return StreamArea;
} else if ( area == "Canal" ) {
return CanalArea;
} else if ( area == "Glacier" ) {
return GlacierArea;
} else if ( area == "Urban" ) {
return UrbanArea;
} else if ( area == "Default" ) {
return DefaultArea;
} else if ( (area == "Bay Estuary or Ocean")
|| (area == "Ocean") ) {
return OceanArea;
} else if ( area == "Void Area" ) {
return VoidArea;
} else if ( area == "Null" ) {
return NullArea;
AreaType
get_area_type (const string &area) {
init();
area_name_map::const_iterator it = area_names.find(area);
if (it != area_names.end()) {
return it->second;
} else {
cout << "unknown area = '" << area << "'" << endl;
// cout << "area = " << area << endl;
@ -87,40 +128,10 @@ AreaType get_area_type( string area ) {
// return text from of area name
string get_area_name( AreaType area ) {
if ( area == DefaultArea ) {
return "Default";
} else if ( area == HoleArea ) {
return "Hole";
} else if ( area == MarshArea ) {
return "Marsh";
} else if ( area == PondArea ) {
return "Pond";
} else if ( area == IslandArea ) {
return "Island";
} else if ( area == LakeArea ) {
return "Lake";
} else if ( area == DryLakeArea ) {
return "DryLake";
} else if ( area == IntLakeArea ) {
return "IntermittentLake";
} else if ( area == ReservoirArea ) {
return "Reservoir";
} else if ( area == IntReservoirArea ) {
return "IntermittentReservoir";
} else if ( area == StreamArea ) {
return "Stream";
} else if ( area == CanalArea ) {
return "Canal";
} else if ( area == GlacierArea ) {
return "Glacier";
} else if ( area == UrbanArea ) {
return "Urban";
} else if ( area == OceanArea ) {
return "Ocean";
} else if ( area == VoidArea ) {
return "VoidArea";
} else if ( area == NullArea ) {
return "Null";
init();
area_type_map::const_iterator it = area_types.find(area);
if (it != area_types.end()) {
return it->second;
} else {
cout << "unknown area code = " << (int)area << endl;
return "Unknown";

View file

@ -39,19 +39,48 @@ enum AreaType {
SomeSortOfArea = 0,
HoleArea = 1,
PondArea = 2,
IslandArea = 3,
LakeArea = 4,
DryLakeArea = 5,
IntLakeArea = 6,
ReservoirArea = 7,
IntReservoirArea = 8,
StreamArea = 9,
CanalArea = 10,
GlacierArea = 11,
OceanArea = 12,
UrbanArea = 13,
MarshArea = 14,
DefaultArea = 15,
LakeArea = 3,
DryLakeArea = 4,
IntLakeArea = 5,
ReservoirArea = 6,
IntReservoirArea = 7,
StreamArea = 8,
CanalArea = 9,
GlacierArea = 10,
OceanArea = 11,
UrbanArea = 12,
MarshArea = 13,
// USGS Land Covers
// These are low-priority, since known polygons should always win.
BuiltUpCover = 14, // Urban and Built-Up Land
DryCropPastureCover = 15, // Dryland Cropland and Pasture
IrrCropPastureCover = 16, // Irrigated Cropland and Pasture
MixedCropPastureCover = 17, // Mixed Dryland/Irrigated Cropland and Pasture
CropGrassCover = 18, // Cropland/Grassland Mosaic
CropWoodCover = 19, // Cropland/Woodland Mosaic
GrassCover = 20, // Grassland
ShrubCover = 21, // Shrubland
ShrubGrassCover = 22, // Mixed Shrubland/Grassland
SavannaCover = 23, // Savanna
DeciduousBroadCover = 24, // Deciduous Broadleaf Forest
DeciduousNeedleCover = 25, // Deciduous Needleleaf Forest
EvergreenBroadCover = 26, // Evergreen Broadleaf Forest
EvergreenNeedleCover = 27, // Evergreen Needleleaf Forest
MixedForestCover = 28, // Mixed Forest
WaterBodyCover = 29, // Water Bodies
HerbWetlandCover = 30, // Herbaceous Wetland
WoodedWetlandCover = 31, // Wooded Wetland
BarrenCover = 32, // Barren or Sparsely Vegetated
HerbTundraCover = 33, // Herbaceous Tundra
WoodedTundraCover = 34, // Wooded Tundra
MixedTundraCover = 35, // Mixed Tundra
BareTundraCover = 36, // Bare Ground Tundra
SnowCover = 37, // Snow or Ice
IslandArea = 38,
DefaultArea = 39,
VoidArea = 9997,
NullArea = 9998,
UnknownArea = 9999
@ -59,7 +88,7 @@ enum AreaType {
// return area type from text name
AreaType get_area_type( string area );
AreaType get_area_type( const string &area );
// return text form of area name
string get_area_name( AreaType area );

View file

@ -43,7 +43,7 @@
FG_USING_STD(string);
FG_USING_STD(vector);
#define FG_MAX_AREA_TYPES 20
#define FG_MAX_AREA_TYPES 40 // FIXME: also defined in clipper.hxx
class FGPolyList {
public: