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:
parent
0788bf0fcb
commit
f0a7f39e7b
21 changed files with 529 additions and 435 deletions
|
@ -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; i<runways.size(); i++ )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Build Runway " << i + 1 << " of " << runways.size());
|
||||
slivers.clear();
|
||||
|
||||
if ( runways[i]->IsPrecision() )
|
||||
{
|
||||
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; i<helipads.size(); i++ )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Build helipad " << i + 1 << " of " << helipads.size());
|
||||
slivers.clear();
|
||||
|
||||
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
|
||||
{
|
||||
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++ )
|
||||
{
|
||||
SG_LOG(SG_GENERAL, SG_INFO, "Build Pavement " << i + 1 << " of " << pavements.size() << " : " << pavements[i]->GetDescription());
|
||||
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; 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() )
|
||||
{
|
||||
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);
|
||||
|
||||
|
|
|
@ -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 <Airport *> AirportList;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,12 +4,16 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <Polygon/chop.hxx>
|
||||
#include <Geometry/poly_support.hxx>
|
||||
|
||||
#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; 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()
|
||||
{
|
||||
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; 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) );
|
||||
|
||||
// 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; 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
|
||||
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; 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 );
|
||||
#endif
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: clipped poly has " << clipped.contours() << " contours");
|
||||
for (int i=0; i<clipped.contours(); i++)
|
||||
{
|
||||
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");
|
||||
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped = " << clipped.contours());
|
||||
|
||||
tgPolygonFindSlivers( clipped, slivers );
|
||||
|
||||
sp.erase();
|
||||
sp.set_poly( split );
|
||||
sp.set_poly( clipped );
|
||||
sp.set_material( material );
|
||||
//sp.set_flag("taxi");
|
||||
|
||||
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 );
|
||||
#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;
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -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 != "" )
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
||||
}
|
||||
|
|
|
@ -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<sections> 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;
|
||||
|
|
|
@ -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 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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<double>& 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<float>& 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<double>& cart)
|
|||
pt.setx(cart.x());
|
||||
pt.sety(cart.y());
|
||||
pt.setz(0);
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
|
@ -259,6 +269,7 @@ inline Point3D Point3D::fromSGVec2(const SGVec2<float>& cart)
|
|||
pt.setx(cart.x());
|
||||
pt.sety(cart.y());
|
||||
pt.setz(0);
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
|
@ -267,27 +278,36 @@ inline Point3D Point3D::fromSGVec2(const SGVec2<float>& 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)
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Polygon/polygon.hxx>
|
||||
#include <Polygon/chop.hxx>
|
||||
|
||||
#include <Triangulate/trieles.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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<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
|
||||
// winding order
|
||||
return fabs(sum / 2.0);
|
||||
return fabs(area * 0.5);
|
||||
}
|
||||
|
||||
|
||||
// return the smallest interior angle of the contour
|
||||
double TGPolygon::minangle_contour( const int 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
|
||||
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 )
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue