- added new program, tgvpf, to generate polygons from Vector Product
Format databases.
This commit is contained in:
parent
3050aca5c7
commit
c69d333d32
3 changed files with 646 additions and 1 deletions
|
@ -6,4 +6,5 @@ SUBDIRS = \
|
|||
GSHHS \
|
||||
MergerClipper \
|
||||
Photo \
|
||||
ShapeFile
|
||||
ShapeFile \
|
||||
TGVPF
|
||||
|
|
11
src/Prep/TGVPF/Makefile.am
Normal file
11
src/Prep/TGVPF/Makefile.am
Normal file
|
@ -0,0 +1,11 @@
|
|||
bin_PROGRAMS = tgvpf
|
||||
|
||||
tgvpf_SOURCES = tgvpf.cxx
|
||||
|
||||
tgvpf_LDADD = \
|
||||
$(top_builddir)/src/Lib/Polygon/libPolygon.a \
|
||||
$(top_builddir)/src/Lib/poly2tri/libpoly2tri.a \
|
||||
$(top_builddir)/src/Lib/vpf/libvpf.a \
|
||||
-lsgdebug -lsgbucket -lsgmisc -lsgmath -lsgio -lsgxml -lgenpolyclip -lz
|
||||
|
||||
INCLUDES += -I$(top_srcdir)/src/Lib
|
633
src/Prep/TGVPF/tgvpf.cxx
Normal file
633
src/Prep/TGVPF/tgvpf.cxx
Normal file
|
@ -0,0 +1,633 @@
|
|||
// tgvpf.cxx -- generate polygons from VPF topologies.
|
||||
//
|
||||
// Written by David Megginson, started September 2001. Based on
|
||||
// code by Curtis Olson.
|
||||
//
|
||||
// Copyright (C) 2001 David Megginson - david@megginson.com
|
||||
// Copyright (C) 1999 Curtis L. Olson - curt@flightgear.org
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
// $Id$
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#include STL_IOSTREAM
|
||||
#include STL_STRING
|
||||
#include <vector>
|
||||
|
||||
#if !defined (SG_HAVE_NATIVE_SGI_COMPILERS)
|
||||
SG_USING_STD(cerr);
|
||||
SG_USING_STD(cout);
|
||||
#endif
|
||||
SG_USING_STD(string);
|
||||
SG_USING_STD(vector);
|
||||
|
||||
#include <Polygon/index.hxx>
|
||||
#include <Polygon/names.hxx>
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <Polygon/split.hxx>
|
||||
#include <vpf/vpf.hxx>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <Win32/mkdir.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Utility stuff.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static inline ostream &
|
||||
operator<< (ostream &output, const VpfRectangle &rect)
|
||||
{
|
||||
output << rect.minX << ','
|
||||
<< rect.minY << ','
|
||||
<< rect.maxX << ','
|
||||
<< rect.maxY;
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline function to clamp an angle between 0 and 360 degrees.
|
||||
*/
|
||||
static inline double
|
||||
ANGLE (double a)
|
||||
{
|
||||
while (a < 0.0)
|
||||
a += 360.0;
|
||||
while (a >= 360.0)
|
||||
a -= 360.0;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the intersection of two lines.
|
||||
*
|
||||
* @param p0 First point on the first line.
|
||||
* @param p1 A second point on the first line.
|
||||
* @param p2 First point on the second line.
|
||||
* @param p3 A second point on the second line.
|
||||
* @param intersection A variable to hold the calculated intersection.
|
||||
* @return true if there was an intersection, false if the lines
|
||||
* are parallel or coincident.
|
||||
*/
|
||||
static bool
|
||||
getIntersection (const Point3D &p0, const Point3D &p1,
|
||||
const Point3D &p2, const Point3D &p3,
|
||||
Point3D &intersection)
|
||||
{
|
||||
double u_num =
|
||||
((p3.x()-p2.x())*(p0.y()-p2.y()))-((p3.y()-p2.y())*(p0.x()-p2.x()));
|
||||
double u_den =
|
||||
((p3.y()-p2.y())*(p1.x()-p0.x()))-((p3.x()-p2.x())*(p1.y()-p0.y()));
|
||||
|
||||
if (u_den == 0) {
|
||||
if (u_num == 0)
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Intersection: coincident lines");
|
||||
else
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Intersection: parallel lines");
|
||||
return false;
|
||||
} else {
|
||||
double u = u_num/u_den;
|
||||
intersection = Point3D((p0.x()+u*(p1.x()-p0.x())),
|
||||
(p0.y()+u*(p1.y()-p0.y())),
|
||||
0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Processing methods.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* An attribute pattern.
|
||||
*/
|
||||
struct Attribute
|
||||
{
|
||||
Attribute ()
|
||||
: state(true), name(""), value("")
|
||||
{}
|
||||
bool state;
|
||||
string name;
|
||||
string value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether an attribute pattern matches a shape.
|
||||
*/
|
||||
static bool
|
||||
checkAttribute (const VpfFeature &feature, int index, const Attribute &att)
|
||||
{
|
||||
bool result = false;
|
||||
const VpfValue &value = feature.getPropertyValue(att.name, index);
|
||||
switch (value.getType()) {
|
||||
case VpfValue::TEXT:
|
||||
result = (att.value == value.getText());
|
||||
break;
|
||||
case VpfValue::INT:
|
||||
result = (atoi(att.value.c_str()) == value.getInt());
|
||||
break;
|
||||
case VpfValue::REAL:
|
||||
result = (strtod(att.value.c_str(), 0) == value.getReal());
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
return (att.state ? result : !result);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a point.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*/
|
||||
static const FGPolygon
|
||||
makePolygon (const VpfPoint &p, int width)
|
||||
{
|
||||
FGPolygon result;
|
||||
|
||||
double x, y, az;
|
||||
double lon = p.x;
|
||||
double lat = p.y;
|
||||
|
||||
result.erase();
|
||||
|
||||
geo_direct_wgs_84(0, lat, lon, 90, width/2, &y, &x, &az);
|
||||
double dlon = x - lon;
|
||||
|
||||
geo_direct_wgs_84(0, lat, lon, 0, width/2, &y, &x, &az);
|
||||
double dlat = y - lat;
|
||||
|
||||
result.add_node(0, Point3D(lon - dlon, lat - dlat, 0));
|
||||
result.add_node(0, Point3D(lon + dlon, lat - dlat, 0));
|
||||
result.add_node(0, Point3D(lon + dlon, lat + dlat, 0));
|
||||
result.add_node(0, Point3D(lon - dlon, lat + dlat, 0));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon out of a line.
|
||||
*
|
||||
* Note that simple geometry doesn't work here, because the scale is
|
||||
* not even -- the points on the x-axis (longitude) become closer and
|
||||
* closer as the y-axis (latitude) approaches the poles, meeting in
|
||||
* a single point at y=90 and y=-90. As a result, this function
|
||||
* uses the WGS80 functions, rather than simple Pythagorean stuff.
|
||||
*/
|
||||
static const FGPolygon
|
||||
makePolygon (const VpfLine &line, int width)
|
||||
{
|
||||
FGPolygon shape;
|
||||
|
||||
vector<FGPolygon> segment_list;
|
||||
|
||||
int nPoints = line.getPointCount();
|
||||
int i;
|
||||
for (i = 0; i < nPoints - 1; i++) {
|
||||
const VpfPoint p1 = line.getPoint(i);
|
||||
const VpfPoint p2 = line.getPoint(i+1);
|
||||
|
||||
double angle1, angle2, dist, x, y, az;
|
||||
|
||||
geo_inverse_wgs_84(0, p1.y, p1.x, p2.y, p2.x, &angle1, &angle2, &dist);
|
||||
shape.erase();
|
||||
|
||||
// Wind each rectangle counterclockwise
|
||||
|
||||
// Corner 1
|
||||
geo_direct_wgs_84(0, p1.y, p1.x, ANGLE(angle1+90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 2
|
||||
geo_direct_wgs_84(0, p2.y, p2.x, ANGLE(angle1+90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 3
|
||||
geo_direct_wgs_84(0, p2.y, p2.x, ANGLE(angle1-90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Corner 4
|
||||
geo_direct_wgs_84(0, p1.y, p1.x, ANGLE(angle1-90), width/2, &y, &x, &az);
|
||||
shape.add_node(0, Point3D(x, y, 0));
|
||||
|
||||
// Save this rectangle
|
||||
segment_list.push_back(shape);
|
||||
}
|
||||
|
||||
// Build one big polygon out of all the rectangles by intersecting
|
||||
// the lines running through the bottom and top sides
|
||||
|
||||
shape.erase();
|
||||
|
||||
// Connect the bottom part.
|
||||
int nSegments = segment_list.size();
|
||||
Point3D intersection;
|
||||
shape.add_node(0, segment_list[0].get_pt(0, 0));
|
||||
for (i = 0; i < nSegments - 1; i++) {
|
||||
if (getIntersection(segment_list[i].get_pt(0, 0),
|
||||
segment_list[i].get_pt(0, 1),
|
||||
segment_list[i+1].get_pt(0, 0),
|
||||
segment_list[i+1].get_pt(0, 1),
|
||||
intersection))
|
||||
shape.add_node(0, intersection);
|
||||
else
|
||||
shape.add_node(0, segment_list[i].get_pt(0, 1));
|
||||
}
|
||||
shape.add_node(0, segment_list[nSegments-1].get_pt(0, 1));
|
||||
|
||||
// Connect the top part
|
||||
shape.add_node(0, segment_list[nSegments-1].get_pt(0, 2));
|
||||
for (i = nSegments - 1; i > 0; i--) {
|
||||
if (getIntersection(segment_list[i].get_pt(0, 2),
|
||||
segment_list[i].get_pt(0, 3),
|
||||
segment_list[i-1].get_pt(0, 2),
|
||||
segment_list[i-1].get_pt(0, 3),
|
||||
intersection))
|
||||
shape.add_node(0, intersection);
|
||||
else
|
||||
shape.add_node(0, segment_list[i].get_pt(0, 3));
|
||||
}
|
||||
shape.add_node(0, segment_list[0].get_pt(0, 3));
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Import all polygons.
|
||||
*/
|
||||
static const FGPolygon
|
||||
makePolygon (const VpfPolygon &polygon)
|
||||
{
|
||||
FGPolygon shape;
|
||||
|
||||
shape.erase();
|
||||
int nContours = polygon.getContourCount();
|
||||
int contour_num = 0;
|
||||
for (int i = 0; i < nContours; i++) {
|
||||
const VpfContour contour = polygon.getContour(i);
|
||||
int nPoints = contour.getPointCount();
|
||||
for (int j = 0; j < nPoints; j++) {
|
||||
const VpfPoint p = contour.getPoint(j);
|
||||
shape.add_node(contour_num, Point3D(p.x, p.y, p.z));
|
||||
}
|
||||
shape.set_hole_flag(contour_num, (i > 0));
|
||||
contour_num++;
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Main program.
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Print the command-line usage and exit.
|
||||
*/
|
||||
static void
|
||||
usage (const char * prog)
|
||||
{
|
||||
cerr << "Usage: " << prog << " [opts] <db> <library> <coverage> <feature>"
|
||||
<< endl;
|
||||
cerr << "Options:" << endl;
|
||||
cerr << "--min-lon=<longitude> (default: -180.0)" << endl;
|
||||
cerr << "--min-lat=<latitude> (default: -90.0)" << endl;
|
||||
cerr << "--max-lon=<longitude> (default: 180.0)" << endl;
|
||||
cerr << "--max-lat=<latitude> (default: 90.0)" << endl;
|
||||
cerr << "--area=<area_type> (default: Default)" << endl;
|
||||
cerr << "--point-width=<meters> (default: 500)" << endl;
|
||||
cerr << "--line-width=<meters> (default: 50)" << endl;
|
||||
cerr << "--work-dir=<dir> (default: .)" << endl;
|
||||
cerr << "--att=<item>:<value> (may be repeated)" << endl;
|
||||
cerr << "--att=!<item>:<value> (may be repeated)" << endl;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse an attribute value specification from the command line.
|
||||
*/
|
||||
static const Attribute
|
||||
parseAttribute (const char * prog, string arg)
|
||||
{
|
||||
Attribute att;
|
||||
|
||||
if (arg[0] == '!') {
|
||||
att.state = false;
|
||||
arg = arg.substr(1);
|
||||
} else {
|
||||
att.state = true;
|
||||
}
|
||||
|
||||
int pos = arg.find(':');
|
||||
if (pos == -1) {
|
||||
cerr << "Bad attribute specification: " << arg << endl;
|
||||
usage(prog);
|
||||
}
|
||||
|
||||
att.name = arg.substr(0, pos);
|
||||
att.value = arg.substr(pos + 1);
|
||||
|
||||
return att;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main entry point.
|
||||
*/
|
||||
int
|
||||
main (int argc, const char **argv)
|
||||
{
|
||||
vector<Attribute> attributes;
|
||||
VpfRectangle bounds;
|
||||
|
||||
// Enable logging.
|
||||
sglog().setLogLevels( SG_ALL, SG_DEBUG );
|
||||
|
||||
|
||||
// Default values
|
||||
bool invert = false;
|
||||
bounds.minX = -180;
|
||||
bounds.minY = -90;
|
||||
bounds.maxX = 180;
|
||||
bounds.maxY = 90;
|
||||
AreaType area_type = DefaultArea;
|
||||
int width = -1; // use default
|
||||
string work_dir = ".";
|
||||
|
||||
|
||||
//
|
||||
// Process command-line options.
|
||||
//
|
||||
int argPos = 1;
|
||||
while (argPos < argc) {
|
||||
string arg = argv[argPos];
|
||||
|
||||
if (arg.find("--min-lon=") == 0) {
|
||||
bounds.minX = strtod(arg.substr(10).c_str(), 0);
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--min-lat=") == 0) {
|
||||
bounds.minY = strtod(arg.substr(10).c_str(), 0);
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--max-lon=") == 0) {
|
||||
bounds.maxX = strtod(arg.substr(10).c_str(), 0);
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--max-lat=") == 0) {
|
||||
bounds.maxY = strtod(arg.substr(10).c_str(), 0);
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--area=") == 0) {
|
||||
area_type = get_area_type(arg.substr(7).c_str());
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--width=") == 0) {
|
||||
width = atoi(arg.substr(8).c_str());
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--work-dir=") == 0) {
|
||||
work_dir = arg.substr(11);
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--invert") == 0) {
|
||||
invert = true;
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg.find("--att=") == 0) {
|
||||
attributes.push_back(parseAttribute(argv[0], arg.substr(6)));
|
||||
argPos++;
|
||||
}
|
||||
|
||||
else if (arg == "--") {
|
||||
argPos++;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (arg.find("-") == 0) {
|
||||
cerr << "Unrecognized option: " << arg << endl;
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Process command-line arguments.
|
||||
//
|
||||
|
||||
if (argPos != (argc - 4))
|
||||
usage(argv[0]);
|
||||
|
||||
const char * database_name = argv[argPos++];
|
||||
const char * library_name = argv[argPos++];
|
||||
const char * coverage_name = argv[argPos++];
|
||||
const char * feature_name = argv[argPos++];
|
||||
|
||||
// Make sure the destination
|
||||
// directory exists.
|
||||
#ifdef _MSC_VER
|
||||
fg_mkdir(work_dir.c_str());
|
||||
#else
|
||||
string command = "mkdir -p " + work_dir;
|
||||
system(command.c_str());
|
||||
#endif
|
||||
|
||||
//
|
||||
// Make the TerraGear polygon for the bounds.
|
||||
//
|
||||
FGPolygon bounds_poly;
|
||||
bounds_poly.add_node(0, Point3D(bounds.minX, bounds.minY, 0));
|
||||
bounds_poly.add_node(0, Point3D(bounds.maxX, bounds.minY, 0));
|
||||
bounds_poly.add_node(0, Point3D(bounds.maxX, bounds.maxY, 0));
|
||||
bounds_poly.add_node(0, Point3D(bounds.minX, bounds.maxY, 0));
|
||||
|
||||
|
||||
//
|
||||
// Show settings.
|
||||
//
|
||||
cout << "Database path: " << database_name << endl;
|
||||
cout << "Library name: " << library_name << endl;
|
||||
cout << "Coverage name: " << coverage_name << endl;
|
||||
cout << "Feature name: " << feature_name << endl;
|
||||
cout << "Working directory: " << work_dir << endl;
|
||||
cout << "Area type: " << get_area_name(area_type) << endl;
|
||||
cout << "Point and line width (-1 for default): " << width << endl;
|
||||
cout << "Bounding rectangle: " << bounds << endl;
|
||||
for (int x = 0; x < attributes.size(); x++) {
|
||||
cout << "Attribute " << attributes[x].name
|
||||
<< (attributes[x].state ? " = " : " != ")
|
||||
<< attributes[x].value << endl;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Main processing loop.
|
||||
//
|
||||
|
||||
// Initialize the persistant polygon counter.
|
||||
string counter_file = work_dir + "/../poly_counter";
|
||||
poly_index_init( counter_file );
|
||||
|
||||
try {
|
||||
VpfDataBase db(database_name);
|
||||
VpfLibrary lib = db.getLibrary(library_name);
|
||||
VpfFeature feature = lib.getCoverage(coverage_name)
|
||||
.getFeature(feature_name);
|
||||
|
||||
const VpfRectangle rect = lib.getBoundingRectangle();
|
||||
if (!overlap(rect, bounds)) {
|
||||
cerr << "Library coverage does not overlap with area" << endl;
|
||||
cerr << "Library: " << rect << endl;
|
||||
cerr << "Requested: " << bounds << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nTopologies = feature.getTopologyCount();
|
||||
int type = feature.getTopologyType();
|
||||
cerr << "Searching through " << nTopologies << " topologies" << endl;
|
||||
int nAttributes = attributes.size();
|
||||
|
||||
FGPolygon mask;
|
||||
for (int i = 0; i < nTopologies; i++) {
|
||||
if ((i % 1000) == 0)
|
||||
cerr << i << "..." << endl;
|
||||
if (feature.isTiled()) {
|
||||
VpfRectangle rect = feature.getTile(i).getBoundingRectangle();
|
||||
if (!overlap(rect, bounds))
|
||||
continue;
|
||||
}
|
||||
|
||||
bool skip = false;
|
||||
for (int j = 0; j < nAttributes; j++) {
|
||||
if (!checkAttribute(feature, i, attributes[j])) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
FGPolygon shape;
|
||||
switch (type) {
|
||||
// FIXME: check for attributes as well
|
||||
case VpfFeature::POINT: {
|
||||
const VpfPoint p = feature.getPoint(i);
|
||||
if (!inside(p, bounds))
|
||||
continue;
|
||||
shape = makePolygon(p, (width == -1 ? 500 : width));
|
||||
break;
|
||||
}
|
||||
case VpfFeature::LINE: {
|
||||
const VpfLine line = feature.getLine(i);
|
||||
if (!overlap(line.getBoundingRectangle(), bounds))
|
||||
continue;
|
||||
shape = makePolygon(line, (width == -1 ? 50 : width));
|
||||
break;
|
||||
}
|
||||
case VpfFeature::POLYGON: {
|
||||
const VpfPolygon polygon = feature.getPolygon(i);
|
||||
if (!overlap(polygon.getBoundingRectangle(), bounds))
|
||||
continue;
|
||||
shape = makePolygon(polygon);
|
||||
break;
|
||||
}
|
||||
case VpfFeature::LABEL: {
|
||||
const VpfPoint p = feature.getLabel(i).getPoint();
|
||||
if (!inside(p, bounds))
|
||||
continue;
|
||||
shape = makePolygon(p, (width == -1 ? 500 : width));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw VpfException("Unsupported topology type");
|
||||
}
|
||||
|
||||
if (invert) {
|
||||
mask = polygon_union(mask, shape);
|
||||
} else {
|
||||
shape = polygon_int(shape, bounds_poly);
|
||||
if (shape.total_size() >= 3) {
|
||||
cout << "Polygon with " << shape.total_size() << " points in "
|
||||
<< shape.contours() << " contour(s)" << endl;
|
||||
split_polygon(work_dir, area_type, shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we are inverting, we have to
|
||||
// wait until the end (and hope for
|
||||
// not too large a polygon)
|
||||
if (invert) {
|
||||
mask = polygon_diff(bounds_poly, mask);
|
||||
if (mask.total_size() >= 3) {
|
||||
cout << "Inverse polygon with " << mask.total_size() << " points in "
|
||||
<< mask.contours() << " contour(s)" << endl;
|
||||
split_polygon(work_dir, area_type, mask);
|
||||
} else {
|
||||
cout << "Inverse polygon is empty" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (VpfException &e) {
|
||||
cerr << "Processing failed with VPF exception: " << e.getMessage() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// end of tgvpf.cxx
|
Loading…
Reference in a new issue