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:
tamasmeszaros 2022-01-07 10:15:16 +01:00
parent eddcebf929
commit 7f153a55b3
13 changed files with 217 additions and 40 deletions

View File

@ -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)) {

View File

@ -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

View File

@ -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);

View 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

View 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

View File

@ -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",

View File

@ -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)

View File

@ -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(

View File

@ -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"
@ -240,8 +243,13 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
m_material_config.apply_only(config, material_diff, true);
// 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 = {

View File

@ -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;
};
/**
@ -527,8 +533,17 @@ public:
// The aggregated and leveled print records from various objects.
// 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;

View File

@ -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);

View File

@ -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.

View File

@ -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