/******************************************************************************* position.c - Created by Peter Mauger 30/07/01 Last Modified 12/10/01 position contains all functions required to manipulate the p_pos structure. It should be noted that all latitudes and longitudes are stored in the form dddmm.mmmmmm - where d represents the degrees values of the number and m represents the minutes values of the number A function (Convert_GPS2deg) has been provided to convert these values into degrees only (ie to ddd.ddddddddd). *******************************************************************************/ #include "position.h" /* Init_Pos initialises the internal variables of the position struct * returns: initialised position */ position Init_Pos() { position pos; pos.latitude = 0; pos.longitude = 0; return pos; } /* Get_Latitude retrieves the latitudinal component of the position * inputs: pos->position (contains latitude info) * returns: latitude as double (+ve -> North, -ve -> South) */ double Get_Latitude(position pos) { return pos.latitude; } /* Set_Latitude sets the latitudinal component of the position * inputs: pos->position (contains latitude info) * latitude->the latitude to be stored (double) * (+ve -> North, -ve -> South) */ void Set_Latitude(position *pos, double latitude) { pos->latitude = latitude; } /* Get_Longitude retrieves the longtitudinal component of the position * inputs: pos->position (contains longitude info) * returns: longitude as double (+ve -> East, -ve -> West) */ double Get_Longitude(position pos) { return pos.longitude; } /* Set_Longitude sets the longitudinal component of the position * inputs: pos->position (contains longitude info) * longitude->the longitude to be stored (double) * (+ve -> East, -ve -> West) */ void Set_Longitude(position *pos, double longitude) { pos->longitude = longitude; } /* Calc_Distance calculates the distance in metres between two navigational points * (lat, long) * inputs: p1->first point * p2->second point * returns: distance in metres {but not quite! There is some error here...}) */ double Calc_Distance(position p1, position p2, double *dist) { double lat1 = Convert_deg2rad(Convert_GPS2deg(Get_Latitude(p1))); /* at the first point (degrees) */ double lat2 = Convert_deg2rad(Convert_GPS2deg(Get_Latitude(p2))); /* at the second point (degrees) */ double long1 = Convert_deg2rad(Convert_GPS2deg(Get_Longitude(p1))); /* at the first point (degrees) */ double long2 = Convert_deg2rad(Convert_GPS2deg(Get_Longitude(p2))); /* at the second point (degrees) */ double d_long = long2 - long1; /* longitude of the second point minus longitude of the first point (degrees) */ double d_lat = lat2 - lat1; /* latitude of the second point minus latitude of the first point (degrees) */ *dist = sqrt( (d_long*d_long) + (d_lat*d_lat) ) * EARTH_RADIUS; /* Works out the distance in radians then converts to metres */ LCDSetPrintf(2,0,"D:%f ",*dist); /* by multiplying by the radius of the earth (can be modified */ return NOERROR; /* for local deviation in radius) */ } /* Calc_Bearing calculates the bearing required to reach the waypoint from * the GPS position (Adaptation of Russell Rodgers function CEarth::direction) * inputs: plane->plane information (contains current position and waypoint) * returns: Bearing in degrees from GPSpos to WPpos */ double Calc_Bearing(planestate plane) { /* this method uses a spheroidal model for the earth*/ position curr_pos_plane = Get_Curr_Pos(plane); position wp_pos = Get_Curr_Wp(plane); double lat1 = Convert_deg2rad(Convert_GPS2deg(Get_Latitude(curr_pos_plane))); double lat2 = Convert_deg2rad(Convert_GPS2deg(Get_Latitude(wp_pos))); double long1 = Convert_deg2rad(Convert_GPS2deg(Get_Longitude(curr_pos_plane))); double long2 = Convert_deg2rad(Convert_GPS2deg(Get_Longitude(wp_pos))); double t; /* This calculation was taken from Russel Rodgers CEarth::direction. I do not understand it however it seems to work... */ t = atan2(sin(long2-long1)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(long2-long1)); if(t<0) t = t + (M_PI*2); /* atan2 returns angle from -PI to PI. Convert to 0 to 2PI */ t = Convert_rad2deg(t); /* then convert to degrees */ LCDSetPrintf(3,0,"B:%f ",t); /* print out the true north bearing */ t = t - MAGNETIC_DEVIATION; /* This takes into account local magnetic deviation (the angle the compass */ return t; /* north is, relative to true north {calculated from lat and long}) */ } /* Calc_Correction calculates the heading correction required to reach the waypoint * given the current heading * inputs: plane->plane information * br->bearing required to reach wp (degrees 0->360) * returns: Correction in degrees from curr_heading to WP_bearing (degrees (+ve->left)(-ve->right)) */ double Calc_Correction(planestate plane, double bearing_req) { double correction; correction = (bearing_req - Get_Curr_Heading(plane)); /*Determine how much heading correction to */ if(correction > 180) /*be made (-180 < correction < 180)*/ { correction = correction - 360; } if(correction < -180) { correction = correction + 360; } return correction; } /* Convert_GPS2deg takes a GPS latitude or longitude (dddmm.mmmmmm where d is a degree value and m * is a minute value) and converts it to degrees only (ddd.ddddddddd where d is a degree value) * inputs: gps_angle->the latitude/longitude value to be converted * returns: the angle in degrees value only */ double Convert_GPS2deg(double gps_angle) { double degrees; double minutes; degrees = floor(gps_angle / 100); /* isolate the degrees value */ minutes = (gps_angle - (degrees * 100)); /* isolate the minutes value */ return (degrees + (minutes/60)); /* recombine them with the minutes divided by 60 */ } /* Convert_deg2rad converts a number in degrees to a number in radians * (Function provided by Russell Rodgers) * inputs: deg->value in degrees * returns: deg as radians */ double Convert_deg2rad(double deg) { return (deg/180.0)*M_PI; } /* Convert_rad2deg converts a number in radians to a number in degrees * (Function provided by Russell Rodgers) * inputs: rad->value in radian * returns: rad as degrees */ double Convert_rad2deg(double rad) { return (rad/M_PI)*180.0; }