1
0
Fork 0

A bit of a re-work (again) but looks to be worth it.

Instead of cleaning polys after clipping, to get good triangulation, try to
clean them before clipping, snap the verticies to 1 1cm x 1cm grid, and
merge any resultant slivers back into adjacent polys.
This is very similar to how fgfs-construct worked.

Although the previous methos only failed on 3 airports, the results weren't
very good.  There were lots of cracks, and mmissing triangles, as the polys were
cleaned.

New methos freezes on two airports during base triangulation, and crashes on four.
I think the quality of the generated airports overcomes the slight regression.

I also added some debug switches so I don't have to keep rebuilding from source
to debug crashes.  --dump-rwy=xxx --dump-pvmt=xxx, --dump-feat=xxx and --dum-base=1
can be used to create shapefiles to debug the particular polys before clipping.
Currently, there needs to be a cp_debug directory to place the shapefiles into.
Probably need better debug infrastructure going forward...

NOTE: I turned off runway shoulder generation in this build.  Polygon snapping for runways,
helipads, and shoulders not implemented yet.  This may help on the failing airports.
This is next on my todo list.
This commit is contained in:
Peter Sadrozinski 2012-03-04 09:29:58 -05:00 committed by Christian Schmitt
parent 0788bf0fcb
commit f0a7f39e7b
21 changed files with 529 additions and 435 deletions

View file

@ -85,6 +85,12 @@ Airport::Airport( int c, char* def)
altitude *= SG_FEET_TO_METER; altitude *= SG_FEET_TO_METER;
boundary = NULL; 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 ); 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 // TODO: Add to runway object
// calculate texture coordinates for runway section using the provided // calculate texture coordinates for runway section using the provided
// texturing parameters. Returns a mirror polygon to the runway, // texturing parameters. Returns a mirror polygon to the runway,
@ -362,12 +377,71 @@ static TGPolygon calc_elevations( TGAptSurface &surf,
return result; 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 ) void Airport::BuildBtg(const string& root, const string_list& elev_src )
{ {
ClipPolyType accum; ClipPolyType accum;
poly_list slivers;
// try to keep line accumulator in clipper format for speed... // try to keep line accumulator in clipper format for speed...
ClipPolyType line_accum; ClipPolyType line_accum;
poly_list line_slivers;
TGPolygon apt_base; TGPolygon apt_base;
TGPolygon apt_clearing; TGPolygon apt_clearing;
@ -388,6 +462,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
Point3D p; Point3D p;
bool verbose_triangulation = false; bool verbose_triangulation = false;
bool make_shapefiles = false;
// parse main airport information // parse main airport information
double apt_lon = 0.0, apt_lat = 0.0; 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 // Starting to clip the polys
gettimeofday(&build_start, NULL); 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() ); SG_LOG(SG_GENERAL, SG_INFO, "Build Feature Poly " << i + 1 << " of " << features.size() << " : " << features[i]->GetDescription() );
#if 0 if ( (dbg_feat_poly >= 0) && (i == (unsigned int)dbg_feat_poly) ) {
if ( i == 22 ) { SG_LOG(SG_GENERAL, SG_INFO, "Problem feat poly (" << i << ")");
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
make_shapefiles = true;
} else {
make_shapefiles = false;
}
features[i]->BuildBtg( altitude, &line_polys, &line_tps, &line_accum, &rwy_lights, make_shapefiles );
} }
} }
else else
@ -474,18 +540,22 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
for ( unsigned int i=0; i<runways.size(); i++ ) for ( unsigned int i=0; i<runways.size(); i++ )
{ {
SG_LOG(SG_GENERAL, SG_INFO, "Build Runway " << i + 1 << " of " << runways.size()); SG_LOG(SG_GENERAL, SG_INFO, "Build Runway " << i + 1 << " of " << runways.size());
slivers.clear();
if ( runways[i]->IsPrecision() ) if ( runways[i]->IsPrecision() )
{ {
if (boundary) 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 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); gettimeofday(&log_time, NULL);
@ -506,14 +576,19 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
for ( unsigned int i=0; i<helipads.size(); i++ ) for ( unsigned int i=0; i<helipads.size(); i++ )
{ {
SG_LOG(SG_GENERAL, SG_INFO, "Build helipad " << i + 1 << " of " << helipads.size()); SG_LOG(SG_GENERAL, SG_INFO, "Build helipad " << i + 1 << " of " << helipads.size());
slivers.clear();
if (boundary) if (boundary)
{ {
helipads[i]->BuildBtg( 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 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; i<pavements.size(); i++ ) for ( unsigned int i=0; i<pavements.size(); i++ )
{ {
SG_LOG(SG_GENERAL, SG_INFO, "Build Pavement " << i + 1 << " of " << pavements.size() << " : " << pavements[i]->GetDescription()); SG_LOG(SG_GENERAL, SG_INFO, "Build Pavement " << i + 1 << " of " << pavements.size() << " : " << pavements[i]->GetDescription());
slivers.clear();
#if 0 if ( (dbg_pvmt_poly >= 0) && (i == (unsigned int)dbg_pvmt_poly) ) {
if (i == 30) { SG_LOG(SG_GENERAL, SG_INFO, "Problem pvmt poly (" << i << ")");
sglog().setLogLevels( SG_GENERAL, SG_BULK );
make_shapefiles = true;
} else { } else {
sglog().setLogLevels( SG_GENERAL, SG_INFO ); make_shapefiles = false;
} }
#endif
if (boundary) 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 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 else
@ -550,15 +630,20 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
gettimeofday(&log_time, NULL); gettimeofday(&log_time, NULL);
SG_LOG( SG_GENERAL, SG_ALERT, "Finished building pavements for " << icao << " at " << ctime(&log_time.tv_sec) ); SG_LOG( SG_GENERAL, SG_ALERT, "Finished building pavements for " << icao << " at " << ctime(&log_time.tv_sec) );
#if 0
// Build runway shoulders here // Build runway shoulders here
#if 0
for ( unsigned int i=0; i<runways.size(); i++ ) for ( unsigned int i=0; i<runways.size(); i++ )
{ {
SG_LOG(SG_GENERAL, SG_INFO, "Build Runway shoulder " << i << " of " << runways.size()); SG_LOG(SG_GENERAL, SG_INFO, "Build Runway shoulder " << i + 1 << " of " << runways.size());
if ( runways[i]->GetsShoulder() ) if ( runways[i]->GetsShoulder() )
{ {
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 #endif
@ -567,7 +652,7 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
if (boundary) if (boundary)
{ {
SG_LOG(SG_GENERAL, SG_INFO, "Build user defined 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 ) if ( apt_base.total_size() == 0 )
@ -576,9 +661,10 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
return; return;
} }
TGPolygon filled_base = tgPolygonStripHoles( apt_base ); TGPolygon filled_base = tgPolygonStripHoles( apt_base );
TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 ); 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); gettimeofday(&build_end, NULL);
timersub(&build_end, &build_start, &build_time); 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()); SG_LOG(SG_GENERAL, SG_DEBUG, "total size of section " << k << " before =" << poly.total_size());
#if 0
poly = remove_cycles( poly ); poly = remove_cycles( poly );
poly = remove_dups( poly ); poly = remove_dups( poly );
poly = remove_bad_contours( 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_dups( poly );
poly = remove_bad_contours( poly ); poly = remove_bad_contours( poly );
poly = remove_small_contours( poly ); poly = remove_small_contours( poly );
#endif
rwy_polys[k].set_poly( poly ); 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()); SG_LOG(SG_GENERAL, SG_DEBUG, "total size of section " << k << " before =" << poly.total_size());
#if 0
poly = remove_cycles( poly ); poly = remove_cycles( poly );
poly = remove_dups( poly ); poly = remove_dups( poly );
poly = remove_bad_contours( 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_dups( poly );
poly = remove_bad_contours( poly ); poly = remove_bad_contours( poly );
poly = remove_small_contours( poly ); poly = remove_small_contours( poly );
#endif
pvmt_polys[k].set_poly( poly ); 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 ); base_poly = add_nodes_to_poly( base_poly, tmp_pvmt_nodes );
SG_LOG(SG_GENERAL, SG_DEBUG, " after adding tmp_nodes: " << base_poly); SG_LOG(SG_GENERAL, SG_DEBUG, " after adding tmp_nodes: " << base_poly);
#if 0
base_poly = remove_cycles( base_poly ); base_poly = remove_cycles( base_poly );
base_poly = remove_dups( base_poly ); base_poly = remove_dups( base_poly );
base_poly = remove_bad_contours( 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_dups( base_poly );
base_poly = remove_bad_contours( base_poly ); base_poly = remove_bad_contours( base_poly );
base_poly = remove_small_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); gettimeofday(&cleanup_end, NULL);
timersub(&cleanup_end, &cleanup_start, &cleanup_time); 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(); TGPolygon poly = rwy_polys[i].get_poly();
#if 0 if ( (dbg_rwy_poly >= 0) && (i == (unsigned int)dbg_rwy_poly) ) {
if ( i == 2 ) { SG_LOG(SG_GENERAL, SG_INFO, "Problem rwy poly (" << i << ") : " << poly );
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly before remove_dups: " << poly );
sglog().setLogLevels( SG_GENERAL, SG_BULK ); tgChopNormalPolygon( "/home/pete", "rwy", poly, false );
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 );
verbose_triangulation = true; verbose_triangulation = true;
} else { } else {
verbose_triangulation = false; verbose_triangulation = false;
} }
#endif
SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size()); SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size());
TGPolygon tri = polygon_tesselate_alt( poly, verbose_triangulation ); 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(); TGPolygon poly = pvmt_polys[i].get_poly();
#if 0 if ( (dbg_pvmt_poly >= 0) && (i == (unsigned int)dbg_pvmt_poly) ) {
if ( i == 0 ) { SG_LOG(SG_GENERAL, SG_INFO, "Problem pvmt poly (" << i << ") : " << poly );
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly );
tgChopNormalPolygon( "/home/pete", "Base", poly, false ); tgChopNormalPolygon( "/home/pete", "pvmt", poly, false );
verbose_triangulation = true; verbose_triangulation = true;
} else { } else {
verbose_triangulation = false; verbose_triangulation = false;
} }
#endif
SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size()); SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size());
TGPolygon tri = polygon_tesselate_alt( poly, verbose_triangulation ); 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(); TGPolygon poly = line_polys[i].get_poly();
#if 0 if ( (dbg_feat_poly >= 0) && (i == (unsigned int)dbg_feat_poly) ) {
if ( i == 282 ) { SG_LOG(SG_GENERAL, SG_INFO, "Problem feat poly (" << i << ") : " << poly );
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << poly );
tgChopNormalPolygon( "/home/pete/", "Base", poly, false ); tgChopNormalPolygon( "/home/pete/", "feat", poly, false );
verbose_triangulation = true; verbose_triangulation = true;
} else { } else {
verbose_triangulation = false; verbose_triangulation = false;
} }
#endif
SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size()); SG_LOG(SG_GENERAL, SG_DEBUG, "contours before " << poly.contours() << " total points before = " << poly.total_size());
TGPolygon tri = polygon_tesselate_alt( poly, verbose_triangulation ); 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 ); line_polys[i].set_texcoords( tc );
} }
#if 0 if ( dbg_base_poly >= 0 ) {
{ SG_LOG(SG_GENERAL, SG_INFO, "Problem base poly: " << base_poly );
SG_LOG(SG_GENERAL, SG_INFO, "Problem poly: " << base_poly );
tgChopNormalPolygon( "/home/pete/", "Base", base_poly, false ); tgChopNormalPolygon( "/home/pete/", "Base", base_poly, false );
verbose_triangulation = true; verbose_triangulation = true;
} }
#endif
SG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly "); SG_LOG(SG_GENERAL, SG_INFO, "Tesselating base poly ");
TGPolygon base_tris = polygon_tesselate_alt( base_poly, verbose_triangulation ); 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); gettimeofday(&triangulation_end, NULL);
timersub(&triangulation_end, &triangulation_start, &triangulation_time); 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 pt_n, tri_n, strip_n;
int_list tri_tc, strip_tc; int_list tri_tc, strip_tc;
SG_LOG(SG_GENERAL, SG_DEBUG, "Calculating airport normal" );
// calculate "the" normal for this airport // calculate "the" normal for this airport
p.setx( base_tris.get_pt(0, 0).x() * SGD_DEGREES_TO_RADIANS ); 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.sety( base_tris.get_pt(0, 0).y() * SGD_DEGREES_TO_RADIANS );
p.setz( 0 ); p.setz( 0 );
Point3D vnt = sgGeodToCart( p ); 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, "geod = " << p);
// SG_LOG(SG_GENERAL, SG_DEBUG, "cart = " << tmp); // SG_LOG(SG_GENERAL, SG_DEBUG, "cart = " << tmp);

