// Copyright 2000 // College of Computer Science // Northeastern University Boston MA 02115 // This software may be used for educational purposes as long as this copyright // notice is retained at the top of all files // Should this software be modified, the words "Modified from Original" must be // included as a comment below this notice // All publication rights are retained. This software or its documentation may // not be published in any media either in whole or in part. /////////////////////////////////////////////////////////////////////////////// // Basic2D.cpp // Basic 2-dimensional types with double precision coordinates /////////////////////////////////////////////////////////////////////////////// #include "CoreTools.h" // needed for core tools compile in Win32 #include "Basic2D.h" #include "IOTools.h" // tools for safe I/O double AngleInRadians (const Point2D& P, const Point2D& Q) { // easy case if (IsZero(P) || IsZero(Q)) return 0; // compute cosine of angle between vectors // arrange to compute only one sqrt double pp = DotProduct(P, P); double qq = DotProduct(Q, Q); double pq = DotProduct(P, Q); double cosine = pq / sqrt(pp * qq); // check for round off on parallel vectors if (cosine > 1) cosine = 1; if (cosine < -1) cosine = -1; // compute angle using arc cosine function return acos( cosine ); } /////////////////////////////////////////////////////////////////////////////// // Point2D IO and string functions Point2D& Point2D::Request( // respond-or-default const string& prompt, // prompt to user const Point2D& answer // default answer ) { string stringanswer(answer.ToString()); string stringresponse; Point2D response; while (true) { RequestString(prompt, stringanswer, stringresponse); if (InputError() || stringresponse.length() == 0) return Set(answer); int start = 0; int next = 0; int error = NoError; response.FromString(stringresponse, start, next, error); if (!error) return Set(response); ErrorPrint(stringresponse, next, error); } } Point2D& Point2D::Request( // mandatory response const string& prompt // prompt to user ) { string stringresponse; Point2D response; while (true) { RequestString(prompt, stringresponse); if (InputError()) return Set(); int start = 0; int next = 0; int error = NoError; if (stringresponse.length()) { response.FromString(stringresponse, start, next, error); if (!error) return Set(response); } else error = NoDataError; ErrorPrint(stringresponse, next, error); } } bool Point2D::Reading( // respond-or-decline const string& prompt // prompt to user ) { string stringresponse; Point2D response; while (true) { RequestString(prompt, stringresponse); if (InputError() || stringresponse.length() == 0) return false; int start = 0; int next = 0; int error = NoError; response.FromString(stringresponse, start, next, error); if (!error) { Set(response); return true; }; ErrorPrint(stringresponse, next, error); } } Point2D& Point2D::FromString( const string& source, // string to read int start, // start position to read int& next, // next position to read int& error // string IO error code ) { // find size int size = source.length(); // check start if (start < 0) start = 0; if (start >= size) { next = size; error = NoDataError; return *this; } // initialize error error = NoError; // process string via const char* pointer const char* temp = source.c_str() + start; const char* stop = temp; // use the C string version of FromString FromString(temp, stop, error); // compute next index next = start + (stop - temp); return *this; } Point2D& Point2D::FromString( const char* start, // start position to read const char*& next, // next position to read int& error // string IO error code ) { int count = 0; // component number const int components = 2; // number of components double number; // temporary number variable Point2D result; // temporary result variable // prepare for initial scan SkipSpace(start); next = start; error = NoError; while (count < components) { // update component count count++; // update start to read next number start = next; // read next number number = StringToDouble(start, next, error); // check for error on read if (error) break; // if no error then assign number to proper field switch (count) { case 1: result.x = number; break; case 2: result.y = number; break; default: break; } // Remove comma separator if present if (count < components) { SkipSpace(next); if (*next == Comma) { next++; SkipSpace(next); } } } // if no error then use result to modify object // otherwise just return original object if (!error) return Set(result); else return *this; } string Point2D::ToString() const { string s; string t; Format(s, x); Format(t, y); string result = s + ", " + t; return result; } string Point2D::ToString(int width, int precision, bool fixed) const { string s; string t; Format(s, x, width, precision, fixed); Format(t, y, width, precision, fixed); string result = s + ", " + t; return result; } /////////////////////////////////////////////////////////////////////////////// // Rect2D IO and string functions Rect2D& Rect2D::Request( // respond-or-default const string& prompt, // prompt to user const Rect2D& answer // default answer ) { string stringanswer = answer.ToString(); string stringresponse; Rect2D response; while (true) { RequestString(prompt, stringanswer, stringresponse); if (InputError() || stringresponse.length() == 0) return Set(answer); int start = 0; int next = 0; int error = NoError; response.FromString(stringresponse, start, next, error); if (!error) return Set(response); ErrorPrint(stringresponse, next, error); } } Rect2D& Rect2D::Request( // mandatory response const string& prompt // prompt to user ) { string stringresponse; Rect2D response; while (true) { RequestString(prompt, stringresponse); if (InputError()) return Set(); int start = 0; int next = 0; int error = NoError; if (stringresponse.length()) { response.FromString(stringresponse, start, next, error); if (!error) return Set(response); } else error = NoDataError; ErrorPrint(stringresponse, next, error); } } bool Rect2D::Reading( // respond-or-decline const string& prompt // prompt to user ) { string stringresponse; Rect2D response; while (true) { RequestString(prompt, stringresponse); if (InputError() || stringresponse.length() == 0) return false; int start = 0; int next = 0; int error = NoError; response.FromString(stringresponse, start, next, error); if (!error) { Set(response); return true; }; ErrorPrint(stringresponse, next, error); } } Rect2D& Rect2D::FromString( const string& source, // string to read int start, // start position to read int& next, // next position to read int& error // string IO error code ) { // find size int size = source.length(); // check start if (start < 0) start = 0; if (start >= size) { next = size; error = NoDataError; return *this; } // initialize error error = NoError; // process string via const char* pointer const char* temp = source.c_str() + start; const char* stop = temp; // use the C string version of FromString FromString(temp, stop, error); // compute next index next = start + (stop - temp); return *this; } Rect2D& Rect2D::FromString( const char* start, // start position to read const char*& next, // next position to read int& error // string IO error code ) { int count = 0; // component number const int components = 4; // number of components double number; // temporary number variable Rect2D result; // temporary result variable // prepare for initial scan SkipSpace(start); next = start; error = NoError; while (count < components) { // update component count count++; // update start to read next number start = next; // read next number number = StringToDouble(start, next, error); // check for error on read if (error) break; // if no error then assign number to proper field switch (count) { case 1: result.x1 = number; break; case 2: result.y1 = number; break; case 3: result.x2 = number; break; case 4: result.y2 = number; break; default: break; } // Remove comma separator if present if (count < components) { SkipSpace(next); if (*next == Comma) { next++; SkipSpace(next); } } } // if no error then use result to modify object // otherwise just return original object if (!error) return Set(result); else return *this; } string Rect2D::ToString() const { string s1; string t1; string s2; string t2; Format(s1, x1); Format(t1, y1); Format(s2, x2); Format(t2, y2); string result = s1 + ", " + t1 + ", " + s2 + ", " + t2; return result; } string Rect2D::ToString(int width, int precision, bool fixed) const { string s1; string t1; string s2; string t2; Format(s1, x1, width, precision, fixed); Format(t1, y1, width, precision, fixed); Format(s2, x2, width, precision, fixed); Format(t2, y2, width, precision, fixed); string result = s1 + ", " + t1 + ", " + s2 + ", " + t2; return result; }