Working svg import
Strange bug in export, see line 111
This commit is contained in:
parent
4ef860811f
commit
885e6964ba
5 changed files with 128 additions and 53 deletions
src/libslic3r/Format
|
@ -264,28 +264,7 @@ template<> struct _RasterTraits<Slic3r::png::ImageGreyscale> {
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
namespace {
|
template<class Fn> static void foreach_vertex(ExPolygon &poly, Fn &&fn)
|
||||||
|
|
||||||
ExPolygons rings_to_expolygons(const std::vector<marchsq::Ring> &rings,
|
|
||||||
double px_w, double px_h)
|
|
||||||
{
|
|
||||||
auto polys = reserve_vector<ExPolygon>(rings.size());
|
|
||||||
|
|
||||||
for (const marchsq::Ring &ring : rings) {
|
|
||||||
Polygon poly; Points &pts = poly.points;
|
|
||||||
pts.reserve(ring.size());
|
|
||||||
|
|
||||||
for (const marchsq::Coord &crd : ring)
|
|
||||||
pts.emplace_back(scaled(crd.c * px_w), scaled(crd.r * px_h));
|
|
||||||
|
|
||||||
polys.emplace_back(poly);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Is a union necessary?
|
|
||||||
return union_ex(polys);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Fn> void foreach_vertex(ExPolygon &poly, Fn &&fn)
|
|
||||||
{
|
{
|
||||||
for (auto &p : poly.contour.points) fn(p);
|
for (auto &p : poly.contour.points) fn(p);
|
||||||
for (auto &h : poly.holes)
|
for (auto &h : poly.holes)
|
||||||
|
@ -318,6 +297,27 @@ void invert_raster_trafo(ExPolygons & expolys,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
ExPolygons rings_to_expolygons(const std::vector<marchsq::Ring> &rings,
|
||||||
|
double px_w, double px_h)
|
||||||
|
{
|
||||||
|
auto polys = reserve_vector<ExPolygon>(rings.size());
|
||||||
|
|
||||||
|
for (const marchsq::Ring &ring : rings) {
|
||||||
|
Polygon poly; Points &pts = poly.points;
|
||||||
|
pts.reserve(ring.size());
|
||||||
|
|
||||||
|
for (const marchsq::Coord &crd : ring)
|
||||||
|
pts.emplace_back(scaled(crd.c * px_w), scaled(crd.r * px_h));
|
||||||
|
|
||||||
|
polys.emplace_back(poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Is a union necessary?
|
||||||
|
return union_ex(polys);
|
||||||
|
}
|
||||||
|
|
||||||
struct RasterParams {
|
struct RasterParams {
|
||||||
sla::RasterBase::Trafo trafo; // Raster transformations
|
sla::RasterBase::Trafo trafo; // Raster transformations
|
||||||
coord_t width, height; // scaled raster dimensions (not resolution)
|
coord_t width, height; // scaled raster dimensions (not resolution)
|
||||||
|
|
|
@ -60,6 +60,11 @@ public:
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void invert_raster_trafo(ExPolygons & expolys,
|
||||||
|
const sla::RasterBase::Trafo &trafo,
|
||||||
|
coord_t width,
|
||||||
|
coord_t height);
|
||||||
|
|
||||||
} // namespace Slic3r::sla
|
} // namespace Slic3r::sla
|
||||||
|
|
||||||
#endif // ARCHIVETRAITS_HPP
|
#endif // ARCHIVETRAITS_HPP
|
||||||
|
|
|
@ -77,10 +77,25 @@ void transform(ExPolygon &ep, const sla::RasterBase::Trafo &tr, const BoundingBo
|
||||||
|
|
||||||
void append_svg(std::string &buf, const Polygon &poly)
|
void append_svg(std::string &buf, const Polygon &poly)
|
||||||
{
|
{
|
||||||
|
// if (poly.points.empty())
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// char intbuf[coord_t_bufsize];
|
||||||
|
// buf += "<path d=\"M "sv;
|
||||||
|
|
||||||
|
// for (auto &p : poly) {
|
||||||
|
// buf += " "sv;
|
||||||
|
// buf += decimal_from(p.x(), intbuf);
|
||||||
|
// buf += " "sv;
|
||||||
|
// buf += decimal_from(p.y(), intbuf);
|
||||||
|
// }
|
||||||
|
// buf += " z\""sv; // mark path as closed
|
||||||
|
// buf += " />\n"sv;
|
||||||
|
|
||||||
if (poly.points.empty())
|
if (poly.points.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto c = poly.points.front();
|
Point c = poly.points.front();
|
||||||
|
|
||||||
char intbuf[coord_t_bufsize];
|
char intbuf[coord_t_bufsize];
|
||||||
|
|
||||||
|
@ -90,14 +105,15 @@ void append_svg(std::string &buf, const Polygon &poly)
|
||||||
buf += decimal_from(c.y(), intbuf);
|
buf += decimal_from(c.y(), intbuf);
|
||||||
buf += " m"sv;
|
buf += " m"sv;
|
||||||
|
|
||||||
for (auto &p : poly) {
|
for (const Point &p : poly) {
|
||||||
auto d = p - c;
|
Point d = p - c;
|
||||||
if (d.squaredNorm() == 0) continue;
|
|
||||||
buf += " "sv;
|
|
||||||
buf += decimal_from(p.x() - c.x(), intbuf);
|
|
||||||
buf += " "sv;
|
|
||||||
buf += decimal_from(p.y() - c.y(), intbuf);
|
|
||||||
c = p;
|
c = p;
|
||||||
|
// if (d.x() == 0 && d.y() == 0)
|
||||||
|
// continue;
|
||||||
|
buf += " "sv;
|
||||||
|
buf += decimal_from(d.x(), intbuf);
|
||||||
|
buf += " "sv;
|
||||||
|
buf += decimal_from(d.y(), intbuf);
|
||||||
}
|
}
|
||||||
buf += " z\""sv; // mark path as closed
|
buf += " z\""sv; // mark path as closed
|
||||||
buf += " />\n"sv;
|
buf += " />\n"sv;
|
||||||
|
@ -142,9 +158,6 @@ public:
|
||||||
"<svg height=\"" + hf + "mm" + "\" width=\"" + wf + "mm" + "\" viewBox=\"0 0 " + w + " " + h +
|
"<svg height=\"" + hf + "mm" + "\" width=\"" + wf + "mm" + "\" viewBox=\"0 0 " + w + " " + h +
|
||||||
"\" style=\"fill: white; stroke: none; fill-rule: nonzero\" "
|
"\" 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";
|
"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
|
void draw(const ExPolygon& poly) override
|
||||||
|
@ -193,8 +206,6 @@ std::unique_ptr<sla::RasterBase> SL1_SVGArchive::create_raster() const
|
||||||
auto w = cfg().display_width.getFloat();
|
auto w = cfg().display_width.getFloat();
|
||||||
auto h = cfg().display_height.getFloat();
|
auto h = cfg().display_height.getFloat();
|
||||||
|
|
||||||
// auto res_x = size_t(cfg().display_pixels_x.getInt());
|
|
||||||
// auto res_y = size_t(cfg().display_pixels_y.getInt());
|
|
||||||
float precision_nm = scaled<float>(cfg().sla_output_precision.getFloat());
|
float precision_nm = scaled<float>(cfg().sla_output_precision.getFloat());
|
||||||
size_t res_x = std::round(scaled(w) / precision_nm);
|
size_t res_x = std::round(scaled(w) / precision_nm);
|
||||||
size_t res_y = std::round(scaled(h) / precision_nm);
|
size_t res_y = std::round(scaled(h) / precision_nm);
|
||||||
|
@ -238,10 +249,50 @@ void SL1_SVGArchive::export_print(const std::string fname,
|
||||||
SL1Archive::export_print(zipper, print, thumbnails, projectname);
|
SL1Archive::export_print(zipper, print, thumbnails, projectname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RasterParams {
|
||||||
|
sla::RasterBase::Trafo trafo; // Raster transformations
|
||||||
|
coord_t width, height; // scaled raster dimensions (not resolution)
|
||||||
|
};
|
||||||
|
|
||||||
|
RasterParams get_raster_params(const DynamicPrintConfig &cfg)
|
||||||
|
{
|
||||||
|
auto *opt_disp_cols = cfg.option<ConfigOptionInt>("display_pixels_x");
|
||||||
|
auto *opt_disp_rows = cfg.option<ConfigOptionInt>("display_pixels_y");
|
||||||
|
auto *opt_disp_w = cfg.option<ConfigOptionFloat>("display_width");
|
||||||
|
auto *opt_disp_h = cfg.option<ConfigOptionFloat>("display_height");
|
||||||
|
auto *opt_mirror_x = cfg.option<ConfigOptionBool>("display_mirror_x");
|
||||||
|
auto *opt_mirror_y = cfg.option<ConfigOptionBool>("display_mirror_y");
|
||||||
|
auto *opt_orient = cfg.option<ConfigOptionEnum<SLADisplayOrientation>>("display_orientation");
|
||||||
|
|
||||||
|
if (!opt_disp_cols || !opt_disp_rows || !opt_disp_w || !opt_disp_h ||
|
||||||
|
!opt_mirror_x || !opt_mirror_y || !opt_orient)
|
||||||
|
throw MissingProfileError("Invalid SL1 / SL1S file");
|
||||||
|
|
||||||
|
RasterParams rstp;
|
||||||
|
|
||||||
|
rstp.trafo = sla::RasterBase::Trafo{opt_orient->value == sladoLandscape ?
|
||||||
|
sla::RasterBase::roLandscape :
|
||||||
|
sla::RasterBase::roPortrait,
|
||||||
|
{opt_mirror_x->value, opt_mirror_y->value}};
|
||||||
|
|
||||||
|
rstp.height = scaled(opt_disp_h->value);
|
||||||
|
rstp.width = scaled(opt_disp_w->value);
|
||||||
|
|
||||||
|
return rstp;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NanoSVGParser {
|
||||||
|
NSVGimage *image;
|
||||||
|
static constexpr const char *Units = "mm"; // Denotes user coordinate system
|
||||||
|
static constexpr float Dpi = 1.f; // Not needed
|
||||||
|
NanoSVGParser(char* input): image{nsvgParse(input, Units, Dpi)} {}
|
||||||
|
~NanoSVGParser() { nsvgDelete(image); }
|
||||||
|
};
|
||||||
|
|
||||||
ConfigSubstitutions SL1_SVGReader::read(std::vector<ExPolygons> &slices,
|
ConfigSubstitutions SL1_SVGReader::read(std::vector<ExPolygons> &slices,
|
||||||
DynamicPrintConfig &profile_out)
|
DynamicPrintConfig &profile_out)
|
||||||
{
|
{
|
||||||
std::vector<std::string> includes = { "config.ini", "prusaslicer.ini", "svg"};
|
std::vector<std::string> includes = { CONFIG_FNAME, PROFILE_FNAME, "svg"};
|
||||||
ZipperArchive arch = read_zipper_archive(m_fname, includes, {});
|
ZipperArchive arch = read_zipper_archive(m_fname, includes, {});
|
||||||
|
|
||||||
DynamicPrintConfig profile_in, profile_use;
|
DynamicPrintConfig profile_in, profile_use;
|
||||||
|
@ -271,25 +322,44 @@ ConfigSubstitutions SL1_SVGReader::read(std::vector<ExPolygons> &slices,
|
||||||
profile_use = profile_in.empty() ? profile_out : profile_in;
|
profile_use = profile_in.empty() ? profile_out : profile_in;
|
||||||
profile_out = profile_in;
|
profile_out = profile_in;
|
||||||
|
|
||||||
|
RasterParams rstp = get_raster_params(profile_use);
|
||||||
|
|
||||||
|
struct Status
|
||||||
|
{
|
||||||
|
double incr, val, prev;
|
||||||
|
bool stop = false;
|
||||||
|
} st{100. / arch.entries.size(), 0., 0.};
|
||||||
|
|
||||||
for (const EntryBuffer &entry : arch.entries) {
|
for (const EntryBuffer &entry : arch.entries) {
|
||||||
NSVGimage* image;
|
if (st.stop) break;
|
||||||
|
|
||||||
|
st.val += st.incr;
|
||||||
|
double curr = std::round(st.val);
|
||||||
|
if (curr > st.prev) {
|
||||||
|
st.prev = curr;
|
||||||
|
st.stop = !m_progr(int(curr));
|
||||||
|
}
|
||||||
|
|
||||||
auto svgtxt = reserve_vector<char>(entry.buf.size());
|
auto svgtxt = reserve_vector<char>(entry.buf.size());
|
||||||
std::copy(entry.buf.begin(), entry.buf.end(), std::back_inserter(svgtxt));
|
std::copy(entry.buf.begin(), entry.buf.end(), std::back_inserter(svgtxt));
|
||||||
image = nsvgParse(svgtxt.data(), "px", 96);
|
NanoSVGParser svgp(svgtxt.data());
|
||||||
printf("size: %f x %f\n", image->width, image->height);
|
|
||||||
// Use...
|
|
||||||
for (NSVGshape *shape = image->shapes; shape != nullptr; shape = shape->next) {
|
|
||||||
for (NSVGpath *path = shape->paths; path != nullptr; path = path->next) {
|
|
||||||
|
|
||||||
|
Polygons polys;
|
||||||
|
for (NSVGshape *shape = svgp.image->shapes; shape != nullptr; shape = shape->next) {
|
||||||
|
for (NSVGpath *path = shape->paths; path != nullptr; path = path->next) {
|
||||||
|
Polygon p;
|
||||||
|
for (int i = 0; i < path->npts; ++i) {
|
||||||
|
size_t c = 2 * i;
|
||||||
|
p.points.emplace_back(scaled(Vec2f(path->pts[c], path->pts[c + 1])));
|
||||||
|
}
|
||||||
|
polys.emplace_back(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Delete
|
|
||||||
nsvgDelete(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RasterParams rstp = get_raster_params(profile_use);
|
ExPolygons expolys = union_ex(polys);
|
||||||
// rstp.win = {windowsize.y(), windowsize.x()};
|
invert_raster_trafo(expolys, rstp.trafo, rstp.width, rstp.height);
|
||||||
// slices = extract_slices_from_sla_archive(arch, rstp, m_progr);
|
slices.emplace_back(expolys);
|
||||||
|
}
|
||||||
|
|
||||||
return config_substitutions;
|
return config_substitutions;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
static const constexpr char *CONFIG_FNAME = "config.ini";
|
|
||||||
static const constexpr char *PROFILE_FNAME = "prusaslicer.ini";
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
|
boost::property_tree::ptree read_ini(const mz_zip_archive_file_stat &entry,
|
||||||
|
@ -83,8 +80,8 @@ ZipperArchive read_zipper_archive(const std::string &zipfname,
|
||||||
}))
|
}))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (name == CONFIG_FNAME) arch.config = read_ini(entry, zip);
|
if (name == CONFIG_FNAME) { arch.config = read_ini(entry, zip); continue; }
|
||||||
if (name == PROFILE_FNAME) arch.profile = read_ini(entry, zip);
|
if (name == PROFILE_FNAME) { arch.profile = read_ini(entry, zip); continue; }
|
||||||
|
|
||||||
auto it = std::lower_bound(
|
auto it = std::lower_bound(
|
||||||
arch.entries.begin(), arch.entries.end(),
|
arch.entries.begin(), arch.entries.end(),
|
||||||
|
|
|
@ -21,6 +21,9 @@ struct ZipperArchive
|
||||||
std::vector<EntryBuffer> entries;
|
std::vector<EntryBuffer> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const constexpr char *CONFIG_FNAME = "config.ini";
|
||||||
|
const constexpr char *PROFILE_FNAME = "prusaslicer.ini";
|
||||||
|
|
||||||
ZipperArchive read_zipper_archive(const std::string &zipfname,
|
ZipperArchive read_zipper_archive(const std::string &zipfname,
|
||||||
const std::vector<std::string> &includes,
|
const std::vector<std::string> &includes,
|
||||||
const std::vector<std::string> &excludes);
|
const std::vector<std::string> &excludes);
|
||||||
|
|
Loading…
Add table
Reference in a new issue