1
0
Fork 0

- some clipperfixes for tgconstruct. bring in clipper 4.8.9

Hopefully, we can start another clc06 test with this fix
- add lots of debug, in case more clipper issues uncovered
  added --debug-areas= allows turning on debug for an area
  can dump the accumulator when using it.
- fixed the swirlies round 2 workaround on tile output, rather than
  stopping the load of polygons at arbitrary threshold.
  (hopefully, we'll have a fix for this in simgear soon)
- modified ogr-decode (when using --texture-lines) to insert triangles
  instead of self-intersecting trapezoids when the turn angle between
  segments is too steep (hit this issue when experimenting with cgal-clipping)
  we were adding a lot of self intersecting polys on line data
- needed to add gdal library to all executables that link against Polygon
  TODO - combne Geometry and Polygon libs - they are completely joined, now.
This commit is contained in:
Peter Sadrozinski 2012-09-28 19:51:13 -04:00 committed by Christian Schmitt
parent 55bfcd80e7
commit b44c6c00d0
18 changed files with 931 additions and 179 deletions

View file

@ -4,6 +4,6 @@ include_directories(${PROJECT_SOURCE_DIR}/src/Lib)
include_directories(${PROJECT_SOURCE_DIR}/src/BuildTiles)
add_subdirectory(Osgb36)
add_subdirectory(Parallel)
add_subdirectory(Match)
add_subdirectory(Main)
add_subdirectory(Parallel)
add_subdirectory(Match)
add_subdirectory(Main)

View file

@ -20,6 +20,22 @@ target_link_libraries(tg-construct
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS tg-construct RUNTIME DESTINATION bin)
add_executable(cliptst
cliptst.cxx)
target_link_libraries(cliptst
Polygon Geometry
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS tg-construct RUNTIME DESTINATION bin)
INSTALL(FILES usgsmap.txt DESTINATION ${PKGDATADIR} )

View file

@ -0,0 +1,319 @@
//---------------------------------------------------------------------------
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <string.h>
#include <Polygon/clipper.hpp>
#include <Polygon/polygon.hxx>
#include <Geometry/poly_support.hxx>
//#include "windows.h"
//#include <conio.h>
//---------------------------------------------------------------------------
using namespace std;
using namespace ClipperLib;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
inline long64 Round(double val)
{
if ((val < 0)) return (long64)(val - 0.5); else return (long64)(val + 0.5);
}
//------------------------------------------------------------------------------
int PrecisionFirstValue(const char * filename)
{
char line[80];
FILE *f = fopen(filename, "r");
if (!f) return 0;
if (fgets(line, 80, f) == 0) return 0; //skip poly count
if (fgets(line, 80, f) == 0) return 0; //skip length first polygon
if (fgets(line, 80, f) == 0) return 0; //get coords first vertex
fclose(f);
int i = 0;
while (line[i] >= ' ' && line[i] != '.') i++;
if (line[i] != '.') return 0;
i++;
int j = i;
while (line[j] >= '0' && line[j] <= '9') j++;
return j - i;
}
//------------------------------------------------------------------------------
bool IsBlankLine(char* line)
{
while (*line)
if (*line > ' ') return false;
else line++;
return true;
}
//------------------------------------------------------------------------------
bool LoadFromFile(Polygons &ppg, char * filename, double scale)
{
ppg.clear();
FILE *f = fopen(filename, "r");
if (!f) return false;
int polyCnt, vertCnt;
char junk [80];
double X, Y;
if (fscanf(f, "%d", &polyCnt) == 1 && polyCnt > 0)
{
ppg.resize(polyCnt);
for (int i = 0; i < polyCnt; i++) {
if (fscanf(f, "%d", &vertCnt) != 1 || vertCnt <= 0) break;
ppg[i].resize(vertCnt);
for (int j = 0; j < vertCnt; j++) {
if (fscanf(f, "%lf%*[, ]%lf", &X, &Y) != 2) break;
ppg[i][j].X = Round(X * scale);
ppg[i][j].Y = Round(Y * scale);
fgets(junk, 80, f);
}
}
}
fclose(f);
return true;
}
//------------------------------------------------------------------------------
bool LoadFromFile2(Polygons &ppg, char * filename, double scale)
{
ppg.clear();
FILE *f = fopen(filename, "r");
if (!f) return false;
char line [80];
double X, Y;
Polygon pg;
while (fgets(line, sizeof line, f))
{
if (IsBlankLine(line))
{
if (pg.size() > 0)
{
ppg.push_back(pg);
pg.clear();
}
continue;
}
if (sscanf(line, "%lf%*[, ]%lf", &X, &Y) != 2) break;
pg.push_back(IntPoint(Round(X * scale), Round(Y * scale)));
}
if (pg.size() > 0) ppg.push_back(pg);
fclose(f);
return true;
}
//------------------------------------------------------------------------------
void SaveToFile(char *filename, Polygons &pp, int precision)
{
double scale = std::pow(double(10), precision);
FILE *f = fopen(filename, "w");
if (!f) return;
fprintf(f, "%d\n", pp.size());
for (unsigned i = 0; i < pp.size(); ++i)
{
fprintf(f, "%d\n", pp[i].size());
if (precision != 0) {
for (unsigned j = 0; j < pp[i].size(); ++j)
fprintf(f, "%.*lf, %.*lf,\n",
precision, (double)pp[i][j].X /scale,
precision, (double)pp[i][j].Y /scale);
}
else
{
for (unsigned j = 0; j < pp[i].size(); ++j)
fprintf(f, "%lld, %lld,\n", pp[i][j].X, pp[i][j].Y );
}
}
fclose(f);
}
//---------------------------------------------------------------------------
void SaveToFile(char *filename, ExPolygons &pp, int precision)
{
double scale = std::pow(double(10), precision);
FILE *f = fopen(filename, "w");
if (!f) return;
int cnt = 0;
for (unsigned i = 0; i < pp.size(); ++i)
cnt += pp[i].holes.size() +1;
fseek(f, 0, SEEK_SET);
fprintf(f, "%d\n", cnt);
for (unsigned i = 0; i < pp.size(); ++i)
{
fprintf(f, "%d\n", pp[i].outer.size());
if (precision != 0) {
for (unsigned j = 0; j < pp[i].outer.size(); ++j)
fprintf(f, "%.*lf, %.*lf,\n",
precision, (double)pp[i].outer[j].X /scale,
precision, (double)pp[i].outer[j].Y /scale);
}
else
{
for (unsigned j = 0; j < pp[i].outer.size(); ++j)
fprintf(f, "%lld, %lld,\n", pp[i].outer[j].X, pp[i].outer[j].Y );
}
for (unsigned k = 0; k < pp[i].holes.size(); ++k)
{
fprintf(f, "%d\n", pp[i].holes[k].size());
if (precision != 0) {
for (unsigned j = 0; j < pp[i].holes[k].size(); ++j)
fprintf(f, "%.*lf, %.*lf,\n",
precision, (double)pp[i].holes[k][j].X /scale,
precision, (double)pp[i].holes[k][j].Y /scale);
}
else
{
for (unsigned j = 0; j < pp[i].holes[k].size(); ++j)
fprintf(f, "%lld, %lld,\n", pp[i].holes[k][j].X, pp[i].holes[k][j].Y );
}
}
}
fclose(f);
}
static void SaveToFileOstream(char *filename, Polygons &pp)
{
std::ofstream file;
file.open (filename);
file << pp;
file.close();
}
//---------------------------------------------------------------------------
#ifdef __BORLANDC__
int _tmain(int argc, _TCHAR* argv[])
#else
int main(int argc, char* argv[])
#endif
{
if (argc < 4)
{
cout << "\nUSAGE:\n"
<< "clipper subject_file clip_file CLIPTYPE [SUBJ_FILL CLIP_FILL] [SVG]\n\n"
<< " CLIPTYPE = i[ntersection] or u[nion] or d[ifference] or x[or], and\n"
<< " SUBJ_FILL & CLIP_FILL = evenodd or nonzero (default = nonzero)\n"
<< " SVG = Create SVG file\n"
<< " where parameters in [] are optional\n\n";
//format 1
//cout << "\nFORMAT OF INPUT AND OUTPUT FILES:\n"
// << "Polygon Count {must be on the first line}\n"
// << "Vertex Count {of first polygon}\n"
// << "X[,] Y[,] {first vertex}\n"
// << "X[,] Y[,] {next vertex}\n"
// << "...\n"
// << "Vertex Count {of second polygon, if there is one}\n"
// << "X[,] Y[,] {first vertex of second polygon}\n"
// << "...\n\n";
//format 2
cout << "\nFORMAT OF INPUT AND OUTPUT FILES:\n"
<< "Each polygon is separated by a blank line \n"
<< "X[,] Y[,] {first vertex}\n"
<< "X[,] Y[,] {next vertex}\n"
<< "...\n"
<< "\n"
<< "X[,] Y[,] {first vertex of second polygon}\n"
<< "...\n\n";
cout << "\nEXAMPLE:\n"
<< "clipper subj.txt clip.txt u evenodd evenodd SVG\n\n";
return 1;
}
int precision = PrecisionFirstValue(argv[1]);
double scale = std::pow(double(10), precision);
bool show_svg =
((argc > 4 && strcasecmp(argv[4], "SVG") == 0) ||
(argc > 5 && strcasecmp(argv[5], "SVG") == 0) ||
(argc > 6 && strcasecmp(argv[6], "SVG") == 0));
Polygons subject, clip;
if (!LoadFromFile2(subject, argv[1], scale))
{
cerr << "\nCan't open the file " << argv[1]
<< " or the file format is invalid.\n";
return 1;
}
if (!LoadFromFile2(clip, argv[2], scale))
{
cerr << "\nCan't open the file " << argv[2]
<< " or the file format is invalid.\n";
return 1;
}
if (show_svg) {
tgShapefileInit();
clipper_to_shapefile( subject, "./clptst_subject" );
clipper_to_shapefile( clip, "./clptst_clip" );
}
ClipType clipType;
switch (toupper(argv[3][0])) {
case 'X': clipType = ctXor; break;
case 'U': clipType = ctUnion; break;
case 'D': clipType = ctDifference; break;
default: clipType = ctIntersection;
}
PolyFillType subj_pft = pftNonZero, clip_pft = pftNonZero;
if (argc > 4&& strcasecmp(argv[4], "EVENODD") == 0)
subj_pft = pftEvenOdd;
if (argc > 5 && strcasecmp(argv[5], "EVENODD") == 0)
clip_pft = pftEvenOdd;
cout << "\nclipping ... ";
Clipper c;
c.AddPolygons(subject, ptSubject);
c.AddPolygons(clip, ptClip);
Polygons solution;
// double elapsed = 0;
// _LARGE_INTEGER qpf, qpc1, qpc2;
// bool HPMEnabled = QueryPerformanceFrequency(&qpf);
// if (HPMEnabled) QueryPerformanceCounter(&qpc1);
bool succeeded = c.Execute(clipType, solution, subj_pft, clip_pft);
// if (HPMEnabled) {
// QueryPerformanceCounter(&qpc2);
// elapsed = double(qpc2.QuadPart - qpc1.QuadPart) / qpf.QuadPart;
// cout << "\nEllapsed: " << elapsed;
// }
if (succeeded) {
SaveToFile("solution.txt", solution, precision);
SaveToFileOstream("solution_ostream", solution );
cout << "succeeded.\nSolution saved to - solution.txt.\n\n";
cout << "\n";
if( show_svg ) {
cout << "Generating shapefile\n";
clipper_to_shapefile( solution, "./clptst_solution" );
}
} else
cout << "failed.\n\n";
return 0;
}
//---------------------------------------------------------------------------

View file

@ -91,15 +91,42 @@ TGConstruct::~TGConstruct() {
nodes.clear();
}
void TGConstruct::set_debug( std::string path, std::vector<string> defs )
void TGConstruct::set_debug( std::string path, std::vector<string> area_defs, std::vector<string> shape_defs )
{
SG_LOG(SG_GENERAL, SG_ALERT, "Set debug Path " << path);
debug_path = path;
/* Find any ids for our tile */
for (unsigned int i=0; i< defs.size(); i++) {
string dsd = defs[i];
for (unsigned int i=0; i< area_defs.size(); i++) {
string dsd = area_defs[i];
size_t d_pos = dsd.find(":");
string tile = dsd.substr(0, d_pos);
if( tile == bucket.gen_index_str() ) {
dsd.erase(0, d_pos+1);
if ( dsd == "all" ) {
debug_all = true;
} else {
std::stringstream ss(dsd);
int i;
while (ss >> i)
{
SG_LOG(SG_GENERAL, SG_ALERT, "Adding debug file " << i);
debug_areas.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
}
}
}
for (unsigned int i=0; i< shape_defs.size(); i++) {
string dsd = shape_defs[i];
size_t d_pos = dsd.find(":");
string tile = dsd.substr(0, d_pos);
@ -145,6 +172,25 @@ bool TGConstruct::IsDebugShape( unsigned int id )
return is_debug;
}
bool TGConstruct::IsDebugArea( unsigned int area )
{
bool is_debug = false;
/* Check global flag */
if ( debug_all ) {
is_debug = true;
} else {
for (unsigned int i=0; i<debug_areas.size(); i++) {
if ( debug_areas[i] == area ) {
is_debug = true;
break;
}
}
}
return is_debug;
}
void TGConstruct::WriteDebugShape( const char* layer_name, const TGShape& shape )
{
char name[64];
@ -153,7 +199,7 @@ void TGConstruct::WriteDebugShape( const char* layer_name, const TGShape& shape
ds_id = tgShapefileOpenDatasource( ds_name );
l_id = tgShapefileOpenLayer( ds_id, layer_name );
tgShapefileCreateFeature( ds_id, l_id, shape.clip_mask, "test" );
tgShapefileCreateFeature( ds_id, l_id, shape.clip_mask, name );
// close after each write
ds_id = tgShapefileCloseDatasource( ds_id );
@ -243,7 +289,7 @@ bool TGConstruct::load_poly(const string& path) {
int hole_flag;
int num_polys;
double startx, starty, startz, x, y, z, lastx, lasty, lastz;
sg_gzifstream in( path );
if ( !in ) {
@ -293,23 +339,8 @@ bool TGConstruct::load_poly(const string& path) {
poly_type = get_area_type( poly_name );
int area = (int)poly_type;
string material;
string material = get_area_name( area );
// only allow 1000 shapes per material
int extension = polys_in.area_size( area ) / 1000;
if (extension)
{
char buff[32];
sprintf( buff, "%s_%d", get_area_name( area ).c_str(), extension );
material = buff;
}
else
{
material = get_area_name( area );
}
// Generate a new Shape for the poly
TGShape shape;
TGSuperPoly sp;
@ -1275,6 +1306,8 @@ bool TGConstruct::ClipLandclassPolys( void ) {
int i, j;
Point3D p;
point2d min, max;
bool debug_area, debug_shape;
static int accum_idx = 0;
#if !USE_ACCUMULATOR
TGPolygon accum;
@ -1342,7 +1375,7 @@ bool TGConstruct::ClipLandclassPolys( void ) {
}
// Dump the masks
if ( debug_all || debug_shapes.size() ) {
if ( debug_all || debug_shapes.size() || debug_areas.size() ) {
WriteDebugPoly( "land_mask", "", land_mask );
WriteDebugPoly( "water_mask", "", water_mask );
WriteDebugPoly( "island_mask", "", island_mask );
@ -1350,10 +1383,13 @@ bool TGConstruct::ClipLandclassPolys( void ) {
// process polygons in priority order
for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) {
debug_area = IsDebugArea( i );
for( j = 0; j < (int)polys_in.area_size(i); ++j ) {
TGPolygon current = polys_in.get_mask(i, j);
debug_shape = IsDebugShape( polys_in.get_shape( i, j ).id );
SG_LOG( SG_CLIPPER, SG_INFO, "Clipping " << get_area_name( (AreaType)i ) << ":" << j+1 << " of " << polys_in.area_size(i) );
SG_LOG( SG_CLIPPER, SG_INFO, "Clipping " << get_area_name( (AreaType)i ) << ":" << j+1 << " of " << polys_in.area_size(i) << " accum_idx: " << accum_idx );
tmp = current;
@ -1368,18 +1404,39 @@ bool TGConstruct::ClipLandclassPolys( void ) {
tmp = tgPolygonDiffClipper( tmp, island_mask );
}
if ( IsDebugShape( polys_in.get_shape( i, j ).id ) ) {
if ( debug_area || debug_shape ) {
char layer[32];
char name[32];
sprintf(layer, "pre_clip_%d", polys_in.get_shape( i, j ).id );
sprintf(name, "shape %d,%d", i,j);
WriteDebugPoly( "pre-clip", name, tmp );
WriteDebugPoly( layer, name, tmp );
sprintf(layer, "pre_clip_accum_%d_%d", accum_idx, polys_in.get_shape( i, j ).id );
sprintf(name, "shape_accum %d,%d", i,j);
#if USE_ACCUMULATOR
tgPolygonDumpAccumulator( ds_name, layer, name );
#else
WriteDebugPoly( layer, name, accum );
#endif
}
// simplify polygon before clipping
tmp = tgPolygonSimplify( tmp );
#if USE_ACCUMULATOR
clipped = tgPolygonDiffClipperWithAccumulator( tmp );
#else
clipped = tgPolygonDiffClipper( tmp, accum );
clipped = tgPolygonDiff( tmp, accum );
#endif
if ( debug_area || debug_shape ) {
char layer[32];
char name[32];
sprintf(layer, "post_clip_%d", polys_in.get_shape( i, j ).id );
sprintf(name, "shape %d,%d", i,j);
WriteDebugPoly( layer, name, clipped );
}
// only add to output list if the clip left us with a polygon
if ( clipped.contours() > 0 ) {
@ -1405,22 +1462,39 @@ bool TGConstruct::ClipLandclassPolys( void ) {
// shape.sps.push_back( sp );
polys_clipped.add_shape( i, shape );
if ( IsDebugShape( shape.id ) ) {
if ( debug_area || debug_shape ) {
WriteDebugShape( "clipped", shape );
}
}
}
#if USE_ACCUMULATOR
tgPolygonAddToClipperAccumulator( tmp );
if ( debug_shape ) {
tgPolygonAddToClipperAccumulator( tmp, true );
} else {
tgPolygonAddToClipperAccumulator( tmp, false );
}
#else
accum = tgPolygonUnionClipper( tmp, accum );
#endif
if ( debug_area || debug_shape ) {
char layer[32];
char name[32];
sprintf(layer, "post_clip_accum_%d_%d", accum_idx, polys_in.get_shape( i, j ).id );
sprintf(name, "shape_accum %d,%d", i,j);
#if USE_ACCUMULATOR
tgPolygonDumpAccumulator( ds_name, layer, name );
#else
WriteDebugPoly( layer, name, accum );
#endif
}
accum_idx++;
}
}
if ( debug_all || debug_shapes.size() ) {
if ( debug_all || debug_shapes.size() || debug_areas.size() ) {
// Dump the sliver list
WriteDebugPolys( "poly_slivers", slivers );
}
@ -1455,7 +1529,7 @@ bool TGConstruct::ClipLandclassPolys( void ) {
// neighboring polygons
if ( slivers.size() > 0 ) {
if ( debug_all || debug_shapes.size() ) {
if ( debug_all || debug_shapes.size() || debug_areas.size() ) {
// Dump the sliver list
WriteDebugPolys( "remains_slivers", slivers );
}
@ -1764,7 +1838,9 @@ void TGConstruct::TesselatePolys( void )
unsigned int id = polys_clipped.get_shape( area, shape ).id;
if ( IsDebugShape( id ) ) {
WriteDebugShape( "preteselate", polys_clipped.get_shape(area, shape) );
char layer[32];
sprintf( layer, " pretess-%d", id );
WriteDebugShape( layer, polys_clipped.get_shape(area, shape) );
}
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
@ -1821,8 +1897,12 @@ void TGConstruct::WriteBtgFile( void )
int_list tri_tc, strip_tc;
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
unsigned int area_tris;
// only tesselate non holes
if ( !is_hole_area( area ) ) {
area_tris = 0;
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
SG_LOG( SG_CLIPPER, SG_INFO, "Ouput nodes for " << get_area_name( (AreaType)area ) << ":" <<
@ -1830,7 +1910,7 @@ void TGConstruct::WriteBtgFile( void )
TGPolyNodes tri_nodes = polys_clipped.get_tri_idxs(area, shape, segment);
TGPolygon tri_txs = polys_clipped.get_texcoords(area, shape, segment);
string material = polys_clipped.get_material(area, shape, segment);
string material;
for (int k = 0; k < tri_nodes.contours(); ++k) {
tri_v.clear();
@ -1851,7 +1931,28 @@ void TGConstruct::WriteBtgFile( void )
tris_v.push_back( tri_v );
tris_n.push_back( tri_n );
tris_tc.push_back( tri_tc );
tri_materials.push_back( material );
switch ( area_tris / 32768 ) {
case 0:
material = polys_clipped.get_material(area, shape, segment);
break;
case 1:
material = polys_clipped.get_material(area, shape, segment) + "_1";
break;
case 2:
material = polys_clipped.get_material(area, shape, segment) + "_2";
break;
case 3:
material = polys_clipped.get_material(area, shape, segment) + "_3";
break;
}
tri_materials.push_back( material );
area_tris++;
}
}
}
@ -1927,7 +2028,7 @@ void TGConstruct::WriteBtgFile( void )
{
throw sg_exception("error writing file. :-(");
}
if (debug_all || debug_shapes.size())
if (debug_all || debug_shapes.size() || debug_areas.size() )
{
result = obj.write_ascii( base, txtname, bucket );
if ( !result )
@ -2026,7 +2127,7 @@ void TGConstruct::ConstructBucketStage1() {
SG_LOG(SG_GENERAL, SG_ALERT, "\nConstructing tile ID " << bucket.gen_index_str() << " in " << bucket.gen_base_path() );
/* If we have some debug IDs, create a datasource */
if ( debug_shapes.size() || debug_all ) {
if ( debug_shapes.size() || debug_all || debug_areas.size() ) {
sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() );
SG_LOG(SG_GENERAL, SG_ALERT, "Debug_string: " << ds_name );
} else {

View file

@ -271,6 +271,7 @@ private:
bool debug_all;
// list of shapes to dump during debug
std::vector<unsigned int> debug_areas;
std::vector<unsigned int> debug_shapes;
// OGR encode variables
@ -346,6 +347,8 @@ private:
// debug
bool IsDebugShape( unsigned int id );
bool IsDebugArea( unsigned int area );
void WriteDebugShape( const char* layer_name, const TGShape& shape );
void WriteDebugPoly( const char* layer_name, const char* name, const TGPolygon& poly );
void WriteDebugPolys( const char* layer_name, const poly_list& polys );
@ -415,7 +418,7 @@ public:
inline point_list get_point_normals() const { return nodes.get_normals(); }
// Debug
void set_debug( std::string path, std::vector<std::string> defs );
void set_debug( std::string path, std::vector<std::string> area_defs, std::vector<std::string> shape_defs );
};

View file

@ -168,7 +168,8 @@ int main(int argc, char **argv) {
long tile_id = -1;
string debug_dir = ".";
vector<string> debug_defs;
vector<string> debug_shape_defs;
vector<string> debug_area_defs;
// flag indicating whether UK grid should be used for in-UK
// texture coordinate generation
@ -230,8 +231,10 @@ int main(int argc, char **argv) {
ignoreLandmass = true;
} else if (arg.find("--debug-dir=") == 0) {
debug_dir = arg.substr(12);
} else if (arg.find("--debug-areas=") == 0) {
debug_area_defs.push_back( arg.substr(14) );
} else if (arg.find("--debug-shapes=") == 0) {
debug_defs.push_back( arg.substr(15) );
debug_shape_defs.push_back( arg.substr(15) );
} else if (arg.find("--") == 0) {
usage(argv[0]);
} else {
@ -292,7 +295,7 @@ int main(int argc, char **argv) {
c->set_nudge( nudge );
c->set_bucket( b );
c->set_debug( debug_dir, debug_defs );
c->set_debug( debug_dir, debug_area_defs, debug_shape_defs );
c->ConstructBucketStage1();
delete c;
@ -321,7 +324,7 @@ int main(int argc, char **argv) {
c->set_nudge( nudge );
c->set_bucket( b_min );
c->set_debug( debug_dir, debug_defs );
c->set_debug( debug_dir, debug_area_defs, debug_shape_defs );
c->ConstructBucketStage1();
delete c;
@ -355,7 +358,7 @@ int main(int argc, char **argv) {
c->set_nudge( nudge );
c->set_bucket( b_cur );
c->set_debug( debug_dir, debug_defs );
c->set_debug( debug_dir, debug_area_defs, debug_shape_defs );
c->ConstructBucketStage1();
delete c;
@ -384,7 +387,7 @@ int main(int argc, char **argv) {
c->set_nudge( nudge );
c->set_bucket( b );
c->set_debug( debug_dir, debug_defs );
c->set_debug( debug_dir, debug_area_defs, debug_shape_defs );
c->ConstructBucketStage1();
delete c;

View file

@ -16,6 +16,16 @@
#include <stdlib.h>
// use cgal for intersection, old implementation returns true, even when line SEGMENTS don't intersect
// CGAL intersection can do that with lines, but we want to use segments (end at the first and last point)
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/intersections.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
typedef Kernel::Point_2 Point_2;
typedef CGAL::Segment_2<Kernel> Segment_2;
#define MP_STRETCH (0.000001)
using std::string;
@ -57,6 +67,34 @@ getIntersection (const Point3D &p0, const Point3D &p1,
}
}
// use CGAL
bool getIntersection_cgal(const Point3D &p0, const Point3D &p1,
const Point3D &p2, const Point3D &p3,
Point3D &intersection)
{
Point_2 a1( p0.x(), p0.y() );
Point_2 b1( p1.x(), p1.y() );
Point_2 a2( p2.x(), p2.y() );
Point_2 b2( p3.x(), p3.y() );
Segment_2 seg1( a1, b1 );
Segment_2 seg2( a2, b2 );
CGAL::Object result = CGAL::intersection(seg1, seg2);
if (const CGAL::Point_2<Kernel> *ipoint = CGAL::object_cast<CGAL::Point_2<Kernel> >(&result)) {
// handle the point intersection case with *ipoint.
return true;
} else {
if (const CGAL::Segment_2<Kernel> *iseg = CGAL::object_cast<CGAL::Segment_2<Kernel> >(&result)) {
// handle the segment intersection case with *iseg.
return false;
} else {
// handle the no intersection case.
return false;
}
}
}
/**
* Create a polygon out of a point.
@ -503,6 +541,7 @@ makePolygons (const Line &line, double width, poly_list& polys)
}
}
#if 0
void
makePolygonsTP (const Line &line, double width, poly_list& polys, texparams_list &tps)
{
@ -600,6 +639,147 @@ makePolygonsTP (const Line &line, double width, poly_list& polys, texparams_list
prev_inner = cur_inner;
}
}
#endif
void
makePolygonsTP (const Line &line, double width, poly_list& polys, texparams_list &tps)
{
int nPoints = line.getPointCount();
int i;
int turn_dir;
Point3D cur_inner;
Point3D cur_outer;
Point3D prev_inner = Point3D(0.0f, 0.0f, 0.0f);
Point3D prev_outer = Point3D(0.0f, 0.0f, 0.0f);
Point3D calc_inner;
Point3D calc_outer;
double last_end_v = 0.0f;
double heading = 0.0f;
double az2 = 0.0f;
double dist = 0.0f;
TGPolygon poly;
TGPolygon accum;
TGTexParams tp;
// generate poly and texparam lists for each line segment
for (i=0; i<nPoints; i++)
{
last_end_v = 0.0f;
turn_dir = 0;
sglog().setLogLevels( SG_ALL, SG_INFO );
SG_LOG(SG_GENERAL, SG_DEBUG, "makePolygonsTP: calculating offsets for segment " << i);
// for each point on the PointsList, generate a quad from
// start to next, offset by 1/2 width from the edge
if (i == 0)
{
// first point on the list - offset heading is 90deg
cur_outer = OffsetPointFirst( line.getPoint(i), line.getPoint(i+1), -width/2.0f );
cur_inner = OffsetPointFirst( line.getPoint(i), line.getPoint(i+1), width/2.0f );
}
else if (i == nPoints-1)
{
// last point on the list - offset heading is 90deg
cur_outer = OffsetPointLast( line.getPoint(i-1), line.getPoint(i), -width/2.0f );
cur_inner = OffsetPointLast( line.getPoint(i-1), line.getPoint(i), width/2.0f );
}
else
{
// middle section
cur_outer = OffsetPointMiddle( line.getPoint(i-1), line.getPoint(i), line.getPoint(i+1), -width/2.0f, turn_dir );
cur_inner = OffsetPointMiddle( line.getPoint(i-1), line.getPoint(i), line.getPoint(i+1), width/2.0f, turn_dir );
}
if ( (prev_inner.x() != 0.0f) && (prev_inner.y() != 0.0f) )
{
// draw the poly in simplified arrow format
TGPolygon ref_trap;
ref_trap.add_node( 0, prev_inner );
ref_trap.add_node( 0, prev_outer );
ref_trap.add_node( 0, cur_outer );
ref_trap.add_node( 0, cur_inner );
}
if ( (prev_inner.x() != 0.0f) && (prev_inner.y() != 0.0f) )
{
Point3D prev_mp = midpoint( prev_outer, prev_inner );
Point3D cur_mp = midpoint( cur_outer, cur_inner );
Point3D intersect;
geo_inverse_wgs_84( prev_mp.y(), prev_mp.x(), cur_mp.y(), cur_mp.x(), &heading, &az2, &dist);
poly.erase();
poly.add_node( 0, prev_inner );
poly.add_node( 0, prev_outer );
// we need to extend one of the points so we're sure we don't create adjacent edges
if (turn_dir == 0)
{
// turned right - offset outer
geo_inverse_wgs_84( prev_outer.y(), prev_outer.x(), cur_outer.y(), cur_outer.x(), &heading, &az2, &dist);
// CHECK for self inersecting poly - angle too steep for this width
if ( getIntersection_cgal( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
{
// yes - make a triangle with inner edge = 0
poly.add_node( 0, cur_outer );
cur_inner = prev_inner;
}
else
{
poly.add_node( 0, cur_outer );
poly.add_node( 0, cur_inner );
}
}
else
{
// turned left - offset inner
geo_inverse_wgs_84( prev_inner.y(), prev_inner.x(), cur_inner.y(), cur_inner.x(), &heading, &az2, &dist);
if ( getIntersection_cgal( prev_inner, prev_outer, cur_inner, cur_outer, intersect ) )
{
// yes - make a triangle with outer edge = 0
poly.add_node( 0, cur_inner );
cur_outer = prev_outer;
}
else
{
poly.add_node( 0, cur_outer );
poly.add_node( 0, cur_inner );
}
}
// draw the poly in simplified arrow format
TGPolygon ref_tri;
ref_tri.add_node( 0, prev_inner );
ref_tri.add_node( 0, prev_outer );
Point3D mp = midpoint( cur_inner, cur_outer );
ref_tri.add_node( 0, mp );
polys.push_back(poly);
tp = TGTexParams( prev_inner, width, 20.0f, heading );
tp.set_minv(last_end_v);
tps.push_back(tp);
last_end_v = 1.0f - (fmod( (double)(dist - last_end_v), (double)1.0f ));
}
prev_outer = cur_outer;
prev_inner = cur_inner;
}
sglog().setLogLevels( SG_ALL, SG_INFO );
}
Rectangle

View file

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 4.8.3 *
* Date : 27 May 2012 *
* Version : 4.8.9 *
* Date : 25 September 2012 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2012 *
* *
@ -49,8 +49,8 @@
namespace ClipperLib {
static long64 const loRange = 1518500249; //sqrt(2^63 -1)/2
static long64 const hiRange = 6521908912666391106LL; //sqrt(2^127 -1)/2
static long64 const loRange = 0x3FFFFFFF;
static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL;
static double const pi = 3.141592653589793238;
enum Direction { dRightToLeft, dLeftToRight };
@ -61,7 +61,7 @@ enum Direction { dRightToLeft, dLeftToRight };
inline long64 Abs(long64 val)
{
if (val < 0) return -val; else return val;
return val < 0 ? -val : val;
}
//------------------------------------------------------------------------------
@ -114,6 +114,12 @@ class Int128
return lo < val.lo;
}
bool operator >= (const Int128 &val) const
{ return !(*this < val);}
bool operator <= (const Int128 &val) const
{ return !(*this > val);}
Int128& operator += (const Int128 &rhs)
{
hi += rhs.hi;
@ -349,10 +355,10 @@ bool Orientation(const Polygon &poly)
throw "Coordinate exceeds range bounds.";
Int128 cross = Int128(vec1.X) * Int128(vec2.Y) -
Int128(vec2.X) * Int128(vec1.Y);
return cross > 0;
return cross >= 0;
}
else
return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0;
return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0;
}
//------------------------------------------------------------------------------
@ -394,9 +400,9 @@ bool Orientation(OutRec *outRec, bool UseFullInt64Range)
ip2.Y = opNext->pt.Y - op->pt.Y;
if (UseFullInt64Range)
return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) > 0;
return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) >= 0;
else
return (ip1.X * ip2.Y - ip2.X * ip1.Y) > 0;
return (ip1.X * ip2.Y - ip2.X * ip1.Y) >= 0;
}
//------------------------------------------------------------------------------
@ -619,11 +625,22 @@ bool IntersectPoint(TEdge &edge1, TEdge &edge2,
ip.X = Round(edge1.dx * b2 + b1);
}
return
//can be *so close* to the top of one edge that the rounded Y equals one ytop ...
(ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) ||
(ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) ||
(ip.Y > edge1.ytop && ip.Y > edge2.ytop);
if (ip.Y < edge1.ytop || ip.Y < edge2.ytop)
{
if (edge1.ytop > edge2.ytop)
{
ip.X = edge1.xtop;
ip.Y = edge1.ytop;
return TopX(edge2, edge1.ytop) < edge1.xtop;
} else
{
ip.X = edge2.xtop;
ip.Y = edge2.ytop;
return TopX(edge1, edge2.ytop) > edge2.xtop;
}
}
else
return true;
}
//------------------------------------------------------------------------------
@ -1221,7 +1238,7 @@ bool PolySort(OutRec *or1, OutRec *or2)
{
if (or1->pts != or2->pts)
{
if (or1->pts) return true; else return false;
return or1->pts ? true : false;
}
else return false;
}
@ -1235,8 +1252,7 @@ bool PolySort(OutRec *or1, OutRec *or2)
int result = i1 - i2;
if (result == 0 && (or1->isHole != or2->isHole))
{
if (or1->isHole) return false;
else return true;
return or1->isHole ? false : true;
}
else return result < 0;
}
@ -1309,10 +1325,7 @@ bool Clipper::ExecuteInternal(bool fixHoleLinkages)
if (outRec->bottomPt == outRec->bottomFlag &&
(Orientation(outRec, m_UseFullRange) != (Area(*outRec, m_UseFullRange) > 0)))
{
DisposeBottomPt(*outRec);
FixupOutPolygon(*outRec);
};
DisposeBottomPt(*outRec);
if (outRec->isHole ==
(m_ReverseOutput ^ Orientation(outRec, m_UseFullRange)))
@ -1579,8 +1592,10 @@ void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
e1->outIdx = -1;
e2->outIdx = -1;
}
else
AppendPolygon( e1, e2 );
else if (e1->outIdx < e2->outIdx)
AppendPolygon(e1, e2);
else
AppendPolygon(e2, e1);
}
//------------------------------------------------------------------------------
@ -1949,6 +1964,17 @@ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
}
//------------------------------------------------------------------------------
bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
{
do
{
outRec1 = outRec1->FirstLeft;
if (outRec1 == outRec2) return true;
} while (outRec1);
return false;
}
//------------------------------------------------------------------------------
void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
{
//get the start and ends of both output polygons ...
@ -1956,8 +1982,8 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutRec *outRec2 = m_PolyOuts[e2->outIdx];
OutRec *holeStateRec;
if (outRec1->FirstLeft == outRec2) holeStateRec = outRec2;
else if (outRec2->FirstLeft == outRec1) holeStateRec = outRec1;
if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
else holeStateRec = GetLowermostRec(outRec1, outRec2);
OutPt* p1_lft = outRec1->pts;
@ -2077,6 +2103,7 @@ void Clipper::DisposeBottomPt(OutRec &outRec)
next->prev = prev;
prev->next = next;
outRec.bottomPt = next;
FixupOutPolygon(outRec);
}
//------------------------------------------------------------------------------
@ -2310,8 +2337,7 @@ void Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2)
TEdge* GetNextInAEL(TEdge *e, Direction dir)
{
if( dir == dLeftToRight ) return e->nextInAEL;
else return e->prevInAEL;
return dir == dLeftToRight ? e->nextInAEL : e->prevInAEL;
}
//------------------------------------------------------------------------------
@ -2520,7 +2546,7 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
}
//------------------------------------------------------------------------------
bool Process1Before2(IntersectNode &node1, IntersectNode &node2)
bool ProcessParam1BeforeParam2(IntersectNode &node1, IntersectNode &node2)
{
bool result;
if (node1.pt.Y == node2.pt.Y)
@ -2528,12 +2554,12 @@ bool Process1Before2(IntersectNode &node1, IntersectNode &node2)
if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1)
{
result = node2.pt.X > node1.pt.X;
if (node2.edge1->dx > 0) return !result; else return result;
return node2.edge1->dx > 0 ? !result : result;
}
else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2)
{
result = node2.pt.X > node1.pt.X;
if (node2.edge2->dx > 0) return !result; else return result;
return node2.edge2->dx > 0 ? !result : result;
}
else return node2.pt.X > node1.pt.X;
}
@ -2549,7 +2575,7 @@ void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
newNode->pt = pt;
newNode->next = 0;
if( !m_IntersectNodes ) m_IntersectNodes = newNode;
else if( Process1Before2(*newNode, *m_IntersectNodes) )
else if( ProcessParam1BeforeParam2(*newNode, *m_IntersectNodes) )
{
newNode->next = m_IntersectNodes;
m_IntersectNodes = newNode;
@ -2557,7 +2583,7 @@ void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
else
{
IntersectNode* iNode = m_IntersectNodes;
while( iNode->next && Process1Before2(*iNode->next, *newNode) )
while( iNode->next && ProcessParam1BeforeParam2(*iNode->next, *newNode) )
iNode = iNode->next;
newNode->next = iNode->next;
iNode->next = newNode;
@ -2859,8 +2885,7 @@ bool Clipper::FixupIntersections()
bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
{
if (e2.xcurr == e1.xcurr) return e2.dx > e1.dx;
else return e2.xcurr < e1.xcurr;
return e2.xcurr == e1.xcurr ? e2.dx > e1.dx : e2.xcurr < e1.xcurr;
}
//------------------------------------------------------------------------------
@ -3029,8 +3054,9 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
//outRec2 is contained by outRec1 ...
outRec2->isHole = !outRec1->isHole;
outRec2->FirstLeft = outRec1;
if (outRec2->isHole == Orientation(outRec2, m_UseFullRange))
ReversePolyPtLinks(*outRec2->pts);
if (outRec2->isHole ==
(m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange)))
ReversePolyPtLinks(*outRec2->pts);
} else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRange))
{
//outRec1 is contained by outRec2 ...
@ -3038,8 +3064,9 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
outRec1->isHole = !outRec2->isHole;
outRec2->FirstLeft = outRec1->FirstLeft;
outRec1->FirstLeft = outRec2;
if (outRec1->isHole == Orientation(outRec1, m_UseFullRange))
ReversePolyPtLinks(*outRec1->pts);
if (outRec1->isHole ==
(m_ReverseOutput ^ Orientation(outRec1, m_UseFullRange)))
ReversePolyPtLinks(*outRec1->pts);
//make sure any contained holes now link to the correct polygon ...
if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2);
} else
@ -3063,6 +3090,12 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
//now cleanup redundant edges too ...
FixupOutPolygon(*outRec1);
FixupOutPolygon(*outRec2);
if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) > 0))
DisposeBottomPt(*outRec1);
if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) > 0))
DisposeBottomPt(*outRec2);
} else
{
//joined 2 polygons together ...
@ -3099,16 +3132,16 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages)
}
//------------------------------------------------------------------------------
void ReversePoints(Polygon& p)
void ReversePolygon(Polygon& p)
{
std::reverse(p.begin(), p.end());
}
//------------------------------------------------------------------------------
void ReversePoints(Polygons& p)
void ReversePolygons(Polygons& p)
{
for (Polygons::size_type i = 0; i < p.size(); ++i)
ReversePoints(p[i]);
ReversePolygon(p[i]);
}
//------------------------------------------------------------------------------
@ -3126,12 +3159,13 @@ struct DoublePoint
Polygon BuildArc(const IntPoint &pt,
const double a1, const double a2, const double r)
{
int steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1)));
Polygon result(steps);
int n = steps - 1;
double da = (a2 - a1) / n;
long64 steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1)));
if (steps > 0x100000) steps = 0x100000;
int n = (unsigned)steps;
Polygon result(n);
double da = (a2 - a1) / (n -1);
double a = a1;
for (int i = 0; i <= n; ++i)
for (int i = 0; i < n; ++i)
{
result[i].X = pt.X + Round(std::cos(a)*r);
result[i].Y = pt.Y + Round(std::sin(a)*r);
@ -3259,7 +3293,7 @@ PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
{
out_polys.erase(out_polys.begin());
ReversePoints(out_polys);
ReversePolygons(out_polys);
} else
out_polys.clear();
@ -3286,23 +3320,23 @@ void DoSquare(double mul = 1.0)
(long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
{
double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
a1 = std::fabs(a2 - a1);
if (a1 > pi) a1 = pi * 2 - a1;
double dx = std::tan((pi - a1)/4) * std::fabs(m_delta * mul);
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
(long64)(pt1.Y + normals[m_k].X * dx));
AddPoint(pt1);
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
(long64)(pt2.Y -normals[m_j].X * dx));
AddPoint(pt2);
double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
a1 = std::fabs(a2 - a1);
if (a1 > pi) a1 = pi * 2 - a1;
double dx = std::tan((pi - a1)/4) * std::fabs(m_delta * mul);
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
(long64)(pt1.Y + normals[m_k].X * dx));
AddPoint(pt1);
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
(long64)(pt2.Y -normals[m_j].X * dx));
AddPoint(pt2);
}
else
{
AddPoint(pt1);
AddPoint(m_p[m_i][m_j]);
AddPoint(pt2);
AddPoint(pt1);
AddPoint(m_p[m_i][m_j]);
AddPoint(pt2);
}
}
//------------------------------------------------------------------------------
@ -3373,25 +3407,25 @@ void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
}
//------------------------------------------------------------------------------
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys)
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType)
{
Clipper c;
c.AddPolygon(in_poly, ptSubject);
c.Execute(ctUnion, out_polys);
c.Execute(ctUnion, out_polys, fillType, fillType);
}
//------------------------------------------------------------------------------
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys)
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType)
{
Clipper c;
c.AddPolygons(in_polys, ptSubject);
c.Execute(ctUnion, out_polys);
c.Execute(ctUnion, out_polys, fillType, fillType);
}
//------------------------------------------------------------------------------
void SimplifyPolygons(Polygons &polys)
void SimplifyPolygons(Polygons &polys, PolyFillType fillType)
{
SimplifyPolygons(polys, polys);
SimplifyPolygons(polys, polys, fillType);
}
//------------------------------------------------------------------------------

View file

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 4.8.3 *
* Date : 27 May 2012 *
* Version : 4.8.9 *
* Date : 25 September 2012 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2012 *
* *
@ -79,12 +79,12 @@ bool Orientation(const Polygon &poly);
double Area(const Polygon &poly);
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
double delta, JoinType jointype = jtSquare, double MiterLimit = 2);
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys);
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys);
void SimplifyPolygons(Polygons &polys);
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
void ReversePoints(Polygon& p);
void ReversePoints(Polygons& p);
void ReversePolygon(Polygon& p);
void ReversePolygons(Polygons& p);
//used internally ...
enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 };

View file

@ -26,10 +26,13 @@
// http://www.cs.man.ac.uk/aig/staff/alan/software/
//
#include <iostream>
#include <fstream>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include <Geometry/point3d.hxx>
#include <Geometry/poly_support.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/structure/exception.hxx>
@ -40,6 +43,7 @@
#include "point2d.hxx"
using std::endl;
using std::cout;
// Constructor
TGPolygon::TGPolygon( void )
@ -395,10 +399,10 @@ typedef enum {
} clip_op;
//#define FIXEDPT (10000000000000)
#define FIXEDPT (10000000000000000)
#define FIXED1M ( 90090)
static ClipperLib::IntPoint MakeClipperPoint( Point3D pt )
{
ClipperLib::long64 x, y;
@ -451,19 +455,20 @@ void make_clipper_poly( const TGPolygon& in, ClipperLib::Polygons *out )
// holes need to be orientation: false
if ( Orientation( contour ) ) {
//SG_LOG(SG_GENERAL, SG_INFO, "Building clipper poly - hole contour needs to be reversed" );
ReversePoints( contour );
ReversePolygon( contour );
}
} else {
// boundaries need to be orientation: true
if ( !Orientation( contour ) ) {
//SG_LOG(SG_GENERAL, SG_INFO, "Building clipper poly - boundary contour needs to be reversed" );
ReversePoints( contour );
ReversePolygon( contour );
}
}
out->push_back(contour);
}
}
#if 0
void make_tg_poly_from_clipper_ex( const ClipperLib::ExPolygons& in, TGPolygon *out )
{
int res_contour = 0;
@ -496,6 +501,7 @@ void make_tg_poly_from_clipper_ex( const ClipperLib::ExPolygons& in, TGPolygon *
}
}
}
#endif
void make_tg_poly_from_clipper( const ClipperLib::Polygons& in, TGPolygon *out )
{
@ -523,6 +529,7 @@ void make_tg_poly_from_clipper( const ClipperLib::Polygons& in, TGPolygon *out )
}
}
#if 0
ClipperLib::Polygons clipper_simplify( ClipperLib::ExPolygons &in )
{
ClipperLib::Polygons out;
@ -535,16 +542,16 @@ ClipperLib::Polygons clipper_simplify( ClipperLib::ExPolygons &in )
// first the boundary
contour = pg->outer;
if ( !Orientation( contour ) ) {
ReversePoints( contour );
ReversePolygon( contour );
}
out.push_back( contour );
// then the holes
for (unsigned int j = 0; j < pg->holes.size(); j++)
{
contour = pg->holes[j];
if ( Orientation( contour ) ) {
ReversePoints( contour );
ReversePolygon( contour );
}
out.push_back( contour );
}
@ -555,6 +562,7 @@ ClipperLib::Polygons clipper_simplify( ClipperLib::ExPolygons &in )
return out;
}
#endif
TGPolygon polygon_clip_clipper( clip_op poly_op, const TGPolygon& subject, const TGPolygon& clip )
{
@ -566,15 +574,15 @@ TGPolygon polygon_clip_clipper( clip_op poly_op, const TGPolygon& subject, const
ClipperLib::Polygons clipper_clip;
make_clipper_poly( clip, &clipper_clip );
ClipperLib::ExPolygons clipper_result;
ClipperLib::Polygons clipper_result;
ClipperLib::ClipType op;
if ( poly_op == POLY_DIFF ) {
op = ClipperLib::ctDifference;
op = ClipperLib::ctDifference;
} else if ( poly_op == POLY_INT ) {
op = ClipperLib::ctIntersection;
op = ClipperLib::ctIntersection;
} else if ( poly_op == POLY_XOR ) {
op = ClipperLib::ctXor;
op = ClipperLib::ctXor;
} else if ( poly_op == POLY_UNION ) {
op = ClipperLib::ctUnion;
} else {
@ -582,16 +590,13 @@ TGPolygon polygon_clip_clipper( clip_op poly_op, const TGPolygon& subject, const
}
ClipperLib::Clipper c;
c.Clear();
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
c.Clear();
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
c.AddPolygons(clipper_clip, ClipperLib::ptClip);
c.Execute(op, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
c.Execute(op, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
// verify each result is simple
ClipperLib::Polygons simple_result = clipper_simplify( clipper_result );
make_tg_poly_from_clipper( simple_result, &result );
make_tg_poly_from_clipper( clipper_result, &result );
return result;
}
@ -633,26 +638,80 @@ void tgPolygonFreeClipperAccumulator( void )
clipper_accumulator.clear();
}
void tgPolygonAddToClipperAccumulator( const TGPolygon& subject )
void tgPolygonDumpAccumulator( char* ds, char* layer, char* name )
{
void* ds_id = tgShapefileOpenDatasource( ds );
void* l_id = tgShapefileOpenLayer( ds_id, layer );
TGPolygon accum;
make_tg_poly_from_clipper( clipper_accumulator, &accum );
tgShapefileCreateFeature( ds_id, l_id, accum, name );
// close after each write
ds_id = tgShapefileCloseDatasource( ds_id );
}
void tgPolygonAddToClipperAccumulator( const TGPolygon& subject, bool dump )
{
std::ofstream subjectFile, clipFile, resultFile;
ClipperLib::Polygons clipper_subject;
make_clipper_poly( subject, &clipper_subject );
ClipperLib::ExPolygons clipper_result;
ClipperLib::Clipper c;
c.Clear();
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
c.AddPolygons(clipper_accumulator, ClipperLib::ptClip);
c.Execute(ClipperLib::ctUnion, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
if (dump) {
subjectFile.open ("subject.txt");
subjectFile << clipper_subject;
subjectFile.close();
// verify each result is simple
ClipperLib::Polygons simple_result = clipper_simplify( clipper_result );
clipFile.open ("clip.txt");
clipFile << clipper_accumulator;
clipFile.close();
}
clipper_accumulator.clear();
clipper_accumulator = simple_result;
if ( !c.Execute(ClipperLib::ctUnion, clipper_accumulator, ClipperLib::pftNonZero, ClipperLib::pftNonZero) ) {
SG_LOG(SG_GENERAL, SG_ALERT, "Add to Accumulator returned FALSE" );
exit(-1);
}
if (dump) {
resultFile.open ("result.txt");
resultFile << clipper_accumulator;
resultFile.close();
}
}
void clipper_to_shapefile( ClipperLib::Polygons polys, char* ds )
{
ClipperLib::Polygons contour;
TGPolygon tgcontour;
char layer[32];
void* ds_id = tgShapefileOpenDatasource( ds );
for (unsigned int i = 0; i < polys.size(); ++i) {
if ( Orientation( polys[i] ) ) {
sprintf( layer, "%04d_hole", i );
} else {
sprintf( layer, "%04d_boundary", i );
}
void* l_id = tgShapefileOpenLayer( ds_id, layer );
contour.clear();
contour.push_back( polys[i] );
tgcontour.erase();
make_tg_poly_from_clipper( contour, &tgcontour );
tgShapefileCreateFeature( ds_id, l_id, tgcontour, "contour" );
}
// close after each write
ds_id = tgShapefileCloseDatasource( ds_id );
}
TGPolygon tgPolygonDiffClipperWithAccumulator( const TGPolygon& subject )
@ -662,19 +721,20 @@ TGPolygon tgPolygonDiffClipperWithAccumulator( const TGPolygon& subject )
ClipperLib::Polygons clipper_subject;
make_clipper_poly( subject, &clipper_subject );
ClipperLib::ExPolygons clipper_result;
ClipperLib::Polygons clipper_result;
ClipperLib::Clipper c;
c.Clear();
c.AddPolygons(clipper_subject, ClipperLib::ptSubject);
c.AddPolygons(clipper_accumulator, ClipperLib::ptClip);
c.Execute(ClipperLib::ctDifference, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
if ( !c.Execute(ClipperLib::ctDifference, clipper_result, ClipperLib::pftNonZero, ClipperLib::pftNonZero) )
{
SG_LOG(SG_GENERAL, SG_ALERT, "Diff With Accumulator returned FALSE" );
exit(-1);
}
// verify each result is simple
ClipperLib::Polygons simple_result = clipper_simplify( clipper_result );
make_tg_poly_from_clipper( simple_result, &result );
make_tg_poly_from_clipper( clipper_result, &result );
return result;
}
@ -695,6 +755,16 @@ TGPolygon tgPolygonUnionClipper( const TGPolygon& subject, const TGPolygon& clip
return polygon_clip_clipper( POLY_UNION, subject, clip );
}
void tgPolygonDumpClipper(const TGPolygon &poly, char* file)
{
ClipperLib::Polygons clipper_subject;
make_clipper_poly( poly, &clipper_subject );
SG_LOG(SG_GENERAL, SG_ALERT, "DUMP POLY" );
SG_LOG(SG_GENERAL, SG_ALERT, clipper_subject );
SG_LOG(SG_GENERAL, SG_ALERT, "\n" );
}
// canonify the polygon winding, outer contour must be anti-clockwise,
// all inner contours must be clockwise.
TGPolygon polygon_canonify( const TGPolygon& in_poly ) {

View file

@ -258,9 +258,13 @@ TGPolygon tgPolygonUnion( const TGPolygon& subject, const TGPolygon& clip );
void tgPolygonInitClipperAccumulator( void );
void tgPolygonFreeClipperAccumulator( void );
void tgPolygonAddToClipperAccumulator( const TGPolygon& subject );
void tgPolygonDumpAccumulator( char* ds, char* layer, char*name );
void tgPolygonAddToClipperAccumulator( const TGPolygon& subject, bool dump );
TGPolygon tgPolygonDiffClipperWithAccumulator( const TGPolygon& subject );
// Save clipper to shapefile
void clipper_to_shapefile( ClipperLib::Polygons polys, char* datasource );
// Difference
TGPolygon tgPolygonDiffClipper( const TGPolygon& subject, const TGPolygon& clip );
@ -276,6 +280,8 @@ TGPolygon tgPolygonExpand(const TGPolygon &poly, double delta);
// Simplify
TGPolygon tgPolygonSimplify(const TGPolygon &poly);
void tgPolygonDumpClipper(const TGPolygon &poly);
// Output
std::ostream &operator<<(std::ostream &output, const TGPolygon &poly);

View file

@ -5,8 +5,9 @@ add_executable(e00lines
target_link_libraries(e00lines
e00
Polygon Geometry Output poly2tri vpf
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS e00lines RUNTIME DESTINATION bin)

View file

@ -6,8 +6,9 @@ add_executable(gshhs
target_link_libraries(gshhs
Polygon Geometry Output poly2tri
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS gshhs RUNTIME DESTINATION bin)
@ -17,8 +18,9 @@ add_executable(gshhs_debug
target_link_libraries(gshhs_debug
Polygon Geometry Output poly2tri
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS gshhs_debug RUNTIME DESTINATION bin)

View file

@ -193,6 +193,8 @@ void processLineStringWithTextureInfo(OGRLineString* poGeometry,
double pt_x = 0.0f, pt_y = 0.0f;
int i, j, numPoints, numSegs;
double max_dist;
double min_dist;
double cur_dist;
numPoints = poGeometry->getNumPoints();
if (numPoints < 2) {
@ -201,6 +203,8 @@ void processLineStringWithTextureInfo(OGRLineString* poGeometry,
}
max_dist = (double)width * 10.0f;
min_dist = (double)width * 1.5f;
cur_dist = 0.0f;
// because vector data can generate adjacent polys, lets stretch the two enpoints by a little bit
p0 = Point3D(poGeometry->getX(0),poGeometry->getY(0),0);
@ -225,11 +229,17 @@ void processLineStringWithTextureInfo(OGRLineString* poGeometry,
{
geo_direct_wgs_84( p0.y(), p0.x(), heading, dist*(j+1), &pt_y, &pt_x, &az2 );
line.addPoint( Point3D( pt_x, pt_y, 0.0f ) );
}
}
cur_dist = 0.0f;
}
else if (dist + cur_dist < max_dist)
{
cur_dist += dist;
}
else
{
line.addPoint(p1);
line.addPoint( p1 );
cur_dist = 0;
}
}

View file

@ -4,8 +4,9 @@ add_executable(photo
target_link_libraries(photo
Polygon Geometry Array Output poly2tri
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS photo RUNTIME DESTINATION bin)
@ -14,8 +15,9 @@ add_executable(wgs84offset
wgs84offset.cxx)
target_link_libraries(wgs84offset
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS wgs84offset RUNTIME DESTINATION bin)
@ -25,8 +27,9 @@ add_executable(findcorners
findcorners.cxx)
target_link_libraries(findcorners
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS findcorners RUNTIME DESTINATION bin)

View file

@ -2,8 +2,9 @@ add_executable(shape-decode shape-decode.cxx)
target_link_libraries(shape-decode
shape Polygon Geometry Output poly2tri vpf
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS shape-decode RUNTIME DESTINATION bin)
@ -12,8 +13,9 @@ add_executable(noaa-decode noaa-decode.cxx)
target_link_libraries(noaa-decode
shape Polygon Geometry Output poly2tri vpf
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS noaa-decode RUNTIME DESTINATION bin)

View file

@ -3,8 +3,9 @@ add_executable(tgvpf tgvpf.cxx)
target_link_libraries(tgvpf
Polygon Geometry Output poly2tri vpf
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${RT_LIBRARY})
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${RT_LIBRARY})
install(TARGETS tgvpf RUNTIME DESTINATION bin)

View file

@ -3,8 +3,9 @@ add_executable(tguserdef tguserdef.cxx)
target_link_libraries(tguserdef
Polygon Geometry Output poly2tri
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
)
install(TARGETS tguserdef RUNTIME DESTINATION bin)