Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FormerLurker/ArcWelderLib.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFormerLurker <hochgebe@gmail.com>2020-11-23 17:39:15 +0300
committerFormerLurker <hochgebe@gmail.com>2020-11-23 17:39:15 +0300
commitf2b52d935ebc81a2eb12cfd7a1c4b924cfc5ea68 (patch)
treec790f2249ef02d6bdd10dc8d44f9b3bcf58a4cdb
parent3eda30c23a6a8f1679989e1862e6c9d815cdbd7e (diff)
Implement #18 and #19. Fix some compiler warnings.
-rw-r--r--ArcWelder/arc_welder.cpp10
-rw-r--r--ArcWelder/arc_welder.h4
-rw-r--r--ArcWelder/segmented_arc.cpp423
-rw-r--r--ArcWelder/segmented_arc.h10
-rw-r--r--ArcWelder/segmented_shape.cpp827
-rw-r--r--ArcWelder/segmented_shape.h21
-rw-r--r--ArcWelderConsole/ArcWelderConsole.cpp39
-rw-r--r--ArcWelderInverseProcessor/ArcWelderInverseProcessor.cpp49
-rw-r--r--ArcWelderInverseProcessor/inverse_processor.cpp36
-rw-r--r--ArcWelderInverseProcessor/inverse_processor.h20
-rw-r--r--ArcWelderTest/ArcWelderTest.cpp12
-rw-r--r--GcodeProcessorLib/CMakeLists.txt10
-rw-r--r--GcodeProcessorLib/gcode_parser.cpp2
-rw-r--r--GcodeProcessorLib/utilities.cpp2
-rw-r--r--PyArcWelder/py_arc_welder.h8
-rw-r--r--PyArcWelder/py_arc_welder_extension.cpp30
-rw-r--r--PyArcWelder/py_arc_welder_extension.h8
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;
};