SLA archiver implemented for svg output, switchable in config.
new config is sla_archive_format as a string. WIP Get rid of SVG class, use manual svg creation Revert changes in SVG.hpp and SVG.cpp
This commit is contained in:
parent
eddcebf929
commit
7f153a55b3
@ -498,8 +498,6 @@ int CLI::run(int argc, char **argv)
|
||||
std::string outfile = m_config.opt_string("output");
|
||||
Print fff_print;
|
||||
SLAPrint sla_print;
|
||||
SL1Archive sla_archive(sla_print.printer_config());
|
||||
sla_print.set_printer(&sla_archive);
|
||||
sla_print.set_status_callback(
|
||||
[](const PrintBase::SlicingStatus& s)
|
||||
{
|
||||
@ -539,7 +537,7 @@ int CLI::run(int argc, char **argv)
|
||||
outfile = sla_print.output_filepath(outfile);
|
||||
// We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
|
||||
outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
|
||||
sla_archive.export_print(outfile_final, sla_print);
|
||||
sla_print.export_print(outfile_final);
|
||||
}
|
||||
if (outfile != outfile_final) {
|
||||
if (Slic3r::rename_file(outfile, outfile_final)) {
|
||||
|
@ -96,6 +96,8 @@ set(SLIC3R_SOURCES
|
||||
Format/STL.hpp
|
||||
Format/SL1.hpp
|
||||
Format/SL1.cpp
|
||||
Format/SL1_SVG.hpp
|
||||
Format/SL1_SVG.cpp
|
||||
GCode/ThumbnailData.cpp
|
||||
GCode/ThumbnailData.hpp
|
||||
GCode/Thumbnails.cpp
|
||||
|
@ -15,27 +15,16 @@ protected:
|
||||
std::unique_ptr<sla::RasterBase> create_raster() const override;
|
||||
sla::RasterEncoder get_encoder() const override;
|
||||
|
||||
SLAPrinterConfig & cfg() { return m_cfg; }
|
||||
const SLAPrinterConfig & cfg() const { return m_cfg; }
|
||||
|
||||
public:
|
||||
|
||||
SL1Archive() = default;
|
||||
explicit SL1Archive(const SLAPrinterConfig &cfg): m_cfg(cfg) {}
|
||||
explicit SL1Archive(SLAPrinterConfig &&cfg): m_cfg(std::move(cfg)) {}
|
||||
|
||||
void export_print(Zipper &zipper, const SLAPrint &print, const std::string &projectname = "");
|
||||
void export_print(const std::string &fname, const SLAPrint &print, const std::string &projectname = "")
|
||||
{
|
||||
Zipper zipper(fname);
|
||||
export_print(zipper, print, projectname);
|
||||
}
|
||||
|
||||
void apply(const SLAPrinterConfig &cfg) override
|
||||
{
|
||||
auto diff = m_cfg.diff(cfg);
|
||||
if (!diff.empty()) {
|
||||
m_cfg.apply_only(cfg, diff);
|
||||
m_layers = {};
|
||||
}
|
||||
}
|
||||
void export_print(Zipper &zipper, const SLAPrint &print, const std::string &projectname = "") override;
|
||||
};
|
||||
|
||||
ConfigSubstitutions import_sla_archive(const std::string &zipfname, DynamicPrintConfig &out);
|
||||
|
139
src/libslic3r/Format/SL1_SVG.cpp
Normal file
139
src/libslic3r/Format/SL1_SVG.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
#include "SL1_SVG.hpp"
|
||||
#include "SLA/RasterBase.hpp"
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
void transform(ExPolygon &ep, const sla::RasterBase::Trafo &tr, const BoundingBox &bb)
|
||||
{
|
||||
if (tr.flipXY) {
|
||||
for (auto &p : ep.contour.points) std::swap(p.x(), p.y());
|
||||
for (auto &h : ep.holes)
|
||||
for (auto &p : h.points) std::swap(p.x(), p.y());
|
||||
}
|
||||
|
||||
if (tr.mirror_x){
|
||||
for (auto &p : ep.contour.points) p.x() = bb.max.x() - p.x() + bb.min.x();
|
||||
for (auto &h : ep.holes)
|
||||
for (auto &p : h.points) p.x() = bb.max.x() - p.x() + bb.min.x();
|
||||
}
|
||||
|
||||
if (tr.mirror_y){
|
||||
for (auto &p : ep.contour.points) p.y() = bb.max.y() - p.y() + bb.min.y();
|
||||
for (auto &h : ep.holes)
|
||||
for (auto &p : h.points) p.y() = bb.max.y() - p.y() + bb.min.y();
|
||||
}
|
||||
}
|
||||
|
||||
void append_svg(std::string &buf, const Polygon &poly)
|
||||
{
|
||||
buf += "<path d=\"M";
|
||||
for (auto &p : poly) {
|
||||
buf += " ";
|
||||
buf += float_to_string_decimal_point(unscaled<float>(p.x()));
|
||||
buf += " ";
|
||||
buf += float_to_string_decimal_point(unscaled<float>(p.y()));
|
||||
}
|
||||
buf += " z\""; // mark path as closed
|
||||
buf += " />\n";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// A fake raster from SVG
|
||||
class SVGRaster : public sla::RasterBase {
|
||||
// Resolution here will be used for svg boundaries
|
||||
BoundingBox m_bb;
|
||||
Trafo m_trafo;
|
||||
|
||||
std::string m_svg;
|
||||
|
||||
public:
|
||||
SVGRaster(Resolution res = {}, Trafo tr = {})
|
||||
: m_bb{BoundingBox{{0, 0}, Vec2crd{res.width_px, res.height_px}}}
|
||||
, m_trafo{tr}
|
||||
{
|
||||
std::string w = float_to_string_decimal_point(unscaled<float>(res.width_px));
|
||||
std::string h = float_to_string_decimal_point(unscaled<float>(res.height_px));
|
||||
// Add svg header.
|
||||
m_svg =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
|
||||
"<svg height=\"" + h + "mm" + "\" width=\"" + w + "mm" + "\" viewBox=\"0 0 " + w + " " + h +
|
||||
"\" style=\"fill: white; stroke: none; fill-rule: nonzero\" "
|
||||
"xmlns=\"http://www.w3.org/2000/svg\" xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
|
||||
|
||||
// Add black background;
|
||||
m_svg += "<rect fill='black' stroke='none' x='0' y='0' width='" + w + "' height='" + h + "'/>\n";
|
||||
}
|
||||
|
||||
void draw(const ExPolygon& poly) override
|
||||
{
|
||||
auto cpoly = poly;
|
||||
|
||||
transform(cpoly, m_trafo, m_bb);
|
||||
append_svg(m_svg, cpoly.contour);
|
||||
for (auto &h : cpoly.holes)
|
||||
append_svg(m_svg, h);
|
||||
}
|
||||
|
||||
Resolution resolution() const override
|
||||
{
|
||||
return {size_t(m_bb.size().x()), size_t(m_bb.size().y())};
|
||||
}
|
||||
|
||||
// Pixel dimension is undefined in this case.
|
||||
PixelDim pixel_dimensions() const override { return {0, 0}; }
|
||||
|
||||
Trafo trafo() const override { return m_trafo; }
|
||||
|
||||
sla::EncodedRaster encode(sla::RasterEncoder /*encoder*/) const override
|
||||
{
|
||||
std::vector<uint8_t> data;
|
||||
constexpr const char finish[] = "</svg>\n";
|
||||
|
||||
data.reserve(m_svg.size() + std::size(finish));
|
||||
|
||||
std::copy(m_svg.begin(), m_svg.end(), std::back_inserter(data));
|
||||
std::copy(finish, finish + std::size(finish) - 1, std::back_inserter(data));
|
||||
|
||||
return sla::EncodedRaster{std::move(data), "svg"};
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<sla::RasterBase> SL1_SVGArchive::create_raster() const
|
||||
{
|
||||
auto w = scaled<size_t>(cfg().display_width.getFloat());
|
||||
auto h = scaled<size_t>(cfg().display_height.getFloat());
|
||||
|
||||
std::array<bool, 2> mirror;
|
||||
|
||||
mirror[X] = cfg().display_mirror_x.getBool();
|
||||
mirror[Y] = cfg().display_mirror_y.getBool();
|
||||
|
||||
auto ro = cfg().display_orientation.getInt();
|
||||
sla::RasterBase::Orientation orientation =
|
||||
ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait :
|
||||
sla::RasterBase::roLandscape;
|
||||
|
||||
if (orientation == sla::RasterBase::roPortrait) {
|
||||
std::swap(w, h);
|
||||
}
|
||||
|
||||
sla::RasterBase::Resolution res{w, h};
|
||||
sla::RasterBase::Trafo tr{orientation, mirror};
|
||||
|
||||
// Gamma does not really make sense in an svg, right?
|
||||
// double gamma = cfg().gamma_correction.getFloat();
|
||||
|
||||
return std::make_unique<SVGRaster>(SVGRaster::Resolution{w, h}, tr);
|
||||
}
|
||||
|
||||
sla::RasterEncoder SL1_SVGArchive::get_encoder() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
22
src/libslic3r/Format/SL1_SVG.hpp
Normal file
22
src/libslic3r/Format/SL1_SVG.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef SL1_SVG_HPP
|
||||
#define SL1_SVG_HPP
|
||||
|
||||
#include "SL1.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class SL1_SVGArchive: public SL1Archive {
|
||||
protected:
|
||||
|
||||
// Override the factory methods to produce svg instead of a real raster.
|
||||
std::unique_ptr<sla::RasterBase> create_raster() const override;
|
||||
sla::RasterEncoder get_encoder() const override;
|
||||
|
||||
public:
|
||||
|
||||
using SL1Archive::SL1Archive;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // SL1_SVG_HPP
|
@ -573,7 +573,7 @@ static std::vector<std::string> s_Preset_sla_printer_options {
|
||||
"elefant_foot_min_width",
|
||||
"gamma_correction",
|
||||
"min_exposure_time", "max_exposure_time",
|
||||
"min_initial_exposure_time", "max_initial_exposure_time",
|
||||
"min_initial_exposure_time", "max_initial_exposure_time", "sla_archive_format",
|
||||
//FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
|
||||
"print_host", "printhost_apikey", "printhost_cafile",
|
||||
"printer_notes",
|
||||
|
@ -3800,6 +3800,11 @@ void PrintConfigDef::init_sla_params()
|
||||
def->enum_labels.push_back(L("Fast"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<SLAMaterialSpeed>(slamsFast));
|
||||
|
||||
def = this->add("sla_archive_format", coString);
|
||||
def->label = L("Format of the output SLA archive");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString("SL1"));
|
||||
}
|
||||
|
||||
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
||||
|
@ -980,6 +980,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloat, max_exposure_time))
|
||||
((ConfigOptionFloat, min_initial_exposure_time))
|
||||
((ConfigOptionFloat, max_initial_exposure_time))
|
||||
((ConfigOptionString, sla_archive_format))
|
||||
)
|
||||
|
||||
PRINT_CONFIG_CLASS_DERIVED_DEFINE0(
|
||||
|
@ -1,6 +1,9 @@
|
||||
#include "SLAPrint.hpp"
|
||||
#include "SLAPrintSteps.hpp"
|
||||
|
||||
#include "Format/SL1.hpp"
|
||||
#include "Format/SL1_SVG.hpp"
|
||||
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "MTUtils.hpp"
|
||||
@ -241,7 +244,12 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
||||
// Handle changes to object config defaults
|
||||
m_default_object_config.apply_only(config, object_diff, true);
|
||||
|
||||
if (m_printer) m_printer->apply(m_printer_config);
|
||||
if (!m_printer || std::find(printer_diff.begin(), printer_diff.end(), "sla_archive_format") != printer_diff.end()) {
|
||||
if (m_printer_config.sla_archive_format.value == "SL1")
|
||||
m_printer = std::make_unique<SL1Archive>(m_printer_config);
|
||||
else if (m_printer_config.sla_archive_format.value == "SL2")
|
||||
m_printer = std::make_unique<SL1_SVGArchive>(m_printer_config);
|
||||
}
|
||||
|
||||
struct ModelObjectStatus {
|
||||
enum Status {
|
||||
@ -670,12 +678,6 @@ std::string SLAPrint::validate(std::string*) const
|
||||
return "";
|
||||
}
|
||||
|
||||
void SLAPrint::set_printer(SLAArchive *arch)
|
||||
{
|
||||
invalidate_step(slapsRasterize);
|
||||
m_printer = arch;
|
||||
}
|
||||
|
||||
bool SLAPrint::invalidate_step(SLAPrintStep step)
|
||||
{
|
||||
bool invalidated = Inherited::invalidate_step(step);
|
||||
@ -835,7 +837,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
|
||||
"display_pixels_y",
|
||||
"display_mirror_x",
|
||||
"display_mirror_y",
|
||||
"display_orientation"
|
||||
"display_orientation",
|
||||
"sla_archive_format"
|
||||
};
|
||||
|
||||
static std::unordered_set<std::string> steps_ignore = {
|
||||
|
@ -399,8 +399,6 @@ protected:
|
||||
public:
|
||||
virtual ~SLAArchive() = default;
|
||||
|
||||
virtual void apply(const SLAPrinterConfig &cfg) = 0;
|
||||
|
||||
// Fn have to be thread safe: void(sla::RasterBase& raster, size_t lyrid);
|
||||
template<class Fn, class CancelFn, class EP = ExecutionTBB>
|
||||
void draw_layers(
|
||||
@ -422,6 +420,14 @@ public:
|
||||
},
|
||||
execution::max_concurrency(ep));
|
||||
}
|
||||
|
||||
// Export the print into an archive using the provided zipper.
|
||||
// TODO: Use an archive writer interface instead of Zipper.
|
||||
// This is quite limiting as the Zipper is a complete class, not an interface.
|
||||
// The output can only be a zip archive.
|
||||
virtual void export_print(Zipper &zipper,
|
||||
const SLAPrint &print,
|
||||
const std::string &projectname = "") = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -528,7 +534,16 @@ public:
|
||||
// TODO: use this structure for the preview in the future.
|
||||
const std::vector<PrintLayer>& print_layers() const { return m_printer_input; }
|
||||
|
||||
void set_printer(SLAArchive *archiver);
|
||||
void export_print(Zipper &zipper, const std::string &projectname = "")
|
||||
{
|
||||
m_printer->export_print(zipper, *this, projectname);
|
||||
}
|
||||
|
||||
void export_print(const std::string &fname, const std::string &projectname = "")
|
||||
{
|
||||
Zipper zipper(fname);
|
||||
export_print(zipper, projectname);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@ -550,7 +565,7 @@ private:
|
||||
std::vector<PrintLayer> m_printer_input;
|
||||
|
||||
// The archive object which collects the raster images after slicing
|
||||
SLAArchive *m_printer = nullptr;
|
||||
std::unique_ptr<SLAArchive> m_printer;
|
||||
|
||||
// Estimated print time, material consumed.
|
||||
SLAPrintStatistics m_print_statistics;
|
||||
|
@ -190,7 +190,7 @@ void BackgroundSlicingProcess::process_sla()
|
||||
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
||||
|
||||
Zipper zipper(export_path);
|
||||
m_sla_archive.export_print(zipper, *m_sla_print); // true, false, true, true); // renders also supports and pad
|
||||
m_sla_print->export_print(zipper);
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
if (data.is_valid())
|
||||
write_thumbnail(zipper, data);
|
||||
@ -741,7 +741,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
||||
// true, false, true, true); // renders also supports and pad
|
||||
Zipper zipper{source_path.string()};
|
||||
m_sla_archive.export_print(zipper, *m_sla_print, m_upload_job.upload_data.upload_path.string());
|
||||
m_sla_print->export_print(zipper, m_upload_job.upload_data.upload_path.string());
|
||||
for (const ThumbnailData& data : thumbnails)
|
||||
if (data.is_valid())
|
||||
write_thumbnail(zipper, data);
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "libslic3r/PrintBase.hpp"
|
||||
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||
#include "libslic3r/Format/SL1.hpp"
|
||||
#include "slic3r/Utils/PrintHost.hpp"
|
||||
#include "libslic3r/GCode/GCodeProcessor.hpp"
|
||||
|
||||
@ -84,7 +83,7 @@ public:
|
||||
~BackgroundSlicingProcess();
|
||||
|
||||
void set_fff_print(Print *print) { m_fff_print = print; }
|
||||
void set_sla_print(SLAPrint *print) { m_sla_print = print; m_sla_print->set_printer(&m_sla_archive); }
|
||||
void set_sla_print(SLAPrint *print) { m_sla_print = print; }
|
||||
void set_thumbnail_cb(ThumbnailsGeneratorCallback cb) { m_thumbnail_cb = cb; }
|
||||
void set_gcode_result(GCodeProcessorResult* result) { m_gcode_result = result; }
|
||||
|
||||
@ -218,9 +217,9 @@ private:
|
||||
// Data structure, to which the G-code export writes its annotations.
|
||||
GCodeProcessorResult *m_gcode_result = nullptr;
|
||||
// Callback function, used to write thumbnails into gcode.
|
||||
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
|
||||
SL1Archive m_sla_archive;
|
||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess, differentiated from the other processes by a process ID.
|
||||
ThumbnailsGeneratorCallback m_thumbnail_cb = nullptr;
|
||||
// Temporary G-code, there is one defined for the BackgroundSlicingProcess,
|
||||
// differentiated from the other processes by a process ID.
|
||||
std::string m_temp_output_path;
|
||||
// Output path provided by the user. The output path may be set even if the slicing is running,
|
||||
// but once set, it cannot be re-set.
|
||||
|
@ -2518,6 +2518,10 @@ void TabPrinter::build_sla()
|
||||
optgroup->append_single_option_line("min_initial_exposure_time");
|
||||
optgroup->append_single_option_line("max_initial_exposure_time");
|
||||
|
||||
|
||||
optgroup = page->new_optgroup(L("Output"));
|
||||
optgroup->append_single_option_line("sla_archive_format");
|
||||
|
||||
build_print_host_upload_group(page.get());
|
||||
|
||||
const int notes_field_height = 25; // 250
|
||||
|
Loading…
Reference in New Issue
Block a user