- Fixed issues where an entire landclass poly wold no triangulate.
- Increase epsilon when looking for intermediate nodes (setup method for calling function to specify the bounding box and error epsilon in case this had adverse effects on genapts) This fixes many of the small vertical gaps (T-Junctions) - Fix an issue with merge slivers. The clip mask optimization broke merge slivers. WHen merging the slivers with a poly segment, it also needs to be merged with the clip mask, so when the segments are seperated from the mask, they include the sliver. - Added to the shapefile debug. --debug_shape=tileid:all generates shapefiles for every polygon in the tile This is usefull to setup individual debug polys on subsequent passes. Also added load, clip, and with_slivers and clean layers for debugging
This commit is contained in:
parent
79bdae93fc
commit
346ae44e14
10 changed files with 361 additions and 90 deletions
|
@ -72,6 +72,7 @@ TGConstruct::TGConstruct():
|
|||
useUKGrid(false),
|
||||
writeSharedEdges(true),
|
||||
useOwnSharedEdges(false),
|
||||
debug_all(false),
|
||||
ds_id((void*)-1)
|
||||
{ }
|
||||
|
||||
|
@ -102,6 +103,10 @@ void TGConstruct::set_debug( std::string path, std::vector<string> defs )
|
|||
|
||||
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;
|
||||
|
||||
|
@ -116,31 +121,62 @@ void TGConstruct::set_debug( std::string path, std::vector<string> defs )
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TGConstruct::IsDebugShape( unsigned int id )
|
||||
{
|
||||
bool is_debug = false;
|
||||
|
||||
/* Check global flag */
|
||||
if ( debug_all ) {
|
||||
is_debug = true;
|
||||
} else {
|
||||
for (unsigned int i=0; i<debug_shapes.size(); i++) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "have debug id " << debug_shapes[i] << " looking for " << id );
|
||||
|
||||
if ( debug_shapes[i] == id ) {
|
||||
is_debug = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is_debug;
|
||||
}
|
||||
|
||||
void TGConstruct::WriteDebugShape( const char* layer_name, unsigned int area, unsigned int shape )
|
||||
void TGConstruct::WriteDebugShape( const char* layer_name, const TGShape& shape )
|
||||
{
|
||||
char name[64];
|
||||
|
||||
ds_id = tgShapefileOpenDatasource( ds_name );
|
||||
l_id = tgShapefileOpenLayer( ds_id, layer_name );
|
||||
|
||||
shape.GetName( name );
|
||||
tgShapefileCreateFeature( ds_id, l_id, shape.clip_mask, name );
|
||||
|
||||
// close after each write
|
||||
ds_id = tgShapefileCloseDatasource( ds_id );
|
||||
}
|
||||
|
||||
void TGConstruct::WriteDebugPoly( const char* layer_name, const char* name, const TGPolygon& poly )
|
||||
{
|
||||
ds_id = tgShapefileOpenDatasource( ds_name );
|
||||
l_id = tgShapefileOpenLayer( ds_id, layer_name );
|
||||
|
||||
sprintf( feature_name, "%s_%d", get_area_name( area ).c_str(), polys_clipped.get_shape( area, shape ).id );
|
||||
tgShapefileCreateFeature( ds_id, l_id, polys_in.get_mask(area, shape), feature_name );
|
||||
tgShapefileCreateFeature( ds_id, l_id, poly, name );
|
||||
|
||||
// close after each write
|
||||
ds_id = tgShapefileCloseDatasource( ds_id );
|
||||
}
|
||||
|
||||
void TGConstruct::WriteDebugPolys( const char* layer_name, const poly_list& polys )
|
||||
{
|
||||
ds_id = tgShapefileOpenDatasource( ds_name );
|
||||
l_id = tgShapefileOpenLayer( ds_id, layer_name );
|
||||
|
||||
for( unsigned int i=0; i<polys.size(); i++ ) {
|
||||
sprintf( feature_name, "poly_%d", i );
|
||||
tgShapefileCreateFeature( ds_id, l_id, polys[i], feature_name );
|
||||
}
|
||||
|
||||
// close after each write
|
||||
ds_id = tgShapefileCloseDatasource( ds_id );
|
||||
|
@ -383,8 +419,8 @@ bool TGConstruct::load_poly(const string& path) {
|
|||
|
||||
sp.set_poly( poly );
|
||||
sp.set_material( material );
|
||||
|
||||
shape.sps.push_back( sp );
|
||||
|
||||
if ( with_tp ) {
|
||||
shape.textured = true;
|
||||
shape.tps.push_back( tp );
|
||||
|
@ -399,9 +435,14 @@ bool TGConstruct::load_poly(const string& path) {
|
|||
|
||||
// Once the full poly is loaded, build the clip mask
|
||||
shape.BuildMask();
|
||||
shape.area = area;
|
||||
shape.id = cur_id++;
|
||||
|
||||
polys_in.add_shape( area, shape );
|
||||
|
||||
if ( IsDebugShape( shape.id ) ) {
|
||||
WriteDebugShape( "loaded", shape );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1172,6 +1213,8 @@ void TGConstruct::merge_slivers( TGLandclass& clipped, poly_list& slivers_list
|
|||
int original_contours, result_contours;
|
||||
bool done;
|
||||
int area, shape, segment, i, j;
|
||||
int merged = 0;
|
||||
int total = 0;
|
||||
|
||||
for ( i = 0; i < (int)slivers_list.size(); i++ ) {
|
||||
slivers = slivers_list[i];
|
||||
|
@ -1179,6 +1222,8 @@ void TGConstruct::merge_slivers( TGLandclass& clipped, poly_list& slivers_list
|
|||
for ( j = 0; j < slivers.contours(); ++j ) {
|
||||
// make the sliver polygon
|
||||
contour = slivers.get_contour( j );
|
||||
total++;
|
||||
|
||||
sliver.erase();
|
||||
sliver.add_contour( contour, 0 );
|
||||
done = false;
|
||||
|
@ -1190,6 +1235,8 @@ void TGConstruct::merge_slivers( TGLandclass& clipped, poly_list& slivers_list
|
|||
}
|
||||
|
||||
for ( shape = 0; shape < (int)clipped.area_size(area) && !done; ++shape ) {
|
||||
unsigned int shape_id = clipped.get_shape( area, shape ).id;
|
||||
|
||||
for ( segment = 0; segment < (int)clipped.shape_size(area, shape) && !done; ++segment ) {
|
||||
|
||||
poly = clipped.get_poly( area, shape, segment );
|
||||
|
@ -1202,7 +1249,24 @@ void TGConstruct::merge_slivers( TGLandclass& clipped, poly_list& slivers_list
|
|||
result_contours = result.contours();
|
||||
|
||||
if ( original_contours == result_contours ) {
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "MERGED SLIVER " << i << ", " << j << " into area " << get_area_name( (AreaType)area ) << " id: " << shape_id << " segment: " << segment );
|
||||
|
||||
clipped.set_poly( area, shape, segment, result );
|
||||
merged++;
|
||||
|
||||
/* add the sliver to the clip_mask, too */
|
||||
TGPolygon mask = clipped.get_mask( area, shape );
|
||||
#if USE_CLIPPER
|
||||
result = tgPolygonUnionClipper( mask, sliver );
|
||||
#else
|
||||
result = tgPolygonUnion( mask, sliver );
|
||||
#endif
|
||||
clipped.set_mask( area, shape, result );
|
||||
|
||||
if ( IsDebugShape( shape_id ) ) {
|
||||
WriteDebugShape( "with_slivers", clipped.get_shape( area, shape ) );
|
||||
}
|
||||
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
@ -1210,10 +1274,14 @@ void TGConstruct::merge_slivers( TGLandclass& clipped, poly_list& slivers_list
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
slivers_list.clear();
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_INFO, " UNMERGED SLIVERS: " << total - merged );
|
||||
}
|
||||
|
||||
bool TGConstruct::ClipLandclassPolys( void ) {
|
||||
TGPolygon accum, clipped, tmp;
|
||||
TGPolygon clipped, tmp;
|
||||
TGPolygon remains;
|
||||
TGPolygon safety_base;
|
||||
poly_list slivers;
|
||||
|
@ -1221,13 +1289,21 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
Point3D p;
|
||||
point2d min, max;
|
||||
|
||||
#if !USE_ACCUMULATOR
|
||||
TGPolygon accum;
|
||||
#endif
|
||||
|
||||
// Get clip bounds
|
||||
min.x = bucket.get_center_lon() - 0.5 * bucket.get_width();
|
||||
min.y = bucket.get_center_lat() - 0.5 * bucket.get_height();
|
||||
max.x = bucket.get_center_lon() + 0.5 * bucket.get_width();
|
||||
max.y = bucket.get_center_lat() + 0.5 * bucket.get_height();
|
||||
|
||||
#if USE_ACCUMULATOR
|
||||
tgPolygonInitAccumulator();
|
||||
#else
|
||||
accum.erase();
|
||||
#endif
|
||||
|
||||
// set up clipping tile : and remember to add the nodes!
|
||||
safety_base.erase();
|
||||
|
@ -1318,19 +1394,28 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
#if USE_CLIPPER
|
||||
clipped = tgPolygonDiffClipper( tmp, accum );
|
||||
#else
|
||||
|
||||
#if USE_ACCUMULATOR
|
||||
clipped = tgPolygonDiffWithAccumulator( tmp );
|
||||
#else
|
||||
clipped = tgPolygonDiff( tmp, accum );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
// only add to output list if the clip left us with a polygon
|
||||
if ( clipped.contours() > 0 ) {
|
||||
|
||||
#if FIND_SLIVERS
|
||||
// move slivers from clipped polygon to slivers polygon
|
||||
tgPolygonFindSlivers( clipped, slivers );
|
||||
#endif
|
||||
|
||||
// add the sliverless result polygon to the clipped polys list
|
||||
if ( clipped.contours() > 0 ) {
|
||||
TGShape shape;
|
||||
TGSuperPoly sp;
|
||||
|
||||
sp.set_material( get_area_name( (AreaType)i ) );
|
||||
//sp.set_material( get_area_name( (AreaType)i ) );
|
||||
|
||||
// copy all of the superpolys and texparams
|
||||
shape.SetMask( clipped );
|
||||
|
@ -1339,47 +1424,81 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
shape.sps = polys_in.get_shape( i, j ).sps;
|
||||
shape.tps = polys_in.get_shape( i, j ).tps;
|
||||
|
||||
shape.sps.push_back( sp );
|
||||
// shape.sps.push_back( sp );
|
||||
polys_clipped.add_shape( i, shape );
|
||||
|
||||
if ( IsDebugShape( shape.id ) ) {
|
||||
WriteDebugShape( "clipped", shape );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_CLIPPER
|
||||
accum = tgPolygonUnionClipper( tmp, accum );
|
||||
// accum = tgPolygonUnionClipper( clipped, accum );
|
||||
#else
|
||||
|
||||
#if USE_ACCUMULATOR
|
||||
tgPolygonAddToAccumulator( tmp );
|
||||
// tgPolygonAddToAccumulator( clipped );
|
||||
#else
|
||||
accum = tgPolygonUnion( tmp, accum );
|
||||
// accum = tgPolygonUnion( clipped, accum );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ( debug_all || debug_shapes.size() ) {
|
||||
// Dump the sliver list
|
||||
WriteDebugPolys( "poly_slivers", slivers );
|
||||
}
|
||||
|
||||
#if FIND_SLIVERS
|
||||
// Now, merge any slivers with clipped polys
|
||||
merge_slivers(polys_clipped, slivers);
|
||||
#endif
|
||||
|
||||
slivers.clear();
|
||||
|
||||
// finally, what ever is left over goes to ocean
|
||||
|
||||
// clip to accum against original base tile
|
||||
// remains = new gpc_polygon;
|
||||
// remains->num_contours = 0;
|
||||
// remains->contour = NULL;
|
||||
#if USE_CLIPPER
|
||||
remains = tgPolygonDiffClipper( safety_base, accum );
|
||||
#else
|
||||
|
||||
#if USE_ACCUMULATOR
|
||||
remains = tgPolygonDiffWithAccumulator( safety_base );
|
||||
#else
|
||||
remains = tgPolygonDiff( safety_base, accum );
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
if ( remains.contours() > 0 ) {
|
||||
// cout << "remains contours = " << remains.contours() << endl;
|
||||
// move slivers from remains polygon to slivers polygon
|
||||
|
||||
#if FIND_SLIVERS
|
||||
tgPolygonFindSlivers( remains, slivers );
|
||||
#endif
|
||||
// cout << " After sliver move:" << endl;
|
||||
// cout << " remains = " << remains.contours() << endl;
|
||||
// cout << " slivers = " << slivers.contours() << endl;
|
||||
|
||||
#if FIND_SLIVERS
|
||||
// merge any slivers with previously clipped
|
||||
// neighboring polygons
|
||||
if ( slivers.size() > 0 ) {
|
||||
|
||||
if ( debug_all || debug_shapes.size() ) {
|
||||
// Dump the sliver list
|
||||
WriteDebugPolys( "remains_slivers", slivers );
|
||||
}
|
||||
|
||||
merge_slivers(polys_clipped, slivers);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( remains.contours() > 0 ) {
|
||||
TGSuperPoly sp;
|
||||
|
@ -1396,6 +1515,10 @@ bool TGConstruct::ClipLandclassPolys( void ) {
|
|||
}
|
||||
}
|
||||
|
||||
#if USE_ACCUMULATOR
|
||||
tgPolygonFreeAccumulator();
|
||||
#endif
|
||||
|
||||
// Once clipping is complete, intersect the individual segments with their clip masks
|
||||
for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) {
|
||||
for (unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||
|
@ -1666,7 +1789,7 @@ void TGConstruct::TesselatePolys( void )
|
|||
unsigned int id = polys_clipped.get_shape( area, shape ).id;
|
||||
|
||||
if ( IsDebugShape( id ) ) {
|
||||
WriteDebugShape( "preteselate", area, shape );
|
||||
WriteDebugShape( "preteselate", polys_clipped.get_shape(area, shape) );
|
||||
}
|
||||
|
||||
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||
|
@ -1834,16 +1957,20 @@ void TGConstruct::WriteBtgFile( void )
|
|||
}
|
||||
}
|
||||
|
||||
void TGConstruct::clean_clipped_polys() {
|
||||
void TGConstruct::CleanClippedPolys() {
|
||||
// Clean the polys
|
||||
unsigned int before, after;
|
||||
|
||||
for ( unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++ ) {
|
||||
for( unsigned int shape = 0; shape < polys_clipped.area_size(area); shape++ ) {
|
||||
unsigned int id = polys_clipped.get_shape( area, shape ).id;
|
||||
|
||||
for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) {
|
||||
TGPolygon poly = polys_clipped.get_poly(area, shape, segment);
|
||||
SG_LOG( SG_CLIPPER, SG_INFO, "Cleaning poly " << get_area_name( (AreaType)area ) <<
|
||||
":" << shape+1 << "-" << segment << " of " << polys_clipped.area_size(area) );
|
||||
|
||||
if ( area == 3 ) {
|
||||
before = poly.total_size();
|
||||
|
||||
if ( false ) {
|
||||
poly = remove_cycles( poly );
|
||||
poly = remove_dups( poly );
|
||||
poly = remove_bad_contours( poly );
|
||||
|
@ -1859,8 +1986,19 @@ void TGConstruct::clean_clipped_polys() {
|
|||
poly = remove_bad_contours( poly );
|
||||
}
|
||||
|
||||
after = poly.total_size();
|
||||
|
||||
if (before != after) {
|
||||
SG_LOG( SG_CLIPPER, SG_INFO, "Cleanined poly " << get_area_name( (AreaType)area ) <<
|
||||
":" << shape+1 << "-" << segment << " of " << polys_clipped.area_size(area) << " before: " << before << " after: " << after );
|
||||
}
|
||||
|
||||
polys_clipped.set_poly( area, shape, segment, poly );
|
||||
}
|
||||
|
||||
if ( IsDebugShape( id ) ) {
|
||||
WriteDebugShape( "cleaned", polys_clipped.get_shape( area, shape ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1899,7 +2037,7 @@ void TGConstruct::CalcTextureCoordinates( void )
|
|||
void TGConstruct::ConstructBucket() {
|
||||
|
||||
/* If we have some debug IDs, create a datasource */
|
||||
if ( debug_shapes.size() ) {
|
||||
if ( debug_shapes.size() || debug_all ) {
|
||||
sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() );
|
||||
}
|
||||
|
||||
|
@ -1927,6 +2065,11 @@ void TGConstruct::ConstructBucket() {
|
|||
// Clip the Landclass polygons
|
||||
ClipLandclassPolys();
|
||||
|
||||
// STEP 5)
|
||||
// Clean the polys - after this, we shouldn't change their shape (other than slightly for
|
||||
// fix T-Junctions - as This is the end of the first pass for multicore design
|
||||
CleanClippedPolys();
|
||||
|
||||
// STEP 5)
|
||||
// Merge in Shared data (just add the nodes to the nodelist)
|
||||
// When this step is complete, some nodes will have normals (from shared tiles)
|
||||
|
@ -1941,7 +2084,7 @@ void TGConstruct::ConstructBucket() {
|
|||
// TODO : Needs to be part of clipping
|
||||
// just before union : If we need to clean again after fixing tjunctions, make
|
||||
// sure we don't alter the shape
|
||||
clean_clipped_polys();
|
||||
// CleanClippedPolys();
|
||||
|
||||
// STEP 7)
|
||||
// Generate triangles - we can't generate the node-face lookup table
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <simgear/compiler.h>
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <Array/array.hxx>
|
||||
|
||||
|
@ -51,6 +52,8 @@
|
|||
#include "priorities.hxx"
|
||||
|
||||
#define USE_CLIPPER (0)
|
||||
#define FIND_SLIVERS (1)
|
||||
#define USE_ACCUMULATOR (1)
|
||||
|
||||
class TGShape
|
||||
{
|
||||
|
@ -59,8 +62,14 @@ public:
|
|||
bool textured;
|
||||
superpoly_list sps;
|
||||
texparams_list tps;
|
||||
AreaType area;
|
||||
unsigned int id;
|
||||
|
||||
void GetName( char* name ) const
|
||||
{
|
||||
sprintf( name, "%s_%d", get_area_name( (AreaType)area ).c_str(), id );
|
||||
}
|
||||
|
||||
void SetMask( TGPolygon mask )
|
||||
{
|
||||
clip_mask = mask;
|
||||
|
@ -84,18 +93,24 @@ public:
|
|||
|
||||
void IntersectPolys( void )
|
||||
{
|
||||
if ( sps.size() > 1 ) {
|
||||
TGPolygon original, intersect;
|
||||
|
||||
for (unsigned int i=0; i<sps.size(); i++)
|
||||
{
|
||||
original = sps[i].get_poly();
|
||||
|
||||
#ifdef USE_CLIPPER
|
||||
intersect = tgPolygonIntClipper( clip_mask, original );
|
||||
#else
|
||||
intersect = tgPolygonInt( clip_mask, original );
|
||||
#endif
|
||||
|
||||
sps[i].set_poly( intersect );
|
||||
}
|
||||
} else {
|
||||
sps[0].set_poly( clip_mask );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -261,6 +276,8 @@ private:
|
|||
// path to the debug shapes
|
||||
std::string debug_path;
|
||||
|
||||
bool debug_all;
|
||||
|
||||
// list of shapes to dump during debug
|
||||
std::vector<unsigned int> debug_shapes;
|
||||
|
||||
|
@ -308,8 +325,8 @@ private:
|
|||
void SaveSharedEdgeData( void );
|
||||
|
||||
// Polygon Cleaning
|
||||
void CleanClippedPolys( void );
|
||||
void FixTJunctions( void );
|
||||
void clean_clipped_polys( void );
|
||||
|
||||
// Tesselation
|
||||
void TesselatePolys( void );
|
||||
|
@ -337,7 +354,9 @@ private:
|
|||
|
||||
// debug
|
||||
bool IsDebugShape( unsigned int id );
|
||||
void WriteDebugShape( const char* layer_name, unsigned int area, unsigned int shape );
|
||||
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 );
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
|
|
|
@ -273,9 +273,6 @@ void TGMatch::load_neighbor_shared( SGBucket b, string work ) {
|
|||
|
||||
// try to load any missing shared data from our own shared data file
|
||||
void TGMatch::load_missing_shared( SGBucket b, string work ) {
|
||||
double clon = b.get_center_lon();
|
||||
double clat = b.get_center_lat();
|
||||
|
||||
string base = work + "/Shared/";
|
||||
|
||||
if ( !nw_flag ) {
|
||||
|
|
|
@ -142,6 +142,7 @@ public:
|
|||
bool HasElevation() const; // does point have elevation data?
|
||||
|
||||
bool IsWithin( Point3D min, Point3D max ) const;
|
||||
bool IsWithin( double xmin, double xmax, double ymin, double ymax ) const;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
double round(double d)
|
||||
|
@ -445,6 +446,12 @@ inline bool Point3D::IsWithin( Point3D min, Point3D max ) const
|
|||
(max.n[PX] >= n[PX]) && (max.n[PY] >= n[PY]) );
|
||||
}
|
||||
|
||||
inline bool Point3D::IsWithin( double xmin, double xmax, double ymin, double ymax ) const
|
||||
{
|
||||
return ( (xmin <= n[PX]) && (ymin <= n[PY]) &&
|
||||
(xmax >= n[PX]) && (ymax >= n[PY]) );
|
||||
}
|
||||
|
||||
// FRIENDS
|
||||
|
||||
inline Point3D operator - (const Point3D& a)
|
||||
|
|
|
@ -35,32 +35,27 @@
|
|||
// new polygon
|
||||
void add_intermediate_nodes( int contour, const Point3D& start,
|
||||
const Point3D& end, point_list& tmp_nodes,
|
||||
TGPolygon *result )
|
||||
TGPolygon *result,
|
||||
const double bbEpsilon,
|
||||
const double errEpsilon
|
||||
)
|
||||
{
|
||||
// SG_LOG(SG_GENERAL, SG_DEBUG, " add_intermediate_nodes()");
|
||||
char buf[200];
|
||||
snprintf(buf, 199, " %.7f %.7f %.7f <=> %.7f %.7f %.7f\n",
|
||||
start.x(), start.y(), start.z(), end.x(), end.y(), end.z() );
|
||||
SG_LOG(SG_GENERAL, SG_BULK, buf);
|
||||
|
||||
|
||||
Point3D new_pt;
|
||||
bool found_extra = find_intermediate_node( start, end, tmp_nodes, &new_pt );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_BULK, " " << start << " <==> " << end );
|
||||
|
||||
bool found_extra = find_intermediate_node( start, end, tmp_nodes, &new_pt, bbEpsilon, errEpsilon );
|
||||
|
||||
if ( found_extra ) {
|
||||
// recurse with two sub segments
|
||||
// SG_LOG(SG_GENERAL, SG_DEBUG, "dividing " << p0 << " " << nodes[extra_index]
|
||||
// << " " << p1);
|
||||
add_intermediate_nodes( contour, start, new_pt, tmp_nodes,
|
||||
result );
|
||||
add_intermediate_nodes( contour, start, new_pt, tmp_nodes, result, bbEpsilon, errEpsilon );
|
||||
|
||||
result->add_node( contour, new_pt );
|
||||
SG_LOG(SG_GENERAL, SG_BULK, " adding = " << new_pt);
|
||||
|
||||
add_intermediate_nodes( contour, new_pt, end, tmp_nodes,
|
||||
result );
|
||||
} else {
|
||||
// this segment does not need to be divided
|
||||
add_intermediate_nodes( contour, new_pt, end, tmp_nodes, result, bbEpsilon, errEpsilon );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +83,7 @@ TGPolygon add_nodes_to_poly( const TGPolygon& poly,
|
|||
result.add_node( i, p0 );
|
||||
|
||||
// add intermediate points
|
||||
add_intermediate_nodes( i, p0, p1, tmp_nodes, &result );
|
||||
add_intermediate_nodes( i, p0, p1, tmp_nodes, &result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
|
||||
// end of segment is beginning of next segment
|
||||
}
|
||||
|
@ -99,7 +94,7 @@ TGPolygon add_nodes_to_poly( const TGPolygon& poly,
|
|||
result.add_node( i, p0 );
|
||||
|
||||
// add intermediate points
|
||||
add_intermediate_nodes( i, p0, p1, tmp_nodes, &result );
|
||||
add_intermediate_nodes( i, p0, p1, tmp_nodes, &result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
|
||||
// end of segment is beginning of next segment
|
||||
// 5/9/2000 CLO - this results in duplicating the last point
|
||||
|
@ -135,7 +130,7 @@ TGPolygon add_tgnodes_to_poly( const TGPolygon& poly,
|
|||
result.add_node( i, p0 );
|
||||
|
||||
// add intermediate points
|
||||
add_intermediate_nodes( i, p0, p1, poly_points, &result );
|
||||
add_intermediate_nodes( i, p0, p1, poly_points, &result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
|
||||
// end of segment is beginning of next segment
|
||||
}
|
||||
|
@ -146,7 +141,7 @@ TGPolygon add_tgnodes_to_poly( const TGPolygon& poly,
|
|||
result.add_node( i, p0 );
|
||||
|
||||
// add intermediate points
|
||||
add_intermediate_nodes( i, p0, p1, poly_points, &result );
|
||||
add_intermediate_nodes( i, p0, p1, poly_points, &result, SG_EPSILON*10, SG_EPSILON*4 );
|
||||
|
||||
// maintain original hole flag setting
|
||||
result.set_hole_flag( i, poly.get_hole_flag( i ) );
|
||||
|
|
|
@ -37,8 +37,11 @@
|
|||
// Divide segment if there are other existing points on it, return the
|
||||
// new polygon
|
||||
void add_intermediate_nodes( int contour, const Point3D& start,
|
||||
const Point3D& end, const TGTriNodes& tmp_nodes,
|
||||
TGPolygon *result );
|
||||
const Point3D& end, const point_list& tmp_nodes,
|
||||
TGPolygon *result,
|
||||
const double bbEpsilon = SG_EPSILON*10,
|
||||
const double errEpsilon = SG_EPSILON*4
|
||||
);
|
||||
|
||||
|
||||
// Search each segment for additional vertex points that may have been
|
||||
|
|
|
@ -946,14 +946,16 @@ TGPolygon snap (const TGPolygon &poly, double grid_size)
|
|||
}
|
||||
|
||||
|
||||
// static const double tgAirportEpsilon = SG_EPSILON / 10.0;
|
||||
static const double tgAirportEpsilon = SG_EPSILON;
|
||||
|
||||
/* TODO : Verify this doesn't break genapt850 - may need an interface to
|
||||
* specify bounding box and error values
|
||||
*/
|
||||
|
||||
// Find a point in the given node list that lies between start and
|
||||
// end, return true if something found, false if nothing found.
|
||||
bool find_intermediate_node( const Point3D& start, const Point3D& end,
|
||||
const point_list& nodes, Point3D *result )
|
||||
const point_list& nodes, Point3D *result,
|
||||
double bbEpsilon, double errEpsilon
|
||||
)
|
||||
{
|
||||
bool found_node = false;
|
||||
double m, m1, b, b1, y_err, x_err, y_err_min, x_err_min;
|
||||
|
@ -991,8 +993,8 @@ bool find_intermediate_node( const Point3D& start, const Point3D& end,
|
|||
// cout << i << endl;
|
||||
Point3D current = nodes[i];
|
||||
|
||||
if ( (current.x() > (p_min.x() + (SG_EPSILON)))
|
||||
&& (current.x() < (p_max.x() - (SG_EPSILON))) ) {
|
||||
if ( (current.x() > (p_min.x() + (bbEpsilon)))
|
||||
&& (current.x() < (p_max.x() - (bbEpsilon))) ) {
|
||||
|
||||
// printf( "found a potential candidate %.7f %.7f %.7f\n",
|
||||
// current.x(), current.y(), current.z() );
|
||||
|
@ -1000,7 +1002,7 @@ bool find_intermediate_node( const Point3D& start, const Point3D& end,
|
|||
y_err = fabs(current.y() - (m * current.x() + b));
|
||||
// cout << "y_err = " << y_err << endl;
|
||||
|
||||
if ( y_err < tgAirportEpsilon ) {
|
||||
if ( y_err < errEpsilon ) {
|
||||
// cout << "FOUND EXTRA SEGMENT NODE (Y)" << endl;
|
||||
// cout << p_min << " < " << current << " < "
|
||||
// << p_max << endl;
|
||||
|
@ -1039,8 +1041,8 @@ bool find_intermediate_node( const Point3D& start, const Point3D& end,
|
|||
for ( int i = 0; i < (int)nodes.size(); ++i ) {
|
||||
Point3D current = nodes[i];
|
||||
|
||||
if ( (current.y() > (p_min.y() + (SG_EPSILON)))
|
||||
&& (current.y() < (p_max.y() - (SG_EPSILON))) ) {
|
||||
if ( (current.y() > (p_min.y() + (bbEpsilon)))
|
||||
&& (current.y() < (p_max.y() - (bbEpsilon))) ) {
|
||||
|
||||
// printf( "found a potential candidate %.7f %.7f %.7f\n",
|
||||
// current.x(), current.y(), current.z() );
|
||||
|
@ -1052,7 +1054,7 @@ bool find_intermediate_node( const Point3D& start, const Point3D& end,
|
|||
// cout << " (" << counter << ") x_err = " << x_err << endl;
|
||||
// }
|
||||
|
||||
if ( x_err < tgAirportEpsilon ) {
|
||||
if ( x_err < errEpsilon ) {
|
||||
// cout << "FOUND EXTRA SEGMENT NODE (X)" << endl;
|
||||
// cout << p_min << " < " << current << " < "
|
||||
// << p_max << endl;
|
||||
|
@ -1550,7 +1552,7 @@ void* tgShapefileOpenLayer( void* ds_id, const char* layer_name ) {
|
|||
return (void*)layer;
|
||||
}
|
||||
|
||||
void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, const char* description )
|
||||
void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, const char* description, bool has_pt_inside )
|
||||
{
|
||||
OGRLayer* layer = (OGRLayer*)l_id;
|
||||
OGRPolygon* polygon = new OGRPolygon();
|
||||
|
@ -1591,6 +1593,26 @@ void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, c
|
|||
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create feature in shapefile");
|
||||
}
|
||||
OGRFeature::DestroyFeature(feature);
|
||||
|
||||
// TEST TEST TEST : Add the point inside - see if we can see it in QGIS
|
||||
if ( has_pt_inside ) {
|
||||
OGRPoint *point=new OGRPoint();
|
||||
|
||||
point->setX( poly.get_point_inside( i ).x() );
|
||||
point->setY( poly.get_point_inside( i ).y() );
|
||||
point->setZ( 0.0 );
|
||||
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "DEBUG: SET POINT INSIDE " << description << " contour " << i << " is " << poly.get_point_inside( i ) );
|
||||
|
||||
feature = new OGRFeature( layer->GetLayerDefn() );
|
||||
feature->SetField("ID", description);
|
||||
feature->SetGeometry(point);
|
||||
if( layer->CreateFeature( feature ) != OGRERR_NONE )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create feature in shapefile");
|
||||
}
|
||||
OGRFeature::DestroyFeature(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,10 @@ TGPolygon remove_spikes( const TGPolygon& poly );
|
|||
// Find a point in the given node list that lies between start and
|
||||
// end, return true if something found, false if nothing found.
|
||||
bool find_intermediate_node( const Point3D& start, const Point3D& end,
|
||||
const point_list& nodes, Point3D *result );
|
||||
const point_list& nodes, Point3D *result,
|
||||
const double bbEpsilon = SG_EPSILON*10,
|
||||
const double errEpsilon = SG_EPSILON*4
|
||||
);
|
||||
|
||||
// remove any degenerate contours
|
||||
TGPolygon remove_bad_contours( const TGPolygon &poly );
|
||||
|
@ -114,7 +117,7 @@ TGPolygon remove_small_contours( const TGPolygon &poly );
|
|||
void tgShapefileInit( void );
|
||||
void* tgShapefileOpenDatasource( const char* datasource_name );
|
||||
void* tgShapefileOpenLayer( void* ds_id, const char* layer_name );
|
||||
void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, const char* feature_name );
|
||||
void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, const char* feature_name, bool has_point_inside = false );
|
||||
void tgShapefileCloseLayer( void* l_id );
|
||||
void* tgShapefileCloseDatasource( void* ds_id );
|
||||
|
||||
|
|
|
@ -359,6 +359,8 @@ void tgPolygonFindSlivers( TGPolygon& in, poly_list& slivers )
|
|||
in.delete_contour( i );
|
||||
} else {
|
||||
// move sliver contour to out polygon
|
||||
SG_LOG(SG_GENERAL, SG_INFO, " Found SLIVER!");
|
||||
|
||||
contour = in.get_contour( i );
|
||||
in.delete_contour( i );
|
||||
out.add_contour( contour, hole_flag );
|
||||
|
@ -703,6 +705,80 @@ TGPolygon polygon_clip_clipper( clip_op poly_op, const TGPolygon& subject, const
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Accumulator optimization ( to keep from massive data copies and format changes
|
||||
gpc_polygon *gpc_accumulator = NULL;
|
||||
|
||||
void tgPolygonInitAccumulator( void )
|
||||
{
|
||||
gpc_accumulator = new gpc_polygon;
|
||||
gpc_accumulator->num_contours = 0;
|
||||
gpc_accumulator->contour = NULL;
|
||||
gpc_accumulator->hole = NULL;
|
||||
}
|
||||
|
||||
void tgPolygonFreeAccumulator( void )
|
||||
{
|
||||
gpc_free_polygon( gpc_accumulator );
|
||||
delete gpc_accumulator;
|
||||
gpc_accumulator = NULL;
|
||||
}
|
||||
|
||||
void tgPolygonAddToAccumulator( const TGPolygon& subject )
|
||||
{
|
||||
gpc_polygon *gpc_subject = new gpc_polygon;
|
||||
gpc_subject->num_contours = 0;
|
||||
gpc_subject->contour = NULL;
|
||||
gpc_subject->hole = NULL;
|
||||
make_gpc_poly( subject, gpc_subject );
|
||||
|
||||
gpc_polygon *gpc_result = new gpc_polygon;
|
||||
gpc_result->num_contours = 0;
|
||||
gpc_result->contour = NULL;
|
||||
gpc_result->hole = NULL;
|
||||
|
||||
gpc_polygon_clip( GPC_UNION, gpc_subject, gpc_accumulator, gpc_result );
|
||||
|
||||
// free allocated memory
|
||||
gpc_free_polygon( gpc_subject );
|
||||
delete gpc_subject;
|
||||
|
||||
// throw away old accumulator : and use result for now on
|
||||
gpc_free_polygon( gpc_accumulator );
|
||||
delete gpc_accumulator;
|
||||
gpc_accumulator = gpc_result;
|
||||
}
|
||||
|
||||
TGPolygon tgPolygonDiffWithAccumulator( const TGPolygon& subject )
|
||||
{
|
||||
TGPolygon result;
|
||||
|
||||
gpc_polygon *gpc_subject = new gpc_polygon;
|
||||
gpc_subject->num_contours = 0;
|
||||
gpc_subject->contour = NULL;
|
||||
gpc_subject->hole = NULL;
|
||||
make_gpc_poly( subject, gpc_subject );
|
||||
|
||||
gpc_polygon *gpc_result = new gpc_polygon;
|
||||
gpc_result->num_contours = 0;
|
||||
gpc_result->contour = NULL;
|
||||
gpc_result->hole = NULL;
|
||||
|
||||
gpc_polygon_clip( GPC_DIFF, gpc_subject, gpc_accumulator, gpc_result );
|
||||
make_tg_poly( gpc_result, &result );
|
||||
|
||||
// free allocated memory
|
||||
gpc_free_polygon( gpc_subject );
|
||||
delete gpc_subject;
|
||||
|
||||
gpc_free_polygon( gpc_result );
|
||||
delete gpc_result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Difference
|
||||
TGPolygon tgPolygonDiff( const TGPolygon& subject, const TGPolygon& clip ) {
|
||||
return polygon_clip( POLY_DIFF, subject, clip );
|
||||
|
|
|
@ -256,6 +256,12 @@ void tgPolygonFindSlivers( TGPolygon& in, poly_list& slivers );
|
|||
|
||||
// wrapper functions for gpc polygon clip routines
|
||||
|
||||
void tgPolygonInitAccumulator( void );
|
||||
void tgPolygonFreeAccumulator( void );
|
||||
void tgPolygonAddToAccumulator( const TGPolygon& subject );
|
||||
TGPolygon tgPolygonDiffWithAccumulator( const TGPolygon& subject );
|
||||
|
||||
|
||||
// Difference
|
||||
TGPolygon tgPolygonDiff( const TGPolygon& subject, const TGPolygon& clip );
|
||||
|
||||
|
|
Loading…
Reference in a new issue