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-05-17 01:17:15 +0300
committerFormerLurker <hochgebe@gmail.com>2020-05-17 01:17:15 +0300
commitd201085f565ed498d218ece1783a5c76bcfdb25d (patch)
treeaaa7304ecb0c89c0fdb5e4930e7db7a5897d907e /ArcWelder
parentf98db3c33c4199eb966c45c9ab2e914b3a689ae1 (diff)
Add max_radius_mm and switch to polar coordinates for arc generation.
Diffstat (limited to 'ArcWelder')
-rw-r--r--ArcWelder/arc_welder.cpp75
-rw-r--r--ArcWelder/arc_welder.h28
-rw-r--r--ArcWelder/segmented_arc.cpp83
-rw-r--r--ArcWelder/segmented_arc.h12
-rw-r--r--ArcWelder/segmented_shape.cpp162
-rw-r--r--ArcWelder/segmented_shape.h36
6 files changed, 221 insertions, 175 deletions
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp
index 0d3c021..81cc467 100644
--- a/ArcWelder/arc_welder.cpp
+++ b/ArcWelder/arc_welder.cpp
@@ -32,7 +32,7 @@
#include <fstream>
#include <iomanip>
#include <sstream>
-arc_welder::arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, gcode_position_args args) : current_arc_(gcode_position_args_.position_buffer_size - 5, resolution_mm)
+arc_welder::arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, double max_radius, gcode_position_args args) : current_arc_(DEFAULT_MIN_SEGMENTS, gcode_position_args_.position_buffer_size - 5, resolution_mm, max_radius)
{
p_logger_ = log;
debug_logging_enabled_ = false;
@@ -70,14 +70,14 @@ arc_welder::arc_welder(std::string source_path, std::string target_path, logger
p_source_position_ = new gcode_position(gcode_position_args_);
}
-arc_welder::arc_welder(std::string source_path, std::string target_path, logger* log, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size)
- : arc_welder(source_path, target_path, log, resolution_mm, arc_welder::get_args_(g90_g91_influences_extruder, buffer_size))
+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)
+ : arc_welder(source_path, target_path, log, resolution_mm, max_radius, arc_welder::get_args_(g90_g91_influences_extruder, buffer_size))
{
}
-arc_welder::arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size, progress_callback callback)
- : arc_welder(source_path, target_path, log, resolution_mm, arc_welder::get_args_(g90_g91_influences_extruder, buffer_size))
+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)
+ : arc_welder(source_path, target_path, log, resolution_mm, max_radius, arc_welder::get_args_(g90_g91_influences_extruder, buffer_size))
{
progress_callback_ = callback;
}
@@ -248,7 +248,7 @@ arc_welder_results arc_welder::process()
process_gcode(cmd, false);
// Only continue to process if we've found a command and either a progress_callback_ is supplied, or debug loggin is enabled.
- if (has_gcode && (progress_callback_ != NULL || debug_logging_enabled_))
+ if (has_gcode && (progress_callback_ != NULL || info_logging_enabled_))
{
if ((lines_processed_ % read_lines_before_clock_check) == 0 && next_update_time < clock())
{
@@ -256,20 +256,7 @@ arc_welder_results arc_welder::process()
{
p_logger_->log(logger_type_, VERBOSE, "Sending progress update.");
}
- arc_welder_progress progress;
- progress.gcodes_processed = gcodes_processed_;
- progress.lines_processed = lines_processed_;
- progress.points_compressed = points_compressed_;
- progress.arcs_created = arcs_created_;
- progress.target_file_size = static_cast<long>(output_file_.tellp());
- progress.source_file_size = static_cast<long>(gcodeFile.tellg());
- // ToDo: tellg does not do what I think it does, but why?
- long bytesRemaining = file_size_ - progress.source_file_size;
- progress.percent_complete = static_cast<double>(progress.source_file_size) / static_cast<double>(file_size_) * 100.0;
- progress.seconds_elapsed = get_time_elapsed(start_clock, clock());
- double bytesPerSecond = static_cast<double>(progress.source_file_size) / progress.seconds_elapsed;
- progress.seconds_remaining = bytesRemaining / bytesPerSecond;
- continue_processing = on_progress_(progress);
+ continue_processing = on_progress_(get_progress_(static_cast<long>(gcodeFile.tellg()), static_cast<double>(start_clock)));
next_update_time = get_next_update_time();
}
}
@@ -284,36 +271,62 @@ arc_welder_results arc_welder::process()
write_unwritten_gcodes_to_file();
p_logger_->log(logger_type_, DEBUG, "Processing complete, closing source and target file.");
+ arc_welder_progress final_progress = get_progress_(static_cast<long>(file_size_), static_cast<double>(start_clock));
+ if (progress_callback_ != NULL || info_logging_enabled_)
+ {
+ // Sending final progress update message
+ on_progress_(final_progress);
+ }
+
output_file_.close();
gcodeFile.close();
const clock_t end_clock = clock();
- const double total_seconds = static_cast<double>(end_clock - start_clock) / CLOCKS_PER_SEC;
+
results.success = continue_processing;
results.cancelled = !continue_processing;
- results.progress.target_file_size = get_file_size(target_path_);
- results.progress.seconds_elapsed = total_seconds;
- results.progress.gcodes_processed = gcodes_processed_;
- results.progress.lines_processed = lines_processed_;
- results.progress.points_compressed = points_compressed_;
- results.progress.arcs_created = arcs_created_;
- results.progress.source_file_size = file_size_;
+ results.progress = final_progress;
return results;
}
-bool arc_welder::on_progress_(arc_welder_progress progress)
+bool arc_welder::on_progress_(const arc_welder_progress& progress)
{
if (progress_callback_ != NULL)
{
return progress_callback_(progress);
}
- else if (debug_logging_enabled_)
+ else if (info_logging_enabled_)
{
- p_logger_->log(logger_type_, DEBUG, progress.str());
+ p_logger_->log(logger_type_, INFO, progress.str());
}
return true;
}
+arc_welder_progress arc_welder::get_progress_(long source_file_position, double start_clock)
+{
+ arc_welder_progress progress;
+ progress.gcodes_processed = gcodes_processed_;
+ progress.lines_processed = lines_processed_;
+ progress.points_compressed = points_compressed_;
+ progress.arcs_created = arcs_created_;
+ progress.source_file_position = source_file_position;
+ progress.target_file_size = static_cast<long>(output_file_.tellp());
+ progress.source_file_size = file_size_;
+ long bytesRemaining = file_size_ - static_cast<long>(source_file_position);
+ progress.percent_complete = static_cast<double>(source_file_position) / static_cast<double>(file_size_) * 100.0;
+ progress.seconds_elapsed = get_time_elapsed(start_clock, clock());
+ double bytesPerSecond = static_cast<double>(source_file_position) / progress.seconds_elapsed;
+ progress.seconds_remaining = bytesRemaining / bytesPerSecond;
+
+ if (source_file_position > 0) {
+ progress.compression_ratio = (static_cast<float>(source_file_position) / static_cast<float>(progress.target_file_size));
+ progress.compression_percent = (1.0 - (static_cast<float>(progress.target_file_size) / static_cast<float>(source_file_position))) * 100.0f;
+ }
+
+ return progress;
+
+}
+
int arc_welder::process_gcode(parsed_command cmd, bool is_end)
{
// Update the position for the source gcode file
diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h
index 208abf3..3e501af 100644
--- a/ArcWelder/arc_welder.h
+++ b/ArcWelder/arc_welder.h
@@ -37,6 +37,8 @@
#include "unwritten_command.h"
#include "logger.h"
+#define DEFAULT_G90_G91_INFLUENCES_EXTREUDER false
+
struct arc_welder_progress {
arc_welder_progress() {
percent_complete = 0.0;
@@ -47,7 +49,10 @@ struct arc_welder_progress {
points_compressed = 0;
arcs_created = 0;
source_file_size = 0;
+ source_file_position = 0;
target_file_size = 0;
+ compression_ratio = 0;
+ compression_percent = 0;
}
double percent_complete;
double seconds_elapsed;
@@ -56,19 +61,15 @@ struct arc_welder_progress {
int lines_processed;
int points_compressed;
int arcs_created;
+ double compression_ratio;
+ double compression_percent;
+ long source_file_position;
long source_file_size;
long target_file_size;
- std::string str() {
+ std::string str() const {
std::stringstream stream;
stream << std::fixed << std::setprecision(2);
- double compression_ratio = 0;
- double target_compression_percent = 0;
-
- if (target_file_size > 0) {
- compression_ratio = (static_cast<float>(source_file_size) / static_cast<float>(target_file_size));
- target_compression_percent = (1.0 - (static_cast<float>(target_file_size) / static_cast<float>(source_file_size))) * 100.0f;
- }
stream << percent_complete << "% complete in " << seconds_elapsed << " seconds with " << seconds_remaining << " seconds remaining.";
stream << " Gcodes Processed: " << gcodes_processed;
@@ -76,7 +77,7 @@ struct arc_welder_progress {
stream << ", Points Compressed: " << points_compressed;
stream << ", ArcsCreated: " << arcs_created;
stream << ", Compression Ratio: " << compression_ratio;
- stream << ", Size Reduction: " << target_compression_percent << "% ";
+ stream << ", Size Reduction: " << compression_percent << "% ";
return stream.str();
}
};
@@ -100,16 +101,17 @@ struct arc_welder_results {
class arc_welder
{
public:
- arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, gcode_position_args args);
- arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size);
- arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, bool g90_g91_influences_extruder, int buffer_size, progress_callback callback);
+ arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, double max_radius_mm, gcode_position_args args);
+ arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, double max_radius_mm, bool g90_g91_influences_extruder, int buffer_size);
+ arc_welder(std::string source_path, std::string target_path, logger * log, double resolution_mm, double max_radius_mm, bool g90_g91_influences_extruder, int buffer_size, progress_callback callback);
void set_logger_type(int logger_type);
virtual ~arc_welder();
arc_welder_results process();
double notification_period_seconds;
protected:
- virtual bool on_progress_(arc_welder_progress progress);
+ virtual bool on_progress_(const arc_welder_progress& progress);
private:
+ arc_welder_progress get_progress_(long source_file_position, double start_clock);
void add_arcwelder_comment_to_target();
void reset();
static gcode_position_args get_args_(bool g90_g91_influences_extruder, int buffer_size);
diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp
index 2af6bc4..28145fd 100644
--- a/ArcWelder/segmented_arc.cpp
+++ b/ArcWelder/segmented_arc.cpp
@@ -32,16 +32,16 @@
#include <stdio.h>
#include <cmath>
-segmented_arc::segmented_arc() : segmented_shape()
+segmented_arc::segmented_arc() : segmented_arc(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM, DEFAULT_MAX_RADIUS_MM)
{
- min_segments_ = 3;
- s_stream_ << std::fixed;
}
-segmented_arc::segmented_arc(int max_segments, double resolution_mm) : segmented_shape(3, max_segments, resolution_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)
{
- min_segments_ = 3;
- s_stream_ << std::fixed;
+ gcode_buffer_[0] = '\0';
+
+ if (max_radius_mm > DEFAULT_MAX_RADIUS_MM) max_radius_mm_ = DEFAULT_MAX_RADIUS_MM;
+ else max_radius_mm_ = max_radius_mm;
}
segmented_arc::~segmented_arc()
@@ -51,7 +51,7 @@ segmented_arc::~segmented_arc()
point segmented_arc::pop_front(double e_relative)
{
e_relative_ -= e_relative;
- if (points_.count() == min_segments_)
+ if (points_.count() == get_min_segments())
{
set_is_shape(false);
}
@@ -61,7 +61,7 @@ point segmented_arc::pop_back(double e_relative)
{
e_relative_ -= e_relative;
return points_.pop_back();
- if (points_.count() == min_segments_)
+ if (points_.count() == get_min_segments())
{
set_is_shape(false);
}
@@ -115,9 +115,11 @@ bool segmented_arc::try_add_point(point p, double e_relative)
return false;
}*/ // Test - see what happens without a max segment length.
}
- if (points_.count() < min_segments_ - 1)
+ if (points_.count() < get_min_segments() - 1)
{
point_added = true;
+ points_.push_back(p);
+ original_shape_length_ += distance;
}
else
{
@@ -126,8 +128,7 @@ bool segmented_arc::try_add_point(point p, double e_relative)
}
if (point_added)
{
- points_.push_back(p);
- original_shape_length_ += distance;
+
if (points_.count() > 1)
{
// Only add the relative distance to the second point on up.
@@ -135,7 +136,7 @@ bool segmented_arc::try_add_point(point p, double e_relative)
}
//std::cout << " success - " << points_.count() << " points.\n";
}
- else if (points_.count() < min_segments_ && points_.count() > 1)
+ 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
@@ -155,7 +156,7 @@ bool segmented_arc::try_add_point(point p, double e_relative)
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() < min_segments_ - 1)
+ if (points_.count() < get_min_segments() - 1)
return false;
// Create a test circle
@@ -163,7 +164,7 @@ bool segmented_arc::try_add_point_internal_(point p, double pd)
bool circle_created;
// Find a point in the middle of our list for p2
int mid_point_index = ((points_.count() - 2) / 2)+1;
- circle_created = circle::try_create_circle(points_[0], points_[mid_point_index], p, test_circle);
+ circle_created = circle::try_create_circle(points_[0], points_[mid_point_index], p, max_radius_mm_, test_circle);
if (circle_created)
{
@@ -172,11 +173,20 @@ bool segmented_arc::try_add_point_internal_(point p, double pd)
bool circle_fits_points;
// the circle is new.. we have to test it now, which is expensive :(
- circle_fits_points = does_circle_fit_points_(test_circle, p, pd);
+ points_.push_back(p);
+ double previous_shape_length = original_shape_length_;
+ original_shape_length_ += pd;
+
+ circle_fits_points = does_circle_fit_points_(test_circle);
if (circle_fits_points)
{
arc_circle_ = test_circle;
}
+ else
+ {
+ points_.pop_back();
+ original_shape_length_ = previous_shape_length;
+ }
// Only set is_shape if it goes from false to true
if (!is_shape())
@@ -190,7 +200,7 @@ bool segmented_arc::try_add_point_internal_(point p, double pd)
}
-bool segmented_arc::does_circle_fit_points_(circle c, point p, double pd)
+bool segmented_arc::does_circle_fit_points_(const circle& c)
{
// We know point 1 must fit (we used it to create the circle). Check the other points
// Note: We have not added the current point, but that's fine since it is guaranteed to fit too.
@@ -229,36 +239,25 @@ bool segmented_arc::does_circle_fit_points_(circle c, point p, double pd)
}
}
-
- // Check the midpoint of the new point and the final point
- point point_to_test;
- if (segment::get_closest_perpendicular_point(points_[points_.count() - 1], p, c.center, point_to_test))
- {
- distance_from_center = utilities::get_cartesian_distance(point_to_test.x, point_to_test.y, c.center.x, c.center.y);
- difference_from_radius = abs(distance_from_center - c.radius);
- // Test allowing more play for the midpoints.
- if (utilities::greater_than(difference_from_radius, resolution_mm_))
- {
- return false;
- }
- }
// get the current arc and compare the total length to the original length
arc a;
- return try_get_arc_(c, p, pd, a );
+ return try_get_arc_(c, a);
}
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);
+ //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);
}
-bool segmented_arc::try_get_arc_(circle& c, point endpoint, double additional_distance, arc &target_arc)
+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);
+ //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);
}
std::string segmented_arc::get_shape_gcode_absolute(double e, double f)
@@ -290,12 +289,12 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f)
if (utilities::greater_than_or_equal(f, 1))
{
// Add F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G2 X%.3f Y%.3f I%.3f J%.3f E%.5f F%.0f", c.end_point.x, c.end_point.y, i, j, e, f);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G2 X%.3f Y%.3f I%.3f J%.3f E%.5f F%.0f", c.end_point.x, c.end_point.y, i, j, e, f);
}
else
{
// No F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G2 X%.3f Y%.3f I%.3f J%.3f E%.5f", c.end_point.x, c.end_point.y, i, j, e);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G2 X%.3f Y%.3f I%.3f J%.3f E%.5f", c.end_point.x, c.end_point.y, i, j, e);
}
}
else
@@ -305,12 +304,12 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f)
if (utilities::greater_than_or_equal(f, 1))
{
// Add F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G2 X%.3f Y%.3f I%.3f J%.3f F%.0f", c.end_point.x, c.end_point.y, i, j, f);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G2 X%.3f Y%.3f I%.3f J%.3f F%.0f", c.end_point.x, c.end_point.y, i, j, f);
}
else
{
// No F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G2 X%.3f Y%.3f I%.3f J%.3f", c.end_point.x, c.end_point.y, i, j);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G2 X%.3f Y%.3f I%.3f J%.3f", c.end_point.x, c.end_point.y, i, j);
}
}
}
@@ -323,12 +322,12 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f)
if (utilities::greater_than_or_equal(f, 1))
{
// Add F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G3 X%.3f Y%.3f I%.3f J%.3f E%.5f F%.0f", c.end_point.x, c.end_point.y, i, j, e, f);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G3 X%.3f Y%.3f I%.3f J%.3f E%.5f F%.0f", c.end_point.x, c.end_point.y, i, j, e, f);
}
else
{
// No F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G3 X%.3f Y%.3f I%.3f J%.3f E%.5f", c.end_point.x, c.end_point.y, i, j, e);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G3 X%.3f Y%.3f I%.3f J%.3f E%.5f", c.end_point.x, c.end_point.y, i, j, e);
}
}
else
@@ -338,7 +337,7 @@ std::string segmented_arc::get_shape_gcode_(bool has_e, double e, double f)
if (utilities::greater_than_or_equal(f, 1))
{
// Add F param
- snprintf(gcode_buffer_, sizeof(gcode_buffer_), "G3 X%.3f Y%.3f I%.3f J%.3f F%.0f", c.end_point.x, c.end_point.y, i, j, f);
+ snprintf(gcode_buffer_, GCODE_CHAR_BUFFER_SIZE, "G3 X%.3f Y%.3f I%.3f J%.3f F%.0f", c.end_point.x, c.end_point.y, i, j, f);
}
else
{
diff --git a/ArcWelder/segmented_arc.h b/ArcWelder/segmented_arc.h
index 416fd3e..4a19b5c 100644
--- a/ArcWelder/segmented_arc.h
+++ b/ArcWelder/segmented_arc.h
@@ -29,12 +29,13 @@
#include <sstream>
#define GCODE_CHAR_BUFFER_SIZE 100
+#define DEFAULT_MAX_RADIUS_MM 1000000.0 // 1km
class segmented_arc :
public segmented_shape
{
public:
segmented_arc();
- segmented_arc(int max_segments, double resolution_mm);
+ segmented_arc(int min_segments, int max_segments, double resolution_mm, double max_radius);
virtual ~segmented_arc();
virtual bool try_add_point(point p, double e_relative);
std::string get_shape_gcode_absolute(double e, double f);
@@ -47,14 +48,13 @@ public:
// static gcode buffer
private:
- char gcode_buffer_[GCODE_CHAR_BUFFER_SIZE];
+ char gcode_buffer_[GCODE_CHAR_BUFFER_SIZE + 1];
bool try_add_point_internal_(point p, double pd);
- bool does_circle_fit_points_(circle c, point p, double additional_distance);
- bool try_get_arc_(circle& c, point endpoint, double additional_distance, arc & target_arc);
+ bool does_circle_fit_points_(const circle& c);
+ bool try_get_arc_(const circle& c, arc& target_arc);
std::string get_shape_gcode_(bool has_e, double e, double f);
- int min_segments_;
circle arc_circle_;
int test_count_ = 0;
- std::ostringstream s_stream_;
+ double max_radius_mm_;
};
diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp
index 21ca2b1..9cf0830 100644
--- a/ArcWelder/segmented_shape.cpp
+++ b/ArcWelder/segmented_shape.cpp
@@ -54,6 +54,14 @@ vector operator -(point& lhs, point& rhs) {
);
}
+vector operator -(const point& lhs, const point& rhs) {
+ 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,
@@ -88,7 +96,7 @@ 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_FLOATING_POINT_TOLERANCE) || utilities::greater_than_or_equal(t, 1, CIRCLE_FLOATING_POINT_TOLERANCE))
+ 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))
return false;
d.x = p1.x + t * (p2.x - p1.x);
@@ -151,10 +159,10 @@ 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_FLOATING_POINT_TOLERANCE);
+ return utilities::less_than(difference, resolution_mm, CIRCLE_GENERATION_A_ZERO_TOLERANCE);
}
-bool circle::try_create_circle(point p1, point p2, point p3, circle& new_circle)
+bool circle::try_create_circle(point p1, point p2, point p3, double max_radius, circle& new_circle)
{
double x1 = p1.x;
double y1 = p1.y;
@@ -165,12 +173,17 @@ bool circle::try_create_circle(point p1, point p2, point p3, circle& new_circle)
double a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2;
- if (utilities::is_zero(a, CIRCLE_FLOATING_POINT_TOLERANCE))
+ if (utilities::is_zero(a, CIRCLE_GENERATION_A_ZERO_TOLERANCE))
{
+#if _DEBUG
+ if (!utilities::is_zero(a, 0.000001))
+ {
+ std::cout << "This is an interesting point. Colinear";
+ }
+#endif
return false;
}
-
double b = (x1 * x1 + y1 * y1) * (y3 - y2)
+ (x2 * x2 + y2 * y2) * (y1 - y3)
+ (x3 * x3 + y3 * y3) * (y2 - y1);
@@ -182,20 +195,31 @@ bool circle::try_create_circle(point p1, point p2, point p3, circle& new_circle)
double x = -b / (2.0 * a);
double y = -c / (2.0 * a);
+ 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 = utilities::get_cartesian_distance(x, y, x1, y1);
+ new_circle.radius = radius;
return true;
}
-double circle::get_radians(point p1, point p2)
+double circle::get_radians(const point& p1, const point& p2) const
{
double distance_sq = 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);
}
-point circle::get_closest_point(point p)
+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;
+}
+
+point circle::get_closest_point(const point& p) const
{
vector v = p - center;
double mag = v.get_magnitude();
@@ -207,112 +231,102 @@ point circle::get_closest_point(point p)
#pragma endregion Circle Functions
#pragma region Arc Functions
-bool arc::try_create_arc(circle c, point start_point, point mid_point, 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, double resolution, arc& target_arc)
{
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)
+ /*// 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);
+ */
- bool found_angle = false;
+ double polar_start_theta = c.get_polar_radians(p1);
+ double polar_mid_theta = c.get_polar_radians(p2);
+ double polar_end_theta = c.get_polar_radians(p3);
+
+ // variable to hold radians
double angle_radians = 0;
- double angle_1, angle_2;
- if (utilities::is_equal(p1_p2_rad + p2_p3_rad + p3_p1_rad, 2 * PI_DOUBLE, CIRCLE_FLOATING_POINT_TOLERANCE))
+ int direction = 0; // 1 = counter clockwise, 2 = clockwise, 3 = unknown.
+ // Determine the direction of the arc
+ if (polar_end_theta > polar_start_theta)
{
- found_angle = true;
- angle_1 = p1_p2_rad;
- angle_2 = p2_p3_rad;
- }
- else if (utilities::is_equal(p1_p2_rad + p2_p3_rad + (2 * PI_DOUBLE - p3_p1_rad), 2 * PI_DOUBLE, CIRCLE_FLOATING_POINT_TOLERANCE))
- {
- found_angle = true;
- angle_1 = p2_p3_rad;
- angle_2 = p1_p2_rad;
+ 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
+ else if (polar_start_theta > polar_end_theta)
{
- double p1_p2_rad_lg = (2 * PI_DOUBLE - p1_p2_rad);
- if (utilities::is_equal(p1_p2_rad_lg + p2_p3_rad + p3_p1_rad, 2 * PI_DOUBLE, CIRCLE_FLOATING_POINT_TOLERANCE))
+ 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)
+ )
{
- found_angle = true;
- angle_1 = p1_p2_rad_lg;
- angle_2 = p2_p3_rad;
+ direction = 1;
+ angle_radians = polar_end_theta + ((2.0 * PI_DOUBLE) - polar_start_theta);
}
- else
+ else if (polar_end_theta < polar_mid_theta && polar_mid_theta < polar_start_theta)
{
- double p2_p3_rad_lg = (2 * PI_DOUBLE - p2_p3_rad);
- if (utilities::is_equal(p1_p2_rad + p2_p3_rad_lg + p3_p1_rad, 2 * PI_DOUBLE, CIRCLE_FLOATING_POINT_TOLERANCE))
- {
- found_angle = true;
- angle_1 = p1_p2_rad;
- angle_2 = p2_p3_rad_lg;
- }
+ direction = 2;
+ angle_radians = polar_start_theta - polar_end_theta;
}
}
- if (!found_angle)
- return false; // No angle could be found, exit.
- angle_radians = angle_1 + angle_2;
- double length = angle_radians * c.radius;
- if (!utilities::is_equal(length, approximate_length, resolution))
- return false;
-
- // Very small angles can't be relied upon to calculate the sign of the arc (clockwise vs anticlockwise)
- if (angle_radians < MIN_ALLOWED_ARC_THETA)
- {
- return false;
- }
- // Calculate the sign of the angle. This should be accurate now that we have filtered out small angles and exited due to lengh mismatches
- vector v1 = p1 - p2;
- vector v2 = p3 - p2;
- // Try to make a reasonable guess about the angle's direction. This works well unless the the angle is very small
- double magnitude1 = vector::cross_product_magnitude(v1, v2);
- // We can't use our utility compare (utility::greater_that) here, else we will lose
- // very important resolution information
- bool is_clockwise = false;
-
- if (magnitude1 > 0.0)
- {
- is_clockwise = true;
- }
- // If the calculated length isn't within the resolution, exit
- if (is_clockwise)
- angle_radians *= -1.0f;
+ if (direction == 0) return false;
+ double arc_length = c.radius * angle_radians;
+ if (!utilities::is_equal(arc_length, approximate_length, resolution))
+ 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 = length;
+ 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, double approximate_length, double resolution, arc& target_arc)
+{
+ 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);
+}
#pragma endregion
-segmented_shape::segmented_shape() : points_(50)
+segmented_shape::segmented_shape() : segmented_shape(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM )
{
- max_segments_ = 50;
- resolution_mm_ = 0.0250;
- e_relative_ = 0;
- is_shape_ = false;
- min_segments_ = 3;
- original_shape_length_ = 0;
- is_extruding_ = true;
}
+
segmented_shape::segmented_shape(int min_segments, int max_segments, double resolution_mm) : points_(max_segments)
{
+
max_segments_ = max_segments;
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_ = min_segments;
+ // 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;
}
diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h
index 5a9b64c..53a30ee 100644
--- a/ArcWelder/segmented_shape.h
+++ b/ArcWelder/segmented_shape.h
@@ -26,14 +26,23 @@
#include <string>
#include <limits>
#define PI_DOUBLE 3.14159265358979323846
-#define CIRCLE_FLOATING_POINT_TOLERANCE 0.0000000001
+//#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
+//#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
+//#define CIRCLE_GENERATION_A_ZERO_TOLERANCE 0.000000875 // fail
+
+
#include <list>
#include "utilities.h"
#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.0001f // Safe value for full theta
//#define MIN_ALLOWED_ARC_THETA 0.0000046875f // Lowest discovered value for full theta
struct point
@@ -117,11 +126,13 @@ struct circle {
double radius;
bool is_point_on_circle(point p, double resolution_mm);
- static bool try_create_circle(point p1, point p2, point p3, circle& new_circle);
+ static bool try_create_circle(point p1, point p2, point p3, double max_radius, circle& new_circle);
- double get_radians(point p1, point p2);
+ double get_radians(const point& p1, const point& p2) const;
- point get_closest_point(point p);
+ double get_polar_radians(const point& p1) const;
+
+ point get_closest_point(const point& p) const;
};
struct arc : circle
@@ -140,19 +151,27 @@ struct arc : circle
end_point.y = 0;
end_point.z = 0;
is_arc = false;
+ polar_start_theta = 0;
+ polar_end_theta = 0;
}
bool is_arc;
double length;
double angle_radians;
+ double polar_start_theta;
+ double polar_end_theta;
point start_point;
point end_point;
- static bool try_create_arc(circle c, point start_point, point mid_point, point end_point, double approximate_length, double resolution, arc& target_arc);
-
+ bool is_point_in_arc_slice(const point& p);
+ 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);
};
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:
@@ -179,14 +198,13 @@ public:
protected:
array_list<point> points_;
void set_is_shape(bool value);
- int min_segments_;
double original_shape_length_;
double e_relative_;
bool is_extruding_;
double resolution_mm_;
bool is_shape_;
private:
-
+ int min_segments_;
int max_segments_;
};