- 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 )
|
||||
// Minimum divs appears to need to be at least 5 before the
|
||||
// leastsquares nurbs surface approximation stops crashing.
|
||||
if ( xdivs < 5 ) { xdivs = 5; }
|
||||
if ( ydivs < 5 ) { ydivs = 5; }
|
||||
if ( xdivs < 6 ) { xdivs = 6; }
|
||||
if ( ydivs < 6 ) { ydivs = 6; }
|
||||
#else
|
||||
# error "Need to define _NURBS_GLOBAL_INTER or _NURBS_LEAST_SQUARES"
|
||||
#endif
|
||||
|
@ -269,8 +269,11 @@ TGAptSurface::TGAptSurface( const string& path,
|
|||
// sanity check: I'm finding that leastSquares() can produce nan
|
||||
// surfaces. We test for this and fall back to globalInterp() if
|
||||
// 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 );
|
||||
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
|
||||
} else {
|
||||
// no, sorry, a nan is not <= 0.0 or >= 0.0
|
||||
|
@ -278,7 +281,7 @@ TGAptSurface::TGAptSurface( const string& path,
|
|||
"leastSquares() nurbs interpolation failed!!!");
|
||||
char command[256];
|
||||
sprintf( command,
|
||||
"least squares nurbs interpolation failed, using globalInterp() >> last_apt" );
|
||||
"echo least squares nurbs interpolation failed, using globalInterp() >> last_apt" );
|
||||
system( command );
|
||||
|
||||
// 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;
|
||||
|
||||
if ( count > 100 ) {
|
||||
// solver failed
|
||||
cout << "binary solver failed..." << endl;
|
||||
return -9999.0;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
|
@ -487,6 +497,12 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
|
|||
}
|
||||
v = (max_v + min_v) / 2.0;
|
||||
|
||||
if ( count > 100 ) {
|
||||
// solver failed
|
||||
cout << "binary solver failed..." << endl;
|
||||
return -9999.0;
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
|
@ -500,15 +516,7 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
|
|||
// cout << " final query distance error = " << dist << endl;
|
||||
return p.z();
|
||||
}
|
||||
|
||||
gcount++;
|
||||
if ( gcount % 100 == 0 ) {
|
||||
cout << "query count = " << gcount << " dist = " << dx << ", "
|
||||
<< dy << endl;
|
||||
}
|
||||
}
|
||||
|
||||
cout << "binary solver failed..." << endl;
|
||||
|
||||
return p.z();
|
||||
}
|
||||
|
|
|
@ -603,16 +603,45 @@ void build_airport( string airport_id, float alt_m,
|
|||
}
|
||||
}
|
||||
|
||||
// write_polygon( accum, "accum" );
|
||||
if ( apt_base.total_size() == 0 ) {
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "no airport points generated");
|
||||
return;
|
||||
// Now generate small surface for each beacon
|
||||
TGPolygon obj_base, obj_safe_base;
|
||||
double obj_hdg = runways[0].heading;
|
||||
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
|
||||
superpoly_list rwy_lights; rwy_lights.clear();
|
||||
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
|
||||
|
@ -620,11 +649,19 @@ void build_airport( string airport_id, float alt_m,
|
|||
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)
|
||||
// TGPolygon hull = convex_hull(apt_pts);
|
||||
|
||||
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 );
|
||||
// write_polygon( divided_base, "divided-base" );
|
||||
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
|
||||
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 normals; normals.clear();
|
||||
|
@ -768,14 +768,21 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
|
|||
lights.push_back( pt1 );
|
||||
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
|
||||
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 );
|
||||
|
||||
// unit1
|
||||
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 );
|
||||
normals.push_back( normal );
|
||||
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 );
|
||||
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 normals_poly; normals_poly.erase();
|
||||
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
|
||||
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 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 );
|
||||
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 normals_poly; normals_poly.erase();
|
||||
lights_poly.add_contour( lights, false );
|
||||
|
@ -2563,7 +2582,7 @@ static superpoly_list gen_malsx( const TGRunway& rwy_info,
|
|||
|
||||
// top level runway light generator
|
||||
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;
|
||||
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
|
||||
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 );
|
||||
} 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 );
|
||||
}
|
||||
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 );
|
||||
} 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 );
|
||||
}
|
||||
|
||||
|
@ -2853,26 +2872,30 @@ void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
|||
|
||||
// Many aproach lighting systems define the threshold lighting
|
||||
// needed, but for those that don't (i.e. REIL, ODALS, or Edge
|
||||
// lights defined but no approach lights.)
|
||||
// Make threshold lighting
|
||||
// lights defined but no approach lights)
|
||||
// make threshold lighting
|
||||
cout << "rwylt1 = " << rwylt1 << " app1 = " << app1 << endl;
|
||||
if ( rwylt1 >= 3 /* Has REIL lighting */
|
||||
|| app1 == 6 /* ODALS Omni-directional approach light system */
|
||||
|| ( rwylt1 >= 2 /* Has edge lighting */
|
||||
&& app1 == 0 /* No approach lighting */ ) )
|
||||
|| ( rwylt1 >= 2 && app1 <= 1 ) /* Has edge lighting, but no
|
||||
approach lighting */ )
|
||||
{
|
||||
// forward direction
|
||||
cout << "threshold lights for forward direction" << endl;
|
||||
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
|
||||
alt_m, false );
|
||||
for ( i = 0; i < s.size(); ++i ) {
|
||||
lights.push_back( s[i] );
|
||||
}
|
||||
}
|
||||
cout << "rwylt2 = " << rwylt2 << " app2 = " << app2 << endl;
|
||||
if ( rwylt2 >= 3 /* Has REIL lighting */
|
||||
|| app2 == 6 /* ODALS Omni-directional approach light system */
|
||||
|| ( rwylt2 >= 2 /* Has edge lighting */
|
||||
&& app2 == 0 /* No approach lighting */ ) )
|
||||
|| ( rwylt2 >= 2 && app2 <= 1 ) /* Has edge lighting, but no
|
||||
approach lighting */ )
|
||||
{
|
||||
// reverse direction
|
||||
cout << "threshold lights for reverse direction" << endl;
|
||||
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
|
||||
alt_m, true );
|
||||
for ( i = 0; i < s.size(); ++i ) {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
// generate runway lighting
|
||||
void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
|
||||
superpoly_list &lights );
|
||||
superpoly_list &lights, TGPolygon *apt_base );
|
||||
|
||||
// generate taxiway lighting
|
||||
void gen_taxiway_lights( const TGRunway& taxiway_info, float alt_m,
|
||||
|
|
|
@ -37,13 +37,13 @@
|
|||
// given a runway center point, length, width, and heading, and
|
||||
// altitude (meters) generate the lon and lat 4 corners using wgs84
|
||||
// math.
|
||||
static 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 )
|
||||
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 )
|
||||
{
|
||||
TGPolygon result_list;
|
||||
double length_hdg = heading_deg;
|
||||
|
|
|
@ -71,6 +71,17 @@ typedef runway_list::iterator 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
|
||||
// factor (return result points in degrees)
|
||||
TGPolygon gen_runway_area_w_scale( const TGRunway& runway,
|
||||
|
|
Loading…
Add table
Reference in a new issue