View file

@ -103,8 +103,11 @@ public:
tm = cleanup_time; tm = cleanup_time;
} }
void merge_slivers( superpoly_list& polys, poly_list& slivers );
void BuildBtg( const string& root, const string_list& elev_src ); void BuildBtg( const string& root, const string_list& elev_src );
void SetDebugPolys( int rwy, int pvmt, int feat, int base );
private: private:
int code; // airport, heliport or sea port int code; // airport, heliport or sea port
int altitude; // in meters int altitude; // in meters
@ -126,6 +129,12 @@ private:
struct timeval build_time; struct timeval build_time;
struct timeval cleanup_time; struct timeval cleanup_time;
struct timeval triangulation_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 <Airport *> AirportList; typedef std::vector <Airport *> AirportList;

View file

@ -218,7 +218,8 @@ void gen_tex_section( const TGPolygon& runway,
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum ) { ClipPolyType *accum,
poly_list& slivers ) {
int j, k; 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. // Clip the new polygon against what ever has already been created.
#if 0
TGPolygon clipped = tgPolygonDiff( section, *accum ); 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 // Split long edges to create an object that can better flow with
// the surface terrain // the surface terrain
@ -329,7 +336,12 @@ void gen_tex_section( const TGPolygon& runway,
sp.set_material( prefix + material ); sp.set_material( prefix + material );
rwy_polys->push_back( sp ); rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "section = " << clipped.contours()); SG_LOG(SG_GENERAL, SG_DEBUG, "section = " << clipped.contours());
#if 0
*accum = tgPolygonUnion( section, *accum ); *accum = tgPolygonUnion( section, *accum );
#else
*accum = tgPolygonUnionClipper( section, *accum );
#endif
// Store away what we need to know for texture coordinate // Store away what we need to know for texture coordinate
// calculation. (CLO 10/20/02: why can't we calculate texture // calculation. (CLO 10/20/02: why can't we calculate texture

View file

@ -37,6 +37,7 @@ void gen_tex_section( const TGPolygon& runway,
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum ); ClipPolyType *accum,
poly_list& slivers );
#endif #endif

View file

