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/Photo/Makefile \
|
||||||
src/Prep/ShapeFile/Makefile \
|
src/Prep/ShapeFile/Makefile \
|
||||||
src/Prep/TGVPF/Makefile \
|
src/Prep/TGVPF/Makefile \
|
||||||
|
src/Prep/UserDef/Makefile \
|
||||||
src/Utils/Makefile \
|
src/Utils/Makefile \
|
||||||
src/Utils/cdrom/Makefile \
|
src/Utils/cdrom/Makefile \
|
||||||
src/Utils/download-map/Makefile \
|
src/Utils/download-map/Makefile \
|
||||||
|
|
|
@ -7,4 +7,5 @@ SUBDIRS = \
|
||||||
MergerClipper \
|
MergerClipper \
|
||||||
Photo \
|
Photo \
|
||||||
ShapeFile \
|
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…
Add table
Reference in a new issue