Added tguserdef, a utility for adding user-defined points, lines, and
polygons to scenery. It uses the regular XML property format, which users can create easily in a text editor. See src/Prep/UserDef/sample.xml for examples.
This commit is contained in:
parent
0349ab6241
commit
7f957c2269
6 changed files with 340 additions and 1 deletions
|
@ -337,6 +337,7 @@ AC_OUTPUT( \
|
|||
src/Prep/Photo/Makefile \
|
||||
src/Prep/ShapeFile/Makefile \
|
||||
src/Prep/TGVPF/Makefile \
|
||||
src/Prep/UserDef/Makefile \
|
||||
src/Utils/Makefile \
|
||||
src/Utils/cdrom/Makefile \
|
||||
src/Utils/download-map/Makefile \
|
||||
|
|
|
@ -7,4 +7,5 @@ SUBDIRS = \
|
|||
MergerClipper \
|
||||
Photo \
|
||||
ShapeFile \
|
||||
TGVPF
|
||||
TGVPF \
|
||||
UserDef
|
||||
|
|
4
src/Prep/UserDef/.cvsignore
Normal file
4
src/Prep/UserDef/.cvsignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
.deps
|
||||
Makefile
|
||||
Makefile.in
|
||||
tguserdef
|
11
src/Prep/UserDef/Makefile.am
Normal file
11
src/Prep/UserDef/Makefile.am
Normal file
|
@ -0,0 +1,11 @@
|
|||
bin_PROGRAMS = tguserdef
|
||||
|
||||
tguserdef_SOURCES = tguserdef.cxx
|
||||
|
||||
tguserdef_LDADD = \
|
||||
$(top_builddir)/src/Lib/Geometry/libGeometry.a \
|
||||
$(top_builddir)/src/Lib/Polygon/libPolygon.a \
|
||||
$(top_builddir)/src/Lib/poly2tri/libpoly2tri.a \
|
||||
-lsgbucket -lsgmisc -lsgmath -lsgio -lsgxml -lsgdebug -lgenpolyclip -lz
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/src/Lib
|
107
src/Prep/UserDef/sample.xml
Normal file
107
src/Prep/UserDef/sample.xml
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
************************************************************************
|
||||
This is a sample file for adding user-defined land-use data.
|
||||
|
||||
There are three types of data that you can add: points, lines, and
|
||||
polygons. All of these get turned into polygons for scenery
|
||||
generation. Use a file like this to add missing roads, towns,
|
||||
villages, lakes etc. for your own scenery with tguserdef.
|
||||
************************************************************************
|
||||
-->
|
||||
|
||||
<PropertyList>
|
||||
|
||||
<!--
|
||||
First we'll add some small towns missing from vmap0.
|
||||
|
||||
For each point, we need to specify a single geographical
|
||||
location in degrees (lon/lat), the width of the area in meters,
|
||||
and the area material (see $FG_ROOT/materials.xml). The first
|
||||
example adds a small town 1km x 1km, and the following ones add
|
||||
small towns 500m x 500m. The name is optional, but you'll find
|
||||
it useful for keeping track of things.
|
||||
|
||||
Don't try too hard to be exact. I find two decimal places (about
|
||||
1km) to be as accurate as I can usually manage from sectional
|
||||
charts; if you go to three decimal places, you'll have 100m
|
||||
accuracy, which should almost always be good enough.
|
||||
-->
|
||||
|
||||
<point>
|
||||
<name>North Gower</name>
|
||||
<material>Town</material>
|
||||
<v>-75.72 45.13</v>
|
||||
<width>1000</width>
|
||||
</point>
|
||||
|
||||
<point>
|
||||
<name>Carp</name>
|
||||
<material>Town</material>
|
||||
<v>-76.04 45.35</v>
|
||||
<width>500</width>
|
||||
</point>
|
||||
|
||||
<point>
|
||||
<name>Kinburn</name>
|
||||
<material>Town</material>
|
||||
<v>-76.20 45.38</v>
|
||||
<width>500</width>
|
||||
</point>
|
||||
|
||||
<point>
|
||||
<name>Galetta</name>
|
||||
<material>Town</material>
|
||||
<v>-76.27 45.42</v>
|
||||
<width>500</width>
|
||||
</point>
|
||||
|
||||
<!--
|
||||
Next, we'll add a missing county road.
|
||||
|
||||
You need to specify the points (lon/lat) that the line will pass
|
||||
through, the material type, and the width in meters. By switching the
|
||||
material, you could make (say) a river or railroad instead of a
|
||||
road.
|
||||
|
||||
Again, don't try to hard to get every bend in the road; add points
|
||||
only for major changes in direction.
|
||||
-->
|
||||
|
||||
<line>
|
||||
<name>Ottawa-Carleton Road 6</name>
|
||||
<material>Road</material>
|
||||
<width>10</width>
|
||||
<v>
|
||||
-75.72 45.13
|
||||
-75.77 45.11
|
||||
-75.90 45.03
|
||||
</v>
|
||||
</line>
|
||||
|
||||
<!--
|
||||
Finally, we'll add a missing urban area.
|
||||
|
||||
A polygon can contain multiple contours, some of which can be holds
|
||||
(say, to create a donut shape). Simply specify the lon/lat points
|
||||
around the outside of each contour, and try to capture the rough
|
||||
shape of the area. By switching types, you could use this to add
|
||||
a park, forest or lake.
|
||||
-->
|
||||
|
||||
<polygon>
|
||||
<name>Kanata (north end)</name>
|
||||
<contour>
|
||||
<hole>false</hole>
|
||||
<v>
|
||||
-75.90 45.34
|
||||
-75.91 45.34
|
||||
-75.92 45.33
|
||||
-75.91 45.32
|
||||
-75.90 45.33
|
||||
-75.91 45.33
|
||||
</v>
|
||||
</contour>
|
||||
</polygon>
|
||||
|
||||
</PropertyList>
|
215
src/Prep/UserDef/tguserdef.cxx
Normal file
215
src/Prep/UserDef/tguserdef.cxx
Normal file
|
@ -0,0 +1,215 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/misc/exception.hxx>
|
||||
#include <simgear/misc/props_io.hxx>
|
||||
#include <simgear/misc/props.hxx>
|
||||
|
||||
#include <Geometry/util.hxx>
|
||||
#include <Polygon/index.hxx>
|
||||
#include <Polygon/names.hxx>
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <Polygon/split.hxx>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vector>
|
||||
SG_USING_STD(vector);
|
||||
|
||||
static string prog_name;
|
||||
static string work_dir = ".";
|
||||
static Rectangle bounds(Point3D(-180, -90, 0), Point3D(180, 90, 0));
|
||||
static FGPolygon bounds_poly;
|
||||
|
||||
|
||||
/**
|
||||
* Parse two vertices from a string.
|
||||
*/
|
||||
static const char *
|
||||
parse_point (const char * s, Point3D &p)
|
||||
{
|
||||
char * endptr;
|
||||
float x = strtof(s, &endptr);
|
||||
if (endptr == s)
|
||||
return 0;
|
||||
else
|
||||
s = endptr;
|
||||
float y = strtof(s, &endptr);
|
||||
if (endptr == s) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "Uneven number of vertices!!");
|
||||
return 0;
|
||||
}
|
||||
p.setx(x);
|
||||
p.sety(y);
|
||||
return endptr;
|
||||
}
|
||||
|
||||
static void
|
||||
add_point (SGPropertyNode_ptr node)
|
||||
{
|
||||
AreaType material =
|
||||
get_area_type(node->getStringValue("material", "Default"));
|
||||
Point3D p, dummy;
|
||||
const char * s = node->getStringValue("v");
|
||||
s = parse_point(s, p);
|
||||
if (s == 0) {
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "No point supplied; skipped");
|
||||
return;
|
||||
}
|
||||
s = parse_point(s, dummy);
|
||||
if (s != 0)
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "More than one vertex supplied for point");
|
||||
FGPolygon poly;
|
||||
makePolygon(p, node->getIntValue("width", 500), poly);
|
||||
poly = polygon_int(poly, bounds_poly);
|
||||
split_polygon(".", material, poly);
|
||||
}
|
||||
|
||||
static void
|
||||
add_line (SGPropertyNode_ptr node)
|
||||
{
|
||||
AreaType material =
|
||||
get_area_type(node->getStringValue("material", "Default"));
|
||||
const char * s = node->getStringValue("v");
|
||||
|
||||
Point3D p;
|
||||
Line line;
|
||||
s = parse_point(s, p);
|
||||
while (s != 0) {
|
||||
line.addPoint(p);
|
||||
s = parse_point(s, p);
|
||||
}
|
||||
|
||||
FGPolygon poly;
|
||||
makePolygon(line, node->getIntValue("width", 10), poly);
|
||||
poly = polygon_int(poly, bounds_poly);
|
||||
split_polygon(".", material, poly);
|
||||
}
|
||||
|
||||
static void
|
||||
add_polygon (SGPropertyNode_ptr node)
|
||||
{
|
||||
FGPolygon poly;
|
||||
AreaType material =
|
||||
get_area_type(node->getStringValue("material", "Default"));
|
||||
vector<SGPropertyNode_ptr> contour_nodes = node->getChildren("contour");
|
||||
for (int i = 0; i < contour_nodes.size(); i++) {
|
||||
SGPropertyNode_ptr contour_node = contour_nodes[i];
|
||||
Point3D p;
|
||||
const char * s = contour_node->getStringValue("v");
|
||||
s = parse_point(s, p);
|
||||
while (s != 0) {
|
||||
poly.add_node(i, p);
|
||||
s = parse_point(s, p);
|
||||
}
|
||||
poly.set_hole_flag(i, contour_node->getBoolValue("hole", false));
|
||||
}
|
||||
poly = polygon_int(poly, bounds_poly);
|
||||
split_polygon(".", material, poly);
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Usage: " << prog_name << " [opts] <file>");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int
|
||||
main (int ac, char ** av)
|
||||
{
|
||||
sglog().setLogLevels( SG_ALL, SG_DEBUG );
|
||||
|
||||
poly_index_init( "../poly_counter" );
|
||||
|
||||
prog_name = av[0];
|
||||
|
||||
//
|
||||
// Process command-line options.
|
||||
//
|
||||
int argPos = 1;
|
||||
while (argPos < ac) {
|
||||
string arg = av[argPos];
|
||||
|
||||
if (arg.find("--chunk=") == 0) {
|
||||
bounds = parseChunk(arg.substr(8));
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--min-lon=") == 0) {
|
||||
bounds.getMin().setx(strtod(arg.substr(10).c_str(), 0));
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--min-lat=") == 0) {
|
||||
bounds.getMin().sety(strtod(arg.substr(10).c_str(), 0));
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--max-lon=") == 0) {
|
||||
bounds.getMax().setx(strtod(arg.substr(10).c_str(), 0));
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--max-lat=") == 0) {
|
||||
bounds.getMax().sety(strtod(arg.substr(10).c_str(), 0));
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--work-dir=") == 0) {
|
||||
work_dir = arg.substr(11);
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg == "--") {
|
||||
argPos++;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (arg.find("-") == 0) {
|
||||
cerr << "Unrecognized option: " << arg << endl;
|
||||
usage();
|
||||
}
|
||||
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bounds.sanify();
|
||||
bounds_poly = bounds.toPoly();
|
||||
|
||||
SGPropertyNode props;
|
||||
if (argPos == ac) {
|
||||
usage();
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (int i = argPos; i < ac; i++) {
|
||||
try {
|
||||
readProperties(av[i], &props);
|
||||
} catch (const sg_throwable &ex) {
|
||||
SG_LOG(SG_TERRAIN, SG_ALERT, "Fatal error loading " << av[1] << ": "
|
||||
<< ex.getFormattedMessage());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nChildren = props.nChildren();
|
||||
for (int j = 0; j < nChildren; j++) {
|
||||
SGPropertyNode_ptr child = props.getChild(j);
|
||||
if (!strcmp("point", child->getName()))
|
||||
add_point(child);
|
||||
else if (!strcmp("line", child->getName()))
|
||||
add_line(child);
|
||||
else if (!strcmp("polygon", child->getName()))
|
||||
add_polygon(child);
|
||||
else
|
||||
SG_LOG(SG_TERRAIN, SG_WARN, "Unrecognized shape type "
|
||||
<< child->getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in a new issue