@ -4,12 +4,16 @@
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx> #include <simgear/math/sg_geodesy.hxx>
#include <Polygon/polygon.hxx>
#include <Polygon/chop.hxx>
#include <Geometry/poly_support.hxx> #include <Geometry/poly_support.hxx>
#include "beznode.hxx" #include "beznode.hxx"
#include "convex_hull.hxx" #include "convex_hull.hxx"
#include "closedpoly.hxx" #include "closedpoly.hxx"
#define NO_BEZIER (0)
static void stringPurifier( string& s ) static void stringPurifier( string& s )
{ {
for ( string::iterator it = s.begin(), itEnd = s.end(); it!=itEnd; ++it) { 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() ClosedPoly::~ClosedPoly()
{ {
SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting ClosedPoly " << description ); SG_LOG( SG_GENERAL, SG_DEBUG, "Deleting ClosedPoly " << description );
} }
void ClosedPoly::AddNode( BezNode* node ) 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; i<boundary->size(); 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() void ClosedPoly::CloseCurContour()
{ {
SG_LOG(SG_GENERAL, SG_DEBUG, "Close Contour"); 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; double num_meters = total_dist / meter_dist;
if (num_meters < 8.0f)
// 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 (curve_type != CURVE_LINEAR) 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 // 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) * 2; 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, "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 else
{ {
@ -277,18 +236,22 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst )
if (curve_type != CURVE_LINEAR) if (curve_type != CURVE_LINEAR)
{ {
num_segs = 8; 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, "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 ); SG_LOG(SG_GENERAL, SG_DEBUG, " Distance is " << num_meters << " (OK) so num_segs is " << num_segs );
} }
else else
{ {
// make sure linear segments don't got over 100m // make sure linear segments don't got over 100m
//num_segs = 1;
num_segs = num_meters / 100.0f + 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 only one segment, revert to linear
if (num_segs == 1) if (num_segs == 1)
{ {
@ -315,7 +278,9 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst )
// add the pavement vertex // add the pavement vertex
// convert from lat/lon to geo // convert from lat/lon to geo
// (maybe later) - check some simgear objects... // (maybe later) - check some simgear objects...
curLoc.snap();
dst->push_back( curLoc ); dst->push_back( curLoc );
if (p==0) if (p==0)
{ {
SG_LOG(SG_GENERAL, SG_DEBUG, "adding Curve Anchor node (type " << curve_type << ") at (" << curLoc.x() << "," << curLoc.y() << ")"); 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 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) if (num_segs > 1)
{ {
for (int p=0; p<num_segs; p++) for (int p=0; p<num_segs; p++)
@ -345,6 +304,7 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst )
nextLoc = CalculateLinearLocation( curNode->GetLoc(), nextNode->GetLoc(), (1.0f/num_segs) * (p+1) ); nextLoc = CalculateLinearLocation( curNode->GetLoc(), nextNode->GetLoc(), (1.0f/num_segs) * (p+1) );
// add the feature vertex // add the feature vertex
curLoc.snap();
dst->push_back( curLoc ); dst->push_back( curLoc );
if (p==0) if (p==0)
@ -365,6 +325,7 @@ void ClosedPoly::ConvertContour( BezContour* src, point_list *dst )
nextLoc = nextNode->GetLoc(); nextLoc = nextNode->GetLoc();
// just add the one vertex - dist is small // just add the one vertex - dist is small
curLoc.snap();
dst->push_back( curLoc ); dst->push_back( curLoc );
SG_LOG(SG_GENERAL, SG_DEBUG, "adding Linear Anchor node at (" << curLoc.x() << "," << curLoc.y() << ")"); 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; i<src.size(); i++)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nExpanding point " << i << "\n\n");
if (i == 0)
{
// set prev node to last in the contour, as all contours must be closed
prevPoint = src.at( src.size()-1 );
}
else
{
// otherwise, it's just the last index
prevPoint = src.at( i-1 );
}
curPoint = src.at(i);
if (i<src.size()-1)
{
nextPoint = src.at(i+1);
}
else
{
// for the last node, next is the first. as all contours are closed
nextPoint = src.at(0);
}
// calculate the angle between cur->prev 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 // finish the poly - convert to TGPolygon, and tesselate
void ClosedPoly::Finish() void ClosedPoly::Finish()
{ {
@ -558,10 +385,18 @@ void ClosedPoly::Finish()
holes.clear(); 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; 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) 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"); SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: original poly has " << pre_tess.contours() << " contours");
// do this before clipping and generating the base // do this before clipping and generating the base
pre_tess = tgPolygonSimplify( pre_tess ); // pre_tess = tgPolygonSimplify( pre_tess );
pre_tess = reduce_degeneracy( pre_tess ); // pre_tess = reduce_degeneracy( pre_tess );
// grow pretess by a little bit
//pre_tess = tgPolygonExpand( pre_tess, 0.05); // 5cm
TGSuperPoly sp; TGSuperPoly sp;
TGTexParams tp; TGTexParams tp;
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: expanded poly has " << pre_tess.contours() << " contours");
for (int i=0; i<pre_tess.contours(); i++)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: expanded countour " << i << " has " << pre_tess.contour_size(i) << " points" );
}
#if 1
TGPolygon clipped = tgPolygonDiff( pre_tess, *accum );
#else
TGPolygon clipped = tgPolygonDiffClipper( pre_tess, *accum ); TGPolygon clipped = tgPolygonDiffClipper( pre_tess, *accum );
#endif SG_LOG(SG_GENERAL, SG_DEBUG, "clipped = " << clipped.contours());
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: clipped poly has " << clipped.contours() << " contours");
for (int i=0; i<clipped.contours(); i++) tgPolygonFindSlivers( clipped, slivers );
{
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: clipped poly countour " << i << " has " << clipped.contour_size(i) << " points" );
}
TGPolygon split = tgPolygonSplitLongEdges( clipped, 400.0 );
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: split poly has " << split.contours() << " contours");
sp.erase(); sp.erase();
sp.set_poly( split ); sp.set_poly( clipped );
sp.set_material( material ); sp.set_material( material );
//sp.set_flag("taxi"); //sp.set_flag("taxi");
rwy_polys->push_back( sp ); rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped = " << clipped.contours());
#if 1
*accum = tgPolygonUnion( pre_tess, *accum );
#else
*accum = tgPolygonUnionClipper( pre_tess, *accum ); *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 ); tp = TGTexParams( pre_tess.get_pt(0,0), 5.0, 5.0, texture_heading );
texparams->push_back( tp ); 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 // 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 // - 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; 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); safe_base = tgPolygonExpand( pre_tess, 5.0);
// add this to the airport clearing // 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 // and add the clearing to the base
*apt_base = tgPolygonUnion( base, *apt_base ); *apt_base = tgPolygonUnionClipper( base, *apt_base );
} }
return 1; return 1;

View file

@ -25,10 +25,10 @@ public:
void Finish(); void Finish();
// Build BTG for airport base for airports with boundary // 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 // 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() FeatureList* GetFeatures()
{ {

View file

@ -79,7 +79,7 @@ void Helipad::BuildBtg( float alt_m,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
superpoly_list *rwy_lights, 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 ); 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, 0.0, 1.0, 0.0, 1.0,
heli.heading, heli.width, heli.length, heli.heading, heli.width, heli.length,
"pc_", "heli", "pc_", "heli",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
// generate area around helipad // 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 ); 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 // 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 // and add the clearing to the base
*apt_base = tgPolygonUnion( base, *apt_base ); *apt_base = tgPolygonUnionClipper( base, *apt_base );
} }
if (heli.edge_lights) if (heli.edge_lights)

View file

@ -27,7 +27,7 @@ class Helipad
{ {
public: public:
Helipad(char* def); 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() Point3D GetLoc()
{ {

View file

@ -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_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_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) ) 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 ); 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 // 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) if (j == lights[i]->start_idx)
{ {
// first point on the light - offset heading is 90deg // 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 // 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); 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 if (cur_light_dist == 0.0f)
cur_light_dist += dist;
}
else
{
while (cur_light_dist < dist)
{ {
if (cur_light_dist == 0.0f) tmp = prev_outer;
{
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;
} }
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 // calculate the normal
cur_light_dist = cur_light_dist - dist; 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; prev_outer = cur_outer;
@ -916,30 +909,28 @@ int LinearFeature::Finish( bool closed, unsigned int idx )
return 1; 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 poly;
TGPolygon clipped; TGPolygon clipped;
void* ds_id = NULL; // If we are going to build shapefiles
void* l_id = NULL; // datasource and layer IDs
if (debug) { if ( make_shapefiles ) {
sglog().setLogLevels( SG_GENERAL, SG_BULK ); char ds_name[128];
} else { sprintf(ds_name, "./lf_debug/problem");
sglog().setLogLevels( SG_GENERAL, SG_INFO ); ds_id = tgShapefileOpenDatasource( ds_name );
} }
SG_LOG(SG_GENERAL, SG_DEBUG, "\nLinearFeature::BuildBtg: " << description); SG_LOG(SG_GENERAL, SG_DEBUG, "\nLinearFeature::BuildBtg: " << description);
for ( unsigned int i = 0; i < marking_polys.size(); i++) for ( unsigned int i = 0; i < marking_polys.size(); i++)
{ {
poly = marking_polys[i].get_poly(); poly = marking_polys[i].get_poly();
poly = tgPolygonSimplify( poly ); //poly = tgPolygonSimplify( poly );
poly = remove_tiny_contours( poly ); //poly = remove_tiny_contours( poly );
SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: clipping poly " << i << " of " << marking_polys.size() ); SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: clipping poly " << i << " of " << marking_polys.size() << " with CLIPPER ");
#if 1
clipped = tgPolygonDiff( poly, *line_accum );
#else
clipped = tgPolygonDiffClipper( poly, *line_accum ); clipped = tgPolygonDiffClipper( poly, *line_accum );
#endif
// clean the poly before union with accum // clean the poly before union with accum
clipped = reduce_degeneracy( clipped ); 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 ); marking_polys[i].set_poly( clipped );
line_polys->push_back( marking_polys[i] ); line_polys->push_back( marking_polys[i] );
#if LF_DEBUG /* If debugging this lf, write the poly, and the accum buffer at each step into their own layers */
if ( (debug) && ( i == 78 ) ) { if (ds_id) {
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 );
char layer_name[128]; char layer_name[128];
sprintf( layer_name, "problem"); sprintf( layer_name, "poly_%d", i );
l_id = tgShapefileOpenLayer( ds_id, layer_name ); l_id = tgShapefileOpenLayer( ds_id, layer_name );
char feature_name[128]; char feature_name[128];
sprintf( feature_name, "prob"); sprintf( feature_name, "poly_%d", i);
tgShapefileCreateFeature( ds_id, l_id, poly, feature_name ); 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 ); 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 ); 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() ); SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: union poly " << i << " of " << marking_polys.size() << " with CLIPPER " );
#if 1
*line_accum = tgPolygonUnion( poly, *line_accum );
#else
*line_accum = tgPolygonUnionClipper( poly, *line_accum ); *line_accum = tgPolygonUnionClipper( poly, *line_accum );
#endif
line_tps->push_back( marking_tps[i] ); 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"); SG_LOG(SG_GENERAL, SG_DEBUG, "LinearFeature::BuildBtg: add " << lighting_polys.size() << " light defs");
for ( unsigned i = 0; i < lighting_polys.size(); i++) for ( unsigned i = 0; i < lighting_polys.size(); i++)
{ {

View file

@ -127,8 +127,7 @@ int main(int argc, char **argv)
elev_src.clear(); elev_src.clear();
setup_default_elevation_sources(elev_src); setup_default_elevation_sources(elev_src);
// Set verbose // Set Normal logging
// sglog().setLogLevels( SG_GENERAL, SG_BULK );
sglog().setLogLevels( SG_GENERAL, SG_INFO ); sglog().setLogLevels( SG_GENERAL, SG_INFO );
SG_LOG(SG_GENERAL, SG_INFO, "Run genapt"); SG_LOG(SG_GENERAL, SG_INFO, "Run genapt");
@ -140,6 +139,11 @@ int main(int argc, char **argv)
string restart_id = ""; string restart_id = "";
string airport_id = ""; string airport_id = "";
string last_apt_file = "./last_apt.txt"; 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; int arg_pos;
for (arg_pos = 1; arg_pos < argc; 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() ); 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) ) else if ( (arg.find("--help") == 0) || (arg.find("-h") == 0) )
{ {
help( argc, argv, elev_src ); help( argc, argv, elev_src );
@ -296,6 +316,9 @@ int main(int argc, char **argv)
// Create the parser... // Create the parser...
Parser* parser = new Parser(input_file, work_dir, elev_src); 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 // just one airport
if ( airport_id != "" ) if ( airport_id != "" )
{ {

View file

@ -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 ) void Parser::Parse( string last_apt_file )
{ {
char tmp[2048]; char tmp[2048];
@ -644,6 +652,7 @@ int Parser::ParseLine(char* line)
SetState( STATE_PARSE_SIMPLE ); SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing land airport: " << line); SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing land airport: " << line);
cur_airport = new Airport( code, line ); cur_airport = new Airport( code, line );
cur_airport->SetDebugPolys( rwy_poly, pvmt_poly, feat_poly, base_poly );
} }
else else
{ {
@ -656,6 +665,7 @@ int Parser::ParseLine(char* line)
SetState( STATE_PARSE_SIMPLE ); SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing heliport: " << line); SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing heliport: " << line);
cur_airport = new Airport( code, line ); cur_airport = new Airport( code, line );
cur_airport->SetDebugPolys( rwy_poly, pvmt_poly, feat_poly, base_poly );
} }
else else
{ {

View file

@ -83,8 +83,15 @@ public:
cur_sign = NULL; cur_sign = NULL;
prev_node = NULL; prev_node = NULL;
cur_state = STATE_NONE; 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 ); long FindAirport( string icao );
void AddAirport( string icao ); void AddAirport( string icao );
void AddAirports( long start_pos, float min_lat, float min_lon, float max_lat, float max_lon ); 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 // List of positions in database file to parse
ParseList parse_positions; ParseList parse_positions;
IcaoList airport_icaos; IcaoList airport_icaos;
// debug
int rwy_poly;
int pvmt_poly;
int feat_poly;
int base_poly;
}; };
#endif #endif

View file

@ -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; TGPolygon base, safe_base;
string material; string material;
@ -128,7 +128,7 @@ int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* te
case 1: // asphalt: case 1: // asphalt:
case 2: // concrete case 2: // concrete
SG_LOG( SG_GENERAL, SG_DEBUG, "Build Runway: asphalt or concrete" << rwy.surface); 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 ); gen_runway_lights( alt_m, rwy_lights );
break; break;
@ -136,7 +136,7 @@ int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* te
case 4: // Dirt case 4: // Dirt
case 5: // Gravel case 5: // Gravel
SG_LOG( SG_GENERAL, SG_DEBUG, "Build Runway: Turf, Dirt or Gravel" << rwy.surface ); 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 ); gen_runway_lights( alt_m, rwy_lights );
break; 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 ); 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 // 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 // and add the clearing to the base
*apt_base = tgPolygonUnion( base, *apt_base ); *apt_base = tgPolygonUnionClipper( base, *apt_base );
} }
return 0; return 0;

View file

@ -46,11 +46,12 @@ public:
else return false; 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, void BuildShoulder( float alt_m,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum, ClipPolyType *accum,
poly_list& slivers,
TGPolygon* apt_base, TGPolygon* apt_base,
TGPolygon* apt_clearing ); TGPolygon* apt_clearing );
@ -102,7 +103,8 @@ private:
double &start_pct, double &end_pct, double &start_pct, double &end_pct,
superpoly_list* rwy_polys, superpoly_list* rwy_polys,
texparams_list* texparams, texparams_list* texparams,
ClipPolyType* accum ); ClipPolyType* accum,
poly_list& slivers );
// generate the runway overrun area // generate the runway overrun area
void gen_runway_overrun( const TGPolygon& runway_half, void gen_runway_overrun( const TGPolygon& runway_half,
@ -110,7 +112,8 @@ private:
const std::string& prefix, const std::string& prefix,
superpoly_list* rwy_polys, superpoly_list* rwy_polys,
texparams_list* texparams, texparams_list* texparams,
ClipPolyType* accum ); ClipPolyType* accum,
poly_list& slivers );
// generate a section of runway // generate a section of runway
void gen_runway_section( const TGPolygon& runway, void gen_runway_section( const TGPolygon& runway,
@ -122,14 +125,16 @@ private:
const std::string& material, const std::string& material,
superpoly_list* rwy_polys, superpoly_list* rwy_polys,
texparams_list* texparams, 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, void gen_rwy( double alt_m,
const std::string& material, const std::string& material,
superpoly_list* rwy_polys, superpoly_list* rwy_polys,
texparams_list* texparams, texparams_list* texparams,
ClipPolyType* accum ); ClipPolyType* accum,
poly_list& slivers );
void gen_rw_marking( const TGPolygon& runway, void gen_rw_marking( const TGPolygon& runway,
double &start1_pct, double &end1_pct, double &start1_pct, double &end1_pct,
@ -137,7 +142,9 @@ private:
const string& material, const string& material,
superpoly_list* rwy_polys, superpoly_list* rwy_polys,
texparams_list* texparams, texparams_list* texparams,
ClipPolyType* accum, int marking); ClipPolyType* accum,
poly_list& slivers,
int marking );
void gen_runway_lights( float alt_m, superpoly_list* lights ); void gen_runway_lights( float alt_m, superpoly_list* lights );

View file

@ -39,12 +39,13 @@ void Runway::gen_rw_designation( const string& material,
double &start_pct, double &end_pct, double &start_pct, double &end_pct,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, 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 */ if (rwname != "XX"){ /* Do not create a designation block if the runway name is set to none */
string letter = ""; string letter = "";
double length = rwy.length / 2.0; 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); string tmp = rwname.substr(i, 1);
if ( tmp == "L" || tmp == "R" || tmp == "C" ) { if ( tmp == "L" || tmp == "R" || tmp == "C" ) {
rwname = rwname.substr(0, i); 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, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, letter, 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, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, tex1, material, tex1,
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
gen_runway_section( poly, gen_runway_section( poly,
start_pct, end_pct, start_pct, end_pct,
0.5, 1.0, 0.5, 1.0,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, tex2, material, tex2,
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} else if (rwname.length() == 1) { } else if (rwname.length() == 1) {
sprintf( tex1, "%c%c", rwname[0], 'c'); 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, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, tex1, 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, const string& prefix,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType* accum ) { ClipPolyType* accum,
poly_list& slivers ) {
const float length = rwy.length / 2.0 + 2.0 * SG_FEET_TO_METER; const float length = rwy.length / 2.0 + 2.0 * SG_FEET_TO_METER;
double start1_pct = 0.0; double start1_pct = 0.0;
double end1_pct = 0.0; double end1_pct = 0.0;
@ -155,7 +157,8 @@ void Runway::gen_runway_overrun( const TGPolygon& runway_half,
"stopway", "stopway",
rwy_polys, rwy_polys,
texparams, texparams,
accum); accum,
slivers );
} }
} }
@ -170,7 +173,8 @@ void Runway::gen_runway_section( const TGPolygon& runway,
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum ) { ClipPolyType *accum,
poly_list& slivers ) {
gen_tex_section( runway, gen_tex_section( runway,
startl_pct, endl_pct, startl_pct, endl_pct,
startw_pct, endw_pct, startw_pct, endw_pct,
@ -180,6 +184,7 @@ void Runway::gen_runway_section( const TGPolygon& runway,
material, material,
rwy_polys, rwy_polys,
texparams, texparams,
accum ); accum,
slivers );
} }

View file

@ -38,12 +38,14 @@ struct sections
}; };
void Runway::gen_rw_marking( const TGPolygon& runway, void Runway::gen_rw_marking( const TGPolygon& runway,
double &start1_pct, double &end1_pct, double &start1_pct, double &end1_pct,
double heading, double heading,
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum, int marking) { ClipPolyType *accum,
poly_list& slivers,
int marking) {
std::vector<sections> rw_marking_list; std::vector<sections> rw_marking_list;
@ -126,7 +128,7 @@ void Runway::gen_rw_marking( const TGPolygon& runway,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, rw_marking_list[i].tex, 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, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum ) ClipPolyType *accum,
poly_list& slivers )
{ {
SG_LOG( SG_GENERAL, SG_DEBUG, "Building runway = " << rwy.rwnum[0] << " / " << rwy.rwnum[1]); 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, 0.0, 1.0, tex_pct, 1.0,
heading, heading,
material, "dspl_thresh", material, "dspl_thresh",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
// main chunks // main chunks
for ( i = 0; i < count; ++i ) { 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, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, "dspl_thresh", material, "dspl_thresh",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} }
// final arrows // final arrows
@ -256,7 +259,7 @@ void Runway::gen_rwy( double alt_m,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, "dspl_arrows", 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, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, "no_threshold", material, "no_threshold",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} else { } else {
// Thresholds for all others // Thresholds for all others
@ -285,19 +288,19 @@ void Runway::gen_rwy( double alt_m,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, "threshold", material, "threshold",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} }
// Runway designation block // Runway designation block
gen_rw_designation( material, runway_half, heading, 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){ if (rwy.marking[rwhalf] > 1){
// Generate remaining markings depending on type of runway // Generate remaining markings depending on type of runway
gen_rw_marking( runway_half, gen_rw_marking( runway_half,
start1_pct, end1_pct, start1_pct, end1_pct,
heading, material, 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, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, "rest", material, "rest",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} }
gen_runway_overrun( runway_half, rwhalf, gen_runway_overrun( runway_half, rwhalf,
material, material,
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} }
} }
@ -334,6 +337,7 @@ void Runway::BuildShoulder( float alt_m,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum, ClipPolyType *accum,
poly_list& slivers,
TGPolygon* apt_base, TGPolygon* apt_base,
TGPolygon* apt_clearing ) TGPolygon* apt_clearing )
{ {
@ -456,17 +460,20 @@ void Runway::BuildShoulder( float alt_m,
poly.add_node( 0, curInnerLoc ); poly.add_node( 0, curInnerLoc );
} }
#if 1 #if 0
TGPolygon clipped = tgPolygonDiff( poly, *accum ); TGPolygon clipped = tgPolygonDiff( poly, *accum );
#else #else
TGPolygon clipped = tgPolygonDiffClipper( poly, *accum ); TGPolygon clipped = tgPolygonDiffClipper( poly, *accum );
#endif #endif
tgPolygonFindSlivers( clipped, slivers );
sp.erase(); sp.erase();
sp.set_poly( clipped ); sp.set_poly( clipped );
sp.set_material( shoulder_surface ); sp.set_material( shoulder_surface );
rwy_polys->push_back( sp ); rwy_polys->push_back( sp );
#if 1 #if 0
*accum = tgPolygonUnion( poly, *accum ); *accum = tgPolygonUnion( poly, *accum );
#else #else
*accum = tgPolygonUnionClipper( poly, *accum ); *accum = tgPolygonUnionClipper( poly, *accum );
@ -486,10 +493,10 @@ void Runway::BuildShoulder( float alt_m,
safe_base = tgPolygonExpand( poly, 50.0f ); safe_base = tgPolygonExpand( poly, 50.0f );
// add this to the airport clearing // 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 // 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 // now set cur locations for the next iteration
curInnerLoc = nextInnerLoc; curInnerLoc = nextInnerLoc;

View file

@ -36,10 +36,9 @@ void Runway::gen_simple_rwy( double alt_m,
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, 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 = gen_runway_w_mid( alt_m, 0.0, 0.0 );
TGPolygon runway_half; TGPolygon runway_half;
@ -92,7 +91,7 @@ for ( int rwhalf=0; rwhalf<2; ++rwhalf ){
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
material, "", material, "",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} }
// Generate runway // Generate runway
Runway::gen_runway_section( runway_half, 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, 0.0, 0.28, 0.0, 1.0,
heading, heading,
material, "", material, "",
rwy_polys, texparams, accum ); rwy_polys, texparams, accum, slivers );
} }

