// 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. /////////////////////////////////////////////////////////////////////////////// // GeoTypes.cpp /////////////////////////////////////////////////////////////////////////////// #include "CoreTools.h" // needed for core tools compile in Win32 #include "GeoTypes.h" #include "IOTools.h" /////////////////////////////////////////////////////////////////////////////// // PointData angle function double AngleInRadians (const PointData& P, const PointData& 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 ); } // PointData IO and string functions PointData& PointData::Request( // respond-or-default const string& prompt, // prompt to user const PointData& answer // default answer ) { string stringanswer(answer.ToString()); string stringresponse; PointData 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); } } PointData& PointData::Request( // mandatory response const string& prompt // prompt to user ) { string stringresponse; PointData 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 PointData::Reading( // respond-or-decline const string& prompt // prompt to user ) { string stringresponse; PointData 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); } } PointData& PointData::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; } PointData& PointData::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 short number; // temporary number variable PointData 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 = StringToShort(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 PointData::ToString(bool wide) const { // define stream stringstream stream; // format to the stream if (wide) stream << right << setw(6) << x << ", " << setw(6) << y; else stream << x << ", " << y; // copy stream to string return stream.str(); } /////////////////////////////////////////////////////////////////////////////// // RectData IO and string functions RectData& RectData::Request( // respond-or-default const string& prompt, // prompt to user const RectData& answer // default answer ) { string stringanswer = answer.ToString(); string stringresponse; RectData 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); } } RectData& RectData::Request( // mandatory response const string& prompt // prompt to user ) { string stringresponse; RectData 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 RectData::Reading( // respond-or-decline const string& prompt // prompt to user ) { string stringresponse; RectData 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); } } RectData& RectData::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; } RectData& RectData::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 short number; // temporary number variable RectData 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 = StringToShort(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 RectData::ToString(bool wide) const { // define stream stringstream stream; // format to the stream if (wide) stream << right << setw(6) << x1 << ", " << setw(6) << y1 << ", " << setw(6) << x2 << ", " << setw(6) << y2; else stream << x1 << ", " << y1 << ", " << x2 << ", " << y2; return stream.str(); }