allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/27/89)
Posting-number: Volume 9, Issue 13 Submitted-by: tynor@prism.gatech.edu (Steve Tynor) Archive-name: fplan/part03 #This is part 3/6 of FPLAN #!/bin/sh # shar: Shell Archiver (v1.22) # Packed Mon Nov 20 19:28:37 EST 1989 by gaffa!tynor # from directory /files/home/users/tynor/src/fplan # # Run the following text with /bin/sh to create: # add.c # compute.c # echo "x - extracting add.c (Text)" sed 's/^X//' << 'SHAR_EOF' > add.c && X/* X * $Id: add.c,v 2.5 89/11/11 19:09:43 tynor Exp $ X *---------------------------------------------------------------------------- X * FPLAN - Flight Planner X * Steve Tynor X * tynor@prism.gatech.edu X * X * This program is in the public domain. Permission to copy, X * distribute, modify this program is hearby given as long as this header X * remains. If you redistribute this program after modifying it, please X * document your changes so that I do not take the blame (or credit) for X * those changes. If you fix bugs or add features, please send me a X * patch so that I can keep the 'official' version up-to-date. X * X * Bug reports are welcome and I'll make an attempt to fix those X * that are reported. X * X * USE AT YOUR OWN RISK! I assume no responsibility for any X * errors in this program, its database or documentation. I will make an X * effort to fix bugs, but if you crash and burn because, for example, X * fuel estimates in this program were inaccurate, it's your own fault X * for trusting somebody else's code! Remember, as PIC, it's _your_ X * responsibility to do complete preflight planning. Use this program as X * a flight planning aid, but verify its results before using them. X *---------------------------------------------------------------------------- X */ X Xstatic char rcsid[] = "$Id: add.c,v 2.5 89/11/11 19:09:43 tynor Exp $"; X X#include "wp_info.h" X Xextern char *malloc(); Xextern BOOLEAN lookup_desig (); X Xstatic BOOLEAN brief_mode = FALSE; X X#if 0 X/*----------------------------------------------------------------------------*/ Xstatic void find_intersection (desig1, radial1, desig2, radial2, X latitude, longitude) X double radial1, radial2; X char *desig1, *desig2; X double *latitude, *longitude; X{ X yyerror ("don't know how to find intersection yet"); X} X#endif X X/*----------------------------------------------------------------------------*/ Xstatic void init_db (db) XDATABASE_INFO *db; X{ X if (db) { X db->freq.valid = FALSE; X db->desig = (char*)0; X db->name = (char*)0; X db->city = (char*)0; X db->comment = (char*)0; X db->altitude.valid = FALSE; X } X} X X/*----------------------------------------------------------------------------*/ Xstatic void new_waypoint () X{ X extern yyerror(); X X if (num_waypoints >= MAX_NUM_WAYPOINTS) X yyerror ("too many waypoints"); X X if (num_waypoints > 0) { X waypoints[num_waypoints] = waypoints[num_waypoints-1]; X waypoints[num_waypoints].refuel = FALSE; X waypoints[num_waypoints].extra_fuel_burn.valid = FALSE; X } X X num_waypoints++; X} X X/*----------------------------------------------------------------------------*/ Xvoid add_named_waypoint (kind, desig) X WAYPOINT_KIND kind; X char *desig; X{ X DATABASE_INFO *db; X X if (lookup_desig (kind, desig, &db)) { X new_waypoint (); X waypoints[num_waypoints-1].wp_kind = kind; X waypoints[num_waypoints-1].db = db; X } X} X X/*----------------------------------------------------------------------------*/ Xvoid add_inc_waypoint (dist_since_last_wp, X name_str, city_str, comment_str) X double dist_since_last_wp; X char *name_str; X char *city_str; X char *comment_str; X{ X if (brief_mode) X return; X X new_waypoint (); X X waypoints[num_waypoints-1].db = X (DATABASE_INFO*) malloc (sizeof (DATABASE_INFO)); X if (! waypoints[num_waypoints-1].db) X yyerror ("unable to allocate space for waypoint"); X X init_db (waypoints[num_waypoints-1].db); X X waypoints[num_waypoints-1].db->mode = WP_INCREMENTAL; X waypoints[num_waypoints-1].wp_kind = WP_VIA; X waypoints[num_waypoints-1].db->name = name_str; X waypoints[num_waypoints-1].db->city = city_str; X waypoints[num_waypoints-1].db->comment = comment_str; X X /* X * NOTE: we can't compute lat/long since we don't know the true course X * yet. So, just store the distance until print time. X */ X waypoints[num_waypoints-1].db->u.dist_since_last_wp = dist_since_last_wp; X} X X#if 0 X/*----------------------------------------------------------------------------*/ Xvoid add_int_waypoint (kind, desig1, radial1, desig2, radial2, X name_str, city_str, comment_str) X WAYPOINT_KIND kind; X double radial1, radial2; X char *desig1, *desig2, *name_str, *city_str, *comment_str; X{ X new_waypoint (); X waypoints[num_waypoints-1].db = X (DATABASE_INFO*) malloc (sizeof (DATABASE_INFO)); X if (! waypoints[num_waypoints-1].db) X yyerror ("unable to allocate space for waypoint"); X X init_db (waypoints[num_waypoints-1].db); X X find_intersection (desig1, radial1, desig2, radial2, X &waypoints[num_waypoints-1].db->latitude, X &waypoints[num_waypoints-1].db->longitude); X waypoints[num_waypoints-1].db->mode = WP_INTERSECTION; X waypoints[num_waypoints-1].wp_kind = kind; X waypoints[num_waypoints-1].db->name = name_str; X waypoints[num_waypoints-1].db->city = city_str; X waypoints[num_waypoints-1].db->comment = comment_str; X} X#endif X X/*----------------------------------------------------------------------------*/ Xvoid add_lat_waypoint (kind, latitude, longitude, X name_str, city_str, comment_str) X WAYPOINT_KIND kind; X double latitude, longitude; X char *name_str; X char *city_str; X char *comment_str; X{ X new_waypoint (); X waypoints[num_waypoints-1].db = X (DATABASE_INFO*) malloc (sizeof (DATABASE_INFO)); X if (! waypoints[num_waypoints-1].db) X yyerror ("unable to allocate space for waypoint"); X X init_db (waypoints[num_waypoints-1].db); X X waypoints[num_waypoints-1].db->mode = WP_LAT_LONG; X waypoints[num_waypoints-1].wp_kind = kind; X waypoints[num_waypoints-1].db->latitude = latitude; X waypoints[num_waypoints-1].db->longitude = longitude; X waypoints[num_waypoints-1].db->name = name_str; X waypoints[num_waypoints-1].db->city = city_str; X waypoints[num_waypoints-1].db->comment = comment_str; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_xfix (vor_num, vor_desig) Xint vor_num; Xchar *vor_desig; X{ X char buffer[80]; X int i = MAX (0, num_waypoints-1); X X if ((vor_num < 1) || (vor_num > MAX_NUM_VOR_FIXES)) { X sprintf (buffer, "Invalid NAV number. Must be between 1 and %d", X MAX_NUM_VOR_FIXES); X yyerror (buffer); X } X if (lookup_desig (WP_VIA, vor_desig, &waypoints[i].vor_fix[vor_num-1].db)) { X waypoints[i].vor_fix[vor_num-1].valid = TRUE; X max_nav = MAX (max_nav, vor_num-1); X } X} X X/*----------------------------------------------------------------------------*/ Xvoid set_tas (tas) X double tas; X{ X int i = MAX (0, num_waypoints-1); X X waypoints[i].tas.valid = TRUE; X waypoints[i].tas.value = tas; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_wind (heading, speed) X double heading, speed; X{ X int i = MAX (0, num_waypoints-1); X X waypoints[i].wind_speed.valid = TRUE; X waypoints[i].wind_speed.value = speed; X waypoints[i].wind_direction.valid = TRUE; X waypoints[i].wind_direction.value = heading; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_fuel_amt (amt) X double amt; X{ X int i = MAX (0, num_waypoints-1); X X waypoints[i].refuel = TRUE; X waypoints[i].fuel_amt.valid = TRUE; X waypoints[i].fuel_amt.value = amt; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_extra_fuel_burn (amt) X double amt; X{ X int i = MAX (0, num_waypoints-1); X X waypoints[i].extra_fuel_burn.valid = TRUE; X waypoints[i].extra_fuel_burn.value = amt; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_fuel_rate (rate) X double rate; X{ X int i = MAX (0, num_waypoints-1); X X waypoints[i].fuel_rate.valid = TRUE; X waypoints[i].fuel_rate.value = rate; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_altitude (feet) X double feet; X{ X int i = MAX (0, num_waypoints-1); X X waypoints[i].altitude.valid = TRUE; X waypoints[i].altitude.value = feet; X} X X/*----------------------------------------------------------------------------*/ Xvoid set_brief (on_off) X BOOLEAN on_off; X{ X brief_mode = on_off; X} X X SHAR_EOF chmod 0444 add.c || echo "restore of add.c fails" echo "x - extracting compute.c (Text)" sed 's/^X//' << 'SHAR_EOF' > compute.c && X/* X * $Id: compute.c,v 2.6 89/11/14 20:27:46 tynor Exp $ X *---------------------------------------------------------------------------- X * FPLAN - Flight Planner X * Steve Tynor X * tynor@prism.gatech.edu X * X * This program is in the public domain. Permission to copy, X * distribute, modify this program is hearby given as long as this header X * remains. If you redistribute this program after modifying it, please X * document your changes so that I do not take the blame (or credit) for X * those changes. If you fix bugs or add features, please send me a X * patch so that I can keep the 'official' version up-to-date. X * X * Bug reports are welcome and I'll make an attempt to fix those X * that are reported. X * X * USE AT YOUR OWN RISK! I assume no responsibility for any X * errors in this program, its database or documentation. I will make an X * effort to fix bugs, but if you crash and burn because, for example, X * fuel estimates in this program were inaccurate, it's your own fault X * for trusting somebody else's code! Remember, as PIC, it's _your_ X * responsibility to do complete preflight planning. Use this program as X * a flight planning aid, but verify its results before using them. X *---------------------------------------------------------------------------- X */ X Xstatic char rcsid[] = "$Id: compute.c,v 2.6 89/11/14 20:27:46 tynor Exp $"; X X#include "wp_info.h" X#include <math.h> X X/*----------------------------------------------------------------------------*/ Xstatic void wind_correct (true_air_speed, mag_course, X wind_speed, wind_heading, X ground_speed, mag_heading) X double true_air_speed, mag_course, X wind_speed, wind_heading, X *ground_speed, *mag_heading; X{ X double hdiff, tx, ty, wca; X X if (wind_heading <= 180.0) X wind_heading += 180.0; X else X wind_heading -= 180.0; X hdiff = DEG2RAD (mag_course - wind_heading); X tx = wind_speed * sin (hdiff); X ty = wind_speed * cos (hdiff); X wca = asin (tx / true_air_speed); X *ground_speed = cos (wca) * true_air_speed + ty; X *mag_heading = mag_course + RAD2DEG (wca); X if (*mag_heading >= 360.0) X *mag_heading -= 360.0; X else if (*mag_heading <= 0.0) X *mag_heading += 360.0; X} X X/*----------------------------------------------------------------------------*/ Xvoid distance_and_heading (lat1, long1, lat2, long2, distance, heading) X double lat1, long1, lat2, long2; X double *distance, *heading; X{ X double tmp; X X lat1 = DEG2RAD (lat1); X long1 = DEG2RAD (long1); X lat2 = DEG2RAD (lat2); X long2 = DEG2RAD (long2); X X if ((lat1 == lat2) && (long1 == long2)) { X *distance = 0.0; X *heading = 0.0; X return; X } X X tmp = atan2 (2.0 * asin (sin ((long1 - long2) / 2.0)), X log (tan (PI / 4.0 + lat2 / 2.0)) - X log (tan (PI / 4.0 + lat1 / 2.0)) ); X if (lat1 == lat2) X *distance = 60.0 * X fabs (RAD2DEG (2.0 * asin (sin ((long1 - long2) / 2.0)))) * X cos (lat1); X else X *distance = 60.0 * RAD2DEG (lat2 - lat1) / cos (fabs (tmp)); X X if (asin (sin (long1-long2)) >= 0.0) X *heading = RAD2DEG (fabs(tmp)); X else X *heading = 360.0 - RAD2DEG (fabs(tmp)); X} X X/*----------------------------------------------------------------------------*/ Xstatic int next_non_incremental (start) X int start; X{ X int i = start; X X for (i = start; i < num_waypoints; i++) X if (waypoints[i].db->mode != WP_INCREMENTAL) X return i; X return -1; X} X X/*----------------------------------------------------------------------------*/ Xstatic void locate_incrementals () X{ X int j, prev, next; X double d, heading; X X for (prev = 0; ((prev >= 0) && (prev < num_waypoints)); ) { X next = next_non_incremental (prev+1); X if (next >= 0) { X distance_and_heading (waypoints[prev].db->latitude, X waypoints[prev].db->longitude, X waypoints[next].db->latitude, X waypoints[next].db->longitude, X &d, &heading); X for (j = prev+1; j < next; j++) { X if (waypoints[j].db->u.dist_since_last_wp >= 0.0) { X waypoints[j].db->latitude = waypoints[prev].db->latitude + X (waypoints[next].db->latitude - waypoints[prev].db->latitude) X * waypoints[j].db->u.dist_since_last_wp / d; X waypoints[j].db->longitude = waypoints[prev].db->longitude + X (waypoints[next].db->longitude - X waypoints[prev].db->longitude) * X waypoints[j].db->u.dist_since_last_wp / d; X } else { X waypoints[j].db->latitude = waypoints[next].db->latitude + X (waypoints[next].db->latitude - waypoints[prev].db->latitude) X * waypoints[j].db->u.dist_since_last_wp / d; X waypoints[j].db->longitude = waypoints[next].db->longitude + X (waypoints[next].db->longitude - X waypoints[prev].db->longitude) * X waypoints[j].db->u.dist_since_last_wp / d; X } X } X } X prev = next; X } X} X X/*----------------------------------------------------------------------------*/ X#define IS_NAVAID(mode) (((mode) == WP_VOR) || ((mode) == WP_NDB) || \ X ((mode) == WP_DME) || ((mode) == WP_TAC) || \ X ((mode) == WP_ILS) || ((mode) == WP_LOM) || \ X ((mode) == WP_LMM)) X X/*---------------------------------------------------------------------------- X * FUZZ is the number of degrees two points can be apart and still be considered X * colocated - we let this be fuzzy, since it's often the case that onfield VORs X * are reported with slightly different lat/long, but we still want to view them X * as the same point... X */ X#define FUZZ 0.01 X#define COLOCATED(db1,db2) \ X ((fabs ((db1)->latitude - (db2)->latitude) <= FUZZ) && \ X (fabs ((db1)->longitude - (db2)->longitude) <= FUZZ)) X X/*----------------------------------------------------------------------------*/ Xstatic DATABASE_INFO *get_navaid (wp) X WAYPOINT_INFO wp; X /* X * If the waypoint is a navaid return its db pointer. If it's an airport X * and there's a navaid colocated on the field, return it's db pointer, X * else return NULL. X */ X{ X DATABASE_INFO *db; X extern BOOLEAN lookup_desig (); X X if (IS_NAVAID (wp.db->mode)) { X return (wp.db); X } else if ((wp.db->mode == WP_AIRPORT) && X (lookup_desig (WP_VIA, wp.db->desig, &db)) && X IS_NAVAID (db->mode) && X COLOCATED (db, wp.db) ) { X return (db); X } else { X return ((DATABASE_INFO*) 0); X } X} X X/*----------------------------------------------------------------------------*/ Xstatic track_nav1 () X /* X * for each waypoint, determine what VOR to tune in on NAV1. X * X * This is tricky - some waypoints are navaids - so we want to track to X * (and sometimes from) them - others are just "distance-since-last- X * -waypoint" or "lat/long" waypoints, and we can't track to those. X * From and To Airports also sometimes have VORS on-field, so we need to X * recognize when that happens so that we can track to/from airport X * waypoints. X * X * The vor_fix[0] for each waypoint is for the leg _between_ that waypoint X * and the next one. If there is no navaid that can be used to track along X * that leg, set the .valid falg to FALSE. X */ X{ X int this, to; X DATABASE_INFO *db; X X /* X * invalidate all the current NAV1 settings X */ X for (this = 0; this < num_waypoints; this++) X waypoints[this].vor_fix[0].valid = FALSE; X X to = 0; X for (this = 0; (to != -1) && (this < num_waypoints); this++) { X to = next_non_incremental (this+1); X if ( X /* X * if the next non-incremental waypoint is a navaid (or if an X * airport and there's a navaid colocated on the field) then use that X * as NAV1 for this waypoint and those up to that one X */ X ((to >= 0) && X (db = get_navaid (waypoints[to]))) || X /* X * else, if this waypoint is a navaid, use it X */ X (db = get_navaid (waypoints[this])) ) { X for (; this < to; this++) { X waypoints[this].vor_fix[0].valid = TRUE; X waypoints[this].vor_fix[0].db = db; X } X this = to - 1; X } X /* X * else, we're out of luck - leave the fix invalid. X */ X } X} X X/*----------------------------------------------------------------------------*/ Xnormalize_heading (head) X double *head; X{ X if (*head < 0.0) X *head += 360.0; X else if (*head > 360.0) X *head -= 360.0; X} X X/*----------------------------------------------------------------------------*/ Xstatic BOOLEAN do_fix (plane_heading, latitude, longitude, vor_fix, force_from) X double plane_heading; X double latitude; X double longitude; X VOR_FIX *vor_fix; X BOOLEAN force_from; X{ X double d; X double lat_from = latitude; X double long_from = longitude; X double lat_to = vor_fix->db->latitude; X double long_to = vor_fix->db->longitude; X X if (! vor_fix->db) X return FALSE; X X if ((lat_from == lat_to) && (long_from == long_to)) X return FALSE; X X distance_and_heading (lat_from, long_from, lat_to, long_to, X &vor_fix->distance, &vor_fix->heading); X vor_fix->heading += vor_fix->db->mag_variation; X d = plane_heading - vor_fix->heading; X vor_fix->from_to = TO; X if (force_from || (d > 180.0) || (d < -180.0)) { X vor_fix->from_to = FROM; X vor_fix->heading += 180.0; X } X normalize_heading (&vor_fix->heading); X return TRUE; X} X X/*----------------------------------------------------------------------------*/ XBOOLEAN compute_plan (auto_nav1) X BOOLEAN auto_nav1; X{ X int i; X int num_pairs = 0; X#define MAX_NUM_PAIRS 30 X double total_dist [MAX_NUM_PAIRS]; X double distance, heading; X X /* X * locate the waypoints specified only by distance from last waypoint: X */ X locate_incrementals (); X X /* X * accumulate the total distance between each from/to pair X */ X num_pairs = 0; X for (i = 0; i < num_waypoints; i++) { X if (waypoints[i].wp_kind == WP_FROM) { X waypoints[i].eta.valid = TRUE; X waypoints[i].eta.value = 0.0; X total_dist [num_pairs] = 0.0; X } X if ((i+1 < num_waypoints) && (waypoints[i].wp_kind != WP_TO)) { X distance_and_heading (waypoints[i].db->latitude, X waypoints[i].db->longitude, X waypoints[i+1].db->latitude, X waypoints[i+1].db->longitude, X &distance, &heading); X waypoints[i].dist_leg.valid = TRUE; X waypoints[i].tc.valid = TRUE; X waypoints[i].mc.valid = TRUE; X waypoints[i].dist_leg.value = distance; X waypoints[i].tc.value = heading; X waypoints[i].mc.value = heading + waypoints[i].db->mag_variation; X normalize_heading (&waypoints[i].mc.value); X normalize_heading (&waypoints[i].tc.value); X } else { X waypoints[i].dist_leg.valid = FALSE; X waypoints[i].tc.valid = FALSE; X waypoints[i].mc.valid = FALSE; X } X X waypoints[i].dist.valid = TRUE; X waypoints[i].dist.value = total_dist [num_pairs]; X X total_dist [num_pairs] += waypoints[i].dist_leg.value; X X if (waypoints[i].wp_kind == WP_TO) X num_pairs++; X } X X /* X * now, do the distance remaining: X */ X num_pairs = 0.0; X for (i = 0; i < num_waypoints; i++) { X waypoints[i].dist_remain.value = X total_dist [num_pairs] - waypoints[i].dist.value; X waypoints[i].dist_remain.valid = TRUE; X if (waypoints[i].wp_kind == WP_TO) X num_pairs++; X } X X /* X * wind correction (heading, ground speed) X */ X for (i = 0; i < num_waypoints; i++) { X if (waypoints[i].tas.valid && X waypoints[i].mc.valid) { X X if (!waypoints[i].wind_speed.valid) X waypoints[i].wind_speed.value = 0.0; X if (!waypoints[i].wind_direction.valid) X waypoints[i].wind_direction.value = 0.0; X X wind_correct (waypoints[i].tas.value, X waypoints[i].mc.value, X waypoints[i].wind_speed.value, X waypoints[i].wind_direction.value, X &waypoints[i].egs.value, X &waypoints[i].mh.value); X X waypoints[i].egs.valid = TRUE; X waypoints[i].mh.valid = TRUE; X normalize_heading (&waypoints[i].mh.value); X X /* X * time in hours X */ X waypoints[i].eta_leg.valid = waypoints[i].dist_leg.valid; X waypoints[i].eta_leg.value = waypoints[i].dist_leg.value / X waypoints[i].egs.value; X } else { X waypoints[i].egs.valid = FALSE; X waypoints[i].mh.valid = FALSE; X waypoints[i].eta.valid = FALSE; X waypoints[i].eta_leg.valid = FALSE; X } X waypoints[i].eta.valid = (BOOLEAN) (waypoints[i].wp_kind != WP_FROM); X waypoints[i].eta.value = (waypoints[i].dist.value == 0.0) ? 0.0 : X waypoints[i-1].eta_leg.value + waypoints[i-1].eta.value; X } X X /* X * fuel burn: X */ X for (i = 0; i < num_waypoints; i++) { X waypoints[i].fuel_leg.valid = (BOOLEAN) (waypoints[i].fuel_rate.valid && X waypoints[i].eta_leg.valid); X if (waypoints[i].fuel_leg.valid) X waypoints[i].fuel_leg.value = X waypoints[i].fuel_rate.value * waypoints[i].eta_leg.value; X if (waypoints[i].refuel) { X waypoints[i].fuel_amt.valid = TRUE; X } else if (i && (waypoints[i].wp_kind == WP_FROM) && X (!waypoints[i].refuel)) { X waypoints[i].fuel_amt.valid = waypoints[i-1].fuel_amt.valid; X waypoints[i].fuel_amt.value = waypoints[i-1].fuel_amt.value; X } else if (i && waypoints[i-1].fuel_leg.valid && X waypoints[i-1].fuel_amt.valid) { X waypoints[i].fuel_amt.value = X waypoints[i-1].fuel_amt.value - waypoints[i-1].fuel_leg.value; X } X if (waypoints[i].extra_fuel_burn.valid) X waypoints[i].fuel_amt.value -= waypoints[i].extra_fuel_burn.value; X } X X if (auto_nav1) X track_nav1 (); X X /* X * VOR cross fixes: X */ X { X int vor; X for (i = 0; i < num_waypoints; i++) { X for (vor = 0; vor < MAX_NUM_VOR_FIXES; vor++) { X if (waypoints[i].vor_fix[vor].valid) { X if (! do_fix (waypoints[i].mh.value, waypoints[i].db->latitude, X waypoints[i].db->longitude, X &waypoints[i].vor_fix[vor], FALSE) ) { X /* X * if we failed to compute an xfix, it could be because we're X * right on top of the navaid - pretend we're at the next X * waypoint (since that's where we're going...) X */ X if ((i+1) < num_waypoints) { X if (!do_fix (waypoints[i].mh.value, X waypoints[i+1].db->latitude, X waypoints[i+1].db->longitude, X &waypoints[i].vor_fix[vor], TRUE)) X waypoints[i].vor_fix[vor].valid = FALSE; X } else X waypoints[i].vor_fix[vor].valid = FALSE; X } X } X } X } X } X return TRUE; X} X X SHAR_EOF chmod 0444 compute.c || echo "restore of compute.c fails" exit 0