diff options
Diffstat (limited to 'GcodeProcessorLib/utilities.cpp')
-rw-r--r-- | GcodeProcessorLib/utilities.cpp | 459 |
1 files changed, 436 insertions, 23 deletions
diff --git a/GcodeProcessorLib/utilities.cpp b/GcodeProcessorLib/utilities.cpp index dbe23fb..74fef46 100644 --- a/GcodeProcessorLib/utilities.cpp +++ b/GcodeProcessorLib/utilities.cpp @@ -19,20 +19,113 @@ // You can contact the author at the following email address: // FormerLurker@pm.me //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + #include "utilities.h" -#include <cmath> -#include <sstream> -#include <iostream> -#include <iomanip> -#include "fpconv.h" -const std::string utilities::WHITESPACE_ = " \n\r\t\f\v"; -const char utilities::GUID_RANGE[] = "0123456789abcdef"; -const bool utilities::GUID_DASHES[] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 }; +namespace utilities { + // Box Drawing Consts + // String Consts + // Note: these ascii replacement characters must NOT appear in the text unless they will be replaced with box characters. + const char box_drawing::table_elements_replacement[8] = {char(128),char(129),char(130),char(131),char(132),char(133),char(134),char(135) }; + //enum BoxElementEnum { HORIZONTAL = 0, VERTICAL = 1, UPPER_LEFT = 2, UPPER_RIGHT = 3, MIDDLE_LEFT = 4, MIDDLE_RIGHT = 5, LOWER_LEFT = 6, LOWER_RIGHT = 7 }; + const std::string box_drawing::table_elements_ascii[8] = {"-","|","+" ,"+" ,"+" ,"+" ,"+" ,"+" }; + const std::string box_drawing::table_elements_utf8[8] = { "\u2500","\u2502","\u250C" ,"\u2510" ,"\u251C" ,"\u2524" ,"\u2514" ,"\u2518" }; + const std::string box_drawing::table_elements_html[8] = { "─","│", "┌","┐","├","┤","└","┘" }; + + box_drawing::box_drawing() + { + set_box_type(BoxEncodingEnum::ASCII); + + width_ = 100; + } + box_drawing::box_drawing(BoxEncodingEnum encoding, int width) + { + set_box_type(encoding); + width_ = width; + } + + void box_drawing::set_box_type(BoxEncodingEnum encoding) + { + box_encoding_ = encoding; + for (int index = 0; index < 8; index++) + { + switch (box_encoding_) + { + case BoxEncodingEnum::ASCII: + table_elements_[index] = table_elements_ascii[index]; + break; + case BoxEncodingEnum::UTF8: + table_elements_[index] = table_elements_utf8[index]; + break; + case BoxEncodingEnum::HTML: + table_elements_[index] = table_elements_html[index]; + break; + default: + table_elements_[index] = table_elements_ascii[index]; + } + + } + } + + void box_drawing::top(std::stringstream& stream) + { + stream << get_box_replacement_element(BoxElementEnum::UPPER_LEFT) << std::setw(width_) << std::setfill(get_box_replacement_element(BoxElementEnum::HORIZONTAL)) << "" << get_box_replacement_element(BoxElementEnum::UPPER_RIGHT) << "\n" << std::setfill(' '); + } + + void box_drawing::row(std::stringstream& stream, std::string line) + { + stream << get_box_replacement_element(BoxElementEnum::VERTICAL) << line << get_box_replacement_element(BoxElementEnum::VERTICAL) << "\n" << std::setfill(' '); + } + + void box_drawing::middle(std::stringstream& stream) + { + stream << get_box_replacement_element(BoxElementEnum::MIDDLE_LEFT) << std::setw(width_) << std::setfill(get_box_replacement_element(BoxElementEnum::HORIZONTAL)) << "" << get_box_replacement_element(BoxElementEnum::MIDDLE_RIGHT) << "\n" << std::setfill(' '); + } + void box_drawing::bottom(std::stringstream& stream) + { + stream << get_box_replacement_element(BoxElementEnum::LOWER_LEFT) << std::setw(width_) << std::setfill(get_box_replacement_element(BoxElementEnum::HORIZONTAL)) << "" << get_box_replacement_element(BoxElementEnum::LOWER_RIGHT) << "\n" << std::setfill(' '); + } + + char box_drawing::get_box_replacement_element(BoxElementEnum element) + { + return table_elements_replacement[(int)element]; + } + + void box_drawing::make_replacements(std::string &box) + { + for (int index = 0; index < 8; index++) + { + char c = table_elements_replacement[index]; + std::string search; + search += c; + box = utilities::replace(box, search, table_elements_[index]); + } + + } + + + + + const std::string WHITESPACE_ = " \n\r\t\f\v"; + const char GUID_RANGE[] = "0123456789abcdef"; + const bool GUID_DASHES[] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 }; + + extern const char PATH_SEPARATOR_ = +#ifdef _WIN32 + '\\'; +#else + '/'; +#endif + +} bool utilities::is_zero(double x, double tolerance) { - return std::fabs(x) < tolerance; + return utilities::abs(x) < tolerance; +} +bool utilities::is_zero(double x) +{ + return utilities::abs(x) < ZERO_TOLERANCE; } int utilities::round_up_to_int(double x, double tolerance) @@ -40,32 +133,63 @@ int utilities::round_up_to_int(double x, double tolerance) return int(x + tolerance); } +int utilities::round_up_to_int(double x) +{ + return int(x + ZERO_TOLERANCE); +} + bool utilities::is_equal(double x, double y, double tolerance) { - double abs_difference = std::fabs(x - y); + double abs_difference = utilities::abs(x - y); return abs_difference < tolerance; } +bool utilities::is_equal(double x, double y) +{ + double abs_difference = utilities::abs(x - y); + return abs_difference < ZERO_TOLERANCE; +} + bool utilities::greater_than(double x, double y, double tolerance) { return x > y && !is_equal(x, y, tolerance); } +bool utilities::greater_than(double x, double y) +{ + return x > y && !is_equal(x, y); +} + bool utilities::greater_than_or_equal(double x, double y, double tolerance) { return x > y || is_equal(x, y, tolerance); } +bool utilities::greater_than_or_equal(double x, double y) +{ + return x > y || is_equal(x, y); +} + bool utilities::less_than(double x, double y, double tolerance) { return x < y && !is_equal(x, y, tolerance); } +bool utilities::less_than(double x, double y) +{ + return x < y && !is_equal(x, y); +} + bool utilities::less_than_or_equal(double x, double y, double tolerance) { return x < y || is_equal(x, y, tolerance); } +bool utilities::less_than_or_equal(double x, double y) +{ + return x < y || is_equal(x, y); +} + double utilities::get_cartesian_distance(double x1, double y1, double x2, double y2) { @@ -73,7 +197,7 @@ double utilities::get_cartesian_distance(double x1, double y1, double x2, double double xdif = x1 - x2; double ydif = y1 - y2; double dist_squared = xdif * xdif + ydif * ydif; - return std::sqrt(dist_squared); + return utilities::sqrt(dist_squared); } double utilities::get_cartesian_distance(double x1, double y1, double z1, double x2, double y2, double z2) @@ -83,7 +207,31 @@ double utilities::get_cartesian_distance(double x1, double y1, double z1, double double ydif = y1 - y2; double zdif = z1 - z2; double dist_squared = xdif * xdif + ydif * ydif + zdif * zdif; - return std::sqrt(dist_squared); + return utilities::sqrt(dist_squared); +} + +double utilities::get_arc_distance(double x1, double y1, double z1, double x2, double y2, double z2, double i, double j, double r, bool is_clockwise) +{ + double center_x = x1 - i; + double center_y = y1 - j; + double radius = utilities::hypot(i, j); + double z_dist = z2 - z1; + double rt_x = x2 - center_x; + double rt_y = y2 - center_y; + double angular_travel_total = utilities::atan2(i * rt_y - j * rt_x, i * rt_x + j * rt_y); + if (angular_travel_total < 0) { angular_travel_total += 2.0 * PI_DOUBLE; } + // Adjust the angular travel if the direction is clockwise + if (is_clockwise) { angular_travel_total -= 2.0 * PI_DOUBLE; } + // Full circle fix. + if (x1 == x2 && y1 == y2 && angular_travel_total == 0) + { + angular_travel_total += 2.0 * PI_DOUBLE; + } + + // 20200417 - FormerLurker - rename millimeters_of_travel to millimeters_of_travel_arc to better describe what we are + // calculating here + return utilities::hypot(angular_travel_total * radius, utilities::abs(z_dist)); + } std::string utilities::to_string(double value) @@ -117,6 +265,33 @@ std::string utilities::trim(const std::string& s) return rtrim(ltrim(s)); } +std::string utilities::join(const std::string* strings, size_t length, std::string sep) +{ + std::string output; + for (int i = 0; i < length; i++) + { + if (i > 0) + { + output += sep; + } + output += strings[i]; + } + return output; +} + +std::string utilities::join(const std::vector<std::string> strings, std::string sep) +{ + std::string output; + + for (std::vector<std::string>::const_iterator p = strings.begin(); + p != strings.end(); ++p) { + output += *p; + if (p != strings.end() - 1) + output += sep; + } + return output; +} + std::istream& utilities::safe_get_line(std::istream& is, std::string& t) { t.clear(); @@ -149,7 +324,7 @@ std::istream& utilities::safe_get_line(std::istream& is, std::string& t) } } -std::string utilities::center(std::string input, int width) +std::string utilities::center(std::string input, int width) { int input_width = (int)input.length(); int difference = width - input_width; @@ -157,7 +332,7 @@ std::string utilities::center(std::string input, int width) { return input; } - int left_padding = difference /2; + int left_padding = difference / 2; int right_padding = width - left_padding - input_width; return std::string(left_padding, ' ') + input + std::string(right_padding, ' '); } @@ -171,6 +346,15 @@ double utilities::get_percent_change(int v1, int v2) return 0; } +double utilities::get_percent_change(double v1, double v2) +{ + if (v1 != 0) + { + return ((v2 - v1) / v1); + } + return 0; +} + std::string utilities::get_percent_change_string(int v1, int v2, int precision) { std::stringstream format_stream; @@ -197,7 +381,7 @@ std::string utilities::get_percent_change_string(int v1, int v2, int precision) int utilities::get_num_digits(int x) { - x = abs(x); + x = utilities::abs(x); return (x < 10 ? 1 : (x < 100 ? 2 : (x < 1000 ? 3 : @@ -207,12 +391,20 @@ int utilities::get_num_digits(int x) (x < 10000000 ? 7 : (x < 100000000 ? 8 : (x < 1000000000 ? 9 : - 10))))))))); + (x < 10000000000 ? 10 : -1)))))))))); +} + +int utilities::get_num_digits(double x, int precision) +{ + return get_num_digits( + (int)utilities::ceil(x * utilities::pow(10, precision) - .4999999999999) + / utilities::pow(10, precision) + ); } int utilities::get_num_digits(double x) { - return get_num_digits((int) x); + return get_num_digits((int)x); } // Nice utility function found here: https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path @@ -243,7 +435,7 @@ std::vector<std::string> utilities::splitpath(const std::string& str) return result; } -bool utilities::get_file_path(const std::string& file_path, std::string & path) +bool utilities::get_file_path(const std::string& file_path, std::string& path) { std::vector<std::string> file_parts = splitpath(file_path); if (file_parts.size() == 0) @@ -269,12 +461,12 @@ std::string utilities::create_uuid() { bool utilities::get_temp_file_path_for_file(const std::string& file_path, std::string& temp_file_path) { temp_file_path = ""; - if (!utilities::get_file_path(file_path, temp_file_path)) + if (!get_file_path(file_path, temp_file_path)) { return false; } temp_file_path = temp_file_path; - temp_file_path += utilities::create_uuid(); + temp_file_path += create_uuid(); temp_file_path += ".tmp"; return true; } @@ -289,7 +481,185 @@ double utilities::hypot(double x, double y) } if (y == 0.0) return x; y /= x; - return x * std::sqrt(1.0 + y * y); + return x * utilities::sqrt(1.0 + y * y); +} + +float utilities::hypotf(float x, float y) +{ + if (x < 0.0f) x = -x; + if (y < 0.0f) y = -y; + if (x < y) { + float tmp = x; + x = y; y = tmp; + } + if (y == 0.0f) return x; + y /= x; + return x * utilities::sqrtf(1.0f + y * y); +} + +double utilities::atan2(double y, double x) +{ + return std::atan2(y, x); +} + +float utilities::atan2f(float y, float x) +{ + return std::atan2(y, x); +} + +double utilities::floor(double x) +{ + return std::floor(x); +} + +float utilities::floorf(float x) +{ + return std::floor(x); +} + +double utilities::ceil(double x) +{ + return std::ceil(x); +} + +float utilities::ceilf(float x) +{ + return std::ceil(x); +} + +double utilities::cos(double x) +{ + return std::cos(x); +} + +float utilities::cosf(float x) +{ + return std::cos(x); +} + +double utilities::sin(double x) +{ + return std::sin(x); +} + +float utilities::sinf(float x) +{ + return std::sin(x); +} + +double utilities::abs(double x) +{ + return std::abs(x); +} + +int utilities::abs(int x) +{ + return std::abs(x); +} + +float utilities::absf(float x) +{ + return std::abs(x); +} + +double utilities::fabs(double x) +{ + return std::fabs(x); +} + +float utilities::fabsf(float x) +{ + return std::fabs(x); +} + +double utilities::sqrt(double x) +{ + return std::sqrt(x); +} + +float utilities::sqrtf(float x) +{ + return std::sqrt(x); +} + +double utilities::pow(int e, double x) +{ + return std::pow(e, x); +} + +double utilities::min(double x, double y) +{ + return std::min(x, y); +} + +float utilities::minf(float x, float y) +{ + return std::min(x, y); +} + +double utilities::max(double x, double y) +{ + return std::max(x, y); +} + +float utilities::maxf(float x, float y) +{ + return std::max(x, y); +} + +double utilities::radians(double x) +{ + return (x * PI_DOUBLE) / 180.0; +} + +float utilities::radiansf(float x) +{ + return (x * PI_FLOAT) / 180.0f; +} + +double utilities::sq(double x) +{ + return x * x; +} + +float utilities::sqf(float x) +{ + return x * x; +} + +bool utilities::within(double value, double min, double max) +{ + return ((value) >= (min) && (value) <= (max)); +} + +bool utilities::withinf(float value, float min, float max) +{ + return ((value) >= (min) && (value) <= (max)); +} + +double utilities::constrain(double value, double arg_min, double arg_max) +{ + return ((value) < (arg_min) ? (arg_min) : ((value) > (arg_max) ? (arg_max) : (value))); +} + +float utilities::constrainf(float value, float arg_min, float arg_max) +{ + return ((value) < (arg_min) ? (arg_min) : ((value) > (arg_max) ? (arg_max) : (value))); +} + +double utilities::reciprocal(double x) +{ + return 1.0 / x; +} + +float utilities::reciprocalf(float x) +{ + return 1.0f / x; +} + +void* utilities::memcpy(void* dest, const void* src, size_t n) +{ + return std::memcpy(dest, src, n); } std::string utilities::dtos(double x, unsigned char precision) @@ -297,18 +667,61 @@ std::string utilities::dtos(double x, unsigned char precision) static char buffer[FPCONV_BUFFER_LENGTH]; char* p = buffer; buffer[fpconv_dtos(x, buffer, precision)] = '\0'; - /* This is code that can be used to compare the output of the + /* This is code that can be used to compare the output of the modified fpconv_dtos function to the ofstream output Note: It currently only fails for some checks where the original double does not store perfectly. In this case I actually think the dtos output is better than ostringstream! std::ostringstream stream; stream << std::fixed; stream << std::setprecision(precision) << x; - + if (std::string(buffer) != stream.str()) { std::cout << std::fixed << "Failed to convert: " << std::setprecision(24) << x << " Precision:" << std::setprecision(0) << static_cast <int> (precision) << " String:" << std::string(buffer) << " Stream:" << stream.str() << std::endl; } */ return buffer; +} +/* +bool case_insensitive_compare_char(char& c1, char& c2) +{ + if (c1 == c2) + return true; + else if (std::toupper(c1) == std::toupper(c2)) + return true; + return false; +} + +/* + * Case Insensitive String Comparision + +bool case_insensitive_compare(std::string& str1, std::string& str2) +{ + return ((str1.size() == str2.size()) && std::equal(str1.begin(), str1.end(), str2.begin(), &case_insensitive_compare_char)); +} + +*/ + +std::string utilities::replace(std::string subject, const std::string& search, const std::string& replace) { + size_t pos = 0; + while ((pos = subject.find(search, pos)) != std::string::npos) { + subject.replace(pos, search.length(), replace); + pos += replace.length(); + } + return subject; +} + +double utilities::rand_range(double min, double max) { + double f = (double)std::rand() / RAND_MAX; + return min + f * (max - min); +} + +unsigned char utilities::rand_range(unsigned char min, unsigned char max) { + double f = (double)std::rand() / RAND_MAX; + return static_cast<unsigned char>(static_cast<double>(min) + f * (static_cast<double>(max) - static_cast<double>(min))); +} + +int utilities::rand_range(int min, int max) { + double f = (double)std::rand() / RAND_MAX; + return static_cast<int>(static_cast<double>(min) + f * (static_cast<double>(max) - static_cast<double>(min))); }
\ No newline at end of file |