diff options
author | FormerLurker <hochgebe@gmail.com> | 2020-11-23 17:39:15 +0300 |
---|---|---|
committer | FormerLurker <hochgebe@gmail.com> | 2020-11-23 17:39:15 +0300 |
commit | f2b52d935ebc81a2eb12cfd7a1c4b924cfc5ea68 (patch) | |
tree | c790f2249ef02d6bdd10dc8d44f9b3bcf58a4cdb | |
parent | 3eda30c23a6a8f1679989e1862e6c9d815cdbd7e (diff) |
Implement #18 and #19. Fix some compiler warnings.
-rw-r--r-- | ArcWelder/arc_welder.cpp | 10 | ||||
-rw-r--r-- | ArcWelder/arc_welder.h | 4 | ||||
-rw-r--r-- | ArcWelder/segmented_arc.cpp | 423 | ||||
-rw-r--r-- | ArcWelder/segmented_arc.h | 10 | ||||
-rw-r--r-- | ArcWelder/segmented_shape.cpp | 827 | ||||
-rw-r--r-- | ArcWelder/segmented_shape.h | 21 | ||||
-rw-r--r-- | ArcWelderConsole/ArcWelderConsole.cpp | 39 | ||||
-rw-r--r-- | ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp | 49 | ||||
-rw-r--r-- | ArcWelderInverseProcessor/inverse_processor.cpp | 36 | ||||
-rw-r--r-- | ArcWelderInverseProcessor/inverse_processor.h | 20 | ||||
-rw-r--r-- | ArcWelderTest/ArcWelderTest.cpp | 12 | ||||
-rw-r--r-- | GcodeProcessorLib/CMakeLists.txt | 10 | ||||
-rw-r--r-- | GcodeProcessorLib/gcode_parser.cpp | 2 | ||||
-rw-r--r-- | GcodeProcessorLib/utilities.cpp | 2 | ||||
-rw-r--r-- | PyArcWelder/py_arc_welder.h | 8 | ||||
-rw-r--r-- | PyArcWelder/py_arc_welder_extension.cpp | 30 | ||||
-rw-r--r-- | PyArcWelder/py_arc_welder_extension.h | 8 |
17 files changed, 855 insertions, 656 deletions
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp index c9cd465..5fb9c82 100644 --- a/ArcWelder/arc_welder.cpp +++ b/ArcWelder/arc_welder.cpp @@ -42,6 +42,8 @@ arc_welder::arc_welder( double resolution_mm, double path_tolerance_percent, double max_radius, + int min_arc_segments, + double mm_per_arc_segment, bool g90_g91_influences_extruder, bool allow_z_axis_changes, int buffer_size, @@ -51,6 +53,8 @@ arc_welder::arc_welder( resolution_mm, path_tolerance_percent, max_radius, + min_arc_segments, + mm_per_arc_segment, allow_z_axis_changes ), segment_statistics_( @@ -183,11 +187,13 @@ arc_welder_results results; error_logging_enabled_ = p_logger_->is_log_level_enabled(logger_type_, ERROR); std::stringstream stream; - stream << std::fixed << std::setprecision(5); + stream << std::fixed << std::setprecision(2); stream << "arc_welder::process - Parameters received: source_file_path: '" << source_path_ << "', target_file_path:'" << target_path_ << "', resolution_mm:" << resolution_mm_ << "mm (+-" << current_arc_.get_resolution_mm() << "mm), path_tolerance_percent: " << current_arc_.get_path_tolerance_percent() - << ", max_radius_mm:" << current_arc_.get_max_radius() + << ", max_radius_mm:" << current_arc_.get_max_radius() + << ", min_arc_segments:" << std::setprecision(0) <<current_arc_.get_min_arc_segments() + << ", mm_per_arc_segment:" << std::setprecision(0) << current_arc_.get_mm_per_arc_segment() << ", g90_91_influences_extruder: " << (p_source_position_->get_g90_91_influences_extruder() ? "True" : "False") << ", allow_z_axis_changes: " << (allow_z_axis_changes_ ? "True" : "False"); p_logger_->log(logger_type_, INFO, stream.str()); diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h index 5577267..79b7712 100644 --- a/ArcWelder/arc_welder.h +++ b/ArcWelder/arc_welder.h @@ -158,7 +158,7 @@ struct source_target_segment_statistics { int percent = 0; if (source_count > 0) { - percent = (((double)target_count - (double)source_count) / (double)source_count) * 100.0; + percent = (int)((((double)target_count - (double)source_count) / (double)source_count) * 100.0); if (percent > max_percent) { max_percent = percent; @@ -419,6 +419,8 @@ public: double resolution_mm, double path_tolerance_percent, double max_radius, + int min_arc_segments, + double mm_per_arc_segment, bool g90_g91_influences_extruder = DEFAULT_G90_G91_INFLUENCES_EXTRUDER, bool allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES, int buffer_size = DEFAULT_GCODE_BUFFER_SIZE, diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp index de12932..8ee8adb 100644 --- a/ArcWelder/segmented_arc.cpp +++ b/ArcWelder/segmented_arc.cpp @@ -33,22 +33,37 @@ segmented_arc::segmented_arc() : segmented_shape(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM, ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT) { - max_radius_mm_ = DEFAULT_MAX_RADIUS_MM; - allow_z_axis_changes_ = DEFAULT_ALLOW_Z_AXIS_CHANGES; + max_radius_mm_ = DEFAULT_MAX_RADIUS_MM; + min_arc_segments_ = DEFAULT_MIN_ARC_SEGMENTS, + allow_z_axis_changes_ = DEFAULT_ALLOW_Z_AXIS_CHANGES; } segmented_arc::segmented_arc( - int min_segments, - int max_segments, - double resolution_mm, - double path_tolerance_percent, - double max_radius_mm, - bool allow_z_axis_changes - ) : segmented_shape(min_segments, max_segments, resolution_mm, path_tolerance_percent) + int min_segments, + int max_segments, + double resolution_mm, + double path_tolerance_percent, + double max_radius_mm, + int min_arc_segments, + double mm_per_arc_segment, + bool allow_z_axis_changes +) : segmented_shape(min_segments, max_segments, resolution_mm, path_tolerance_percent) { - if (max_radius_mm > DEFAULT_MAX_RADIUS_MM) max_radius_mm_ = DEFAULT_MAX_RADIUS_MM; - else max_radius_mm_ = max_radius_mm; - allow_z_axis_changes_ = allow_z_axis_changes; + max_radius_mm_ = max_radius_mm; + if (max_radius_mm > DEFAULT_MAX_RADIUS_MM) { + max_radius_mm_ = DEFAULT_MAX_RADIUS_MM; + } + mm_per_arc_segment_ = mm_per_arc_segment; + if (mm_per_arc_segment_ < 0 || utilities::is_zero(mm_per_arc_segment_)) + { + mm_per_arc_segment = 0; + } + min_arc_segments_ = min_arc_segments; + if (min_arc_segments_ < 0) + { + min_arc_segments_ = 0; + } + allow_z_axis_changes_ = allow_z_axis_changes; } segmented_arc::~segmented_arc() @@ -57,226 +72,234 @@ segmented_arc::~segmented_arc() point segmented_arc::pop_front(double e_relative) { - e_relative_ -= e_relative; - if (points_.count() == get_min_segments()) - { - set_is_shape(false); - } - return points_.pop_front(); + e_relative_ -= e_relative; + if (points_.count() == get_min_segments()) + { + set_is_shape(false); + } + return points_.pop_front(); } point segmented_arc::pop_back(double e_relative) { - e_relative_ -= e_relative; - return points_.pop_back(); - if (points_.count() == get_min_segments()) - { - set_is_shape(false); - } + e_relative_ -= e_relative; + return points_.pop_back(); + if (points_.count() == get_min_segments()) + { + set_is_shape(false); + } } double segmented_arc::get_max_radius() const { - return max_radius_mm_; + return max_radius_mm_; } +int segmented_arc::get_min_arc_segments() const +{ + return min_arc_segments_; +} +double segmented_arc::get_mm_per_arc_segment() const +{ + return mm_per_arc_segment_; +} bool segmented_arc::is_shape() const { - return is_shape_; + return is_shape_; } bool segmented_arc::try_add_point(point p, double e_relative) { - - bool point_added = false; - // if we don't have enough segnemts to check the shape, just add - if (points_.count() > get_max_segments() - 1) - { - // Too many points, we can't add more - return false; - } - double distance = 0; - if (points_.count() > 0) - { - point p1 = points_[points_.count() - 1]; - if (allow_z_axis_changes_){ - // If we can draw arcs in 3 space, add in the distance of the z axis changes - distance = utilities::get_cartesian_distance(p1.x, p1.y, p1.z, p.x, p.y, p.z); - } - else { - distance = utilities::get_cartesian_distance(p1.x, p1.y, p.x, p.y); - if (!utilities::is_equal(p1.z, p.z)) - { - // Z axis changes aren't allowed - return false; - } - } - - if (utilities::is_zero(distance)) - { - // there must be some distance between the points - // to make an arc. - return false; - } - - } - - if (points_.count() < get_min_segments() - 1) - { - point_added = true; - points_.push_back(p); - original_shape_length_ += distance; - if (points_.count() == get_min_segments()) - { - if (!arc::try_create_arc(points_, current_arc_, original_shape_length_, max_radius_mm_, resolution_mm_, path_tolerance_percent_)) - { - point_added = false; - points_.pop_back(); - original_shape_length_ -= distance; - } - } - } - else - { - // if we're here, we need to see if the new point can be included in the shape - point_added = try_add_point_internal_(p, distance); - } - if (point_added) - { - - if (points_.count() > 1) - { - // Only add the relative distance to the second point on up. - e_relative_ += e_relative; - } - //std::cout << " success - " << points_.count() << " points.\n"; - } - else if (points_.count() < get_min_segments() && points_.count() > 1) - { - // If we haven't added a point, and we have exactly min_segments_, - // pull off the initial arc point and try again - - point old_initial_point = points_.pop_front(); - // We have to remove the distance and e relative value - // accumulated between the old arc start point and the new - point new_initial_point = points_[0]; - if (allow_z_axis_changes_) { - original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, old_initial_point.z, new_initial_point.x, new_initial_point.y, new_initial_point.z); - } - else { - original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, new_initial_point.x, new_initial_point.y); - } - - e_relative_ -= new_initial_point.e_relative; - //std::cout << " failed - removing start point and retrying current point.\n"; - return try_add_point(p, e_relative); - } - - return point_added; + + bool point_added = false; + // if we don't have enough segnemts to check the shape, just add + if (points_.count() > get_max_segments() - 1) + { + // Too many points, we can't add more + return false; + } + double distance = 0; + if (points_.count() > 0) + { + point p1 = points_[points_.count() - 1]; + if (allow_z_axis_changes_) { + // If we can draw arcs in 3 space, add in the distance of the z axis changes + distance = utilities::get_cartesian_distance(p1.x, p1.y, p1.z, p.x, p.y, p.z); + } + else { + distance = utilities::get_cartesian_distance(p1.x, p1.y, p.x, p.y); + if (!utilities::is_equal(p1.z, p.z)) + { + // Z axis changes aren't allowed + return false; + } + } + + if (utilities::is_zero(distance)) + { + // there must be some distance between the points + // to make an arc. + return false; + } + + } + + if (points_.count() < get_min_segments() - 1) + { + point_added = true; + points_.push_back(p); + original_shape_length_ += distance; + if (points_.count() == get_min_segments()) + { + if (!arc::try_create_arc(points_, current_arc_, original_shape_length_, max_radius_mm_, resolution_mm_, path_tolerance_percent_, min_arc_segments_, mm_per_arc_segment_, xyz_precision_, allow_z_axis_changes_)) + { + point_added = false; + points_.pop_back(); + original_shape_length_ -= distance; + } + } + } + else + { + // if we're here, we need to see if the new point can be included in the shape + point_added = try_add_point_internal_(p, distance); + } + if (point_added) + { + + if (points_.count() > 1) + { + // Only add the relative distance to the second point on up. + e_relative_ += e_relative; + } + //std::cout << " success - " << points_.count() << " points.\n"; + } + else if (points_.count() < get_min_segments() && points_.count() > 1) + { + // If we haven't added a point, and we have exactly min_segments_, + // pull off the initial arc point and try again + + point old_initial_point = points_.pop_front(); + // We have to remove the distance and e relative value + // accumulated between the old arc start point and the new + point new_initial_point = points_[0]; + if (allow_z_axis_changes_) { + original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, old_initial_point.z, new_initial_point.x, new_initial_point.y, new_initial_point.z); + } + else { + original_shape_length_ -= utilities::get_cartesian_distance(old_initial_point.x, old_initial_point.y, new_initial_point.x, new_initial_point.y); + } + + e_relative_ -= new_initial_point.e_relative; + //std::cout << " failed - removing start point and retrying current point.\n"; + return try_add_point(p, e_relative); + } + + return point_added; } bool segmented_arc::try_add_point_internal_(point p, double pd) { - // If we don't have enough points (at least min_segments) return false - if (points_.count() < get_min_segments() - 1) - return false; - - // Create a test circle - circle target_circle; - - // the circle is new.. we have to test it now, which is expensive :( - points_.push_back(p); - double previous_shape_length = original_shape_length_; - original_shape_length_ += pd; - - if (arc::try_create_arc(points_, current_arc_, original_shape_length_, max_radius_mm_, resolution_mm_, path_tolerance_percent_, xyz_precision_, allow_z_axis_changes_)) - { - if (!is_shape()) - { - set_is_shape(true); - } - return true; - } - // Can't create the arc. Remove the point and remove the previous segment length. - points_.pop_back(); - original_shape_length_ = previous_shape_length; - return false; + // If we don't have enough points (at least min_segments) return false + if (points_.count() < get_min_segments() - 1) + return false; + + // Create a test circle + circle target_circle; + + // the circle is new.. we have to test it now, which is expensive :( + points_.push_back(p); + double previous_shape_length = original_shape_length_; + original_shape_length_ += pd; + + if (arc::try_create_arc(points_, current_arc_, original_shape_length_, max_radius_mm_, resolution_mm_, path_tolerance_percent_, min_arc_segments_, mm_per_arc_segment_, xyz_precision_, allow_z_axis_changes_)) + { + if (!is_shape()) + { + set_is_shape(true); + } + return true; + } + // Can't create the arc. Remove the point and remove the previous segment length. + points_.pop_back(); + original_shape_length_ = previous_shape_length; + return false; } std::string segmented_arc::get_shape_gcode_absolute(double e, double f) { - bool has_e = e_relative_ != 0; - return get_shape_gcode_(has_e, e, f); + bool has_e = e_relative_ != 0; + return get_shape_gcode_(has_e, e, f); } std::string segmented_arc::get_shape_gcode_relative(double f) { - bool has_e = e_relative_ != 0; - return get_shape_gcode_(has_e, e_relative_, f); + bool has_e = e_relative_ != 0; + return get_shape_gcode_(has_e, e_relative_, f); } std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f) const { - - char buf[20]; - std::string gcode; - - double i = current_arc_.center.x - current_arc_.start_point.x; - double j = current_arc_.center.y - current_arc_.start_point.y; - // Here is where the performance part kicks in (these are expensive calls) that makes things a bit ugly. - // there are a few cases we need to take into consideration before choosing our sprintf string - // create the XYZ portion - - if (current_arc_.angle_radians < 0) - { - gcode = "G2"; - } - else - { - gcode = "G3"; - - } - // Add X, Y, I and J - gcode += " X"; - gcode += utilities::to_string(current_arc_.end_point.x, xyz_precision_, buf, false); - - gcode += " Y"; - gcode += utilities::to_string(current_arc_.end_point.y, xyz_precision_, buf, false); - - if (allow_z_axis_changes_) - { - // We may need to add a z coordinate - double z_initial = current_arc_.start_point.z; - double z_final = current_arc_.end_point.z; - if (!utilities::is_equal(z_initial, z_final, std::pow(10.0, -1.0 * xyz_precision_))) - { - // The z axis has changed within the precision of the gcode coordinates - gcode += " Z"; - gcode += utilities::to_string(current_arc_.end_point.z, xyz_precision_, buf, false); - } - } - - gcode += " I"; - gcode += utilities::to_string(i, xyz_precision_, buf, false); - - gcode += " J"; - gcode += utilities::to_string(j, xyz_precision_, buf, false); - - // Add E if it appears - if (has_e) - { - gcode += " E"; - gcode += utilities::to_string(e, e_precision_, buf, false); - } - - // Add F if it appears - if (utilities::greater_than_or_equal(f, 1)) - { - gcode += " F"; - gcode += utilities::to_string(f, 0, buf, true); - } - - return gcode; + char buf[100]; + std::string gcode; + + + double i = current_arc_.center.x - current_arc_.start_point.x; + double j = current_arc_.center.y - current_arc_.start_point.y; + // Here is where the performance part kicks in (these are expensive calls) that makes things a bit ugly. + // there are a few cases we need to take into consideration before choosing our sprintf string + // create the XYZ portion + + if (current_arc_.angle_radians < 0) + { + gcode = "G2"; + } + else + { + gcode = "G3"; + + } + // Add X, Y, I and J + gcode += " X"; + gcode += utilities::to_string(current_arc_.end_point.x, xyz_precision_, buf, false); + + gcode += " Y"; + gcode += utilities::to_string(current_arc_.end_point.y, xyz_precision_, buf, false); + + if (allow_z_axis_changes_) + { + // We may need to add a z coordinate + double z_initial = current_arc_.start_point.z; + double z_final = current_arc_.end_point.z; + if (!utilities::is_equal(z_initial, z_final, std::pow(10.0, -1.0 * xyz_precision_))) + { + // The z axis has changed within the precision of the gcode coordinates + gcode += " Z"; + gcode += utilities::to_string(current_arc_.end_point.z, xyz_precision_, buf, false); + } + } + + gcode += " I"; + gcode += utilities::to_string(i, xyz_precision_, buf, false); + + gcode += " J"; + gcode += utilities::to_string(j, xyz_precision_, buf, false); + + // Add E if it appears + if (has_e) + { + gcode += " E"; + gcode += utilities::to_string(e, e_precision_, buf, false); + } + + // Add F if it appears + if (utilities::greater_than_or_equal(f, 1)) + { + gcode += " F"; + gcode += utilities::to_string(f, 0, buf, true); + } + + return gcode; } diff --git a/ArcWelder/segmented_arc.h b/ArcWelder/segmented_arc.h index 9af5f25..6705e2e 100644 --- a/ArcWelder/segmented_arc.h +++ b/ArcWelder/segmented_arc.h @@ -40,7 +40,9 @@ public: int max_segments = DEFAULT_MAX_SEGMENTS, double resolution_mm = DEFAULT_RESOLUTION_MM, double path_tolerance_percnet = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT, - double max_radius_mm = DEFAULT_MAX_RADIUS_MM , + double max_radius_mm = DEFAULT_MAX_RADIUS_MM, + int min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS, + double mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT, bool allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES ); virtual ~segmented_arc(); @@ -52,13 +54,19 @@ public: point pop_front(double e_relative); point pop_back(double e_relative); double get_max_radius() const; + int get_min_arc_segments() const; + double get_mm_per_arc_segment() const; private: bool try_add_point_internal_(point p, double pd); std::string get_shape_gcode_(bool has_e, double e, double f) const; + std::string get_g1(double x, double y, double z, double e, double f, bool has_z); + std::string interpolate_arc(double f, bool is_relative, double start_e = 0); //circle arc_circle_; arc current_arc_; double max_radius_mm_; + int min_arc_segments_; + double mm_per_arc_segment_; bool allow_z_axis_changes_; }; diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp index 76bcca1..7a7f8c2 100644 --- a/ArcWelder/segmented_shape.cpp +++ b/ArcWelder/segmented_shape.cpp @@ -30,82 +30,82 @@ #include <iostream> #pragma region Operators for Vector and Point point operator +(point lhs, const vector rhs) { - point p( - lhs.x + rhs.x, - lhs.y + rhs.y, - lhs.z + rhs.z, - lhs.e_relative + rhs.e_relative - ); - return p; + point p( + lhs.x + rhs.x, + lhs.y + rhs.y, + lhs.z + rhs.z, + lhs.e_relative + rhs.e_relative + ); + return p; } point operator -(point lhs, const vector rhs) { - return point( - lhs.x - rhs.x, - lhs.y - rhs.y, - lhs.z - rhs.z, - lhs.e_relative - rhs.e_relative - ); + return point( + lhs.x - rhs.x, + lhs.y - rhs.y, + lhs.z - rhs.z, + lhs.e_relative - rhs.e_relative + ); } vector operator -(point& lhs, point& rhs) { - return vector( - lhs.x - rhs.x, - lhs.y - rhs.y, - lhs.z - rhs.z - ); + return vector( + lhs.x - rhs.x, + lhs.y - rhs.y, + lhs.z - rhs.z + ); } vector operator -(const point& lhs, const point& rhs) { - return vector( - lhs.x - rhs.x, - lhs.y - rhs.y, - lhs.z - rhs.z - ); + return vector( + lhs.x - rhs.x, + lhs.y - rhs.y, + lhs.z - rhs.z + ); } vector operator *(vector lhs, const double& rhs) { - return vector( - lhs.x*rhs, - lhs.y*rhs, - lhs.z*rhs - ); + return vector( + lhs.x * rhs, + lhs.y * rhs, + lhs.z * rhs + ); } #pragma endregion Operators for Vector and Point #pragma region Point Functions point point::get_midpoint(point p1, point p2) { - double x = (p1.x + p2.x) / 2.0; - double y = (p1.y + p2.y) / 2.0; - double z = (p1.z + p2.z) / 2.0; + double x = (p1.x + p2.x) / 2.0; + double y = (p1.y + p2.y) / 2.0; + double z = (p1.z + p2.z) / 2.0; - return point(x, y, z, 0); + return point(x, y, z, 0); } #pragma endregion Point Functions #pragma region Segment Functions -bool segment::get_closest_perpendicular_point(point c, point &d) +bool segment::get_closest_perpendicular_point(point c, point& d) { - return segment::get_closest_perpendicular_point(p1, p2, c, d); + return segment::get_closest_perpendicular_point(p1, p2, c, d); } -bool segment::get_closest_perpendicular_point(const point &p1, const point &p2, const point &c, point& d) +bool segment::get_closest_perpendicular_point(const point& p1, const point& p2, const point& c, point& d) { - // [(Cx - Ax)(Bx - Ax) + (Cy - Ay)(By - Ay)] / [(Bx - Ax) ^ 2 + (By - Ay) ^ 2] - double num = (c.x - p1.x)*(p2.x - p1.x) + (c.y - p1.y)*(p2.y - p1.y); - double denom = (std::pow((p2.x - p1.x), 2) + std::pow((p2.y - p1.y), 2)); - double t = num / denom; + // [(Cx - Ax)(Bx - Ax) + (Cy - Ay)(By - Ay)] / [(Bx - Ax) ^ 2 + (By - Ay) ^ 2] + double num = (c.x - p1.x) * (p2.x - p1.x) + (c.y - p1.y) * (p2.y - p1.y); + double denom = (std::pow((p2.x - p1.x), 2) + std::pow((p2.y - p1.y), 2)); + double t = num / denom; - // We're considering this a failure if t == 0 or t==1 within our tolerance. In that case we hit the endpoint, which is OK. - // Why are we using the CIRCLE_GENERATION_A_ZERO_TOLERANCE tolerance here?? - if (utilities::less_than_or_equal(t, 0) || utilities::greater_than_or_equal(t, 1)) - return false; + // We're considering this a failure if t == 0 or t==1 within our tolerance. In that case we hit the endpoint, which is OK. + // Why are we using the CIRCLE_GENERATION_A_ZERO_TOLERANCE tolerance here?? + if (utilities::less_than_or_equal(t, 0) || utilities::greater_than_or_equal(t, 1)) + return false; - d.x = p1.x + t * (p2.x - p1.x); - d.y = p1.y + t * (p2.y - p1.y); + d.x = p1.x + t * (p2.x - p1.x); + d.y = p1.y + t * (p2.y - p1.y); - return true; + return true; } #pragma endregion @@ -113,12 +113,12 @@ bool segment::get_closest_perpendicular_point(const point &p1, const point &p2, #pragma region Vector Functions double vector::get_magnitude() { - return sqrt(x * x + y * y + z * z); + return sqrt(x * x + y * y + z * z); } double vector::cross_product_magnitude(vector v1, vector v2) { - return (v1.x * v2.y - v1.y * v2.x); + return (v1.x * v2.y - v1.y * v2.x); } #pragma endregion Vector Functions @@ -138,20 +138,20 @@ double vector::cross_product_magnitude(vector v1, vector v2) double distance_from_segment(segment s, point p) { - vector v = s.p2 - s.p1; - vector w = p - s.p1; + vector v = s.p2 - s.p1; + vector w = p - s.p1; - double c1 = dot(w, v); - if (c1 <= 0) - return d(p, s.p1); + double c1 = dot(w, v); + if (c1 <= 0) + return d(p, s.p1); - double c2 = dot(v, v); - if (c2 <= c1) - return d(p, s.p2); + double c2 = dot(v, v); + if (c2 <= c1) + return d(p, s.p2); - double b = c1 / c2; - point pb = s.p1 + (v * b); - return d(p, pb); + double b = c1 / c2; + point pb = s.p1 + (v * b); + return d(p, pb); } #pragma endregion Distance Calculation Source @@ -161,474 +161,495 @@ double distance_from_segment(segment s, point p) bool circle::try_create_circle(const point& p1, const point& p2, const point& p3, const double max_radius, circle& new_circle) { - double x1 = p1.x; - double y1 = p1.y; - double x2 = p2.x; - double y2 = p2.y; - double x3 = p3.x; - double y3 = p3.y; + double x1 = p1.x; + double y1 = p1.y; + double x2 = p2.x; + double y2 = p2.y; + double x3 = p3.x; + double y3 = p3.y; - double a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2; - // Take out to figure out how we handle very small values for a - if (utilities::is_zero(a,0.000000001)) - { - return false; - } - + double a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2; + // Take out to figure out how we handle very small values for a + if (utilities::is_zero(a, 0.000000001)) + { + return false; + } - double b = (x1 * x1 + y1 * y1) * (y3 - y2) - + (x2 * x2 + y2 * y2) * (y1 - y3) - + (x3 * x3 + y3 * y3) * (y2 - y1); - double c = (x1 * x1 + y1 * y1) * (x2 - x3) - + (x2 * x2 + y2 * y2) * (x3 - x1) - + (x3 * x3 + y3 * y3) * (x1 - x2); + double b = (x1 * x1 + y1 * y1) * (y3 - y2) + + (x2 * x2 + y2 * y2) * (y1 - y3) + + (x3 * x3 + y3 * y3) * (y2 - y1); - double x = -b / (2.0 * a); - double y = -c / (2.0 * a); + double c = (x1 * x1 + y1 * y1) * (x2 - x3) + + (x2 * x2 + y2 * y2) * (x3 - x1) + + (x3 * x3 + y3 * y3) * (x1 - x2); - double radius = utilities::get_cartesian_distance(x, y, x1, y1); - if (radius > max_radius) - return false; - new_circle.center.x = x; - new_circle.center.y = y; - new_circle.center.z = p1.z; - new_circle.radius = radius; + double x = -b / (2.0 * a); + double y = -c / (2.0 * a); - return true; + double radius = utilities::get_cartesian_distance(x, y, x1, y1); + if (radius > max_radius) + return false; + new_circle.center.x = x; + new_circle.center.y = y; + new_circle.center.z = p1.z; + new_circle.radius = radius; + + return true; } bool circle::try_create_circle(const array_list<point>& points, const double max_radius, const double resolution_mm, const int xyz_precision, bool allow_z_axis_changes, bool check_middle_only, circle& new_circle) { - int middle_index = points.count() / 2; - int check_index; - int step = 0; + int middle_index = points.count() / 2; + int check_index; + int step = 0; bool is_right = true; - while (true) { - - check_index = middle_index + (is_right ? step : -1*step); - // Check the index - if (circle::try_create_circle(points[0], points[check_index], points[points.count() - 1], max_radius, new_circle)) - { - if (!new_circle.is_over_deviation(points, resolution_mm, xyz_precision, allow_z_axis_changes)) - { - return true; - } - } - if (is_right) - { - if (check_index == points.count() - 1) - { - return false; - } - if (check_index == middle_index) - { - if (check_middle_only) - { - return false; - } - step++; - continue; - } - } - else - { - if (check_index == 0) - { - return false; - } - step++; - } - is_right = !is_right; - } - return false; + while (true) { + + check_index = middle_index + (is_right ? step : -1 * step); + // Check the index + if (circle::try_create_circle(points[0], points[check_index], points[points.count() - 1], max_radius, new_circle)) + { + if (!new_circle.is_over_deviation(points, resolution_mm, xyz_precision, allow_z_axis_changes)) + { + return true; + } + } + if (is_right) + { + if (check_index == points.count() - 1) + { + return false; + } + if (check_index == middle_index) + { + if (check_middle_only) + { + return false; + } + step++; + continue; + } + } + else + { + if (check_index == 0) + { + return false; + } + step++; + } + is_right = !is_right; + } + return false; } double circle::get_radians(const point& p1, const point& p2) const { - double distance_sq = std::pow(utilities::get_cartesian_distance(p1.x, p1.y, p2.x, p2.y), 2.0); - double two_r_sq = 2.0 * radius * radius; - return acos((two_r_sq - distance_sq) / two_r_sq); + double distance_sq = std::pow(utilities::get_cartesian_distance(p1.x, p1.y, p2.x, p2.y), 2.0); + double two_r_sq = 2.0 * radius * radius; + return acos((two_r_sq - distance_sq) / two_r_sq); } double circle::get_polar_radians(const point& p1) const { - double polar_radians = atan2(p1.y - center.y, p1.x - center.x); - if (polar_radians < 0) - polar_radians = (2.0 * PI_DOUBLE) + polar_radians; - return polar_radians; + double polar_radians = atan2(p1.y - center.y, p1.x - center.x); + if (polar_radians < 0) + polar_radians = (2.0 * PI_DOUBLE) + polar_radians; + return polar_radians; } point circle::get_closest_point(const point& p) const { - vector v = p - center; - double mag = v.get_magnitude(); - double px = center.x + v.x / mag * radius; - double py = center.y + v.y / mag * radius; - double pz = center.z + v.z / mag * radius; - return point(px, py, pz, 0); + vector v = p - center; + double mag = v.get_magnitude(); + double px = center.x + v.x / mag * radius; + double py = center.y + v.y / mag * radius; + double pz = center.z + v.z / mag * radius; + return point(px, py, pz, 0); } bool circle::is_over_deviation(const array_list<point>& points, const double resolution_mm, const int xyz_precision, const bool allow_z_axis_changes) { - // We need to ensure that the Z steps are constand per linear travel unit - double z_step_per_distance = 0; - // Skip the first and last points since they will fit perfectly. - // UNLESS allow z changes is set to true, then we need to do some different stuff - int final_index = points.count() - 1 + (allow_z_axis_changes ? 1 : 0); - for (int index = 1; index < points.count() - 1; index++) - { - // Make sure the length from the center of our circle to the test point is - // at or below our max distance. - double distance = distance = utilities::get_cartesian_distance(points[index].x, points[index].y, center.x, center.y); - if (allow_z_axis_changes) { - double z1 = points[index - 1].z; - double z2 = points[index].z; - - double current_z_stepper_distance = (z2 - z1)/distance; - if (z_step_per_distance == 0){ - z_step_per_distance = current_z_stepper_distance; - } - if (!utilities::is_equal(z_step_per_distance, current_z_stepper_distance, std::pow(10.0, -1.0 * xyz_precision))) - { - // The z step is uneven, can't create arc - return true; - } - - } - - if (std::abs(distance - radius) > resolution_mm) - { - return true; - } - } - - // Check the point perpendicular from the segment to the circle's center, if any such point exists - for (int index = 0; index < points.count() - 1; index++) - { - point point_to_test; - if (segment::get_closest_perpendicular_point(points[index], points[index + 1], center, point_to_test)) - { - double distance = utilities::get_cartesian_distance(point_to_test.x, point_to_test.y, center.x, center.y); - if (std::abs(distance - radius) > resolution_mm) - { - return true; - } - } - - } - return false; + // We need to ensure that the Z steps are constand per linear travel unit + double z_step_per_distance = 0; + // Skip the first and last points since they will fit perfectly. + // UNLESS allow z changes is set to true, then we need to do some different stuff + int final_index = points.count() - 1 + (allow_z_axis_changes ? 1 : 0); + for (int index = 1; index < points.count() - 1; index++) + { + // Make sure the length from the center of our circle to the test point is + // at or below our max distance. + double distance = distance = utilities::get_cartesian_distance(points[index].x, points[index].y, center.x, center.y); + if (allow_z_axis_changes) { + double z1 = points[index - 1].z; + double z2 = points[index].z; + + double current_z_stepper_distance = (z2 - z1) / distance; + if (z_step_per_distance == 0) { + z_step_per_distance = current_z_stepper_distance; + } + if (!utilities::is_equal(z_step_per_distance, current_z_stepper_distance, std::pow(10.0, -1.0 * xyz_precision))) + { + // The z step is uneven, can't create arc + return true; + } + + } + + if (std::abs(distance - radius) > resolution_mm) + { + return true; + } + } + + // Check the point perpendicular from the segment to the circle's center, if any such point exists + for (int index = 0; index < points.count() - 1; index++) + { + point point_to_test; + if (segment::get_closest_perpendicular_point(points[index], points[index + 1], center, point_to_test)) + { + double distance = utilities::get_cartesian_distance(point_to_test.x, point_to_test.y, center.x, center.y); + if (std::abs(distance - radius) > resolution_mm) + { + return true; + } + } + + } + return false; } #pragma endregion Circle Functions #pragma region Arc Functions bool arc::try_create_arc( - const circle& c, - const point& start_point, - const point& mid_point, - const point& end_point, - arc& target_arc, - double approximate_length, - double resolution, - double path_tolerance_percent, - bool allow_z_axis_changes) -{ - double polar_start_theta = c.get_polar_radians(start_point); - double polar_mid_theta = c.get_polar_radians(mid_point); - double polar_end_theta = c.get_polar_radians(end_point); - - // variable to hold radians - double angle_radians = 0; - int direction = 0; // 1 = counter clockwise, 2 = clockwise, 3 = unknown. - // Determine the direction of the arc - if (polar_end_theta > polar_start_theta) - { - if (polar_start_theta < polar_mid_theta && polar_mid_theta < polar_end_theta) { - direction = 1; - angle_radians = polar_end_theta - polar_start_theta; - } - else if ( - (0.0 <= polar_mid_theta && polar_mid_theta < polar_start_theta) || - (polar_end_theta < polar_mid_theta && polar_mid_theta < (2.0 * PI_DOUBLE)) - ) - { - direction = 2; - angle_radians = polar_start_theta + ((2.0 * PI_DOUBLE) - polar_end_theta); - } - } - else if (polar_start_theta > polar_end_theta) - { - if ( - (polar_start_theta < polar_mid_theta && polar_mid_theta < (2.0 * PI_DOUBLE)) || - (0.0 < polar_mid_theta && polar_mid_theta < polar_end_theta) - ) - { - direction = 1; - angle_radians = polar_end_theta + ((2.0 * PI_DOUBLE) - polar_start_theta); - } - else if (polar_end_theta < polar_mid_theta && polar_mid_theta < polar_start_theta) - { - direction = 2; - angle_radians = polar_start_theta - polar_end_theta; - } - } - - // this doesn't always work.. in rare situations, the angle may be backward - if (direction == 0 || utilities::is_zero(angle_radians)) return false; - - // Let's check the length against the original length - // This can trigger simply due to the differing path lengths - // but also could indicate that our vector calculation above - // got the direction wrong - double arc_length = c.radius * angle_radians; - - if (allow_z_axis_changes) - { - // We may be traveling in 3 space, calculate the arc_length of the spiral - if (start_point.z != end_point.z) - { - arc_length = utilities::hypot(arc_length, end_point.z - start_point.z); - } - } - // Calculate the percent difference of the original path - double difference = (arc_length - approximate_length) / approximate_length; - if (!utilities::is_zero(difference, path_tolerance_percent)) - { - // So it's possible our vector calculation above got the direction wrong. - // This can happen if there is a crazy arrangement of points - // extremely close to eachother. They have to be close enough to - // break our other checks. However, we may be able to salvage this. - // see if an arc moving in the opposite direction had the correct length. - - // Find the rest of the angle across the circle - double test_radians = std::abs(angle_radians - 2 * PI_DOUBLE); - // Calculate the length of that arc - double test_arc_length = c.radius * test_radians; - if (allow_z_axis_changes) - { - // We may be traveling in 3 space, calculate the arc_length of the spiral - if (start_point.z != end_point.z) - { - test_arc_length = utilities::hypot(arc_length, end_point.z - start_point.z); - } - } - difference = (test_arc_length - approximate_length) / approximate_length; - if (!utilities::is_zero(difference, path_tolerance_percent)) - { - return false; - } - // So, let's set the new length and flip the direction (but not the angle)! - arc_length = test_arc_length; - direction = direction == 1 ? 2 : 1; - } - - if (allow_z_axis_changes) - { - // Ensure the perimeter of the arc is less than that of a full circle - double perimeter = utilities::hypot(c.radius * 2.0 * PI_DOUBLE, end_point.z - start_point.z); - if (perimeter <= approximate_length) { - return false; - } - - } - - if(direction == 2) - angle_radians *= -1.0; - - target_arc.center.x = c.center.x; - target_arc.center.y = c.center.y; - target_arc.center.z = c.center.z; - target_arc.radius = c.radius; - target_arc.start_point = start_point; - target_arc.end_point = end_point; - target_arc.length = arc_length; - target_arc.angle_radians = angle_radians; - target_arc.polar_start_theta = polar_start_theta; - target_arc.polar_end_theta = polar_end_theta; - - return true; - + const circle& c, + const point& start_point, + const point& mid_point, + const point& end_point, + arc& target_arc, + double approximate_length, + double resolution, + double path_tolerance_percent, + int min_arc_segments, + double mm_per_arc_segment, + bool allow_z_axis_changes) +{ + double polar_start_theta = c.get_polar_radians(start_point); + double polar_mid_theta = c.get_polar_radians(mid_point); + double polar_end_theta = c.get_polar_radians(end_point); + + // variable to hold radians + double angle_radians = 0; + int direction = 0; // 1 = counter clockwise, 2 = clockwise, 3 = unknown. + // Determine the direction of the arc + if (polar_end_theta > polar_start_theta) + { + if (polar_start_theta < polar_mid_theta && polar_mid_theta < polar_end_theta) { + direction = 1; + angle_radians = polar_end_theta - polar_start_theta; + } + else if ( + (0.0 <= polar_mid_theta && polar_mid_theta < polar_start_theta) || + (polar_end_theta < polar_mid_theta && polar_mid_theta < (2.0 * PI_DOUBLE)) + ) + { + direction = 2; + angle_radians = polar_start_theta + ((2.0 * PI_DOUBLE) - polar_end_theta); + } + } + else if (polar_start_theta > polar_end_theta) + { + if ( + (polar_start_theta < polar_mid_theta && polar_mid_theta < (2.0 * PI_DOUBLE)) || + (0.0 < polar_mid_theta && polar_mid_theta < polar_end_theta) + ) + { + direction = 1; + angle_radians = polar_end_theta + ((2.0 * PI_DOUBLE) - polar_start_theta); + } + else if (polar_end_theta < polar_mid_theta && polar_mid_theta < polar_start_theta) + { + direction = 2; + angle_radians = polar_start_theta - polar_end_theta; + } + } + + // this doesn't always work.. in rare situations, the angle may be backward + if (direction == 0 || utilities::is_zero(angle_radians)) return false; + + // Let's check the length against the original length + // This can trigger simply due to the differing path lengths + // but also could indicate that our vector calculation above + // got the direction wrong + double arc_length = c.radius * angle_radians; + + if (allow_z_axis_changes) + { + // We may be traveling in 3 space, calculate the arc_length of the spiral + if (start_point.z != end_point.z) + { + arc_length = utilities::hypot(arc_length, end_point.z - start_point.z); + } + } + // Calculate the percent difference of the original path + double difference = (arc_length - approximate_length) / approximate_length; + if (!utilities::is_zero(difference, path_tolerance_percent)) + { + // So it's possible our vector calculation above got the direction wrong. + // This can happen if there is a crazy arrangement of points + // extremely close to eachother. They have to be close enough to + // break our other checks. However, we may be able to salvage this. + // see if an arc moving in the opposite direction had the correct length. + + // Find the rest of the angle across the circle + double test_radians = std::abs(angle_radians - 2 * PI_DOUBLE); + // Calculate the length of that arc + double test_arc_length = c.radius * test_radians; + if (allow_z_axis_changes) + { + // We may be traveling in 3 space, calculate the arc_length of the spiral + if (start_point.z != end_point.z) + { + test_arc_length = utilities::hypot(arc_length, end_point.z - start_point.z); + } + } + difference = (test_arc_length - approximate_length) / approximate_length; + if (!utilities::is_zero(difference, path_tolerance_percent)) + { + return false; + } + // So, let's set the new length and flip the direction (but not the angle)! + arc_length = test_arc_length; + direction = direction == 1 ? 2 : 1; + } + + if (allow_z_axis_changes) + { + // Ensure the perimeter of the arc is less than that of a full circle + double perimeter = utilities::hypot(c.radius * 2.0 * PI_DOUBLE, end_point.z - start_point.z); + if (perimeter <= approximate_length) { + return false; + } + + } + + if (direction == 2) { + angle_radians *= -1.0; + } + + // See how many arcs will be interpolated + if (min_arc_segments > 0 && mm_per_arc_segment > 0) + { + double circumference = 2.0*PI_DOUBLE*c.radius; + int num_segments = (int)std::ceil(circumference/mm_per_arc_segment); + if (num_segments < min_arc_segments) { + // We might be able to salvage this. See if there would be enough segments if we use an arc of the current size + num_segments = (int)std::ceil(circumference / arc_length); + if (num_segments < min_arc_segments) { + return false; + } + } + } + + target_arc.center.x = c.center.x; + target_arc.center.y = c.center.y; + target_arc.center.z = c.center.z; + target_arc.radius = c.radius; + target_arc.start_point = start_point; + target_arc.end_point = end_point; + target_arc.length = arc_length; + target_arc.angle_radians = angle_radians; + target_arc.polar_start_theta = polar_start_theta; + target_arc.polar_end_theta = polar_end_theta; + + return true; + } bool arc::try_create_arc( - const circle& c, - const array_list<point>& points, - arc& target_arc, - double approximate_length, - double resolution, - double path_tolerance_percent, - bool allow_z_axis_changes) -{ - int mid_point_index = ((points.count() - 2) / 2) + 1; - return arc::try_create_arc(c, points[0], points[mid_point_index], points[points.count() - 1], target_arc, approximate_length, resolution, path_tolerance_percent, allow_z_axis_changes); + const circle& c, + const array_list<point>& points, + arc& target_arc, + double approximate_length, + double resolution, + double path_tolerance_percent, + int min_arc_segments, + double mm_per_arc_segment, + bool allow_z_axis_changes) +{ + int mid_point_index = ((points.count() - 2) / 2) + 1; + return arc::try_create_arc(c, points[0], points[mid_point_index], points[points.count() - 1], target_arc, approximate_length, resolution, path_tolerance_percent, min_arc_segments, mm_per_arc_segment, allow_z_axis_changes); } bool arc::try_create_arc( - const array_list<point>& points, - arc& target_arc, - double approximate_length, - double max_radius_mm, - double resolution_mm, - double path_tolerance_percent, - int xyz_precision, - bool allow_z_axis_changes) -{ - circle test_circle; - if (circle::try_create_circle(points, max_radius_mm, resolution_mm, xyz_precision, allow_z_axis_changes, false, test_circle)) - { - int mid_point_index = ((points.count() - 2) / 2) + 1; - return arc::try_create_arc(test_circle, points[0], points[mid_point_index], points[points.count()-1], target_arc, approximate_length, resolution_mm, path_tolerance_percent, allow_z_axis_changes); - } - return false; + const array_list<point>& points, + arc& target_arc, + double approximate_length, + double max_radius_mm, + double resolution_mm, + double path_tolerance_percent, + int min_arc_segments, + double mm_per_arc_segment, + int xyz_precision, + bool allow_z_axis_changes) +{ + circle test_circle; + if (circle::try_create_circle(points, max_radius_mm, resolution_mm, xyz_precision, allow_z_axis_changes, false, test_circle)) + { + int mid_point_index = ((points.count() - 2) / 2) + 1; + return arc::try_create_arc(test_circle, points[0], points[mid_point_index], points[points.count() - 1], target_arc, approximate_length, resolution_mm, path_tolerance_percent, min_arc_segments, mm_per_arc_segment, allow_z_axis_changes); + } + return false; } #pragma endregion segmented_shape::segmented_shape(int min_segments, int max_segments, double resolution_mm, double path_tolerance_percnet) : points_(max_segments) { - - xyz_precision_ = DEFAULT_XYZ_PRECISION; - e_precision_ = DEFAULT_E_PRECISION; - max_segments_ = max_segments; - path_tolerance_percent_ = path_tolerance_percnet; - resolution_mm_ = resolution_mm / 2.0; // divide by 2 because it is + or - 1/2 of the desired resolution. - e_relative_ = 0; - is_shape_ = false; - // min segments can never be lower than 3 (the default) else there could be no compression. - if (min_segments < DEFAULT_MIN_SEGMENTS) min_segments_ = DEFAULT_MIN_SEGMENTS; - else min_segments_ = min_segments; - original_shape_length_ = 0; - is_extruding_ = true; + xyz_precision_ = DEFAULT_XYZ_PRECISION; + e_precision_ = DEFAULT_E_PRECISION; + max_segments_ = max_segments; + path_tolerance_percent_ = path_tolerance_percnet; + resolution_mm_ = resolution_mm / 2.0; // divide by 2 because it is + or - 1/2 of the desired resolution. + e_relative_ = 0; + is_shape_ = false; + // min segments can never be lower than 3 (the default) else there could be no compression. + if (min_segments < DEFAULT_MIN_SEGMENTS) min_segments_ = DEFAULT_MIN_SEGMENTS; + else min_segments_ = min_segments; + + original_shape_length_ = 0; + is_extruding_ = true; } segmented_shape::~segmented_shape() { - + } void segmented_shape::reset_precision() { - xyz_precision_ = DEFAULT_XYZ_PRECISION; - e_precision_ = DEFAULT_E_PRECISION; + xyz_precision_ = DEFAULT_XYZ_PRECISION; + e_precision_ = DEFAULT_E_PRECISION; } -void segmented_shape::update_xyz_precision(double precision) +void segmented_shape::update_xyz_precision(int precision) { - if (xyz_precision_ < precision) - { - xyz_precision_ = precision; - } + if (xyz_precision_ < precision) + { + xyz_precision_ = precision; + } } -void segmented_shape::update_e_precision(double precision) +void segmented_shape::update_e_precision(int precision) { - if (e_precision_ < precision) - { - e_precision_ = precision; - } + if (e_precision_ < precision) + { + e_precision_ = precision; + } } bool segmented_shape::is_extruding() { - return is_extruding_; + return is_extruding_; } segmented_shape& segmented_shape::operator=(const segmented_shape& obj) { - points_.clear(); - if (obj.max_segments_ != max_segments_) - { - max_segments_ = obj.max_segments_; - - points_.resize(max_segments_); - } - points_.copy(obj.points_); - - original_shape_length_ = obj.original_shape_length_; - e_relative_ = obj.e_relative_; - is_shape_ = obj.is_shape_; - max_segments_ = obj.max_segments_; - resolution_mm_ = obj.resolution_mm_; - return *this; + points_.clear(); + if (obj.max_segments_ != max_segments_) + { + max_segments_ = obj.max_segments_; + + points_.resize(max_segments_); + } + points_.copy(obj.points_); + + original_shape_length_ = obj.original_shape_length_; + e_relative_ = obj.e_relative_; + is_shape_ = obj.is_shape_; + max_segments_ = obj.max_segments_; + resolution_mm_ = obj.resolution_mm_; + return *this; } int segmented_shape::get_num_segments() { - return points_.count(); + return points_.count(); } double segmented_shape::get_shape_length() { - return original_shape_length_; + return original_shape_length_; } double segmented_shape::get_shape_e_relative() { - return e_relative_; + return e_relative_; } void segmented_shape::clear() { - points_.clear(); - is_shape_ = false; - e_relative_ = 0; - original_shape_length_ = 0; + points_.clear(); + is_shape_ = false; + e_relative_ = 0; + original_shape_length_ = 0; } bool segmented_shape::is_shape() const { - // return the pre-calculated value. This should be updated by the plugin - return is_shape_; + // return the pre-calculated value. This should be updated by the plugin + return is_shape_; } void segmented_shape::set_is_shape(bool value) { - is_shape_ = value; + is_shape_ = value; } int segmented_shape::get_min_segments() { - return min_segments_; + return min_segments_; } int segmented_shape::get_max_segments() { - return max_segments_; + return max_segments_; } double segmented_shape::get_resolution_mm() { - return resolution_mm_; + return resolution_mm_; } double segmented_shape::get_path_tolerance_percent() { - return path_tolerance_percent_; + return path_tolerance_percent_; } void segmented_shape::set_resolution_mm(double resolution_mm) { - resolution_mm_ = resolution_mm; - + resolution_mm_ = resolution_mm; + } point segmented_shape::pop_front() { - return points_.pop_front(); + return points_.pop_front(); } point segmented_shape::pop_back() { - return points_.pop_back(); + return points_.pop_back(); } bool segmented_shape::try_add_point(point p, double e_relative) { - throw std::exception(); + throw std::exception(); } std::string segmented_shape::get_shape_gcode_absolute(double e_abs_start) { - throw std::exception(); + throw std::exception(); } std::string segmented_shape::get_shape_gcode_relative() { - throw std::exception(); + throw std::exception(); }
\ No newline at end of file diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h index 3c8da0f..af7d8be 100644 --- a/ArcWelder/segmented_shape.h +++ b/ArcWelder/segmented_shape.h @@ -122,6 +122,8 @@ struct circle { #define DEFAULT_RESOLUTION_MM 0.05 #define DEFAULT_ALLOW_Z_AXIS_CHANGES false +#define DEFAULT_MIN_ARC_SEGMENTS 0 +#define DEFAULT_MM_PER_ARC_SEGMENT 0 struct arc : circle { arc() { @@ -158,25 +160,31 @@ struct arc : circle const point& mid_point, const point& end_point, arc& target_arc, - double approximate_length, + double approximate_length, double resolution = DEFAULT_RESOLUTION_MM, - double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT, + double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT, + int min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS, + double mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT, bool allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES); static bool try_create_arc( const circle& c, const array_list<point>& points, arc& target_arc, - double approximate_length, + double approximate_length, double resolution = DEFAULT_RESOLUTION_MM, double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT, + int min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS, + double mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT, bool allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES); static bool try_create_arc( const array_list<point>& points, arc& target_arc, double approximate_length, - double max_radius = DEFAULT_MAX_RADIUS_MM, + double max_radius = DEFAULT_MAX_RADIUS_MM, double resolution = DEFAULT_RESOLUTION_MM, double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT, + int min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS, + double mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT, int xyz_precision = DEFAULT_XYZ_PRECISION, bool allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES); }; @@ -184,6 +192,7 @@ double distance_from_segment(segment s, point p); #define DEFAULT_MIN_SEGMENTS 3 #define DEFAULT_MAX_SEGMENTS 50 + class segmented_shape { public: @@ -204,8 +213,8 @@ public: double get_shape_e_relative(); void set_resolution_mm(double resolution_mm); void reset_precision(); - void update_xyz_precision(double precision); - void update_e_precision(double precision); + void update_xyz_precision(int precision); + void update_e_precision(int precision); virtual bool is_shape() const; // public virtual functions virtual void clear(); diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp index ce17764..f9c22d4 100644 --- a/ArcWelderConsole/ArcWelderConsole.cpp +++ b/ArcWelderConsole/ArcWelderConsole.cpp @@ -40,6 +40,8 @@ int main(int argc, char* argv[]) std::string target_file_path; double resolution_mm; double max_radius_mm; + int min_arc_segments; + double mm_per_arc_segment; double path_tolerance_percent; bool g90_g91_influences_extruder; bool hide_progress; @@ -90,6 +92,19 @@ int main(int argc, char* argv[]) arg_description_stream << "The maximum radius of any arc in mm. Default Value: " << DEFAULT_MAX_RADIUS_MM; TCLAP::ValueArg<double> max_radius_arg("m", "max-radius-mm", arg_description_stream.str(), false, DEFAULT_MAX_RADIUS_MM, "float"); + + // -s --mm-per-arc-segment + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The mm per arc segment as defined in your firmware. Used to compensate for firmware without min-arc-segments setting. Requires that min-arc-segments be set. Default Value: " << DEFAULT_MAX_RADIUS_MM; + TCLAP::ValueArg<double> mm_per_arc_segment_arg("s", "mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MAX_RADIUS_MM, "float"); + + // -a --min-arc-segments + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum number of segments in a full circle of the same radius as any given arc. Can only be used if --mm-per-arc-segment is also set. Used to compensate for firmware without min-arc-segments setting. Default: " << DEFAULT_MIN_ARC_SEGMENTS; + TCLAP::ValueArg<int> min_arc_segments_arg("a", "min-arc-segments", arg_description_stream.str(), false, DEFAULT_MIN_ARC_SEGMENTS, "int"); + // -g --g90-influences-extruder arg_description_stream.clear(); arg_description_stream.str(""); @@ -127,6 +142,8 @@ int main(int argc, char* argv[]) cmd.add(resolution_arg); cmd.add(path_tolerance_percent_arg); cmd.add(max_radius_arg); + cmd.add(min_arc_segments_arg); + cmd.add(mm_per_arc_segment_arg); cmd.add(allow_z_axis_changes_arg); cmd.add(g90_arg); cmd.add(hide_progress_arg); @@ -146,6 +163,8 @@ int main(int argc, char* argv[]) resolution_mm = resolution_arg.getValue(); max_radius_mm = max_radius_arg.getValue(); + min_arc_segments = min_arc_segments_arg.getValue(); + mm_per_arc_segment = mm_per_arc_segment_arg.getValue(); path_tolerance_percent = path_tolerance_percent_arg.getValue(); allow_z_axis_changes = allow_z_axis_changes_arg.getValue(); g90_g91_influences_extruder = g90_arg.getValue(); @@ -174,6 +193,20 @@ int main(int argc, char* argv[]) std::cout << "warning: The provided path max radius of " << max_radius_mm << "mm is greater than 1000000 (1km), which is not recommended." << std::endl; } + if (min_arc_segments < 0) + { + // warning + std::cout << "warning: The provided min_arc_segments " << min_arc_segments << " is less than zero. Setting to 0." << std::endl; + min_arc_segments = 0; + } + + if (mm_per_arc_segment < 0) + { + // warning + std::cout << "warning: The provided mm_per_arc_segment " << mm_per_arc_segment << "mm is less than zero. Setting to 0." << std::endl; + mm_per_arc_segment = 0; + } + if (path_tolerance_percent > 0.05) { // warning @@ -257,6 +290,8 @@ int main(int argc, char* argv[]) log_messages << "\tResolution : " << resolution_mm << "mm (+-" << std::setprecision(5) << resolution_mm/2.0 << "mm)\n"; log_messages << "\tPath Tolerance : " << std::setprecision(3) << path_tolerance_percent*100.0 << "%\n"; log_messages << "\tMaximum Arc Radius : " << std::setprecision(0) << max_radius_mm << "mm\n"; + log_messages << "\tMin Arc Segments : " << std::setprecision(0) << min_arc_segments << "\n"; + log_messages << "\tMM Per Arc Segment : " << std::setprecision(3) << mm_per_arc_segment << "\n"; log_messages << "\tAllow Z-Axis Changes : " << (allow_z_axis_changes ? "True" : "False") << "\n"; log_messages << "\tG90/G91 Influences Extruder : " << (g90_g91_influences_extruder ? "True" : "False") << "\n"; log_messages << "\tLog Level : " << log_level_string << "\n"; @@ -269,9 +304,9 @@ int main(int argc, char* argv[]) target_file_path = temp_file_path; } if (!hide_progress) - p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, path_tolerance_percent, max_radius_mm, g90_g91_influences_extruder, allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, on_progress); + p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, path_tolerance_percent, max_radius_mm, min_arc_segments, mm_per_arc_segment, g90_g91_influences_extruder, allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, on_progress); else - p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, path_tolerance_percent, max_radius_mm, g90_g91_influences_extruder, allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, suppress_progress); + p_arc_welder = new arc_welder(source_file_path, target_file_path, p_logger, resolution_mm, path_tolerance_percent, max_radius_mm, min_arc_segments, mm_per_arc_segment, g90_g91_influences_extruder, allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, suppress_progress); arc_welder_results results = p_arc_welder->process(); if (results.success) diff --git a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp index 62a3a07..ea333b3 100644 --- a/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp +++ b/ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp @@ -55,6 +55,12 @@ int main(int argc, char* argv[]) std::string target_file_path; bool overwrite_source_file = false; bool g90_g91_influences_extruder; + + ConfigurationStore cs; + double mm_per_arc_segment; + double min_mm_per_arc_segment; + int min_arc_segments; + double arc_segments_per_sec; std::string log_level_string; std::string log_level_string_default = "INFO"; @@ -77,7 +83,31 @@ int main(int argc, char* argv[]) arg_description_stream.str(""); arg_description_stream << "If supplied, G90/G91 influences the extruder axis. Default Value: " << DEFAULT_G90_G91_INFLUENCES_EXTRUDER; TCLAP::SwitchArg g90_arg("g", "g90-influences-extruder", arg_description_stream.str(), false); - + + // -m --mm-per-arc-segment + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The default segment length. Default Value: " << DEFAULT_MM_PER_ARC_SEGMENT; + TCLAP::ValueArg<double> mm_per_arc_segment_arg("m", "mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MM_PER_ARC_SEGMENT, "float"); + + // -n --min-mm-per-arc-segment + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum mm per arc segment. Used to prevent unnecessarily small segments from being generated. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_MM_PER_ARC_SEGMENT; + TCLAP::ValueArg<double> min_mm_per_arc_segment_arg("n", "min-mm-per-arc-segment", arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); + + // -s --min-arc-segments + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The minimum number of segments within a circle of the same radius as the arc. Can be used to increase detail on small arcs. The smallest segment generated will be no larger than min_mm_per_arc_segment. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_MIN_ARC_SEGMENTS; + TCLAP::ValueArg<int> min_arc_segments_arg("r", "min-arc-segments", arg_description_stream.str(), false, DEFAULT_MIN_ARC_SEGMENTS, "int"); + + // -s --arc-segments-per-second + arg_description_stream.clear(); + arg_description_stream.str(""); + arg_description_stream << "The number of segments per second. This will produce a constant number of arcs, clamped between mm-per-arc-segment and min-mm-per-arc-segment. Can be used to prevent stuttering when printing very quickly. A value less than or equal to 0 will disable this feature. Default Value: " << DEFAULT_ARC_SEGMENTS_PER_SEC; + TCLAP::ValueArg<double> arc_segments_per_sec_arg("s", "arc-segments-per-second", arg_description_stream.str(), false, DEFAULT_MIN_MM_PER_ARC_SEGMENT, "float"); + // -l --log-level std::vector<std::string> log_levels_vector; log_levels_vector.push_back("NOSET"); @@ -98,6 +128,12 @@ int main(int argc, char* argv[]) cmd.add(source_arg); cmd.add(target_arg); cmd.add(g90_arg); + + cmd.add(mm_per_arc_segment_arg); + cmd.add(min_mm_per_arc_segment_arg); + cmd.add(min_arc_segments_arg); + cmd.add(arc_segments_per_sec_arg); + cmd.add(log_level_arg); // Parse the argv array. @@ -106,6 +142,15 @@ int main(int argc, char* argv[]) // Get the value parsed by each arg. source_file_path = source_arg.getValue(); target_file_path = target_arg.getValue(); + mm_per_arc_segment = mm_per_arc_segment_arg.getValue(); + min_mm_per_arc_segment = min_mm_per_arc_segment_arg.getValue(); + min_arc_segments = min_arc_segments_arg.getValue(); + arc_segments_per_sec = arc_segments_per_sec_arg.getValue(); + + cs.mm_per_arc_segment = (float)mm_per_arc_segment; + cs.min_mm_per_arc_segment = (float)min_mm_per_arc_segment; + cs.min_arc_segments = min_arc_segments; + cs.arc_segments_per_sec = arc_segments_per_sec; if (target_file_path.size() == 0) { @@ -188,7 +233,7 @@ int main(int argc, char* argv[]) target_file_path = temp_file_path; } - inverse_processor processor(source_file_path, target_file_path, g90_g91_influences_extruder, 50); + inverse_processor processor(source_file_path, target_file_path, g90_g91_influences_extruder, 50, cs); processor.process(); // Todo: get some results! if (true) diff --git a/ArcWelderInverseProcessor/inverse_processor.cpp b/ArcWelderInverseProcessor/inverse_processor.cpp index 6717700..d82568c 100644 --- a/ArcWelderInverseProcessor/inverse_processor.cpp +++ b/ArcWelderInverseProcessor/inverse_processor.cpp @@ -54,11 +54,12 @@ //#include "stepper.h" //#include "planner.h" -inverse_processor::inverse_processor(std::string source_path, std::string target_path, bool g90_g91_influences_extruder, int buffer_size) +inverse_processor::inverse_processor(std::string source_path, std::string target_path, bool g90_g91_influences_extruder, int buffer_size, ConfigurationStore cs) { source_path_ = source_path; target_path_ = target_path; p_source_position_ = new gcode_position(get_args_(g90_g91_influences_extruder, buffer_size)); + cs_ = cs; // ** Gloabal Variable Definition ** // 20200417 - FormerLurker - Declare two globals and pre-calculate some values that will reduce the // amount of trig funcitons we need to call while printing. For the price of having two globals we @@ -259,50 +260,50 @@ void inverse_processor::mc_arc(float* position, float* target, float* offset, fl float rt_x = t_x - center_axis_x; float rt_y = t_y - center_axis_y; // 20200419 - Add a variable that will be used to hold the arc segment length - float mm_per_arc_segment = cs.mm_per_arc_segment; + float mm_per_arc_segment = cs_.mm_per_arc_segment; // CCW angle between position and target from circle center. Only one atan2() trig computation required. float angular_travel_total = atan2(r_axis_x * rt_y - r_axis_y * rt_x, r_axis_x * rt_x + r_axis_y * rt_y); - if (angular_travel_total < 0) { angular_travel_total += 2 * M_PI; } + if (angular_travel_total < 0) { angular_travel_total += (float)(2 * M_PI); } bool check_mm_per_arc_segment_max = false; - if (cs.min_arc_segments > 0) + if (cs_.min_arc_segments > 0) { // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation // Do this before converting the angular travel for clockwise rotation - mm_per_arc_segment = radius * ((2.0f * M_PI) / cs.min_arc_segments); + mm_per_arc_segment = (float)(radius * ((2.0f * M_PI) / cs_.min_arc_segments)); check_mm_per_arc_segment_max = true; } - if (cs.arc_segments_per_sec > 0) + if (cs_.arc_segments_per_sec > 0) { // 20200417 - FormerLurker - Implement MIN_ARC_SEGMENTS if it is defined - from Marlin 2.0 implementation - float mm_per_arc_segment_sec = (feed_rate / 60.0f) * (1.0f / cs.arc_segments_per_sec); + float mm_per_arc_segment_sec = (float)((feed_rate / 60.0f) * (1.0f / cs_.arc_segments_per_sec)); if (mm_per_arc_segment_sec < mm_per_arc_segment) mm_per_arc_segment = mm_per_arc_segment_sec; check_mm_per_arc_segment_max = true; } - if (cs.min_mm_per_arc_segment > 0) + if (cs_.min_mm_per_arc_segment > 0) { check_mm_per_arc_segment_max = true; // 20200417 - FormerLurker - Implement MIN_MM_PER_ARC_SEGMENT if it is defined // This prevents a very high number of segments from being generated for curves of a short radius - if (mm_per_arc_segment < cs.min_mm_per_arc_segment) mm_per_arc_segment = cs.min_mm_per_arc_segment; + if (mm_per_arc_segment < cs_.min_mm_per_arc_segment) mm_per_arc_segment = cs_.min_mm_per_arc_segment; } - if (check_mm_per_arc_segment_max && mm_per_arc_segment > cs.mm_per_arc_segment) mm_per_arc_segment = cs.mm_per_arc_segment; + if (check_mm_per_arc_segment_max && mm_per_arc_segment > cs_.mm_per_arc_segment) mm_per_arc_segment = cs_.mm_per_arc_segment; // Adjust the angular travel if the direction is clockwise - if (isclockwise) { angular_travel_total -= 2 * M_PI; } + if (isclockwise) { angular_travel_total -= (float)(2 * M_PI); } //20141002:full circle for G03 did not work, e.g. G03 X80 Y80 I20 J0 F2000 is giving an Angle of zero so head is not moving //to compensate when start pos = target pos && angle is zero -> angle = 2Pi if (p_x == t_x && p_y == t_y && angular_travel_total == 0) { - angular_travel_total += 2 * M_PI; + angular_travel_total += (float)(2 * M_PI); } //end fix G03 @@ -388,15 +389,8 @@ void inverse_processor::plan_buffer_line(float x, float y, float z, const float& //output_file_ << stream << "G1 X" << std::setprecision(3) << x << " Y" << y; - if (output_relative_) - { - stream << std::setprecision(5) << " E" << output_relative_; - } - else - { - stream << std::setprecision(5) << " E" << e; - } - + stream << std::setprecision(5) << " E" << e; + stream << std::setprecision(0) << " F" << feed_rate << "\n"; output_file_ << stream.str(); } diff --git a/ArcWelderInverseProcessor/inverse_processor.h b/ArcWelderInverseProcessor/inverse_processor.h index ae4e19b..a5f7184 100644 --- a/ArcWelderInverseProcessor/inverse_processor.h +++ b/ArcWelderInverseProcessor/inverse_processor.h @@ -38,12 +38,12 @@ typedef signed char int8_t; #define M_PI 3.14159265358979323846 // pi enum AxisEnum { X_AXIS = 0, Y_AXIS= 1, Z_AXIS = 2, E_AXIS = 3, X_HEAD = 4, Y_HEAD = 5 }; // Arc interpretation settings: -#define DEFAULT_MM_PER_ARC_SEGMENT 100.0 // REQUIRED - The enforced maximum length of an arc segment -#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0.2 /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than +#define DEFAULT_MM_PER_ARC_SEGMENT 1.0 // REQUIRED - The enforced maximum length of an arc segment +#define DEFAULT_MIN_MM_PER_ARC_SEGMENT 0 /* OPTIONAL - the enforced minimum length of an interpolated segment. Must be smaller than MM_PER_ARC_SEGMENT. Only has an effect if MIN_ARC_SEGMENTS > 0 or ARC_SEGMENTS_PER_SEC > 0 */ // If both MIN_ARC_SEGMENTS and ARC_SEGMENTS_PER_SEC is defined, the minimum calculated segment length is used. -#define DEFAULT_MIN_ARC_SEGMENTS 10 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. -#define DEFAULT_ARC_SEGMENTS_PER_SEC 30 // OPTIONAL - Use feedrate to choose segment length. +#define DEFAULT_MIN_ARC_SEGMENTS 0 // OPTIONAL - The enforced minimum segments in a full circle of the same radius. +#define DEFAULT_ARC_SEGMENTS_PER_SEC 0 // OPTIONAL - Use feedrate to choose segment length. // approximation will not be used for the first segment. Subsequent segments will be corrected following DEFAULT_N_ARC_CORRECTION. struct ConfigurationStore { @@ -53,19 +53,21 @@ struct ConfigurationStore { min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; arc_segments_per_sec = DEFAULT_ARC_SEGMENTS_PER_SEC; } - float mm_per_arc_segment; - float min_mm_per_arc_segment; + float mm_per_arc_segment; // This value is ALWAYS used. + float min_mm_per_arc_segment; // if less than or equal to 0, this is disabled int min_arc_segments; // If less than or equal to zero, this is disabled - int arc_segments_per_sec; // If less than or equal to zero, this is disabled + double arc_segments_per_sec; // If less than or equal to zero, this is disabled + }; class inverse_processor { public: - inverse_processor(std::string source_path, std::string target_path, bool g90_g91_influences_extruder, int buffer_size); + inverse_processor(std::string source_path, std::string target_path, bool g90_g91_influences_extruder, int buffer_size, ConfigurationStore cs = ConfigurationStore()); virtual ~inverse_processor(); void process(); void mc_arc(float* position, float* target, float* offset, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder); - ConfigurationStore cs; + private: + ConfigurationStore cs_; gcode_position_args get_args_(bool g90_g91_influences_extruder, int buffer_size); std::string source_path_; std::string target_path_; diff --git a/ArcWelderTest/ArcWelderTest.cpp b/ArcWelderTest/ArcWelderTest.cpp index 226e4b6..b121d05 100644 --- a/ArcWelderTest/ArcWelderTest.cpp +++ b/ArcWelderTest/ArcWelderTest.cpp @@ -233,9 +233,13 @@ static gcode_position_args get_5_extruder_position_args() static void TestAntiStutter(std::string filePath) { - //double max_resolution = DEFAULT_RESOLUTION_MM; - double max_resolution = 1; + double max_resolution = DEFAULT_RESOLUTION_MM; + //double max_resolution = 1; double max_radius_mm = DEFAULT_MAX_RADIUS_MM; + //int min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; + int min_arc_segments = 12; + double mm_per_arc_segment = 1; + double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT; // 1 percent //double path_tolerance_percent = 0.05; std::vector<std::string> logger_names; @@ -253,12 +257,14 @@ static void TestAntiStutter(std::string filePath) //arc_welder arc_welder_obj(BENCHY_0_5_MM_NO_WIPE, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, false, 50, static_cast<progress_callback>(on_progress)); //arc_welder arc_welder_obj(SIX_SPEED_TEST, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, false, 50, on_progress); arc_welder arc_welder_obj( - SPIRAL_VASE_TEST_DOUBLE_SPIRAL, + BENCHY_L1_DIFFICULT, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, path_tolerance_percent, max_radius_mm, + min_arc_segments, + mm_per_arc_segment, false, true, DEFAULT_GCODE_BUFFER_SIZE, diff --git a/GcodeProcessorLib/CMakeLists.txt b/GcodeProcessorLib/CMakeLists.txt index 21fe511..52d1d3a 100644 --- a/GcodeProcessorLib/CMakeLists.txt +++ b/GcodeProcessorLib/CMakeLists.txt @@ -20,9 +20,17 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) +# get the tag for the current branch +execute_process( + COMMAND git describe --abbrev=0 + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_TAG + OUTPUT_STRIP_TRAILING_WHITESPACE +) + # get the most recent tagged version execute_process( - COMMAND git describe --tags + COMMAND git describe WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_TAGGED_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE diff --git a/GcodeProcessorLib/gcode_parser.cpp b/GcodeProcessorLib/gcode_parser.cpp index 8d2e68a..a4035fb 100644 --- a/GcodeProcessorLib/gcode_parser.cpp +++ b/GcodeProcessorLib/gcode_parser.cpp @@ -480,7 +480,7 @@ bool gcode_parser::try_extract_double(char ** p_p_gcode, double * p_double, unsi ++p; } r += f / ten_pow(n); - *p_precision = n; + *p_precision = (unsigned char)n; } if (neg) { r = -r; diff --git a/GcodeProcessorLib/utilities.cpp b/GcodeProcessorLib/utilities.cpp index 2818eee..b0b0edc 100644 --- a/GcodeProcessorLib/utilities.cpp +++ b/GcodeProcessorLib/utilities.cpp @@ -218,7 +218,7 @@ std::istream& utilities::safe_get_line(std::istream& is, std::string& t) std::string utilities::center(std::string input, int width) { - int input_width = input.length(); + int input_width = (int)input.length(); int difference = width - input_width; if (difference < 1) { diff --git a/PyArcWelder/py_arc_welder.h b/PyArcWelder/py_arc_welder.h index ba2dcf7..979c3d0 100644 --- a/PyArcWelder/py_arc_welder.h +++ b/PyArcWelder/py_arc_welder.h @@ -41,7 +41,9 @@ public: py_logger* logger, double resolution_mm, double path_tolerance_percent, - double max_radius, + double max_radius, + int min_arc_segments, + double mm_per_arc_segment, bool g90_g91_influences_extruder, bool allow_z_axis_changes, int buffer_size, @@ -52,7 +54,9 @@ public: logger, resolution_mm, path_tolerance_percent, - max_radius, + max_radius, + min_arc_segments, + mm_per_arc_segment, g90_g91_influences_extruder, allow_z_axis_changes, buffer_size diff --git a/PyArcWelder/py_arc_welder_extension.cpp b/PyArcWelder/py_arc_welder_extension.cpp index 194ee22..4796230 100644 --- a/PyArcWelder/py_arc_welder_extension.cpp +++ b/PyArcWelder/py_arc_welder_extension.cpp @@ -196,7 +196,7 @@ extern "C" std::string message = "py_gcode_arc_converter.ConvertFile - Beginning Arc Conversion."; p_py_logger->log(GCODE_CONVERSION, INFO, message); - py_arc_welder arc_welder_obj(args.guid, args.source_path, args.target_path, p_py_logger, args.resolution_mm, args.path_tolerance_percent, args.max_radius_mm, args.g90_g91_influences_extruder, args.allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, py_progress_callback); + py_arc_welder arc_welder_obj(args.guid, args.source_path, args.target_path, p_py_logger, args.resolution_mm, args.path_tolerance_percent, args.max_radius_mm, args.min_arc_segments, args.mm_per_arc_segment, args.g90_g91_influences_extruder, args.allow_z_axis_changes, DEFAULT_GCODE_BUFFER_SIZE, py_progress_callback); arc_welder_results results = arc_welder_obj.process(); message = "py_gcode_arc_converter.ConvertFile - Arc Conversion Complete."; p_py_logger->log(GCODE_CONVERSION, INFO, message); @@ -300,6 +300,34 @@ static bool ParseArgs(PyObject* py_args, py_gcode_arc_args& args, PyObject** py_ args.max_radius_mm = DEFAULT_MAX_RADIUS_MM; // Set to the default if no resolution is provided, or if it is less than 0. } + // Extract the mm_per_arc_segment + PyObject* py_mm_per_arc_segment = PyDict_GetItemString(py_args, "mm_per_arc_segment"); + if (py_mm_per_arc_segment == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the mm_per_arc_segment parameter from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + args.mm_per_arc_segment = gcode_arc_converter::PyFloatOrInt_AsDouble(py_mm_per_arc_segment); + if (args.mm_per_arc_segment < 0) + { + args.mm_per_arc_segment = 0; + } + + // Extract min_arc_segments + PyObject* py_min_arc_segments = PyDict_GetItemString(py_args, "min_arc_segments"); + if (py_min_arc_segments == NULL) + { + std::string message = "ParseArgs - Unable to retrieve the min_arc_segments parameter from the args."; + p_py_logger->log_exception(GCODE_CONVERSION, message); + return false; + } + args.min_arc_segments = (int) gcode_arc_converter::PyIntOrLong_AsLong(py_min_arc_segments); + if (args.min_arc_segments < 0) + { + args.min_arc_segments = 0; // Set to the default if no resolution is provided, or if it is less than 0. + } + // Extract Allow Z Axis Changes // allow_z_axis_changes PyObject* py_allow_z_axis_changes = PyDict_GetItemString(py_args, "allow_z_axis_changes"); diff --git a/PyArcWelder/py_arc_welder_extension.h b/PyArcWelder/py_arc_welder_extension.h index fb5524c..bcd368b 100644 --- a/PyArcWelder/py_arc_welder_extension.h +++ b/PyArcWelder/py_arc_welder_extension.h @@ -49,6 +49,8 @@ struct py_gcode_arc_args { resolution_mm = DEFAULT_RESOLUTION_MM; path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT; max_radius_mm = DEFAULT_MAX_RADIUS_MM; + min_arc_segments = DEFAULT_MIN_ARC_SEGMENTS; + mm_per_arc_segment = DEFAULT_MM_PER_ARC_SEGMENT; g90_g91_influences_extruder = DEFAULT_G90_G91_INFLUENCES_EXTREUDER; allow_z_axis_changes = DEFAULT_ALLOW_Z_AXIS_CHANGES; log_level = 0; @@ -60,6 +62,8 @@ struct py_gcode_arc_args { double resolution_mm_, double path_tolerance_percent_, double max_radius_mm_, + int min_arc_segments_, + double mm_per_arc_segment_, bool g90_g91_influences_extruder_, bool allow_z_axis_changes_, int log_level_ @@ -70,6 +74,8 @@ struct py_gcode_arc_args { resolution_mm = resolution_mm_; path_tolerance_percent = path_tolerance_percent_; max_radius_mm = max_radius_mm_; + min_arc_segments = min_arc_segments_; + mm_per_arc_segment = mm_per_arc_segment_; allow_z_axis_changes = allow_z_axis_changes_; g90_g91_influences_extruder = g90_g91_influences_extruder_; log_level = log_level_; @@ -82,6 +88,8 @@ struct py_gcode_arc_args { bool allow_z_axis_changes; bool g90_g91_influences_extruder; double max_radius_mm; + int min_arc_segments; + double mm_per_arc_segment; int log_level; }; |