- Chased down a bug that caused threshold lighting to be omitted in some
situations - Made the code a bit more robust and able to handle the handful of rare occasions when the least squares nurbs interpolator fails. - Add airport surface bases for towers, windsocks, beacons, and vasi/papi lighting so they never are buried and never float. (I'm considering the idea of doing this for the approach lighting too ...)
This commit is contained in:
parent
696fa632b4
commit
fb71b5876c
6 changed files with 121 additions and 42 deletions
|
@ -132,8 +132,8 @@ TGAptSurface::TGAptSurface( const string& path,
|
||||||
#elif defined( _NURBS_LEAST_SQUARES )
|
#elif defined( _NURBS_LEAST_SQUARES )
|
||||||
// Minimum divs appears to need to be at least 5 before the
|
// Minimum divs appears to need to be at least 5 before the
|
||||||
// leastsquares nurbs surface approximation stops crashing.
|
// leastsquares nurbs surface approximation stops crashing.
|
||||||
if ( xdivs < 5 ) { xdivs = 5; }
|
if ( xdivs < 6 ) { xdivs = 6; }
|
||||||
if ( ydivs < 5 ) { ydivs = 5; }
|
if ( ydivs < 6 ) { ydivs = 6; }
|
||||||
#else
|
#else
|
||||||
# error "Need to define _NURBS_GLOBAL_INTER or _NURBS_LEAST_SQUARES"
|
# error "Need to define _NURBS_GLOBAL_INTER or _NURBS_LEAST_SQUARES"
|
||||||
#endif
|
#endif
|
||||||
|
@ -269,8 +269,11 @@ TGAptSurface::TGAptSurface( const string& path,
|
||||||
// sanity check: I'm finding that leastSquares() can produce nan
|
// sanity check: I'm finding that leastSquares() can produce nan
|
||||||
// surfaces. We test for this and fall back to globalInterp() if
|
// surfaces. We test for this and fall back to globalInterp() if
|
||||||
// the least squares fails.
|
// the least squares fails.
|
||||||
|
double result = query_solver( (min_deg.lon() + max_deg.lon()) / 2.0,
|
||||||
|
(min_deg.lat() + max_deg.lat()) / 2.0 );
|
||||||
Point3Dd p = apt_surf->pointAt( 0.5, 0.5 );
|
Point3Dd p = apt_surf->pointAt( 0.5, 0.5 );
|
||||||
if ( p.z() <= 0.0 || p.z() >= 0.0 ) {
|
|
||||||
|
if ( (result > -9000.0) && (p.z() <= 0.0 || p.z() >= 0.0) ) {
|
||||||
// ok, a valid number
|
// ok, a valid number
|
||||||
} else {
|
} else {
|
||||||
// no, sorry, a nan is not <= 0.0 or >= 0.0
|
// no, sorry, a nan is not <= 0.0 or >= 0.0
|
||||||
|
@ -278,7 +281,7 @@ TGAptSurface::TGAptSurface( const string& path,
|
||||||
"leastSquares() nurbs interpolation failed!!!");
|
"leastSquares() nurbs interpolation failed!!!");
|
||||||
char command[256];
|
char command[256];
|
||||||
sprintf( command,
|
sprintf( command,
|
||||||
"least squares nurbs interpolation failed, using globalInterp() >> last_apt" );
|
"echo least squares nurbs interpolation failed, using globalInterp() >> last_apt" );
|
||||||
system( command );
|
system( command );
|
||||||
|
|
||||||
// we could fall back to globalInterp() rather than aborting
|
// we could fall back to globalInterp() rather than aborting
|
||||||
|
@ -454,6 +457,13 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
u = (max_u + min_u) / 2.0;
|
u = (max_u + min_u) / 2.0;
|
||||||
|
|
||||||
|
if ( count > 100 ) {
|
||||||
|
// solver failed
|
||||||
|
cout << "binary solver failed..." << endl;
|
||||||
|
return -9999.0;
|
||||||
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +497,12 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
|
||||||
}
|
}
|
||||||
v = (max_v + min_v) / 2.0;
|
v = (max_v + min_v) / 2.0;
|
||||||
|
|
||||||
|
if ( count > 100 ) {
|
||||||
|
// solver failed
|
||||||
|
cout << "binary solver failed..." << endl;
|
||||||
|
return -9999.0;
|
||||||
|
}
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,15 +516,7 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
|
||||||
// cout << " final query distance error = " << dist << endl;
|
// cout << " final query distance error = " << dist << endl;
|
||||||
return p.z();
|
return p.z();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcount++;
|
|
||||||
if ( gcount % 100 == 0 ) {
|
|
||||||
cout << "query count = " << gcount << " dist = " << dx << ", "
|
|
||||||
<< dy << endl;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cout << "binary solver failed..." << endl;
|
|
||||||
|
|
||||||
return p.z();
|
return p.z();
|
||||||
}
|
}
|
||||||
|
|
|
@ -603,16 +603,45 @@ void build_airport( string airport_id, float alt_m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_polygon( accum, "accum" );
|
// Now generate small surface for each beacon
|
||||||
if ( apt_base.total_size() == 0 ) {
|
TGPolygon obj_base, obj_safe_base;
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "no airport points generated");
|
double obj_hdg = runways[0].heading;
|
||||||
return;
|
for ( i = 0; i < (int)beacons.size(); ++i ) {
|
||||||
|
obj_base = gen_wgs84_area( beacons[i], 20.0, 0.0, 0.0, 20.0,
|
||||||
|
obj_hdg, alt_m, false );
|
||||||
|
obj_safe_base = gen_wgs84_area( beacons[i], 40.0, 0.0, 0.0, 40.0,
|
||||||
|
obj_hdg, alt_m, false );
|
||||||
|
|
||||||
|
apt_base = tgPolygonUnion( obj_base, apt_base );
|
||||||
|
apt_clearing = tgPolygonUnion( obj_safe_base, apt_clearing );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now generate small surface for each tower
|
||||||
|
for ( i = 0; i < (int)towers.size(); ++i ) {
|
||||||
|
obj_base = gen_wgs84_area( towers[i], 20.0, 0.0, 0.0, 20.0,
|
||||||
|
obj_hdg, alt_m, false );
|
||||||
|
obj_safe_base = gen_wgs84_area( towers[i], 40.0, 0.0, 0.0, 40.0,
|
||||||
|
obj_hdg, alt_m, false );
|
||||||
|
|
||||||
|
apt_base = tgPolygonUnion( obj_base, apt_base );
|
||||||
|
apt_clearing = tgPolygonUnion( obj_safe_base, apt_clearing );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now generate small surface for each windsock
|
||||||
|
for ( i = 0; i < (int)windsocks.size(); ++i ) {
|
||||||
|
obj_base = gen_wgs84_area( windsocks[i], 20.0, 0.0, 0.0, 20.0,
|
||||||
|
obj_hdg, alt_m, false );
|
||||||
|
obj_safe_base = gen_wgs84_area( windsocks[i], 40.0, 0.0, 0.0, 40.0,
|
||||||
|
obj_hdg, alt_m, false );
|
||||||
|
|
||||||
|
apt_base = tgPolygonUnion( obj_base, apt_base );
|
||||||
|
apt_clearing = tgPolygonUnion( obj_safe_base, apt_clearing );
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5th pass: generate runway lights
|
// 5th pass: generate runway lights
|
||||||
superpoly_list rwy_lights; rwy_lights.clear();
|
superpoly_list rwy_lights; rwy_lights.clear();
|
||||||
for ( i = 0; i < (int)runways.size(); ++i ) {
|
for ( i = 0; i < (int)runways.size(); ++i ) {
|
||||||
gen_runway_lights( runways[i], alt_m, rwy_lights );
|
gen_runway_lights( runways[i], alt_m, rwy_lights, &apt_base );
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6th pass: generate all taxiway lights
|
// 6th pass: generate all taxiway lights
|
||||||
|
@ -620,11 +649,19 @@ void build_airport( string airport_id, float alt_m,
|
||||||
gen_taxiway_lights( taxiways[i], alt_m, rwy_lights );
|
gen_taxiway_lights( taxiways[i], alt_m, rwy_lights );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write_polygon( accum, "accum" );
|
||||||
|
// write_polygon( apt_base, "base" );
|
||||||
|
// write_polygon( apt_clearing, "clear" );
|
||||||
|
if ( apt_base.total_size() == 0 ) {
|
||||||
|
SG_LOG(SG_GENERAL, SG_ALERT, "no airport points generated");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// generate convex hull (no longer)
|
// generate convex hull (no longer)
|
||||||
// TGPolygon hull = convex_hull(apt_pts);
|
// TGPolygon hull = convex_hull(apt_pts);
|
||||||
|
|
||||||
TGPolygon filled_base = tgPolygonStripHoles( apt_base );
|
TGPolygon filled_base = tgPolygonStripHoles( apt_base );
|
||||||
// write_polygon( filled_base, "filled-base" );
|
// write_polygon( filled_base, "base" );
|
||||||
TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 );
|
TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 );
|
||||||
// write_polygon( divided_base, "divided-base" );
|
// write_polygon( divided_base, "divided-base" );
|
||||||
TGPolygon base_poly = tgPolygonDiff( divided_base, accum );
|
TGPolygon base_poly = tgPolygonDiff( divided_base, accum );
|
||||||
|
|
|
@ -681,7 +681,7 @@ static TGSuperPoly gen_touchdown_zone_lights( const TGRunway& rwy_info,
|
||||||
|
|
||||||
// generate a simple 2 bar VASI for a 3 degree approach
|
// generate a simple 2 bar VASI for a 3 degree approach
|
||||||
static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
|
static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
|
||||||
bool recip )
|
bool recip, TGPolygon *apt_base )
|
||||||
{
|
{
|
||||||
point_list lights; lights.clear();
|
point_list lights; lights.clear();
|
||||||
point_list normals; normals.clear();
|
point_list normals; normals.clear();
|
||||||
|
@ -768,14 +768,21 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
|
||||||
lights.push_back( pt1 );
|
lights.push_back( pt1 );
|
||||||
normals.push_back( normal );
|
normals.push_back( normal );
|
||||||
|
|
||||||
|
// grass base
|
||||||
|
Point3D base_pt = (ref + pt1) / 2.0;
|
||||||
|
TGPolygon obj_base = gen_wgs84_area( base_pt, 15.0, 0.0, 0.0, 15.0,
|
||||||
|
length_hdg, alt_m, false );
|
||||||
|
*apt_base = tgPolygonUnion( obj_base, *apt_base );
|
||||||
|
|
||||||
// upwind bar
|
// upwind bar
|
||||||
|
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), length_hdg,
|
||||||
|
700 * SG_FEET_TO_METER, &lat, &lon, &r );
|
||||||
|
ref = Point3D( lon, lat, 0.0 );
|
||||||
|
|
||||||
normal = gen_runway_light_vector( rwy_info, 3.0, recip );
|
normal = gen_runway_light_vector( rwy_info, 3.0, recip );
|
||||||
|
|
||||||
// unit1
|
// unit1
|
||||||
pt1 = ref;
|
pt1 = ref;
|
||||||
geo_direct_wgs_84 ( alt_m, pt1.lat(), pt1.lon(), length_hdg,
|
|
||||||
700 * SG_FEET_TO_METER, &lat, &lon, &r );
|
|
||||||
pt1 = Point3D( lon, lat, 0.0 );
|
|
||||||
lights.push_back( pt1 );
|
lights.push_back( pt1 );
|
||||||
normals.push_back( normal );
|
normals.push_back( normal );
|
||||||
geo_direct_wgs_84 ( alt_m, pt1.lat(), pt1.lon(), left_hdg,
|
geo_direct_wgs_84 ( alt_m, pt1.lat(), pt1.lon(), left_hdg,
|
||||||
|
@ -808,6 +815,12 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
|
||||||
lights.push_back( pt1 );
|
lights.push_back( pt1 );
|
||||||
normals.push_back( normal );
|
normals.push_back( normal );
|
||||||
|
|
||||||
|
// grass base
|
||||||
|
base_pt = (ref + pt1) / 2.0;
|
||||||
|
obj_base = gen_wgs84_area( base_pt, 15.0, 0.0, 0.0, 15.0,
|
||||||
|
length_hdg, alt_m, false );
|
||||||
|
*apt_base = tgPolygonUnion( obj_base, *apt_base );
|
||||||
|
|
||||||
TGPolygon lights_poly; lights_poly.erase();
|
TGPolygon lights_poly; lights_poly.erase();
|
||||||
TGPolygon normals_poly; normals_poly.erase();
|
TGPolygon normals_poly; normals_poly.erase();
|
||||||
lights_poly.add_contour( lights, false );
|
lights_poly.add_contour( lights, false );
|
||||||
|
@ -826,7 +839,7 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
|
||||||
|
|
||||||
// generate a simple PAPI for a 3 degree approach
|
// generate a simple PAPI for a 3 degree approach
|
||||||
static TGSuperPoly gen_papi( const TGRunway& rwy_info, float alt_m,
|
static TGSuperPoly gen_papi( const TGRunway& rwy_info, float alt_m,
|
||||||
bool recip )
|
bool recip, TGPolygon *apt_base )
|
||||||
{
|
{
|
||||||
point_list lights; lights.clear();
|
point_list lights; lights.clear();
|
||||||
point_list normals; normals.clear();
|
point_list normals; normals.clear();
|
||||||
|
@ -908,6 +921,12 @@ static TGSuperPoly gen_papi( const TGRunway& rwy_info, float alt_m,
|
||||||
normal = gen_runway_light_vector( rwy_info, 2.5, recip );
|
normal = gen_runway_light_vector( rwy_info, 2.5, recip );
|
||||||
normals.push_back( normal );
|
normals.push_back( normal );
|
||||||
|
|
||||||
|
// grass base
|
||||||
|
Point3D base_pt = (ref + pt1) / 2.0;
|
||||||
|
TGPolygon obj_base = gen_wgs84_area( base_pt, 15.0, 0.0, 0.0, 30.0,
|
||||||
|
length_hdg, alt_m, false );
|
||||||
|
*apt_base = tgPolygonUnion( obj_base, *apt_base );
|
||||||
|
|
||||||
TGPolygon lights_poly; lights_poly.erase();
|
TGPolygon lights_poly; lights_poly.erase();
|
||||||
TGPolygon normals_poly; normals_poly.erase();
|
TGPolygon normals_poly; normals_poly.erase();
|
||||||
lights_poly.add_contour( lights, false );
|
lights_poly.add_contour( lights, false );
|
||||||
|
@ -2563,7 +2582,7 @@ static superpoly_list gen_malsx( const TGRunway& rwy_info,
|
||||||
|
|
||||||
// top level runway light generator
|
// top level runway light generator
|
||||||
void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
||||||
superpoly_list &lights ) {
|
superpoly_list &lights, TGPolygon *apt_base ) {
|
||||||
|
|
||||||
string lighting_flags = rwy_info.lighting_flags;
|
string lighting_flags = rwy_info.lighting_flags;
|
||||||
SG_LOG( SG_GENERAL, SG_DEBUG, "gen runway lights " << rwy_info.rwy_no << " "
|
SG_LOG( SG_GENERAL, SG_DEBUG, "gen runway lights " << rwy_info.rwy_no << " "
|
||||||
|
@ -2632,17 +2651,17 @@ void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
||||||
|
|
||||||
// VASI/PAPI lighting
|
// VASI/PAPI lighting
|
||||||
if ( vasi1 == 2 /* Has VASI */ ) {
|
if ( vasi1 == 2 /* Has VASI */ ) {
|
||||||
TGSuperPoly s = gen_vasi( rwy_info, alt_m, false );
|
TGSuperPoly s = gen_vasi( rwy_info, alt_m, false, apt_base );
|
||||||
lights.push_back( s );
|
lights.push_back( s );
|
||||||
} else if ( vasi1 == 3 /* Has PAPI */ ) {
|
} else if ( vasi1 == 3 /* Has PAPI */ ) {
|
||||||
TGSuperPoly s = gen_papi( rwy_info, alt_m, false );
|
TGSuperPoly s = gen_papi( rwy_info, alt_m, false, apt_base );
|
||||||
lights.push_back( s );
|
lights.push_back( s );
|
||||||
}
|
}
|
||||||
if ( vasi2 == 2 /* Has VASI */ ) {
|
if ( vasi2 == 2 /* Has VASI */ ) {
|
||||||
TGSuperPoly s = gen_vasi( rwy_info, alt_m, true );
|
TGSuperPoly s = gen_vasi( rwy_info, alt_m, true, apt_base );
|
||||||
lights.push_back( s );
|
lights.push_back( s );
|
||||||
} else if ( vasi2 == 3 /* Has PAPI */ ) {
|
} else if ( vasi2 == 3 /* Has PAPI */ ) {
|
||||||
TGSuperPoly s = gen_papi( rwy_info, alt_m, true );
|
TGSuperPoly s = gen_papi( rwy_info, alt_m, true, apt_base );
|
||||||
lights.push_back( s );
|
lights.push_back( s );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2853,26 +2872,30 @@ void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
||||||
|
|
||||||
// Many aproach lighting systems define the threshold lighting
|
// Many aproach lighting systems define the threshold lighting
|
||||||
// needed, but for those that don't (i.e. REIL, ODALS, or Edge
|
// needed, but for those that don't (i.e. REIL, ODALS, or Edge
|
||||||
// lights defined but no approach lights.)
|
// lights defined but no approach lights)
|
||||||
// Make threshold lighting
|
// make threshold lighting
|
||||||
|
cout << "rwylt1 = " << rwylt1 << " app1 = " << app1 << endl;
|
||||||
if ( rwylt1 >= 3 /* Has REIL lighting */
|
if ( rwylt1 >= 3 /* Has REIL lighting */
|
||||||
|| app1 == 6 /* ODALS Omni-directional approach light system */
|
|| app1 == 6 /* ODALS Omni-directional approach light system */
|
||||||
|| ( rwylt1 >= 2 /* Has edge lighting */
|
|| ( rwylt1 >= 2 && app1 <= 1 ) /* Has edge lighting, but no
|
||||||
&& app1 == 0 /* No approach lighting */ ) )
|
approach lighting */ )
|
||||||
{
|
{
|
||||||
// forward direction
|
// forward direction
|
||||||
|
cout << "threshold lights for forward direction" << endl;
|
||||||
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
|
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
|
||||||
alt_m, false );
|
alt_m, false );
|
||||||
for ( i = 0; i < s.size(); ++i ) {
|
for ( i = 0; i < s.size(); ++i ) {
|
||||||
lights.push_back( s[i] );
|
lights.push_back( s[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cout << "rwylt2 = " << rwylt2 << " app2 = " << app2 << endl;
|
||||||
if ( rwylt2 >= 3 /* Has REIL lighting */
|
if ( rwylt2 >= 3 /* Has REIL lighting */
|
||||||
|| app2 == 6 /* ODALS Omni-directional approach light system */
|
|| app2 == 6 /* ODALS Omni-directional approach light system */
|
||||||
|| ( rwylt2 >= 2 /* Has edge lighting */
|
|| ( rwylt2 >= 2 && app2 <= 1 ) /* Has edge lighting, but no
|
||||||
&& app2 == 0 /* No approach lighting */ ) )
|
approach lighting */ )
|
||||||
{
|
{
|
||||||
// reverse direction
|
// reverse direction
|
||||||
|
cout << "threshold lights for reverse direction" << endl;
|
||||||
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
|
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
|
||||||
alt_m, true );
|
alt_m, true );
|
||||||
for ( i = 0; i < s.size(); ++i ) {
|
for ( i = 0; i < s.size(); ++i ) {
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
|
|
||||||
// generate runway lighting
|
// generate runway lighting
|
||||||
void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
||||||
superpoly_list &lights );
|
superpoly_list &lights, TGPolygon *apt_base );
|
||||||
|
|
||||||
// generate taxiway lighting
|
// generate taxiway lighting
|
||||||
void gen_taxiway_lights( const TGRunway& taxiway_info, float alt_m,
|
void gen_taxiway_lights( const TGRunway& taxiway_info, float alt_m,
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
// given a runway center point, length, width, and heading, and
|
// given a runway center point, length, width, and heading, and
|
||||||
// altitude (meters) generate the lon and lat 4 corners using wgs84
|
// altitude (meters) generate the lon and lat 4 corners using wgs84
|
||||||
// math.
|
// math.
|
||||||
static TGPolygon gen_wgs84_area( Point3D origin,
|
TGPolygon gen_wgs84_area( Point3D origin,
|
||||||
double length_m,
|
double length_m,
|
||||||
double displ1, double displ2,
|
double displ1, double displ2,
|
||||||
double width_m,
|
double width_m,
|
||||||
|
|
|
@ -71,6 +71,17 @@ typedef runway_list::iterator runway_list_iterator;
|
||||||
typedef runway_list::const_iterator const_runway_list_iterator;
|
typedef runway_list::const_iterator const_runway_list_iterator;
|
||||||
|
|
||||||
|
|
||||||
|
// given a runway center point, length, width, and heading, and
|
||||||
|
// altitude (meters) generate the lon and lat 4 corners using wgs84
|
||||||
|
// math.
|
||||||
|
TGPolygon gen_wgs84_area( Point3D origin,
|
||||||
|
double length_m,
|
||||||
|
double displ1, double displ2,
|
||||||
|
double width_m,
|
||||||
|
double heading_deg,
|
||||||
|
double alt_m,
|
||||||
|
bool add_mid );
|
||||||
|
|
||||||
// generate an area for a runway with expantion specified as a scale
|
// generate an area for a runway with expantion specified as a scale
|
||||||
// factor (return result points in degrees)
|
// factor (return result points in degrees)
|
||||||
TGPolygon gen_runway_area_w_scale( const TGRunway& runway,
|
TGPolygon gen_runway_area_w_scale( const TGRunway& runway,
|
||||||
|
|
Loading…
Add table
Reference in a new issue