mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 01:01:15 -06:00
Merge branch 'lm_gizmos' into lm_fdm_supports_gizmo
This commit is contained in:
commit
a380053a17
227 changed files with 28690 additions and 16849 deletions
|
|
@ -577,7 +577,7 @@ void _arrange(
|
|||
std::function<bool()> stopfn)
|
||||
{
|
||||
// Integer ceiling the min distance from the bed perimeters
|
||||
coord_t md = minobjd - 2 * scaled(0.1 + EPSILON);
|
||||
coord_t md = minobjd;
|
||||
md = (md % 2) ? md / 2 + 1 : md / 2;
|
||||
|
||||
auto corrected_bin = bin;
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ add_library(libslic3r STATIC
|
|||
Fill/FillRectilinear3.hpp
|
||||
Flow.cpp
|
||||
Flow.hpp
|
||||
format.hpp
|
||||
Format/3mf.cpp
|
||||
Format/3mf.hpp
|
||||
Format/AMF.cpp
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "Config.hpp"
|
||||
#include "format.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <assert.h>
|
||||
#include <fstream>
|
||||
|
|
@ -464,7 +465,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
|
|||
void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append)
|
||||
{
|
||||
if (! this->set_deserialize_nothrow(opt_key_src, value_src, append))
|
||||
throw BadOptionTypeException("ConfigBase::set_deserialize() failed");
|
||||
throw BadOptionTypeException(format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"", opt_key_src, value_src));
|
||||
}
|
||||
|
||||
void ConfigBase::set_deserialize(std::initializer_list<SetDeserializeItem> items)
|
||||
|
|
@ -620,7 +621,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file)
|
|||
|
||||
size_t key_value_pairs = load_from_gcode_string(data.data());
|
||||
if (key_value_pairs < 80)
|
||||
throw std::runtime_error((boost::format("Suspiciously low number of configuration values extracted from %1%: %2%") % file % key_value_pairs).str());
|
||||
throw std::runtime_error(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs));
|
||||
}
|
||||
|
||||
// Load the config keys from the given string.
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
#include "Point.hpp"
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/format/format_fwd.hpp>
|
||||
#include <boost/property_tree/ptree_fwd.hpp>
|
||||
|
||||
#include <cereal/access.hpp>
|
||||
#include <cereal/types/base_class.hpp>
|
||||
|
|
@ -56,10 +56,9 @@ public:
|
|||
class BadOptionTypeException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
BadOptionTypeException() :
|
||||
std::runtime_error("Bad option type exception") {}
|
||||
BadOptionTypeException(const char* message) :
|
||||
std::runtime_error(message) {}
|
||||
BadOptionTypeException() : std::runtime_error("Bad option type exception") {}
|
||||
BadOptionTypeException(const std::string &message) : std::runtime_error(message) {}
|
||||
BadOptionTypeException(const char* message) : std::runtime_error(message) {}
|
||||
};
|
||||
|
||||
// Type of a configuration value.
|
||||
|
|
|
|||
|
|
@ -218,10 +218,10 @@ public:
|
|||
bbox.min /= m_resolution;
|
||||
bbox.max /= m_resolution;
|
||||
// Trim with the cells.
|
||||
bbox.min.x() = std::max(bbox.min.x(), 0);
|
||||
bbox.min.y() = std::max(bbox.min.y(), 0);
|
||||
bbox.max.x() = std::min(bbox.max.x(), (coord_t)m_cols - 1);
|
||||
bbox.max.y() = std::min(bbox.max.y(), (coord_t)m_rows - 1);
|
||||
bbox.min.x() = std::max<coord_t>(bbox.min.x(), 0);
|
||||
bbox.min.y() = std::max<coord_t>(bbox.min.y(), 0);
|
||||
bbox.max.x() = std::min<coord_t>(bbox.max.x(), (coord_t)m_cols - 1);
|
||||
bbox.max.y() = std::min<coord_t>(bbox.max.y(), (coord_t)m_rows - 1);
|
||||
for (coord_t iy = bbox.min.y(); iy <= bbox.max.y(); ++ iy)
|
||||
for (coord_t ix = bbox.min.x(); ix <= bbox.max.x(); ++ ix)
|
||||
if (! visitor(iy, ix))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "Extruder.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@
|
|||
|
||||
#include "libslic3r.h"
|
||||
#include "Point.hpp"
|
||||
#include "PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class GCodeConfig;
|
||||
|
||||
class Extruder
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public:
|
|||
~ExtrusionEntityCollection() { clear(); }
|
||||
explicit operator ExtrusionPaths() const;
|
||||
|
||||
bool is_collection() const { return true; }
|
||||
bool is_collection() const override { return true; }
|
||||
ExtrusionRole role() const override {
|
||||
ExtrusionRole out = erNone;
|
||||
for (const ExtrusionEntity *ee : entities) {
|
||||
|
|
@ -49,7 +49,7 @@ public:
|
|||
}
|
||||
return out;
|
||||
}
|
||||
bool can_reverse() const { return !this->no_sort; }
|
||||
bool can_reverse() const override { return !this->no_sort; }
|
||||
bool empty() const { return this->entities.empty(); }
|
||||
void clear();
|
||||
void swap (ExtrusionEntityCollection &c);
|
||||
|
|
@ -83,9 +83,9 @@ public:
|
|||
static ExtrusionEntityCollection chained_path_from(const ExtrusionEntitiesPtr &extrusion_entities, const Point &start_near, ExtrusionRole role = erMixed);
|
||||
ExtrusionEntityCollection chained_path_from(const Point &start_near, ExtrusionRole role = erMixed) const
|
||||
{ return this->no_sort ? *this : chained_path_from(this->entities, start_near, role); }
|
||||
void reverse();
|
||||
const Point& first_point() const { return this->entities.front()->first_point(); }
|
||||
const Point& last_point() const { return this->entities.back()->last_point(); }
|
||||
void reverse() override;
|
||||
const Point& first_point() const override { return this->entities.front()->first_point(); }
|
||||
const Point& last_point() const override { return this->entities.back()->last_point(); }
|
||||
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
|
||||
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
|
||||
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const override;
|
||||
|
|
@ -102,11 +102,11 @@ public:
|
|||
/// You should be iterating over flatten().entities if you are interested in the underlying ExtrusionEntities (and don't care about hierarchy).
|
||||
/// \param preserve_ordering Flag to method that will flatten if and only if the underlying collection is sortable when True (default: False).
|
||||
ExtrusionEntityCollection flatten(bool preserve_ordering = false) const;
|
||||
double min_mm3_per_mm() const;
|
||||
double min_mm3_per_mm() const override;
|
||||
double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; }
|
||||
|
||||
// Following methods shall never be called on an ExtrusionEntityCollection.
|
||||
Polyline as_polyline() const {
|
||||
Polyline as_polyline() const override {
|
||||
throw std::runtime_error("Calling as_polyline() on a ExtrusionEntityCollection");
|
||||
return Polyline();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
if (surface.surface_type == stInternalVoid)
|
||||
has_internal_voids = true;
|
||||
else {
|
||||
FlowRole extrusion_role = (surface.surface_type == stTop) ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||
FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
|
||||
bool is_bridge = layer.id() > 0 && surface.is_bridge();
|
||||
params.extruder = layerm.region()->extruder(extrusion_role);
|
||||
params.pattern = layerm.region()->config().fill_pattern.value;
|
||||
|
|
@ -132,7 +132,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
|
|||
is_bridge ?
|
||||
erBridgeInfill :
|
||||
(surface.is_solid() ?
|
||||
((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) :
|
||||
(surface.is_top() ? erTopSolidInfill : erSolidInfill) :
|
||||
erInternalInfill);
|
||||
params.bridge_angle = float(surface.bridge_angle);
|
||||
params.angle = float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
#include "../Utils.hpp"
|
||||
#include "../GCode.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "../GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include "../I18N.hpp"
|
||||
|
||||
|
|
@ -47,9 +45,7 @@ const std::string MODEL_EXTENSION = ".model";
|
|||
const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
|
||||
const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
|
||||
const std::string RELATIONSHIPS_FILE = "_rels/.rels";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
const std::string THUMBNAIL_FILE = "Metadata/thumbnail.png";
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
|
||||
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
|
||||
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
|
||||
|
|
@ -1969,22 +1965,12 @@ namespace Slic3r {
|
|||
bool m_fullpath_sources{ true };
|
||||
|
||||
public:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
bool save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data);
|
||||
#else
|
||||
bool _save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
|
||||
bool _add_model_file_to_archive(mz_zip_archive& archive, const Model& model, IdToObjectDataMap &objects_data);
|
||||
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items, VolumeToOffsetsMap& volumes_offsets);
|
||||
|
|
@ -1999,26 +1985,14 @@ namespace Slic3r {
|
|||
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||
};
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
{
|
||||
clear_errors();
|
||||
m_fullpath_sources = fullpath_sources;
|
||||
return _save_model_to_file(filename, model, config, thumbnail_data);
|
||||
}
|
||||
#else
|
||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
{
|
||||
clear_errors();
|
||||
return _save_model_to_file(filename, model, config);
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config, const ThumbnailData* thumbnail_data)
|
||||
#else
|
||||
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const DynamicPrintConfig* config)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
|
@ -2037,7 +2011,6 @@ namespace Slic3r {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
if ((thumbnail_data != nullptr) && thumbnail_data->is_valid())
|
||||
{
|
||||
// Adds the file Metadata/thumbnail.png.
|
||||
|
|
@ -2048,7 +2021,6 @@ namespace Slic3r {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Adds relationships file ("_rels/.rels").
|
||||
// The content of this file is the same for each PrusaSlicer 3mf.
|
||||
|
|
@ -2160,9 +2132,7 @@ namespace Slic3r {
|
|||
stream << "<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n";
|
||||
stream << " <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\" />\n";
|
||||
stream << " <Default Extension=\"model\" ContentType=\"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\" />\n";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << " <Default Extension=\"png\" ContentType=\"image/png\" />\n";
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << "</Types>";
|
||||
|
||||
std::string out = stream.str();
|
||||
|
|
@ -2176,7 +2146,6 @@ namespace Slic3r {
|
|||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool _3MF_Exporter::_add_thumbnail_file_to_archive(mz_zip_archive& archive, const ThumbnailData& thumbnail_data)
|
||||
{
|
||||
bool res = false;
|
||||
|
|
@ -2194,7 +2163,6 @@ namespace Slic3r {
|
|||
|
||||
return res;
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive)
|
||||
{
|
||||
|
|
@ -2202,9 +2170,7 @@ namespace Slic3r {
|
|||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n";
|
||||
stream << " <Relationship Target=\"/" << MODEL_FILE << "\" Id=\"rel-1\" Type=\"http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel\" />\n";
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << " <Relationship Target=\"/" << THUMBNAIL_FILE << "\" Id=\"rel-2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail\" />\n";
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
stream << "</Relationships>";
|
||||
|
||||
std::string out = stream.str();
|
||||
|
|
@ -2795,22 +2761,13 @@ bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool c
|
|||
return res;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data)
|
||||
#else
|
||||
bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr))
|
||||
return false;
|
||||
|
||||
_3MF_Exporter exporter;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources, thumbnail_data);
|
||||
#else
|
||||
bool res = exporter.save_model_to_file(path, *model, config, fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
if (!res)
|
||||
exporter.log_errors();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,20 +26,14 @@ namespace Slic3r {
|
|||
|
||||
class Model;
|
||||
class DynamicPrintConfig;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
struct ThumbnailData;
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Load the content of a 3mf file into the given model and preset bundle.
|
||||
extern bool load_3mf(const char* path, DynamicPrintConfig* config, Model* model, bool check_version);
|
||||
|
||||
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources, const ThumbnailData* thumbnail_data = nullptr);
|
||||
#else
|
||||
extern bool store_3mf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,7 @@
|
|||
#include <boost/foreach.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include <boost/beast/core/detail/base64.hpp>
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
|
|
@ -631,13 +629,16 @@ std::vector<GCode::LayerToPrint> GCode::collect_layers_to_print(const PrintObjec
|
|||
// Negative support_contact_z is not taken into account, it can result in false positives in cases
|
||||
// where previous layer has object extrusions too (https://github.com/prusa3d/PrusaSlicer/issues/2752)
|
||||
|
||||
// Only check this layer in case it has some extrusions.
|
||||
bool has_extrusions = (layer_to_print.object_layer && layer_to_print.object_layer->has_extrusions())
|
||||
|| (layer_to_print.support_layer && layer_to_print.support_layer->has_extrusions());
|
||||
|
||||
if (layer_to_print.print_z() > maximal_print_z + 2. * EPSILON)
|
||||
if (has_extrusions && layer_to_print.print_z() > maximal_print_z + 2. * EPSILON)
|
||||
throw std::runtime_error(_(L("Empty layers detected, the output would not be printable.")) + "\n\n" +
|
||||
_(L("Object name")) + ": " + object.model_object()->name + "\n" + _(L("Print z")) + ": " +
|
||||
std::to_string(layers_to_print.back().print_z()) + "\n\n" + _(L("This is "
|
||||
"usually caused by negligibly small extrusions or by a faulty model. Try to repair "
|
||||
" the model or change its orientation on the bed.")));
|
||||
"the model or change its orientation on the bed.")));
|
||||
// Remember last layer with extrusions.
|
||||
last_extrusion_layer = &layers_to_print.back();
|
||||
}
|
||||
|
|
@ -697,11 +698,7 @@ std::vector<std::pair<coordf_t, std::vector<GCode::LayerToPrint>>> GCode::collec
|
|||
return layers_to_print;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::do_export(Print* print, const char* path, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_data)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
PROFILE_CLEAR();
|
||||
|
||||
|
|
@ -727,11 +724,7 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
|
||||
try {
|
||||
m_placeholder_parser_failed_templates.clear();
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
this->_do_export(*print, file, thumbnail_cb);
|
||||
#else
|
||||
this->_do_export(*print, file);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
fflush(file);
|
||||
if (ferror(file)) {
|
||||
fclose(file);
|
||||
|
|
@ -971,7 +964,6 @@ namespace DoExport {
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
template<typename WriteToOutput, typename ThrowIfCanceledCallback>
|
||||
static void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector<Vec2d> &sizes, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled)
|
||||
{
|
||||
|
|
@ -1015,7 +1007,6 @@ namespace DoExport {
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Fill in print_statistics and return formatted string containing filament statistics to be inserted into G-code comment section.
|
||||
static std::string update_print_stats_and_format_filament_stats(
|
||||
|
|
@ -1121,11 +1112,7 @@ std::vector<const PrintInstance*> sort_object_instances_by_model_order(const Pri
|
|||
return instances;
|
||||
}
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
void GCode::_do_export(Print& print, FILE* file)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
|
|
@ -2876,11 +2863,12 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string description, dou
|
|||
std::string GCode::extrude_perimeters(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region, std::unique_ptr<EdgeGrid::Grid> &lower_layer_edge_grid)
|
||||
{
|
||||
std::string gcode;
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
for (const ExtrusionEntity *ee : region.perimeters)
|
||||
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
|
||||
}
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||
if (! region.perimeters.empty()) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
for (const ExtrusionEntity *ee : region.perimeters)
|
||||
gcode += this->extrude_entity(*ee, "perimeter", -1., &lower_layer_edge_grid);
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
|
@ -2888,19 +2876,20 @@ std::string GCode::extrude_perimeters(const Print &print, const std::vector<Obje
|
|||
std::string GCode::extrude_infill(const Print &print, const std::vector<ObjectByExtruder::Island::Region> &by_region)
|
||||
{
|
||||
std::string gcode;
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
ExtrusionEntitiesPtr extrusions { region.infills };
|
||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||
for (const ExtrusionEntity *fill : extrusions) {
|
||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||
if (eec) {
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
||||
gcode += this->extrude_entity(*ee, "infill");
|
||||
} else
|
||||
gcode += this->extrude_entity(*fill, "infill");
|
||||
for (const ObjectByExtruder::Island::Region ®ion : by_region)
|
||||
if (! region.infills.empty()) {
|
||||
m_config.apply(print.regions()[®ion - &by_region.front()]->config());
|
||||
ExtrusionEntitiesPtr extrusions { region.infills };
|
||||
chain_and_reorder_extrusion_entities(extrusions, &m_last_pos);
|
||||
for (const ExtrusionEntity *fill : extrusions) {
|
||||
auto *eec = dynamic_cast<const ExtrusionEntityCollection*>(fill);
|
||||
if (eec) {
|
||||
for (ExtrusionEntity *ee : eec->chained_path_from(m_last_pos).entities)
|
||||
gcode += this->extrude_entity(*ee, "infill");
|
||||
} else
|
||||
gcode += this->extrude_entity(*fill, "infill");
|
||||
}
|
||||
}
|
||||
}
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
|
@ -3366,17 +3355,18 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
|
|||
has_overrides = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Data is cleared, but the memory is not.
|
||||
by_region_per_copy_cache.clear();
|
||||
|
||||
if (! has_overrides)
|
||||
// Simple case. No need to copy the regions.
|
||||
return this->by_region;
|
||||
return wiping_entities ? by_region_per_copy_cache : this->by_region;
|
||||
|
||||
// Complex case. Some of the extrusions of some object instances are to be printed first - those are the wiping extrusions.
|
||||
// Some of the extrusions of some object instances are printed later - those are the clean print extrusions.
|
||||
// Filter out the extrusions based on the infill_overrides / perimeter_overrides:
|
||||
|
||||
// Data is cleared, but the memory is not.
|
||||
by_region_per_copy_cache.clear();
|
||||
|
||||
for (const auto& reg : by_region) {
|
||||
by_region_per_copy_cache.emplace_back(); // creates a region in the newly created Island
|
||||
|
||||
|
|
@ -3437,15 +3427,17 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
|
|||
|
||||
// First we append the entities, there are eec->entities.size() of them:
|
||||
size_t old_size = perimeters_or_infills->size();
|
||||
perimeters_or_infills->reserve(perimeters_or_infills->size() + eec->entities.size());
|
||||
size_t new_size = old_size + eec->entities.size();
|
||||
perimeters_or_infills->reserve(new_size);
|
||||
for (auto* ee : eec->entities)
|
||||
perimeters_or_infills->emplace_back(ee);
|
||||
|
||||
if (copies_extruder != nullptr) {
|
||||
perimeters_or_infills_overrides->reserve(old_size + eec->entities.size());
|
||||
perimeters_or_infills_overrides->resize(old_size, nullptr);
|
||||
for (unsigned int i = 0; i < eec->entities.size(); ++ i)
|
||||
perimeters_or_infills_overrides->emplace_back(copies_extruder);
|
||||
// Don't reallocate overrides if not needed.
|
||||
// Missing overrides are implicitely considered non-overridden.
|
||||
perimeters_or_infills_overrides->reserve(new_size);
|
||||
perimeters_or_infills_overrides->resize(old_size, nullptr);
|
||||
perimeters_or_infills_overrides->resize(new_size, copies_extruder);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@
|
|||
#include "GCodeTimeEstimator.hpp"
|
||||
#include "EdgeGrid.hpp"
|
||||
#include "GCode/Analyzer.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -166,11 +164,7 @@ public:
|
|||
|
||||
// throws std::runtime_exception on error,
|
||||
// throws CanceledException through print->throw_if_canceled().
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void do_export(Print* print, const char* path, GCodePreviewData* preview_data = nullptr, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||
const Vec2d& origin() const { return m_origin; }
|
||||
|
|
@ -210,11 +204,7 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
void _do_export(Print &print, FILE *file, ThumbnailsGeneratorCallback thumbnail_cb);
|
||||
#else
|
||||
void _do_export(Print &print, FILE *file);
|
||||
#endif //ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
static std::vector<LayerToPrint> collect_layers_to_print(const PrintObject &object);
|
||||
static std::vector<std::pair<coordf_t, std::vector<LayerToPrint>>> collect_layers_to_print(const Print &print);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ static const float INCHES_TO_MM = 25.4f;
|
|||
static const float DEFAULT_FEEDRATE = 0.0f;
|
||||
static const unsigned int DEFAULT_EXTRUDER_ID = 0;
|
||||
static const unsigned int DEFAULT_COLOR_PRINT_ID = 0;
|
||||
static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f);
|
||||
static const Slic3r::Vec3f DEFAULT_START_POSITION = Slic3r::Vec3f::Zero();
|
||||
static const float DEFAULT_START_EXTRUSION = 0.0f;
|
||||
static const float DEFAULT_FAN_SPEED = 0.0f;
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ const std::string GCodeAnalyzer::Pause_Print_Tag = "_ANALYZER_PAUSE_PRINT";
|
|||
const std::string GCodeAnalyzer::Custom_Code_Tag = "_ANALYZER_CUSTOM_CODE";
|
||||
const std::string GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag = "_ANALYZER_END_PAUSE_PRINT_OR_CUSTOM_CODE";
|
||||
|
||||
const double GCodeAnalyzer::Default_mm3_per_mm = 0.0;
|
||||
const float GCodeAnalyzer::Default_mm3_per_mm = 0.0f;
|
||||
const float GCodeAnalyzer::Default_Width = 0.0f;
|
||||
const float GCodeAnalyzer::Default_Height = 0.0f;
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ GCodeAnalyzer::Metadata::Metadata()
|
|||
{
|
||||
}
|
||||
|
||||
GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id/* = 0*/)
|
||||
GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id/* = 0*/)
|
||||
: extrusion_role(extrusion_role)
|
||||
, extruder_id(extruder_id)
|
||||
, mm3_per_mm(mm3_per_mm)
|
||||
|
|
@ -90,7 +90,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other)
|
|||
return false;
|
||||
}
|
||||
|
||||
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id/* = 0*/)
|
||||
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id/* = 0*/)
|
||||
: type(type)
|
||||
, data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate, fan_speed, cp_color_id)
|
||||
, start_position(start_position)
|
||||
|
|
@ -99,7 +99,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi
|
|||
{
|
||||
}
|
||||
|
||||
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
|
||||
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder)
|
||||
: type(type)
|
||||
, data(data)
|
||||
, start_position(start_position)
|
||||
|
|
@ -444,8 +444,10 @@ void GCodeAnalyzer::_processG92(const GCodeReader::GCodeLine& line)
|
|||
anyFound = true;
|
||||
}
|
||||
|
||||
if (!anyFound)
|
||||
if (!anyFound && ! line.has_unknown_axis())
|
||||
{
|
||||
// The G92 may be called for axes that PrusaSlicer does not recognize, for example see GH issue #3510,
|
||||
// where G92 A0 B0 is called although the extruder axis is till E.
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
_set_axis_origin((EAxis)a, _get_axis_position((EAxis)a));
|
||||
|
|
@ -470,7 +472,7 @@ void GCodeAnalyzer::_processM106(const GCodeReader::GCodeLine& line)
|
|||
// The absence of P means the print cooling fan, so ignore anything else.
|
||||
float new_fan_speed;
|
||||
if (line.has_value('S', new_fan_speed))
|
||||
_set_fan_speed((100.0f / 256.0f) * new_fan_speed);
|
||||
_set_fan_speed((100.0f / 255.0f) * new_fan_speed);
|
||||
else
|
||||
_set_fan_speed(100.0f);
|
||||
}
|
||||
|
|
@ -689,7 +691,7 @@ void GCodeAnalyzer::_process_extrusion_role_tag(const std::string& comment, size
|
|||
|
||||
void GCodeAnalyzer::_process_mm3_per_mm_tag(const std::string& comment, size_t pos)
|
||||
{
|
||||
_set_mm3_per_mm(::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr));
|
||||
_set_mm3_per_mm((float)::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr));
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_process_width_tag(const std::string& comment, size_t pos)
|
||||
|
|
@ -782,12 +784,12 @@ unsigned int GCodeAnalyzer::_get_cp_color_id() const
|
|||
return m_state.data.cp_color_id;
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_set_mm3_per_mm(double value)
|
||||
void GCodeAnalyzer::_set_mm3_per_mm(float value)
|
||||
{
|
||||
m_state.data.mm3_per_mm = value;
|
||||
}
|
||||
|
||||
double GCodeAnalyzer::_get_mm3_per_mm() const
|
||||
float GCodeAnalyzer::_get_mm3_per_mm() const
|
||||
{
|
||||
return m_state.data.mm3_per_mm;
|
||||
}
|
||||
|
|
@ -862,12 +864,12 @@ void GCodeAnalyzer::_reset_axes_origin()
|
|||
::memset((void*)m_state.origin, 0, Num_Axis * sizeof(float));
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_set_start_position(const Vec3d& position)
|
||||
void GCodeAnalyzer::_set_start_position(const Vec3f& position)
|
||||
{
|
||||
m_state.start_position = position;
|
||||
}
|
||||
|
||||
const Vec3d& GCodeAnalyzer::_get_start_position() const
|
||||
const Vec3f& GCodeAnalyzer::_get_start_position() const
|
||||
{
|
||||
return m_state.start_position;
|
||||
}
|
||||
|
|
@ -898,9 +900,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const
|
|||
return _get_axis_position(E) - m_state.start_extrusion;
|
||||
}
|
||||
|
||||
Vec3d GCodeAnalyzer::_get_end_position() const
|
||||
Vec3f GCodeAnalyzer::_get_end_position() const
|
||||
{
|
||||
return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]);
|
||||
return Vec3f(m_state.position[X], m_state.position[Y], m_state.position[Z]);
|
||||
}
|
||||
|
||||
void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
|
||||
|
|
@ -911,14 +913,14 @@ void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
|
|||
it = m_moves_map.insert(TypeToMovesMap::value_type(type, GCodeMovesList())).first;
|
||||
|
||||
// store move
|
||||
Vec3d extruder_offset = Vec3d::Zero();
|
||||
Vec3f extruder_offset = Vec3f::Zero();
|
||||
unsigned int extruder_id = _get_extruder_id();
|
||||
ExtruderOffsetsMap::iterator extr_it = m_extruder_offsets.find(extruder_id);
|
||||
if (extr_it != m_extruder_offsets.end())
|
||||
extruder_offset = Vec3d(extr_it->second(0), extr_it->second(1), 0.0);
|
||||
extruder_offset = Vec3f((float)extr_it->second(0), (float)extr_it->second(1), 0.0f);
|
||||
|
||||
Vec3d start_position = _get_start_position() + extruder_offset;
|
||||
Vec3d end_position = _get_end_position() + extruder_offset;
|
||||
Vec3f start_position = _get_start_position() + extruder_offset;
|
||||
Vec3f end_position = _get_end_position() + extruder_offset;
|
||||
it->second.emplace_back(type, _get_extrusion_role(), extruder_id, _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), start_position, end_position, _get_delta_extrusion(), _get_fan_speed(), _get_cp_color_id());
|
||||
}
|
||||
|
||||
|
|
@ -956,8 +958,8 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||
GCodePreviewData::Extrusion::Path &path = paths.back();
|
||||
path.polyline = polyline;
|
||||
path.extrusion_role = data.extrusion_role;
|
||||
path.mm3_per_mm = float(data.mm3_per_mm);
|
||||
path.width = data.width;
|
||||
path.mm3_per_mm = data.mm3_per_mm;
|
||||
path.width = data.width;
|
||||
path.height = data.height;
|
||||
path.feedrate = data.feedrate;
|
||||
path.extruder_id = data.extruder_id;
|
||||
|
|
@ -974,7 +976,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||
Metadata data;
|
||||
float z = FLT_MAX;
|
||||
Polyline polyline;
|
||||
Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
Vec3f position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
float volumetric_rate = FLT_MAX;
|
||||
GCodePreviewData::Range height_range;
|
||||
GCodePreviewData::Range width_range;
|
||||
|
|
@ -994,7 +996,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||
if (cancel_callback_curr == 0)
|
||||
cancel_callback();
|
||||
|
||||
if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm))
|
||||
if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * move.data.mm3_per_mm))
|
||||
{
|
||||
// store current polyline
|
||||
polyline.remove_duplicate_points();
|
||||
|
|
@ -1010,7 +1012,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
|||
// update current values
|
||||
data = move.data;
|
||||
z = (float)move.start_position.z();
|
||||
volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm;
|
||||
volumetric_rate = move.data.feedrate * move.data.mm3_per_mm;
|
||||
height_range.update_from(move.data.height);
|
||||
width_range.update_from(move.data.width);
|
||||
feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::EXTRUSION);
|
||||
|
|
@ -1058,7 +1060,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
|
|||
return;
|
||||
|
||||
Polyline3 polyline;
|
||||
Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
Vec3f position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types;
|
||||
GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions;
|
||||
float feedrate = FLT_MAX;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public:
|
|||
static const std::string Custom_Code_Tag;
|
||||
static const std::string End_Pause_Print_Or_Custom_Code_Tag;
|
||||
|
||||
static const double Default_mm3_per_mm;
|
||||
static const float Default_mm3_per_mm;
|
||||
static const float Default_Width;
|
||||
static const float Default_Height;
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ public:
|
|||
{
|
||||
ExtrusionRole extrusion_role;
|
||||
unsigned int extruder_id;
|
||||
double mm3_per_mm;
|
||||
float mm3_per_mm;
|
||||
float width; // mm
|
||||
float height; // mm
|
||||
float feedrate; // mm/s
|
||||
|
|
@ -61,7 +61,7 @@ public:
|
|||
unsigned int cp_color_id;
|
||||
|
||||
Metadata();
|
||||
Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id = 0);
|
||||
Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id = 0);
|
||||
|
||||
bool operator != (const Metadata& other) const;
|
||||
};
|
||||
|
|
@ -81,12 +81,12 @@ public:
|
|||
|
||||
EType type;
|
||||
Metadata data;
|
||||
Vec3d start_position;
|
||||
Vec3d end_position;
|
||||
Vec3f start_position;
|
||||
Vec3f end_position;
|
||||
float delta_extruder;
|
||||
|
||||
GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id = 0);
|
||||
GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
|
||||
GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id = 0);
|
||||
GCodeMove(EType type, const Metadata& data, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder);
|
||||
};
|
||||
|
||||
typedef std::vector<GCodeMove> GCodeMovesList;
|
||||
|
|
@ -101,7 +101,7 @@ private:
|
|||
EPositioningType global_positioning_type;
|
||||
EPositioningType e_local_positioning_type;
|
||||
Metadata data;
|
||||
Vec3d start_position = Vec3d::Zero();
|
||||
Vec3f start_position = Vec3f::Zero();
|
||||
float cached_position[5];
|
||||
float start_extrusion;
|
||||
float position[Num_Axis];
|
||||
|
|
@ -246,8 +246,8 @@ private:
|
|||
void _set_cp_color_id(unsigned int id);
|
||||
unsigned int _get_cp_color_id() const;
|
||||
|
||||
void _set_mm3_per_mm(double value);
|
||||
double _get_mm3_per_mm() const;
|
||||
void _set_mm3_per_mm(float value);
|
||||
float _get_mm3_per_mm() const;
|
||||
|
||||
void _set_width(float width);
|
||||
float _get_width() const;
|
||||
|
|
@ -272,8 +272,8 @@ private:
|
|||
// Sets origin position to zero
|
||||
void _reset_axes_origin();
|
||||
|
||||
void _set_start_position(const Vec3d& position);
|
||||
const Vec3d& _get_start_position() const;
|
||||
void _set_start_position(const Vec3f& position);
|
||||
const Vec3f& _get_start_position() const;
|
||||
|
||||
void _set_cached_position(unsigned char axis, float position);
|
||||
float _get_cached_position(unsigned char axis) const;
|
||||
|
|
@ -285,7 +285,7 @@ private:
|
|||
float _get_delta_extrusion() const;
|
||||
|
||||
// Returns current xyz position (from m_state.position[])
|
||||
Vec3d _get_end_position() const;
|
||||
Vec3f _get_end_position() const;
|
||||
|
||||
// Adds a new move with the given data
|
||||
void _store_move(GCodeMove::EType type);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ Color GCodePreviewData::RangeBase::get_color_at(float value) const
|
|||
{
|
||||
// Input value scaled to the color range
|
||||
float step = step_size();
|
||||
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step_size() : 0.0f; // lower limit of 0.0f
|
||||
const float global_t = (step != 0.0f) ? std::max(0.0f, value - min()) / step : 0.0f; // lower limit of 0.0f
|
||||
|
||||
constexpr std::size_t color_max_idx = range_rainbow_colors.size() - 1;
|
||||
|
||||
|
|
@ -241,6 +241,7 @@ void GCodePreviewData::reset()
|
|||
ranges.width.reset();
|
||||
ranges.height.reset();
|
||||
ranges.feedrate.reset();
|
||||
ranges.fan_speed.reset();
|
||||
ranges.volumetric_rate.reset();
|
||||
extrusion.layers.clear();
|
||||
travel.polylines.clear();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
#include "libslic3r/libslic3r.h"
|
||||
#include "ThumbnailData.hpp"
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
void ThumbnailData::set(unsigned int w, unsigned int h)
|
||||
|
|
@ -32,5 +30,3 @@ bool ThumbnailData::is_valid() const
|
|||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef slic3r_ThumbnailData_hpp_
|
||||
#define slic3r_ThumbnailData_hpp_
|
||||
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include <vector>
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
|
|
@ -26,6 +24,4 @@ typedef std::function<void(ThumbnailsList & thumbnails, const Vec2ds & sizes, bo
|
|||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#endif // slic3r_ThumbnailData_hpp_
|
||||
|
|
@ -94,7 +94,7 @@ ToolOrdering::ToolOrdering(const PrintObject &object, unsigned int first_extrude
|
|||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
|
||||
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height);
|
||||
this->fill_wipe_tower_partitions(object.print()->config(), object.layers().front()->print_z - object.layers().front()->height, object.config().layer_height);
|
||||
|
||||
this->collect_extruder_statistics(prime_multi_material);
|
||||
}
|
||||
|
|
@ -107,6 +107,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
|
||||
// Initialize the print layers for all objects and all layers.
|
||||
coordf_t object_bottom_z = 0.;
|
||||
coordf_t max_layer_height = 0.;
|
||||
{
|
||||
std::vector<coordf_t> zs;
|
||||
for (auto object : print.objects()) {
|
||||
|
|
@ -122,6 +123,8 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
object_bottom_z = layer->print_z - layer->height;
|
||||
break;
|
||||
}
|
||||
|
||||
max_layer_height = std::max(max_layer_height, object->config().layer_height.value);
|
||||
}
|
||||
this->initialize_layers(zs);
|
||||
}
|
||||
|
|
@ -144,7 +147,7 @@ ToolOrdering::ToolOrdering(const Print &print, unsigned int first_extruder, bool
|
|||
// Reorder the extruders to minimize tool switches.
|
||||
this->reorder_extruders(first_extruder);
|
||||
|
||||
this->fill_wipe_tower_partitions(print.config(), object_bottom_z);
|
||||
this->fill_wipe_tower_partitions(print.config(), object_bottom_z, max_layer_height);
|
||||
|
||||
this->collect_extruder_statistics(prime_multi_material);
|
||||
}
|
||||
|
|
@ -212,10 +215,8 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
|||
if (m_print_config_ptr) { // in this case complete_objects is false (see ToolOrdering constructors)
|
||||
something_nonoverriddable = false;
|
||||
for (const auto& eec : layerm->perimeters.entities) // let's check if there are nonoverriddable entities
|
||||
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region)) {
|
||||
if (!layer_tools.wiping_extrusions().is_overriddable_and_mark(dynamic_cast<const ExtrusionEntityCollection&>(*eec), *m_print_config_ptr, object, region))
|
||||
something_nonoverriddable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (something_nonoverriddable)
|
||||
|
|
@ -237,7 +238,7 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
|
|||
has_infill = true;
|
||||
|
||||
if (m_print_config_ptr) {
|
||||
if (!something_nonoverriddable && !layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
|
||||
if (! layer_tools.wiping_extrusions().is_overriddable_and_mark(*fill, *m_print_config_ptr, object, region))
|
||||
something_nonoverriddable = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -320,7 +321,7 @@ void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
|
|||
}
|
||||
}
|
||||
|
||||
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z)
|
||||
void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_object_layer_height)
|
||||
{
|
||||
if (m_layer_tools.empty())
|
||||
return;
|
||||
|
|
@ -353,6 +354,10 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
|
|||
mlh = 0.75 * config.nozzle_diameter.values[i];
|
||||
max_layer_height = std::min(max_layer_height, mlh);
|
||||
}
|
||||
// The Prusa3D Fast (0.35mm layer height) print profile sets a higher layer height than what is normally allowed
|
||||
// by the nozzle. This is a hack and it works by increasing extrusion width.
|
||||
max_layer_height = std::max(max_layer_height, max_object_layer_height);
|
||||
|
||||
for (size_t i = 0; i + 1 < m_layer_tools.size(); ++ i) {
|
||||
const LayerTools < = m_layer_tools[i];
|
||||
const LayerTools <_next = m_layer_tools[i + 1];
|
||||
|
|
@ -395,21 +400,47 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_
|
|||
// and maybe other problems. We will therefore go through layer_tools and detect and fix this.
|
||||
// So, if there is a non-object layer starting with different extruder than the last one ended with (or containing more than one extruder),
|
||||
// we'll mark it with has_wipe tower.
|
||||
for (unsigned int i=0; i+1<m_layer_tools.size(); ++i) {
|
||||
LayerTools& lt = m_layer_tools[i];
|
||||
LayerTools& lt_next = m_layer_tools[i+1];
|
||||
if (lt.extruders.empty() || lt_next.extruders.empty())
|
||||
break;
|
||||
if (!lt_next.has_wipe_tower && (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1))
|
||||
lt_next.has_wipe_tower = true;
|
||||
// We should also check that the next wipe tower layer is no further than max_layer_height:
|
||||
unsigned int j = i+1;
|
||||
double last_wipe_tower_print_z = lt_next.print_z;
|
||||
while (++j < m_layer_tools.size()-1 && !m_layer_tools[j].has_wipe_tower)
|
||||
if (m_layer_tools[j+1].print_z - last_wipe_tower_print_z > max_layer_height) {
|
||||
m_layer_tools[j].has_wipe_tower = true;
|
||||
last_wipe_tower_print_z = m_layer_tools[j].print_z;
|
||||
assert(! m_layer_tools.empty() && m_layer_tools.front().has_wipe_tower);
|
||||
if (! m_layer_tools.empty() && m_layer_tools.front().has_wipe_tower) {
|
||||
for (size_t i = 0; i + 1 < m_layer_tools.size();) {
|
||||
const LayerTools < = m_layer_tools[i];
|
||||
assert(lt.has_wipe_tower);
|
||||
assert(! lt.extruders.empty());
|
||||
// Find the next layer with wipe tower or mark a layer as such.
|
||||
size_t j = i + 1;
|
||||
for (; j < m_layer_tools.size() && ! m_layer_tools[j].has_wipe_tower; ++ j) {
|
||||
LayerTools <_next = m_layer_tools[j];
|
||||
if (lt_next.extruders.empty()) {
|
||||
//FIXME Vojtech: Lukasi, proc?
|
||||
j = m_layer_tools.size();
|
||||
break;
|
||||
}
|
||||
if (lt_next.extruders.front() != lt.extruders.back() || lt_next.extruders.size() > 1) {
|
||||
// Support only layer, soluble layers? Otherwise the layer should have been already marked as having wipe tower.
|
||||
assert(lt_next.has_support && ! lt_next.has_object);
|
||||
lt_next.has_wipe_tower = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == m_layer_tools.size())
|
||||
// No wipe tower above layer i, therefore no need to add any wipe tower layer above i.
|
||||
break;
|
||||
// We should also check that the next wipe tower layer is no further than max_layer_height.
|
||||
// This algorith may in theory create very thin wipe layer j if layer closely below j is marked as wipe tower.
|
||||
// This may happen if printing with non-soluble break away supports.
|
||||
// On the other side it should not hurt as there will be no wipe, just perimeter and sparse infill printed
|
||||
// at that particular wipe tower layer without extruder change.
|
||||
double last_wipe_tower_print_z = lt.print_z;
|
||||
assert(m_layer_tools[j].has_wipe_tower);
|
||||
for (size_t k = i + 1; k < j; ++k) {
|
||||
assert(! m_layer_tools[k].has_wipe_tower);
|
||||
if (m_layer_tools[k + 1].print_z - last_wipe_tower_print_z > max_layer_height + EPSILON) {
|
||||
m_layer_tools[k].has_wipe_tower = true;
|
||||
last_wipe_tower_print_z = m_layer_tools[k].print_z;
|
||||
}
|
||||
}
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the wipe_tower_layer_height values.
|
||||
|
|
|
|||
|
|
@ -30,14 +30,6 @@ public:
|
|||
// When allocating extruder overrides of an object's ExtrusionEntity, overrides for maximum 3 copies are allocated in place.
|
||||
typedef boost::container::small_vector<int32_t, 3> ExtruderPerCopy;
|
||||
|
||||
class ExtruderOverrides
|
||||
{
|
||||
public:
|
||||
ExtruderOverrides(const ExtruderPerCopy *overrides, const int correct_extruder_id) : m_overrides(overrides) {}
|
||||
private:
|
||||
const ExtruderPerCopy *m_overrides;
|
||||
};
|
||||
|
||||
// This is called from GCode::process_layer - see implementation for further comments:
|
||||
const ExtruderPerCopy* get_extruder_overrides(const ExtrusionEntity* entity, int correct_extruder_id, size_t num_of_copies);
|
||||
|
||||
|
|
@ -174,7 +166,7 @@ private:
|
|||
void initialize_layers(std::vector<coordf_t> &zs);
|
||||
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
|
||||
void reorder_extruders(unsigned int last_extruder_id);
|
||||
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z);
|
||||
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);
|
||||
void collect_extruder_statistics(bool prime_multi_material);
|
||||
|
||||
std::vector<LayerTools> m_layer_tools;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
|
|||
if (is_end_of_gcode_line(*c))
|
||||
break;
|
||||
// Check the name of the axis.
|
||||
Axis axis = NUM_AXES;
|
||||
Axis axis = NUM_AXES_WITH_UNKNOWN;
|
||||
switch (*c) {
|
||||
case 'X': axis = X; break;
|
||||
case 'Y': axis = Y; break;
|
||||
|
|
@ -49,15 +49,19 @@ const char* GCodeReader::parse_line_internal(const char *ptr, GCodeLine &gline,
|
|||
default:
|
||||
if (*c == m_extrusion_axis)
|
||||
axis = E;
|
||||
else if (*c >= 'A' && *c <= 'Z')
|
||||
// Unknown axis, but we still want to remember that such a axis was seen.
|
||||
axis = UNKNOWN_AXIS;
|
||||
break;
|
||||
}
|
||||
if (axis != NUM_AXES) {
|
||||
if (axis != NUM_AXES_WITH_UNKNOWN) {
|
||||
// Try to parse the numeric value.
|
||||
char *pend = nullptr;
|
||||
double v = strtod(++ c, &pend);
|
||||
if (pend != nullptr && is_end_of_word(*pend)) {
|
||||
// The axis value has been parsed correctly.
|
||||
gline.m_axis[int(axis)] = float(v);
|
||||
if (axis != UNKNOWN_AXIS)
|
||||
gline.m_axis[int(axis)] = float(v);
|
||||
gline.m_mask |= 1 << int(axis);
|
||||
c = pend;
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ public:
|
|||
bool has_z() const { return this->has(Z); }
|
||||
bool has_e() const { return this->has(E); }
|
||||
bool has_f() const { return this->has(F); }
|
||||
bool has_unknown_axis() const { return this->has(UNKNOWN_AXIS); }
|
||||
float x() const { return m_axis[X]; }
|
||||
float y() const { return m_axis[Y]; }
|
||||
float z() const { return m_axis[Z]; }
|
||||
|
|
|
|||
|
|
@ -46,19 +46,19 @@ namespace Slic3r {
|
|||
::memset(abs_axis_feedrate, 0, Num_Axis * sizeof(float));
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float acceleration) const
|
||||
float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float entry_feedrate, float acceleration) const
|
||||
{
|
||||
return acceleration_time_from_distance(feedrate.entry, accelerate_until, acceleration);
|
||||
return acceleration_time_from_distance(entry_feedrate, accelerate_until, acceleration);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::Trapezoid::cruise_time() const
|
||||
{
|
||||
return (feedrate.cruise != 0.0f) ? cruise_distance() / feedrate.cruise : 0.0f;
|
||||
return (cruise_feedrate != 0.0f) ? cruise_distance() / cruise_feedrate : 0.0f;
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float acceleration) const
|
||||
float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float distance, float acceleration) const
|
||||
{
|
||||
return acceleration_time_from_distance(feedrate.cruise, (distance - decelerate_after), -acceleration);
|
||||
return acceleration_time_from_distance(cruise_feedrate, (distance - decelerate_after), -acceleration);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::Trapezoid::cruise_distance() const
|
||||
|
|
@ -78,29 +78,9 @@ namespace Slic3r {
|
|||
return ::sqrt(value);
|
||||
}
|
||||
|
||||
GCodeTimeEstimator::Block::Block()
|
||||
{
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::move_length() const
|
||||
{
|
||||
float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
return (length > 0.0f) ? length : std::abs(delta_pos[E]);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::is_extruder_only_move() const
|
||||
{
|
||||
return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::is_travel_move() const
|
||||
{
|
||||
return delta_pos[E] == 0.0f;
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::acceleration_time() const
|
||||
{
|
||||
return trapezoid.acceleration_time(acceleration);
|
||||
return trapezoid.acceleration_time(feedrate.entry, acceleration);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::cruise_time() const
|
||||
|
|
@ -110,7 +90,7 @@ namespace Slic3r {
|
|||
|
||||
float GCodeTimeEstimator::Block::deceleration_time() const
|
||||
{
|
||||
return trapezoid.deceleration_time(acceleration);
|
||||
return trapezoid.deceleration_time(distance, acceleration);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::Block::cruise_distance() const
|
||||
|
|
@ -120,10 +100,7 @@ namespace Slic3r {
|
|||
|
||||
void GCodeTimeEstimator::Block::calculate_trapezoid()
|
||||
{
|
||||
float distance = move_length();
|
||||
|
||||
trapezoid.distance = distance;
|
||||
trapezoid.feedrate = feedrate;
|
||||
trapezoid.cruise_feedrate = feedrate.cruise;
|
||||
|
||||
float accelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration));
|
||||
float decelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration));
|
||||
|
|
@ -134,9 +111,9 @@ namespace Slic3r {
|
|||
// and start braking in order to reach the exit_feedrate exactly at the end of this block.
|
||||
if (cruise_distance < 0.0f)
|
||||
{
|
||||
accelerate_distance = clamp(0.0f, distance, intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance));
|
||||
accelerate_distance = std::clamp(intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance), 0.0f, distance);
|
||||
cruise_distance = 0.0f;
|
||||
trapezoid.feedrate.cruise = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration);
|
||||
trapezoid.cruise_feedrate = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration);
|
||||
}
|
||||
|
||||
trapezoid.accelerate_until = accelerate_distance;
|
||||
|
|
@ -207,11 +184,8 @@ namespace Slic3r {
|
|||
{
|
||||
PROFILE_FUNC();
|
||||
if (start_from_beginning)
|
||||
{
|
||||
_reset_time();
|
||||
m_last_st_synchronized_block_id = -1;
|
||||
}
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
|
|
@ -221,6 +195,7 @@ namespace Slic3r {
|
|||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
|
||||
#if 0
|
||||
void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode)
|
||||
{
|
||||
reset();
|
||||
|
|
@ -229,7 +204,7 @@ namespace Slic3r {
|
|||
[this](GCodeReader &reader, const GCodeReader::GCodeLine &line)
|
||||
{ this->_process_gcode_line(reader, line); });
|
||||
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
|
|
@ -244,7 +219,7 @@ namespace Slic3r {
|
|||
reset();
|
||||
|
||||
m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
|
||||
|
|
@ -262,7 +237,7 @@ namespace Slic3r {
|
|||
{ this->_process_gcode_line(reader, line); };
|
||||
for (const std::string& line : gcode_lines)
|
||||
m_parser.parse_line(line, action);
|
||||
_calculate_time();
|
||||
_calculate_time(0);
|
||||
|
||||
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
|
||||
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache});
|
||||
|
|
@ -271,6 +246,7 @@ namespace Slic3r {
|
|||
_log_moves_stats();
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
}
|
||||
#endif
|
||||
|
||||
bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode)
|
||||
{
|
||||
|
|
@ -317,25 +293,25 @@ namespace Slic3r {
|
|||
if (data == nullptr)
|
||||
return;
|
||||
|
||||
assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count));
|
||||
const Block* block = nullptr;
|
||||
if (g1_line_id < (int)data->g1_line_ids.size())
|
||||
assert((g1_line_id >= (int)data->g1_times.size()) || (data->g1_times[g1_line_id].first >= (int)g1_lines_count));
|
||||
float elapsed_time = -1.0f;
|
||||
if (g1_line_id < (int)data->g1_times.size())
|
||||
{
|
||||
const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id];
|
||||
const G1LineIdTime& map_item = data->g1_times[g1_line_id];
|
||||
if (map_item.first == g1_lines_count)
|
||||
{
|
||||
if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size()))
|
||||
block = &data->blocks[map_item.second];
|
||||
if (line.has_e())
|
||||
elapsed_time = map_item.second;
|
||||
++g1_line_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ((block != nullptr) && (block->elapsed_time != -1.0f))
|
||||
if (elapsed_time != -1.0f)
|
||||
{
|
||||
float block_remaining_time = data->time - block->elapsed_time;
|
||||
float block_remaining_time = data->time - elapsed_time;
|
||||
if (std::abs(last_recorded_time - block_remaining_time) > interval_sec)
|
||||
{
|
||||
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str());
|
||||
gcode_line += line_M73;
|
||||
|
||||
last_recorded_time = block_remaining_time;
|
||||
|
|
@ -643,22 +619,6 @@ namespace Slic3r {
|
|||
m_state.extruder_id = m_state.extruder_id_unloaded;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
m_state.additional_time += timeSec;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_additional_time(float timeSec)
|
||||
{
|
||||
m_state.additional_time = timeSec;
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::get_additional_time() const
|
||||
{
|
||||
return m_state.additional_time;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_default()
|
||||
{
|
||||
set_units(Millimeters);
|
||||
|
|
@ -788,7 +748,7 @@ namespace Slic3r {
|
|||
{
|
||||
size_t out = sizeof(*this);
|
||||
out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block);
|
||||
out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId);
|
||||
out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_times, G1LineIdTime);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
@ -807,13 +767,9 @@ namespace Slic3r {
|
|||
if (get_e_local_positioning_type() == Absolute)
|
||||
set_axis_position(E, 0.0f);
|
||||
|
||||
set_additional_time(0.0f);
|
||||
|
||||
reset_extruder_id();
|
||||
reset_g1_line_id();
|
||||
m_g1_line_ids.clear();
|
||||
|
||||
m_last_st_synchronized_block_id = -1;
|
||||
m_g1_times.clear();
|
||||
|
||||
m_needs_custom_gcode_times = false;
|
||||
m_custom_gcode_times.clear();
|
||||
|
|
@ -830,17 +786,19 @@ namespace Slic3r {
|
|||
m_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_calculate_time()
|
||||
void GCodeTimeEstimator::_calculate_time(size_t keep_last_n_blocks)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
||||
assert(keep_last_n_blocks <= m_blocks.size());
|
||||
|
||||
_forward_pass();
|
||||
_reverse_pass();
|
||||
_recalculate_trapezoids();
|
||||
|
||||
m_time += get_additional_time();
|
||||
m_custom_gcode_time_cache += get_additional_time();
|
||||
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i)
|
||||
size_t n_blocks_process = m_blocks.size() - keep_last_n_blocks;
|
||||
m_g1_times.reserve(m_g1_times.size() + n_blocks_process);
|
||||
for (size_t i = 0; i < n_blocks_process; ++ i)
|
||||
{
|
||||
Block& block = m_blocks[i];
|
||||
float block_time = 0.0f;
|
||||
|
|
@ -848,7 +806,8 @@ namespace Slic3r {
|
|||
block_time += block.cruise_time();
|
||||
block_time += block.deceleration_time();
|
||||
m_time += block_time;
|
||||
block.elapsed_time = m_time;
|
||||
if (block.g1_line_id >= 0)
|
||||
m_g1_times.emplace_back(block.g1_line_id, m_time);
|
||||
|
||||
#if ENABLE_MOVE_STATS
|
||||
MovesStatsMap::iterator it = _moves_stats.find(block.move_type);
|
||||
|
|
@ -862,9 +821,10 @@ namespace Slic3r {
|
|||
m_custom_gcode_time_cache += block_time;
|
||||
}
|
||||
|
||||
m_last_st_synchronized_block_id = (int)m_blocks.size() - 1;
|
||||
// The additional time has been consumed (added to the total time), reset it to zero.
|
||||
set_additional_time(0.);
|
||||
if (keep_last_n_blocks)
|
||||
m_blocks.erase(m_blocks.begin(), m_blocks.begin() + n_blocks_process);
|
||||
else
|
||||
m_blocks.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line)
|
||||
|
|
@ -1021,6 +981,17 @@ namespace Slic3r {
|
|||
return current_absolute_position;
|
||||
};
|
||||
|
||||
// delta_pos must have size >= Num_Axis
|
||||
auto move_length = [](const float* delta_pos) {
|
||||
float xyz_length = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
|
||||
return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[E]);
|
||||
};
|
||||
|
||||
// delta_pos must have size >= Num_Axis
|
||||
auto is_extruder_only_move = [](const float* delta_pos) {
|
||||
return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f);
|
||||
};
|
||||
|
||||
PROFILE_FUNC();
|
||||
increment_g1_line_id();
|
||||
|
||||
|
|
@ -1040,10 +1011,11 @@ namespace Slic3r {
|
|||
|
||||
// calculates block movement deltas
|
||||
float max_abs_delta = 0.0f;
|
||||
float delta_pos[Num_Axis];
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
block.delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a);
|
||||
max_abs_delta = std::max(max_abs_delta, std::abs(block.delta_pos[a]));
|
||||
delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a);
|
||||
max_abs_delta = std::max(max_abs_delta, std::abs(delta_pos[a]));
|
||||
}
|
||||
|
||||
// is it a move ?
|
||||
|
|
@ -1051,15 +1023,15 @@ namespace Slic3r {
|
|||
return;
|
||||
|
||||
// calculates block feedrate
|
||||
m_curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate());
|
||||
m_curr.feedrate = std::max(get_feedrate(), (delta_pos[E] == 0.0f) ? get_minimum_travel_feedrate() : get_minimum_feedrate());
|
||||
|
||||
float distance = block.move_length();
|
||||
float invDistance = 1.0f / distance;
|
||||
block.distance = move_length(delta_pos);
|
||||
float invDistance = 1.0f / block.distance;
|
||||
|
||||
float min_feedrate_factor = 1.0f;
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
m_curr.axis_feedrate[a] = m_curr.feedrate * block.delta_pos[a] * invDistance;
|
||||
m_curr.axis_feedrate[a] = m_curr.feedrate * delta_pos[a] * invDistance;
|
||||
if (a == E)
|
||||
m_curr.axis_feedrate[a] *= get_extrude_factor_override_percentage();
|
||||
|
||||
|
|
@ -1080,12 +1052,12 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
// calculates block acceleration
|
||||
float acceleration = block.is_extruder_only_move() ? get_retract_acceleration() : get_acceleration();
|
||||
float acceleration = is_extruder_only_move(delta_pos) ? get_retract_acceleration() : get_acceleration();
|
||||
|
||||
for (unsigned char a = X; a < Num_Axis; ++a)
|
||||
{
|
||||
float axis_max_acceleration = get_axis_max_acceleration((EAxis)a);
|
||||
if (acceleration * std::abs(block.delta_pos[a]) * invDistance > axis_max_acceleration)
|
||||
if (acceleration * std::abs(delta_pos[a]) * invDistance > axis_max_acceleration)
|
||||
acceleration = axis_max_acceleration;
|
||||
}
|
||||
|
||||
|
|
@ -1165,7 +1137,7 @@ namespace Slic3r {
|
|||
vmax_junction = m_curr.safe_feedrate;
|
||||
}
|
||||
|
||||
float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, distance);
|
||||
float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, block.distance);
|
||||
block.feedrate.entry = std::min(vmax_junction, v_allowable);
|
||||
|
||||
block.max_entry_speed = vmax_junction;
|
||||
|
|
@ -1189,27 +1161,30 @@ namespace Slic3r {
|
|||
// detects block move type
|
||||
block.move_type = Block::Noop;
|
||||
|
||||
if (block.delta_pos[E] < 0.0f)
|
||||
if (delta_pos[E] < 0.0f)
|
||||
{
|
||||
if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f))
|
||||
if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f))
|
||||
block.move_type = Block::Move;
|
||||
else
|
||||
block.move_type = Block::Retract;
|
||||
}
|
||||
else if (block.delta_pos[E] > 0.0f)
|
||||
else if (delta_pos[E] > 0.0f)
|
||||
{
|
||||
if ((block.delta_pos[X] == 0.0f) && (block.delta_pos[Y] == 0.0f) && (block.delta_pos[Z] == 0.0f))
|
||||
if ((delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f))
|
||||
block.move_type = Block::Unretract;
|
||||
else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f))
|
||||
else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f))
|
||||
block.move_type = Block::Extrude;
|
||||
}
|
||||
else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f))
|
||||
else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f))
|
||||
block.move_type = Block::Move;
|
||||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
// adds block to blocks list
|
||||
block.g1_line_id = this->get_g1_line_id();
|
||||
m_blocks.emplace_back(block);
|
||||
m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1));
|
||||
|
||||
if (m_blocks.size() > planner_refresh_if_larger)
|
||||
_calculate_time(planner_queue_size);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line)
|
||||
|
|
@ -1218,8 +1193,9 @@ namespace Slic3r {
|
|||
GCodeFlavor dialect = get_dialect();
|
||||
|
||||
float value;
|
||||
float extra_time = 0.f;
|
||||
if (line.has_value('P', value))
|
||||
add_additional_time(value * MILLISEC_TO_SEC);
|
||||
extra_time += value * MILLISEC_TO_SEC;
|
||||
|
||||
// see: http://reprap.org/wiki/G-code#G4:_Dwell
|
||||
if ((dialect == gcfRepetier) ||
|
||||
|
|
@ -1228,10 +1204,10 @@ namespace Slic3r {
|
|||
(dialect == gcfRepRap))
|
||||
{
|
||||
if (line.has_value('S', value))
|
||||
add_additional_time(value);
|
||||
extra_time += value;
|
||||
}
|
||||
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(extra_time);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line)
|
||||
|
|
@ -1296,7 +1272,7 @@ namespace Slic3r {
|
|||
anyFound = true;
|
||||
}
|
||||
else
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(0.f);
|
||||
|
||||
if (!anyFound)
|
||||
{
|
||||
|
|
@ -1310,7 +1286,7 @@ namespace Slic3r {
|
|||
void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(0.f);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line)
|
||||
|
|
@ -1462,9 +1438,9 @@ namespace Slic3r {
|
|||
// MK3 MMU2 specific M code:
|
||||
// M702 C is expected to be sent by the custom end G-code when finalizing a print.
|
||||
// The MK3 unit shall unload and park the active filament into the MMU2 unit.
|
||||
add_additional_time(get_filament_unload_time(get_extruder_id()));
|
||||
float extra_time = get_filament_unload_time(get_extruder_id());
|
||||
reset_extruder_id();
|
||||
_simulate_st_synchronize();
|
||||
_simulate_st_synchronize(extra_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1478,10 +1454,10 @@ namespace Slic3r {
|
|||
{
|
||||
// Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating
|
||||
// that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet.
|
||||
add_additional_time(get_filament_unload_time(get_extruder_id()));
|
||||
float extra_time = get_filament_unload_time(get_extruder_id());
|
||||
set_extruder_id(id);
|
||||
add_additional_time(get_filament_load_time(get_extruder_id()));
|
||||
_simulate_st_synchronize();
|
||||
extra_time += get_filament_load_time(get_extruder_id());
|
||||
_simulate_st_synchronize(extra_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1513,7 +1489,9 @@ namespace Slic3r {
|
|||
{
|
||||
PROFILE_FUNC();
|
||||
m_needs_custom_gcode_times = true;
|
||||
_calculate_time();
|
||||
//FIXME this simulates st_synchronize! is it correct?
|
||||
// The estimated time may be longer than the real print time.
|
||||
_simulate_st_synchronize(0.f);
|
||||
if (m_custom_gcode_time_cache != 0.0f)
|
||||
{
|
||||
m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache});
|
||||
|
|
@ -1521,34 +1499,26 @@ namespace Slic3r {
|
|||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize()
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize(float extra_time)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
_calculate_time();
|
||||
m_time += extra_time;
|
||||
m_custom_gcode_time_cache += extra_time;
|
||||
_calculate_time(0);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_forward_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (m_blocks.size() > 1)
|
||||
{
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i)
|
||||
{
|
||||
_planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i + 1 < (int)m_blocks.size(); ++i)
|
||||
_planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_reverse_pass()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (m_blocks.size() > 1)
|
||||
{
|
||||
for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i)
|
||||
{
|
||||
_planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]);
|
||||
}
|
||||
}
|
||||
for (int i = (int)m_blocks.size() - 1; i > 0; -- i)
|
||||
_planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr)
|
||||
|
|
@ -1562,7 +1532,7 @@ namespace Slic3r {
|
|||
{
|
||||
if (prev.feedrate.entry < curr.feedrate.entry)
|
||||
{
|
||||
float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.move_length()));
|
||||
float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.distance));
|
||||
|
||||
// Check for junction speed change
|
||||
if (curr.feedrate.entry != entry_speed)
|
||||
|
|
@ -1584,7 +1554,7 @@ namespace Slic3r {
|
|||
// If nominal length true, max junction speed is guaranteed to be reached. Only compute
|
||||
// for max allowable speed if block is decelerating and nominal length is false.
|
||||
if (!curr.flags.nominal_length && (curr.max_entry_speed > next.feedrate.entry))
|
||||
curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.move_length()));
|
||||
curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.distance));
|
||||
else
|
||||
curr.feedrate.entry = curr.max_entry_speed;
|
||||
|
||||
|
|
@ -1598,7 +1568,7 @@ namespace Slic3r {
|
|||
Block* curr = nullptr;
|
||||
Block* next = nullptr;
|
||||
|
||||
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i)
|
||||
for (size_t i = 0; i < m_blocks.size(); ++ i)
|
||||
{
|
||||
Block& b = m_blocks[i];
|
||||
|
||||
|
|
@ -1657,7 +1627,7 @@ namespace Slic3r {
|
|||
{
|
||||
char buffer[64];
|
||||
|
||||
int minutes = std::round(time_in_secs / 60.);
|
||||
int minutes = int(std::round(time_in_secs / 60.));
|
||||
if (minutes <= 0) {
|
||||
::sprintf(buffer, "%ds", (int)time_in_secs);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,6 @@ namespace Slic3r {
|
|||
// hard limit for the acceleration, to which the firmware will clamp.
|
||||
float max_acceleration; // mm/s^2
|
||||
float retract_acceleration; // mm/s^2
|
||||
float additional_time; // s
|
||||
float minimum_feedrate; // mm/s
|
||||
float minimum_travel_feedrate; // mm/s
|
||||
float extrude_factor_override_percentage;
|
||||
|
|
@ -125,14 +124,13 @@ namespace Slic3r {
|
|||
|
||||
struct Trapezoid
|
||||
{
|
||||
float distance; // mm
|
||||
float accelerate_until; // mm
|
||||
float decelerate_after; // mm
|
||||
FeedrateProfile feedrate;
|
||||
float cruise_feedrate; // mm/sec
|
||||
|
||||
float acceleration_time(float acceleration) const;
|
||||
float acceleration_time(float entry_feedrate, float acceleration) const;
|
||||
float cruise_time() const;
|
||||
float deceleration_time(float acceleration) const;
|
||||
float deceleration_time(float distance, float acceleration) const;
|
||||
float cruise_distance() const;
|
||||
|
||||
// This function gives the time needed to accelerate from an initial speed to reach a final distance.
|
||||
|
|
@ -153,25 +151,16 @@ namespace Slic3r {
|
|||
#endif // ENABLE_MOVE_STATS
|
||||
Flags flags;
|
||||
|
||||
float delta_pos[Num_Axis]; // mm
|
||||
float distance; // mm
|
||||
float acceleration; // mm/s^2
|
||||
float max_entry_speed; // mm/s
|
||||
float safe_feedrate; // mm/s
|
||||
|
||||
FeedrateProfile feedrate;
|
||||
Trapezoid trapezoid;
|
||||
float elapsed_time;
|
||||
|
||||
Block();
|
||||
|
||||
// Returns the length of the move covered by this block, in mm
|
||||
float move_length() const;
|
||||
|
||||
// Returns true if this block is a retract/unretract move only
|
||||
float is_extruder_only_move() const;
|
||||
|
||||
// Returns true if this block is a move with no extrusion
|
||||
float is_travel_move() const;
|
||||
// Ordnary index of this G1 line in the file.
|
||||
int g1_line_id { -1 };
|
||||
|
||||
// Returns the time spent accelerating toward cruise speed, in seconds
|
||||
float acceleration_time() const;
|
||||
|
|
@ -217,16 +206,13 @@ namespace Slic3r {
|
|||
#endif // ENABLE_MOVE_STATS
|
||||
|
||||
public:
|
||||
typedef std::pair<unsigned int, unsigned int> G1LineIdToBlockId;
|
||||
typedef std::vector<G1LineIdToBlockId> G1LineIdToBlockIdMap;
|
||||
typedef std::pair<int, float> G1LineIdTime;
|
||||
typedef std::vector<G1LineIdTime> G1LineIdsTimes;
|
||||
|
||||
struct PostProcessData
|
||||
{
|
||||
const G1LineIdToBlockIdMap& g1_line_ids;
|
||||
const BlocksList& blocks;
|
||||
const G1LineIdsTimes& g1_times;
|
||||
float time;
|
||||
|
||||
PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {}
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -236,10 +222,14 @@ namespace Slic3r {
|
|||
Feedrates m_curr;
|
||||
Feedrates m_prev;
|
||||
BlocksList m_blocks;
|
||||
// Map between g1 line id and blocks id, used to speed up export of remaining times
|
||||
G1LineIdToBlockIdMap m_g1_line_ids;
|
||||
// Index of the last block already st_synchronized
|
||||
int m_last_st_synchronized_block_id;
|
||||
// Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks.
|
||||
// Let's be conservative and plan for newer boards with more memory.
|
||||
static constexpr size_t planner_queue_size = 64;
|
||||
// The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added.
|
||||
// We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate.
|
||||
static constexpr size_t planner_refresh_if_larger = planner_queue_size * 4;
|
||||
// Map from g1 line id to its elapsed time from the start of the print.
|
||||
G1LineIdsTimes m_g1_times;
|
||||
float m_time; // s
|
||||
|
||||
// data to calculate custom code times
|
||||
|
|
@ -267,13 +257,13 @@ namespace Slic3r {
|
|||
void calculate_time(bool start_from_beginning);
|
||||
|
||||
// Calculates the time estimate from the given gcode in string format
|
||||
void calculate_time_from_text(const std::string& gcode);
|
||||
//void calculate_time_from_text(const std::string& gcode);
|
||||
|
||||
// Calculates the time estimate from the gcode contained in the file with the given filename
|
||||
void calculate_time_from_file(const std::string& file);
|
||||
//void calculate_time_from_file(const std::string& file);
|
||||
|
||||
// Calculates the time estimate from the gcode contained in given list of gcode lines
|
||||
void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||
//void calculate_time_from_lines(const std::vector<std::string>& gcode_lines);
|
||||
|
||||
// Process the gcode contained in the file with the given filename,
|
||||
// replacing placeholders with correspondent new lines M73
|
||||
|
|
@ -350,10 +340,6 @@ namespace Slic3r {
|
|||
unsigned int get_extruder_id() const;
|
||||
void reset_extruder_id();
|
||||
|
||||
void add_additional_time(float timeSec);
|
||||
void set_additional_time(float timeSec);
|
||||
float get_additional_time() const;
|
||||
|
||||
void set_default();
|
||||
|
||||
// Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator
|
||||
|
|
@ -389,7 +375,7 @@ namespace Slic3r {
|
|||
// Return an estimate of the memory consumed by the time estimator.
|
||||
size_t memory_used() const;
|
||||
|
||||
PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); }
|
||||
PostProcessData get_post_process_data() const { return PostProcessData{ m_g1_times, m_time }; }
|
||||
|
||||
private:
|
||||
void _reset();
|
||||
|
|
@ -397,7 +383,7 @@ namespace Slic3r {
|
|||
void _reset_blocks();
|
||||
|
||||
// Calculates the time estimate
|
||||
void _calculate_time();
|
||||
void _calculate_time(size_t keep_last_n_blocks);
|
||||
|
||||
// Processes the given gcode line
|
||||
void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line);
|
||||
|
|
@ -470,7 +456,7 @@ namespace Slic3r {
|
|||
void _process_custom_gcode_tag(CustomGcodeType code);
|
||||
|
||||
// Simulates firmware st_synchronize() call
|
||||
void _simulate_st_synchronize();
|
||||
void _simulate_st_synchronize(float additional_time);
|
||||
|
||||
void _forward_pass();
|
||||
void _reverse_pass();
|
||||
|
|
|
|||
|
|
@ -112,72 +112,82 @@ void Layer::make_perimeters()
|
|||
// keep track of regions whose perimeters we have already generated
|
||||
std::vector<unsigned char> done(m_regions.size(), false);
|
||||
|
||||
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm) {
|
||||
size_t region_id = layerm - m_regions.begin();
|
||||
if (done[region_id])
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
|
||||
done[region_id] = true;
|
||||
const PrintRegionConfig &config = (*layerm)->region()->config();
|
||||
|
||||
// find compatible regions
|
||||
LayerRegionPtrs layerms;
|
||||
layerms.push_back(*layerm);
|
||||
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it) {
|
||||
LayerRegion* other_layerm = *it;
|
||||
const PrintRegionConfig &other_config = other_layerm->region()->config();
|
||||
if (config.perimeter_extruder == other_config.perimeter_extruder
|
||||
&& config.perimeters == other_config.perimeters
|
||||
&& config.perimeter_speed == other_config.perimeter_speed
|
||||
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
||||
&& config.gap_fill_speed == other_config.gap_fill_speed
|
||||
&& config.overhangs == other_config.overhangs
|
||||
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
|
||||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first
|
||||
&& config.infill_overlap == other_config.infill_overlap) {
|
||||
layerms.push_back(other_layerm);
|
||||
done[it - m_regions.begin()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (layerms.size() == 1) { // optimization
|
||||
(*layerm)->fill_surfaces.surfaces.clear();
|
||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
|
||||
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||
} else {
|
||||
SurfaceCollection new_slices;
|
||||
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
||||
LayerRegion *layerm_config = layerms.front();
|
||||
{
|
||||
// group slices (surfaces) according to number of extra perimeters
|
||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegion *layerm : layerms) {
|
||||
for (Surface &surface : layerm->slices.surfaces)
|
||||
slices[surface.extra_perimeters].emplace_back(surface);
|
||||
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
|
||||
layerm_config = layerm;
|
||||
}
|
||||
// merge the surfaces assigned to each group
|
||||
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
|
||||
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
|
||||
}
|
||||
|
||||
// make perimeters
|
||||
SurfaceCollection fill_surfaces;
|
||||
layerm_config->make_perimeters(new_slices, &fill_surfaces);
|
||||
for (LayerRegionPtrs::iterator layerm = m_regions.begin(); layerm != m_regions.end(); ++ layerm)
|
||||
if ((*layerm)->slices.empty()) {
|
||||
(*layerm)->perimeters.clear();
|
||||
(*layerm)->fills.clear();
|
||||
(*layerm)->thin_fills.clear();
|
||||
} else {
|
||||
size_t region_id = layerm - m_regions.begin();
|
||||
if (done[region_id])
|
||||
continue;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << ", region " << region_id;
|
||||
done[region_id] = true;
|
||||
const PrintRegionConfig &config = (*layerm)->region()->config();
|
||||
|
||||
// find compatible regions
|
||||
LayerRegionPtrs layerms;
|
||||
layerms.push_back(*layerm);
|
||||
for (LayerRegionPtrs::const_iterator it = layerm + 1; it != m_regions.end(); ++it)
|
||||
if (! (*it)->slices.empty()) {
|
||||
LayerRegion* other_layerm = *it;
|
||||
const PrintRegionConfig &other_config = other_layerm->region()->config();
|
||||
if (config.perimeter_extruder == other_config.perimeter_extruder
|
||||
&& config.perimeters == other_config.perimeters
|
||||
&& config.perimeter_speed == other_config.perimeter_speed
|
||||
&& config.external_perimeter_speed == other_config.external_perimeter_speed
|
||||
&& config.gap_fill_speed == other_config.gap_fill_speed
|
||||
&& config.overhangs == other_config.overhangs
|
||||
&& config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width")
|
||||
&& config.thin_walls == other_config.thin_walls
|
||||
&& config.external_perimeters_first == other_config.external_perimeters_first
|
||||
&& config.infill_overlap == other_config.infill_overlap)
|
||||
{
|
||||
other_layerm->perimeters.clear();
|
||||
other_layerm->fills.clear();
|
||||
other_layerm->thin_fills.clear();
|
||||
layerms.push_back(other_layerm);
|
||||
done[it - m_regions.begin()] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (layerms.size() == 1) { // optimization
|
||||
(*layerm)->fill_surfaces.surfaces.clear();
|
||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
|
||||
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||
} else {
|
||||
SurfaceCollection new_slices;
|
||||
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
||||
LayerRegion *layerm_config = layerms.front();
|
||||
{
|
||||
// group slices (surfaces) according to number of extra perimeters
|
||||
std::map<unsigned short, Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||
for (LayerRegion *layerm : layerms) {
|
||||
for (Surface &surface : layerm->slices.surfaces)
|
||||
slices[surface.extra_perimeters].emplace_back(surface);
|
||||
if (layerm->region()->config().fill_density > layerm_config->region()->config().fill_density)
|
||||
layerm_config = layerm;
|
||||
}
|
||||
// merge the surfaces assigned to each group
|
||||
for (std::pair<const unsigned short,Surfaces> &surfaces_with_extra_perimeters : slices)
|
||||
new_slices.append(union_ex(surfaces_with_extra_perimeters.second, true), surfaces_with_extra_perimeters.second.front());
|
||||
}
|
||||
|
||||
// make perimeters
|
||||
SurfaceCollection fill_surfaces;
|
||||
layerm_config->make_perimeters(new_slices, &fill_surfaces);
|
||||
|
||||
// assign fill_surfaces to each layer
|
||||
if (!fill_surfaces.surfaces.empty()) {
|
||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||
// Separate the fill surfaces.
|
||||
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
|
||||
(*l)->fill_expolygons = expp;
|
||||
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// assign fill_surfaces to each layer
|
||||
if (!fill_surfaces.surfaces.empty()) {
|
||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||
// Separate the fill surfaces.
|
||||
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
|
||||
(*l)->fill_expolygons = expp;
|
||||
(*l)->fill_surfaces.set(std::move(expp), fill_surfaces.surfaces.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(trace) << "Generating perimeters for layer " << this->id() << " - Done";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
|||
// Voids are sparse infills if infill rate is zero.
|
||||
Polygons voids;
|
||||
for (const Surface &surface : this->fill_surfaces.surfaces) {
|
||||
if (surface.surface_type == stTop) {
|
||||
if (surface.is_top()) {
|
||||
// Collect the top surfaces, inflate them and trim them by the bottom surfaces.
|
||||
// This gives the priority to bottom surfaces.
|
||||
surfaces_append(top, offset_ex(surface.expolygon, margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS), surface);
|
||||
|
|
@ -313,7 +313,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
|||
s2.clear();
|
||||
}
|
||||
}
|
||||
if (s1.surface_type == stTop)
|
||||
if (s1.is_top())
|
||||
// Trim the top surfaces by the bottom surfaces. This gives the priority to the bottom surfaces.
|
||||
polys = diff(polys, bottom_polygons);
|
||||
surfaces_append(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ TriangleMesh eigen_to_triangle_mesh(const EigenMesh &emesh)
|
|||
auto &VC = emesh.first; auto &FC = emesh.second;
|
||||
|
||||
Pointf3s points(size_t(VC.rows()));
|
||||
std::vector<Vec3crd> facets(size_t(FC.rows()));
|
||||
std::vector<Vec3i> facets(size_t(FC.rows()));
|
||||
|
||||
for (Eigen::Index i = 0; i < VC.rows(); ++i)
|
||||
points[size_t(i)] = VC.row(i);
|
||||
|
|
@ -154,7 +154,7 @@ inline Vec3d to_vec3d(const _EpecMesh::Point &v)
|
|||
template<class _Mesh> TriangleMesh cgal_to_triangle_mesh(const _Mesh &cgalmesh)
|
||||
{
|
||||
Pointf3s points;
|
||||
std::vector<Vec3crd> facets;
|
||||
std::vector<Vec3i> facets;
|
||||
points.reserve(cgalmesh.num_vertices());
|
||||
facets.reserve(cgalmesh.num_faces());
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ template<class _Mesh> TriangleMesh cgal_to_triangle_mesh(const _Mesh &cgalmesh)
|
|||
for (auto &face : cgalmesh.faces()) {
|
||||
auto vtc = cgalmesh.vertices_around_face(cgalmesh.halfedge(face));
|
||||
int i = 0;
|
||||
Vec3crd trface;
|
||||
Vec3i trface;
|
||||
for (auto v : vtc) trface(i++) = static_cast<int>(v);
|
||||
facets.emplace_back(trface);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -419,7 +419,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
|||
if (input[i].bed_idx != 0) ret = false;
|
||||
if (input[i].bed_idx >= 0) {
|
||||
input[i].translation += Vec2crd{input[i].bed_idx * stride, 0};
|
||||
instances[i]->apply_arrange_result(input[i].translation,
|
||||
instances[i]->apply_arrange_result(input[i].translation.cast<double>(),
|
||||
input[i].rotation);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -668,7 +668,7 @@ public:
|
|||
arrangement::ArrangePolygon get_arrange_polygon() const;
|
||||
|
||||
// Apply the arrange result on the ModelInstance
|
||||
void apply_arrange_result(const Vec2crd& offs, double rotation)
|
||||
void apply_arrange_result(const Vec2d& offs, double rotation)
|
||||
{
|
||||
// write the transformation data into the model instance
|
||||
set_rotation(Z, rotation);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ typedef Eigen::Matrix<coord_t, 2, 1, Eigen::DontAlign> Vec2crd;
|
|||
typedef Eigen::Matrix<coord_t, 3, 1, Eigen::DontAlign> Vec3crd;
|
||||
typedef Eigen::Matrix<int, 2, 1, Eigen::DontAlign> Vec2i;
|
||||
typedef Eigen::Matrix<int, 3, 1, Eigen::DontAlign> Vec3i;
|
||||
typedef Eigen::Matrix<int32_t, 2, 1, Eigen::DontAlign> Vec2i32;
|
||||
typedef Eigen::Matrix<int64_t, 2, 1, Eigen::DontAlign> Vec2i64;
|
||||
typedef Eigen::Matrix<int32_t, 3, 1, Eigen::DontAlign> Vec3i32;
|
||||
typedef Eigen::Matrix<int64_t, 3, 1, Eigen::DontAlign> Vec3i64;
|
||||
|
||||
// Vector types with a double coordinate base type.
|
||||
|
|
@ -53,12 +55,12 @@ typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d
|
|||
|
||||
inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); }
|
||||
|
||||
inline int32_t cross2(const Vec2i32 &v1, const Vec2i32 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||
|
||||
inline Vec2crd to_2d(const Vec3crd &pt3) { return Vec2crd(pt3(0), pt3(1)); }
|
||||
inline Vec2i32 to_2d(const Vec2i32 &pt3) { return Vec2i32(pt3(0), pt3(1)); }
|
||||
inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); }
|
||||
inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); }
|
||||
inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); }
|
||||
|
|
@ -89,8 +91,8 @@ public:
|
|||
typedef coord_t coord_type;
|
||||
|
||||
Point() : Vec2crd(0, 0) {}
|
||||
Point(coord_t x, coord_t y) : Vec2crd(x, y) {}
|
||||
Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {} // for Clipper
|
||||
Point(int32_t x, int32_t y) : Vec2crd(coord_t(x), coord_t(y)) {}
|
||||
Point(int64_t x, int64_t y) : Vec2crd(coord_t(x), coord_t(y)) {}
|
||||
Point(double x, double y) : Vec2crd(coord_t(lrint(x)), coord_t(lrint(y))) {}
|
||||
Point(const Point &rhs) { *this = rhs; }
|
||||
explicit Point(const Vec2d& rhs) : Vec2crd(coord_t(lrint(rhs.x())), coord_t(lrint(rhs.y()))) {}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public:
|
|||
// last point == first point for polygons
|
||||
const Point& last_point() const override { return this->points.front(); }
|
||||
|
||||
virtual Lines lines() const;
|
||||
Lines lines() const override;
|
||||
Polyline split_at_vertex(const Point &point) const;
|
||||
// Split a closed polygon into an open polyline, with the split point duplicated at both ends.
|
||||
Polyline split_at_index(int index) const;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public:
|
|||
const Point& last_point() const override { return this->points.back(); }
|
||||
|
||||
const Point& leftmost_point() const;
|
||||
virtual Lines lines() const;
|
||||
Lines lines() const override;
|
||||
void clip_end(double distance);
|
||||
void clip_start(double distance);
|
||||
void extend_end(double distance);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
} else if (
|
||||
opt_key == "skirts"
|
||||
|| opt_key == "skirt_height"
|
||||
|| opt_key == "draft_shield"
|
||||
|| opt_key == "skirt_distance"
|
||||
|| opt_key == "min_skirt_length"
|
||||
|| opt_key == "ooze_prevention"
|
||||
|
|
@ -1146,14 +1147,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||
|
||||
bool Print::has_infinite_skirt() const
|
||||
{
|
||||
return (m_config.skirt_height == -1 && m_config.skirts > 0)
|
||||
|| (m_config.ooze_prevention && this->extruders().size() > 1);
|
||||
return (m_config.draft_shield && m_config.skirts > 0) || (m_config.ooze_prevention && this->extruders().size() > 1);
|
||||
}
|
||||
|
||||
bool Print::has_skirt() const
|
||||
{
|
||||
return (m_config.skirt_height > 0 && m_config.skirts > 0)
|
||||
|| this->has_infinite_skirt();
|
||||
return (m_config.skirt_height > 0 && m_config.skirts > 0) || this->has_infinite_skirt();
|
||||
}
|
||||
|
||||
static inline bool sequential_print_horizontal_clearance_valid(const Print &print)
|
||||
|
|
@ -1623,11 +1622,7 @@ void Print::process()
|
|||
// The export_gcode may die for various reasons (fails to process output_filename_format,
|
||||
// write error into the G-code, cannot execute post-processing scripts).
|
||||
// It is up to the caller to show an error message.
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
std::string Print::export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb)
|
||||
#else
|
||||
std::string Print::export_gcode(const std::string &path_template, GCodePreviewData *preview_data)
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
{
|
||||
// output everything to a G-code file
|
||||
// The following call may die if the output_filename_format template substitution fails.
|
||||
|
|
@ -1644,11 +1639,7 @@ std::string Print::export_gcode(const std::string &path_template, GCodePreviewDa
|
|||
|
||||
// The following line may die for multiple reasons.
|
||||
GCode gcode;
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
gcode.do_export(this, path.c_str(), preview_data, thumbnail_cb);
|
||||
#else
|
||||
gcode.do_export(this, path.c_str(), preview_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
|
|
@ -2138,6 +2129,7 @@ std::string Print::output_filename(const std::string &filename_base) const
|
|||
// Set the placeholders for the data know first after the G-code export is finished.
|
||||
// These values will be just propagated into the output file name.
|
||||
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)m_config.nozzle_diameter.size()));
|
||||
return this->PrintBase::output_filename(m_config.output_filename_format.value, ".gcode", filename_base, &config);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@
|
|||
#include "Slicing.hpp"
|
||||
#include "GCode/ToolOrdering.hpp"
|
||||
#include "GCode/WipeTower.hpp"
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
#include "GCode/ThumbnailData.hpp"
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
#include "libslic3r.h"
|
||||
|
||||
|
|
@ -349,7 +347,7 @@ public:
|
|||
Print() = default;
|
||||
virtual ~Print() { this->clear(); }
|
||||
|
||||
PrinterTechnology technology() const noexcept { return ptFFF; }
|
||||
PrinterTechnology technology() const noexcept override { return ptFFF; }
|
||||
|
||||
// Methods, which change the state of Print / PrintObject / PrintRegion.
|
||||
// The following methods are synchronized with process() and export_gcode(),
|
||||
|
|
@ -364,11 +362,7 @@ public:
|
|||
void process() override;
|
||||
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
|
||||
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
|
||||
#if ENABLE_THUMBNAIL_GENERATOR
|
||||
std::string export_gcode(const std::string& path_template, GCodePreviewData* preview_data, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||
#else
|
||||
std::string export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
|
||||
#endif // ENABLE_THUMBNAIL_GENERATOR
|
||||
|
||||
// methods for handling state
|
||||
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ void PrintConfigDef::init_fff_params()
|
|||
"to clip the overlapping object parts one by the other "
|
||||
"(2nd part will be clipped by the 1st, 3rd part will be clipped by the 1st and 2nd etc).");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("colorprint_heights", coFloats);
|
||||
def->label = L("Colorprint height");
|
||||
|
|
@ -1691,6 +1691,13 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
def = this->add("draft_shield", coBool);
|
||||
def->label = L("Draft shield");
|
||||
def->tooltip = L("If enabled, the skirt will be as tall as a highest printed object. "
|
||||
"This is useful to protect an ABS or ASA print from warping and detaching from print bed due to wind draft.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("skirts", coInt);
|
||||
def->label = L("Loops (minimum)");
|
||||
def->full_label = L("Skirt Loops");
|
||||
|
|
@ -2998,6 +3005,11 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
|||
} else if (opt_key == "support_material_pattern" && value == "pillars") {
|
||||
// Slic3r PE does not support the pillars. They never worked well.
|
||||
value = "rectilinear";
|
||||
} else if (opt_key == "skirt_height" && value == "-1") {
|
||||
// PrusaSlicer no more accepts skirt_height == -1 to print a draft shield to the top of the highest object.
|
||||
// A new "draft_shield" boolean config value is used instead.
|
||||
opt_key = "draft_shield";
|
||||
value = "1";
|
||||
} else if (opt_key == "octoprint_host") {
|
||||
opt_key = "print_host";
|
||||
} else if (opt_key == "octoprint_cafile") {
|
||||
|
|
@ -3206,7 +3218,7 @@ std::string FullPrintConfig::validate()
|
|||
return "Invalid value for --infill-every-layers";
|
||||
|
||||
// --skirt-height
|
||||
if (this->skirt_height < -1) // -1 means as tall as the object
|
||||
if (this->skirt_height < 0)
|
||||
return "Invalid value for --skirt-height";
|
||||
|
||||
// --bridge-flow-ratio
|
||||
|
|
|
|||
|
|
@ -800,6 +800,7 @@ public:
|
|||
ConfigOptionBools retract_layer_change;
|
||||
ConfigOptionFloat skirt_distance;
|
||||
ConfigOptionInt skirt_height;
|
||||
ConfigOptionBool draft_shield;
|
||||
ConfigOptionInt skirts;
|
||||
ConfigOptionInts slowdown_below_layer_time;
|
||||
ConfigOptionBool spiral_vase;
|
||||
|
|
@ -872,6 +873,7 @@ protected:
|
|||
OPT_PTR(retract_layer_change);
|
||||
OPT_PTR(skirt_distance);
|
||||
OPT_PTR(skirt_height);
|
||||
OPT_PTR(draft_shield);
|
||||
OPT_PTR(skirts);
|
||||
OPT_PTR(slowdown_below_layer_time);
|
||||
OPT_PTR(spiral_vase);
|
||||
|
|
|
|||
|
|
@ -817,11 +817,12 @@ void PrintObject::detect_surfaces_type()
|
|||
m_layers[idx_layer]->m_regions[idx_region]->slices.surfaces = std::move(surfaces_new[idx_layer]);
|
||||
}
|
||||
|
||||
if (spiral_vase && num_layers > 1) {
|
||||
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
|
||||
Surfaces &surfaces = m_layers[num_layers - 1]->m_regions[idx_region]->slices.surfaces;
|
||||
for (Surface &surface : surfaces)
|
||||
surface.surface_type = stTop;
|
||||
if (spiral_vase) {
|
||||
if (num_layers > 1)
|
||||
// Turn the last bottom layer infill to a top infill, so it will be extruded with a proper pattern.
|
||||
m_layers[num_layers - 1]->m_regions[idx_region]->slices.set_type(stTop);
|
||||
for (size_t i = num_layers; i < m_layers.size(); ++ i)
|
||||
m_layers[i]->m_regions[idx_region]->slices.set_type(stInternal);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Detecting solid surfaces for region " << idx_region << " - clipping in parallel - start";
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ void to_eigen_mesh(const TriangleMesh &tmesh, Eigen::MatrixXd &V, Eigen::MatrixX
|
|||
void to_triangle_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, TriangleMesh &out)
|
||||
{
|
||||
Pointf3s points(size_t(V.rows()));
|
||||
std::vector<Vec3crd> facets(size_t(F.rows()));
|
||||
std::vector<Vec3i> facets(size_t(F.rows()));
|
||||
|
||||
for (Eigen::Index i = 0; i < V.rows(); ++i)
|
||||
points[size_t(i)] = V.row(i);
|
||||
|
|
|
|||
|
|
@ -48,9 +48,8 @@ Contour3D sphere(double rho, Portion portion, double fa) {
|
|||
vertices.emplace_back(Vec3d(b(0), b(1), z));
|
||||
|
||||
if (sbegin == 0)
|
||||
facets.emplace_back((i == 0) ?
|
||||
Vec3crd(coord_t(ring.size()), 0, 1) :
|
||||
Vec3crd(id - 1, 0, id));
|
||||
(i == 0) ? facets.emplace_back(coord_t(ring.size()), 0, 1) :
|
||||
facets.emplace_back(id - 1, 0, id);
|
||||
++id;
|
||||
}
|
||||
|
||||
|
|
@ -66,12 +65,11 @@ Contour3D sphere(double rho, Portion portion, double fa) {
|
|||
auto id_ringsize = coord_t(id - int(ring.size()));
|
||||
if (i == 0) {
|
||||
// wrap around
|
||||
facets.emplace_back(Vec3crd(id - 1, id,
|
||||
id + coord_t(ring.size() - 1)));
|
||||
facets.emplace_back(Vec3crd(id - 1, id_ringsize, id));
|
||||
facets.emplace_back(id - 1, id, id + coord_t(ring.size() - 1) );
|
||||
facets.emplace_back(id - 1, id_ringsize, id);
|
||||
} else {
|
||||
facets.emplace_back(Vec3crd(id_ringsize - 1, id_ringsize, id));
|
||||
facets.emplace_back(Vec3crd(id - 1, id_ringsize - 1, id));
|
||||
facets.emplace_back(id_ringsize - 1, id_ringsize, id);
|
||||
facets.emplace_back(id - 1, id_ringsize - 1, id);
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
|
@ -85,10 +83,10 @@ Contour3D sphere(double rho, Portion portion, double fa) {
|
|||
auto id_ringsize = coord_t(id - int(ring.size()));
|
||||
if (i == 0) {
|
||||
// third vertex is on the other side of the ring.
|
||||
facets.emplace_back(Vec3crd(id - 1, id_ringsize, id));
|
||||
facets.emplace_back(id - 1, id_ringsize, id);
|
||||
} else {
|
||||
auto ci = coord_t(id_ringsize + coord_t(i));
|
||||
facets.emplace_back(Vec3crd(ci - 1, ci, id));
|
||||
facets.emplace_back(ci - 1, ci, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ public:
|
|||
void remove_type(const SurfaceType type);
|
||||
void remove_types(const SurfaceType *types, int ntypes);
|
||||
void filter_by_type(SurfaceType type, Polygons* polygons);
|
||||
void set_type(SurfaceType type) {
|
||||
for (Surface &surface : this->surfaces)
|
||||
surface.surface_type = type;
|
||||
}
|
||||
|
||||
void clear() { surfaces.clear(); }
|
||||
bool empty() const { return surfaces.empty(); }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _technologies_h_
|
||||
#define _technologies_h_
|
||||
#ifndef _prusaslicer_technologies_h_
|
||||
#define _prusaslicer_technologies_h_
|
||||
|
||||
//============
|
||||
// debug techs
|
||||
|
|
@ -17,37 +17,44 @@
|
|||
#define ENABLE_CAMERA_STATISTICS 0
|
||||
// Render the picking pass instead of the main scene (use [T] key to toggle between regular rendering and picking pass only rendering)
|
||||
#define ENABLE_RENDER_PICKING_PASS 0
|
||||
|
||||
|
||||
//====================
|
||||
// 1.42.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_1_42_0_ALPHA1 1
|
||||
|
||||
// Enable extracting thumbnails from selected gcode and save them as png files
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG 0
|
||||
// Disable synchronization of unselected instances
|
||||
#define DISABLE_INSTANCES_SYNCH (0 && ENABLE_1_42_0_ALPHA1)
|
||||
#define DISABLE_INSTANCES_SYNCH 0
|
||||
// Use wxDataViewRender instead of wxDataViewCustomRenderer
|
||||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING (0 && ENABLE_1_42_0_ALPHA1)
|
||||
#define ENABLE_NONCUSTOM_DATA_VIEW_RENDERING 0
|
||||
|
||||
|
||||
//====================
|
||||
// 2.2.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_2_0_ALPHA1 1
|
||||
|
||||
// Enable thumbnail generator
|
||||
// When removing this technology, remove it also from stable branch,
|
||||
// where it has been partially copied for patch 2.1.1
|
||||
#define ENABLE_THUMBNAIL_GENERATOR (1 && ENABLE_2_2_0_ALPHA1)
|
||||
#define ENABLE_THUMBNAIL_GENERATOR_DEBUG (0 && ENABLE_THUMBNAIL_GENERATOR)
|
||||
|
||||
|
||||
//==================
|
||||
//================
|
||||
// 2.2.0.rc1 techs
|
||||
//==================
|
||||
//================
|
||||
#define ENABLE_2_2_0_RC1 1
|
||||
|
||||
// Enable hack to remove crash when closing on OSX 10.9.5
|
||||
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
|
||||
|
||||
#endif // _technologies_h_
|
||||
|
||||
//==================
|
||||
// 2.2.0.final techs
|
||||
//==================
|
||||
#define ENABLE_2_2_0_FINAL 1
|
||||
|
||||
// Enable tooltips for GLCanvas3D using ImGUI
|
||||
#define ENABLE_CANVAS_TOOLTIP_USING_IMGUI (1 && ENABLE_2_2_0_FINAL)
|
||||
// Enable fix for dragging mouse event handling for gizmobar
|
||||
#define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL)
|
||||
|
||||
|
||||
//===================
|
||||
// 2.3.0.alpha1 techs
|
||||
//===================
|
||||
#define ENABLE_2_3_0_ALPHA1 1
|
||||
|
||||
// Enable rendering of objects colored by facets' slope
|
||||
#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
// Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App
|
||||
#define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_3_0_ALPHA1)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets) : repaired(false)
|
||||
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3i> &facets) : repaired(false)
|
||||
{
|
||||
stl_file &stl = this->stl;
|
||||
stl.stats.type = inmemory;
|
||||
|
|
@ -600,7 +600,7 @@ TriangleMesh TriangleMesh::convex_hull_3d() const
|
|||
|
||||
// Let's collect results:
|
||||
Pointf3s dst_vertices;
|
||||
std::vector<Vec3crd> facets;
|
||||
std::vector<Vec3i> facets;
|
||||
auto facet_list = qhull.facetList().toStdVector();
|
||||
for (const orgQhull::QhullFacet& facet : facet_list)
|
||||
{ // iterate through facets
|
||||
|
|
@ -1931,22 +1931,18 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
|||
// Generate the vertex list for a cube solid of arbitrary size in X/Y/Z.
|
||||
TriangleMesh make_cube(double x, double y, double z)
|
||||
{
|
||||
Vec3d pv[8] = {
|
||||
Vec3d(x, y, 0), Vec3d(x, 0, 0), Vec3d(0, 0, 0),
|
||||
Vec3d(0, y, 0), Vec3d(x, y, z), Vec3d(0, y, z),
|
||||
Vec3d(0, 0, z), Vec3d(x, 0, z)
|
||||
};
|
||||
Vec3crd fv[12] = {
|
||||
Vec3crd(0, 1, 2), Vec3crd(0, 2, 3), Vec3crd(4, 5, 6),
|
||||
Vec3crd(4, 6, 7), Vec3crd(0, 4, 7), Vec3crd(0, 7, 1),
|
||||
Vec3crd(1, 7, 6), Vec3crd(1, 6, 2), Vec3crd(2, 6, 5),
|
||||
Vec3crd(2, 5, 3), Vec3crd(4, 0, 3), Vec3crd(4, 3, 5)
|
||||
};
|
||||
|
||||
std::vector<Vec3crd> facets(&fv[0], &fv[0]+12);
|
||||
Pointf3s vertices(&pv[0], &pv[0]+8);
|
||||
|
||||
TriangleMesh mesh(vertices ,facets);
|
||||
TriangleMesh mesh(
|
||||
{
|
||||
{x, y, 0}, {x, 0, 0}, {0, 0, 0},
|
||||
{0, y, 0}, {x, y, z}, {0, y, z},
|
||||
{0, 0, z}, {x, 0, z}
|
||||
},
|
||||
{
|
||||
{0, 1, 2}, {0, 2, 3}, {4, 5, 6},
|
||||
{4, 6, 7}, {0, 4, 7}, {0, 7, 1},
|
||||
{1, 7, 6}, {1, 6, 2}, {2, 6, 5},
|
||||
{2, 5, 3}, {4, 0, 3}, {4, 3, 5}
|
||||
});
|
||||
mesh.repair();
|
||||
return mesh;
|
||||
}
|
||||
|
|
@ -1959,8 +1955,8 @@ TriangleMesh make_cylinder(double r, double h, double fa)
|
|||
size_t n_steps = (size_t)ceil(2. * PI / fa);
|
||||
double angle_step = 2. * PI / n_steps;
|
||||
|
||||
Pointf3s vertices;
|
||||
std::vector<Vec3crd> facets;
|
||||
Pointf3s vertices;
|
||||
std::vector<Vec3i> facets;
|
||||
vertices.reserve(2 * n_steps + 2);
|
||||
facets.reserve(4 * n_steps);
|
||||
|
||||
|
|
@ -1980,17 +1976,17 @@ TriangleMesh make_cylinder(double r, double h, double fa)
|
|||
vertices.emplace_back(Vec3d(p(0), p(1), 0.));
|
||||
vertices.emplace_back(Vec3d(p(0), p(1), h));
|
||||
int id = (int)vertices.size() - 1;
|
||||
facets.emplace_back(Vec3crd( 0, id - 1, id - 3)); // top
|
||||
facets.emplace_back(Vec3crd(id, 1, id - 2)); // bottom
|
||||
facets.emplace_back(Vec3crd(id, id - 2, id - 3)); // upper-right of side
|
||||
facets.emplace_back(Vec3crd(id, id - 3, id - 1)); // bottom-left of side
|
||||
facets.emplace_back( 0, id - 1, id - 3); // top
|
||||
facets.emplace_back(id, 1, id - 2); // bottom
|
||||
facets.emplace_back(id, id - 2, id - 3); // upper-right of side
|
||||
facets.emplace_back(id, id - 3, id - 1); // bottom-left of side
|
||||
}
|
||||
// Connect the last set of vertices with the first.
|
||||
int id = (int)vertices.size() - 1;
|
||||
facets.emplace_back(Vec3crd( 0, 2, id - 1));
|
||||
facets.emplace_back(Vec3crd( 3, 1, id));
|
||||
facets.emplace_back(Vec3crd(id, 2, 3));
|
||||
facets.emplace_back(Vec3crd(id, id - 1, 2));
|
||||
facets.emplace_back( 0, 2, id - 1);
|
||||
facets.emplace_back( 3, 1, id);
|
||||
facets.emplace_back(id, 2, 3);
|
||||
facets.emplace_back(id, id - 1, 2);
|
||||
|
||||
TriangleMesh mesh(std::move(vertices), std::move(facets));
|
||||
mesh.repair();
|
||||
|
|
@ -2025,7 +2021,7 @@ TriangleMesh make_sphere(double radius, double fa)
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<Vec3crd> facets;
|
||||
std::vector<Vec3i> facets;
|
||||
facets.reserve(2 * (stackCount - 1) * sectorCount);
|
||||
for (int i = 0; i < stackCount; ++ i) {
|
||||
// Beginning of current stack.
|
||||
|
|
@ -2040,11 +2036,11 @@ TriangleMesh make_sphere(double radius, double fa)
|
|||
int k2_next = k2;
|
||||
if (i != 0) {
|
||||
k1_next = (j + 1 == sectorCount) ? k1_first : (k1 + 1);
|
||||
facets.emplace_back(Vec3crd(k1, k2, k1_next));
|
||||
facets.emplace_back(k1, k2, k1_next);
|
||||
}
|
||||
if (i + 1 != stackCount) {
|
||||
k2_next = (j + 1 == sectorCount) ? k2_first : (k2 + 1);
|
||||
facets.emplace_back(Vec3crd(k1_next, k2, k2_next));
|
||||
facets.emplace_back(k1_next, k2, k2_next);
|
||||
}
|
||||
k1 = k1_next;
|
||||
k2 = k2_next;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ class TriangleMesh
|
|||
{
|
||||
public:
|
||||
TriangleMesh() : repaired(false) {}
|
||||
TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
|
||||
TriangleMesh(const Pointf3s &points, const std::vector<Vec3i> &facets);
|
||||
explicit TriangleMesh(const indexed_triangle_set &M);
|
||||
void clear() { this->stl.clear(); this->its.clear(); this->repaired = false; }
|
||||
bool ReadSTLFile(const char* input_file) { return stl_open(&stl, input_file); }
|
||||
|
|
|
|||
57
src/libslic3r/format.hpp
Normal file
57
src/libslic3r/format.hpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef slic3r_format_hpp_
|
||||
#define slic3r_format_hpp_
|
||||
|
||||
// Functional wrapper around boost::format.
|
||||
// One day we may replace this wrapper with C++20 format
|
||||
// https://en.cppreference.com/w/cpp/utility/format/format
|
||||
// though C++20 format uses a different template pattern for position independent parameters.
|
||||
//
|
||||
// Boost::format works around the missing variadic templates by an ugly % chaining operator. The usage of boost::format looks like this:
|
||||
// (boost::format("template") % arg1 %arg2).str()
|
||||
// This wrapper allows for a nicer syntax:
|
||||
// Slic3r::format("template", arg1, arg2)
|
||||
// One can also override Slic3r::internal::format::cook() function to convert a Slic3r::format() argument to something that
|
||||
// boost::format may convert to string, see slic3r/GUI/I18N.hpp for a "cook" function to convert wxString to UTF8.
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// https://gist.github.com/gchudnov/6a90d51af004d97337ec
|
||||
namespace internal {
|
||||
namespace format {
|
||||
// Default "cook" function - just forward.
|
||||
template<typename T>
|
||||
inline T&& cook(T&& arg) {
|
||||
return std::forward<T>(arg);
|
||||
}
|
||||
|
||||
// End of the recursive chain.
|
||||
inline std::string format_recursive(boost::format& message) {
|
||||
return message.str();
|
||||
}
|
||||
|
||||
template<typename TValue, typename... TArgs>
|
||||
std::string format_recursive(boost::format& message, TValue&& arg, TArgs&&... args) {
|
||||
// Format, possibly convert the argument by the "cook" function.
|
||||
message % cook(std::forward<TValue>(arg));
|
||||
return format_recursive(message, std::forward<TArgs>(args)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... TArgs>
|
||||
inline std::string format(const char* fmt, TArgs&&... args) {
|
||||
boost::format message(fmt);
|
||||
return internal::format::format_recursive(message, std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
inline std::string format(const std::string& fmt, TArgs&&... args) {
|
||||
boost::format message(fmt);
|
||||
return internal::format::format_recursive(message, std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_format_hpp_
|
||||
|
|
@ -21,7 +21,13 @@
|
|||
#include "Technologies.hpp"
|
||||
#include "Semver.hpp"
|
||||
|
||||
#if 1
|
||||
// Saves around 32% RAM after slicing step, 6.7% after G-code export (tested on PrusaSlicer 2.2.0 final).
|
||||
typedef int32_t coord_t;
|
||||
#else
|
||||
typedef int64_t coord_t;
|
||||
#endif
|
||||
|
||||
typedef double coordf_t;
|
||||
|
||||
//FIXME This epsilon value is used for many non-related purposes:
|
||||
|
|
@ -33,6 +39,7 @@ typedef double coordf_t;
|
|||
// This scaling generates a following fixed point representation with for a 32bit integer:
|
||||
// 0..4294mm with 1nm resolution
|
||||
// int32_t fits an interval of (-2147.48mm, +2147.48mm)
|
||||
// with int64_t we don't have to worry anymore about the size of the int.
|
||||
#define SCALING_FACTOR 0.000001
|
||||
// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm.
|
||||
#define RESOLUTION 0.0125
|
||||
|
|
@ -98,7 +105,17 @@ extern Semver SEMVER;
|
|||
template<typename T, typename Q>
|
||||
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
|
||||
|
||||
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
|
||||
enum Axis {
|
||||
X=0,
|
||||
Y,
|
||||
Z,
|
||||
E,
|
||||
F,
|
||||
NUM_AXES,
|
||||
// For the GCodeReader to mark a parsed axis, which is not in "XYZEF", it was parsed correctly.
|
||||
UNKNOWN_AXIS = NUM_AXES,
|
||||
NUM_AXES_WITH_UNKNOWN,
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline void append_to(std::vector<T> &dst, const std::vector<T> &src)
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@
|
|||
#include "BoundingBox.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Config.hpp"
|
||||
#include "format.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "MultiPoint.hpp"
|
||||
#include "Point.hpp"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue