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-06 19:43:13 +0300
committerFormerLurker <hochgebe@gmail.com>2020-11-06 19:43:13 +0300
commit91633ba765214d1c6eece514e2dd2d0e898be8b4 (patch)
tree21ed3e43d72bc89efb0f363464ec26ee5e3ce536 /ArcWelder
parent395c472dfc6080b0b0b2fca9f1dba6eeb46c21cf (diff)
Implementations for #8, #9, #10, #11.
Diffstat (limited to 'ArcWelder')
-rw-r--r--ArcWelder/arc_welder.cpp60
-rw-r--r--ArcWelder/arc_welder.h27
-rw-r--r--ArcWelder/segmented_arc.cpp115
-rw-r--r--ArcWelder/segmented_arc.h13
-rw-r--r--ArcWelder/segmented_shape.cpp117
-rw-r--r--ArcWelder/segmented_shape.h50
6 files changed, 292 insertions, 90 deletions
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp
index 01de169..417d09d 100644
--- a/ArcWelder/arc_welder.cpp
+++ b/ArcWelder/arc_welder.cpp
@@ -35,8 +35,27 @@
#include <iomanip>
#include <sstream>
-
-arc_welder::arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, double max_radius, bool g90_g91_influences_extruder, int buffer_size, progress_callback callback) : current_arc_(DEFAULT_MIN_SEGMENTS, buffer_size - 5, resolution_mm, max_radius), segment_statistics_(segment_statistic_lengths, segment_statistic_lengths_count, log)
+arc_welder::arc_welder(
+ std::string source_path,
+ std::string target_path,
+ logger * log,
+ double resolution_mm,
+ double path_tolerance_percent,
+ double max_radius,
+ bool g90_g91_influences_extruder,
+ int buffer_size,
+ progress_callback callback) : current_arc_(
+ DEFAULT_MIN_SEGMENTS,
+ buffer_size - 5,
+ resolution_mm,
+ path_tolerance_percent,
+ max_radius
+ ),
+ segment_statistics_(
+ segment_statistic_lengths,
+ segment_statistic_lengths_count,
+ log
+ )
{
p_logger_ = log;
debug_logging_enabled_ = false;
@@ -45,11 +64,11 @@ arc_welder::arc_welder(std::string source_path, std::string target_path, logger
verbose_logging_enabled_ = false;
logger_type_ = 0;
+ resolution_mm_ = resolution_mm;
progress_callback_ = callback;
verbose_output_ = false;
source_path_ = source_path;
target_path_ = target_path;
- resolution_mm_ = resolution_mm;
gcode_position_args_ = get_args_(g90_g91_influences_extruder, buffer_size);
notification_period_seconds = 1;
lines_processed_ = 0;
@@ -164,8 +183,9 @@ arc_welder_results results;
stream << std::fixed << std::setprecision(5);
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), max_radius_mm:" << current_arc_.get_max_radius()
- << "mm, g90_91_influences_extruder: " << (p_source_position_->get_g90_91_influences_extruder() ? "True" : "False");
+ 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() <<
+ "mm, g90_91_influences_extruder: " << (p_source_position_->get_g90_91_influences_extruder() ? "True" : "False");
p_logger_->log(logger_type_, INFO, stream.str());
@@ -333,6 +353,12 @@ arc_welder_progress arc_welder::get_progress_(long source_file_position, double
int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess)
{
+ /* use to catch gcode for debugging since I can't set conditions equal to strings
+ if (cmd.gcode == "G1 X118.762 Y104.054 E0.0163")
+ {
+ std::cout << "Found it!";
+ }
+ */
// Update the position for the source gcode file
p_source_position_->update(cmd, lines_processed_, gcodes_processed_, -1);
position* p_cur_pos = p_source_position_->get_current_position_ptr();
@@ -360,9 +386,28 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess
// 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
// TODO: Handle relative XYZ axis. This is possible, but maybe not so important.
+ bool is_g1_g2 = cmd.command == "G0" || cmd.command == "G1";
+ if (is_g1_g2)
+ {
+ for (std::vector<parsed_command_parameter>::iterator it = cmd.parameters.begin(); it != cmd.parameters.end(); ++it)
+ {
+ switch ((*it).name[0])
+ {
+ case 'X':
+ case 'Y':
+ case 'Z':
+ current_arc_.update_xyz_precision((*it).double_precision);
+ break;
+ case 'E':
+ current_arc_.update_e_precision((*it).double_precision);
+ break;
+ }
+ }
+ }
+
if (
!is_end && cmd.is_known_command && !cmd.is_empty && (
- (cmd.command == "G0" || cmd.command == "G1") &&
+ is_g1_g2 &&
utilities::is_equal(p_cur_pos->z, p_pre_pos->z) &&
utilities::is_equal(p_cur_pos->x_offset, p_pre_pos->x_offset) &&
utilities::is_equal(p_cur_pos->y_offset, p_pre_pos->y_offset) &&
@@ -377,7 +422,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess
(previous_extruder.is_retracting && extruder_current.is_retracting)
) &&
p_cur_pos->is_extruder_relative == p_pre_pos->is_extruder_relative &&
- (!waiting_for_arc_ || p_pre_pos->f == p_cur_pos->f) &&
+ (/*!waiting_for_arc_ || */p_pre_pos->f == p_cur_pos->f) && // might need to skip the waiting for arc check...
(!waiting_for_arc_ || p_pre_pos->feature_type_tag == p_cur_pos->feature_type_tag)
)
) {
@@ -405,7 +450,6 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess
if (!waiting_for_arc_)
{
waiting_for_arc_ = true;
- previous_feedrate_ = p_pre_pos->f;
}
else
{
diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h
index 50917be..c81a8e1 100644
--- a/ArcWelder/arc_welder.h
+++ b/ArcWelder/arc_welder.h
@@ -344,13 +344,13 @@ struct arc_welder_progress {
std::stringstream stream;
stream << std::fixed << std::setprecision(2);
- stream << percent_complete << "% complete in " << seconds_elapsed << " seconds with " << seconds_remaining << " seconds remaining.";
- stream << " Gcodes Processed: " << gcodes_processed;
- stream << ", Current Line: " << lines_processed;
- stream << ", Points Compressed: " << points_compressed;
- stream << ", ArcsCreated: " << arcs_created;
- stream << ", Compression Ratio: " << compression_ratio;
- stream << ", Size Reduction: " << compression_percent << "% ";
+ stream << " percent_complete:" << percent_complete << ", seconds_elapsed:" << seconds_elapsed << ", seconds_remaining:" << seconds_remaining;
+ stream << ", gcodes_processed: " << gcodes_processed;
+ stream << ", current_file_line: " << lines_processed;
+ stream << ", points_compressed: " << points_compressed;
+ stream << ", arcs_created: " << arcs_created;
+ stream << ", compression_ratio: " << compression_ratio;
+ stream << ", size_reduction: " << compression_percent << "% ";
return stream.str();
}
std::string detail_str() const {
@@ -375,11 +375,21 @@ struct arc_welder_results {
std::string message;
arc_welder_progress progress;
};
+#define DEFAULT_GCODE_BUFFER_SIZE 100
class arc_welder
{
public:
- arc_welder(std::string source_path, std::string target_path, logger* log, double resolution_mm, double max_radius, bool g90_g91_influences_extruder, int buffer_size, progress_callback callback = NULL);
+ arc_welder(
+ std::string source_path,
+ std::string target_path,
+ logger* log,
+ double resolution_mm,
+ double path_tolerance_percent,
+ double max_radius,
+ bool g90_g91_influences_extruder,
+ int buffer_size = DEFAULT_GCODE_BUFFER_SIZE,
+ progress_callback callback = NULL);
void set_logger_type(int logger_type);
virtual ~arc_welder();
arc_welder_results process();
@@ -402,7 +412,6 @@ private:
std::string source_path_;
std::string target_path_;
double resolution_mm_;
- double max_segments_;
gcode_position_args gcode_position_args_;
long file_size_;
int lines_processed_;
diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp
index 591d616..abc50a4 100644
--- a/ArcWelder/segmented_arc.cpp
+++ b/ArcWelder/segmented_arc.cpp
@@ -31,12 +31,17 @@
#include <stdio.h>
#include <cmath>
-segmented_arc::segmented_arc() : segmented_shape(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM)
+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;
+
}
-segmented_arc::segmented_arc(int min_segments, int max_segments, double resolution_mm, double max_radius_mm) : segmented_shape(min_segments, max_segments, resolution_mm)
+segmented_arc::segmented_arc(
+ int min_segments,
+ int max_segments,
+ double resolution_mm,
+ double path_tolerance_percent,
+ double max_radius_mm) : 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;
@@ -120,7 +125,7 @@ bool segmented_arc::try_add_point(point p, double e_relative)
if (points_.count() == get_min_segments())
{
arc a;
- if (!arc::try_create_arc(arc_circle_, points_, original_shape_length_, resolution_mm_, a))
+ if (!arc::try_create_arc(arc_circle_, points_, original_shape_length_, a, resolution_mm_, path_tolerance_percent_))
{
point_added = false;
points_.pop_back();
@@ -187,6 +192,7 @@ bool segmented_arc::try_add_point_internal_(point p, double pd)
original_shape_length_ += pd;
circle_fits_points = does_circle_fit_points_(test_circle);
+
if (circle_fits_points)
{
arc_circle_ = test_circle;
@@ -209,6 +215,75 @@ bool segmented_arc::try_add_point_internal_(point p, double pd)
}
+bool segmented_arc::does_arc_fit_points(circle& c) const
+{
+ arc a;
+ return arc::try_create_arc(c, points_, original_shape_length_, a, resolution_mm_, path_tolerance_percent_);
+ /*double distance_from_center;
+ double difference_from_radius;
+ for (int index = 0; 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.
+ point cur_point(points_[index]);
+ double x_rel = cur_point.x - c.center.x;
+ double y_rel = cur_point.y - c.center.y;
+ bool clockwise = a.angle_radians < 0;
+
+ bool not_in_sector = (
+ ! (-a.start_point.x * y_rel + a.start_point.y * x_rel > 0)
+ && (-a.end_point.x * y_rel + a.end_point.y * x_rel > 0)
+ ) == clockwise;
+ if (not_in_sector)
+ {
+ return false;
+ }
+
+
+ } */
+ // Radius compare
+ /*
+ double r_axis_x = -(a.center.x - a.start_point.x);
+ double r_axis_y = -(a.center.y - a.start_point.y);
+ float center_axis_x = a.start_point.x - r_axis_x;
+ float center_axis_y = a.start_point.y - r_axis_y;
+ float rt_x = a.end_point.x - center_axis_x;
+ float rt_y = a.end_point.y - center_axis_y;
+ float angular_travel_total = std::atan2(r_axis_x * rt_y - r_axis_y * rt_x, r_axis_x * rt_x + r_axis_y * rt_y);
+ if (a.angle_radians>0) { angular_travel_total -= 2 * PI_DOUBLE; }
+ double test_radius = std::abs(a.radius * angular_travel_total);
+ if (utilities::is_zero(test_radius - original_shape_length_, resolution_mm_))
+ {
+ return true;
+ }
+ return false;
+ */
+}
+
+bool segmented_arc::is_point_on_arc(const arc& a, const point& p) const
+{
+ double distance_from_center;
+ double difference_from_radius;
+
+
+ for (int index = 0; 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.
+ distance_from_center = utilities::get_cartesian_distance(points_[index].x, points_[index].y, a.center.x, a.center.y);
+ double difference_from_radius = std::abs(distance_from_center - a.radius);
+ if (utilities::greater_than(difference_from_radius, resolution_mm_))
+ {
+ //std::cout << " failed - end points do not lie on circle.\n";
+ return false;
+ }
+ // see if the point is within the cone
+
+ }
+ return true;
+}
+
+
bool segmented_arc::does_circle_fit_points_(circle& c) const
{
// We know point 1 must fit (we used it to create the circle). Check the other points
@@ -250,8 +325,10 @@ bool segmented_arc::does_circle_fit_points_(circle& c) const
}
// get the current arc and compare the total length to the original length
- arc a;
- return arc::try_create_arc(c, points_, original_shape_length_, resolution_mm_, a);
+ //arc a;
+ //return arc::try_create_arc(c, points_, original_shape_length_, resolution_mm_, a))
+
+ return does_arc_fit_points(c);
}
@@ -259,14 +336,14 @@ bool segmented_arc::try_get_arc(arc & target_arc)
{
//int mid_point_index = ((points_.count() - 2) / 2) + 1;
//return arc::try_create_arc(arc_circle_, points_[0], points_[mid_point_index], points_[points_.count() - 1], original_shape_length_, resolution_mm_, target_arc);
- return arc::try_create_arc(arc_circle_ ,points_, original_shape_length_, resolution_mm_, target_arc);
+ return arc::try_create_arc(arc_circle_ ,points_, original_shape_length_, target_arc, resolution_mm_, path_tolerance_percent_);
}
bool segmented_arc::try_get_arc_(const circle& c, arc &target_arc)
{
//int mid_point_index = ((points_.count() - 1) / 2) + 1;
//return arc::try_create_arc(c, points_[0], points_[mid_point_index], endpoint, original_shape_length_ + additional_distance, resolution_mm_, target_arc);
- return arc::try_create_arc(c, points_, original_shape_length_, resolution_mm_, target_arc);
+ return arc::try_create_arc(c, points_, original_shape_length_, target_arc, resolution_mm_, path_tolerance_percent_);
}
std::string segmented_arc::get_shape_gcode_absolute(double e, double f)
@@ -286,15 +363,15 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f) cons
char buf[20];
std::string gcode;
arc c;
- arc::try_create_arc(arc_circle_, points_, original_shape_length_, resolution_mm_, c);
-
+
+ arc::try_create_arc(arc_circle_, points_, original_shape_length_, c, resolution_mm_, path_tolerance_percent_);
double i = c.center.x - c.start_point.x;
double j = c.center.y - c.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 (utilities::less_than(c.angle_radians, 0))
+ if (c.angle_radians < 0)
{
gcode = "G2";
}
@@ -305,30 +382,26 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f) cons
}
// Add X, Y, I and J
gcode += " X";
- gcode += utilities::to_string(c.end_point.x, 3, buf);
+ gcode += utilities::to_string(c.end_point.x, xyz_precision_, buf, false);
gcode += " Y";
- gcode += utilities::to_string(c.end_point.y, 3, buf);
+ gcode += utilities::to_string(c.end_point.y, xyz_precision_, buf, false);
gcode += " I";
- gcode += utilities::to_string(i, 3, buf);
+ gcode += utilities::to_string(i, xyz_precision_, buf, false);
gcode += " J";
- gcode += utilities::to_string(j, 3, buf);
+ gcode += utilities::to_string(j, xyz_precision_, buf, false);
// Add E if it appears
if (has_e)
{
gcode += " E";
- gcode += utilities::to_string(e, 5, buf);
+ 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);
- }
+ // Never add F, it should NEVER change!
return gcode;
diff --git a/ArcWelder/segmented_arc.h b/ArcWelder/segmented_arc.h
index 352deab..179d7af 100644
--- a/ArcWelder/segmented_arc.h
+++ b/ArcWelder/segmented_arc.h
@@ -30,12 +30,19 @@
#define GCODE_CHAR_BUFFER_SIZE 100
#define DEFAULT_MAX_RADIUS_MM 1000000.0 // 1km
+//#define DEFAULT_MAX_RADIUS_MM 10000.0 // 10M
class segmented_arc :
public segmented_shape
{
public:
segmented_arc();
- segmented_arc(int min_segments = DEFAULT_MIN_SEGMENTS, int max_segments = DEFAULT_MAX_SEGMENTS, double resolution_mm = DEFAULT_RESOLUTION_MM, double max_radius_mm = DEFAULT_MAX_RADIUS_MM);
+ segmented_arc(
+ int min_segments = DEFAULT_MIN_SEGMENTS,
+ 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
+ );
virtual ~segmented_arc();
virtual bool try_add_point(point p, double e_relative);
std::string get_shape_gcode_absolute(double e, double f);
@@ -51,9 +58,11 @@ public:
private:
bool try_add_point_internal_(point p, double pd);
bool does_circle_fit_points_(circle& c) const;
+ bool does_arc_fit_points(circle& c) const;
bool try_get_arc_(const circle& c, arc& target_arc);
+ bool is_point_on_arc(const arc& a, const point & p) const;
std::string get_shape_gcode_(bool has_e, double e, double f) const;
circle arc_circle_;
double max_radius_mm_;
-};
+};
diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp
index 6ec8d84..c1114c2 100644
--- a/ArcWelder/segmented_shape.cpp
+++ b/ArcWelder/segmented_shape.cpp
@@ -96,7 +96,8 @@ bool segment::get_closest_perpendicular_point(point p1, point p2, point c, point
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.
- if (utilities::less_than_or_equal(t, 0, CIRCLE_GENERATION_A_ZERO_TOLERANCE) || utilities::greater_than_or_equal(t, 1, CIRCLE_GENERATION_A_ZERO_TOLERANCE))
+ // 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);
@@ -155,12 +156,6 @@ double distance_from_segment(segment s, point p)
#pragma region Circle Functions
-bool circle::is_point_on_circle(point p, double resolution_mm)
-{
- // get the difference between the point and the circle's center.
- double difference = std::abs(utilities::get_cartesian_distance(p.x, p.y, center.x, center.y) - radius);
- return utilities::less_than(difference, resolution_mm, CIRCLE_GENERATION_A_ZERO_TOLERANCE);
-}
bool circle::try_create_circle(point p1, point p2, point p3, double max_radius, circle& new_circle)
{
@@ -172,11 +167,12 @@ bool circle::try_create_circle(point p1, point p2, point p3, double max_radius,
double y3 = p3.y;
double a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2;
-
- if (utilities::is_zero(a, CIRCLE_GENERATION_A_ZERO_TOLERANCE))
+ // 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)
@@ -196,6 +192,12 @@ bool circle::try_create_circle(point p1, point p2, point p3, double max_radius,
new_circle.center.y = y;
new_circle.center.z = p1.z;
new_circle.radius = radius;
+
+ /*if (utilities::is_zero(a, CIRCLE_GENERATION_A_ZERO_TOLERANCE))
+ {
+ return false;
+ } */
+
return true;
}
double circle::get_radians(const point& p1, const point& p2) const
@@ -225,17 +227,16 @@ point circle::get_closest_point(const point& p) const
#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, double approximate_length, double resolution, arc& target_arc)
+bool arc::try_create_arc(
+ const circle& c,
+ const point& start_point,
+ const point& mid_point,
+ const point& end_point,
+ double approximate_length,
+ arc& target_arc,
+ double resolution,
+ double path_tolerance_percent)
{
- //point p1 = c.get_closest_point(start_point);
- //point p2 = c.get_closest_point(mid_point);
- //point p3 = c.get_closest_point(end_point);
- /*// Get the radians between p1 and p2 (short angle)
- double p1_p2_rad = c.get_radians(p1, p2);
- double p2_p3_rad = c.get_radians(p2, p3);
- double p3_p1_rad = c.get_radians(p3, p1);
- */
-
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);
@@ -276,12 +277,37 @@ bool arc::try_create_arc(const circle& c, const point& start_point, const point&
}
}
- if (direction == 0) return false;
-
- double arc_length = c.radius * angle_radians;
- if (!utilities::is_equal(arc_length, approximate_length, resolution))
- return false;
+ // 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;
+ // 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;
+ 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(direction == 2)
angle_radians *= -1.0;
@@ -295,21 +321,31 @@ bool arc::try_create_arc(const circle& c, const point& start_point, const point&
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, double approximate_length, double resolution, arc& target_arc)
+bool arc::try_create_arc(
+ const circle& c,
+ const array_list<point>& points,
+ double approximate_length,
+ arc& target_arc,
+ double resolution,
+ double path_tolerance_percent)
{
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], approximate_length, resolution, target_arc);
+ return arc::try_create_arc(c, points[0], points[mid_point_index], points[points.count() - 1], approximate_length, target_arc, resolution, path_tolerance_percent);
}
#pragma endregion
-segmented_shape::segmented_shape(int min_segments, int max_segments, double resolution_mm) : points_(max_segments)
+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;
@@ -326,6 +362,27 @@ segmented_shape::~segmented_shape()
}
+void segmented_shape::reset_precision()
+{
+ xyz_precision_ = DEFAULT_XYZ_PRECISION;
+ e_precision_ = DEFAULT_E_PRECISION;
+}
+void segmented_shape::update_xyz_precision(double precision)
+{
+ if (xyz_precision_ < precision)
+ {
+ xyz_precision_ = precision;
+ }
+}
+void segmented_shape::update_e_precision(double precision)
+{
+ if (e_precision_ < precision)
+ {
+ e_precision_ = precision;
+ }
+
+}
+
bool segmented_shape::is_extruding()
{
return is_extruding_;
@@ -394,6 +451,12 @@ double segmented_shape::get_resolution_mm()
{
return resolution_mm_;
}
+
+double segmented_shape::get_path_tolerance_percent()
+{
+ return path_tolerance_percent_;
+}
+
void segmented_shape::set_resolution_mm(double resolution_mm)
{
resolution_mm_ = resolution_mm;
diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h
index 09d3d86..c4d622e 100644
--- a/ArcWelder/segmented_shape.h
+++ b/ArcWelder/segmented_shape.h
@@ -29,8 +29,11 @@
//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.0000000001 // fail
//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.001 // pass
//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.0001 // pass
-#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.00001 // PASS
-//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.000001 // pass
+// Todo: Figure out EXACTLY what this should be!!! 0.00001 is conservative
+//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.00001 // PASS , but fails to draw spiral test
+//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.000005 // Pass, but fails the spiral test
+//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.0000025 // Passes both... This is tricky...
+//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.000001 // fails on barbarian test!!!
//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.0000001 // fail
//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.0000005 // fail
//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.00000075 // fail
@@ -42,24 +45,15 @@
#include "array_list.h"
// The minimum theta value allowed between any two arc in order for an arc to be
// created. This prevents sign calculation issues for very small values of theta
-
-//#define MIN_ALLOWED_ARC_THETA 0.0000046875f // Lowest discovered value for full theta
-
+#define DEFAULT_XYZ_PRECISION 3
+#define DEFAULT_E_PRECISION 5
+#define ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT 0.01 // one percent
struct point
{
public:
- point() {
- x = 0;
- y = 0;
- z = 0;
- e_relative = 0;
- }
- point(double p_x, double p_y, double p_z, double p_e_relative) {
- x = p_x;
- y = p_y;
- z = p_z;
- e_relative = p_e_relative;
- }
+ point() :x(0), y(0), z(0), e_relative(0){}
+ point(double x, double y, double z, double e_relative)
+ : x(x), y(y), z(z), e_relative(e_relative){}
double x;
double y;
double z;
@@ -125,7 +119,6 @@ struct circle {
point center;
double radius;
- bool is_point_on_circle(point p, double resolution_mm);
static bool try_create_circle(point p1, point p2, point p3, double max_radius, circle& new_circle);
double get_radians(const point& p1, const point& p2) const;
@@ -135,6 +128,7 @@ struct circle {
point get_closest_point(const point& p) const;
};
+#define DEFAULT_RESOLUTION_MM 0.05
struct arc : circle
{
arc() {
@@ -163,28 +157,35 @@ struct arc : circle
double polar_end_theta;
point start_point;
point end_point;
- static bool try_create_arc(const circle& c, const point& start_point, const point& mid_point, const point& end_point, double approximate_length, double resolution, arc& target_arc);
- static bool try_create_arc(const circle& c, const array_list<point>& points, double approximate_length, double resolution, arc& target_arc);
+ static bool try_create_arc(const circle& c, const point& start_point, const point& mid_point, const point& end_point, double approximate_length, arc& target_arc, double resolution = DEFAULT_RESOLUTION_MM, double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT);
+ static bool try_create_arc(const circle& c, const array_list<point>& points, double approximate_length, arc& target_arc, double resolution = DEFAULT_RESOLUTION_MM, double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT);
};
double distance_from_segment(segment s, point p);
#define DEFAULT_MIN_SEGMENTS 3
#define DEFAULT_MAX_SEGMENTS 50
-#define DEFAULT_RESOLUTION_MM 0.05
class segmented_shape
{
public:
- segmented_shape(int min_segments = DEFAULT_MIN_SEGMENTS, int max_segments = DEFAULT_MAX_SEGMENTS, double resolution_mm = DEFAULT_RESOLUTION_MM);
+ segmented_shape(int min_segments = DEFAULT_MIN_SEGMENTS,
+ int max_segments = DEFAULT_MAX_SEGMENTS,
+ double resolution_mm = DEFAULT_RESOLUTION_MM,
+ double path_tolerance_percent = ARC_LENGTH_PERCENT_TOLERANCE_DEFAULT
+ );
segmented_shape& operator=(const segmented_shape& pos);
virtual ~segmented_shape();
int get_num_segments();
int get_min_segments();
int get_max_segments();
double get_resolution_mm();
+ double get_path_tolerance_percent();
double get_shape_length();
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);
virtual bool is_shape() const;
// public virtual functions
virtual void clear();
@@ -197,11 +198,14 @@ public:
protected:
array_list<point> points_;
void set_is_shape(bool value);
- double original_shape_length_;
+ unsigned char xyz_precision_;
+ unsigned char e_precision_;
+ double original_shape_length_;
double e_relative_;
bool is_extruding_;
double resolution_mm_;
bool is_shape_;
+ double path_tolerance_percent_;
private:
int min_segments_;
int max_segments_;