View file

@ -50,6 +50,9 @@
//const double fgPoint3_Epsilon = 0.0000001; //const double fgPoint3_Epsilon = 0.0000001;
const double fgPoint3_Epsilon = 0.000001; const double fgPoint3_Epsilon = 0.000001;
#define DO_SNAP 0
#define SNAP_GRID (0.0000001)
enum {PX, PY, PZ}; // axes enum {PX, PY, PZ}; // axes
// Kludge for msvc++ 6.0 - requires forward decls of friend functions. // Kludge for msvc++ 6.0 - requires forward decls of friend functions.
@ -101,6 +104,8 @@ public:
void setradius(const double z); void setradius(const double z);
void setelev(const double z); void setelev(const double z);
void snap(void);
// Queries // Queries
double& operator [] ( int i); // indexing double& operator [] ( int i); // indexing
@ -214,6 +219,7 @@ inline Point3D Point3D::fromSGGeod(const SGGeod& geod)
pt.setlon(geod.getLongitudeRad()); pt.setlon(geod.getLongitudeRad());
pt.setlat(geod.getLatitudeRad()); pt.setlat(geod.getLatitudeRad());
pt.setelev(geod.getElevationM()); pt.setelev(geod.getElevationM());
return pt; return pt;
} }
@ -223,6 +229,7 @@ inline Point3D Point3D::fromSGGeoc(const SGGeoc& geoc)
pt.setlon(geoc.getLongitudeRad()); pt.setlon(geoc.getLongitudeRad());
pt.setlat(geoc.getLatitudeRad()); pt.setlat(geoc.getLatitudeRad());
pt.setradius(geoc.getRadiusM()); pt.setradius(geoc.getRadiusM());
return pt; return pt;
} }
@ -232,6 +239,7 @@ inline Point3D Point3D::fromSGVec3(const SGVec3<double>& cart)
pt.setx(cart.x()); pt.setx(cart.x());
pt.sety(cart.y()); pt.sety(cart.y());
pt.setz(cart.z()); pt.setz(cart.z());
return pt; return pt;
} }
@ -241,6 +249,7 @@ inline Point3D Point3D::fromSGVec3(const SGVec3<float>& cart)
pt.setx(cart.x()); pt.setx(cart.x());
pt.sety(cart.y()); pt.sety(cart.y());
pt.setz(cart.z()); pt.setz(cart.z());
return pt; return pt;
} }
@ -250,6 +259,7 @@ inline Point3D Point3D::fromSGVec2(const SGVec2<double>& cart)
pt.setx(cart.x()); pt.setx(cart.x());
pt.sety(cart.y()); pt.sety(cart.y());
pt.setz(0); pt.setz(0);
return pt; return pt;
} }
@ -259,6 +269,7 @@ inline Point3D Point3D::fromSGVec2(const SGVec2<float>& cart)
pt.setx(cart.x()); pt.setx(cart.x());
pt.sety(cart.y()); pt.sety(cart.y());
pt.setz(0); pt.setz(0);
return pt; return pt;
} }
@ -267,27 +278,36 @@ inline Point3D Point3D::fromSGVec2(const SGVec2<float>& cart)
inline Point3D& Point3D::operator = (const Point3D& p) 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 ) 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 ) 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 ) 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 ) inline Point3D& Point3D::operator /= ( const double d )
{ {
double d_inv = 1./d; n[PX] *= d_inv; n[PY] *= d_inv; n[PZ] *= d_inv; double d_inv = 1./d; n[PX] *= d_inv; n[PY] *= d_inv; n[PZ] *= d_inv;
return *this; return *this;
} }
@ -319,6 +339,13 @@ inline void Point3D::setelev(const double z) {
n[PZ] = 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 // QUERIES
inline double& Point3D::operator [] ( int i) 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) 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) 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) inline bool operator == (const Point3D& a, const Point3D& b)

View file

@ -33,6 +33,8 @@
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <Polygon/polygon.hxx> #include <Polygon/polygon.hxx>
#include <Polygon/chop.hxx>
#include <Triangulate/trieles.hxx> #include <Triangulate/trieles.hxx>
#include <algorithm> #include <algorithm>
@ -361,10 +363,10 @@ TGPolygon polygon_tesselate_alt( TGPolygon &p, bool verbose ) {
point_list nodes; point_list nodes;
string flags; string flags;
if (verbose) { if (verbose) {
flags = "pzqenXYY"; flags = "pzenXYY";
// flags = "pzqenXY"; // allow adding interior points // flags = "pzqenXY"; // allow adding interior points
} else { } else {
flags = "pzqenXYYQ"; flags = "pzenXYYQ";
// flags = "pzqenXYQ"; // allow adding interior points // 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; point_list nodes;
string flags; string flags;
if (verbose) { if (verbose) {
flags = "VVpzqenXYY"; flags = "VVpzenXYY";
} else { } else {
flags = "pzqenXYYQ"; flags = "pzenXYYQ";
} }
if ( polygon_tesselate( p, extra_nodes, trieles, nodes, flags ) >= 0 ) { 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; // cout << endl;
if ( xcuts.size() < 2 || (xcuts.size() % 2) != 0 ) { 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; double maxlen=0.0;

View file

@ -163,23 +163,19 @@ double tgPolygonCalcAngle(point2d a, point2d b, point2d c) {
// positive areas indicate clockwise winding. // positive areas indicate clockwise winding.
double TGPolygon::area_contour( const int contour ) const { 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]; point_list c = poly[contour];
int size = c.size(); double area = 0.0;
double sum = 0.0; int i, j;
for ( int i = 0; i < size; ++i ) { j = c.size() - 1;
sum += c[(i+1)%size].x() * c[i].y() - c[i].x() * c[(i+1)%size].y(); for (i=0; i<c.size(); i++) {
area += (c[j].x() + c[i].x()) * (c[j].y() - c[i].y());
j=i;
} }
// area can be negative or positive depending on the polygon return fabs(area * 0.5);
// winding order
return fabs(sum / 2.0);
} }
// return the smallest interior angle of the contour // return the smallest interior angle of the contour
double TGPolygon::minangle_contour( const int contour ) { double TGPolygon::minangle_contour( const int contour ) {
point_list c = poly[contour]; point_list c = poly[contour];
@ -286,6 +282,74 @@ void TGPolygon::write( const string& file ) const {
} }
// Move slivers from in polygon to out polygon.
void tgPolygonFindSlivers( TGPolygon& in, poly_list& slivers )
{
// traverse each contour of the polygon and attempt to identify
// likely slivers
SG_LOG(SG_GENERAL, SG_DEBUG, "tgPolygonFindSlivers()");
TGPolygon out;
int i;
out.erase();
double angle_cutoff = 10.0 * SGD_DEGREES_TO_RADIANS;
double area_cutoff = 0.000000001;
double min_angle;
double area;
point_list contour;
int hole_flag;
// process contours in reverse order so deleting a contour doesn't
// foul up our sequence
for ( i = in.contours() - 1; 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 // output
void TGPolygon::write_contour( const int contour, const string& file ) const { void TGPolygon::write_contour( const int contour, const string& file ) const {
FILE *fp = fopen( file.c_str(), "w" ); FILE *fp = fopen( file.c_str(), "w" );
@ -431,12 +495,16 @@ IntPoint MakeClipperPoint( Point3D pt )
Point3D MakeTGPoint( IntPoint pt ) Point3D MakeTGPoint( IntPoint pt )
{ {
Point3D tg_pt;
double x, y; double x, y;
x = (double)( ((double)pt.X) / (double)FIXEDPT ); x = (double)( ((double)pt.X) / (double)FIXEDPT );
y = (double)( ((double)pt.Y) / (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 ) double MakeClipperDelta( double mDelta )

View file

@ -252,6 +252,7 @@ TGPolygon tgPolygonStripHoles( const TGPolygon &poly );
TGPolygon tgPolygon2tristrip( const TGPolygon& poly ); TGPolygon tgPolygon2tristrip( const TGPolygon& poly );
void tgPolygonFindSlivers( TGPolygon& in, poly_list& slivers );
// wrapper functions for gpc polygon clip routines // wrapper functions for gpc polygon clip routines