mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 01:15:55 +08:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_preview_layout
This commit is contained in:
commit
33da203b18
@ -126,6 +126,45 @@ ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input)
|
|||||||
return PolyTreeToExPolygons(std::move(polytree));
|
return PolyTreeToExPolygons(std::move(polytree));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Global test.
|
||||||
|
bool has_duplicate_points(const ClipperLib::PolyTree &polytree)
|
||||||
|
{
|
||||||
|
struct Helper {
|
||||||
|
static void collect_points_recursive(const ClipperLib::PolyNode &polynode, ClipperLib::Path &out) {
|
||||||
|
// For each hole of the current expolygon:
|
||||||
|
out.insert(out.end(), polynode.Contour.begin(), polynode.Contour.end());
|
||||||
|
for (int i = 0; i < polynode.ChildCount(); ++ i)
|
||||||
|
collect_points_recursive(*polynode.Childs[i], out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClipperLib::Path pts;
|
||||||
|
for (int i = 0; i < polytree.ChildCount(); ++ i)
|
||||||
|
Helper::collect_points_recursive(*polytree.Childs[i], pts);
|
||||||
|
return has_duplicate_points(std::move(pts));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Local test inside each of the contours.
|
||||||
|
bool has_duplicate_points(const ClipperLib::PolyTree &polytree)
|
||||||
|
{
|
||||||
|
struct Helper {
|
||||||
|
static bool has_duplicate_points_recursive(const ClipperLib::PolyNode &polynode) {
|
||||||
|
if (has_duplicate_points(polynode.Contour))
|
||||||
|
return true;
|
||||||
|
for (int i = 0; i < polynode.ChildCount(); ++ i)
|
||||||
|
if (has_duplicate_points_recursive(*polynode.Childs[i]))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ClipperLib::Path pts;
|
||||||
|
for (int i = 0; i < polytree.ChildCount(); ++ i)
|
||||||
|
if (Helper::has_duplicate_points_recursive(*polytree.Childs[i]))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Offset outside by 10um, one by one.
|
// Offset outside by 10um, one by one.
|
||||||
template<typename PathsProvider>
|
template<typename PathsProvider>
|
||||||
static ClipperLib::Paths safety_offset(PathsProvider &&paths)
|
static ClipperLib::Paths safety_offset(PathsProvider &&paths)
|
||||||
|
@ -740,7 +740,11 @@ ConfigSubstitutions ConfigBase::load(const boost::property_tree::ptree &tree, Fo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the config keys from the given string.
|
// Load the config keys from the given string.
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
size_t ConfigBase::load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
|
||||||
|
#else
|
||||||
static inline size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
|
static inline size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions)
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
{
|
{
|
||||||
if (str == nullptr)
|
if (str == nullptr)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2015,6 +2015,10 @@ public:
|
|||||||
// Set all the nullable values to nils.
|
// Set all the nullable values to nils.
|
||||||
void null_nullables();
|
void null_nullables();
|
||||||
|
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
static size_t load_from_gcode_string_legacy(ConfigBase& config, const char* str, ConfigSubstitutionContext& substitutions);
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Set a configuration value from a string.
|
// Set a configuration value from a string.
|
||||||
bool set_deserialize_raw(const t_config_option_key& opt_key_src, const std::string& value, ConfigSubstitutionContext& substitutions, bool append);
|
bool set_deserialize_raw(const t_config_option_key& opt_key_src, const std::string& value, ConfigSubstitutionContext& substitutions, bool append);
|
||||||
|
@ -114,10 +114,11 @@ bool ExPolygon::contains(const Polylines &polylines) const
|
|||||||
|
|
||||||
bool ExPolygon::contains(const Point &point) const
|
bool ExPolygon::contains(const Point &point) const
|
||||||
{
|
{
|
||||||
if (!this->contour.contains(point)) return false;
|
if (! this->contour.contains(point))
|
||||||
for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) {
|
return false;
|
||||||
if (it->contains(point)) return false;
|
for (const Polygon &hole : this->holes)
|
||||||
}
|
if (hole.contains(point))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,6 +368,57 @@ extern std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_duplicate_points(const ExPolygon &expoly)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// Check globally.
|
||||||
|
size_t cnt = expoly.contour.points.size();
|
||||||
|
for (const Polygon &hole : expoly.holes)
|
||||||
|
cnt += hole.points.size();
|
||||||
|
std::vector<Point> allpts;
|
||||||
|
allpts.reserve(cnt);
|
||||||
|
allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end());
|
||||||
|
for (const Polygon &hole : expoly.holes)
|
||||||
|
allpts.insert(allpts.end(), hole.points.begin(), hole.points.end());
|
||||||
|
return has_duplicate_points(std::move(allpts));
|
||||||
|
#else
|
||||||
|
// Check per contour.
|
||||||
|
if (has_duplicate_points(expoly.contour))
|
||||||
|
return true;
|
||||||
|
for (const Polygon &hole : expoly.holes)
|
||||||
|
if (has_duplicate_points(hole))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_duplicate_points(const ExPolygons &expolys)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// Check globally.
|
||||||
|
size_t cnt = 0;
|
||||||
|
for (const ExPolygon &expoly : expolys) {
|
||||||
|
cnt += expoly.contour.points.size();
|
||||||
|
for (const Polygon &hole : expoly.holes)
|
||||||
|
cnt += hole.points.size();
|
||||||
|
}
|
||||||
|
std::vector<Point> allpts;
|
||||||
|
allpts.reserve(cnt);
|
||||||
|
for (const ExPolygon &expoly : expolys) {
|
||||||
|
allpts.insert(allpts.begin(), expoly.contour.points.begin(), expoly.contour.points.end());
|
||||||
|
for (const Polygon &hole : expoly.holes)
|
||||||
|
allpts.insert(allpts.end(), hole.points.begin(), hole.points.end());
|
||||||
|
}
|
||||||
|
return has_duplicate_points(std::move(allpts));
|
||||||
|
#else
|
||||||
|
// Check per contour.
|
||||||
|
for (const ExPolygon &expoly : expolys)
|
||||||
|
if (has_duplicate_points(expoly))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool remove_sticks(ExPolygon &poly)
|
bool remove_sticks(ExPolygon &poly)
|
||||||
{
|
{
|
||||||
return remove_sticks(poly.contour) || remove_sticks(poly.holes);
|
return remove_sticks(poly.contour) || remove_sticks(poly.holes);
|
||||||
|
@ -351,20 +351,24 @@ inline ExPolygons expolygons_simplify(const ExPolygons &expolys, double toleranc
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern BoundingBox get_extents(const ExPolygon &expolygon);
|
BoundingBox get_extents(const ExPolygon &expolygon);
|
||||||
extern BoundingBox get_extents(const ExPolygons &expolygons);
|
BoundingBox get_extents(const ExPolygons &expolygons);
|
||||||
extern BoundingBox get_extents_rotated(const ExPolygon &poly, double angle);
|
BoundingBox get_extents_rotated(const ExPolygon &poly, double angle);
|
||||||
extern BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle);
|
BoundingBox get_extents_rotated(const ExPolygons &polygons, double angle);
|
||||||
extern std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons);
|
std::vector<BoundingBox> get_extents_vector(const ExPolygons &polygons);
|
||||||
|
|
||||||
extern bool remove_sticks(ExPolygon &poly);
|
// Test for duplicate points. The points are copied, sorted and checked for duplicates globally.
|
||||||
extern void keep_largest_contour_only(ExPolygons &polygons);
|
bool has_duplicate_points(const ExPolygon &expoly);
|
||||||
|
bool has_duplicate_points(const ExPolygons &expolys);
|
||||||
|
|
||||||
|
bool remove_sticks(ExPolygon &poly);
|
||||||
|
void keep_largest_contour_only(ExPolygons &polygons);
|
||||||
|
|
||||||
inline double area(const ExPolygon &poly) { return poly.area(); }
|
inline double area(const ExPolygon &poly) { return poly.area(); }
|
||||||
inline double area(const ExPolygons &polys) { double s = 0.; for (auto &p : polys) s += p.area(); return s; }
|
inline double area(const ExPolygons &polys) { double s = 0.; for (auto &p : polys) s += p.area(); return s; }
|
||||||
|
|
||||||
// Removes all expolygons smaller than min_area and also removes all holes smaller than min_area
|
// Removes all expolygons smaller than min_area and also removes all holes smaller than min_area
|
||||||
extern bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area);
|
bool remove_small_and_small_holes(ExPolygons &expolygons, double min_area);
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
@ -1890,6 +1890,7 @@ namespace Slic3r {
|
|||||||
|
|
||||||
unsigned int geo_tri_count = (unsigned int)geometry.triangles.size();
|
unsigned int geo_tri_count = (unsigned int)geometry.triangles.size();
|
||||||
unsigned int renamed_volumes_count = 0;
|
unsigned int renamed_volumes_count = 0;
|
||||||
|
int processed_vertices_max_id = 0;
|
||||||
|
|
||||||
for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) {
|
for (const ObjectMetadata::VolumeMetadata& volume_data : volumes) {
|
||||||
if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) {
|
if (geo_tri_count <= volume_data.first_triangle_id || geo_tri_count <= volume_data.last_triangle_id || volume_data.last_triangle_id < volume_data.first_triangle_id) {
|
||||||
@ -1911,13 +1912,31 @@ namespace Slic3r {
|
|||||||
// splits volume out of imported geometry
|
// splits volume out of imported geometry
|
||||||
std::vector<Vec3i> faces(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1);
|
std::vector<Vec3i> faces(geometry.triangles.begin() + volume_data.first_triangle_id, geometry.triangles.begin() + volume_data.last_triangle_id + 1);
|
||||||
const size_t triangles_count = faces.size();
|
const size_t triangles_count = faces.size();
|
||||||
for (Vec3i face : faces)
|
|
||||||
for (unsigned int tri_id : face)
|
int min_id = faces.front()[0];
|
||||||
|
int max_id = faces.front()[0];
|
||||||
|
for (const Vec3i& face : faces) {
|
||||||
|
for (const int tri_id : face) {
|
||||||
if (tri_id < 0 || tri_id >= geometry.vertices.size()) {
|
if (tri_id < 0 || tri_id >= geometry.vertices.size()) {
|
||||||
add_error("Found invalid vertex id");
|
add_error("Found invalid vertex id");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TriangleMesh triangle_mesh(std::move(geometry.vertices), std::move(faces));
|
min_id = std::min(min_id, tri_id);
|
||||||
|
max_id = std::max(max_id, tri_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// rebase indices to the current vertices list
|
||||||
|
for (Vec3i& face : faces) {
|
||||||
|
for (int& tri_id : face) {
|
||||||
|
tri_id -= min_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processed_vertices_max_id = 1 + std::max(processed_vertices_max_id, max_id);
|
||||||
|
|
||||||
|
std::vector<Vec3f> vertices(geometry.vertices.begin() + min_id, geometry.vertices.begin() + max_id + 1);
|
||||||
|
TriangleMesh triangle_mesh(std::move(vertices), std::move(faces));
|
||||||
|
|
||||||
if (m_version == 0) {
|
if (m_version == 0) {
|
||||||
// if the 3mf was not produced by PrusaSlicer and there is only one instance,
|
// if the 3mf was not produced by PrusaSlicer and there is only one instance,
|
||||||
|
@ -598,7 +598,7 @@ void AMFParserContext::endElement(const char * /* name */)
|
|||||||
case NODE_TYPE_VERTEX:
|
case NODE_TYPE_VERTEX:
|
||||||
assert(m_object);
|
assert(m_object);
|
||||||
// Parse the vertex data
|
// Parse the vertex data
|
||||||
m_object_vertices.emplace_back(float(atof(m_value[0].c_str())), float(atof(m_value[1].c_str())), float(atof(m_value[1].c_str())));
|
m_object_vertices.emplace_back(float(atof(m_value[0].c_str())), float(atof(m_value[1].c_str())), float(atof(m_value[2].c_str())));
|
||||||
m_value[0].clear();
|
m_value[0].clear();
|
||||||
m_value[1].clear();
|
m_value[1].clear();
|
||||||
m_value[2].clear();
|
m_value[2].clear();
|
||||||
|
@ -203,7 +203,7 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg)
|
|||||||
|
|
||||||
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
|
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
|
||||||
!opt_mirror_x || !opt_mirror_y || !opt_orient)
|
!opt_mirror_x || !opt_mirror_y || !opt_orient)
|
||||||
throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
|
throw MissingProfileError("Invalid SL1 / SL1S file");
|
||||||
|
|
||||||
RasterParams rstp;
|
RasterParams rstp;
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg)
|
|||||||
auto *opt_init_layerh = cfg.option<ConfigOptionFloat>("initial_layer_height");
|
auto *opt_init_layerh = cfg.option<ConfigOptionFloat>("initial_layer_height");
|
||||||
|
|
||||||
if (!opt_layerh || !opt_init_layerh)
|
if (!opt_layerh || !opt_init_layerh)
|
||||||
throw Slic3r::FileIOError("Invalid SL1 / SL1S file");
|
throw MissingProfileError("Invalid SL1 / SL1S file");
|
||||||
|
|
||||||
return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
|
return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()};
|
||||||
}
|
}
|
||||||
@ -293,24 +293,34 @@ ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrint
|
|||||||
return out.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
|
return out.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the profile is missing from the archive (older PS versions did not have
|
||||||
|
// it), profile_out's initial value will be used as fallback. profile_out will be empty on
|
||||||
|
// function return if the archive did not contain any profile.
|
||||||
ConfigSubstitutions import_sla_archive(
|
ConfigSubstitutions import_sla_archive(
|
||||||
const std::string & zipfname,
|
const std::string & zipfname,
|
||||||
Vec2i windowsize,
|
Vec2i windowsize,
|
||||||
indexed_triangle_set & out,
|
indexed_triangle_set & out,
|
||||||
DynamicPrintConfig & profile,
|
DynamicPrintConfig & profile_out,
|
||||||
std::function<bool(int)> progr)
|
std::function<bool(int)> progr)
|
||||||
{
|
{
|
||||||
// Ensure minimum window size for marching squares
|
// Ensure minimum window size for marching squares
|
||||||
windowsize.x() = std::max(2, windowsize.x());
|
windowsize.x() = std::max(2, windowsize.x());
|
||||||
windowsize.y() = std::max(2, windowsize.y());
|
windowsize.y() = std::max(2, windowsize.y());
|
||||||
|
|
||||||
ArchiveData arch = extract_sla_archive(zipfname, "thumbnail");
|
std::string exclude_entries{"thumbnail"};
|
||||||
ConfigSubstitutions config_substitutions = profile.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
|
ArchiveData arch = extract_sla_archive(zipfname, exclude_entries);
|
||||||
|
DynamicPrintConfig profile_in, profile_use;
|
||||||
|
ConfigSubstitutions config_substitutions = profile_in.load(arch.profile, ForwardCompatibilitySubstitutionRule::Enable);
|
||||||
|
|
||||||
RasterParams rstp = get_raster_params(profile);
|
// If the archive contains an empty profile, use the one that was passed as output argument
|
||||||
|
// then replace it with the readed profile to report that it was empty.
|
||||||
|
profile_use = profile_in.empty() ? profile_out : profile_in;
|
||||||
|
profile_out = profile_in;
|
||||||
|
|
||||||
|
RasterParams rstp = get_raster_params(profile_use);
|
||||||
rstp.win = {windowsize.y(), windowsize.x()};
|
rstp.win = {windowsize.y(), windowsize.x()};
|
||||||
|
|
||||||
SliceParams slicp = get_slice_params(profile);
|
SliceParams slicp = get_slice_params(profile_use);
|
||||||
|
|
||||||
std::vector<ExPolygons> slices =
|
std::vector<ExPolygons> slices =
|
||||||
extract_slices_from_sla_archive(arch, rstp, progr);
|
extract_slices_from_sla_archive(arch, rstp, progr);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class SL1Archive: public SLAPrinter {
|
class SL1Archive: public SLAArchive {
|
||||||
SLAPrinterConfig m_cfg;
|
SLAPrinterConfig m_cfg;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -57,6 +57,8 @@ inline ConfigSubstitutions import_sla_archive(
|
|||||||
return import_sla_archive(zipfname, windowsize, out, profile, progr);
|
return import_sla_archive(zipfname, windowsize, out, profile, progr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MissingProfileError : public RuntimeError { using RuntimeError::RuntimeError; };
|
||||||
|
|
||||||
} // namespace Slic3r::sla
|
} // namespace Slic3r::sla
|
||||||
|
|
||||||
#endif // ARCHIVETRAITS_HPP
|
#endif // ARCHIVETRAITS_HPP
|
||||||
|
@ -784,7 +784,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
|
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
|
||||||
m_processor.finalize();
|
// Post-process the G-code to update time stamps.
|
||||||
|
m_processor.finalize(true);
|
||||||
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
|
||||||
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
|
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
|
||||||
if (result != nullptr) {
|
if (result != nullptr) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
|
#include "libslic3r/format.hpp"
|
||||||
#include "GCodeProcessor.hpp"
|
#include "GCodeProcessor.hpp"
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
@ -746,6 +747,9 @@ const std::vector<std::pair<GCodeProcessor::EProducer, std::string>> GCodeProces
|
|||||||
{ EProducer::PrusaSlicer, "generated by PrusaSlicer" },
|
{ EProducer::PrusaSlicer, "generated by PrusaSlicer" },
|
||||||
{ EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" },
|
{ EProducer::Slic3rPE, "generated by Slic3r Prusa Edition" },
|
||||||
{ EProducer::Slic3r, "generated by Slic3r" },
|
{ EProducer::Slic3r, "generated by Slic3r" },
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
{ EProducer::SuperSlicer, "generated by SuperSlicer" },
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
{ EProducer::Cura, "Cura_SteamEngine" },
|
{ EProducer::Cura, "Cura_SteamEngine" },
|
||||||
{ EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" },
|
{ EProducer::Simplify3D, "G-Code generated by Simplify3D(R)" },
|
||||||
{ EProducer::CraftWare, "CraftWare" },
|
{ EProducer::CraftWare, "CraftWare" },
|
||||||
@ -1189,6 +1193,8 @@ static inline const char* remove_eols(const char *begin, const char *end) {
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load a G-code into a stand-alone G-code viewer.
|
||||||
|
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
||||||
void GCodeProcessor::process_file(const std::string& filename, std::function<void()> cancel_callback)
|
void GCodeProcessor::process_file(const std::string& filename, std::function<void()> cancel_callback)
|
||||||
{
|
{
|
||||||
CNumericLocalesSetter locales_setter;
|
CNumericLocalesSetter locales_setter;
|
||||||
@ -1225,6 +1231,10 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
|
|||||||
}
|
}
|
||||||
else if (m_producer == EProducer::Simplify3D)
|
else if (m_producer == EProducer::Simplify3D)
|
||||||
apply_config_simplify3d(filename);
|
apply_config_simplify3d(filename);
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
else if (m_producer == EProducer::SuperSlicer)
|
||||||
|
apply_config_superslicer(filename);
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
}
|
}
|
||||||
|
|
||||||
// process gcode
|
// process gcode
|
||||||
@ -1243,7 +1253,8 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
|
|||||||
this->process_gcode_line(line, true);
|
this->process_gcode_line(line, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
this->finalize();
|
// Don't post-process the G-code to update time stamps.
|
||||||
|
this->finalize(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeProcessor::initialize(const std::string& filename)
|
void GCodeProcessor::initialize(const std::string& filename)
|
||||||
@ -1269,7 +1280,7 @@ void GCodeProcessor::process_buffer(const std::string &buffer)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeProcessor::finalize()
|
void GCodeProcessor::finalize(bool post_process)
|
||||||
{
|
{
|
||||||
// update width/height of wipe moves
|
// update width/height of wipe moves
|
||||||
for (MoveVertex& move : m_result.moves) {
|
for (MoveVertex& move : m_result.moves) {
|
||||||
@ -1299,6 +1310,7 @@ void GCodeProcessor::finalize()
|
|||||||
m_width_compare.output();
|
m_width_compare.output();
|
||||||
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||||
|
|
||||||
|
if (post_process)
|
||||||
m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends);
|
m_time_processor.post_process(m_result.filename, m_result.moves, m_result.lines_ends);
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
m_result.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_start_time).count();
|
m_result.time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - m_start_time).count();
|
||||||
@ -1356,6 +1368,41 @@ std::vector<std::pair<ExtrusionRole, float>> GCodeProcessor::get_roles_time(Prin
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
ConfigSubstitutions load_from_superslicer_gcode_file(const std::string& filename, DynamicPrintConfig& config, ForwardCompatibilitySubstitutionRule compatibility_rule)
|
||||||
|
{
|
||||||
|
// for reference, see: ConfigBase::load_from_gcode_file()
|
||||||
|
|
||||||
|
boost::nowide::ifstream ifs(filename);
|
||||||
|
|
||||||
|
auto header_end_pos = ifs.tellg();
|
||||||
|
ConfigSubstitutionContext substitutions_ctxt(compatibility_rule);
|
||||||
|
size_t key_value_pairs = 0;
|
||||||
|
|
||||||
|
ifs.seekg(0, ifs.end);
|
||||||
|
auto file_length = ifs.tellg();
|
||||||
|
auto data_length = std::min<std::fstream::pos_type>(65535, file_length - header_end_pos);
|
||||||
|
ifs.seekg(file_length - data_length, ifs.beg);
|
||||||
|
std::vector<char> data(size_t(data_length) + 1, 0);
|
||||||
|
ifs.read(data.data(), data_length);
|
||||||
|
ifs.close();
|
||||||
|
key_value_pairs = ConfigBase::load_from_gcode_string_legacy(config, data.data(), substitutions_ctxt);
|
||||||
|
|
||||||
|
if (key_value_pairs < 80)
|
||||||
|
throw Slic3r::RuntimeError(format("Suspiciously low number of configuration values extracted from %1%: %2%", filename, key_value_pairs));
|
||||||
|
|
||||||
|
return std::move(substitutions_ctxt.substitutions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCodeProcessor::apply_config_superslicer(const std::string& filename)
|
||||||
|
{
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
config.apply(FullPrintConfig::defaults());
|
||||||
|
load_from_superslicer_gcode_file(filename, config, ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||||
|
apply_config(config);
|
||||||
|
}
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
|
||||||
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
|
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
|
||||||
{
|
{
|
||||||
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ?
|
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ?
|
||||||
@ -1845,6 +1892,9 @@ bool GCodeProcessor::process_producers_tags(const std::string_view comment)
|
|||||||
{
|
{
|
||||||
case EProducer::Slic3rPE:
|
case EProducer::Slic3rPE:
|
||||||
case EProducer::Slic3r:
|
case EProducer::Slic3r:
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
case EProducer::SuperSlicer:
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
|
case EProducer::PrusaSlicer: { return process_prusaslicer_tags(comment); }
|
||||||
case EProducer::Cura: { return process_cura_tags(comment); }
|
case EProducer::Cura: { return process_cura_tags(comment); }
|
||||||
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
|
case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
|
||||||
@ -2674,15 +2724,15 @@ void GCodeProcessor::process_G28(const GCodeReader::GCodeLine& line)
|
|||||||
std::string_view cmd = line.cmd();
|
std::string_view cmd = line.cmd();
|
||||||
std::string new_line_raw = { cmd.data(), cmd.size() };
|
std::string new_line_raw = { cmd.data(), cmd.size() };
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if (line.has_x()) {
|
if (line.has('X')) {
|
||||||
new_line_raw += " X0";
|
new_line_raw += " X0";
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
if (line.has_y()) {
|
if (line.has('Y')) {
|
||||||
new_line_raw += " Y0";
|
new_line_raw += " Y0";
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
if (line.has_z()) {
|
if (line.has('Z')) {
|
||||||
new_line_raw += " Z0";
|
new_line_raw += " Z0";
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@ -2818,16 +2868,16 @@ void GCodeProcessor::process_M132(const GCodeReader::GCodeLine& line)
|
|||||||
// see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md
|
// see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md
|
||||||
// Using this command to reset the axis origin to zero helps in fixing: https://github.com/prusa3d/PrusaSlicer/issues/3082
|
// Using this command to reset the axis origin to zero helps in fixing: https://github.com/prusa3d/PrusaSlicer/issues/3082
|
||||||
|
|
||||||
if (line.has_x())
|
if (line.has('X'))
|
||||||
m_origin[X] = 0.0f;
|
m_origin[X] = 0.0f;
|
||||||
|
|
||||||
if (line.has_y())
|
if (line.has('Y'))
|
||||||
m_origin[Y] = 0.0f;
|
m_origin[Y] = 0.0f;
|
||||||
|
|
||||||
if (line.has_z())
|
if (line.has('Z'))
|
||||||
m_origin[Z] = 0.0f;
|
m_origin[Z] = 0.0f;
|
||||||
|
|
||||||
if (line.has_e())
|
if (line.has('E'))
|
||||||
m_origin[E] = 0.0f;
|
m_origin[E] = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2988,7 +3038,7 @@ void GCodeProcessor::process_M402(const GCodeReader::GCodeLine& line)
|
|||||||
// https://github.com/repetier/Repetier-Firmware/blob/master/src/ArduinoAVR/Repetier/Printer.cpp
|
// https://github.com/repetier/Repetier-Firmware/blob/master/src/ArduinoAVR/Repetier/Printer.cpp
|
||||||
// void Printer::GoToMemoryPosition(bool x, bool y, bool z, bool e, float feed)
|
// void Printer::GoToMemoryPosition(bool x, bool y, bool z, bool e, float feed)
|
||||||
|
|
||||||
bool has_xyz = !(line.has_x() || line.has_y() || line.has_z());
|
bool has_xyz = !(line.has('X') || line.has('Y') || line.has('Z'));
|
||||||
|
|
||||||
float p = FLT_MAX;
|
float p = FLT_MAX;
|
||||||
for (unsigned char a = X; a <= Z; ++a) {
|
for (unsigned char a = X; a <= Z; ++a) {
|
||||||
|
@ -543,6 +543,9 @@ namespace Slic3r {
|
|||||||
PrusaSlicer,
|
PrusaSlicer,
|
||||||
Slic3rPE,
|
Slic3rPE,
|
||||||
Slic3r,
|
Slic3r,
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
SuperSlicer,
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
Cura,
|
Cura,
|
||||||
Simplify3D,
|
Simplify3D,
|
||||||
CraftWare,
|
CraftWare,
|
||||||
@ -579,14 +582,14 @@ namespace Slic3r {
|
|||||||
const Result& get_result() const { return m_result; }
|
const Result& get_result() const { return m_result; }
|
||||||
Result&& extract_result() { return std::move(m_result); }
|
Result&& extract_result() { return std::move(m_result); }
|
||||||
|
|
||||||
// Process the gcode contained in the file with the given filename
|
// Load a G-code into a stand-alone G-code viewer.
|
||||||
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
// throws CanceledException through print->throw_if_canceled() (sent by the caller as callback).
|
||||||
void process_file(const std::string& filename, std::function<void()> cancel_callback = nullptr);
|
void process_file(const std::string& filename, std::function<void()> cancel_callback = nullptr);
|
||||||
|
|
||||||
// Streaming interface, for processing G-codes just generated by PrusaSlicer in a pipelined fashion.
|
// Streaming interface, for processing G-codes just generated by PrusaSlicer in a pipelined fashion.
|
||||||
void initialize(const std::string& filename);
|
void initialize(const std::string& filename);
|
||||||
void process_buffer(const std::string& buffer);
|
void process_buffer(const std::string& buffer);
|
||||||
void finalize();
|
void finalize(bool post_process);
|
||||||
|
|
||||||
float get_time(PrintEstimatedStatistics::ETimeMode mode) const;
|
float get_time(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||||
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
|
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const;
|
||||||
@ -599,6 +602,9 @@ namespace Slic3r {
|
|||||||
private:
|
private:
|
||||||
void apply_config(const DynamicPrintConfig& config);
|
void apply_config(const DynamicPrintConfig& config);
|
||||||
void apply_config_simplify3d(const std::string& filename);
|
void apply_config_simplify3d(const std::string& filename);
|
||||||
|
#if ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
|
void apply_config_superslicer(const std::string& filename);
|
||||||
|
#endif // ENABLE_FIX_SUPERSLICER_GCODE_IMPORT
|
||||||
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
|
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
|
||||||
|
|
||||||
// Process tags embedded into comments
|
// Process tags embedded into comments
|
||||||
|
@ -179,6 +179,15 @@ Point Point::projection_onto(const Line &line) const
|
|||||||
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
|
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_duplicate_points(std::vector<Point> &&pts)
|
||||||
|
{
|
||||||
|
std::sort(pts.begin(), pts.end());
|
||||||
|
for (size_t i = 1; i < pts.size(); ++ i)
|
||||||
|
if (pts[i - 1] == pts[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BoundingBox get_extents(const Points &pts)
|
BoundingBox get_extents(const Points &pts)
|
||||||
{
|
{
|
||||||
return BoundingBox(pts);
|
return BoundingBox(pts);
|
||||||
|
@ -211,8 +211,34 @@ inline Point lerp(const Point &a, const Point &b, double t)
|
|||||||
return ((1. - t) * a.cast<double>() + t * b.cast<double>()).cast<coord_t>();
|
return ((1. - t) * a.cast<double>() + t * b.cast<double>()).cast<coord_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern BoundingBox get_extents(const Points &pts);
|
BoundingBox get_extents(const Points &pts);
|
||||||
extern BoundingBox get_extents(const std::vector<Points> &pts);
|
BoundingBox get_extents(const std::vector<Points> &pts);
|
||||||
|
|
||||||
|
// Test for duplicate points in a vector of points.
|
||||||
|
// The points are copied, sorted and checked for duplicates globally.
|
||||||
|
bool has_duplicate_points(std::vector<Point> &&pts);
|
||||||
|
inline bool has_duplicate_points(const std::vector<Point> &pts)
|
||||||
|
{
|
||||||
|
std::vector<Point> cpy = pts;
|
||||||
|
return has_duplicate_points(std::move(cpy));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for duplicate points in a vector of points.
|
||||||
|
// Only successive points are checked for equality.
|
||||||
|
inline bool has_duplicate_successive_points(const std::vector<Point> &pts)
|
||||||
|
{
|
||||||
|
for (size_t i = 1; i < pts.size(); ++ i)
|
||||||
|
if (pts[i - 1] == pts[i])
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for duplicate points in a vector of points.
|
||||||
|
// Only successive points are checked for equality. Additionally, first and last points are compared for equality.
|
||||||
|
inline bool has_duplicate_successive_points_closed(const std::vector<Point> &pts)
|
||||||
|
{
|
||||||
|
return has_duplicate_successive_points(pts) || (pts.size() >= 2 && pts.front() == pts.back());
|
||||||
|
}
|
||||||
|
|
||||||
namespace int128 {
|
namespace int128 {
|
||||||
// Exact orientation predicate,
|
// Exact orientation predicate,
|
||||||
|
@ -334,6 +334,27 @@ extern std::vector<BoundingBox> get_extents_vector(const Polygons &polygons)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_duplicate_points(const Polygons &polys)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// Check globally.
|
||||||
|
size_t cnt = 0;
|
||||||
|
for (const Polygon &poly : polys)
|
||||||
|
cnt += poly.points.size();
|
||||||
|
std::vector<Point> allpts;
|
||||||
|
allpts.reserve(cnt);
|
||||||
|
for (const Polygon &poly : polys)
|
||||||
|
allpts.insert(allpts.end(), poly.points.begin(), poly.points.end());
|
||||||
|
return has_duplicate_points(std::move(allpts));
|
||||||
|
#else
|
||||||
|
// Check per contour.
|
||||||
|
for (const Polygon &poly : polys)
|
||||||
|
if (has_duplicate_points(poly))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3)
|
static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3)
|
||||||
{
|
{
|
||||||
Point v1 = p2 - p1;
|
Point v1 = p2 - p1;
|
||||||
|
@ -78,11 +78,16 @@ public:
|
|||||||
inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; }
|
inline bool operator==(const Polygon &lhs, const Polygon &rhs) { return lhs.points == rhs.points; }
|
||||||
inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; }
|
inline bool operator!=(const Polygon &lhs, const Polygon &rhs) { return lhs.points != rhs.points; }
|
||||||
|
|
||||||
extern BoundingBox get_extents(const Polygon &poly);
|
BoundingBox get_extents(const Polygon &poly);
|
||||||
extern BoundingBox get_extents(const Polygons &polygons);
|
BoundingBox get_extents(const Polygons &polygons);
|
||||||
extern BoundingBox get_extents_rotated(const Polygon &poly, double angle);
|
BoundingBox get_extents_rotated(const Polygon &poly, double angle);
|
||||||
extern BoundingBox get_extents_rotated(const Polygons &polygons, double angle);
|
BoundingBox get_extents_rotated(const Polygons &polygons, double angle);
|
||||||
extern std::vector<BoundingBox> get_extents_vector(const Polygons &polygons);
|
std::vector<BoundingBox> get_extents_vector(const Polygons &polygons);
|
||||||
|
|
||||||
|
// Test for duplicate points. The points are copied, sorted and checked for duplicates globally.
|
||||||
|
inline bool has_duplicate_points(Polygon &&poly) { return has_duplicate_points(std::move(poly.points)); }
|
||||||
|
inline bool has_duplicate_points(const Polygon &poly) { return has_duplicate_points(poly.points); }
|
||||||
|
bool has_duplicate_points(const Polygons &polys);
|
||||||
|
|
||||||
inline double total_length(const Polygons &polylines) {
|
inline double total_length(const Polygons &polylines) {
|
||||||
double total = 0;
|
double total = 0;
|
||||||
@ -102,14 +107,14 @@ inline double area(const Polygons &polys)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove sticks (tentacles with zero area) from the polygon.
|
// Remove sticks (tentacles with zero area) from the polygon.
|
||||||
extern bool remove_sticks(Polygon &poly);
|
bool remove_sticks(Polygon &poly);
|
||||||
extern bool remove_sticks(Polygons &polys);
|
bool remove_sticks(Polygons &polys);
|
||||||
|
|
||||||
// Remove polygons with less than 3 edges.
|
// Remove polygons with less than 3 edges.
|
||||||
extern bool remove_degenerate(Polygons &polys);
|
bool remove_degenerate(Polygons &polys);
|
||||||
extern bool remove_small(Polygons &polys, double min_area);
|
bool remove_small(Polygons &polys, double min_area);
|
||||||
extern void remove_collinear(Polygon &poly);
|
void remove_collinear(Polygon &poly);
|
||||||
extern void remove_collinear(Polygons &polys);
|
void remove_collinear(Polygons &polys);
|
||||||
|
|
||||||
// Append a vector of polygons at the end of another vector of polygons.
|
// Append a vector of polygons at the end of another vector of polygons.
|
||||||
inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); }
|
inline void polygons_append(Polygons &dst, const Polygons &src) { dst.insert(dst.end(), src.begin(), src.end()); }
|
||||||
|
@ -1097,14 +1097,6 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
|
|||||||
return m_idx_selected;
|
return m_idx_selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the preset under a new name. If the name is different from the old one,
|
|
||||||
// a new preset is stored into the list of presets.
|
|
||||||
// All presets are marked as not modified and the new preset is activated.
|
|
||||||
//void PresetCollection::save_current_preset(const std::string &new_name);
|
|
||||||
|
|
||||||
// Delete the current preset, activate the first visible preset.
|
|
||||||
//void PresetCollection::delete_current_preset();
|
|
||||||
|
|
||||||
// Update a dirty flag of the current preset
|
// Update a dirty flag of the current preset
|
||||||
// Return true if the dirty flag changed.
|
// Return true if the dirty flag changed.
|
||||||
bool PresetCollection::update_dirty()
|
bool PresetCollection::update_dirty()
|
||||||
|
@ -143,7 +143,7 @@ public:
|
|||||||
|
|
||||||
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const;
|
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const;
|
||||||
|
|
||||||
// Save current preset of a required type under a new name. If the name is different from the old one,
|
// Save current preset of a provided type under a new name. If the name is different from the old one,
|
||||||
// Unselected option would be reverted to the beginning values
|
// Unselected option would be reverted to the beginning values
|
||||||
void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector<std::string>& unselected_options);
|
void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector<std::string>& unselected_options);
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
|
|||||||
DynamicConfig cfg;
|
DynamicConfig cfg;
|
||||||
if (config_override != nullptr)
|
if (config_override != nullptr)
|
||||||
cfg = *config_override;
|
cfg = *config_override;
|
||||||
|
cfg.set_key_value("version", new ConfigOptionString(std::string(SLIC3R_VERSION)));
|
||||||
PlaceholderParser::update_timestamp(cfg);
|
PlaceholderParser::update_timestamp(cfg);
|
||||||
this->update_object_placeholders(cfg, default_ext);
|
this->update_object_placeholders(cfg, default_ext);
|
||||||
if (! filename_base.empty()) {
|
if (! filename_base.empty()) {
|
||||||
|
@ -670,7 +670,7 @@ std::string SLAPrint::validate(std::string*) const
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void SLAPrint::set_printer(SLAPrinter *arch)
|
void SLAPrint::set_printer(SLAArchive *arch)
|
||||||
{
|
{
|
||||||
invalidate_step(slapsRasterize);
|
invalidate_step(slapsRasterize);
|
||||||
m_printer = arch;
|
m_printer = arch;
|
||||||
@ -1047,15 +1047,15 @@ Vec3d SLAPrint::relative_correction() const
|
|||||||
Vec3d corr(1., 1., 1.);
|
Vec3d corr(1., 1., 1.);
|
||||||
|
|
||||||
if(printer_config().relative_correction.values.size() >= 2) {
|
if(printer_config().relative_correction.values.size() >= 2) {
|
||||||
corr(X) = printer_config().relative_correction.values[0];
|
corr.x() = printer_config().relative_correction.values[0];
|
||||||
corr(Y) = printer_config().relative_correction.values[0];
|
corr.y() = corr.x();
|
||||||
corr(Z) = printer_config().relative_correction.values.back();
|
corr.z() = printer_config().relative_correction.values[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(material_config().material_correction.values.size() >= 2) {
|
if(material_config().material_correction.values.size() >= 2) {
|
||||||
corr(X) *= material_config().material_correction.values[0];
|
corr.x() *= material_config().material_correction.values[0];
|
||||||
corr(Y) *= material_config().material_correction.values[0];
|
corr.y() = corr.x();
|
||||||
corr(Z) *= material_config().material_correction.values.back();
|
corr.z() *= material_config().material_correction.values[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return corr;
|
return corr;
|
||||||
|
@ -387,7 +387,7 @@ struct SLAPrintStatistics
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SLAPrinter {
|
class SLAArchive {
|
||||||
protected:
|
protected:
|
||||||
std::vector<sla::EncodedRaster> m_layers;
|
std::vector<sla::EncodedRaster> m_layers;
|
||||||
|
|
||||||
@ -395,7 +395,7 @@ protected:
|
|||||||
virtual sla::RasterEncoder get_encoder() const = 0;
|
virtual sla::RasterEncoder get_encoder() const = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~SLAPrinter() = default;
|
virtual ~SLAArchive() = default;
|
||||||
|
|
||||||
virtual void apply(const SLAPrinterConfig &cfg) = 0;
|
virtual void apply(const SLAPrinterConfig &cfg) = 0;
|
||||||
|
|
||||||
@ -526,7 +526,7 @@ public:
|
|||||||
// TODO: use this structure for the preview in the future.
|
// TODO: use this structure for the preview in the future.
|
||||||
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
||||||
|
|
||||||
void set_printer(SLAPrinter *archiver);
|
void set_printer(SLAArchive *archiver);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -548,7 +548,7 @@ private:
|
|||||||
std::vector<PrintLayer> m_printer_input;
|
std::vector<PrintLayer> m_printer_input;
|
||||||
|
|
||||||
// The archive object which collects the raster images after slicing
|
// The archive object which collects the raster images after slicing
|
||||||
SLAPrinter *m_printer = nullptr;
|
SLAArchive *m_printer = nullptr;
|
||||||
|
|
||||||
// Estimated print time, material consumed.
|
// Estimated print time, material consumed.
|
||||||
SLAPrintStatistics m_print_statistics;
|
SLAPrintStatistics m_print_statistics;
|
||||||
|
@ -1630,7 +1630,7 @@ static inline std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupport
|
|||||||
// Don't want to print a layer below the first layer height as it may not stick well.
|
// Don't want to print a layer below the first layer height as it may not stick well.
|
||||||
//FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact
|
//FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact
|
||||||
// and it may actually make sense to do it with a thinner layer than the first layer height.
|
// and it may actually make sense to do it with a thinner layer than the first layer height.
|
||||||
const coordf_t min_print_z = slicing_params.has_raft() ? slicing_params.raft_interface_top_z + support_layer_height_min + EPSILON : slicing_params.first_print_layer_height - EPSILON;
|
const coordf_t min_print_z = slicing_params.raft_layers() > 1 ? slicing_params.raft_interface_top_z + support_layer_height_min + EPSILON : slicing_params.first_print_layer_height - EPSILON;
|
||||||
if (print_z < min_print_z) {
|
if (print_z < min_print_z) {
|
||||||
// This contact layer is below the first layer height, therefore not printable. Don't support this surface.
|
// This contact layer is below the first layer height, therefore not printable. Don't support this surface.
|
||||||
return std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupportMaterial::MyLayer*>(nullptr, nullptr);
|
return std::pair<PrintObjectSupportMaterial::MyLayer*, PrintObjectSupportMaterial::MyLayer*>(nullptr, nullptr);
|
||||||
|
@ -66,4 +66,13 @@
|
|||||||
#define ENABLE_PREVIEW_LAYOUT (1 && ENABLE_2_4_0_ALPHA2)
|
#define ENABLE_PREVIEW_LAYOUT (1 && ENABLE_2_4_0_ALPHA2)
|
||||||
|
|
||||||
|
|
||||||
|
//====================
|
||||||
|
// 2.4.0.alpha3 techs
|
||||||
|
//====================
|
||||||
|
#define ENABLE_2_4_0_ALPHA3 1
|
||||||
|
|
||||||
|
// Enable fixing loading of gcode files generated with SuperSlicer in GCodeViewer
|
||||||
|
#define ENABLE_FIX_SUPERSLICER_GCODE_IMPORT (1 && ENABLE_2_4_0_ALPHA3)
|
||||||
|
|
||||||
|
|
||||||
#endif // _prusaslicer_technologies_h_
|
#endif // _prusaslicer_technologies_h_
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
#include <boost/nowide/cstdio.hpp>
|
#include <boost/nowide/cstdio.hpp>
|
||||||
|
#include <boost/predef/other/endian.h>
|
||||||
|
|
||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/Dense>
|
#include <Eigen/Dense>
|
||||||
|
@ -12,7 +12,7 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@
|
|||||||
VALUE "ProductName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
VALUE "ProductName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||||
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
||||||
VALUE "InternalName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
VALUE "InternalName", "@SLIC3R_APP_NAME@ G-code Viewer"
|
||||||
VALUE "LegalCopyright", "Copyright \251 2016-2020 Prusa Research, \251 2011-2018 Alessandro Ranellucci"
|
VALUE "LegalCopyright", "Copyright \251 2016-2021 Prusa Research, \251 2011-2018 Alessandro Ranellucci"
|
||||||
VALUE "OriginalFilename", "prusa-gcodeviewer.exe"
|
VALUE "OriginalFilename", "prusa-gcodeviewer.exe"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ PRODUCTVERSION @SLIC3R_RC_VERSION@
|
|||||||
VALUE "ProductName", "@SLIC3R_APP_NAME@"
|
VALUE "ProductName", "@SLIC3R_APP_NAME@"
|
||||||
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
VALUE "ProductVersion", "@SLIC3R_BUILD_ID@"
|
||||||
VALUE "InternalName", "@SLIC3R_APP_NAME@"
|
VALUE "InternalName", "@SLIC3R_APP_NAME@"
|
||||||
VALUE "LegalCopyright", "Copyright \251 2016-2020 Prusa Research, \251 2011-2018 Alessandro Ranellucci"
|
VALUE "LegalCopyright", "Copyright \251 2016-2021 Prusa Research, \251 2011-2018 Alessandro Ranellucci"
|
||||||
VALUE "OriginalFilename", "prusa-slicer.exe"
|
VALUE "OriginalFilename", "prusa-slicer.exe"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>@SLIC3R_APP_KEY@</string>
|
<string>@SLIC3R_APP_KEY@</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>@SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2020 Prusa Reseach</string>
|
<string>@SLIC3R_APP_NAME@ Copyright (C) 2011-2019 Alessandro Ranellucci, (C) 2016-2021 Prusa Reseach</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>PrusaSlicer.icns</string>
|
<string>PrusaSlicer.icns</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
|
@ -275,7 +275,7 @@ AboutDialog::AboutDialog()
|
|||||||
"<html>"
|
"<html>"
|
||||||
"<body bgcolor= %1% link= %2%>"
|
"<body bgcolor= %1% link= %2%>"
|
||||||
"<font color=%3%>"
|
"<font color=%3%>"
|
||||||
"%4% © 2016-2020 Prusa Research. <br />"
|
"%4% © 2016-2021 Prusa Research. <br />"
|
||||||
"%5% © 2011-2018 Alessandro Ranellucci. <br />"
|
"%5% © 2011-2018 Alessandro Ranellucci. <br />"
|
||||||
"<a href=\"http://slic3r.org/\">Slic3r</a> %6% "
|
"<a href=\"http://slic3r.org/\">Slic3r</a> %6% "
|
||||||
"<a href=\"http://www.gnu.org/licenses/agpl-3.0.html\">%7%</a>."
|
"<a href=\"http://www.gnu.org/licenses/agpl-3.0.html\">%7%</a>."
|
||||||
|
@ -573,6 +573,89 @@ GCodeViewer::GCodeViewer()
|
|||||||
// m_sequential_view.skip_invisible_moves = true;
|
// m_sequential_view.skip_invisible_moves = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLE_SEAMS_USING_MODELS
|
||||||
|
void GCodeViewer::init()
|
||||||
|
{
|
||||||
|
if (m_gl_data_initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// initializes opengl data of TBuffers
|
||||||
|
for (size_t i = 0; i < m_buffers.size(); ++i) {
|
||||||
|
TBuffer& buffer = m_buffers[i];
|
||||||
|
EMoveType type = buffer_type(i);
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
default: { break; }
|
||||||
|
case EMoveType::Tool_change:
|
||||||
|
case EMoveType::Color_change:
|
||||||
|
case EMoveType::Pause_Print:
|
||||||
|
case EMoveType::Custom_GCode:
|
||||||
|
case EMoveType::Retract:
|
||||||
|
case EMoveType::Unretract:
|
||||||
|
case EMoveType::Seam: {
|
||||||
|
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||||
|
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
||||||
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
|
||||||
|
buffer.shader = "gouraud_light_instanced";
|
||||||
|
buffer.model.model.init_from(diamond(16));
|
||||||
|
buffer.model.color = option_color(type);
|
||||||
|
buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel;
|
||||||
|
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
|
||||||
|
buffer.shader = "gouraud_light";
|
||||||
|
|
||||||
|
buffer.model.data = diamond(16);
|
||||||
|
buffer.model.color = option_color(type);
|
||||||
|
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
||||||
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
|
||||||
|
buffer.shader = "gouraud_light_instanced";
|
||||||
|
buffer.model.model.init_from(diamond(16));
|
||||||
|
buffer.model.color = option_color(type);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
|
||||||
|
buffer.vertices.format = VBuffer::EFormat::Position;
|
||||||
|
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
||||||
|
}
|
||||||
|
case EMoveType::Wipe:
|
||||||
|
case EMoveType::Extrude: {
|
||||||
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
|
||||||
|
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
|
||||||
|
buffer.shader = "gouraud_light";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EMoveType::Travel: {
|
||||||
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Line;
|
||||||
|
buffer.vertices.format = VBuffer::EFormat::PositionNormal1;
|
||||||
|
buffer.shader = "toolpaths_lines";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_toolpath_move_type_visible(EMoveType::Extrude, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initializes tool marker
|
||||||
|
m_sequential_view.marker.init();
|
||||||
|
|
||||||
|
// initializes point sizes
|
||||||
|
std::array<int, 2> point_sizes;
|
||||||
|
::glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_sizes.data());
|
||||||
|
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
|
||||||
|
|
||||||
|
m_gl_data_initialized = true;
|
||||||
|
}
|
||||||
|
#endif // ENABLE_SEAMS_USING_MODELS
|
||||||
|
|
||||||
void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized)
|
void GCodeViewer::load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized)
|
||||||
{
|
{
|
||||||
// avoid processing if called with the same gcode_result
|
// avoid processing if called with the same gcode_result
|
||||||
@ -765,6 +848,7 @@ void GCodeViewer::reset()
|
|||||||
|
|
||||||
void GCodeViewer::render()
|
void GCodeViewer::render()
|
||||||
{
|
{
|
||||||
|
#if !ENABLE_SEAMS_USING_MODELS
|
||||||
auto init_gl_data = [this]() {
|
auto init_gl_data = [this]() {
|
||||||
// initializes opengl data of TBuffers
|
// initializes opengl data of TBuffers
|
||||||
for (size_t i = 0; i < m_buffers.size(); ++i) {
|
for (size_t i = 0; i < m_buffers.size(); ++i) {
|
||||||
@ -780,26 +864,6 @@ void GCodeViewer::render()
|
|||||||
case EMoveType::Retract:
|
case EMoveType::Retract:
|
||||||
case EMoveType::Unretract:
|
case EMoveType::Unretract:
|
||||||
case EMoveType::Seam: {
|
case EMoveType::Seam: {
|
||||||
#if ENABLE_SEAMS_USING_MODELS
|
|
||||||
#if ENABLE_SEAMS_USING_BATCHED_MODELS
|
|
||||||
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
|
||||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::InstancedModel;
|
|
||||||
buffer.shader = "gouraud_light_instanced";
|
|
||||||
buffer.model.model.init_from(diamond(16));
|
|
||||||
buffer.model.color = option_color(type);
|
|
||||||
buffer.model.instances.format = InstanceVBuffer::EFormat::InstancedModel;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::BatchedModel;
|
|
||||||
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
|
|
||||||
buffer.shader = "gouraud_light";
|
|
||||||
|
|
||||||
buffer.model.data = diamond(16);
|
|
||||||
buffer.model.color = option_color(type);
|
|
||||||
buffer.model.instances.format = InstanceVBuffer::EFormat::BatchedModel;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
if (wxGetApp().is_gl_version_greater_or_equal_to(3, 3)) {
|
||||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
|
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Model;
|
||||||
buffer.shader = "gouraud_light_instanced";
|
buffer.shader = "gouraud_light_instanced";
|
||||||
@ -812,36 +876,17 @@ void GCodeViewer::render()
|
|||||||
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
|
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif // ENABLE_SEAMS_USING_BATCHED_MODELS
|
|
||||||
#else
|
|
||||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Point;
|
|
||||||
buffer.vertices.format = VBuffer::EFormat::Position;
|
|
||||||
buffer.shader = wxGetApp().is_glsl_version_greater_or_equal_to(1, 20) ? "options_120" : "options_110";
|
|
||||||
break;
|
|
||||||
#endif // ENABLE_SEAMS_USING_MODELS
|
|
||||||
}
|
}
|
||||||
case EMoveType::Wipe:
|
case EMoveType::Wipe:
|
||||||
case EMoveType::Extrude: {
|
case EMoveType::Extrude: {
|
||||||
#if ENABLE_SEAMS_USING_MODELS
|
|
||||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Triangle;
|
|
||||||
buffer.vertices.format = VBuffer::EFormat::PositionNormal3;
|
|
||||||
#endif // ENABLE_SEAMS_USING_MODELS
|
|
||||||
buffer.shader = "gouraud_light";
|
buffer.shader = "gouraud_light";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EMoveType::Travel: {
|
case EMoveType::Travel: {
|
||||||
#if ENABLE_SEAMS_USING_MODELS
|
|
||||||
buffer.render_primitive_type = TBuffer::ERenderPrimitiveType::Line;
|
|
||||||
buffer.vertices.format = VBuffer::EFormat::PositionNormal1;
|
|
||||||
#endif // ENABLE_SEAMS_USING_MODELS
|
|
||||||
buffer.shader = "toolpaths_lines";
|
buffer.shader = "toolpaths_lines";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_SEAMS_USING_MODELS
|
|
||||||
set_toolpath_move_type_visible(EMoveType::Extrude, true);
|
|
||||||
#endif // ENABLE_SEAMS_USING_MODELS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializes tool marker
|
// initializes tool marker
|
||||||
@ -853,6 +898,7 @@ void GCodeViewer::render()
|
|||||||
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
|
m_detected_point_sizes = { static_cast<float>(point_sizes[0]), static_cast<float>(point_sizes[1]) };
|
||||||
m_gl_data_initialized = true;
|
m_gl_data_initialized = true;
|
||||||
};
|
};
|
||||||
|
#endif // !ENABLE_SEAMS_USING_MODELS
|
||||||
|
|
||||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
m_statistics.reset_opengl();
|
m_statistics.reset_opengl();
|
||||||
@ -861,10 +907,12 @@ void GCodeViewer::render()
|
|||||||
#endif // ENABLE_SEAMS_USING_MODELS
|
#endif // ENABLE_SEAMS_USING_MODELS
|
||||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||||
|
|
||||||
|
#if !ENABLE_SEAMS_USING_MODELS
|
||||||
// OpenGL data must be initialized after the glContext has been created.
|
// OpenGL data must be initialized after the glContext has been created.
|
||||||
// This is ensured when this method is called by GLCanvas3D::_render_gcode().
|
// This is ensured when this method is called by GLCanvas3D::_render_gcode().
|
||||||
if (!m_gl_data_initialized)
|
if (!m_gl_data_initialized)
|
||||||
init_gl_data();
|
init_gl_data();
|
||||||
|
#endif // !ENABLE_SEAMS_USING_MODELS
|
||||||
|
|
||||||
if (m_roles.empty())
|
if (m_roles.empty())
|
||||||
return;
|
return;
|
||||||
|
@ -821,6 +821,10 @@ public:
|
|||||||
GCodeViewer();
|
GCodeViewer();
|
||||||
~GCodeViewer() { reset(); }
|
~GCodeViewer() { reset(); }
|
||||||
|
|
||||||
|
#if ENABLE_SEAMS_USING_MODELS
|
||||||
|
void init();
|
||||||
|
#endif // ENABLE_SEAMS_USING_MODELS
|
||||||
|
|
||||||
// extract rendering data from the given parameters
|
// extract rendering data from the given parameters
|
||||||
void load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized);
|
void load(const GCodeProcessor::Result& gcode_result, const Print& print, bool initialized);
|
||||||
// recalculate ranges in dependence of what is visible and sets tool/print colors
|
// recalculate ranges in dependence of what is visible and sets tool/print colors
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "slic3r/GUI/3DBed.hpp"
|
#include "slic3r/GUI/3DBed.hpp"
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
#include "slic3r/GUI/MainFrame.hpp"
|
#include "slic3r/GUI/MainFrame.hpp"
|
||||||
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
|
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "GUI_ObjectList.hpp"
|
#include "GUI_ObjectList.hpp"
|
||||||
@ -1399,6 +1400,11 @@ void GLCanvas3D::render()
|
|||||||
if (!is_initialized() && !init())
|
if (!is_initialized() && !init())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if ENABLE_SEAMS_USING_MODELS
|
||||||
|
if (!m_main_toolbar.is_enabled())
|
||||||
|
m_gcode_viewer.init();
|
||||||
|
#endif // ENABLE_SEAMS_USING_MODELS
|
||||||
|
|
||||||
if (wxGetApp().plater()->get_bed().get_shape().empty()) {
|
if (wxGetApp().plater()->get_bed().get_shape().empty()) {
|
||||||
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
|
// this happens at startup when no data is still saved under <>\AppData\Roaming\Slic3rPE
|
||||||
post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE));
|
post_event(SimpleEvent(EVT_GLCANVAS_UPDATE_BED_SHAPE));
|
||||||
@ -6441,7 +6447,7 @@ void GLCanvas3D::_update_selection_from_hover()
|
|||||||
|
|
||||||
// the selection is going to be modified (Add)
|
// the selection is going to be modified (Add)
|
||||||
if (!contains_all) {
|
if (!contains_all) {
|
||||||
wxGetApp().plater()->take_snapshot(_(L("Selection-Add from rectangle")));
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add from rectangle")), UndoRedo::SnapshotType::Selection);
|
||||||
selection_changed = true;
|
selection_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6456,7 +6462,7 @@ void GLCanvas3D::_update_selection_from_hover()
|
|||||||
|
|
||||||
// the selection is going to be modified (Remove)
|
// the selection is going to be modified (Remove)
|
||||||
if (contains_any) {
|
if (contains_any) {
|
||||||
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove from rectangle")));
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove from rectangle")), UndoRedo::SnapshotType::Selection);
|
||||||
selection_changed = true;
|
selection_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -617,6 +617,9 @@ public:
|
|||||||
void reset_volumes();
|
void reset_volumes();
|
||||||
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
|
ModelInstanceEPrintVolumeState check_volumes_outside_state() const;
|
||||||
|
|
||||||
|
#if ENABLE_SEAMS_USING_MODELS
|
||||||
|
void init_gcode_viewer() { m_gcode_viewer.init(); }
|
||||||
|
#endif // ENABLE_SEAMS_USING_MODELS
|
||||||
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
|
void reset_gcode_toolpaths() { m_gcode_viewer.reset(); }
|
||||||
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
|
const GCodeViewer::SequentialView& get_gcode_sequential_view() const { return m_gcode_viewer.get_sequential_view(); }
|
||||||
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
|
void update_gcode_sequential_view_current(unsigned int first, unsigned int last) { m_gcode_viewer.update_sequential_view_current(first, last); }
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "BitmapComboBox.hpp"
|
#include "BitmapComboBox.hpp"
|
||||||
#include "GalleryDialog.hpp"
|
#include "GalleryDialog.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
|
|
||||||
#include "OptionsGroup.hpp"
|
#include "OptionsGroup.hpp"
|
||||||
#include "Tab.hpp"
|
#include "Tab.hpp"
|
||||||
@ -3469,7 +3470,7 @@ void ObjectList::update_selections_on_canvas()
|
|||||||
volume_idxs = selection.get_missing_volume_idxs_from(volume_idxs);
|
volume_idxs = selection.get_missing_volume_idxs_from(volume_idxs);
|
||||||
if (volume_idxs.size() > 0)
|
if (volume_idxs.size() > 0)
|
||||||
{
|
{
|
||||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Selection-Remove from list")));
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Selection-Remove from list")), UndoRedo::SnapshotType::Selection);
|
||||||
selection.remove_volumes(mode, volume_idxs);
|
selection.remove_volumes(mode, volume_idxs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3481,7 +3482,7 @@ void ObjectList::update_selections_on_canvas()
|
|||||||
// OR there is no single selection
|
// OR there is no single selection
|
||||||
if (selection.get_mode() == mode || !single_selection)
|
if (selection.get_mode() == mode || !single_selection)
|
||||||
volume_idxs = selection.get_unselected_volume_idxs_from(volume_idxs);
|
volume_idxs = selection.get_unselected_volume_idxs_from(volume_idxs);
|
||||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Selection-Add from list")));
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Selection-Add from list")), UndoRedo::SnapshotType::Selection);
|
||||||
selection.add_volumes(mode, volume_idxs, single_selection);
|
selection.add_volumes(mode, volume_idxs, single_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "slic3r/GUI/GUI_App.hpp"
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
#include "slic3r/GUI/Camera.hpp"
|
#include "slic3r/GUI/Camera.hpp"
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
#include "libslic3r/TriangleMesh.hpp"
|
#include "libslic3r/TriangleMesh.hpp"
|
||||||
@ -42,14 +43,14 @@ void GLGizmoPainterBase::activate_internal_undo_redo_stack(bool activate)
|
|||||||
|
|
||||||
if (activate && !m_internal_stack_active) {
|
if (activate && !m_internal_stack_active) {
|
||||||
if (std::string str = this->get_gizmo_entering_text(); last_snapshot_name != str)
|
if (std::string str = this->get_gizmo_entering_text(); last_snapshot_name != str)
|
||||||
Plater::TakeSnapshot(plater, str);
|
Plater::TakeSnapshot(plater, str, UndoRedo::SnapshotType::EnteringGizmo);
|
||||||
plater->enter_gizmos_stack();
|
plater->enter_gizmos_stack();
|
||||||
m_internal_stack_active = true;
|
m_internal_stack_active = true;
|
||||||
}
|
}
|
||||||
if (!activate && m_internal_stack_active) {
|
if (!activate && m_internal_stack_active) {
|
||||||
plater->leave_gizmos_stack();
|
plater->leave_gizmos_stack();
|
||||||
if (std::string str = this->get_gizmo_leaving_text(); last_snapshot_name != str)
|
if (std::string str = this->get_gizmo_leaving_text(); last_snapshot_name != str)
|
||||||
Plater::TakeSnapshot(plater, str);
|
Plater::TakeSnapshot(plater, str, UndoRedo::SnapshotType::LeavingGizmoWithAction);
|
||||||
m_internal_stack_active = false;
|
m_internal_stack_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "slic3r/GUI/Camera.hpp"
|
#include "slic3r/GUI/Camera.hpp"
|
||||||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||||
#include "slic3r/GUI/MainFrame.hpp"
|
#include "slic3r/GUI/MainFrame.hpp"
|
||||||
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
|
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include "slic3r/GUI/GUI_App.hpp"
|
#include "slic3r/GUI/GUI_App.hpp"
|
||||||
#include "slic3r/GUI/Plater.hpp"
|
#include "slic3r/GUI/Plater.hpp"
|
||||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||||
|
#include "slic3r/GUI/NotificationManager.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
@ -144,16 +145,16 @@ void SLAImportJob::process()
|
|||||||
try {
|
try {
|
||||||
switch (p->sel) {
|
switch (p->sel) {
|
||||||
case Sel::modelAndProfile:
|
case Sel::modelAndProfile:
|
||||||
p->config_substitutions = import_sla_archive(path, p->win, p->mesh, p->profile, progr);
|
|
||||||
break;
|
|
||||||
case Sel::modelOnly:
|
case Sel::modelOnly:
|
||||||
p->config_substitutions = import_sla_archive(path, p->win, p->mesh, progr);
|
p->config_substitutions = import_sla_archive(path, p->win, p->mesh, p->profile, progr);
|
||||||
break;
|
break;
|
||||||
case Sel::profileOnly:
|
case Sel::profileOnly:
|
||||||
p->config_substitutions = import_sla_archive(path, p->profile);
|
p->config_substitutions = import_sla_archive(path, p->profile);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} catch (MissingProfileError &) {
|
||||||
|
p->err = _L("The archive doesn't contain any profile data. Try to import after switching "
|
||||||
|
"to an SLA profile that can be used as fallback.").ToStdString();
|
||||||
} catch (std::exception &ex) {
|
} catch (std::exception &ex) {
|
||||||
p->err = ex.what();
|
p->err = ex.what();
|
||||||
}
|
}
|
||||||
@ -166,7 +167,7 @@ void SLAImportJob::reset()
|
|||||||
{
|
{
|
||||||
p->sel = Sel::modelAndProfile;
|
p->sel = Sel::modelAndProfile;
|
||||||
p->mesh = {};
|
p->mesh = {};
|
||||||
p->profile = {};
|
p->profile = m_plater->sla_print().full_print_config();
|
||||||
p->win = {2, 2};
|
p->win = {2, 2};
|
||||||
p->path.Clear();
|
p->path.Clear();
|
||||||
}
|
}
|
||||||
@ -202,7 +203,18 @@ void SLAImportJob::finalize()
|
|||||||
|
|
||||||
std::string name = wxFileName(p->path).GetName().ToUTF8().data();
|
std::string name = wxFileName(p->path).GetName().ToUTF8().data();
|
||||||
|
|
||||||
if (!p->profile.empty()) {
|
if (p->profile.empty()) {
|
||||||
|
m_plater->get_notification_manager()->push_notification(
|
||||||
|
NotificationType::CustomNotification,
|
||||||
|
NotificationManager::NotificationLevel::WarningNotificationLevel,
|
||||||
|
_L("Loaded archive did not contain any profile data. "
|
||||||
|
"The current SLA profile was used as fallback.").ToStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->sel != Sel::modelOnly) {
|
||||||
|
if (p->profile.empty())
|
||||||
|
p->profile = m_plater->sla_print().full_print_config();
|
||||||
|
|
||||||
const ModelObjectPtrs& objects = p->plater->model().objects;
|
const ModelObjectPtrs& objects = p->plater->model().objects;
|
||||||
for (auto object : objects)
|
for (auto object : objects)
|
||||||
if (object->volumes.size() > 1)
|
if (object->volumes.size() > 1)
|
||||||
|
@ -1172,7 +1172,7 @@ void NotificationManager::SlicingProgressNotification::set_status_text(const std
|
|||||||
{
|
{
|
||||||
NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slicing finished."), m_is_fff ? _u8L("Export G-Code.") : _u8L("Export.") };
|
NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slicing finished."), m_is_fff ? _u8L("Export G-Code.") : _u8L("Export.") };
|
||||||
update(data);
|
update(data);
|
||||||
m_state = EState::NotFading;
|
m_state = EState::Shown;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -1191,7 +1191,7 @@ void NotificationManager::SlicingProgressNotification::set_print_info(const std:
|
|||||||
void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(bool collapsed)
|
void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(bool collapsed)
|
||||||
{
|
{
|
||||||
m_sidebar_collapsed = collapsed;
|
m_sidebar_collapsed = collapsed;
|
||||||
if (m_sp_state == SlicingProgressState::SP_COMPLETED)
|
if (m_sp_state == SlicingProgressState::SP_COMPLETED && collapsed)
|
||||||
m_state = EState::NotFading;
|
m_state = EState::NotFading;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1208,7 +1208,7 @@ int NotificationManager::SlicingProgressNotification::get_duration()
|
|||||||
if (m_sp_state == SlicingProgressState::SP_CANCELLED)
|
if (m_sp_state == SlicingProgressState::SP_CANCELLED)
|
||||||
return 2;
|
return 2;
|
||||||
else if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)
|
else if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)
|
||||||
return 0;
|
return 2;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1530,25 +1530,25 @@ struct Plater::priv
|
|||||||
|
|
||||||
void arrange()
|
void arrange()
|
||||||
{
|
{
|
||||||
m->take_snapshot(_(L("Arrange")));
|
m->take_snapshot(_L("Arrange"));
|
||||||
start(m_arrange_id);
|
start(m_arrange_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_bed()
|
void fill_bed()
|
||||||
{
|
{
|
||||||
m->take_snapshot(_(L("Fill bed")));
|
m->take_snapshot(_L("Fill bed"));
|
||||||
start(m_fill_bed_id);
|
start(m_fill_bed_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void optimize_rotation()
|
void optimize_rotation()
|
||||||
{
|
{
|
||||||
m->take_snapshot(_(L("Optimize Rotation")));
|
m->take_snapshot(_L("Optimize Rotation"));
|
||||||
start(m_rotoptimize_id);
|
start(m_rotoptimize_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void import_sla_arch()
|
void import_sla_arch()
|
||||||
{
|
{
|
||||||
m->take_snapshot(_(L("Import SLA archive")));
|
m->take_snapshot(_L("Import SLA archive"));
|
||||||
start(m_sla_import_id);
|
start(m_sla_import_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1679,8 +1679,9 @@ struct Plater::priv
|
|||||||
void enter_gizmos_stack();
|
void enter_gizmos_stack();
|
||||||
void leave_gizmos_stack();
|
void leave_gizmos_stack();
|
||||||
|
|
||||||
void take_snapshot(const std::string& snapshot_name);
|
void take_snapshot(const std::string& snapshot_name, UndoRedo::SnapshotType snapshot_type = UndoRedo::SnapshotType::Action);
|
||||||
void take_snapshot(const wxString& snapshot_name) { this->take_snapshot(std::string(snapshot_name.ToUTF8().data())); }
|
void take_snapshot(const wxString& snapshot_name, UndoRedo::SnapshotType snapshot_type = UndoRedo::SnapshotType::Action)
|
||||||
|
{ this->take_snapshot(std::string(snapshot_name.ToUTF8().data()), snapshot_type); }
|
||||||
int get_active_snapshot_index();
|
int get_active_snapshot_index();
|
||||||
|
|
||||||
void undo();
|
void undo();
|
||||||
@ -2064,7 +2065,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the Undo / Redo stack with a first snapshot.
|
// Initialize the Undo / Redo stack with a first snapshot.
|
||||||
this->take_snapshot(_L("New Project"));
|
this->take_snapshot(_L("New Project"), UndoRedo::SnapshotType::ProjectSeparator);
|
||||||
|
|
||||||
this->q->Bind(EVT_LOAD_MODEL_OTHER_INSTANCE, [this](LoadFromOtherInstanceEvent& evt) {
|
this->q->Bind(EVT_LOAD_MODEL_OTHER_INSTANCE, [this](LoadFromOtherInstanceEvent& evt) {
|
||||||
BOOST_LOG_TRIVIAL(trace) << "Received load from other instance event.";
|
BOOST_LOG_TRIVIAL(trace) << "Received load from other instance event.";
|
||||||
@ -2440,7 +2441,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||||||
for (ModelObject* model_object : model.objects) {
|
for (ModelObject* model_object : model.objects) {
|
||||||
if (!type_3mf && !type_zip_amf)
|
if (!type_3mf && !type_zip_amf)
|
||||||
model_object->center_around_origin(false);
|
model_object->center_around_origin(false);
|
||||||
model_object->ensure_on_bed(is_project_file);
|
model_object->ensure_on_bed(is_project_file || type_3mf || type_zip_amf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check multi-part object adding for the SLA-printing
|
// check multi-part object adding for the SLA-printing
|
||||||
@ -2457,7 +2458,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||||||
if (one_by_one) {
|
if (one_by_one) {
|
||||||
if (type_3mf && !is_project_file)
|
if (type_3mf && !is_project_file)
|
||||||
model.center_instances_around_point(bed_shape_bb().center());
|
model.center_instances_around_point(bed_shape_bb().center());
|
||||||
auto loaded_idxs = load_model_objects(model.objects, is_project_file);
|
auto loaded_idxs = load_model_objects(model.objects, is_project_file || type_3mf || type_zip_amf);
|
||||||
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
|
obj_idxs.insert(obj_idxs.end(), loaded_idxs.begin(), loaded_idxs.end());
|
||||||
} else {
|
} else {
|
||||||
// This must be an .stl or .obj file, which may contain a maximum of one volume.
|
// This must be an .stl or .obj file, which may contain a maximum of one volume.
|
||||||
@ -2820,7 +2821,7 @@ void Plater::priv::delete_all_objects_from_model()
|
|||||||
|
|
||||||
void Plater::priv::reset()
|
void Plater::priv::reset()
|
||||||
{
|
{
|
||||||
Plater::TakeSnapshot snapshot(q, _L("Reset Project"));
|
Plater::TakeSnapshot snapshot(q, _L("Reset Project"), UndoRedo::SnapshotType::ProjectSeparator);
|
||||||
|
|
||||||
clear_warnings();
|
clear_warnings();
|
||||||
|
|
||||||
@ -3802,9 +3803,7 @@ void Plater::priv::set_current_panel(wxPanel* panel)
|
|||||||
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
|
bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside;
|
||||||
if (!model.objects.empty() && !export_in_progress && model_fits) {
|
if (!model.objects.empty() && !export_in_progress && model_fits) {
|
||||||
#if ENABLE_SEAMS_USING_MODELS
|
#if ENABLE_SEAMS_USING_MODELS
|
||||||
// the following call is needed to ensure that GCodeViewer buffers are initialized
|
preview->get_canvas3d()->init_gcode_viewer();
|
||||||
// before calling reslice() when background processing is active
|
|
||||||
preview->SetFocusFromKbd();
|
|
||||||
#endif // ENABLE_SEAMS_USING_MODELS
|
#endif // ENABLE_SEAMS_USING_MODELS
|
||||||
q->reslice();
|
q->reslice();
|
||||||
}
|
}
|
||||||
@ -4664,12 +4663,13 @@ int Plater::priv::get_active_snapshot_index()
|
|||||||
return it - ss_stack.begin();
|
return it - ss_stack.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::take_snapshot(const std::string& snapshot_name)
|
void Plater::priv::take_snapshot(const std::string& snapshot_name, const UndoRedo::SnapshotType snapshot_type)
|
||||||
{
|
{
|
||||||
if (m_prevent_snapshots > 0)
|
if (m_prevent_snapshots > 0)
|
||||||
return;
|
return;
|
||||||
assert(m_prevent_snapshots >= 0);
|
assert(m_prevent_snapshots >= 0);
|
||||||
UndoRedo::SnapshotData snapshot_data;
|
UndoRedo::SnapshotData snapshot_data;
|
||||||
|
snapshot_data.snapshot_type = snapshot_type;
|
||||||
snapshot_data.printer_technology = this->printer_technology;
|
snapshot_data.printer_technology = this->printer_technology;
|
||||||
if (this->view3D->is_layers_editing_enabled())
|
if (this->view3D->is_layers_editing_enabled())
|
||||||
snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
|
snapshot_data.flags |= UndoRedo::SnapshotData::VARIABLE_LAYER_EDITING_ACTIVE;
|
||||||
@ -4955,7 +4955,7 @@ void Plater::new_project()
|
|||||||
}
|
}
|
||||||
|
|
||||||
p->select_view_3D("3D");
|
p->select_view_3D("3D");
|
||||||
take_snapshot(_L("New Project"));
|
take_snapshot(_L("New Project"), UndoRedo::SnapshotType::ProjectSeparator);
|
||||||
Plater::SuppressSnapshots suppress(this);
|
Plater::SuppressSnapshots suppress(this);
|
||||||
reset();
|
reset();
|
||||||
reset_project_dirty_initial_presets();
|
reset_project_dirty_initial_presets();
|
||||||
@ -4980,7 +4980,7 @@ void Plater::load_project(const wxString& filename)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Take the Undo / Redo snapshot.
|
// Take the Undo / Redo snapshot.
|
||||||
Plater::TakeSnapshot snapshot(this, _L("Load Project") + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str()));
|
Plater::TakeSnapshot snapshot(this, _L("Load Project") + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str()), UndoRedo::SnapshotType::ProjectSeparator);
|
||||||
|
|
||||||
p->reset();
|
p->reset();
|
||||||
|
|
||||||
@ -5996,6 +5996,8 @@ void Plater::eject_drive()
|
|||||||
|
|
||||||
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
|
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||||
void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
|
void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||||
|
void Plater::take_snapshot(const std::string &snapshot_name, UndoRedo::SnapshotType snapshot_type) { p->take_snapshot(snapshot_name, snapshot_type); }
|
||||||
|
void Plater::take_snapshot(const wxString &snapshot_name, UndoRedo::SnapshotType snapshot_type) { p->take_snapshot(snapshot_name, snapshot_type); }
|
||||||
void Plater::suppress_snapshots() { p->suppress_snapshots(); }
|
void Plater::suppress_snapshots() { p->suppress_snapshots(); }
|
||||||
void Plater::allow_snapshots() { p->allow_snapshots(); }
|
void Plater::allow_snapshots() { p->allow_snapshots(); }
|
||||||
void Plater::undo() { p->undo(); }
|
void Plater::undo() { p->undo(); }
|
||||||
|
@ -37,6 +37,7 @@ using ModelInstancePtrs = std::vector<ModelInstance*>;
|
|||||||
|
|
||||||
namespace UndoRedo {
|
namespace UndoRedo {
|
||||||
class Stack;
|
class Stack;
|
||||||
|
enum class SnapshotType : unsigned char;
|
||||||
struct Snapshot;
|
struct Snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,6 +241,9 @@ public:
|
|||||||
|
|
||||||
void take_snapshot(const std::string &snapshot_name);
|
void take_snapshot(const std::string &snapshot_name);
|
||||||
void take_snapshot(const wxString &snapshot_name);
|
void take_snapshot(const wxString &snapshot_name);
|
||||||
|
void take_snapshot(const std::string &snapshot_name, UndoRedo::SnapshotType snapshot_type);
|
||||||
|
void take_snapshot(const wxString &snapshot_name, UndoRedo::SnapshotType snapshot_type);
|
||||||
|
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
void undo_to(int selection);
|
void undo_to(int selection);
|
||||||
@ -393,6 +397,12 @@ public:
|
|||||||
m_plater->take_snapshot(snapshot_name);
|
m_plater->take_snapshot(snapshot_name);
|
||||||
m_plater->suppress_snapshots();
|
m_plater->suppress_snapshots();
|
||||||
}
|
}
|
||||||
|
TakeSnapshot(Plater *plater, const wxString &snapshot_name, UndoRedo::SnapshotType snapshot_type) : m_plater(plater)
|
||||||
|
{
|
||||||
|
m_plater->take_snapshot(snapshot_name, snapshot_type);
|
||||||
|
m_plater->suppress_snapshots();
|
||||||
|
}
|
||||||
|
|
||||||
~TakeSnapshot()
|
~TakeSnapshot()
|
||||||
{
|
{
|
||||||
m_plater->allow_snapshots();
|
m_plater->allow_snapshots();
|
||||||
|
@ -195,7 +195,9 @@ void ProjectDirtyStateManager::update_from_undo_redo_stack(UpdateType type)
|
|||||||
void ProjectDirtyStateManager::update_from_presets()
|
void ProjectDirtyStateManager::update_from_presets()
|
||||||
{
|
{
|
||||||
m_state.presets = false;
|
m_state.presets = false;
|
||||||
for (const auto& [type, name] : wxGetApp().get_selected_presets()) {
|
// check switching of the presets only for exist/loaded project, but not for new
|
||||||
|
if (!wxGetApp().plater()->get_project_filename().IsEmpty()) {
|
||||||
|
for (const auto& [type, name] : wxGetApp().get_selected_presets())
|
||||||
m_state.presets |= !m_initial_presets[type].empty() && m_initial_presets[type] != name;
|
m_state.presets |= !m_initial_presets[type].empty() && m_initial_presets[type] != name;
|
||||||
}
|
}
|
||||||
m_state.presets |= wxGetApp().has_unsaved_preset_changes();
|
m_state.presets |= wxGetApp().has_unsaved_preset_changes();
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Gizmos/GLGizmoBase.hpp"
|
#include "Gizmos/GLGizmoBase.hpp"
|
||||||
#include "Camera.hpp"
|
#include "Camera.hpp"
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
|
#include "slic3r/Utils/UndoRedo.hpp"
|
||||||
|
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
@ -162,7 +163,7 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
|
|||||||
needs_reset |= is_any_modifier() && !volume->is_modifier;
|
needs_reset |= is_any_modifier() && !volume->is_modifier;
|
||||||
|
|
||||||
if (!already_contained || needs_reset) {
|
if (!already_contained || needs_reset) {
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Add"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Add"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
if (needs_reset)
|
if (needs_reset)
|
||||||
clear();
|
clear();
|
||||||
@ -203,7 +204,7 @@ void Selection::remove(unsigned int volume_idx)
|
|||||||
if (!contains_volume(volume_idx))
|
if (!contains_volume(volume_idx))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Remove"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Remove"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
GLVolume* volume = (*m_volumes)[volume_idx];
|
GLVolume* volume = (*m_volumes)[volume_idx];
|
||||||
|
|
||||||
@ -235,7 +236,7 @@ void Selection::add_object(unsigned int object_idx, bool as_single_selection)
|
|||||||
(as_single_selection && matches(volume_idxs)))
|
(as_single_selection && matches(volume_idxs)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Add Object"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Add Object"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
// resets the current list if needed
|
// resets the current list if needed
|
||||||
if (as_single_selection)
|
if (as_single_selection)
|
||||||
@ -254,7 +255,7 @@ void Selection::remove_object(unsigned int object_idx)
|
|||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Remove Object"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Remove Object"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
do_remove_object(object_idx);
|
do_remove_object(object_idx);
|
||||||
|
|
||||||
@ -272,7 +273,7 @@ void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx,
|
|||||||
(as_single_selection && matches(volume_idxs)))
|
(as_single_selection && matches(volume_idxs)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Add Instance"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Add Instance"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
// resets the current list if needed
|
// resets the current list if needed
|
||||||
if (as_single_selection)
|
if (as_single_selection)
|
||||||
@ -291,7 +292,7 @@ void Selection::remove_instance(unsigned int object_idx, unsigned int instance_i
|
|||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Remove Instance"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Remove Instance"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
do_remove_instance(object_idx, instance_idx);
|
do_remove_instance(object_idx, instance_idx);
|
||||||
|
|
||||||
@ -388,7 +389,7 @@ void Selection::add_all()
|
|||||||
if ((unsigned int)m_list.size() == count)
|
if ((unsigned int)m_list.size() == count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxGetApp().plater()->take_snapshot(_(L("Selection-Add All")));
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add All")), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
m_mode = Instance;
|
m_mode = Instance;
|
||||||
clear();
|
clear();
|
||||||
@ -413,7 +414,7 @@ void Selection::remove_all()
|
|||||||
// Not taking the snapshot with non-empty Redo stack will likely be more confusing than losing the Redo stack.
|
// Not taking the snapshot with non-empty Redo stack will likely be more confusing than losing the Redo stack.
|
||||||
// Let's wait for user feedback.
|
// Let's wait for user feedback.
|
||||||
// if (!wxGetApp().plater()->can_redo())
|
// if (!wxGetApp().plater()->can_redo())
|
||||||
wxGetApp().plater()->take_snapshot(_L("Selection-Remove All"));
|
wxGetApp().plater()->take_snapshot(_L("Selection-Remove All"), UndoRedo::SnapshotType::Selection);
|
||||||
|
|
||||||
m_mode = Instance;
|
m_mode = Instance;
|
||||||
clear();
|
clear();
|
||||||
|
@ -1188,11 +1188,21 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto set_focus = [](wxWindow* win) {
|
||||||
|
win->SetFocus();
|
||||||
|
#ifdef WIN32
|
||||||
|
if (wxTextCtrl* text = dynamic_cast<wxTextCtrl*>(win))
|
||||||
|
text->SetSelection(-1, -1);
|
||||||
|
else if (wxSpinCtrl* spin = dynamic_cast<wxSpinCtrl*>(win))
|
||||||
|
spin->SetSelection(-1, -1);
|
||||||
|
#endif // WIN32
|
||||||
|
};
|
||||||
|
|
||||||
Field* field = get_field(opt_key);
|
Field* field = get_field(opt_key);
|
||||||
|
|
||||||
// focused selected field
|
// focused selected field
|
||||||
if (field)
|
if (field)
|
||||||
field->getWindow()->SetFocus();
|
set_focus(field->getWindow());
|
||||||
else if (category == "Single extruder MM setup") {
|
else if (category == "Single extruder MM setup") {
|
||||||
// When we show and hide "Single extruder MM setup" page,
|
// When we show and hide "Single extruder MM setup" page,
|
||||||
// related options are still in the search list
|
// related options are still in the search list
|
||||||
@ -1200,7 +1210,7 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
|
|||||||
// as a "way" to show hidden page again
|
// as a "way" to show hidden page again
|
||||||
field = get_field("single_extruder_multi_material");
|
field = get_field("single_extruder_multi_material");
|
||||||
if (field)
|
if (field)
|
||||||
field->getWindow()->SetFocus();
|
set_focus(field->getWindow());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_highlighter.init(get_custom_ctrl_with_blinking_ptr(opt_key));
|
m_highlighter.init(get_custom_ctrl_with_blinking_ptr(opt_key));
|
||||||
|
@ -556,6 +556,12 @@ public:
|
|||||||
|
|
||||||
// Snapshot history (names with timestamps).
|
// Snapshot history (names with timestamps).
|
||||||
const std::vector<Snapshot>& snapshots() const { return m_snapshots; }
|
const std::vector<Snapshot>& snapshots() const { return m_snapshots; }
|
||||||
|
const Snapshot& snapshot(size_t time) const {
|
||||||
|
const auto it = std::lower_bound(m_snapshots.cbegin(), m_snapshots.cend(), UndoRedo::Snapshot(time));
|
||||||
|
assert(it != m_snapshots.end() && it->timestamp == time);
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
// Timestamp of the active snapshot.
|
// Timestamp of the active snapshot.
|
||||||
size_t active_snapshot_time() const { return m_active_snapshot_time; }
|
size_t active_snapshot_time() const { return m_active_snapshot_time; }
|
||||||
bool temp_snapshot_active() const { return m_snapshots.back().timestamp == m_active_snapshot_time && ! m_snapshots.back().is_topmost_captured(); }
|
bool temp_snapshot_active() const { return m_snapshots.back().timestamp == m_active_snapshot_time && ! m_snapshots.back().is_topmost_captured(); }
|
||||||
@ -1097,48 +1103,9 @@ bool Stack::redo(Slic3r::Model& model, Slic3r::GUI::GLGizmosManager& gizmos, siz
|
|||||||
const Selection& Stack::selection_deserialized() const { return pimpl->selection_deserialized(); }
|
const Selection& Stack::selection_deserialized() const { return pimpl->selection_deserialized(); }
|
||||||
|
|
||||||
const std::vector<Snapshot>& Stack::snapshots() const { return pimpl->snapshots(); }
|
const std::vector<Snapshot>& Stack::snapshots() const { return pimpl->snapshots(); }
|
||||||
|
const Snapshot& Stack::snapshot(size_t time) const { return pimpl->snapshot(time); }
|
||||||
size_t Stack::active_snapshot_time() const { return pimpl->active_snapshot_time(); }
|
size_t Stack::active_snapshot_time() const { return pimpl->active_snapshot_time(); }
|
||||||
bool Stack::temp_snapshot_active() const { return pimpl->temp_snapshot_active(); }
|
bool Stack::temp_snapshot_active() const { return pimpl->temp_snapshot_active(); }
|
||||||
|
|
||||||
} // namespace UndoRedo
|
} // namespace UndoRedo
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
|
||||||
//FIXME we should have unit tests for testing serialization of basic types as DynamicPrintConfig.
|
|
||||||
#if 0
|
|
||||||
#include "libslic3r/Config.hpp"
|
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
|
||||||
namespace Slic3r {
|
|
||||||
bool test_dynamic_print_config_serialization() {
|
|
||||||
FullPrintConfig full_print_config;
|
|
||||||
DynamicPrintConfig cfg;
|
|
||||||
cfg.apply(full_print_config, false);
|
|
||||||
|
|
||||||
std::string serialized;
|
|
||||||
try {
|
|
||||||
std::ostringstream ss;
|
|
||||||
cereal::BinaryOutputArchive oarchive(ss);
|
|
||||||
oarchive(cfg);
|
|
||||||
serialized = ss.str();
|
|
||||||
} catch (std::runtime_error e) {
|
|
||||||
e.what();
|
|
||||||
}
|
|
||||||
|
|
||||||
DynamicPrintConfig cfg2;
|
|
||||||
try {
|
|
||||||
std::stringstream ss(serialized);
|
|
||||||
cereal::BinaryInputArchive iarchive(ss);
|
|
||||||
iarchive(cfg2);
|
|
||||||
} catch (std::runtime_error e) {
|
|
||||||
e.what();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cfg == cfg2) {
|
|
||||||
printf("Yes!\n");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
printf("No!\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // namespace Slic3r
|
|
||||||
#endif
|
|
||||||
|
@ -24,6 +24,23 @@ namespace GUI {
|
|||||||
|
|
||||||
namespace UndoRedo {
|
namespace UndoRedo {
|
||||||
|
|
||||||
|
enum class SnapshotType : unsigned char {
|
||||||
|
// Some action modifying project state.
|
||||||
|
Action,
|
||||||
|
// Selection change at the Plater.
|
||||||
|
Selection,
|
||||||
|
// New project, Reset project, Load project ...
|
||||||
|
ProjectSeparator,
|
||||||
|
// Entering a Gizmo, which opens a secondary Undo / Redo stack.
|
||||||
|
EnteringGizmo,
|
||||||
|
// Leaving a Gizmo, which closes a secondary Undo / Redo stack.
|
||||||
|
// No action modifying a project state was done between EnteringGizmo / LeavingGizmo.
|
||||||
|
LeavingGizmoNoAction,
|
||||||
|
// Leaving a Gizmo, which closes a secondary Undo / Redo stack.
|
||||||
|
// Some action modifying a project state was done between EnteringGizmo / LeavingGizmo.
|
||||||
|
LeavingGizmoWithAction,
|
||||||
|
};
|
||||||
|
|
||||||
// Data structure to be stored with each snapshot.
|
// Data structure to be stored with each snapshot.
|
||||||
// Storing short data (bit masks, ints) with each snapshot instead of being serialized into the Undo / Redo stack
|
// Storing short data (bit masks, ints) with each snapshot instead of being serialized into the Undo / Redo stack
|
||||||
// is likely cheaper in term of both the runtime and memory allocation.
|
// is likely cheaper in term of both the runtime and memory allocation.
|
||||||
@ -34,6 +51,7 @@ struct SnapshotData
|
|||||||
// Constructor is defined in .cpp due to the forward declaration of enum PrinterTechnology.
|
// Constructor is defined in .cpp due to the forward declaration of enum PrinterTechnology.
|
||||||
SnapshotData();
|
SnapshotData();
|
||||||
|
|
||||||
|
SnapshotType snapshot_type;
|
||||||
PrinterTechnology printer_technology;
|
PrinterTechnology printer_technology;
|
||||||
// Bitmap of Flags (see the Flags enum).
|
// Bitmap of Flags (see the Flags enum).
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
@ -122,10 +140,13 @@ public:
|
|||||||
// There is one additional snapshot taken at the very end, which indicates the current unnamed state.
|
// There is one additional snapshot taken at the very end, which indicates the current unnamed state.
|
||||||
|
|
||||||
const std::vector<Snapshot>& snapshots() const;
|
const std::vector<Snapshot>& snapshots() const;
|
||||||
|
const Snapshot& snapshot(size_t time) const;
|
||||||
|
|
||||||
// Timestamp of the active snapshot. One of the snapshots of this->snapshots() shall have Snapshot::timestamp equal to this->active_snapshot_time().
|
// Timestamp of the active snapshot. One of the snapshots of this->snapshots() shall have Snapshot::timestamp equal to this->active_snapshot_time().
|
||||||
// The snapshot time indicates start of an operation, which is finished at the time of the following snapshot, therefore
|
// The active snapshot may be a special placeholder "@@@ Topmost @@@" indicating an uncaptured current state,
|
||||||
// the active snapshot is the successive snapshot. The same logic applies to the time_to_load parameter of undo() and redo() operations.
|
// or the active snapshot may be an active state to which the application state was undoed or redoed.
|
||||||
size_t active_snapshot_time() const;
|
size_t active_snapshot_time() const;
|
||||||
|
const Snapshot& active_snapshot() const { return this->snapshot(this->active_snapshot_time()); }
|
||||||
// Temporary snapshot is active if the topmost snapshot is active and it has not been captured yet.
|
// Temporary snapshot is active if the topmost snapshot is active and it has not been captured yet.
|
||||||
// In that case the Undo action will capture the last snapshot.
|
// In that case the Undo action will capture the last snapshot.
|
||||||
bool temp_snapshot_active() const;
|
bool temp_snapshot_active() const;
|
||||||
|
@ -3,6 +3,11 @@
|
|||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "libslic3r/LocalesUtils.hpp"
|
#include "libslic3r/LocalesUtils.hpp"
|
||||||
|
|
||||||
|
#include <cereal/types/polymorphic.hpp>
|
||||||
|
#include <cereal/types/string.hpp>
|
||||||
|
#include <cereal/types/vector.hpp>
|
||||||
|
#include <cereal/archives/binary.hpp>
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
||||||
SCENARIO("Generic config validation performs as expected.", "[Config]") {
|
SCENARIO("Generic config validation performs as expected.", "[Config]") {
|
||||||
@ -202,3 +207,33 @@ SCENARIO("Config ini load/save interface", "[Config]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCENARIO("DynamicPrintConfig serialization", "[Config]") {
|
||||||
|
WHEN("DynamicPrintConfig is serialized and deserialized") {
|
||||||
|
FullPrintConfig full_print_config;
|
||||||
|
DynamicPrintConfig cfg;
|
||||||
|
cfg.apply(full_print_config, false);
|
||||||
|
|
||||||
|
std::string serialized;
|
||||||
|
try {
|
||||||
|
std::ostringstream ss;
|
||||||
|
cereal::BinaryOutputArchive oarchive(ss);
|
||||||
|
oarchive(cfg);
|
||||||
|
serialized = ss.str();
|
||||||
|
} catch (std::runtime_error e) {
|
||||||
|
e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN("Config object contains ini file options.") {
|
||||||
|
DynamicPrintConfig cfg2;
|
||||||
|
try {
|
||||||
|
std::stringstream ss(serialized);
|
||||||
|
cereal::BinaryInputArchive iarchive(ss);
|
||||||
|
iarchive(cfg2);
|
||||||
|
} catch (std::runtime_error e) {
|
||||||
|
e.what();
|
||||||
|
}
|
||||||
|
REQUIRE(cfg == cfg2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
set(SLIC3R_APP_NAME "PrusaSlicer")
|
set(SLIC3R_APP_NAME "PrusaSlicer")
|
||||||
set(SLIC3R_APP_KEY "PrusaSlicer")
|
set(SLIC3R_APP_KEY "PrusaSlicer")
|
||||||
set(SLIC3R_VERSION "2.4.0-alpha1")
|
set(SLIC3R_VERSION "2.4.0-alpha2")
|
||||||
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
|
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
|
||||||
set(SLIC3R_RC_VERSION "2,4,0,0")
|
set(SLIC3R_RC_VERSION "2,4,0,0")
|
||||||
set(SLIC3R_RC_VERSION_DOTS "2.4.0.0")
|
set(SLIC3R_RC_VERSION_DOTS "2.4.0.0")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user