diff --git a/src/Airports/GenAirports850/airport.cxx b/src/Airports/GenAirports850/airport.cxx index 637c4c06..c1e68c89 100644 --- a/src/Airports/GenAirports850/airport.cxx +++ b/src/Airports/GenAirports850/airport.cxx @@ -85,6 +85,12 @@ Airport::Airport( int c, char* def) altitude *= SG_FEET_TO_METER; boundary = NULL; + dbg_rwy_poly = -1; + dbg_pvmt_poly = -1; + dbg_feat_poly = -1; + dbg_base_poly = -1; + + SG_LOG( SG_GENERAL, SG_DEBUG, "Created airport with icao " << icao << ", control tower " << ct << ", and description " << description ); } @@ -141,6 +147,15 @@ Airport::~Airport() } } +void Airport::SetDebugPolys( int rwy, int pvmt, int feat, int base ) +{ + dbg_rwy_poly = rwy; + dbg_pvmt_poly = pvmt; + dbg_feat_poly = feat; + dbg_base_poly = base; +} + + // TODO: Add to runway object // calculate texture coordinates for runway section using the provided // texturing parameters. Returns a mirror polygon to the runway, @@ -362,12 +377,71 @@ static TGPolygon calc_elevations( TGAptSurface &surf, return result; } + +void Airport::merge_slivers( superpoly_list& polys, poly_list& slivers_list ) { + TGPolygon poly, result, slivers, sliver; + point_list contour; + int original_contours, result_contours; + bool done; + int i, j, k; + + for ( i = 0; i < (int)slivers_list.size(); i++ ) { + slivers = slivers_list[i]; + for ( j = 0; j < slivers.contours(); ++j ) { + SG_LOG(SG_GENERAL, SG_DEBUG, "Merging sliver = " << i << ", " << j); + + // make the sliver polygon + contour = slivers.get_contour( j ); + sliver.erase(); + sliver.add_contour( contour, 0 ); + done = false; + + // try to merge the slivers with the list of clipped polys + for ( k = 0; k < (int)polys.size() && !done; ++k ) { + poly = polys[k].get_poly(); + original_contours = poly.contours(); + result = tgPolygonUnionClipper( poly, sliver ); + result_contours = result.contours(); + + if ( original_contours == result_contours ) { + SG_LOG(SG_GENERAL, SG_DEBUG, " FOUND a poly to merge the sliver with"); + polys[k].set_poly( result ); + done = true; + + // poly.write("orig"); + // sliver.write("sliver"); + // result.write("result"); + // cout << "press return: "; + // string input; + // cin >> input; + } else { + // cout << " poly not a match" << endl; + // cout << " original = " << original_contours + // << " result = " << result_contours << endl; + // cout << " sliver = " << endl; + // for ( k = 0; k < (int)contour.size(); ++k ) { + // cout << " " << contour[k].x() << ", " + // << contour[k].y() << endl; + } + } + + if ( !done ) { + SG_LOG(SG_GENERAL, SG_DEBUG, "couldn't merge sliver " << i << ", " << j); + } + } + } +} + + + void Airport::BuildBtg(const string& root, const string_list& elev_src ) { ClipPolyType accum; + poly_list slivers; // try to keep line accumulator in clipper format for speed... ClipPolyType line_accum; + poly_list line_slivers; TGPolygon apt_base; TGPolygon apt_clearing; @@ -388,6 +462,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) Point3D p; bool verbose_triangulation = false; + bool make_shapefiles = false; // parse main airport information double apt_lon = 0.0, apt_lat = 0.0; @@ -432,14 +507,6 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) } } -#if 0 - if (icao == "SSOK") - { - SG_LOG(SG_GENERAL, SG_ALERT, "Injecting error at icao " << icao ); - exit(-1); - } -#endif - // Starting to clip the polys gettimeofday(&build_start, NULL); @@ -450,16 +517,15 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) { SG_LOG(SG_GENERAL, SG_INFO, "Build Feature Poly " << i + 1 << " of " << features.size() << " : " << features[i]->GetDescription() ); -#if 0 - if ( i == 22 ) { - features[i]->BuildBtg( altitude, &line_polys, &line_tps, &line_accum, &rwy_lights, true ); - } else { - //features[i]->BuildBtg( altitude, &line_polys, &line_tps, &line_accum, &rwy_lights, false ); - } -#else - features[i]->BuildBtg( altitude, &line_polys, &line_tps, &line_accum, &rwy_lights, false ); -#endif + if ( (dbg_feat_poly >= 0) && (i == (unsigned int)dbg_feat_poly) ) { + SG_LOG(SG_GENERAL, SG_INFO, "Problem feat poly (" << i << ")"); + make_shapefiles = true; + } else { + make_shapefiles = false; + } + + features[i]->BuildBtg( altitude, &line_polys, &line_tps, &line_accum, &rwy_lights, make_shapefiles ); } } else @@ -474,18 +540,22 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) for ( unsigned int i=0; iIsPrecision() ) { if (boundary) { - runways[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, NULL, NULL ); + runways[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, NULL, NULL ); } else { - runways[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, &apt_base, &apt_clearing ); + runways[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, &apt_base, &apt_clearing ); } } + + // Now try to merge any slivers we found + merge_slivers( rwy_polys, slivers ); } gettimeofday(&log_time, NULL); @@ -506,14 +576,19 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) for ( unsigned int i=0; iBuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, NULL, NULL ); + helipads[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, NULL, NULL ); } else { - helipads[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, &apt_base, &apt_clearing ); + helipads[i]->BuildBtg( altitude, &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, &apt_base, &apt_clearing ); } + + // Now try to merge any slivers we found + merge_slivers( rwy_polys, slivers ); } } @@ -523,23 +598,28 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) for ( unsigned int i=0; iGetDescription()); + slivers.clear(); -#if 0 - if (i == 30) { - sglog().setLogLevels( SG_GENERAL, SG_BULK ); + if ( (dbg_pvmt_poly >= 0) && (i == (unsigned int)dbg_pvmt_poly) ) { + SG_LOG(SG_GENERAL, SG_INFO, "Problem pvmt poly (" << i << ")"); + + make_shapefiles = true; } else { - sglog().setLogLevels( SG_GENERAL, SG_INFO ); + make_shapefiles = false; } -#endif if (boundary) { - pavements[i]->BuildBtg( altitude, &pvmt_polys, &pvmt_tps, &accum, NULL, NULL ); + pavements[i]->BuildBtg( altitude, &pvmt_polys, &pvmt_tps, &accum, slivers, NULL, NULL, make_shapefiles ); } else { - pavements[i]->BuildBtg( altitude, &pvmt_polys, &pvmt_tps, &accum, &apt_base, &apt_clearing ); + pavements[i]->BuildBtg( altitude, &pvmt_polys, &pvmt_tps, &accum, slivers, &apt_base, &apt_clearing, make_shapefiles ); } + + // Now try to merge any slivers we found + merge_slivers( rwy_polys, slivers ); + merge_slivers( pvmt_polys, slivers ); } } else @@ -550,15 +630,20 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) gettimeofday(&log_time, NULL); SG_LOG( SG_GENERAL, SG_ALERT, "Finished building pavements for " << icao << " at " << ctime(&log_time.tv_sec) ); -#if 0 // Build runway shoulders here +#if 0 for ( unsigned int i=0; iGetsShoulder() ) { - runways[i]->BuildShoulder( altitude, &rwy_polys, &rwy_tps, &accum, &apt_base, &apt_clearing ); + slivers.clear(); + runways[i]->BuildShoulder( altitude, &rwy_polys, &rwy_tps, &accum, slivers, &apt_base, &apt_clearing ); + + // Now try to merge any slivers we found + merge_slivers( rwy_polys, slivers ); + merge_slivers( pvmt_polys, slivers ); } } #endif @@ -567,7 +652,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) if (boundary) { SG_LOG(SG_GENERAL, SG_INFO, "Build user defined boundary " ); - boundary->BuildBtg( altitude, &apt_base, &apt_clearing ); + boundary->BuildBtg( altitude, &apt_base, &apt_clearing, false ); } if ( apt_base.total_size() == 0 ) @@ -576,9 +661,10 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) return; } + TGPolygon filled_base = tgPolygonStripHoles( apt_base ); TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 ); - TGPolygon base_poly = tgPolygonDiff( divided_base, accum ); + TGPolygon base_poly = tgPolygonDiffClipper( divided_base, accum ); gettimeofday(&build_end, NULL); timersub(&build_end, &build_start, &build_time); @@ -690,6 +776,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) SG_LOG(SG_GENERAL, SG_DEBUG, "total size of section " << k << " before =" << poly.total_size()); +#if 0 poly = remove_cycles( poly ); poly = remove_dups( poly ); poly = remove_bad_contours( poly ); @@ -698,6 +785,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) poly = remove_dups( poly ); poly = remove_bad_contours( poly ); poly = remove_small_contours( poly ); +#endif rwy_polys[k].set_poly( poly ); } @@ -708,6 +796,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) SG_LOG(SG_GENERAL, SG_DEBUG, "total size of section " << k << " before =" << poly.total_size()); +#if 0 poly = remove_cycles( poly ); poly = remove_dups( poly ); poly = remove_bad_contours( poly ); @@ -716,6 +805,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) poly = remove_dups( poly ); poly = remove_bad_contours( poly ); poly = remove_small_contours( poly ); +#endif pvmt_polys[k].set_poly( poly ); } @@ -750,6 +840,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) base_poly = add_nodes_to_poly( base_poly, tmp_pvmt_nodes ); SG_LOG(SG_GENERAL, SG_DEBUG, " after adding tmp_nodes: " << base_poly); +#if 0 base_poly = remove_cycles( base_poly ); base_poly = remove_dups( base_poly ); base_poly = remove_bad_contours( base_poly ); @@ -759,6 +850,15 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) base_poly = remove_dups( base_poly ); base_poly = remove_bad_contours( base_poly ); base_poly = remove_small_contours( base_poly ); +#endif + + // Finally find slivers in base + SG_LOG(SG_GENERAL, SG_INFO, "before find slivers in base - contours is : " << base_poly.contours() ); + tgPolygonFindSlivers( base_poly, slivers ); + SG_LOG(SG_GENERAL, SG_INFO, "after find slivers in base - contours is : " << base_poly.contours() ); + + merge_slivers( rwy_polys, slivers ); + merge_slivers( pvmt_polys, slivers ); gettimeofday(&cleanup_end, NULL); timersub(&cleanup_end, &cleanup_start, &cleanup_time); @@ -772,23 +872,15 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) TGPolygon poly = rwy_polys[i].get_poly(); -#if 0 - if ( i == 2 ) { - SG_LOG(SG_GENERAL, SG_INFO, "Problem poly before remove_dups: " << poly ); + if ( (dbg_rwy_poly >= 0) && (i == (unsigned int)dbg_rwy_poly) ) { + SG_LOG(SG_GENERAL, SG_INFO, "Problem rwy poly (" << i << ") : " << poly ); - sglog().setLogLevels( SG_GENERAL, SG_BULK ); - poly = remove_dups( poly ); - sglog().setLogLevels( SG_GENERAL, SG_INFO ); - - SG_LOG(SG_GENERAL, SG_INFO, "Problem poly after remove_dups(): " << poly ); - - tgChopNormalPolygon( "/home/pete", "Base", poly, false ); + tgChopNormalPolygon( "/home/pete", "rwy", poly, false ); verbose_triangulation = true; } else { verbose_triangulation = false; } -#endif SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size()); TGPolygon tri = polygon_tesselate_alt( poly, verbose_triangulation ); @@ -808,16 +900,14 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) TGPolygon poly = pvmt_polys[i].get_poly(); -#if 0 - if ( i == 0 ) { - SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly ); + if ( (dbg_pvmt_poly >= 0) && (i == (unsigned int)dbg_pvmt_poly) ) { + SG_LOG(SG_GENERAL, SG_INFO, "Problem pvmt poly (" << i << ") : " << poly ); - tgChopNormalPolygon( "/home/pete", "Base", poly, false ); + tgChopNormalPolygon( "/home/pete", "pvmt", poly, false ); verbose_triangulation = true; } else { verbose_triangulation = false; } -#endif SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size()); TGPolygon tri = polygon_tesselate_alt( poly, verbose_triangulation ); @@ -844,16 +934,14 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) TGPolygon poly = line_polys[i].get_poly(); -#if 0 - if ( i == 282 ) { - SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly ); + if ( (dbg_feat_poly >= 0) && (i == (unsigned int)dbg_feat_poly) ) { + SG_LOG(SG_GENERAL, SG_INFO, "Problem feat poly (" << i << ") : " << poly ); - tgChopNormalPolygon( "/home/pete/", "Base", poly, false ); + tgChopNormalPolygon( "/home/pete/", "feat", poly, false ); verbose_triangulation = true; } else { verbose_triangulation = false; } -#endif SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size()); TGPolygon tri = polygon_tesselate_alt( poly, verbose_triangulation ); @@ -866,19 +954,18 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) line_polys[i].set_texcoords( tc ); } -#if 0 - { - SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << base_poly ); + if ( dbg_base_poly >= 0 ) { + SG_LOG(SG_GENERAL, SG_INFO, "Problem base poly: " << base_poly ); tgChopNormalPolygon( "/home/pete/", "Base", base_poly, false ); verbose_triangulation = true; } -#endif SG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly "); TGPolygon base_tris = polygon_tesselate_alt( base_poly, verbose_triangulation ); - SG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly - done"); + verbose_triangulation = false; + SG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly - done : contours = " << base_tris.contours()); gettimeofday(&triangulation_end, NULL); timersub(&triangulation_end, &triangulation_start, &triangulation_time); @@ -919,12 +1006,16 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src ) int_list pt_n, tri_n, strip_n; int_list tri_tc, strip_tc; + SG_LOG(SG_GENERAL, SG_DEBUG, "Calculating airport normal" ); + // calculate "the" normal for this airport p.setx( base_tris.get_pt(0, 0).x() * SGD_DEGREES_TO_RADIANS ); p.sety( base_tris.get_pt(0, 0).y() * SGD_DEGREES_TO_RADIANS ); p.setz( 0 ); Point3D vnt = sgGeodToCart( p ); + SG_LOG(SG_GENERAL, SG_DEBUG, "Calculating airport normal - done"); + // SG_LOG(SG_GENERAL, SG_DEBUG, "geod = " << p); // SG_LOG(SG_GENERAL, SG_DEBUG, "cart = " << tmp); diff --git a/src/Airports/GenAirports850/airport.hxx b/src/Airports/GenAirports850/airport.hxx index aaa851a5..6ca6a93b 100644 --- a/src/Airports/GenAirports850/airport.hxx +++ b/src/Airports/GenAirports850/airport.hxx @@ -103,8 +103,11 @@ public: tm = cleanup_time; } + void merge_slivers( superpoly_list& polys, poly_list& slivers ); void BuildBtg( const string& root, const string_list& elev_src ); + void SetDebugPolys( int rwy, int pvmt, int feat, int base ); + private: int code; // airport, heliport or sea port int altitude; // in meters @@ -126,6 +129,12 @@ private: struct timeval build_time; struct timeval cleanup_time; struct timeval triangulation_time; + + // debug + int dbg_rwy_poly; + int dbg_pvmt_poly; + int dbg_feat_poly; + int dbg_base_poly; }; typedef std::vector AirportList; diff --git a/src/Airports/GenAirports850/apt_math.cxx b/src/Airports/GenAirports850/apt_math.cxx index ed550a7f..9ed36334 100644 --- a/src/Airports/GenAirports850/apt_math.cxx +++ b/src/Airports/GenAirports850/apt_math.cxx @@ -218,7 +218,8 @@ void gen_tex_section( const TGPolygon& runway, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType *accum ) { + ClipPolyType *accum, + poly_list& slivers ) { int j, k; @@ -315,7 +316,13 @@ void gen_tex_section( const TGPolygon& runway, } // Clip the new polygon against what ever has already been created. +#if 0 TGPolygon clipped = tgPolygonDiff( section, *accum ); +#else + TGPolygon clipped = tgPolygonDiffClipper( section, *accum ); +#endif + + tgPolygonFindSlivers( clipped, slivers ); // Split long edges to create an object that can better flow with // the surface terrain @@ -329,7 +336,12 @@ void gen_tex_section( const TGPolygon& runway, sp.set_material( prefix + material ); rwy_polys->push_back( sp ); SG_LOG(SG_GENERAL, SG_DEBUG, "section = " << clipped.contours()); + +#if 0 *accum = tgPolygonUnion( section, *accum ); +#else + *accum = tgPolygonUnionClipper( section, *accum ); +#endif // Store away what we need to know for texture coordinate // calculation. (CLO 10/20/02: why can't we calculate texture diff --git a/src/Airports/GenAirports850/apt_math.hxx b/src/Airports/GenAirports850/apt_math.hxx index 59e3ead9..41dd46f7 100644 --- a/src/Airports/GenAirports850/apt_math.hxx +++ b/src/Airports/GenAirports850/apt_math.hxx @@ -37,6 +37,7 @@ void gen_tex_section( const TGPolygon& runway, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType *accum ); + ClipPolyType *accum, + poly_list& slivers ); #endif diff --git a/src/Airports/GenAirports850/closedpoly.cxx b/src/Airports/GenAirports850/closedpoly.cxx index a57c1042..f58593c9 100644 --- a/src/Airports/GenAirports850/closedpoly.cxx +++ b/src/Airports/GenAirports850/closedpoly.cxx @@ -4,12 +4,16 @@ #include #include +#include +#include #include #include "beznode.hxx" #include "convex_hull.hxx" #include "closedpoly.hxx" +#define NO_BEZIER (0) + static void stringPurifier( string& s ) { for ( string::iterator it = s.begin(), itEnd = s.end(); it!=itEnd; ++it) { @@ -63,8 +67,6 @@ ClosedPoly::ClosedPoly( int st, float s, float th, char* desc ) ClosedPoly::~ClosedPoly() { SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting ClosedPoly " << description ); - - } void ClosedPoly::AddNode( BezNode* node ) @@ -100,31 +102,6 @@ void ClosedPoly::AddNode( BezNode* node ) } } -#if 0 -void ClosedPoly::CreateConvexHull( void ) -{ - TGPolygon convexHull; - point_list nodes; - Point3D p; - unsigned int i; - - if (boundary->size() > 2) - { - for (i=0; isize(); i++) - { - p = boundary->at(i)->GetLoc(); - nodes.push_back( p ); - } - convexHull = convex_hull( nodes ); - hull = convexHull.get_contour(0); - } - else - { - SG_LOG(SG_GENERAL, SG_ALERT, "Boundary size too small: " << boundary->size() << ". Ignoring..." ); - } -} -#endif - void ClosedPoly::CloseCurContour() { SG_LOG(SG_GENERAL, SG_DEBUG, "Close Contour"); @@ -232,33 +209,15 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst ) } } -#if 0 double num_meters = total_dist / meter_dist; - - // If total distance is < 4 meters, then we need to modify num Segments so that each segment >= 0.5 meter - if (num_meters < 4.0f) - { - num_segs = ((int)num_meters + 1) * 2; - } - else if (num_meters > 800.0f) - { - num_segs = num_meters / 100.0f + 1; - } - else - { - num_segs = 8; - } -#endif - - double num_meters = total_dist / meter_dist; - if (num_meters < 4.0f) + if (num_meters < 8.0f) { if (curve_type != CURVE_LINEAR) { - // If total distance is < 4 meters, then we need to modify num Segments so that each segment >= 1/2 meter - num_segs = ((int)num_meters + 1) * 2; + // If total distance is < 4 meters, then we need to modify num Segments so that each segment >= 2 meters + num_segs = ((int)num_meters + 1); SG_LOG(SG_GENERAL, SG_DEBUG, "Segment from (" << curNode->GetLoc().x() << "," << curNode->GetLoc().y() << ") to (" << nextNode->GetLoc().x() << "," << nextNode->GetLoc().y() << ")" ); - SG_LOG(SG_GENERAL, SG_DEBUG, " Distance is " << num_meters << " ( < 4.0) so num_segs is " << num_segs ); + SG_LOG(SG_GENERAL, SG_DEBUG, " Distance is " << num_meters << " ( < 16.0) so num_segs is " << num_segs ); } else { @@ -277,18 +236,22 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst ) if (curve_type != CURVE_LINEAR) { num_segs = 8; - // num_segs = 16; SG_LOG(SG_GENERAL, SG_DEBUG, "Segment from (" << curNode->GetLoc().x() << "," << curNode->GetLoc().y() << ") to (" << nextNode->GetLoc().x() << "," << nextNode->GetLoc().y() << ")" ); SG_LOG(SG_GENERAL, SG_DEBUG, " Distance is " << num_meters << " (OK) so num_segs is " << num_segs ); } else { // make sure linear segments don't got over 100m - //num_segs = 1; num_segs = num_meters / 100.0f + 1; } + +// num_segs = 1; } +#if NO_BEZIER + num_segs = 1; +#endif + // if only one segment, revert to linear if (num_segs == 1) { @@ -315,7 +278,9 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst ) // add the pavement vertex // convert from lat/lon to geo // (maybe later) - check some simgear objects... + curLoc.snap(); dst->push_back( curLoc ); + if (p==0) { SG_LOG(SG_GENERAL, SG_DEBUG, "adding Curve Anchor node (type " << curve_type << ") at (" << curLoc.x() << "," << curLoc.y() << ")"); @@ -331,12 +296,6 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst ) } else { -// nextLoc = nextNode->GetLoc(); - -// // just add the one vertex - linear -// dst->push_back( curLoc ); -// SG_LOG(SG_GENERAL, SG_DEBUG, "adding Linear Anchor node at (" << curLoc.x() << "," << curLoc.y() << ")"); - if (num_segs > 1) { for (int p=0; pGetLoc(), nextNode->GetLoc(), (1.0f/num_segs) * (p+1) ); // add the feature vertex + curLoc.snap(); dst->push_back( curLoc ); if (p==0) @@ -365,6 +325,7 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst ) nextLoc = nextNode->GetLoc(); // just add the one vertex - dist is small + curLoc.snap(); dst->push_back( curLoc ); SG_LOG(SG_GENERAL, SG_DEBUG, "adding Linear Anchor node at (" << curLoc.x() << "," << curLoc.y() << ")"); @@ -375,140 +336,6 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst ) } } -#if 0 -void ExpandPoint( Point3D *prev, Point3D *cur, Point3D *next, double expand_by, double *heading, double *offset ) -{ - double offset_dir; - double next_dir; - double az2; - double dist; - - SG_LOG(SG_GENERAL, SG_DEBUG, "Find average angle for contour: prev (" << *prev << "), " - "cur (" << *cur << "), " - "next (" << *next << ")" ); - - // first, find if the line turns left or right ar src - // for this, take the cross product of the vectors from prev to src, and src to next. - // if the cross product is negetive, we've turned to the left - // if the cross product is positive, we've turned to the right - // if the cross product is 0, then we need to use the direction passed in - SGVec3d dir1 = prev->toSGVec3d() - cur->toSGVec3d(); - dir1 = normalize(dir1); - - SGVec3d dir2 = next->toSGVec3d() - cur->toSGVec3d(); - dir2 = normalize(dir2); - - // Now find the average - SGVec3d avg = dir1 + dir2; - avg = normalize(avg); - - // find the offset angle - geo_inverse_wgs_84( avg.y(), avg.x(), 0.0f, 0.0f, &offset_dir, &az2, &dist); - - // find the direction to the next point - geo_inverse_wgs_84( cur->y(), cur->x(), next->y(), next->x(), &next_dir, &az2, &dist); - - // calculate correct distance for the offset point - *offset = (expand_by)/sin(SGMiscd::deg2rad(offset_dir-next_dir)); - *heading = offset_dir; - - SG_LOG(SG_GENERAL, SG_DEBUG, "heading is " << *heading << " distance is " << *offset ); -} -#endif - -#if 0 -void ClosedPoly::ExpandContour( point_list& src, TGPolygon& dst, double dist ) -{ - point_list expanded_boundary; - Point3D prevPoint, curPoint, nextPoint; - double theta; - double expanded_x = 0, expanded_y = 0; - Point3D expanded_point; - - double h1; - double o1; - double az2; - unsigned int i; - - // iterate through each bezier node in the contour - for (i=0; iprev and cur->next - theta = SGMiscd::rad2deg(CalculateTheta(prevPoint, curPoint, nextPoint)); - - if ( theta < 90.0 ) - { - SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY case 1 (theta < 90) " << description << ": theta is " << theta ); - - // calculate the expanded point heading and offset from current point - ExpandPoint( &prevPoint, &curPoint, &nextPoint, dist, &h1, &o1 ); - - if (o1 > dist*2.0) - { - SG_LOG(SG_GENERAL, SG_DEBUG, "\ntheta is " << theta << " distance is " << o1 << " CLAMPING to " << dist*2 ); - o1 = dist*2; - } - - geo_direct_wgs_84( curPoint.y(), curPoint.x(), h1, o1, &expanded_y, &expanded_x, &az2 ); - expanded_point = Point3D( expanded_x, expanded_y, 0.0f ); - expanded_boundary.push_back( expanded_point ); - } - else if ( abs(theta - 180.0) < 0.1 ) - { - SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY case 2 (theta close to 180) " << description << ": theta is " << theta ); - - // calculate the expanded point heading and offset from current point - ExpandPoint( &prevPoint, &curPoint, &nextPoint, dist, &h1, &o1 ); - - // straight line blows up math - dist should be exactly as given - o1 = dist; - - geo_direct_wgs_84( curPoint.y(), curPoint.x(), h1, o1, &expanded_y, &expanded_x, &az2 ); - expanded_point = Point3D( expanded_x, expanded_y, 0.0f ); - expanded_boundary.push_back( expanded_point ); - } - else - { - SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY case 3 (fall through) " << description << ": theta is " << theta ); - - // calculate the expanded point heading and offset from current point - ExpandPoint( &prevPoint, &curPoint, &nextPoint, dist, &h1, &o1 ); - - geo_direct_wgs_84( curPoint.y(), curPoint.x(), h1, o1, &expanded_y, &expanded_x, &az2 ); - expanded_point = Point3D( expanded_x, expanded_y, 0.0f ); - expanded_boundary.push_back( expanded_point ); - } - } - - dst.add_contour( expanded_boundary, 9 ); -} -#endif - // finish the poly - convert to TGPolygon, and tesselate void ClosedPoly::Finish() { @@ -558,10 +385,18 @@ void ClosedPoly::Finish() holes.clear(); } -int ClosedPoly::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, ClipPolyType* accum, TGPolygon* apt_base, TGPolygon* apt_clearing ) +int ClosedPoly::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing, bool make_shapefiles ) { TGPolygon base, safe_base; - string material; + string material; + void* ds_id = NULL; // If we are going to build shapefiles + void* l_id = NULL; // datasource and layer IDs + + if ( make_shapefiles ) { + char ds_name[128]; + sprintf(ds_name, "./cp_debug/problem"); + ds_id = tgShapefileOpenDatasource( ds_name ); + } if (is_pavement) { @@ -600,47 +435,49 @@ int ClosedPoly::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: original poly has " << pre_tess.contours() << " contours"); // do this before clipping and generating the base - pre_tess = tgPolygonSimplify( pre_tess ); - pre_tess = reduce_degeneracy( pre_tess ); - - // grow pretess by a little bit - //pre_tess = tgPolygonExpand( pre_tess, 0.05); // 5cm - + // pre_tess = tgPolygonSimplify( pre_tess ); + // pre_tess = reduce_degeneracy( pre_tess ); + TGSuperPoly sp; TGTexParams tp; - SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: expanded poly has " << pre_tess.contours() << " contours"); - for (int i=0; ipush_back( sp ); - SG_LOG(SG_GENERAL, SG_DEBUG, "clipped = " << clipped.contours()); -#if 1 - *accum = tgPolygonUnion( pre_tess, *accum ); -#else + *accum = tgPolygonUnionClipper( pre_tess, *accum ); -#endif + + /* If debugging this poly, write the poly, and clipped poly and the accum buffer into their own layers */ + if (ds_id) { + char layer_name[128]; + char feature_name[128]; + + sprintf( layer_name, "original" ); + l_id = tgShapefileOpenLayer( ds_id, layer_name ); + sprintf( feature_name, "original" ); + tgShapefileCreateFeature( ds_id, l_id, pre_tess, feature_name ); + + sprintf( layer_name, "clipped" ); + l_id = tgShapefileOpenLayer( ds_id, layer_name ); + sprintf( feature_name, "clipped" ); + tgShapefileCreateFeature( ds_id, l_id, clipped, feature_name ); + + sprintf( layer_name, "accum" ); + l_id = tgShapefileOpenLayer( ds_id, layer_name ); + sprintf( feature_name, "accum" ); + tgShapefileCreateFeature( ds_id, l_id, *accum, feature_name ); + + tgShapefileCloseDatasource( ds_id ); + } + tp = TGTexParams( pre_tess.get_pt(0,0), 5.0, 5.0, texture_heading ); texparams->push_back( tp ); @@ -664,7 +501,7 @@ int ClosedPoly::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list // Just used for user defined border - add a little bit, as some modelers made the border exactly on the edges // - resulting in no base, which we can't handle -int ClosedPoly::BuildBtg( float alt_m, TGPolygon* apt_base, TGPolygon* apt_clearing ) +int ClosedPoly::BuildBtg( float alt_m, TGPolygon* apt_base, TGPolygon* apt_clearing, bool make_shapefiles ) { TGPolygon base, safe_base; @@ -677,10 +514,10 @@ int ClosedPoly::BuildBtg( float alt_m, TGPolygon* apt_base, TGPolygon* apt_clear safe_base = tgPolygonExpand( pre_tess, 5.0); // add this to the airport clearing - *apt_clearing = tgPolygonUnion( safe_base, *apt_clearing); + *apt_clearing = tgPolygonUnionClipper( safe_base, *apt_clearing); // and add the clearing to the base - *apt_base = tgPolygonUnion( base, *apt_base ); + *apt_base = tgPolygonUnionClipper( base, *apt_base ); } return 1; diff --git a/src/Airports/GenAirports850/closedpoly.hxx b/src/Airports/GenAirports850/closedpoly.hxx index 35d3bb1b..5647086a 100644 --- a/src/Airports/GenAirports850/closedpoly.hxx +++ b/src/Airports/GenAirports850/closedpoly.hxx @@ -25,10 +25,10 @@ public: void Finish(); // Build BTG for airport base for airports with boundary - int BuildBtg( float alt_m, TGPolygon* apt_base, TGPolygon* apt_clearing ); + int BuildBtg( float alt_m, TGPolygon* apt_base, TGPolygon* apt_clearing, bool make_shapefiles ); // Build BTG for pavements for airports with no boundary - int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, ClipPolyType* accum, TGPolygon* apt_base, TGPolygon* apt_clearing ); + int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing, bool make_shapefiles ); FeatureList* GetFeatures() { diff --git a/src/Airports/GenAirports850/helipad.cxx b/src/Airports/GenAirports850/helipad.cxx index eade6223..d2371d47 100644 --- a/src/Airports/GenAirports850/helipad.cxx +++ b/src/Airports/GenAirports850/helipad.cxx @@ -79,7 +79,7 @@ void Helipad::BuildBtg( float alt_m, superpoly_list *rwy_polys, texparams_list *texparams, superpoly_list *rwy_lights, - ClipPolyType *accum, TGPolygon* apt_base, TGPolygon* apt_clearing ) + ClipPolyType *accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ) { SG_LOG( SG_GENERAL, SG_INFO, "Building helipad = " << heli.designator ); @@ -110,7 +110,7 @@ void Helipad::BuildBtg( float alt_m, 0.0, 1.0, 0.0, 1.0, heli.heading, heli.width, heli.length, "pc_", "heli", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); // generate area around helipad @@ -123,10 +123,10 @@ void Helipad::BuildBtg( float alt_m, safe_base = gen_runway_area_w_extend( 0.0, maxsize * 0.5, 0.0, 0.0, maxsize * 0.5 ); // add this to the airport clearing - *apt_clearing = tgPolygonUnion(safe_base, *apt_clearing); + *apt_clearing = tgPolygonUnionClipper(safe_base, *apt_clearing); // and add the clearing to the base - *apt_base = tgPolygonUnion( base, *apt_base ); + *apt_base = tgPolygonUnionClipper( base, *apt_base ); } if (heli.edge_lights) diff --git a/src/Airports/GenAirports850/helipad.hxx b/src/Airports/GenAirports850/helipad.hxx index e6195fea..53dea924 100644 --- a/src/Airports/GenAirports850/helipad.hxx +++ b/src/Airports/GenAirports850/helipad.hxx @@ -27,7 +27,7 @@ class Helipad { public: Helipad(char* def); - void BuildBtg( float alt_m, superpoly_list* heli_polys, texparams_list* texparams, superpoly_list* heli_lights, ClipPolyType* accum, TGPolygon* apt_base, TGPolygon* apt_clearing ); + void BuildBtg( float alt_m, superpoly_list* heli_polys, texparams_list* texparams, superpoly_list* heli_lights, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ); Point3D GetLoc() { diff --git a/src/Airports/GenAirports850/linearfeature.cxx b/src/Airports/GenAirports850/linearfeature.cxx index 4f864c65..cff9bc12 100644 --- a/src/Airports/GenAirports850/linearfeature.cxx +++ b/src/Airports/GenAirports850/linearfeature.cxx @@ -742,6 +742,8 @@ int LinearFeature::Finish( bool closed, unsigned int idx ) cur_outer = OffsetPointMiddle( &points[j-1], &points[j], &points[j+1], offset-width/2.0f ); cur_inner = OffsetPointMiddle( &points[j-1], &points[j], &points[j+1], offset+width/2.0f ); } + cur_outer.snap(); + cur_inner.snap(); if ( (prev_inner.x() != 0.0f) && (prev_inner.y() != 0.0f) ) { @@ -832,7 +834,6 @@ int LinearFeature::Finish( bool closed, unsigned int idx ) { SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::Finish: calculating offsets for light " << i << " whose start idx is " << lights[i]->start_idx << " and end idx is " << lights[i]->end_idx << " cur idx is " << j ); // for each point on the PointsList, offset by 2 distnaces from the edge, and add a point to the superpoly contour - if (j == lights[i]->start_idx) { // first point on the light - offset heading is 90deg @@ -855,42 +856,34 @@ int LinearFeature::Finish( bool closed, unsigned int idx ) // calculate the heading and distance from prev to cur geo_inverse_wgs_84( prev_outer.y(), prev_outer.x(), cur_outer.y(), cur_outer.x(), &heading, &az2, &dist); - if (cur_light_dist > dist) + while (cur_light_dist < dist) { - // no lights in this segment - increment cur_light_dist only - cur_light_dist += dist; - } - else - { - while (cur_light_dist < dist) + if (cur_light_dist == 0.0f) { - if (cur_light_dist == 0.0f) - { - tmp = prev_outer; - } - else - { - // calculate the position of the next light - geo_direct_wgs_84( prev_outer.y(), prev_outer.x(), heading, cur_light_dist, &pt_y, &pt_x, &az2 ); - tmp = Point3D( pt_x, pt_y, 0.0 ); - } - - poly.add_node(0, tmp); - - // calculate the normal - Point3D vec = sgGeodToCart( tmp * SG_DEGREES_TO_RADIANS ); - double length = vec.distance3D( Point3D(0.0) ); - vec = vec / length; - - normals_poly.add_node(0, vec ); - - // update current light distance - cur_light_dist += light_delta; + tmp = prev_outer; } + else + { + // calculate the position of the next light + geo_direct_wgs_84( prev_outer.y(), prev_outer.x(), heading, cur_light_dist, &pt_y, &pt_x, &az2 ); + tmp = Point3D( pt_x, pt_y, 0.0 ); + } + + poly.add_node(0, tmp); - // start next segment at the correct distance - cur_light_dist = cur_light_dist - dist; + // calculate the normal + Point3D vec = sgGeodToCart( tmp * SG_DEGREES_TO_RADIANS ); + double length = vec.distance3D( Point3D(0.0) ); + vec = vec / length; + + normals_poly.add_node(0, vec ); + + // update current light distance + cur_light_dist += light_delta; } + + // start next segment at the correct distance + cur_light_dist = cur_light_dist - dist; } prev_outer = cur_outer; @@ -916,30 +909,28 @@ int LinearFeature::Finish( bool closed, unsigned int idx ) return 1; } -int LinearFeature::BuildBtg(float alt_m, superpoly_list* line_polys, texparams_list* line_tps, ClipPolyType* line_accum, superpoly_list* lights, bool debug ) +int LinearFeature::BuildBtg(float alt_m, superpoly_list* line_polys, texparams_list* line_tps, ClipPolyType* line_accum, superpoly_list* lights, bool make_shapefiles ) { TGPolygon poly; TGPolygon clipped; + void* ds_id = NULL; // If we are going to build shapefiles + void* l_id = NULL; // datasource and layer IDs - if (debug) { - sglog().setLogLevels( SG_GENERAL, SG_BULK ); - } else { - sglog().setLogLevels( SG_GENERAL, SG_INFO ); + if ( make_shapefiles ) { + char ds_name[128]; + sprintf(ds_name, "./lf_debug/problem"); + ds_id = tgShapefileOpenDatasource( ds_name ); } SG_LOG(SG_GENERAL, SG_DEBUG, "\nLinearFeature::BuildBtg: " << description); for ( unsigned int i = 0; i < marking_polys.size(); i++) { poly = marking_polys[i].get_poly(); - poly = tgPolygonSimplify( poly ); - poly = remove_tiny_contours( poly ); + //poly = tgPolygonSimplify( poly ); + //poly = remove_tiny_contours( poly ); - SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: clipping poly " << i << " of " << marking_polys.size() ); -#if 1 - clipped = tgPolygonDiff( poly, *line_accum ); -#else + SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: clipping poly " << i << " of " << marking_polys.size() << " with CLIPPER "); clipped = tgPolygonDiffClipper( poly, *line_accum ); -#endif // clean the poly before union with accum clipped = reduce_degeneracy( clipped ); @@ -947,46 +938,33 @@ int LinearFeature::BuildBtg(float alt_m, superpoly_list* line_polys, texparams_l marking_polys[i].set_poly( clipped ); line_polys->push_back( marking_polys[i] ); -#if LF_DEBUG - if ( (debug) && ( i == 78 ) ) { - void* ds_id; - void* l_id; - - SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly ); - - char ds_name[128]; - sprintf(ds_name, "./lf_debug/problem"); - ds_id = tgShapefileOpenDatasource( ds_name ); - + /* If debugging this lf, write the poly, and the accum buffer at each step into their own layers */ + if (ds_id) { char layer_name[128]; - sprintf( layer_name, "problem"); + sprintf( layer_name, "poly_%d", i ); l_id = tgShapefileOpenLayer( ds_id, layer_name ); char feature_name[128]; - sprintf( feature_name, "prob"); + sprintf( feature_name, "poly_%d", i); tgShapefileCreateFeature( ds_id, l_id, poly, feature_name ); - sprintf( layer_name, "accum"); + sprintf( layer_name, "accum_%d", i ); l_id = tgShapefileOpenLayer( ds_id, layer_name ); - sprintf( feature_name, "accum"); + sprintf( feature_name, "accum_%d", i ); tgShapefileCreateFeature( ds_id, l_id, *line_accum, feature_name ); - - tgShapefileCloseDatasource( ds_id ); } -#endif - SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: union poly " << i << " of " << marking_polys.size() ); - -#if 1 - *line_accum = tgPolygonUnion( poly, *line_accum ); -#else + SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: union poly " << i << " of " << marking_polys.size() << " with CLIPPER " ); *line_accum = tgPolygonUnionClipper( poly, *line_accum ); -#endif line_tps->push_back( marking_tps[i] ); } + if (ds_id) { + tgShapefileCloseDatasource( ds_id ); + } + SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: add " << lighting_polys.size() << " light defs"); for ( unsigned i = 0; i < lighting_polys.size(); i++) { diff --git a/src/Airports/GenAirports850/main.cxx b/src/Airports/GenAirports850/main.cxx index 50a56a64..a1a2d609 100644 --- a/src/Airports/GenAirports850/main.cxx +++ b/src/Airports/GenAirports850/main.cxx @@ -127,8 +127,7 @@ int main(int argc, char **argv) elev_src.clear(); setup_default_elevation_sources(elev_src); - // Set verbose - // sglog().setLogLevels( SG_GENERAL, SG_BULK ); + // Set Normal logging sglog().setLogLevels( SG_GENERAL, SG_INFO ); SG_LOG(SG_GENERAL, SG_INFO, "Run genapt"); @@ -140,6 +139,11 @@ int main(int argc, char **argv) string restart_id = ""; string airport_id = ""; string last_apt_file = "./last_apt.txt"; + int dump_rwy_poly = -1; + int dump_pvmt_poly = -1; + int dump_feat_poly = -1; + int dump_base_poly = -1; + int arg_pos; for (arg_pos = 1; arg_pos < argc; arg_pos++) @@ -225,6 +229,22 @@ int main(int argc, char **argv) { slope_max = atof( arg.substr(12).c_str() ); } + else if ( arg.find("--dump-rwy=") == 0 ) + { + dump_rwy_poly = atoi( arg.substr(11).c_str() ); + } + else if ( arg.find("--dump-pvmt=") == 0 ) + { + dump_pvmt_poly = atoi( arg.substr(12).c_str() ); + } + else if ( arg.find("--dump-feat=") == 0 ) + { + dump_feat_poly = atoi( arg.substr(12).c_str() ); + } + else if ( arg.find("--dump-base=") == 0 ) + { + dump_base_poly = atoi( arg.substr(12).c_str() ); + } else if ( (arg.find("--help") == 0) || (arg.find("-h") == 0) ) { help( argc, argv, elev_src ); @@ -296,6 +316,9 @@ int main(int argc, char **argv) // Create the parser... Parser* parser = new Parser(input_file, work_dir, elev_src); + // Add any debug + parser->SetDebugPolys( dump_rwy_poly, dump_pvmt_poly, dump_feat_poly, dump_base_poly ); + // just one airport if ( airport_id != "" ) { diff --git a/src/Airports/GenAirports850/parser.cxx b/src/Airports/GenAirports850/parser.cxx index 850e801d..9cd456e2 100644 --- a/src/Airports/GenAirports850/parser.cxx +++ b/src/Airports/GenAirports850/parser.cxx @@ -317,6 +317,14 @@ void Parser::RemoveAirport( string icao ) } } +void Parser::SetDebugPolys( int rwy, int pvmt, int feat, int base ) +{ + rwy_poly = rwy; + pvmt_poly = pvmt; + feat_poly = feat; + base_poly = base; +} + void Parser::Parse( string last_apt_file ) { char tmp[2048]; @@ -644,6 +652,7 @@ int Parser::ParseLine(char* line) SetState( STATE_PARSE_SIMPLE ); SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing land airport: " << line); cur_airport = new Airport( code, line ); + cur_airport->SetDebugPolys( rwy_poly, pvmt_poly, feat_poly, base_poly ); } else { @@ -656,6 +665,7 @@ int Parser::ParseLine(char* line) SetState( STATE_PARSE_SIMPLE ); SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing heliport: " << line); cur_airport = new Airport( code, line ); + cur_airport->SetDebugPolys( rwy_poly, pvmt_poly, feat_poly, base_poly ); } else { diff --git a/src/Airports/GenAirports850/parser.hxx b/src/Airports/GenAirports850/parser.hxx index 12658634..e2051867 100644 --- a/src/Airports/GenAirports850/parser.hxx +++ b/src/Airports/GenAirports850/parser.hxx @@ -83,8 +83,15 @@ public: cur_sign = NULL; prev_node = NULL; cur_state = STATE_NONE; + + // Debug + rwy_poly = -1; + pvmt_poly = -1; + feat_poly = -1; + base_poly = -1; } + void SetDebugPolys( int rwy, int pvmt, int feat, int base ); long FindAirport( string icao ); void AddAirport( string icao ); void AddAirports( long start_pos, float min_lat, float min_lon, float max_lat, float max_lon ); @@ -126,6 +133,12 @@ private: // List of positions in database file to parse ParseList parse_positions; IcaoList airport_icaos; + + // debug + int rwy_poly; + int pvmt_poly; + int feat_poly; + int base_poly; }; #endif diff --git a/src/Airports/GenAirports850/runway.cxx b/src/Airports/GenAirports850/runway.cxx index 672f5ad2..b5034605 100644 --- a/src/Airports/GenAirports850/runway.cxx +++ b/src/Airports/GenAirports850/runway.cxx @@ -79,7 +79,7 @@ TGPolygon WaterRunway::GetNodes() } -int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, superpoly_list* rwy_lights, ClipPolyType* accum, TGPolygon* apt_base, TGPolygon* apt_clearing ) +int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, superpoly_list* rwy_lights, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ) { TGPolygon base, safe_base; string material; @@ -128,7 +128,7 @@ int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* te case 1: // asphalt: case 2: // concrete SG_LOG( SG_GENERAL, SG_DEBUG, "Build Runway: asphalt or concrete" << rwy.surface); - gen_rwy( alt_m, material, rwy_polys, texparams, accum ); + gen_rwy( alt_m, material, rwy_polys, texparams, accum, slivers ); gen_runway_lights( alt_m, rwy_lights ); break; @@ -136,7 +136,7 @@ int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* te case 4: // Dirt case 5: // Gravel SG_LOG( SG_GENERAL, SG_DEBUG, "Build Runway: Turf, Dirt or Gravel" << rwy.surface ); - gen_simple_rwy( alt_m, material, rwy_polys, texparams, accum ); + gen_simple_rwy( alt_m, material, rwy_polys, texparams, accum, slivers ); gen_runway_lights( alt_m, rwy_lights ); break; @@ -172,10 +172,10 @@ int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* te safe_base = gen_runway_area_w_extend( 0.0, 180.0, -rwy.overrun[0], -rwy.overrun[1], 50.0 ); // add this to the airport clearing - *apt_clearing = tgPolygonUnion(safe_base, *apt_clearing); + *apt_clearing = tgPolygonUnionClipper(safe_base, *apt_clearing); // and add the clearing to the base - *apt_base = tgPolygonUnion( base, *apt_base ); + *apt_base = tgPolygonUnionClipper( base, *apt_base ); } return 0; diff --git a/src/Airports/GenAirports850/runway.hxx b/src/Airports/GenAirports850/runway.hxx index e86c6951..13fd9213 100644 --- a/src/Airports/GenAirports850/runway.hxx +++ b/src/Airports/GenAirports850/runway.hxx @@ -46,11 +46,12 @@ public: else return false; } - int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, superpoly_list* rwy_lights, ClipPolyType* accum, TGPolygon* apt_base, TGPolygon* apt_clearing ); + int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, superpoly_list* rwy_lights, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ); void BuildShoulder( float alt_m, superpoly_list *rwy_polys, texparams_list *texparams, ClipPolyType *accum, + poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ); @@ -102,7 +103,8 @@ private: double &start_pct, double &end_pct, superpoly_list* rwy_polys, texparams_list* texparams, - ClipPolyType* accum ); + ClipPolyType* accum, + poly_list& slivers ); // generate the runway overrun area void gen_runway_overrun( const TGPolygon& runway_half, @@ -110,7 +112,8 @@ private: const std::string& prefix, superpoly_list* rwy_polys, texparams_list* texparams, - ClipPolyType* accum ); + ClipPolyType* accum, + poly_list& slivers ); // generate a section of runway void gen_runway_section( const TGPolygon& runway, @@ -122,14 +125,16 @@ private: const std::string& material, superpoly_list* rwy_polys, texparams_list* texparams, - ClipPolyType* accum ); + ClipPolyType* accum, + poly_list& slivers ); - void gen_simple_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, ClipPolyType *accum ); + void gen_simple_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, ClipPolyType *accum, poly_list& slivers ); void gen_rwy( double alt_m, const std::string& material, superpoly_list* rwy_polys, texparams_list* texparams, - ClipPolyType* accum ); + ClipPolyType* accum, + poly_list& slivers ); void gen_rw_marking( const TGPolygon& runway, double &start1_pct, double &end1_pct, @@ -137,7 +142,9 @@ private: const string& material, superpoly_list* rwy_polys, texparams_list* texparams, - ClipPolyType* accum, int marking); + ClipPolyType* accum, + poly_list& slivers, + int marking ); void gen_runway_lights( float alt_m, superpoly_list* lights ); diff --git a/src/Airports/GenAirports850/rwy_common.cxx b/src/Airports/GenAirports850/rwy_common.cxx index 63d49523..a30057a1 100644 --- a/src/Airports/GenAirports850/rwy_common.cxx +++ b/src/Airports/GenAirports850/rwy_common.cxx @@ -39,12 +39,13 @@ void Runway::gen_rw_designation( const string& material, double &start_pct, double &end_pct, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType *accum ) + ClipPolyType *accum, + poly_list& slivers ) { if (rwname != "XX"){ /* Do not create a designation block if the runway name is set to none */ string letter = ""; double length = rwy.length / 2.0; - for ( int i = 0; i < rwname.length(); ++i ) { + for ( unsigned int i = 0; i < rwname.length(); ++i ) { string tmp = rwname.substr(i, 1); if ( tmp == "L" || tmp == "R" || tmp == "C" ) { rwname = rwname.substr(0, i); @@ -63,7 +64,7 @@ void Runway::gen_rw_designation( const string& material, 0.0, 1.0, 0.0, 1.0, heading, material, letter, - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } @@ -88,14 +89,14 @@ void Runway::gen_rw_designation( const string& material, 0.0, 1.0, 0.0, 1.0, heading, material, tex1, - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); gen_runway_section( poly, start_pct, end_pct, 0.5, 1.0, 0.0, 1.0, 0.0, 1.0, heading, material, tex2, - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } else if (rwname.length() == 1) { sprintf( tex1, "%c%c", rwname[0], 'c'); @@ -106,7 +107,7 @@ void Runway::gen_rw_designation( const string& material, 0.0, 1.0, 0.0, 1.0, heading, material, tex1, - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } } } @@ -117,7 +118,8 @@ void Runway::gen_runway_overrun( const TGPolygon& runway_half, const string& prefix, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType* accum ) { + ClipPolyType* accum, + poly_list& slivers ) { const float length = rwy.length / 2.0 + 2.0 * SG_FEET_TO_METER; double start1_pct = 0.0; double end1_pct = 0.0; @@ -155,7 +157,8 @@ void Runway::gen_runway_overrun( const TGPolygon& runway_half, "stopway", rwy_polys, texparams, - accum); + accum, + slivers ); } } @@ -170,7 +173,8 @@ void Runway::gen_runway_section( const TGPolygon& runway, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType *accum ) { + ClipPolyType *accum, + poly_list& slivers ) { gen_tex_section( runway, startl_pct, endl_pct, startw_pct, endw_pct, @@ -180,6 +184,7 @@ void Runway::gen_runway_section( const TGPolygon& runway, material, rwy_polys, texparams, - accum ); + accum, + slivers ); } diff --git a/src/Airports/GenAirports850/rwy_gen.cxx b/src/Airports/GenAirports850/rwy_gen.cxx index ed2dbae8..323a58c0 100644 --- a/src/Airports/GenAirports850/rwy_gen.cxx +++ b/src/Airports/GenAirports850/rwy_gen.cxx @@ -38,12 +38,14 @@ struct sections }; void Runway::gen_rw_marking( const TGPolygon& runway, - double &start1_pct, double &end1_pct, - double heading, - const string& material, - superpoly_list *rwy_polys, - texparams_list *texparams, - ClipPolyType *accum, int marking) { + double &start1_pct, double &end1_pct, + double heading, + const string& material, + superpoly_list *rwy_polys, + texparams_list *texparams, + ClipPolyType *accum, + poly_list& slivers, + int marking) { std::vector rw_marking_list; @@ -126,7 +128,7 @@ void Runway::gen_rw_marking( const TGPolygon& runway, 0.0, 1.0, 0.0, 1.0, heading, material, rw_marking_list[i].tex, - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } } @@ -142,7 +144,8 @@ void Runway::gen_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType *accum ) + ClipPolyType *accum, + poly_list& slivers ) { SG_LOG( SG_GENERAL, SG_DEBUG, "Building runway = " << rwy.rwnum[0] << " / " << rwy.rwnum[1]); @@ -232,7 +235,7 @@ void Runway::gen_rwy( double alt_m, 0.0, 1.0, tex_pct, 1.0, heading, material, "dspl_thresh", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); // main chunks for ( i = 0; i < count; ++i ) { @@ -244,7 +247,7 @@ void Runway::gen_rwy( double alt_m, 0.0, 1.0, 0.0, 1.0, heading, material, "dspl_thresh", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } // final arrows @@ -256,7 +259,7 @@ void Runway::gen_rwy( double alt_m, 0.0, 1.0, 0.0, 1.0, heading, material, "dspl_arrows", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } @@ -272,7 +275,7 @@ void Runway::gen_rwy( double alt_m, 0.0, 1.0, 0.0, 1.0, heading, material, "no_threshold", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } else { // Thresholds for all others @@ -285,19 +288,19 @@ void Runway::gen_rwy( double alt_m, 0.0, 1.0, 0.0, 1.0, heading, material, "threshold", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } // Runway designation block gen_rw_designation( material, runway_half, heading, - rwname, start1_pct, end1_pct, rwy_polys, texparams, accum ); + rwname, start1_pct, end1_pct, rwy_polys, texparams, accum, slivers ); if (rwy.marking[rwhalf] > 1){ // Generate remaining markings depending on type of runway gen_rw_marking( runway_half, start1_pct, end1_pct, heading, material, - rwy_polys, texparams, accum, rwy.marking[rwhalf] ); + rwy_polys, texparams, accum, slivers, rwy.marking[rwhalf] ); } // @@ -321,12 +324,12 @@ void Runway::gen_rwy( double alt_m, 0.0, 1.0, 0.0, 1.0, heading, material, "rest", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } gen_runway_overrun( runway_half, rwhalf, material, - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } } @@ -334,6 +337,7 @@ void Runway::BuildShoulder( float alt_m, superpoly_list *rwy_polys, texparams_list *texparams, ClipPolyType *accum, + poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ) { @@ -456,17 +460,20 @@ void Runway::BuildShoulder( float alt_m, poly.add_node( 0, curInnerLoc ); } -#if 1 +#if 0 TGPolygon clipped = tgPolygonDiff( poly, *accum ); #else TGPolygon clipped = tgPolygonDiffClipper( poly, *accum ); #endif + + tgPolygonFindSlivers( clipped, slivers ); + sp.erase(); sp.set_poly( clipped ); sp.set_material( shoulder_surface ); rwy_polys->push_back( sp ); -#if 1 +#if 0 *accum = tgPolygonUnion( poly, *accum ); #else *accum = tgPolygonUnionClipper( poly, *accum ); @@ -486,10 +493,10 @@ void Runway::BuildShoulder( float alt_m, safe_base = tgPolygonExpand( poly, 50.0f ); // add this to the airport clearing - *apt_clearing = tgPolygonUnion(safe_base, *apt_clearing); + *apt_clearing = tgPolygonUnionClipper(safe_base, *apt_clearing); // and add the clearing to the base - *apt_base = tgPolygonUnion( base, *apt_base ); + *apt_base = tgPolygonUnionClipper( base, *apt_base ); // now set cur locations for the next iteration curInnerLoc = nextInnerLoc; diff --git a/src/Airports/GenAirports850/rwy_simple.cxx b/src/Airports/GenAirports850/rwy_simple.cxx index aac85ced..5c7a6cf4 100644 --- a/src/Airports/GenAirports850/rwy_simple.cxx +++ b/src/Airports/GenAirports850/rwy_simple.cxx @@ -36,10 +36,9 @@ void Runway::gen_simple_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, - ClipPolyType *accum ) + ClipPolyType *accum, + poly_list& slivers ) { - int i; - TGPolygon runway = gen_runway_w_mid( alt_m, 0.0, 0.0 ); TGPolygon runway_half; @@ -92,7 +91,7 @@ for ( int rwhalf=0; rwhalf<2; ++rwhalf ){ 0.0, 1.0, 0.0, 1.0, heading, material, "", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } // Generate runway Runway::gen_runway_section( runway_half, @@ -101,7 +100,7 @@ for ( int rwhalf=0; rwhalf<2; ++rwhalf ){ 0.0, 0.28, 0.0, 1.0, heading, material, "", - rwy_polys, texparams, accum ); + rwy_polys, texparams, accum, slivers ); } diff --git a/src/Lib/Geometry/point3d.hxx b/src/Lib/Geometry/point3d.hxx index b7b29227..bb54eab6 100644 --- a/src/Lib/Geometry/point3d.hxx +++ b/src/Lib/Geometry/point3d.hxx @@ -50,6 +50,9 @@ //const double fgPoint3_Epsilon = 0.0000001; const double fgPoint3_Epsilon = 0.000001; +#define DO_SNAP 0 +#define SNAP_GRID (0.0000001) + enum {PX, PY, PZ}; // axes // Kludge for msvc++ 6.0 - requires forward decls of friend functions. @@ -101,6 +104,8 @@ public: void setradius(const double z); void setelev(const double z); + void snap(void); + // Queries double& operator [] ( int i); // indexing @@ -214,6 +219,7 @@ inline Point3D Point3D::fromSGGeod(const SGGeod& geod) pt.setlon(geod.getLongitudeRad()); pt.setlat(geod.getLatitudeRad()); pt.setelev(geod.getElevationM()); + return pt; } @@ -223,6 +229,7 @@ inline Point3D Point3D::fromSGGeoc(const SGGeoc& geoc) pt.setlon(geoc.getLongitudeRad()); pt.setlat(geoc.getLatitudeRad()); pt.setradius(geoc.getRadiusM()); + return pt; } @@ -232,6 +239,7 @@ inline Point3D Point3D::fromSGVec3(const SGVec3& cart) pt.setx(cart.x()); pt.sety(cart.y()); pt.setz(cart.z()); + return pt; } @@ -241,6 +249,7 @@ inline Point3D Point3D::fromSGVec3(const SGVec3& cart) pt.setx(cart.x()); pt.sety(cart.y()); pt.setz(cart.z()); + return pt; } @@ -250,6 +259,7 @@ inline Point3D Point3D::fromSGVec2(const SGVec2& cart) pt.setx(cart.x()); pt.sety(cart.y()); pt.setz(0); + return pt; } @@ -259,6 +269,7 @@ inline Point3D Point3D::fromSGVec2(const SGVec2& cart) pt.setx(cart.x()); pt.sety(cart.y()); pt.setz(0); + return pt; } @@ -267,27 +278,36 @@ inline Point3D Point3D::fromSGVec2(const SGVec2& cart) inline Point3D& Point3D::operator = (const Point3D& p) { - n[PX] = p.n[PX]; n[PY] = p.n[PY]; n[PZ] = p.n[PZ]; return *this; + n[PX] = p.n[PX]; n[PY] = p.n[PY]; n[PZ] = p.n[PZ]; + + return *this; } inline Point3D& Point3D::operator += ( const Point3D& p ) { - n[PX] += p.n[PX]; n[PY] += p.n[PY]; n[PZ] += p.n[PZ]; return *this; + n[PX] += p.n[PX]; n[PY] += p.n[PY]; n[PZ] += p.n[PZ]; + + return *this; } inline Point3D& Point3D::operator -= ( const Point3D& p ) { - n[PX] -= p.n[PX]; n[PY] -= p.n[PY]; n[PZ] -= p.n[PZ]; return *this; + n[PX] -= p.n[PX]; n[PY] -= p.n[PY]; n[PZ] -= p.n[PZ]; + + return *this; } inline Point3D& Point3D::operator *= ( const double d ) { - n[PX] *= d; n[PY] *= d; n[PZ] *= d; return *this; + n[PX] *= d; n[PY] *= d; n[PZ] *= d; + + return *this; } inline Point3D& Point3D::operator /= ( const double d ) { double d_inv = 1./d; n[PX] *= d_inv; n[PY] *= d_inv; n[PZ] *= d_inv; + return *this; } @@ -319,6 +339,13 @@ inline void Point3D::setelev(const double z) { n[PZ] = z; } +inline void Point3D::snap( void ) +{ + n[PX] = SNAP_GRID * round( n[PX]/SNAP_GRID ); + n[PY] = SNAP_GRID * round( n[PY]/SNAP_GRID ); + n[PZ] = SNAP_GRID * round( n[PZ]/SNAP_GRID ); +} + // QUERIES inline double& Point3D::operator [] ( int i) @@ -417,12 +444,16 @@ inline Point3D operator * (const Point3D& a, const double d) inline Point3D operator * (const double d, const Point3D& a) { - return a*d; + Point3D pt = a*d; + + return pt; } inline Point3D operator / (const Point3D& a, const double d) { - return Point3D(a) *= (1.0 / d ); + Point3D pt = Point3D(a) *= (1.0 / d ); + + return pt; } inline bool operator == (const Point3D& a, const Point3D& b) diff --git a/src/Lib/Geometry/poly_support.cxx b/src/Lib/Geometry/poly_support.cxx index 6ff8acc7..fcbd80af 100644 --- a/src/Lib/Geometry/poly_support.cxx +++ b/src/Lib/Geometry/poly_support.cxx @@ -33,6 +33,8 @@ #include #include +#include + #include #include @@ -361,10 +363,10 @@ TGPolygon polygon_tesselate_alt( TGPolygon &p, bool verbose ) { point_list nodes; string flags; if (verbose) { - flags = "pzqenXYY"; + flags = "pzenXYY"; // flags = "pzqenXY"; // allow adding interior points } else { - flags = "pzqenXYYQ"; + flags = "pzenXYYQ"; // flags = "pzqenXYQ"; // allow adding interior points } @@ -427,9 +429,9 @@ TGPolygon polygon_tesselate_alt_with_extra( TGPolygon &p, const point_list& extr point_list nodes; string flags; if (verbose) { - flags = "VVpzqenXYY"; + flags = "VVpzenXYY"; } else { - flags = "pzqenXYYQ"; + flags = "pzenXYYQ"; } if ( polygon_tesselate( p, extra_nodes, trieles, nodes, flags ) >= 0 ) { @@ -613,7 +615,7 @@ static void calc_point_inside( TGContourNode *node, TGPolygon &p ) { // cout << endl; if ( xcuts.size() < 2 || (xcuts.size() % 2) != 0 ) { - throw sg_exception("Geometric inconsistency in calc_point_inside()"); + throw sg_exception("Geometric inconsistency in calc_point_inside()"); } double maxlen=0.0; diff --git a/src/Lib/Polygon/polygon.cxx b/src/Lib/Polygon/polygon.cxx index b0a273d1..a0c6a897 100644 --- a/src/Lib/Polygon/polygon.cxx +++ b/src/Lib/Polygon/polygon.cxx @@ -163,23 +163,19 @@ double tgPolygonCalcAngle(point2d a, point2d b, point2d c) { // positive areas indicate clockwise winding. double TGPolygon::area_contour( const int contour ) const { - // area = 1/2 * sum[i = 0 to k-1][x(i)*y(i+1) - x(i+1)*y(i)] - // where i=k is defined as i=0 - point_list c = poly[contour]; - int size = c.size(); - double sum = 0.0; + double area = 0.0; + int i, j; - for ( int i = 0; i < size; ++i ) { - sum += c[(i+1)%size].x() * c[i].y() - c[i].x() * c[(i+1)%size].y(); + j = c.size() - 1; + for (i=0; i= 0; --i ) { + SG_LOG(SG_GENERAL, SG_DEBUG, "contour " << i ); + + min_angle = in.minangle_contour( i ); + area = in.area_contour( i ); + + SG_LOG(SG_GENERAL, SG_DEBUG, " min_angle (rad) = " << min_angle ); + SG_LOG(SG_GENERAL, SG_DEBUG, " min_angle (deg) = " << min_angle * 180.0 / SGD_PI ); + SG_LOG(SG_GENERAL, SG_DEBUG, " area = " << area ); + + if ( ((min_angle < angle_cutoff) && (area < area_cutoff)) || + ( area < area_cutoff / 10.0) ) + { + if ((min_angle < angle_cutoff) && (area < area_cutoff)) + { + SG_LOG(SG_GENERAL, SG_DEBUG, " WE THINK IT'S A SLIVER! - min angle < 10 deg, and area < 10 sq meters"); + } + else + { + SG_LOG(SG_GENERAL, SG_DEBUG, " WE THINK IT'S A SLIVER! - min angle > 10 deg, but area < 1 sq meters"); + } + + // check if this is a hole + hole_flag = in.get_hole_flag( i ); + + if ( hole_flag ) { + // just delete/eliminate/remove sliver holes + // cout << "just deleting a sliver hole" << endl; + in.delete_contour( i ); + } else { + // move sliver contour to out polygon + contour = in.get_contour( i ); + in.delete_contour( i ); + out.add_contour( contour, hole_flag ); + } + } + } + + if ( out.contours() ) + { + slivers.push_back( out ); + } +} + + // output void TGPolygon::write_contour( const int contour, const string& file ) const { FILE *fp = fopen( file.c_str(), "w" ); @@ -431,12 +495,16 @@ IntPoint MakeClipperPoint( Point3D pt ) Point3D MakeTGPoint( IntPoint pt ) { + Point3D tg_pt; double x, y; x = (double)( ((double)pt.X) / (double)FIXEDPT ); y = (double)( ((double)pt.Y) / (double)FIXEDPT ); - return Point3D( x, y, -9999.0f); + tg_pt = Point3D( x, y, -9999.0f); + tg_pt.snap(); + + return tg_pt; } double MakeClipperDelta( double mDelta ) diff --git a/src/Lib/Polygon/polygon.hxx b/src/Lib/Polygon/polygon.hxx index 48e0d57a..dc7a8e54 100644 --- a/src/Lib/Polygon/polygon.hxx +++ b/src/Lib/Polygon/polygon.hxx @@ -252,6 +252,7 @@ TGPolygon tgPolygonStripHoles( const TGPolygon &poly ); TGPolygon tgPolygon2tristrip( const TGPolygon& poly ); +void tgPolygonFindSlivers( TGPolygon& in, poly_list& slivers ); // wrapper functions for gpc polygon clip routines