From 4f59886aaa29b31b8a812a7ae2604055e285ee06 Mon Sep 17 00:00:00 2001 From: Peter Sadrozinski Date: Fri, 24 Jul 2015 08:57:24 -0400 Subject: [PATCH] genapts fixes - remove splinter remaval / merging - remove snap after adding colinear nodes - added zfighting detector - intersects all generated triangles against one another - this fixes ELLX, and to a large extent all 'large' airport self z-fighting. - very small z-fighting still exists at 72 airports. This is down from over 100 before the fix. --- src/Airports/GenAirports850/airport.cxx | 242 ++++++++++++++++++--- src/Airports/GenAirports850/airport.hxx | 2 + src/Airports/GenAirports850/closedpoly.cxx | 24 +- src/Airports/GenAirports850/helipad.cxx | 6 +- src/Airports/GenAirports850/rwy_gen.cxx | 6 +- src/BuildTiles/Main/tgconstruct.cxx | 2 +- src/BuildTiles/Main/tgconstruct_clip.cxx | 2 + src/Lib/terragear/tg_misc.cxx | 2 +- src/Lib/terragear/tg_polygon.hxx | 29 +++ src/Lib/terragear/tg_polygon_clip.cxx | 50 +++++ src/Lib/terragear/tg_polygon_tesselate.cxx | 6 + src/Lib/terragear/tg_shapefile.cxx | 68 ++++++ src/Lib/terragear/tg_shapefile.hxx | 2 + 13 files changed, 399 insertions(+), 42 deletions(-) diff --git a/src/Airports/GenAirports850/airport.cxx b/src/Airports/GenAirports850/airport.cxx index 9c5d2dcf..a0e3c576 100644 --- a/src/Airports/GenAirports850/airport.cxx +++ b/src/Airports/GenAirports850/airport.cxx @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -233,6 +234,8 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) tglightcontour_list rwy_lights; bool make_shapefiles = false; + char debug_root[32]; + sprintf(debug_root, "./airport_dbg/%s/", icao.c_str() ); // parse main airport information double apt_lon = 0.0, apt_lat = 0.0; @@ -311,7 +314,7 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) for ( unsigned int i=0; iGetDescription()); - slivers.clear(); + //slivers.clear(); if ( isDebugPavement(i) ) { sprintf( shapefile_name, "pvmnt_%d", i ); @@ -396,8 +399,8 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) } // Now try to merge any slivers we found - tgPolygon::MergeSlivers( rwy_polys, slivers ); - tgPolygon::MergeSlivers( pvmt_polys, slivers ); + //tgPolygon::MergeSlivers( rwy_polys, slivers ); + //tgPolygon::MergeSlivers( pvmt_polys, slivers ); } log_time = time(0); @@ -411,7 +414,7 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) for ( unsigned int i=0; iGetsShoulder() ) { - slivers.clear(); + //slivers.clear(); runways[i]->BuildShoulder( rwy_polys, slivers, pvmt_accum ); // Now try to merge any slivers we found - tgPolygon::MergeSlivers( rwy_polys, slivers ); - tgPolygon::MergeSlivers( pvmt_polys, slivers ); + //tgPolygon::MergeSlivers( rwy_polys, slivers ); + //tgPolygon::MergeSlivers( pvmt_polys, slivers ); } } } @@ -465,12 +468,12 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) if ( helipads[i]->GetsShoulder() ) { - slivers.clear(); + //slivers.clear(); helipads[i]->BuildShoulder( rwy_polys, slivers, pvmt_accum ); // Now try to merge any slivers we found - tgPolygon::MergeSlivers( rwy_polys, slivers ); - tgPolygon::MergeSlivers( pvmt_polys, slivers ); + //tgPolygon::MergeSlivers( rwy_polys, slivers ); + //tgPolygon::MergeSlivers( pvmt_polys, slivers ); } } } @@ -628,14 +631,15 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) TG_LOG( SG_GENERAL, SG_ALERT, "Finished cleaning polys for " << icao << " at " << DebugTimeToString(log_time) ); base_poly = tgPolygon::AddColinearNodes( base_poly, tmp_pvmt_nodes ); - base_poly = tgPolygon::Snap( base_poly, gSnap ); - + // base_poly = tgPolygon::Snap( base_poly, gSnap ); + // Finally find slivers in base - slivers.clear(); - tgPolygon::RemoveSlivers( base_poly, slivers ); - tgPolygon::MergeSlivers( rwy_polys, slivers ); - tgPolygon::MergeSlivers( pvmt_polys, slivers ); - + //slivers.clear(); + //tgPolygon::RemoveSlivers( base_poly, slivers ); + //tgPolygon::MergeSlivers( rwy_polys, slivers ); + //tgPolygon::MergeSlivers( pvmt_polys, slivers ); + +#if 0 // Then snap rwy and pavement to grid (was done right after adding intermediate nodes...) for ( unsigned int k = 0; k < rwy_polys.size(); ++k ) { @@ -653,10 +657,15 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) poly = tgPolygon::RemoveBadContours( poly ); pvmt_polys[k] = poly; } - +#endif + cleanup_end.stamp(); cleanup_time = cleanup_end - cleanup_start; - + + /* before tessellating the base, make sure there are no + intersecting contours */ + base_poly = tgPolygon::Simplify( base_poly ); + triangulation_start.stamp(); // tesselate the polygons and prepair them for final output @@ -669,6 +678,14 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) TG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << rwy_polys[i].Contours() << " total points before = " << rwy_polys[i].TotalNodes()); rwy_polys[i].Tesselate(); + +#if 0 + // dump the triangles for each poly + char desc[128]; + sprintf( desc, "poly_%06d", i ); + tgShapefile::FromTriangles( rwy_polys[i], debug_root, "rwy_polys", desc ); +#endif + TG_LOG(SG_GENERAL, SG_DEBUG, "triangles after = " << rwy_polys[i].Triangles()); rwy_polys[i].Texture(); } @@ -684,6 +701,13 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) TG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << pvmt_polys[i].Contours() << " total points before = " << pvmt_polys[i].TotalNodes()); pvmt_polys[i].Tesselate(); + +#if 0 + char desc[128]; + sprintf( desc, "poly_%06d", i ); + tgShapefile::FromTriangles( pvmt_polys[i], debug_root, "pvmt_polys", desc ); +#endif + TG_LOG(SG_GENERAL, SG_DEBUG, "triangles after = " << pvmt_polys[i].Triangles()); pvmt_polys[i].Texture(); } @@ -699,17 +723,27 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) TG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << line_polys[i].Contours() << " total points before = " << line_polys[i].TotalNodes()); line_polys[i].Tesselate(); + +#if 0 + char desc[128]; + sprintf( desc, "poly_%06d", i ); + tgShapefile::FromTriangles( line_polys[i], debug_root, "line_polys", desc ); +#endif + TG_LOG(SG_GENERAL, SG_DEBUG, "triangles after = " << line_polys[i].Triangles()); line_polys[i].Texture(); } } - - /* before tessellating the base, make sure there are no - intersecting contours */ - base_poly = tgPolygon::Simplify( base_poly ); - + TG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly : " << base_poly.Contours() << " contours " ); base_poly.Tesselate(); + +#if 0 + char desc[128]; + sprintf( desc, "poly" ); + tgShapefile::FromTriangles( base_poly, debug_root, "base_poly", desc ); +#endif + TG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly - done : Triangles = " << base_poly.Triangles()); // should we texture base here? base_poly.SetTexMethod( TG_TEX_BY_GEODE, b.get_center_lat() ); @@ -726,6 +760,15 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) triangulation_time = triangulation_end - triangulation_start; +#if 0 + // CheckZFighting( "post triangulation", debug_root, base_poly, rwy_polys, pvmt_polys ); + if ( CheckZFightingTriangles( "post triangulation tris", debug_root, base_poly, rwy_polys, pvmt_polys ) ) { + char cmd[128]; + sprintf( cmd, "echo %s >> zfight.txt\n", icao.c_str() ); + system ( cmd ); + } +#endif + // // We should now have the runway polygons all generated with their // corresponding triangles and texture coordinates, and the @@ -1166,3 +1209,142 @@ void Airport::BuildBtg(const std::string& root, const string_list& elev_src ) chopper.Add( apt_clearing, "Airport" ); chopper.Save( false ); } + +bool Airport::CheckZFightingTriangles( const char* prefix, const char* debug_root, const tgPolygon& base_poly, const tgpolygon_list& rwy_polys, const tgpolygon_list& pvmt_polys ) +{ + char layer[128]; + char desc[128]; + + sprintf( layer, "zfighting_%s", prefix ); + double min_area_thresh = 1.0e-10; + + bool zfighting = false; + + if ( rwy_polys.size() ) { + for ( unsigned int i = 0; i < rwy_polys.size(); ++i ) { + tgPolygon subject = rwy_polys[i]; + for ( unsigned int j = 0; j < subject.Triangles(); ++j ) { + tgTriangle subTri = subject.GetTriangle( j ); + tgRectangle subBB = subTri.GetBoundingBox(); + + for ( unsigned int k = 0; k < pvmt_polys.size(); ++k ) { + tgPolygon test = pvmt_polys[k]; + for ( unsigned int l = 0; l < test.Triangles(); ++l ) { + tgTriangle testTri = test.GetTriangle( l ); + tgRectangle testBB = testTri.GetBoundingBox(); + + if ( subBB.intersects( testBB ) ) { + // find the intersection + tgPolygon intersection = tgTriangle::Intersect( subTri, testTri ); + + for ( unsigned int m = 0; m < intersection.Contours(); m++ ) { + tgContour intContour = intersection.GetContour( m ); + if ( (intContour.GetSize() > 2) && (intContour.GetArea() > min_area_thresh) ) { + TG_LOG( SG_GENERAL, SG_ALERT, prefix << "Z-FIGHTING between runway poly " << i << " and pavement poly " << k << " contour has " << intContour.GetSize() << " nodes " << " area is " << intContour.GetArea() ); + sprintf( desc, "rwy_%06d_pvmt_%06d", i, j ); + tgShapefile::FromContour( intContour, debug_root, layer, desc ); + zfighting = true; + } + } + } + } + } + } + } + } + + // intersect each pavement poly with each pavement, runway, and base poly + if ( pvmt_polys.size() ) { + for ( unsigned int i = 0; i < pvmt_polys.size(); ++i ) { + tgPolygon subject = pvmt_polys[i]; + for ( unsigned int j = 0; j < subject.Triangles(); ++j ) { + tgTriangle subTri = subject.GetTriangle( j ); + tgRectangle subBB = subTri.GetBoundingBox(); + + for ( unsigned int k = 0; k < rwy_polys.size(); ++k ) { + tgPolygon test = rwy_polys[k]; + for ( unsigned int l = 0; l < test.Triangles(); ++l ) { + tgTriangle testTri = test.GetTriangle( l ); + tgRectangle testBB = testTri.GetBoundingBox(); + + if ( subBB.intersects( testBB ) ) { + // find the intersection + tgPolygon intersection = tgTriangle::Intersect( subTri, testTri ); + + for ( unsigned int m = 0; m < intersection.Contours(); m++ ) { + tgContour intContour = intersection.GetContour( m ); + if ( (intContour.GetSize() > 2) && (intContour.GetArea() > min_area_thresh) ) { + TG_LOG( SG_GENERAL, SG_ALERT, prefix << "Z-FIGHTING between pavement poly " << i << " and runway poly " << k << " contour has " << intContour.GetSize() << " nodes " << " area is " << intContour.GetArea() ); + sprintf( desc, "pvmt_%06d_rwy_%06d", i, j ); + tgShapefile::FromContour( intContour, debug_root, layer, desc ); + zfighting = true; + } + } + } + } + } + } + } + } + + // intersect base poly with each runway and pavement poly + tgPolygon subject = base_poly; + + for ( unsigned int i = 0; i < subject.Triangles(); ++i ) { + tgTriangle subTri = subject.GetTriangle( i ); + tgRectangle subBB = subTri.GetBoundingBox(); + + for ( unsigned int j = 0; j < rwy_polys.size(); ++j ) { + tgPolygon test = rwy_polys[j]; + for ( unsigned int k = 0; k < test.Triangles(); ++k ) { + tgTriangle testTri = test.GetTriangle( k ); + tgRectangle testBB = testTri.GetBoundingBox(); + + if ( subBB.intersects( testBB ) ) { + // find the intersection + tgPolygon intersection = tgTriangle::Intersect( subTri, testTri ); + + for ( unsigned int m = 0; m < intersection.Contours(); m++ ) { + tgContour intContour = intersection.GetContour( m ); + if ( (intContour.GetSize() > 2) && (intContour.GetArea() > min_area_thresh) ) { + TG_LOG( SG_GENERAL, SG_ALERT, prefix << "Z-FIGHTING between base poly and runway poly " << j << " contour has " << intContour.GetSize() << " nodes " << " area is " << intContour.GetArea() ); + sprintf( desc, "base_rwy_%06d", j ); + tgShapefile::FromContour( intContour, debug_root, layer, desc ); + zfighting = true; + } + } + } + } + } + } + + for ( unsigned int i = 0; i < subject.Triangles(); ++i ) { + tgTriangle subTri = subject.GetTriangle( i ); + tgRectangle subBB = subTri.GetBoundingBox(); + + for ( unsigned int j = 0; j < pvmt_polys.size(); ++j ) { + tgPolygon test = pvmt_polys[j]; + for ( unsigned int k = 0; k < test.Triangles(); ++k ) { + tgTriangle testTri = test.GetTriangle( k ); + tgRectangle testBB = testTri.GetBoundingBox(); + + if ( subBB.intersects( testBB ) ) { + // find the intersection + tgPolygon intersection = tgTriangle::Intersect( subTri, testTri ); + + for ( unsigned int m = 0; m < intersection.Contours(); m++ ) { + tgContour intContour = intersection.GetContour( m ); + if ( (intContour.GetSize() > 2) && (intContour.GetArea() > min_area_thresh) ) { + TG_LOG( SG_GENERAL, SG_ALERT, prefix << "Z-FIGHTING between base poly and pavement poly " << j << " contour has " << intContour.GetSize() << " nodes " << " area is " << intContour.GetArea() ); + sprintf( desc, "base_pvmt_%06d", j ); + tgShapefile::FromContour( intContour, debug_root, layer, desc ); + zfighting = true; + } + } + } + } + } + } + + return zfighting; +} \ No newline at end of file diff --git a/src/Airports/GenAirports850/airport.hxx b/src/Airports/GenAirports850/airport.hxx index a72ae7a5..74ab00f0 100644 --- a/src/Airports/GenAirports850/airport.hxx +++ b/src/Airports/GenAirports850/airport.hxx @@ -131,6 +131,8 @@ public: bool isDebugFeature ( int i ); private: + bool CheckZFightingTriangles( const char* prefix, const char* debug_root, const tgPolygon& base_poly, const tgpolygon_list& rwy_polys, const tgpolygon_list& pvmt_polys ); + int code; // airport, heliport or sea port int altitude; // in meters std::string icao; // airport code diff --git a/src/Airports/GenAirports850/closedpoly.cxx b/src/Airports/GenAirports850/closedpoly.cxx index a558750e..a96f4e86 100644 --- a/src/Airports/GenAirports850/closedpoly.cxx +++ b/src/Airports/GenAirports850/closedpoly.cxx @@ -1,3 +1,4 @@ +#include #include #include @@ -457,21 +458,36 @@ int ClosedPoly::BuildBtg( tgpolygon_list& rwy_polys, tgcontour_list& slivers, tg int ClosedPoly::BuildBtg( tgpolygon_list& rwy_polys, tgcontour_list& slivers, tgAccumulator& accum, std::string& shapefile_name ) { + char layer[128]; + if ( is_pavement && pre_tess.Contours() ) { if( shapefile_name.size() ) { - tgShapefile::FromPolygon( pre_tess, "./airport_dbg", std::string("preclip"), shapefile_name ); - accum.ToShapefiles( "./airport_dbg", "accum", true ); + sprintf( layer, "%s_preclip", shapefile_name.c_str() ); + tgShapefile::FromPolygon( pre_tess, "./airport_dbg", layer, std::string("preclip") ); + + pre_tess.Tesselate(); + sprintf( layer, "%s_preclip_tris", shapefile_name.c_str() ); + tgShapefile::FromTriangles( pre_tess, "./airport_dbg", layer, std::string("preclip") ); + + //accum.ToShapefiles( "./airport_dbg", "accum", true ); } tgPolygon clipped = accum.Diff( pre_tess ); if ( clipped.Contours() ) { if( shapefile_name.size() ) { - tgShapefile::FromPolygon( clipped, "./airport_dbg", std::string("postclip"), shapefile_name ); + sprintf( layer, "%s_postclip", shapefile_name.c_str() ); + tgShapefile::FromPolygon( clipped, "./airport_dbg", layer, std::string("postclip") ); } - tgPolygon::RemoveSlivers( clipped, slivers ); + // tgPolygon::RemoveSlivers( clipped, slivers ); + if( shapefile_name.size() ) { + clipped.Tesselate(); + sprintf( layer, "%s_postclip_tris", shapefile_name.c_str() ); + tgShapefile::FromTriangles( clipped, "./airport_dbg", layer, std::string("postclip") ); + } + clipped.SetMaterial( GetMaterial( surface_type ) ); clipped.SetTexParams( clipped.GetNode(0,0), 5.0, 5.0, texture_heading ); clipped.SetTexLimits( 0.0, 0.0, 1.0, 1.0 ); diff --git a/src/Airports/GenAirports850/helipad.cxx b/src/Airports/GenAirports850/helipad.cxx index 0c46f934..6c26c925 100644 --- a/src/Airports/GenAirports850/helipad.cxx +++ b/src/Airports/GenAirports850/helipad.cxx @@ -146,7 +146,7 @@ void Helipad::BuildBtg( tgpolygon_list& rwy_polys, // Clip the new polygon against what ever has already been created. tgPolygon clipped = accum.Diff( helipad ); - tgPolygon::RemoveSlivers( clipped, slivers ); + // tgPolygon::RemoveSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain @@ -171,7 +171,7 @@ void Helipad::BuildBtg( tgpolygon_list& rwy_polys, tgPolygon outer_poly = tgContour::Diff( outer_area, heli_poly ); clipped = accum.Diff( outer_poly ); - tgPolygon::RemoveSlivers( clipped, slivers ); + // tgPolygon::RemoveSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain @@ -249,7 +249,7 @@ void Helipad::BuildShoulder( tgpolygon_list& rwy_polys, // Clip the new polygon against what ever has already been created. tgPolygon clipped = accum.Diff( shoulder ); - tgPolygon::RemoveSlivers( clipped, slivers ); + // tgPolygon::RemoveSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain diff --git a/src/Airports/GenAirports850/rwy_gen.cxx b/src/Airports/GenAirports850/rwy_gen.cxx index fe53f4a3..8f728849 100644 --- a/src/Airports/GenAirports850/rwy_gen.cxx +++ b/src/Airports/GenAirports850/rwy_gen.cxx @@ -313,7 +313,7 @@ void Runway::gen_runway_section( const tgPolygon& runway, tgShapefile::FromPolygon( clipped, "./airport_dbg", std::string("postclip"), shapefile_name ); } - tgPolygon::RemoveSlivers( clipped, slivers ); + //tgPolygon::RemoveSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain @@ -451,7 +451,7 @@ void Runway::gen_runway_section( const tgPolygon& runway, // Clip the new polygon against what ever has already been created. tgPolygon clipped = accum.Diff( section ); - tgPolygon::RemoveSlivers( clipped, slivers ); + //tgPolygon::RemoveSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain @@ -875,7 +875,7 @@ void Runway::BuildShoulder( tgpolygon_list& rwy_polys, // Clip the new polygon against what ever has already been created. tgPolygon clipped = accum.Diff( shoulder ); - tgPolygon::RemoveSlivers( clipped, slivers ); + //tgPolygon::RemoveSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain diff --git a/src/BuildTiles/Main/tgconstruct.cxx b/src/BuildTiles/Main/tgconstruct.cxx index 8ecf346b..1e0082f8 100644 --- a/src/BuildTiles/Main/tgconstruct.cxx +++ b/src/BuildTiles/Main/tgconstruct.cxx @@ -93,7 +93,7 @@ void TGConstruct::run() if ( debug_shapes.size() || debug_all ) { sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() ); } else { - strcpy( ds_name, "" ); + sprintf(ds_name, "%s/constructdbg_%s", debug_path.c_str(), bucket.gen_index_str().c_str() ); } if ( stage == 1 ) { diff --git a/src/BuildTiles/Main/tgconstruct_clip.cxx b/src/BuildTiles/Main/tgconstruct_clip.cxx index b6a9ef83..1aa47327 100644 --- a/src/BuildTiles/Main/tgconstruct_clip.cxx +++ b/src/BuildTiles/Main/tgconstruct_clip.cxx @@ -218,6 +218,8 @@ bool TGConstruct::ClipLandclassPolys( void ) { // finally, what ever is left over goes to ocean remains = accum.Diff( safety_base ); + // tgShapefile::FromPolygon( remains, ds_name, "remains", "poly" ); + if ( debug_all || debug_shapes.size() || debug_areas.size() ) { char layer[32]; char name[32]; diff --git a/src/Lib/terragear/tg_misc.cxx b/src/Lib/terragear/tg_misc.cxx index 2931607d..615960fa 100644 --- a/src/Lib/terragear/tg_misc.cxx +++ b/src/Lib/terragear/tg_misc.cxx @@ -8,7 +8,7 @@ #include "tg_polygon.hxx" #include "tg_misc.hxx" -const double isEqual2D_Epsilon = 0.000001; +const double isEqual2D_Epsilon = 0.000000001; #define CLIPPER_FIXEDPT (1000000000000) #define CLIPPER_METERS_PER_DEGREE (111000) diff --git a/src/Lib/terragear/tg_polygon.hxx b/src/Lib/terragear/tg_polygon.hxx index f24f1948..0329d089 100644 --- a/src/Lib/terragear/tg_polygon.hxx +++ b/src/Lib/terragear/tg_polygon.hxx @@ -112,6 +112,29 @@ public: idx_list.resize( 3, -1 ); } + tgRectangle GetBoundingBox( void ) const + { + SGGeod min, max; + + double minx = std::numeric_limits::infinity(); + double miny = std::numeric_limits::infinity(); + double maxx = -std::numeric_limits::infinity(); + double maxy = -std::numeric_limits::infinity(); + + for (unsigned int i = 0; i < node_list.size(); i++) { + SGGeod pt = GetNode(i); + if ( pt.getLongitudeDeg() < minx ) { minx = pt.getLongitudeDeg(); } + if ( pt.getLongitudeDeg() > maxx ) { maxx = pt.getLongitudeDeg(); } + if ( pt.getLatitudeDeg() < miny ) { miny = pt.getLatitudeDeg(); } + if ( pt.getLatitudeDeg() > maxy ) { maxy = pt.getLatitudeDeg(); } + } + + min = SGGeod::fromDeg( minx, miny ); + max = SGGeod::fromDeg( maxx, maxy ); + + return tgRectangle( min, max ); + } + SGGeod const& GetNode( unsigned int i ) const { return node_list[i]; } @@ -155,6 +178,9 @@ public: p3.getLongitudeDeg() * p1.getLatitudeDeg() - p1.getLongitudeDeg() * p3.getLatitudeDeg() )); } + static ClipperLib::Path ToClipper( const tgTriangle& subject ); + static tgPolygon Intersect( const tgTriangle& subject, const tgTriangle& clip ); + void SaveToGzFile( gzFile& fp ) const; void LoadFromGzFile( gzFile& fp ); @@ -282,6 +308,9 @@ public: void AddTriangle( const SGGeod& p1, const SGGeod p2, const SGGeod p3 ) { triangles.push_back( tgTriangle( p1, p2, p3 ) ); } + tgTriangle GetTriangle( unsigned int t ) { + return triangles[t]; + } SGGeod GetTriNode( unsigned int c, unsigned int i ) const { return triangles[c].GetNode( i ); diff --git a/src/Lib/terragear/tg_polygon_clip.cxx b/src/Lib/terragear/tg_polygon_clip.cxx index 1fbc958b..359f9ef5 100644 --- a/src/Lib/terragear/tg_polygon_clip.cxx +++ b/src/Lib/terragear/tg_polygon_clip.cxx @@ -4,6 +4,7 @@ #include #include "tg_polygon.hxx" +#include "tg_misc.hxx" static bool clipper_dump = false; void tgPolygon::SetClipperDump( bool dmp ) @@ -197,3 +198,52 @@ tgPolygon tgPolygon::FromClipper( const ClipperLib::Paths& subject ) return result; } + +ClipperLib::Path tgTriangle::ToClipper( const tgTriangle& subject ) +{ + ClipperLib::Path contour; + + for ( unsigned int i=0; i<3; i++) + { + SGGeod p = subject.GetNode( i ); + contour.push_back( SGGeod_ToClipper(p) ); + } + + // boundaries need to be orientation: true + if ( !Orientation( contour ) ) { + //SG_LOG(SG_GENERAL, SG_INFO, "Building clipper contour - boundary contour needs to be reversed" ); + ReversePath( contour ); + } + + return contour; +} + +tgPolygon tgTriangle::Intersect( const tgTriangle& subject, const tgTriangle& clip ) +{ + tgPolygon result; + UniqueSGGeodSet all_nodes; + + /* before diff - gather all nodes */ + for ( unsigned int i = 0; i < 3; ++i ) { + all_nodes.add( subject.GetNode(i) ); + } + + for ( unsigned int i = 0; i < 3; ++i ) { + all_nodes.add( clip.GetNode(i) ); + } + + ClipperLib::Path clipper_subject = tgTriangle::ToClipper( subject ); + ClipperLib::Path clipper_clip = tgTriangle::ToClipper( clip ); + ClipperLib::Paths clipper_result; + + ClipperLib::Clipper c; + c.Clear(); + c.AddPath(clipper_subject, ClipperLib::ptSubject, true); + c.AddPath(clipper_clip, ClipperLib::ptClip, true); + c.Execute(ClipperLib::ctIntersection, clipper_result, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); + + result = tgPolygon::FromClipper( clipper_result ); + result = tgPolygon::AddColinearNodes( result, all_nodes ); + + return result; +} diff --git a/src/Lib/terragear/tg_polygon_tesselate.cxx b/src/Lib/terragear/tg_polygon_tesselate.cxx index 181f00ac..9cc29021 100644 --- a/src/Lib/terragear/tg_polygon_tesselate.cxx +++ b/src/Lib/terragear/tg_polygon_tesselate.cxx @@ -105,6 +105,9 @@ void tgPolygon::Tesselate( const std::vector& extra ) SG_LOG( SG_GENERAL, SG_DEBUG, "Tess with extra" ); + // clear any triangles from previous tesselation + triangles.clear(); + // Bail right away if polygon is empty if ( contours.size() != 0 ) { // First, convert the extra points to cgal Points @@ -162,6 +165,9 @@ void tgPolygon::Tesselate() SG_LOG( SG_GENERAL, SG_DEBUG, "Tess" ); + // clear any triangles from previous tesselation + triangles.clear(); + // Bail right away if polygon is empty if ( contours.size() != 0 ) { // insert each polygon as a constraint into the triangulation diff --git a/src/Lib/terragear/tg_shapefile.cxx b/src/Lib/terragear/tg_shapefile.cxx index acbfed3e..54001719 100644 --- a/src/Lib/terragear/tg_shapefile.cxx +++ b/src/Lib/terragear/tg_shapefile.cxx @@ -65,6 +65,34 @@ void* tgShapefile::OpenLayer( void* ds_id, const char* layer_name ) { return (void*)layer; } +void* tgShapefile::OpenLineLayer( void* ds_id, const char* layer_name ) { + OGRDataSource* datasource = ( OGRDataSource * )ds_id; + OGRLayer* layer; + + OGRSpatialReference srs; + srs.SetWellKnownGeogCS("WGS84"); + + layer = datasource->GetLayerByName( layer_name ); + + if ( !layer ) { + layer = datasource->CreateLayer( layer_name, &srs, wkbLineString25D, NULL ); + + OGRFieldDefn descriptionField( "ID", OFTString ); + descriptionField.SetWidth( 128 ); + + if( layer->CreateField( &descriptionField ) != OGRERR_NONE ) { + SG_LOG( SG_GENERAL, SG_ALERT, "Creation of field 'Description' failed" ); + } + } + + if ( !layer ) { + SG_LOG( SG_GENERAL, SG_ALERT, "Creation of layer '" << layer_name << "' failed" ); + return NULL; + } + + return (void*)layer; +} + void* tgShapefile::CloseDatasource( void* ds_id ) { OGRDataSource* datasource = ( OGRDataSource * )ds_id; @@ -172,6 +200,46 @@ void tgShapefile::FromContour( const tgContour& subject, const std::string& data ds_id = tgShapefile::CloseDatasource( ds_id ); } +void tgShapefile::FromTriangles( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& description ) +{ + void* ds_id = tgShapefile::OpenDatasource( datasource.c_str() ); + SG_LOG(SG_GENERAL, SG_DEBUG, "tgShapefile::OpenDatasource returned " << (unsigned long)ds_id); + + OGRLayer* l_id = (OGRLayer *)tgShapefile::OpenLineLayer( ds_id, layer.c_str() ); + SG_LOG(SG_GENERAL, SG_DEBUG, "tgShapefile::OpenLayer returned " << (unsigned long)l_id); + + SG_LOG(SG_GENERAL, SG_DEBUG, "subject has " << subject.Contours() << " contours "); + + for ( unsigned int i = 0; i < subject.Triangles(); i++ ) { + // FIXME: Current we ignore the hole-flag and instead assume + // that the first ring is not a hole and the rest + // are holes + OGRLinearRing ring; + for (unsigned int pt = 0; pt < 3; pt++) { + OGRPoint point; + + point.setX( subject.GetTriNode(i, pt).getLongitudeDeg() ); + point.setY( subject.GetTriNode(i, pt).getLatitudeDeg() ); + point.setZ( 0.0 ); + ring.addPoint(&point); + } + ring.closeRings(); + + OGRFeature* feature = NULL; + feature = new OGRFeature( l_id->GetLayerDefn() ); + feature->SetField("ID", description.c_str()); + feature->SetGeometry(&ring); + if( l_id->CreateFeature( feature ) != OGRERR_NONE ) + { + SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create feature in shapefile"); + } + OGRFeature::DestroyFeature(feature); + } + + // close after each write + ds_id = tgShapefile::CloseDatasource( ds_id ); +} + void tgShapefile::FromPolygon( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& description ) { void* ds_id = tgShapefile::OpenDatasource( datasource.c_str() ); diff --git a/src/Lib/terragear/tg_shapefile.hxx b/src/Lib/terragear/tg_shapefile.hxx index 43520ee6..d40ac46d 100644 --- a/src/Lib/terragear/tg_shapefile.hxx +++ b/src/Lib/terragear/tg_shapefile.hxx @@ -8,6 +8,7 @@ class tgShapefile public: static void FromContour( const tgContour& subject, const std::string& datasource, const std::string& layer, const std::string& description ); static void FromPolygon( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& description ); + static void FromTriangles( const tgPolygon& subject, const std::string& datasource, const std::string& layer, const std::string& description ); static tgPolygon ToPolygon( const void* subject ); static void FromClipper( const ClipperLib::Paths& subject, const std::string& datasource, const std::string& layer, const std::string& description ); @@ -17,5 +18,6 @@ private: static void* OpenDatasource( const char* datasource_name ); static void* OpenLayer( void* ds_id, const char* layer_name ); + static void* OpenLineLayer( void* ds_id, const char* layer_name ); static void* CloseDatasource( void* ds_id ); }; \ No newline at end of file