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-10-17 02:34:25 +0300
committerFormerLurker <hochgebe@gmail.com>2020-10-17 02:34:25 +0300
commit4fd38897fd66c245991a4066c7bb3db373087e70 (patch)
tree30a91cd0ded86278929869ec265c939fc839e18a
parent04958af691abfebc8314b300b4d8676f074439a7 (diff)
Add additional statistics. Fix windows c++ build for python 2.7 compilers.
-rw-r--r--.gitignore4
-rw-r--r--ArcWelder/arc_welder.cpp109
-rw-r--r--ArcWelder/arc_welder.h298
-rw-r--r--ArcWelder/segmented_arc.cpp5
-rw-r--r--ArcWelder/segmented_arc.h1
-rw-r--r--ArcWelder/segmented_shape.cpp18
-rw-r--r--ArcWelder/segmented_shape.h2
-rw-r--r--ArcWelder/unwritten_command.h11
-rw-r--r--ArcWelderConsole/ArcWelderConsole.cpp2
-rw-r--r--ArcWelderTest/ArcWelderTest.cpp21
-rw-r--r--ArcWelderTest/ArcWelderTest.h1
-rw-r--r--GcodeProcessorLib/GcodeProcessorLib.vcxproj2
-rw-r--r--GcodeProcessorLib/gcode_parser.cpp40
-rw-r--r--GcodeProcessorLib/gcode_parser.h2
-rw-r--r--GcodeProcessorLib/logger.cpp63
-rw-r--r--GcodeProcessorLib/logger.h9
-rw-r--r--GcodeProcessorLib/utilities.cpp65
-rw-r--r--GcodeProcessorLib/utilities.h7
-rw-r--r--PyArcWelder/py_arc_welder.cpp78
-rw-r--r--PyArcWelder/py_arc_welder.h2
-rw-r--r--PyArcWelder/py_arc_welder_extension.cpp8
21 files changed, 613 insertions, 135 deletions
diff --git a/.gitignore b/.gitignore
index 212afe6..7666809 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,7 +26,9 @@ bld/
[Bb]in/
[Oo]bj/
[Ll]og/
-
+*.tlog
+*.idb
+Remote_Pi/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
diff --git a/ArcWelder/arc_welder.cpp b/ArcWelder/arc_welder.cpp
index 2d3eac5..c283e26 100644
--- a/ArcWelder/arc_welder.cpp
+++ b/ArcWelder/arc_welder.cpp
@@ -22,6 +22,9 @@
// You can contact the author at the following email address:
// FormerLurker@pm.me
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#if _MSC_VER > 1200
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
#include "arc_welder.h"
#include <vector>
@@ -31,7 +34,9 @@
#include <fstream>
#include <iomanip>
#include <sstream>
-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)
+
+
+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)
{
p_logger_ = log;
debug_logging_enabled_ = false;
@@ -40,12 +45,12 @@ arc_welder::arc_welder(std::string source_path, std::string target_path, logger
verbose_logging_enabled_ = false;
logger_type_ = 0;
- progress_callback_ = NULL;
+ progress_callback_ = callback;
verbose_output_ = false;
source_path_ = source_path;
target_path_ = target_path;
resolution_mm_ = resolution_mm;
- gcode_position_args_ = args;
+ gcode_position_args_ = get_args_(g90_g91_influences_extruder, buffer_size);
notification_period_seconds = 1;
lines_processed_ = 0;
gcodes_processed_ = 0;
@@ -66,19 +71,8 @@ arc_welder::arc_welder(std::string source_path, std::string target_path, logger
}
// We don't care about the printer settings, except for g91 influences extruder.
- 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, 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, 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;
+ p_source_position_ = new gcode_position(gcode_position_args_);
}
gcode_position_args arc_welder::get_args_(bool g90_g91_influences_extruder, int buffer_size)
@@ -236,7 +230,7 @@ arc_welder_results results;
stream << "Parsing: " << line;
p_logger_->log(logger_type_, VERBOSE, stream.str());
}
- parser_.try_parse_gcode(line.c_str(), cmd);
+ parser_.try_parse_gcode(line.c_str(), cmd, true);
bool has_gcode = false;
if (cmd.gcode.length() > 0)
{
@@ -251,7 +245,7 @@ arc_welder_results results;
// Always process the command through the printer, even if no command is found
// This is important so that comments can be analyzed
//std::cout << "stabilization::process_file - updating position...";
- process_gcode(cmd, false);
+ process_gcode(cmd, false, 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 || info_logging_enabled_))
@@ -271,19 +265,20 @@ arc_welder_results results;
if (current_arc_.is_shape() && waiting_for_arc_)
{
p_logger_->log(logger_type_, DEBUG, "The target file opened successfully.");
- process_gcode(cmd, true);
+ process_gcode(cmd, true, false);
}
p_logger_->log(logger_type_, DEBUG, "Writing all unwritten gcodes to the target file.");
write_unwritten_gcodes_to_file();
+ p_logger_->log(logger_type_, DEBUG, "Fetching the final progress struct.");
- 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
+ p_logger_->log(logger_type_, VERBOSE, "Sending final progress update message.");
on_progress_(final_progress);
}
-
+ p_logger_->log(logger_type_, DEBUG, "Processing complete, closing source and target file.");
output_file_.close();
gcodeFile.close();
const clock_t end_clock = clock();
@@ -291,6 +286,8 @@ arc_welder_results results;
results.success = continue_processing;
results.cancelled = !continue_processing;
results.progress = final_progress;
+ p_logger_->log(logger_type_, DEBUG, "Returning processing results.");
+
return results;
}
@@ -329,20 +326,20 @@ arc_welder_progress arc_welder::get_progress_(long source_file_position, double
progress.compression_percent = (1.0 - (static_cast<float>(progress.target_file_size) / static_cast<float>(source_file_position))) * 100.0f;
}
+ progress.segment_statistics = segment_statistics_;
return progress;
}
-int arc_welder::process_gcode(parsed_command cmd, bool is_end)
+int arc_welder::process_gcode(parsed_command cmd, bool is_end, bool is_reprocess)
{
// 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();
position* p_pre_pos = p_source_position_->get_previous_position_ptr();
extruder extruder_current = p_cur_pos->get_current_extruder();
extruder previous_extruder = p_pre_pos->get_current_extruder();
- point p(p_cur_pos->x, p_cur_pos->y, p_cur_pos->z, extruder_current.e_relative);
+ point p(p_cur_pos->get_gcode_x(), p_cur_pos->get_gcode_y(), p_cur_pos->get_gcode_z(), extruder_current.e_relative);
//std::cout << lines_processed_ << " - " << cmd.gcode << ", CurrentEAbsolute: " << cur_extruder.e <<", ExtrusionLength: " << cur_extruder.extrusion_length << ", Retraction Length: " << cur_extruder.retraction_length << ", IsExtruding: " << cur_extruder.is_extruding << ", IsRetracting: " << cur_extruder.is_retracting << ".\n";
int lines_written = 0;
@@ -351,12 +348,28 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
bool arc_added = false;
bool clear_shapes = false;
+ // Update the source file statistics
+ if (p_cur_pos->has_xy_position_changed && (extruder_current.is_extruding || extruder_current.is_retracting) && !is_reprocess)
+ {
+ double movement_length_mm = utilities::get_cartesian_distance(p_pre_pos->x, p_pre_pos->y, p_cur_pos->x, p_cur_pos->y);
+ if (movement_length_mm > 0)
+ {
+ segment_statistics_.update(movement_length_mm, true);
+ }
+ }
+
// We need to make sure the printer is using absolute xyz, is extruding, and the extruder axis mode is the same as that of the previous position
// TODO: Handle relative XYZ axis. This is possible, but maybe not so important.
if (
!is_end && cmd.is_known_command && !cmd.is_empty && (
(cmd.command == "G0" || cmd.command == "G1") &&
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) &&
+ utilities::is_equal(p_cur_pos->z_offset, p_pre_pos->z_offset) &&
+ utilities::is_equal(p_cur_pos->x_firmware_offset, p_pre_pos->x_firmware_offset) &&
+ utilities::is_equal(p_cur_pos->y_firmware_offset, p_pre_pos->y_firmware_offset) &&
+ utilities::is_equal(p_cur_pos->z_firmware_offset, p_pre_pos->z_firmware_offset) &&
!p_cur_pos->is_relative &&
(
!waiting_for_arc_ ||
@@ -378,7 +391,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
}
write_unwritten_gcodes_to_file();
// add the previous point as the starting point for the current arc
- point previous_p(p_pre_pos->x, p_pre_pos->y, p_pre_pos->z, previous_extruder.e_relative);
+ point previous_p(p_pre_pos->get_gcode_x(), p_pre_pos->get_gcode_y(), p_pre_pos->get_gcode_z(), previous_extruder.e_relative);
// Don't add any extrusion, or you will over extrude!
//std::cout << "Trying to add first point (" << p.x << "," << p.y << "," << p.z << ")...";
current_arc_.try_add_point(previous_p, 0);
@@ -488,6 +501,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
}
}
}
+
if (!arc_added)
{
if (current_arc_.get_num_segments() < current_arc_.get_min_segments()) {
@@ -507,9 +521,10 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
if (current_arc_.is_shape())
{
- // increment our statistics
+ // update our statistics
points_compressed_ += current_arc_.get_num_segments()-1;
- arcs_created_++;
+ arcs_created_++; // increment the number of generated arcs
+
//std::cout << "Arc shape found.\n";
// Get the comment now, before we remove the previous comments
std::string comment = get_comment_for_arc();
@@ -548,13 +563,21 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
if (debug_logging_enabled_)
{
- p_logger_->log(logger_type_, DEBUG, "Arc created with " + std::to_string(current_arc_.get_num_segments()) + " segments: " + gcode);
+ char buffer[20];
+ std::string message = "Arc created with ";
+ sprintf(buffer, "%d", current_arc_.get_num_segments());
+ message += buffer;
+ message += " segments: ";
+ message += gcode;
+ p_logger_->log(logger_type_, DEBUG, message);
}
// Get and alter the current position so we can add it to the unwritten commands list
parsed_command arc_command = parser_.parse_gcode(gcode.c_str());
+ double arc_extrusion_length = current_arc_.get_shape_length();
+
unwritten_commands_.push_back(
- unwritten_command(arc_command, p_cur_pos->is_extruder_relative)
+ unwritten_command(arc_command, p_cur_pos->is_extruder_relative, arc_extrusion_length)
);
// write all unwritten commands (if we don't do this we'll mess up absolute e by adding an offset to the arc)
@@ -569,7 +592,7 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
// Reprocess this line
if (!is_end)
{
- return process_gcode(cmd, false);
+ return process_gcode(cmd, false, true);
}
else
{
@@ -597,17 +620,21 @@ int arc_welder::process_gcode(parsed_command cmd, bool is_end)
}
}
- if (clear_shapes)
- {
- waiting_for_arc_ = false;
- current_arc_.clear();
- // The current command is unwritten, add it.
- unwritten_commands_.push_back(unwritten_command(p_source_position_->get_current_position_ptr()));
- }
- else if (waiting_for_arc_ || !arc_added)
+
+
+ if (waiting_for_arc_ || !arc_added)
{
+ position* cur_pos = p_source_position_->get_current_position_ptr();
+ extruder& cur_extruder = cur_pos->get_current_extruder();
- unwritten_commands_.push_back(unwritten_command(p_source_position_->get_current_position_ptr()));
+ double length = 0;
+ if (p_cur_pos->has_xy_position_changed && (cur_extruder.is_extruding || cur_extruder.is_retracting))
+ {
+ position* prev_pos = p_source_position_->get_previous_position_ptr();
+ length = utilities::get_cartesian_distance(cur_pos->x, cur_pos->y, prev_pos->x, prev_pos->y);
+ }
+
+ unwritten_commands_.push_back(unwritten_command(cur_pos, length));
}
if (!waiting_for_arc_)
@@ -648,7 +675,7 @@ std::string arc_welder::create_g92_e(double absolute_e)
int arc_welder::write_gcode_to_file(std::string gcode)
{
- output_file_ << utilities::trim(gcode) << "\n";
+ output_file_ << gcode << "\n";
return 1;
}
@@ -662,6 +689,10 @@ int arc_welder::write_unwritten_gcodes_to_file()
{
// The the current unwritten position and remove it from the list
unwritten_command p = unwritten_commands_.pop_front();
+ if (p.extrusion_length > 0)
+ {
+ segment_statistics_.update(p.extrusion_length, false);
+ }
write_gcode_to_file(p.command.to_string());
}
diff --git a/ArcWelder/arc_welder.h b/ArcWelder/arc_welder.h
index 3e501af..d21c2c8 100644
--- a/ArcWelder/arc_welder.h
+++ b/ArcWelder/arc_welder.h
@@ -36,11 +36,284 @@
#include "array_list.h"
#include "unwritten_command.h"
#include "logger.h"
+#include <cmath>
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
#define DEFAULT_G90_G91_INFLUENCES_EXTREUDER false
+static const int segment_statistic_lengths_count = 12;
+const double segment_statistic_lengths[] = { 0.002f, 0.005f, 0.01f, 0.05f, 0.1f, 0.5f, 1.0f, 5.0f, 10.0f, 20.0f, 50.0f, 100.0f };
+
+struct segment_statistic {
+ segment_statistic(double min_length_mm, double max_length_mm)
+ {
+ count = 0;
+ min_mm = min_length_mm;
+ max_mm = max_length_mm;
+ }
+
+ double min_mm;
+ double max_mm;
+ int count;
+};
+
+struct source_target_segment_statistics {
+
+
+ source_target_segment_statistics(const double segment_tracking_lengths[], const int num_lengths, logger* p_logger = NULL) {
+ total_length_source = 0;
+ total_length_target = 0;
+ total_count_source = 0;
+ total_count_target = 0;
+ max_width = 0;
+ max_precision = 3;
+ num_segment_tracking_lengths = num_lengths;
+ double current_min = 0;
+ for (int index = 0; index < num_lengths; index++)
+ {
+ double current_max = segment_tracking_lengths[index];
+ source_segments.push_back(segment_statistic(current_min, segment_tracking_lengths[index]));
+ target_segments.push_back(segment_statistic(current_min, segment_tracking_lengths[index]));
+ current_min = current_max;
+ }
+ source_segments.push_back(segment_statistic(current_min, -1.0f));
+ target_segments.push_back(segment_statistic(current_min, -1.0f));
+ max_width = utilities::get_num_digits(current_min);
+ p_logger_ = p_logger_;
+ logger_type_ = 0;
+ }
+
+ std::vector<segment_statistic> source_segments;
+ std::vector<segment_statistic> target_segments;
+ double total_length_source;
+ double total_length_target;
+ int max_width;
+ int max_precision;
+ int total_count_source;
+ int total_count_target;
+ int num_segment_tracking_lengths;
+
+ void update(double length, bool is_source)
+ {
+ if (length <= 0)
+ return;
+
+ std::vector<segment_statistic>* stats;
+ if (is_source)
+ {
+ total_count_source++;
+ total_length_source += length;
+ stats = &source_segments;
+ }
+ else
+ {
+ total_count_target++;
+ total_length_target += length;
+ stats = &target_segments;
+ }
+ for (int index = 0; index < (*stats).size(); index++)
+ {
+ segment_statistic& stat = (*stats)[index];
+ if (stat.min_mm <= length && stat.max_mm > length || (index + 1) == (*stats).size())
+ {
+ stat.count++;
+ break;
+ }
+ }
+ }
+
+ std::string str() const {
+
+ //if (p_logger_ != NULL) p_logger_->log(logger_type_, VERBOSE, "Building Segment Statistics.");
+
+ std::stringstream output_stream;
+ std::stringstream format_stream;
+ const int min_column_size = 8;
+ int mm_col_size = max_width + max_precision + 2; // Adding 2 for the mm
+ int min_max_label_col_size = 4;
+ int percent_col_size = 9;
+ int totals_row_label_size = 22;
+ int count_col_size;
+
+ // Calculate the count column size
+ int max_count = 0;
+ //if (p_logger_ != NULL) p_logger_->log(logger_type_, VERBOSE, "Calculating Column Size.");
+
+ for (int index = 0; index < source_segments.size(); index++)
+ {
+ int source_count = source_segments[index].count;
+ int target_count = target_segments[index].count;
+ if (max_count < source_count)
+ {
+ max_count = source_count;
+ }
+ if (max_count < target_count)
+ {
+ max_count = target_count;
+ }
+ }
+ // Get the number of digits in the max count
+ count_col_size = utilities::get_num_digits(max_count);
+ // enforce the minimum of 6
+ if (count_col_size < min_column_size)
+ {
+ count_col_size = min_column_size;
+ }
+
+ if (max_precision > 0)
+ {
+ // We need an extra space in our column for the decimal.
+ mm_col_size++;
+ }
+
+ // enforce the min column size
+ if (mm_col_size < min_column_size)
+ {
+ mm_col_size = min_column_size;
+ }
+ // Get the table width
+ int table_width = mm_col_size + min_max_label_col_size + mm_col_size + count_col_size + count_col_size + percent_col_size;
+ // Add a separator for the statistics
+ //output_stream << std::setw(table_width) << std::setfill('-') << "-" << "\n" << std::setfill(' ') ;
+ // Output the column headers
+ // Center the min and max column.
+ output_stream << utilities::center("Min", mm_col_size);
+ output_stream << std::setw(min_max_label_col_size) << "";
+ output_stream << utilities::center("Max", mm_col_size);
+ // right align the source, target and change columns
+ output_stream << std::setw(count_col_size) << std::right << "Source";
+ output_stream << std::setw(count_col_size) << std::right << "Target";
+ output_stream << std::setw(percent_col_size) << std::right << "Change";
+ output_stream << "\n";
+ output_stream << std::setw(table_width) << std::setfill('-') << "" << std::setfill(' ') << "\n";
+ output_stream << std::fixed << std::setprecision(max_precision);
+ for (int index = 0; index < source_segments.size(); index++) {
+ //extract the necessary variables from the source and target segments
+ double min_mm = source_segments[index].min_mm;
+ double max_mm = source_segments[index].max_mm;
+ int source_count = source_segments[index].count;
+ int target_count = target_segments[index].count;
+ // Calculate the percent change and create the string
+ // Construct the percent_change_string
+ std::string percent_change_string = utilities::get_percent_change_string(source_count, target_count, 1);
+
+ // Create the strings to hold the column values
+ std::string min_mm_string;
+ std::string max_mm_string;
+ std::string source_count_string;
+ std::string target_count_string;
+
+ // Clear the format stream and construct the min_mm_string
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(max_precision) << min_mm << "mm";
+ min_mm_string = format_stream.str();
+ // Clear the format stream and construct the max_mm_string
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(max_precision) << max_mm << "mm";
+ max_mm_string = format_stream.str();
+ // Clear the format stream and construct the source_count_string
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(0) << source_count;
+ source_count_string = format_stream.str();
+ // Clear the format stream and construct the target_count_string
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(0) << target_count;
+ target_count_string = format_stream.str();
+ // The min and max columns and the label need to be handled differently if this is the last item
+ if (index == source_segments.size() - 1)
+ {
+ // If we are on the last setment item, the 'min' value is the max, and there is no end
+ // The is because the last item contains the count of all items above the max length provided
+ // in the constructor
+
+ // The 'min' column is empty here
+ output_stream << std::setw(mm_col_size) << std::internal << "";
+ // Add the min/max label
+ output_stream << std::setw(min_max_label_col_size) << " >= ";
+ // Add the min mm string
+ output_stream << std::setw(mm_col_size) << std::internal << min_mm_string;
+ }
+ else
+ {
+ //if (p_logger_ != NULL) p_logger_->log(logger_type_, VERBOSE, "Adding row text.");
+
+ // add the 'min' column
+ output_stream << std::setw(mm_col_size) << std::internal << min_mm_string;
+ // Add the min/max label
+ output_stream << std::setw(min_max_label_col_size) << " to ";
+ // Add the 'max' column
+ output_stream << std::setw(mm_col_size) << std::internal << max_mm_string;
+ }
+ // Add the source count
+ output_stream << std::setw(count_col_size) << source_count_string;
+ // Add the target count
+ output_stream << std::setw(count_col_size) << target_count_string;
+ // Add the percent change string
+ output_stream << std::setw(percent_col_size) << percent_change_string;
+ // End the line
+ output_stream << "\n";
+ }
+ // Add the total rows separator
+ output_stream << std::setw(table_width) << std::setfill('-') << "" << std::setfill(' ') << "\n";
+ // Add the total rows;
+ if (utilities::is_equal(total_length_source, total_length_target, 0.001))
+ {
+ std::string total_distance_string;
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(max_precision) << total_length_source << "mm";
+ total_distance_string = format_stream.str();
+ output_stream << std::setw(totals_row_label_size) << std::right << "Total distance:";
+ output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_distance_string << "\n" << std::setfill(' ');
+ }
+ else
+ {
+ // We need to output two different distances (this probably should never happen)
+ // Format the total source distance string
+ std::string total_source_distance_string;
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(max_precision) << total_length_source << "mm";
+ total_source_distance_string = format_stream.str();
+ // Add the total source distance row
+ output_stream << std::setw(totals_row_label_size) << std::right << "Total distance source:";
+ output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_source_distance_string << "\n" << std::setfill(' ');
+
+ // Format the total target distance string
+ std::string total_target_distance_string;
+ format_stream.str(std::string());
+ format_stream << std::fixed << std::setprecision(max_precision) << total_length_target << "mm";
+ total_target_distance_string = format_stream.str();
+ // Add the total target distance row
+ output_stream << std::setw(totals_row_label_size) << std::right << "Total distance target:";
+ output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_target_distance_string << "\n" << std::setfill(' ');
+ }
+
+ // Add the total count rows
+ // Add the source count
+ output_stream << std::setprecision(0) << std::setw(totals_row_label_size) << std::right << "Total count source:";
+ output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_count_source << "\n" << std::setfill(' ');
+ // Add the target count
+ output_stream << std::setw(totals_row_label_size) << std::right << "Total count target:";
+ output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_count_target << "\n" << std::setfill(' ');
+ // Add the total percent change row
+ std::string total_percent_change_string = utilities::get_percent_change_string(total_count_source, total_count_target, 1);
+ output_stream << std::setw(totals_row_label_size) << std::right << "Total percent change:";
+ output_stream << std::setw(table_width - totals_row_label_size) << std::setfill('.') << std::right << total_percent_change_string << "\n" << std::setfill(' ');
+ std::string output_string = output_stream.str();
+ return output_string;
+ }
+
+private:
+ logger* p_logger_;
+ int logger_type_;
+};
+
+// Struct to hold the progress, statistics, and return values
struct arc_welder_progress {
- arc_welder_progress() {
+ arc_welder_progress() : segment_statistics(segment_statistic_lengths, segment_statistic_lengths_count, NULL) {
percent_complete = 0.0;
seconds_elapsed = 0.0;
seconds_remaining = 0.0;
@@ -53,6 +326,7 @@ struct arc_welder_progress {
target_file_size = 0;
compression_ratio = 0;
compression_percent = 0;
+
}
double percent_complete;
double seconds_elapsed;
@@ -66,11 +340,12 @@ struct arc_welder_progress {
long source_file_position;
long source_file_size;
long target_file_size;
+ source_target_segment_statistics segment_statistics;
std::string str() const {
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;
@@ -80,8 +355,12 @@ struct arc_welder_progress {
stream << ", Size Reduction: " << compression_percent << "% ";
return stream.str();
}
+ std::string detail_str() const {
+ std::stringstream stream;
+ stream << "\n" << "Extrusion/Retraction Counts" << "\n" << segment_statistics.str() << "\n";
+ return stream.str();
+ }
};
-
// define the progress callback type
typedef bool(*progress_callback)(arc_welder_progress);
@@ -101,9 +380,7 @@ struct arc_welder_results {
class arc_welder
{
public:
- 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);
+ 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);
void set_logger_type(int logger_type);
virtual ~arc_welder();
arc_welder_results process();
@@ -111,12 +388,12 @@ public:
protected:
virtual bool on_progress_(const arc_welder_progress& progress);
private:
- arc_welder_progress get_progress_(long source_file_position, double start_clock);
+ 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);
progress_callback progress_callback_;
- int process_gcode(parsed_command cmd, bool is_end);
+ int process_gcode(parsed_command cmd, bool is_end, bool is_reprocess);
int write_gcode_to_file(std::string gcode);
std::string get_arc_gcode_relative(double f, const std::string comment);
std::string get_arc_gcode_absolute(double e, double f, const std::string comment);
@@ -134,6 +411,7 @@ private:
int last_gcode_line_written_;
int points_compressed_;
int arcs_created_;
+ source_target_segment_statistics segment_statistics_;
long get_file_size(const std::string& file_path);
double get_time_elapsed(double start_clock, double end_clock);
double get_next_update_time() const;
@@ -141,9 +419,9 @@ private:
array_list<unwritten_command> unwritten_commands_;
segmented_arc current_arc_;
std::ofstream output_file_;
-
+
// We don't care about the printer settings, except for g91 influences extruder.
- gcode_position * p_source_position_;
+ gcode_position* p_source_position_;
double previous_feedrate_;
bool previous_is_extruder_relative_;
gcode_parser parser_;
diff --git a/ArcWelder/segmented_arc.cpp b/ArcWelder/segmented_arc.cpp
index 220e740..297304b 100644
--- a/ArcWelder/segmented_arc.cpp
+++ b/ArcWelder/segmented_arc.cpp
@@ -31,11 +31,12 @@
#include <stdio.h>
#include <cmath>
-segmented_arc::segmented_arc() : segmented_arc(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM, DEFAULT_MAX_RADIUS_MM)
+segmented_arc::segmented_arc() : segmented_shape(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM)
{
+ 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 = DEFAULT_MIN_SEGMENTS, int max_segments = DEFAULT_MAX_SEGMENTS, double resolution_mm = DEFAULT_RESOLUTION_MM, double max_radius_mm = DEFAULT_MAX_RADIUS_MM) : segmented_shape(min_segments, max_segments, resolution_mm)
{
if (max_radius_mm > DEFAULT_MAX_RADIUS_MM) max_radius_mm_ = DEFAULT_MAX_RADIUS_MM;
else max_radius_mm_ = max_radius_mm;
diff --git a/ArcWelder/segmented_arc.h b/ArcWelder/segmented_arc.h
index 9a412ad..04dbeea 100644
--- a/ArcWelder/segmented_arc.h
+++ b/ArcWelder/segmented_arc.h
@@ -54,7 +54,6 @@ private:
bool try_get_arc_(const circle& c, arc& target_arc);
std::string get_shape_gcode_(bool has_e, double e, double f) const;
circle arc_circle_;
- int test_count_ = 0;
double max_radius_mm_;
};
diff --git a/ArcWelder/segmented_shape.cpp b/ArcWelder/segmented_shape.cpp
index 312a7dc..cd5d808 100644
--- a/ArcWelder/segmented_shape.cpp
+++ b/ArcWelder/segmented_shape.cpp
@@ -227,18 +227,18 @@ point circle::get_closest_point(const point& p) const
#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)
{
- point p1 = c.get_closest_point(start_point);
- point p2 = c.get_closest_point(mid_point);
- point p3 = c.get_closest_point(end_point);
+ //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(p1);
- double polar_mid_theta = c.get_polar_radians(p2);
- double polar_end_theta = c.get_polar_radians(p3);
+ 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;
@@ -306,11 +306,7 @@ bool arc::try_create_arc(const circle& c, const array_list<point>& points, doubl
}
#pragma endregion
-segmented_shape::segmented_shape() : segmented_shape(DEFAULT_MIN_SEGMENTS, DEFAULT_MAX_SEGMENTS, DEFAULT_RESOLUTION_MM )
-{
-}
-
-segmented_shape::segmented_shape(int min_segments, int max_segments, double resolution_mm) : points_(max_segments)
+segmented_shape::segmented_shape(int min_segments = DEFAULT_MIN_SEGMENTS, int max_segments = DEFAULT_MAX_SEGMENTS, double resolution_mm = DEFAULT_RESOLUTION_MM) : points_(max_segments)
{
max_segments_ = max_segments;
diff --git a/ArcWelder/segmented_shape.h b/ArcWelder/segmented_shape.h
index 9ca480b..957ceab 100644
--- a/ArcWelder/segmented_shape.h
+++ b/ArcWelder/segmented_shape.h
@@ -174,7 +174,7 @@ double distance_from_segment(segment s, point p);
class segmented_shape
{
public:
- segmented_shape();
+
segmented_shape(int min_segments, int max_segments, double resolution_mm);
segmented_shape& operator=(const segmented_shape& pos);
virtual ~segmented_shape();
diff --git a/ArcWelder/unwritten_command.h b/ArcWelder/unwritten_command.h
index 5591dbe..5c6f151 100644
--- a/ArcWelder/unwritten_command.h
+++ b/ArcWelder/unwritten_command.h
@@ -31,20 +31,25 @@ struct unwritten_command
is_extruder_relative = false;
e_relative = 0;
offset_e = 0;
+ extrusion_length = 0;
}
- unwritten_command(parsed_command &cmd, bool is_relative) {
- is_relative = false;
+ unwritten_command(parsed_command &cmd, bool is_relative, double command_length) {
+ is_extruder_relative = is_relative;
command = cmd;
+ extrusion_length = command_length;
}
- unwritten_command(position* p) {
+ unwritten_command(position* p, double command_length) {
+
e_relative = p->get_current_extruder().e_relative;
offset_e = p->get_current_extruder().get_offset_e();
is_extruder_relative = p->is_extruder_relative;
command = p->command;
+ extrusion_length = command_length;
}
bool is_extruder_relative;
double e_relative;
double offset_e;
+ double extrusion_length;
parsed_command command;
std::string to_string(bool rewrite, std::string additional_comment)
diff --git a/ArcWelderConsole/ArcWelderConsole.cpp b/ArcWelderConsole/ArcWelderConsole.cpp
index ae31e10..b9cad50 100644
--- a/ArcWelderConsole/ArcWelderConsole.cpp
+++ b/ArcWelderConsole/ArcWelderConsole.cpp
@@ -112,7 +112,7 @@ int main(int argc, char* argv[])
log_level_string = log_level_arg.getValue();
log_level_value = -1;
- for (unsigned int log_name_index = 0; log_name_index < log_level_names.size(); log_name_index++)
+ for (unsigned int log_name_index = 0; log_name_index < log_level_names_size; log_name_index++)
{
if (log_level_string == log_level_names[log_name_index])
{
diff --git a/ArcWelderTest/ArcWelderTest.cpp b/ArcWelderTest/ArcWelderTest.cpp
index 8601ba6..b330d98 100644
--- a/ArcWelderTest/ArcWelderTest.cpp
+++ b/ArcWelderTest/ArcWelderTest.cpp
@@ -52,6 +52,7 @@ int run_tests(int argc, char* argv[])
{
std::cout << "Processing test run " << index + 1 << " of " << num_runs << ".\r\n";
TestAntiStutter(ANTI_STUTTER_TEST);
+ //TestParsingCase();
//TestDoubleToString();
//TestInverseProcessor();
//TestCircularBuffer();
@@ -240,10 +241,10 @@ static void TestAntiStutter(std::string filePath)
//logger_levels.push_back(log_levels::DEBUG);
logger_levels.push_back(log_levels::INFO);
logger* p_logger = new logger(logger_names, logger_levels);
- p_logger->set_log_level(INFO);
+ p_logger->set_log_level(VERBOSE);
//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(BENCHY_DIFFICULT, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, max_radius_mm, false, 50, on_progress);
+ arc_welder arc_welder_obj(BENCHY_L1_DIFFICULT, "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\test_output.gcode", p_logger, max_resolution, max_radius_mm, false, 50, on_progress);
//BENCHY_LAYER_1GCODE
//SMALL_TEST
//FACE_SHIELD
@@ -261,8 +262,9 @@ static void TestAntiStutter(std::string filePath)
//DIFFICULT_CURVES
//ISSUE_PRICKLYPEAR_LAYER_0_114
//BARBARIAN
- // Benchy_L1_Difficult
- arc_welder_obj.process();
+ // BENCHY_L1_DIFFICULT
+ arc_welder_results results = arc_welder_obj.process();
+ p_logger->log(0, INFO, results.progress.detail_str());
p_logger->log(0, INFO, "Processing Complete.");
delete p_logger;
}
@@ -288,3 +290,14 @@ void TestDoubleToString()
}
}
+
+static void TestParsingCase()
+{
+ gcode_parser parser;
+ //parsed_command command = parser.parse_gcode(" G0 X1 y2 ; test", true);
+ parsed_command command2 = parser.parse_gcode(" M73 P0 R93", true);
+ //parsed_command command2 = parser.parse_gcode("M204 P2000 R1500 T2000 ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2", true);
+ parsed_command command3 = parser.parse_gcode("G0 X1 y2; test", true);
+
+
+} \ No newline at end of file
diff --git a/ArcWelderTest/ArcWelderTest.h b/ArcWelderTest/ArcWelderTest.h
index 940c4aa..4ce0ccd 100644
--- a/ArcWelderTest/ArcWelderTest.h
+++ b/ArcWelderTest/ArcWelderTest.h
@@ -46,6 +46,7 @@ static gcode_position_args get_5_extruder_position_args();
static void TestAntiStutter(std::string filePath);
static bool on_progress(arc_welder_progress progress);
static void TestDoubleToString();
+static void TestParsingCase();
static std::string ANTI_STUTTER_TEST = "C:\\Users\\Brad\\Documents\\3DPrinter\\AntiStutter\\5x5_cylinder_2000Fn_0.2mm_PLA_MK2.5MMU2_4m.gcode";
diff --git a/GcodeProcessorLib/GcodeProcessorLib.vcxproj b/GcodeProcessorLib/GcodeProcessorLib.vcxproj
index ec6b6a7..0457545 100644
--- a/GcodeProcessorLib/GcodeProcessorLib.vcxproj
+++ b/GcodeProcessorLib/GcodeProcessorLib.vcxproj
@@ -129,7 +129,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
diff --git a/GcodeProcessorLib/gcode_parser.cpp b/GcodeProcessorLib/gcode_parser.cpp
index a4e7d0a..b12b4e9 100644
--- a/GcodeProcessorLib/gcode_parser.cpp
+++ b/GcodeProcessorLib/gcode_parser.cpp
@@ -104,14 +104,25 @@ gcode_parser::~gcode_parser()
parsed_command gcode_parser::parse_gcode(const char * gcode)
{
+ parsed_command p_cmd;
+ try_parse_gcode(gcode, p_cmd, true);
+ return p_cmd;
+}
+parsed_command gcode_parser::parse_gcode(const char* gcode, bool preserve_format)
+{
parsed_command p_cmd;
- try_parse_gcode(gcode, p_cmd);
+ try_parse_gcode(gcode, p_cmd, preserve_format);
return p_cmd;
}
+
+bool gcode_parser::try_parse_gcode(const char* gcode, parsed_command& command)
+{
+ return try_parse_gcode(gcode, command, true) ;
+}
// Superfast gcode parser - v2
-bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command)
+bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command, bool preserve_format)
{
// Create a command
char * p_gcode = const_cast<char *>(gcode);
@@ -130,6 +141,9 @@ bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command)
command.is_empty = false;
break;
}
+ else if (preserve_format) {
+ command.gcode.push_back(c);
+ }
p_gcode++;
}
command.command = "";
@@ -138,6 +152,9 @@ bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command)
command.is_empty = false;
bool has_seen_character = false;
+
+ bool is_text_only_parameter = text_only_functions_.find(command.command) != text_only_functions_.end();
+
while (true)
{
char cur_char = *p_gcode;
@@ -145,23 +162,25 @@ bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command)
break;
else if (cur_char > 32 || (cur_char == ' ' && has_seen_character))
{
- if (cur_char >= 'a' && cur_char <= 'z')
+ if (!preserve_format && !is_text_only_parameter && (cur_char >= 'a' && cur_char <= 'z'))
command.gcode.push_back(cur_char - 32);
else
command.gcode.push_back(cur_char);
has_seen_character = true;
}
+ else if (preserve_format)
+ {
+ command.gcode.push_back(cur_char);
+ }
p_gcode++;
}
- command.gcode = utilities::rtrim(command.gcode);
+ if (!preserve_format){
+ command.gcode = utilities::rtrim(command.gcode);
+ }
- if (command.is_known_command)
+ if (command.is_known_command && parsable_commands_.find(command.command) != parsable_commands_.end())
{
- if (parsable_commands_.find(command.command) == parsable_commands_.end())
- {
- return true;
- }
if (command.command.length() > 0 && command.command == "@OCTOLAPSE")
{
@@ -188,7 +207,7 @@ bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command)
}
else if (
- text_only_functions_.find(command.command) != text_only_functions_.end() ||
+ is_text_only_parameter ||
(
command.command.length() > 0 && command.command[0] == '@'
)
@@ -232,6 +251,7 @@ bool gcode_parser::try_parse_gcode(const char * gcode, parsed_command & command)
}
}
}
+
try_extract_comment(&p_gcode, &(command.comment));
diff --git a/GcodeProcessorLib/gcode_parser.h b/GcodeProcessorLib/gcode_parser.h
index 50cb01b..714dfe4 100644
--- a/GcodeProcessorLib/gcode_parser.h
+++ b/GcodeProcessorLib/gcode_parser.h
@@ -35,7 +35,9 @@ public:
gcode_parser();
~gcode_parser();
bool try_parse_gcode(const char * gcode, parsed_command & command);
+ bool try_parse_gcode(const char* gcode, parsed_command& command, bool preserve_format);
parsed_command parse_gcode(const char * gcode);
+ parsed_command parse_gcode(const char* gcode, bool preserve_format);
private:
gcode_parser(const gcode_parser &source);
// Variables and lookups
diff --git a/GcodeProcessorLib/logger.cpp b/GcodeProcessorLib/logger.cpp
index 0118e52..8511777 100644
--- a/GcodeProcessorLib/logger.cpp
+++ b/GcodeProcessorLib/logger.cpp
@@ -19,7 +19,9 @@
// You can contact the author at the following email address:
// FormerLurker@pm.me
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
+#if _MSC_VER > 1200
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
#include "logger.h"
logger::logger(std::vector<std::string> names, std::vector<int> levels) {
// set to true by default, but can be changed by inheritance to support mandatory innitialization (for python or other integrations)
@@ -89,20 +91,8 @@ void logger::create_log_message(const int logger_type, const int log_level, cons
// example message
// 2020-04-20 21:36:59,414 - arc_welder.__init__ - INFO - MESSAGE_GOES_HERE
- // Create the time string in YYYY-MM-DD HH:MM:SS format
- std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
- std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
- const time_t now_time = std::chrono::system_clock::to_time_t(now);
- struct tm tstruct;
- char buf[25];
- tstruct = *localtime(&now_time);
- // DOESN'T WORK WITH ALL COMPILERS...
- //localtime_s(&tstruct, &now_time);
- strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.", &tstruct);
- output = buf;
- std::string s_miliseconds = std::to_string(ms.count());
- // Add the milliseconds, padded with 0s, to the output
- output.append(std::string(3 - s_miliseconds.length(), '0') + s_miliseconds);
+ // Create the time string in YYYY-MM-DD HH:MM:SS.ms format
+ logger::get_timestamp(output);
// Add a spacer
output.append(" - ");
// Add the logger name
@@ -148,3 +138,46 @@ void logger::log(const int logger_type, const int log_level, const std::string&
std::cout.flush();
}
+
+void logger::get_timestamp(std::string &timestamp)
+{
+ std::time_t rawtime;
+ std::tm* timeinfo;
+ char buffer[80];
+
+ std::time(&rawtime);
+ timeinfo = std::localtime(&rawtime);
+ std::strftime(buffer, 80, "%Y-%m-%d %H:%M:%S.", timeinfo);
+
+ timestamp = buffer;
+ clock_t t = std::clock();
+ int ms = static_cast<int>((t / CLOCKS_PER_MS)) % 1000;
+
+ std::string s_miliseconds;
+ sprintf(buffer, "%d", ms) ;// std::to_string(ms);
+ s_miliseconds = buffer;
+ timestamp.append(std::string(3 - s_miliseconds.length(), '0') + s_miliseconds);
+
+}
+
+/*
+
+Severity Code Description Project File Line Suppression State
+
+
+
+std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
+ std::chrono::milliseconds ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
+ const time_t now_time = std::chrono::system_clock::to_time_t(now);
+ struct tm tstruct;
+ char buf[25];
+ tstruct = *localtime(&now_time);
+ // DOESN'T WORK WITH ALL COMPILERS...
+ //localtime_s(&tstruct, &now_time);
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.", &tstruct);
+ output = buf;
+ std::string s_miliseconds = std::to_string(ms.count());
+ // Add the milliseconds, padded with 0s, to the output
+ output.append(std::string(3 - s_miliseconds.length(), '0') + s_miliseconds);
+
+*/ \ No newline at end of file
diff --git a/GcodeProcessorLib/logger.h b/GcodeProcessorLib/logger.h
index c681674..9db2df1 100644
--- a/GcodeProcessorLib/logger.h
+++ b/GcodeProcessorLib/logger.h
@@ -25,12 +25,16 @@
#include <vector>
#include <cstdarg>
#include <stdio.h>
-#include <chrono>
+#include <ctime>
+//#include <chrono>
#include <array>
#define LOG_LEVEL_COUNT 7
+#define CLOCKS_PER_MS (CLOCKS_PER_SEC / 1000.0)
enum log_levels { NOSET, VERBOSE, DEBUG, INFO, WARNING , ERROR, CRITICAL};
-const std::array<std::string, 7> log_level_names = { {"NOSET", "VERBOSE", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} };
+//const std::array<std::string, 7> log_level_names = { {"NOSET", "VERBOSE", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} };
+static const int log_level_names_size = 7;
+static const char* log_level_names[] = {"NOSET", "VERBOSE", "DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"};
const static int log_level_values[LOG_LEVEL_COUNT] = { 0, 5, 10, 20, 30, 40, 50};
class logger
@@ -59,6 +63,7 @@ private:
std::string* logger_names_;
int * logger_levels_;
int num_loggers_;
+ static void get_timestamp(std::string &timestamp);
};
diff --git a/GcodeProcessorLib/utilities.cpp b/GcodeProcessorLib/utilities.cpp
index 5e90768..0af96a9 100644
--- a/GcodeProcessorLib/utilities.cpp
+++ b/GcodeProcessorLib/utilities.cpp
@@ -23,6 +23,7 @@
#include <cmath>
#include <sstream>
#include <iostream>
+#include <iomanip>
// Had to increase the zero tolerance because prusa slicer doesn't always retract enough while wiping.
const double ZERO_TOLERANCE = 0.000005;
@@ -123,6 +124,13 @@ std::string utilities::to_string(double value)
return os.str();
}
+std::string utilities::to_string(int value)
+{
+ std::ostringstream os;
+ os << value;
+ return os.str();
+}
+
char * utilities::to_string(double value, unsigned short precision, char * str)
{
char reversed_int[20];
@@ -219,3 +227,60 @@ 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 difference = width - input_width;
+ if (difference < 1)
+ {
+ return input;
+ }
+ int left_padding = difference /2;
+ int right_padding = width - left_padding - input_width;
+ return std::string(left_padding, ' ') + input + std::string(right_padding, ' ');
+}
+
+std::string utilities::get_percent_change_string(int v1, int v2, int precision)
+{
+ std::stringstream format_stream;
+ format_stream.str(std::string());
+ std::string percent_change_string;
+ if (v1 == 0)
+ {
+ if (v2 > 0)
+ {
+ format_stream << "INF";
+ }
+ else
+ {
+ format_stream << std::fixed << std::setprecision(1) << 0.0 << "%";
+ }
+ }
+ else
+ {
+ double percent_change = (((double)v2 - (double)v1) / (double)v1) * 100.0;
+ format_stream << std::fixed << std::setprecision(precision) << percent_change << "%";
+ }
+ return format_stream.str();
+}
+
+int utilities::get_num_digits(int x)
+{
+ x = abs(x);
+ return (x < 10 ? 1 :
+ (x < 100 ? 2 :
+ (x < 1000 ? 3 :
+ (x < 10000 ? 4 :
+ (x < 100000 ? 5 :
+ (x < 1000000 ? 6 :
+ (x < 10000000 ? 7 :
+ (x < 100000000 ? 8 :
+ (x < 1000000000 ? 9 :
+ 10)))))))));
+}
+
+int utilities::get_num_digits(double x)
+{
+ return get_num_digits((int) x);
+}
diff --git a/GcodeProcessorLib/utilities.h b/GcodeProcessorLib/utilities.h
index db858ad..a6ddbd2 100644
--- a/GcodeProcessorLib/utilities.h
+++ b/GcodeProcessorLib/utilities.h
@@ -44,12 +44,17 @@ public:
static double get_cartesian_distance(double x1, double y1, double x2, double y2);
static double get_cartesian_distance(double x1, double y1, double z1, double x2, double y2, double z2);
static std::string to_string(double value);
+ static std::string to_string(int value);
static char* to_string(double value, unsigned short precision, char* str);
static std::string ltrim(const std::string& s);
static std::string rtrim(const std::string& s);
static std::string trim(const std::string& s);
static std::istream& safe_get_line(std::istream& is, std::string& t);
-
+ static std::string center(std::string input, int width);
+ static std::string get_percent_change_string(int v1, int v2, int precision);
+
+ static int get_num_digits(int x);
+ static int get_num_digits(double x);
protected:
static const std::string WHITESPACE_;
private:
diff --git a/PyArcWelder/py_arc_welder.cpp b/PyArcWelder/py_arc_welder.cpp
index 302aa95..0eacf39 100644
--- a/PyArcWelder/py_arc_welder.cpp
+++ b/PyArcWelder/py_arc_welder.cpp
@@ -22,35 +22,55 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "py_arc_welder.h"
-
-PyObject* py_arc_welder::build_py_progress(arc_welder_progress progress)
+PyObject* py_arc_welder::build_py_progress(const arc_welder_progress& progress)
{
- PyObject* py_progress = Py_BuildValue("{s:d,s:d,s:d,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:f,s:f}",
- u8"percent_complete",
- progress.percent_complete,
- u8"seconds_elapsed",
- progress.seconds_elapsed,
- u8"seconds_remaining",
- progress.seconds_remaining,
- u8"gcodes_processed",
- progress.gcodes_processed,
- u8"lines_processed",
- progress.lines_processed,
- u8"points_compressed",
- progress.points_compressed,
- u8"arcs_created",
- progress.arcs_created,
- u8"source_file_position",
- progress.source_file_position,
- u8"source_file_size",
- progress.source_file_size,
- u8"target_file_size",
- progress.target_file_size,
- u8"compression_ratio",
- progress.compression_ratio,
- u8"compression_percent",
- progress.compression_percent
+ std::string segment_statistics = progress.segment_statistics.str();
+ PyObject* pyMessage = gcode_arc_converter::PyUnicode_SafeFromString(segment_statistics);
+ if (pyMessage == NULL)
+ return NULL;
+ PyObject* py_progress = Py_BuildValue("{s:d,s:d,s:d,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:f,s:f,s:f,s:f,s:i,s:i}",
+ "percent_complete",
+ progress.percent_complete, //1
+ "seconds_elapsed",
+ progress.seconds_elapsed, //2
+ "seconds_remaining",
+ progress.seconds_remaining, //3
+ "gcodes_processed",
+ progress.gcodes_processed, //4
+ "lines_processed",
+ progress.lines_processed, //5
+ "points_compressed",
+ progress.points_compressed, //6
+ "arcs_created",
+ progress.arcs_created, //7
+ "source_file_position",
+ progress.source_file_position, //8
+ "source_file_size",
+ progress.source_file_size, //9
+ "target_file_size",
+ progress.target_file_size, //10
+ "compression_ratio",
+ progress.compression_ratio, //11
+ "compression_percent",
+ progress.compression_percent, //12
+ "source_file_total_length",
+ progress.segment_statistics.total_length_source, //13
+ "target_file_total_length",
+ progress.segment_statistics.total_length_target, //14
+ "source_file_total_count",
+ progress.segment_statistics.total_count_source, //15
+ "target_file_total_count",
+ progress.segment_statistics.total_length_target //16
);
+
+ if (py_progress == NULL)
+ {
+ return NULL;
+ }
+ // Due to a CRAZY issue, I have to add this item after building the py_progress object,
+ // else it crashes in python 2.7. Looking forward to retiring this backwards
+ // compatible code...
+ PyDict_SetItemString(py_progress, "segment_statistics_text", pyMessage);
return py_progress;
}
@@ -58,12 +78,14 @@ bool py_arc_welder::on_progress_(const arc_welder_progress& progress)
{
PyObject* py_dict = py_arc_welder::build_py_progress(progress);
if (py_dict == NULL)
+ {
return false;
+ }
PyObject* func_args = Py_BuildValue("(O)", py_dict);
if (func_args == NULL)
{
Py_DECREF(py_dict);
- return true;
+ return false; // This was returning true, I think it was a typo. Making a note just in case.
}
PyGILState_STATE gstate = PyGILState_Ensure();
diff --git a/PyArcWelder/py_arc_welder.h b/PyArcWelder/py_arc_welder.h
index ef56715..1b70980 100644
--- a/PyArcWelder/py_arc_welder.h
+++ b/PyArcWelder/py_arc_welder.h
@@ -41,7 +41,7 @@ public:
virtual ~py_arc_welder() {
}
- static PyObject* build_py_progress(arc_welder_progress progress);
+ static PyObject* build_py_progress(const arc_welder_progress& progress);
protected:
virtual bool on_progress_(const arc_welder_progress& progress);
private:
diff --git a/PyArcWelder/py_arc_welder_extension.cpp b/PyArcWelder/py_arc_welder_extension.cpp
index 07f9dfc..ea24f59 100644
--- a/PyArcWelder/py_arc_welder_extension.cpp
+++ b/PyArcWelder/py_arc_welder_extension.cpp
@@ -202,13 +202,13 @@ extern "C"
PyObject* p_results = Py_BuildValue(
"{s:i,s:i,s:s,s:O}",
- u8"success",
+ "success",
results.success,
- u8"cancelled",
+ "cancelled",
results.cancelled,
- u8"message",
+ "message",
results.message.c_str(),
- u8"progress",
+ "progress",
p_progress
);
return p_results;