// Filename: bearing.cpp // Author: Joshua Boyce (aka Chazwazza) // Purpose: Program used to find the bearing between two arbitrary points (from 0 degrees, rotating clockwise) // Important: Program assumes that positive 'x' on our plane is 0 deg (+x = 0, -y = 90, -x = 180, +y = 270) // Include declarations #include #include #include #include #include #include #include #include // Definitions #define PI 3.14159265358979323846 // Using declarations using std::cin; using std::cout; using std::vector; using std::endl; using std::string; using std::istringstream; using std::setprecision; using std::fixed; using std::runtime_error; using std::range_error; using std::domain_error; // Function declarations void split_string(string& str, string& delim, vector& results); double string_to_double(const string& s); double calculate_bearing(vector& point_one, vector& point_two, unsigned int& deg_rad); int main(){ // Variables vector point_one; vector point_two; string temp_one; string temp_two; string delimiter = ","; double result = 0; unsigned int deg_rad; // Greet the user and get the points to be used cout << endl << "Welcome to Chazwazza's bearing calculator." << endl; cout << "Important: Program assumes that positive 'x' on our plane is 0 deg (+x = 0, -y = 90, -x = 180, +y = 270)" << endl; cout << "Please enter the coordinates of your first point, delimited by a comma: "; cin >> temp_one; cout << "Please enter the coordinates of your second point, delimited by a comma: "; cin >> temp_two; cout << "Would you like the answer to be displayed in degrees or radians? (0 for degrees, 1 for radians): "; cin >> deg_rad; // Split the strings and push back each coordinate into the associated vector try{ split_string(temp_one,delimiter,point_one); split_string(temp_two,delimiter,point_two); } catch (runtime_error e){ cout << e.what() << "Software will now abort."; return 1; } // Calculate the bearing between the two points try{ result = calculate_bearing(point_one,point_two,deg_rad); } catch (range_error e) { cout << e.what(); return 1; } catch (domain_error e) { cout << e.what(); return 1; } // Get and set the precision from the user and display the answer int d; cout << "Please choose how many decimal places you would like the answer to be given to: "; if (!(cin >> d)){ cout << "Invalid amount of decimal places! Software will now abort."; return 1; } cout << fixed << "The bearing between the given points is " << setprecision(d) << result << endl; return 0; } // Function used to split a string based on a delimiter and push it into a vector void split_string(string& str, string& delim, vector& results){ try{ int i; while ((i = str.find_first_of(delim)) != str.npos){ if (i > 0) results.push_back(string_to_double(str.substr(0,i))); str = str.substr(i+1); } if (str.length() > 0) results.push_back(string_to_double(str)); } catch (runtime_error e){ throw e; } } // Function used to convert a string to a double double string_to_double(const string& s){ istringstream i(s); double x; if (!(i >> x)) throw runtime_error("Conversion of \"" + s + "\" from string to double failed. "); return x; } // Function to calculate the bearing between the two points double calculate_bearing(vector& point_one, vector& point_two, unsigned int& deg_rad){ double result = 0; if (point_one.size() != 2 || point_two.size() != 2) { throw range_error("Null or invalid dimension amount, you must be using exactly two dimensions!"); } else { try { if (deg_rad == 0) { if (point_one[1] > point_two[1]){ result = acos((pow((point_one[0] - point_two[0]),2) + sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)) - pow((point_one[1] - point_two[1]),2)) / (2 * fabs(point_one[0] - point_two[0]) * sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)))) * 180 / PI; } else if (point_one[1] < point_two[1]){ result = (acos((pow((point_one[0] - point_two[0]),2) + sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)) - pow((point_one[1] - point_two[1]),2)) / (2 * fabs(point_one[0] - point_two[0]) * sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)))) * 180 / PI) + 180; } else if (point_one[1] == point_two[1]){ result = 180; } } else if (deg_rad == 1) { if (point_one[1] > point_two[1]){ result = acos((pow((point_one[0] - point_two[0]),2) + sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)) - pow((point_one[1] - point_two[1]),2)) / (2 * fabs(point_one[0] - point_two[0]) * sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)))); } else if (point_one[1] < point_two[1]){ result = acos((pow((point_one[0] - point_two[0]),2) + sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)) - pow((point_one[1] - point_two[1]),2)) / (2 * fabs(point_one[0] - point_two[0]) * sqrt(pow((point_one[1] - point_two[1]),2) + pow((point_one[0] - point_two[0]),2)))); } else if (point_one[1] == point_two[1]){ result = PI; } } else { throw range_error("Invalid selection of degrees or radians, value must be zero or one."); } } catch (domain_error e) { throw e; } } return result; }