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;