diff options
author | FormerLurker <hochgebe@gmail.com> | 2021-07-02 22:24:47 +0300 |
---|---|---|
committer | FormerLurker <hochgebe@gmail.com> | 2021-07-02 22:24:47 +0300 |
commit | 18d1e992d3773485d2b7b05ffaec1ea00b16c777 (patch) | |
tree | 42983ee7c351d32d38afb437642ed9f9e861a024 /ArcWelder | |
parent | 65768d59a9ed785ddb740fc6df67d2912d2a5bdf (diff) |
Add support for variable line widths.
Diffstat (limited to 'ArcWelder')
-rw-r--r-- | ArcWelder/arc_welder.cpp | 49 | ||||
-rw-r--r-- | ArcWelder/arc_welder.h | 9 | ||||
-rw-r--r-- | ArcWelder/segmented_arc.cpp | 10 | ||||
-rw-r--r-- | ArcWelder/segmented_shape.cpp | 40 | ||||
-rw-r--r-- | ArcWelder/segmented_shape.h | 3 |
5 files changed, 82 insertions, 29 deletions
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp index a1f4ca7..95fbcda 100644 --- a/ArcWelder/arc_welder.cpp +++ b/ArcWelder/arc_welder.cpp @@ -34,6 +34,7 @@ #include <fstream> #include <iomanip> #include <sstream> +#include <version.h> arc_welder::arc_welder( std::string source_path, @@ -53,7 +54,7 @@ arc_welder::arc_welder( int buffer_size, progress_callback callback) : current_arc_( DEFAULT_MIN_SEGMENTS, - buffer_size - 5, + buffer_size, resolution_mm, path_tolerance_percent, max_radius, @@ -92,6 +93,7 @@ arc_welder::arc_welder( last_gcode_line_written_ = 0; points_compressed_ = 0; arcs_created_ = 0; + arcs_aborted_by_flow_rate_ = 0; waiting_for_arc_ = false; previous_feedrate_ = -1; gcode_position_args_.set_num_extruders(8); @@ -114,6 +116,10 @@ gcode_position_args arc_welder::get_args_(bool g90_g91_influences_extruder, int gcode_position_args args; // Configure gcode_position_args args.g90_influences_extruder = g90_g91_influences_extruder; + if (buffer_size < 2) + { + buffer_size = 2; + } args.position_buffer_size = buffer_size; args.autodetect_position = true; args.home_x = 0; @@ -258,7 +264,8 @@ arc_welder_results results; p_logger_->log(logger_type_, DEBUG, "Sending initial progress update."); continue_processing = on_progress_(get_progress_(static_cast<long>(gcodeFile.tellg()), static_cast<double>(start_clock))); p_logger_->log(logger_type_, DEBUG, "Processing source file."); - + + bool arc_Welder_comment_added = false; while (std::getline(gcodeFile, line) && continue_processing) { lines_processed_++; @@ -267,17 +274,20 @@ arc_welder_results results; if (lines_processed_ == 1) { bool isUltiGCode = line == ";FLAVOR:UltiGCode"; - if (isUltiGCode) + bool isPrusaSlicer = line.rfind("; generated by PrusaSlicer", 0) == 0; + if (isUltiGCode || isPrusaSlicer) { write_gcode_to_file(line); } add_arcwelder_comment_to_target(); - if (isUltiGCode) + if (isUltiGCode || isPrusaSlicer) { lines_with_no_commands++; continue; } } + + cmd.clear(); if (verbose_logging_enabled_) { @@ -368,6 +378,7 @@ arc_welder_progress arc_welder::get_progress_(long source_file_position, double progress.lines_processed = lines_processed_; progress.points_compressed = points_compressed_; progress.arcs_created = arcs_created_; + progress.arcs_aborted_by_flow_rate = arcs_aborted_by_flow_rate_; progress.source_file_position = source_file_position; progress.target_file_size = static_cast<long>(output_file_.tellp()); progress.source_file_size = file_size_; @@ -432,6 +443,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess // calculate the extrusion rate (mm/mm) and see how much it changes double mm_extruded_per_mm_travel = 0; double extrusion_rate_change_percent = 0; + bool aborted_by_flow_rate = false; if (movement_length_mm > 0) { mm_extruded_per_mm_travel = extruder_current.e_relative / movement_length_mm; @@ -440,9 +452,10 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess extrusion_rate_change_percent = std::fabs(utilities::get_percent_change(previous_extrusion_rate_, mm_extruded_per_mm_travel)); } } - if (extrusion_rate_change_percent > extrusion_rate_variance_percent_) + if (previous_extrusion_rate_ != 0 && utilities::greater_than(extrusion_rate_change_percent, extrusion_rate_variance_percent_)) { - std::cout << "Extrusion Rate Change Percent: " << extrusion_rate_change_percent << "\n"; + arcs_aborted_by_flow_rate_++; + aborted_by_flow_rate = true; } // We need to make sure the printer is using absolute xyz, is extruding, and the extruder axis mode is the same as that of the previous position @@ -483,6 +496,8 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess ( !waiting_for_arc_ || extruder_current.is_extruding || + // Test for travel conversion + //(previous_extruder.is_extruding && extruder_current.is_extruding) || // Test to see if // we can get more arcs. (previous_extruder.is_retracting && extruder_current.is_retracting) @@ -493,6 +508,8 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess ) ) { + // Record the extrusion rate + previous_extrusion_rate_ = mm_extruded_per_mm_travel; printer_point p(p_cur_pos->get_gcode_x(), p_cur_pos->get_gcode_y(), p_cur_pos->get_gcode_z(), extruder_current.e_relative, movement_length_mm); if (!waiting_for_arc_) { @@ -514,6 +531,11 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess arc_added = current_arc_.try_add_point(p); if (arc_added) { + // Make sure our position list is large enough to handle all the segments + if (current_arc_.get_num_segments()+2 > p_source_position_->get_max_positions()) + { + p_source_position_->grow_max_positions(p_source_position_->get_max_positions()*2); + } if (!waiting_for_arc_) { waiting_for_arc_ = true; @@ -533,7 +555,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess } } else { - previous_extrusion_rate_ = 0; + if (debug_logging_enabled_) { if (is_end) { @@ -606,9 +628,12 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess { p_logger_->log(logger_type_, DEBUG, "Feature type changed, cannot add point to current arc: " + cmd.gcode); } - else if (previous_extrusion_rate_ != 0 && !utilities::is_equal(previous_extrusion_rate_, mm_extruded_per_mm_travel)) + else if (aborted_by_flow_rate) { - p_logger_->log(logger_type_, DEBUG, "Previus extrusion rate changed: " + cmd.gcode); + std::stringstream stream; + stream << std::fixed << std::setprecision(5); + stream << "Arc Canceled - The extrusion rate variance of " << extrusion_rate_variance_percent_ << "% exceeded by " << extrusion_rate_change_percent - extrusion_rate_variance_percent_ <<"% on line " << lines_processed_ << ". Extruded " << extruder_current.e_relative << "mm over " << movement_length_mm << "mm of travel (" << mm_extruded_per_mm_travel << "mm/mm). Previous rate: " << previous_extrusion_rate_ << "mm/mm."; + p_logger_->log(logger_type_, DEBUG, stream.str()); } else { @@ -617,9 +642,12 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess } } } + + // Reset the previous extrusion rate + previous_extrusion_rate_ = 0; } - previous_extrusion_rate_ = mm_extruded_per_mm_travel; + if (!arc_added && !(cmd.is_empty && cmd.comment.length() == 0)) { @@ -844,6 +872,7 @@ void arc_welder::add_arcwelder_comment_to_target() stream << std::fixed; stream << "; Postprocessed by [ArcWelder](https://github.com/FormerLurker/ArcWelderLib)\n"; stream << "; Copyright(C) 2020 - Brad Hochgesang\n"; + stream << "; Version: " << GIT_TAGGED_VERSION << ", Branch: " << GIT_BRANCH << ", BuildDate: " << BUILD_DATE << "\n"; stream << "; resolution=" << std::setprecision(2) << resolution_mm_ << "mm\n"; stream << "; path_tolerance=" << std::setprecision(0) << (current_arc_.get_path_tolerance_percent() * 100.0) << "%\n"; stream << "; max_radius=" << std::setprecision(2) << (current_arc_.get_max_radius()) << "mm\n"; diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h index 2da8929..a4fdded 100644 --- a/ArcWelder/arc_welder.h +++ b/ArcWelder/arc_welder.h @@ -354,6 +354,7 @@ struct arc_welder_progress { lines_processed = 0; points_compressed = 0; arcs_created = 0; + arcs_aborted_by_flow_rate = 0; num_firmware_compensations = 0; source_file_size = 0; source_file_position = 0; @@ -368,6 +369,7 @@ struct arc_welder_progress { int lines_processed; int points_compressed; int arcs_created; + int arcs_aborted_by_flow_rate; int num_firmware_compensations; double compression_ratio; double compression_percent; @@ -385,6 +387,7 @@ struct arc_welder_progress { stream << ", current_file_line: " << lines_processed; stream << ", points_compressed: " << points_compressed; stream << ", arcs_created: " << arcs_created; + stream << ", arcs_aborted_by_flowrate: " << arcs_aborted_by_flow_rate; stream << ", num_firmware_compensations: " << num_firmware_compensations; stream << ", compression_ratio: " << compression_ratio; stream << ", size_reduction: " << compression_percent << "% "; @@ -412,11 +415,10 @@ struct arc_welder_results { std::string message; arc_welder_progress progress; }; -#define DEFAULT_GCODE_BUFFER_SIZE 1000 +#define DEFAULT_GCODE_BUFFER_SIZE 10 #define DEFAULT_G90_G91_INFLUENCES_EXTRUDER false #define DEFAULT_ALLOW_DYNAMIC_PRECISION false -#define DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT 1 -//#define DEFAULT_EXTRUSION_RATE_VARIANCE 0.0001 +#define DEFAULT_EXTRUSION_RATE_VARIANCE_PERCENT 5 class arc_welder { public: @@ -469,6 +471,7 @@ private: int last_gcode_line_written_; int points_compressed_; int arcs_created_; + int arcs_aborted_by_flow_rate_; source_target_segment_statistics segment_statistics_; long get_file_size(const std::string& file_path); double get_time_elapsed(double start_clock, double end_clock); diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp index 4da8f8e..62593d7 100644 --- a/ArcWelder/segmented_arc.cpp +++ b/ArcWelder/segmented_arc.cpp @@ -127,11 +127,12 @@ bool segmented_arc::try_add_point(printer_point p) bool point_added = false; // if we don't have enough segnemts to check the shape, just add - if (points_.count() > get_max_segments() - 1) + + if (points_.count() == points_.get_max_size()) { // Too many points, we can't add more - return false; - } + points_.resize(points_.get_max_size()*2); + } if (points_.count() > 0) { printer_point p1 = points_[points_.count() - 1]; @@ -193,9 +194,6 @@ bool segmented_arc::try_add_point_internal_(printer_point p) 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_; diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp index 42aadcb..ec0611e 100644 --- a/ArcWelder/segmented_shape.cpp +++ b/ArcWelder/segmented_shape.cpp @@ -86,6 +86,11 @@ bool point::is_near_collinear(const point& p1, const point& p2, const point& p3, return fabs((p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x)) <= 1e-9; } +double point::cartesian_distance(const point& p1, const point& p2) +{ + return utilities::get_cartesian_distance(p1.x, p1.y, p2.x, p2.y); +} + #pragma endregion Point Functions #pragma region Segment Functions @@ -148,15 +153,12 @@ double vector::cross_product_magnitude(vector v1, vector v2) #pragma region Circle Functions - bool circle::try_create_circle(const point& p1, const point& p2, const point& p3, const double max_radius, circle& new_circle) { if (point::is_near_collinear(p1,p2,p3, 0.001)) { return false; } - - double x1 = p1.x; double y1 = p1.y; double x2 = p2.x; @@ -196,22 +198,40 @@ bool circle::try_create_circle(const point& p1, const point& p2, const point& p3 bool circle::try_create_circle(const array_list<printer_point>& points, const double max_radius, const double resolution_mm, const double xyz_tolerance, bool allow_3d_arcs, circle& new_circle) { int count = points.count(); - int middle_index = count / 2; + int end_index = count - 1; + - // The middle point will almost always produce the best arcs. - if (circle::try_create_circle(points[0], points[middle_index], points[count - 1], max_radius, new_circle) && !new_circle.is_over_deviation(points, resolution_mm, xyz_tolerance, allow_3d_arcs)) + + if (circle::try_create_circle(points[0], points[middle_index], points[end_index], max_radius, new_circle) && !new_circle.is_over_deviation(points, resolution_mm, xyz_tolerance, allow_3d_arcs)) { return true; } - + + /* + // This could be a near complete circle. In that case, the endpoints might be too close together to generate an accurate circle with the + // precision we have to work with. Let's adjust our circle into thirds and test those points as a last ditch effort. + if (count > 5) + { + middle_index = count / 3; + end_index = middle_index + middle_index; + if (circle::try_create_circle(points[0], points[middle_index], points[end_index], max_radius, test_circle) && !test_circle.is_over_deviation(points, resolution_mm, xyz_tolerance, allow_3d_arcs)) + { + new_circle = test_circle; + return true; + } + } + return false; + */ + // Find the circle with the least deviation, if one exists. // Note, this could possibly take a LONG time in the worst case, but it's a pretty unlikely. // However, if the midpoint check doesn't pass, it's worth it to spend a bit more time // finding the best fit for the circle (least squares deviation) - circle test_circle; + double least_deviation; bool found_circle=false; + for (int index = 1; index < count - 1; index++) { @@ -220,7 +240,7 @@ bool circle::try_create_circle(const array_list<printer_point>& points, const do // We already checked this one, and it failed, continue. continue; } - + circle test_circle; double current_deviation; if (circle::try_create_circle(points[0], points[index], points[count - 1], max_radius, test_circle) && test_circle.get_deviation_sum_squared(points, resolution_mm, xyz_tolerance, allow_3d_arcs, current_deviation)) { @@ -234,6 +254,7 @@ bool circle::try_create_circle(const array_list<printer_point>& points, const do } } return found_circle; + } double circle::get_polar_radians(const point& p1) const @@ -332,6 +353,7 @@ bool circle::is_over_deviation(const array_list<printer_point>& points, const do } // Check the point perpendicular from the segment to the circle's center, if any such point exists + if (segment::get_closest_perpendicular_point(current_point, 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); diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h index 8b014bc..ec4bde9 100644 --- a/ArcWelder/segmented_shape.h +++ b/ArcWelder/segmented_shape.h @@ -47,6 +47,7 @@ public: double z; static point get_midpoint(point p1, point p2); static bool is_near_collinear(const point& p1, const point& p2, const point& p3, double percent_tolerance); + static double cartesian_distance(const point& p1, const point& p2); }; struct printer_point : point @@ -99,7 +100,7 @@ struct vector : point }; -#define DEFAULT_MAX_RADIUS_MM 1000000.0 // 1km +#define DEFAULT_MAX_RADIUS_MM 10000.0 // 10m struct circle { circle() { center.x = 0; |