From c1de74f4fa0dbf6076dc73b9b5eb4ef1d98e17e6 Mon Sep 17 00:00:00 2001 From: Peter Sadrozinski <pete@loft.sadrohome> Date: Sun, 26 Aug 2012 12:41:25 -0400 Subject: [PATCH] Some fixes - genapt850 : some airports (LSMM) have multiple airport boundaries. This caused a lot of the airport to not get a smoothed base (so some landclass polys were not clipped against the airport). Changed boundary from a single ClosedPolygon to a list. Seems to work. Some misc warnings cleanup in scheduler, and parser - Clipper using accumulator results in a significant speed boots - enable clipper and the accumulator by default. - ogr-decode - most of the crashes I'm getting are due to non-continuous roads. Within a line string, I create adjacent polys that snap correctly. On the ends, I generate 90 degree angles. Some linestrings should be consecutive. As a workaround, I am now extending every start and end poly of linestrings by 0.1 meters. It makes it better, but I need to do a better job of creating continuous roads. This will require some preprocessing of the entire shapefile. (Perhaps all line data shapefiles, to handle correct overpass / underpass logic) --- src/Airports/GenAirports850/airport.cxx | 24 ++-- src/Airports/GenAirports850/airport.hxx | 6 +- src/Airports/GenAirports850/closedpoly.cxx | 2 +- src/Airports/GenAirports850/parser.cxx | 2 +- src/Airports/GenAirports850/scheduler.cxx | 2 +- src/Airports/GenAirports850/scheduler.hxx | 2 +- src/BuildTiles/Main/construct.cxx | 156 ++++++++++++++------- src/BuildTiles/Main/construct.hxx | 2 +- src/Lib/Geometry/poly_support.cxx | 6 +- src/Lib/Polygon/polygon.cxx | 67 ++++++++- src/Lib/Polygon/polygon.hxx | 9 +- src/Prep/OGRDecode/ogr-decode.cxx | 3 +- 12 files changed, 206 insertions(+), 75 deletions(-) diff --git a/src/Airports/GenAirports850/airport.cxx b/src/Airports/GenAirports850/airport.cxx index a0e50e01..e50f5a1b 100644 --- a/src/Airports/GenAirports850/airport.cxx +++ b/src/Airports/GenAirports850/airport.cxx @@ -85,7 +85,6 @@ Airport::Airport( int c, char* def) } altitude *= SG_FEET_TO_METER; - boundary = NULL; dbg_rwy_poly = 0; dbg_pvmt_poly = 0; @@ -149,9 +148,9 @@ Airport::~Airport() delete signs[i]; } - if (boundary) + for (unsigned int i=0; i<boundary.size(); i++) { - delete boundary; + delete boundary[i]; } } @@ -636,7 +635,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) make_shapefiles = false; } - if (boundary) + if (boundary.size()) { runways[i]->BuildBtg( &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, NULL, NULL, make_shapefiles ); } @@ -670,7 +669,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) SG_LOG(SG_GENERAL, SG_INFO, "Build helipad " << i + 1 << " of " << helipads.size()); slivers.clear(); - if (boundary) + if (boundary.size()) { helipads[i]->BuildBtg( &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, NULL, NULL ); } @@ -700,7 +699,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) make_shapefiles = false; } - if (boundary) + if (boundary.size()) { pavements[i]->BuildBtg( &pvmt_polys, &pvmt_tps, &accum, slivers, NULL, NULL, make_shapefiles ); } @@ -738,7 +737,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) make_shapefiles = false; } - if (boundary) + if (boundary.size()) { taxiways[i]->BuildBtg( &pvmt_polys, &pvmt_tps, &rwy_lights, &accum, slivers, NULL, NULL, make_shapefiles ); } @@ -767,7 +766,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) { slivers.clear(); - if (boundary) + if (boundary.size()) { runways[i]->BuildShoulder( &rwy_polys, &rwy_tps, &accum, slivers, NULL, NULL ); } @@ -807,10 +806,13 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) } // build the base and clearing if there's a boundary - if (boundary) + if (boundary.size()) { - SG_LOG(SG_GENERAL, SG_INFO, "Build user defined boundary " ); - boundary->BuildBtg( &apt_base, &apt_clearing, false ); + for ( unsigned int i=0; i<boundary.size(); i++ ) + { + SG_LOG(SG_GENERAL, SG_INFO, "Build Userdefined boundary " << i + 1 << " of " << boundary.size()); + boundary[i]->BuildBtg( &apt_base, &apt_clearing, false ); + } } if ( apt_base.total_size() == 0 ) diff --git a/src/Airports/GenAirports850/airport.hxx b/src/Airports/GenAirports850/airport.hxx index f5ed48a1..7f5669eb 100644 --- a/src/Airports/GenAirports850/airport.hxx +++ b/src/Airports/GenAirports850/airport.hxx @@ -70,9 +70,9 @@ public: return features.size(); } - void SetBoundary( ClosedPoly* bndry ) + void AddBoundary( ClosedPoly* bndry ) { - boundary = bndry; + boundary.push_back( bndry ); } void AddWindsock( Windsock* windsock ) @@ -132,7 +132,7 @@ private: BeaconList beacons; SignList signs; HelipadList helipads; - ClosedPoly* boundary; + PavementList boundary; // stats SGTimeStamp build_time; diff --git a/src/Airports/GenAirports850/closedpoly.cxx b/src/Airports/GenAirports850/closedpoly.cxx index 086eeaaa..6118b0fe 100644 --- a/src/Airports/GenAirports850/closedpoly.cxx +++ b/src/Airports/GenAirports850/closedpoly.cxx @@ -546,7 +546,7 @@ int ClosedPoly::BuildBtg( TGPolygon* apt_base, TGPolygon* apt_clearing, bool mak TGPolygon base, safe_base; // verify the poly has been generated - if ( pre_tess.contours() ) + if ( pre_tess.contours() ) { SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: original poly has " << pre_tess.contours() << " contours"); diff --git a/src/Airports/GenAirports850/parser.cxx b/src/Airports/GenAirports850/parser.cxx index 655a6845..ea02daac 100644 --- a/src/Airports/GenAirports850/parser.cxx +++ b/src/Airports/GenAirports850/parser.cxx @@ -357,7 +357,7 @@ int Parser::SetState( int state ) { SG_LOG(SG_GENERAL, SG_DEBUG, "Closing and Adding boundary"); cur_boundary->Finish(); - cur_airport->SetBoundary( cur_boundary ); + cur_airport->AddBoundary( cur_boundary ); cur_boundary = NULL; } diff --git a/src/Airports/GenAirports850/scheduler.cxx b/src/Airports/GenAirports850/scheduler.cxx index 2dcfafad..4047e669 100644 --- a/src/Airports/GenAirports850/scheduler.cxx +++ b/src/Airports/GenAirports850/scheduler.cxx @@ -301,7 +301,7 @@ void ProcessList::HandleFinished( void ) for ( unsigned int i=0; i< plist.size(); i++ ) { switch ( plist[i].GetState() ) { case P_STATE_DONE: - plist[i].SetErrorString( "success" ); + plist[i].SetErrorString( (char *)"success" ); // holding the list lock - only one thread can write to the csvfile at a time csvfile << plist[i].GetInfo() << "\n"; diff --git a/src/Airports/GenAirports850/scheduler.hxx b/src/Airports/GenAirports850/scheduler.hxx index ef6c8b57..55e28b80 100644 --- a/src/Airports/GenAirports850/scheduler.hxx +++ b/src/Airports/GenAirports850/scheduler.hxx @@ -154,7 +154,7 @@ private: ProcessInfoList plist; Net::ServerSocket* pss; int state; - int threads; + unsigned int threads; ofstream csvfile; Scheduler* scheduler; }; diff --git a/src/BuildTiles/Main/construct.cxx b/src/BuildTiles/Main/construct.cxx index ff2c17ce..3c2a5350 100644 --- a/src/BuildTiles/Main/construct.cxx +++ b/src/BuildTiles/Main/construct.cxx @@ -51,7 +51,8 @@ using std::string; -double gSnap = 0.00000001; // approx 1 mm +//double gSnap = 0.00000001; // approx 1 mm +double gSnap = 0.0000001; // approx 1 cm static const double cover_size = 1.0 / 120.0; static const double half_cover_size = cover_size * 0.5; @@ -146,12 +147,12 @@ bool TGConstruct::IsDebugShape( unsigned int id ) void TGConstruct::WriteDebugShape( const char* layer_name, const TGShape& shape ) { char name[64]; - + shape.GetName( name ); + ds_id = tgShapefileOpenDatasource( ds_name ); l_id = tgShapefileOpenLayer( ds_id, layer_name ); - shape.GetName( name ); - tgShapefileCreateFeature( ds_id, l_id, shape.clip_mask, name ); + tgShapefileCreateFeature( ds_id, l_id, shape.clip_mask, "test" ); // close after each write ds_id = tgShapefileCloseDatasource( ds_id ); @@ -1236,7 +1237,7 @@ 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 ); @@ -1300,7 +1301,13 @@ bool TGConstruct::ClipLandclassPolys( void ) { max.y = bucket.get_center_lat() + 0.5 * bucket.get_height(); #if USE_ACCUMULATOR - tgPolygonInitAccumulator(); + +#if USE_CLIPPER + tgPolygonInitClipperAccumulator(); +#else + tgPolygonInitGPCAccumulator(); +#endif + #else accum.erase(); #endif @@ -1344,6 +1351,7 @@ bool TGConstruct::ClipLandclassPolys( void ) { #endif } + } else if ( is_water_area( i ) ) { for (unsigned int j = 0; j < polys_in.area_size(i); j++) { #if USE_CLIPPER @@ -1363,6 +1371,13 @@ bool TGConstruct::ClipLandclassPolys( void ) { } } + // Dump the masks + if ( debug_all || debug_shapes.size() ) { + WriteDebugPoly( "land_mask", "", land_mask ); + WriteDebugPoly( "water_mask", "", water_mask ); + WriteDebugPoly( "island_mask", "", island_mask ); + } + // process polygons in priority order for ( i = 0; i < TG_MAX_AREA_TYPES; ++i ) { for( j = 0; j < (int)polys_in.area_size(i); ++j ) { @@ -1391,8 +1406,20 @@ bool TGConstruct::ClipLandclassPolys( void ) { #endif } + if ( IsDebugShape( polys_in.get_shape( i, j ).id ) ) { + char name[32]; + sprintf(name, "shape %d,%d", i,j); + WriteDebugPoly( "pre-clip", name, tmp ); + } + #if USE_CLIPPER + +#if USE_ACCUMULATOR + clipped = tgPolygonDiffClipperWithAccumulator( tmp ); +#else clipped = tgPolygonDiffClipper( tmp, accum ); +#endif + #else #if USE_ACCUMULATOR @@ -1402,6 +1429,7 @@ bool TGConstruct::ClipLandclassPolys( void ) { #endif #endif + // only add to output list if the clip left us with a polygon if ( clipped.contours() > 0 ) { @@ -1413,14 +1441,13 @@ bool TGConstruct::ClipLandclassPolys( void ) { // 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 ) ); // copy all of the superpolys and texparams shape.SetMask( clipped ); shape.textured = polys_in.get_textured( i, j ); shape.id = polys_in.get_shape( i, j ).id; + + shape.area= polys_in.get_shape( i, j ).area; shape.sps = polys_in.get_shape( i, j ).sps; shape.tps = polys_in.get_shape( i, j ).tps; @@ -1431,19 +1458,22 @@ bool TGConstruct::ClipLandclassPolys( void ) { WriteDebugShape( "clipped", shape ); } } - } + } #if USE_CLIPPER - accum = tgPolygonUnionClipper( tmp, accum ); -// accum = tgPolygonUnionClipper( clipped, accum ); -#else +#if USE_ACCUMULATOR + tgPolygonAddToClipperAccumulator( tmp ); +#else + accum = tgPolygonUnionClipper( tmp, accum ); +#endif + +#else + #if USE_ACCUMULATOR tgPolygonAddToAccumulator( tmp ); -// tgPolygonAddToAccumulator( clipped ); #else accum = tgPolygonUnion( tmp, accum ); -// accum = tgPolygonUnion( clipped, accum ); #endif #endif @@ -1461,10 +1491,16 @@ bool TGConstruct::ClipLandclassPolys( void ) { #endif slivers.clear(); - + // finally, what ever is left over goes to ocean #if USE_CLIPPER + +#if USE_ACCUMULATOR + remains = tgPolygonDiffClipperWithAccumulator( safety_base ); +#else remains = tgPolygonDiffClipper( safety_base, accum ); +#endif + #else #if USE_ACCUMULATOR @@ -1516,8 +1552,14 @@ bool TGConstruct::ClipLandclassPolys( void ) { } #if USE_ACCUMULATOR - tgPolygonFreeAccumulator(); -#endif + +#if USE_CLIPPER + tgPolygonFreeClipperAccumulator(); +#else + tgPolygonFreeGPCAccumulator(); +#endif + +#endif // Once clipping is complete, intersect the individual segments with their clip masks for (unsigned int area = 0; area < TG_MAX_AREA_TYPES; area++) { @@ -1723,11 +1765,13 @@ void TGConstruct::CalcFaceNormals( void ) void TGConstruct::CalcPointNormals( void ) { // traverse triangle structure building the face normal table - SG_LOG(SG_GENERAL, SG_ALERT, "Calculating point normals"); + SG_LOG(SG_GENERAL, SG_ALERT, "Calculating point normals: 0%"); Point3D normal; point_list wgs84_nodes = nodes.get_wgs84_nodes_as_Point3d(); - + unsigned int ten_percent = nodes.size() / 10; + unsigned int cur_percent = 10; + for ( unsigned int i = 0; i<nodes.size(); i++ ) { TGNode node = nodes.get_node( i ); TGFaceList faces = node.GetFaces(); @@ -1735,6 +1779,12 @@ void TGConstruct::CalcPointNormals( void ) Point3D average( 0.0 ); + if ( i == ten_percent ) { + SG_LOG(SG_GENERAL, SG_ALERT, "Calculating point normals: " << cur_percent << "%" ); + ten_percent += nodes.size() / 10; + cur_percent += 10; + } + // for each triangle that shares this node for ( unsigned int j = 0; j < faces.size(); ++j ) { unsigned int at = faces[j].area; @@ -1958,47 +2008,55 @@ void TGConstruct::WriteBtgFile( void ) } void TGConstruct::CleanClippedPolys() { - // Clean the polys unsigned int before, after; + // Clean the polys 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; - + + // step 1 : snap for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) { TGPolygon poly = polys_clipped.get_poly(area, shape, segment); - - before = poly.total_size(); - - if ( false ) { - poly = remove_cycles( poly ); - poly = remove_dups( poly ); - poly = remove_bad_contours( poly ); - poly = tgPolygonSimplify( poly ); - poly = remove_tiny_contours( poly ); - poly = remove_spikes( poly ); - poly = remove_dups( poly ); - poly = remove_bad_contours( poly ); - poly = remove_tiny_contours( poly ); - } else { - poly = snap(poly, gSnap); - poly = remove_dups( poly ); - 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 ); - } - + poly = snap(poly, gSnap); polys_clipped.set_poly( area, shape, segment, poly ); } if ( IsDebugShape( id ) ) { - WriteDebugShape( "cleaned", polys_clipped.get_shape( area, shape ) ); + WriteDebugShape( "snapped", polys_clipped.get_shape( area, shape ) ); } + + // step 2 : remove_dups + for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) { + TGPolygon poly = polys_clipped.get_poly(area, shape, segment); + poly = remove_dups( poly ); + polys_clipped.set_poly( area, shape, segment, poly ); + } + + if ( IsDebugShape( id ) ) { + WriteDebugShape( "rem dupes", polys_clipped.get_shape( area, shape ) ); + } + + // step 3 : remove_bad_contours + for ( unsigned int segment = 0; segment < polys_clipped.shape_size(area, shape); segment++ ) { + TGPolygon poly = polys_clipped.get_poly(area, shape, segment); + poly = remove_bad_contours( poly ); + polys_clipped.set_poly( area, shape, segment, poly ); + } + + if ( IsDebugShape( id ) ) { + WriteDebugShape( "rem bad contours", polys_clipped.get_shape( area, shape ) ); + } + +// todo - add up all segments in a shape for printout +#if 0 + 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 ); + } +#endif + } } } diff --git a/src/BuildTiles/Main/construct.hxx b/src/BuildTiles/Main/construct.hxx index d909bb33..54b39cbe 100644 --- a/src/BuildTiles/Main/construct.hxx +++ b/src/BuildTiles/Main/construct.hxx @@ -69,7 +69,7 @@ public: { sprintf( name, "%s_%d", get_area_name( (AreaType)area ).c_str(), id ); } - + void SetMask( TGPolygon mask ) { clip_mask = mask; diff --git a/src/Lib/Geometry/poly_support.cxx b/src/Lib/Geometry/poly_support.cxx index f1d0a5d2..092ad786 100644 --- a/src/Lib/Geometry/poly_support.cxx +++ b/src/Lib/Geometry/poly_support.cxx @@ -1553,10 +1553,10 @@ void* tgShapefileOpenLayer( void* ds_id, const char* layer_name ) { } 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(); - + for ( int i = 0; i < poly.contours(); i++ ) { bool skip_ring=false; point_list contour = poly.get_contour( i ); @@ -1595,6 +1595,7 @@ void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, c OGRFeature::DestroyFeature(feature); // TEST TEST TEST : Add the point inside - see if we can see it in QGIS +#if 0 if ( has_pt_inside ) { OGRPoint *point=new OGRPoint(); @@ -1613,6 +1614,7 @@ void tgShapefileCreateFeature( void* ds_id, void* l_id, const TGPolygon &poly, c } OGRFeature::DestroyFeature(feature); } +#endif } } diff --git a/src/Lib/Polygon/polygon.cxx b/src/Lib/Polygon/polygon.cxx index 09ae45c7..0074214e 100644 --- a/src/Lib/Polygon/polygon.cxx +++ b/src/Lib/Polygon/polygon.cxx @@ -709,7 +709,7 @@ TGPolygon polygon_clip_clipper( clip_op poly_op, const TGPolygon& subject, const // Accumulator optimization ( to keep from massive data copies and format changes gpc_polygon *gpc_accumulator = NULL; -void tgPolygonInitAccumulator( void ) +void tgPolygonInitGPCAccumulator( void ) { gpc_accumulator = new gpc_polygon; gpc_accumulator->num_contours = 0; @@ -717,7 +717,7 @@ void tgPolygonInitAccumulator( void ) gpc_accumulator->hole = NULL; } -void tgPolygonFreeAccumulator( void ) +void tgPolygonFreeGPCAccumulator( void ) { gpc_free_polygon( gpc_accumulator ); delete gpc_accumulator; @@ -801,6 +801,69 @@ TGPolygon tgPolygonUnion( const TGPolygon& subject, const TGPolygon& clip ) { + +// Accumulator optimization ( to keep from massive data copies and format changes +ClipperLib::Polygons clipper_accumulator; + +void tgPolygonInitClipperAccumulator( void ) +{ + clipper_accumulator.clear(); +} + +void tgPolygonFreeClipperAccumulator( void ) +{ + clipper_accumulator.clear(); +} + + +void tgPolygonAddToClipperAccumulator( const TGPolygon& subject ) +{ + 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); + + // verify each result is simple + ClipperLib::Polygons simple_result = clipper_simplify( clipper_result ); + + clipper_accumulator.clear(); + clipper_accumulator = simple_result; +} + +TGPolygon tgPolygonDiffClipperWithAccumulator( const TGPolygon& subject ) +{ + TGPolygon result; + + 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::ctDifference, 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 ); + + return result; +} + + + + // CLIPPER TGPolygon tgPolygonDiffClipper( const TGPolygon& subject, const TGPolygon& clip ) { return polygon_clip_clipper( POLY_DIFF, subject, clip ); diff --git a/src/Lib/Polygon/polygon.hxx b/src/Lib/Polygon/polygon.hxx index 8fa454f5..b514d1b0 100644 --- a/src/Lib/Polygon/polygon.hxx +++ b/src/Lib/Polygon/polygon.hxx @@ -256,8 +256,8 @@ void tgPolygonFindSlivers( TGPolygon& in, poly_list& slivers ); // wrapper functions for gpc polygon clip routines -void tgPolygonInitAccumulator( void ); -void tgPolygonFreeAccumulator( void ); +void tgPolygonInitGPCAccumulator( void ); +void tgPolygonFreeGPCAccumulator( void ); void tgPolygonAddToAccumulator( const TGPolygon& subject ); TGPolygon tgPolygonDiffWithAccumulator( const TGPolygon& subject ); @@ -276,6 +276,11 @@ TGPolygon tgPolygonUnion( const TGPolygon& subject, const TGPolygon& clip ); // wrapper for clipper clip routines +void tgPolygonInitClipperAccumulator( void ); +void tgPolygonFreeClipperAccumulator( void ); +void tgPolygonAddToClipperAccumulator( const TGPolygon& subject ); +TGPolygon tgPolygonDiffClipperWithAccumulator( const TGPolygon& subject ); + // Difference TGPolygon tgPolygonDiffClipper( const TGPolygon& subject, const TGPolygon& clip ); diff --git a/src/Prep/OGRDecode/ogr-decode.cxx b/src/Prep/OGRDecode/ogr-decode.cxx index a7a1e728..cd89f91e 100644 --- a/src/Prep/OGRDecode/ogr-decode.cxx +++ b/src/Prep/OGRDecode/ogr-decode.cxx @@ -45,7 +45,8 @@ #include <ogrsf_frmts.h> /* stretch endpoints to reduce slivers in linear data ~.1 meters */ -#define EP_STRETCH (0.000001) +// #define EP_STRETCH (0.000001) +#define EP_STRETCH (0.1) using std::string; using std::map;