Archive reader types are now registered in one place
This commit is contained in:
parent
885e6964ba
commit
32a923da93
10 changed files with 225 additions and 167 deletions
|
@ -297,34 +297,6 @@ 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 {
|
||||
sla::RasterBase::Trafo trafo; // Raster transformations
|
||||
coord_t width, height; // scaled raster dimensions (not resolution)
|
||||
double px_h, px_w; // pixel dimesions
|
||||
marchsq::Coord win; // marching squares window size
|
||||
};
|
||||
|
||||
RasterParams get_raster_params(const DynamicPrintConfig &cfg)
|
||||
{
|
||||
auto *opt_disp_cols = cfg.option<ConfigOptionInt>("display_pixels_x");
|
||||
|
@ -355,9 +327,31 @@ RasterParams get_raster_params(const DynamicPrintConfig &cfg)
|
|||
return rstp;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::vector<ExPolygons> extract_slices_from_sla_archive(
|
||||
ZipperArchive &arch,
|
||||
const RasterParams &rstp,
|
||||
const marchsq::Coord &win,
|
||||
std::function<bool(int)> progr)
|
||||
{
|
||||
std::vector<ExPolygons> slices(arch.entries.size());
|
||||
|
@ -371,7 +365,7 @@ std::vector<ExPolygons> extract_slices_from_sla_archive(
|
|||
|
||||
execution::for_each(
|
||||
ex_tbb, size_t(0), arch.entries.size(),
|
||||
[&arch, &slices, &st, &rstp, progr](size_t i) {
|
||||
[&arch, &slices, &st, &rstp, &win, progr](size_t i) {
|
||||
// Status indication guarded with the spinlock
|
||||
{
|
||||
std::lock_guard lck(st.mutex);
|
||||
|
@ -391,7 +385,7 @@ std::vector<ExPolygons> extract_slices_from_sla_archive(
|
|||
if (!png::decode_png(rb, img)) return;
|
||||
|
||||
constexpr uint8_t isoval = 128;
|
||||
auto rings = marchsq::execute(img, isoval, rstp.win);
|
||||
auto rings = marchsq::execute(img, isoval, win);
|
||||
ExPolygons expolys = rings_to_expolygons(rings, rstp.px_w,
|
||||
rstp.px_h);
|
||||
|
||||
|
@ -430,38 +424,13 @@ ConfigSubstitutions SL1Reader::read(std::vector<ExPolygons> &slices,
|
|||
std::vector<std::string> includes = { "ini", "png"};
|
||||
std::vector<std::string> excludes = { "thumbnail" };
|
||||
ZipperArchive arch = read_zipper_archive(m_fname, includes, excludes);
|
||||
auto [profile_use, config_substitutions] = extract_profile(arch, profile_out);
|
||||
|
||||
DynamicPrintConfig profile_in, profile_use;
|
||||
ConfigSubstitutions config_substitutions =
|
||||
profile_in.load(arch.profile,
|
||||
ForwardCompatibilitySubstitutionRule::Enable);
|
||||
RasterParams rstp = get_raster_params(profile_use);
|
||||
marchsq::Coord win = {windowsize.y(), windowsize.x()};
|
||||
slices = extract_slices_from_sla_archive(arch, rstp, win, m_progr);
|
||||
|
||||
if (profile_in.empty()) { // missing profile... do guess work
|
||||
// try to recover the layer height from the config.ini which was
|
||||
// present in all versions of sl1 files.
|
||||
if (auto lh_opt = arch.config.find("layerHeight");
|
||||
lh_opt != arch.config.not_found()) {
|
||||
auto lh_str = lh_opt->second.data();
|
||||
|
||||
size_t pos;
|
||||
double lh = string_to_double_decimal_point(lh_str, &pos);
|
||||
if (pos) { // TODO: verify that pos is 0 when parsing fails
|
||||
profile_out.set("layer_height", lh);
|
||||
profile_out.set("initial_layer_height", lh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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()};
|
||||
slices = extract_slices_from_sla_archive(arch, rstp, m_progr);
|
||||
|
||||
return config_substitutions;
|
||||
return std::move(config_substitutions);
|
||||
}
|
||||
|
||||
ConfigSubstitutions SL1Reader::read(DynamicPrintConfig &out)
|
||||
|
|
|
@ -60,6 +60,14 @@ public:
|
|||
{}
|
||||
};
|
||||
|
||||
struct RasterParams {
|
||||
sla::RasterBase::Trafo trafo; // Raster transformations
|
||||
coord_t width, height; // scaled raster dimensions (not resolution)
|
||||
double px_h, px_w; // pixel dimesions
|
||||
};
|
||||
|
||||
RasterParams get_raster_params(const DynamicPrintConfig &cfg);
|
||||
|
||||
void invert_raster_trafo(ExPolygons & expolys,
|
||||
const sla::RasterBase::Trafo &trafo,
|
||||
coord_t width,
|
||||
|
|
|
@ -77,21 +77,6 @@ void transform(ExPolygon &ep, const sla::RasterBase::Trafo &tr, const BoundingBo
|
|||
|
||||
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())
|
||||
return;
|
||||
|
||||
|
@ -207,10 +192,10 @@ std::unique_ptr<sla::RasterBase> SL1_SVGArchive::create_raster() const
|
|||
auto h = cfg().display_height.getFloat();
|
||||
|
||||
float precision_nm = scaled<float>(cfg().sla_output_precision.getFloat());
|
||||
size_t res_x = std::round(scaled(w) / precision_nm);
|
||||
size_t res_y = std::round(scaled(h) / precision_nm);
|
||||
auto res_x = size_t(std::round(scaled(w) / precision_nm));
|
||||
auto res_y = size_t(std::round(scaled(h) / precision_nm));
|
||||
|
||||
std::array<bool, 2> mirror;
|
||||
std::array<bool, 2> mirror;
|
||||
|
||||
mirror[X] = cfg().display_mirror_x.getBool();
|
||||
mirror[Y] = cfg().display_mirror_y.getBool();
|
||||
|
@ -249,43 +234,11 @@ void SL1_SVGArchive::export_print(const std::string fname,
|
|||
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)} {}
|
||||
explicit NanoSVGParser(char* input): image{nsvgParse(input, Units, Dpi)} {}
|
||||
~NanoSVGParser() { nsvgDelete(image); }
|
||||
};
|
||||
|
||||
|
@ -294,33 +247,7 @@ ConfigSubstitutions SL1_SVGReader::read(std::vector<ExPolygons> &slices,
|
|||
{
|
||||
std::vector<std::string> includes = { CONFIG_FNAME, PROFILE_FNAME, "svg"};
|
||||
ZipperArchive arch = read_zipper_archive(m_fname, includes, {});
|
||||
|
||||
DynamicPrintConfig profile_in, profile_use;
|
||||
ConfigSubstitutions config_substitutions =
|
||||
profile_in.load(arch.profile,
|
||||
ForwardCompatibilitySubstitutionRule::Enable);
|
||||
|
||||
if (profile_in.empty()) { // missing profile... do guess work
|
||||
// try to recover the layer height from the config.ini which was
|
||||
// present in all versions of sl1 files.
|
||||
if (auto lh_opt = arch.config.find("layerHeight");
|
||||
lh_opt != arch.config.not_found()) {
|
||||
auto lh_str = lh_opt->second.data();
|
||||
|
||||
size_t pos;
|
||||
double lh = string_to_double_decimal_point(lh_str, &pos);
|
||||
if (pos) { // TODO: verify that pos is 0 when parsing fails
|
||||
profile_out.set("layer_height", lh);
|
||||
profile_out.set("initial_layer_height", lh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
auto [profile_use, config_substitutions] = extract_profile(arch, profile_out);
|
||||
|
||||
RasterParams rstp = get_raster_params(profile_use);
|
||||
|
||||
|
@ -361,7 +288,8 @@ ConfigSubstitutions SL1_SVGReader::read(std::vector<ExPolygons> &slices,
|
|||
slices.emplace_back(expolys);
|
||||
}
|
||||
|
||||
return config_substitutions;
|
||||
// Compile error without the move
|
||||
return std::move(config_substitutions);
|
||||
}
|
||||
|
||||
ConfigSubstitutions SL1_SVGReader::read(DynamicPrintConfig &out)
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
};
|
||||
|
||||
class SL1_SVGReader: public SLAArchiveReader {
|
||||
SLAImportQuality m_quality = SLAImportQuality::Balanced;
|
||||
std::function<bool(int)> m_progr;
|
||||
std::string m_fname;
|
||||
|
||||
|
@ -38,9 +37,9 @@ public:
|
|||
|
||||
SL1_SVGReader() = default;
|
||||
SL1_SVGReader(const std::string &fname,
|
||||
SLAImportQuality quality,
|
||||
std::function<bool(int)> progr)
|
||||
: m_quality(quality), m_progr(progr), m_fname(fname)
|
||||
SLAImportQuality /*quality*/,
|
||||
const ProgrFn & progr)
|
||||
: m_progr(progr), m_fname(fname)
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
@ -7,48 +7,101 @@
|
|||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
constexpr const char * L(const char * str) { return str; }
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace {
|
||||
|
||||
using ArchiveFactory = std::function<
|
||||
std::unique_ptr<SLAArchiveReader>(const std::string &fname,
|
||||
SLAImportQuality quality,
|
||||
const ProgrFn & progr)>;
|
||||
|
||||
struct ArchiveEntry {
|
||||
const char *descr;
|
||||
std::vector<const char *> extensions;
|
||||
ArchiveFactory factoryfn;
|
||||
};
|
||||
|
||||
static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
|
||||
{
|
||||
"SL1",
|
||||
{ L("SL1 / SL1S archive files"), {"sl1", "sl1s", "zip"},
|
||||
[] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1Reader>(fname, quality, progr); } }
|
||||
},
|
||||
{
|
||||
"SL2",
|
||||
{ L("SL2 archive files"), {"sl2", "sl1_svg", "zip"},
|
||||
[] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1_SVGReader>(fname, quality, progr); }}
|
||||
},
|
||||
// TODO: pwmx
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<SLAArchiveReader> SLAArchiveReader::create(
|
||||
const std::string &fname,
|
||||
SLAImportQuality quality,
|
||||
std::function<bool(int)> progr)
|
||||
const ProgrFn & progr)
|
||||
{
|
||||
std::string ext = boost::filesystem::path(fname).extension().string();
|
||||
boost::algorithm::to_lower(ext);
|
||||
|
||||
std::unique_ptr<SLAArchiveReader> ret;
|
||||
|
||||
const char *SL1_ext[] = {
|
||||
SLAArchiveWriter::get_extension("SL1"),
|
||||
"sl1s",
|
||||
// ...
|
||||
};
|
||||
|
||||
const char *SL2_ext[] = {
|
||||
SLAArchiveWriter::get_extension("SL2"),
|
||||
"sl1_svg",
|
||||
// ...
|
||||
};
|
||||
|
||||
if (!ext.empty()) {
|
||||
if (ext.front() == '.')
|
||||
ext.erase(ext.begin());
|
||||
|
||||
auto extcmp = [&ext](const auto &e) { return e == ext; };
|
||||
|
||||
if (std::any_of(std::begin(SL1_ext), std::end(SL1_ext), extcmp)) {
|
||||
ret = std::make_unique<SL1Reader>(fname, quality, progr);
|
||||
} else if (std::any_of(std::begin(SL2_ext), std::end(SL2_ext), extcmp)) {
|
||||
ret = std::make_unique<SL1_SVGReader>(fname, quality, progr);
|
||||
for (const auto &[format_id, entry] : REGISTERED_ARCHIVES) {
|
||||
if (std::any_of(entry.extensions.begin(), entry.extensions.end(), extcmp))
|
||||
ret = entry.factoryfn(fname, quality, progr);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::vector<const char *> &SLAArchiveReader::registered_archives()
|
||||
{
|
||||
static std::vector<const char*> archnames;
|
||||
|
||||
if (archnames.empty()) {
|
||||
archnames.reserve(REGISTERED_ARCHIVES.size());
|
||||
|
||||
for (auto &[name, _] : REGISTERED_ARCHIVES)
|
||||
archnames.emplace_back(name.c_str());
|
||||
}
|
||||
|
||||
return archnames;
|
||||
}
|
||||
|
||||
std::vector<const char *> SLAArchiveReader::get_extensions(const char *archtype)
|
||||
{
|
||||
auto it = REGISTERED_ARCHIVES.find(archtype);
|
||||
|
||||
if (it != REGISTERED_ARCHIVES.end())
|
||||
return it->second.extensions;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const char *SLAArchiveReader::get_description(const char *archtype)
|
||||
{
|
||||
auto it = REGISTERED_ARCHIVES.find(archtype);
|
||||
|
||||
if (it != REGISTERED_ARCHIVES.end())
|
||||
return it->second.descr;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct SliceParams { double layerh = 0., initial_layerh = 0.; };
|
||||
|
||||
static SliceParams get_slice_params(const DynamicPrintConfig &cfg)
|
||||
|
@ -66,7 +119,7 @@ ConfigSubstitutions import_sla_archive(const std::string &zipfname,
|
|||
indexed_triangle_set &out,
|
||||
DynamicPrintConfig &profile,
|
||||
SLAImportQuality quality,
|
||||
std::function<bool(int)> progr)
|
||||
const ProgrFn & progr)
|
||||
{
|
||||
ConfigSubstitutions ret;
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ enum class SLAImportQuality { Accurate, Balanced, Fast };
|
|||
|
||||
class MissingProfileError : public RuntimeError { using RuntimeError::RuntimeError; };
|
||||
|
||||
using ProgrFn = std::function<bool(int)>;
|
||||
|
||||
class SLAArchiveReader {
|
||||
public:
|
||||
|
||||
|
@ -23,9 +25,17 @@ public:
|
|||
virtual ConfigSubstitutions read(DynamicPrintConfig &profile) = 0;
|
||||
|
||||
static std::unique_ptr<SLAArchiveReader> create(
|
||||
const std::string &fname,
|
||||
SLAImportQuality quality = SLAImportQuality::Balanced,
|
||||
std::function<bool(int)> progr = [](int){ return false; });
|
||||
const std::string &fname,
|
||||
SLAImportQuality quality = SLAImportQuality::Balanced,
|
||||
const ProgrFn &progr = [](int) { return false; });
|
||||
|
||||
// Get the names of currently known archive reader implementations
|
||||
static const std::vector<const char *> & registered_archives();
|
||||
|
||||
// Get the default file extensions belonging to an archive format
|
||||
static std::vector<const char *> get_extensions(const char *archtype);
|
||||
|
||||
static const char * get_description(const char *archtype);
|
||||
};
|
||||
|
||||
class ReaderUnimplementedError : public RuntimeError { using RuntimeError::RuntimeError; };
|
||||
|
@ -38,7 +48,7 @@ ConfigSubstitutions import_sla_archive(
|
|||
indexed_triangle_set &out,
|
||||
DynamicPrintConfig &profile,
|
||||
SLAImportQuality quality = SLAImportQuality::Balanced,
|
||||
std::function<bool(int)> progr = [](int) { return true; });
|
||||
const ProgrFn &progr = [](int) { return true; });
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
@ -97,4 +98,36 @@ ZipperArchive read_zipper_archive(const std::string &zipfname,
|
|||
return arch;
|
||||
}
|
||||
|
||||
std::pair<DynamicPrintConfig, ConfigSubstitutions> extract_profile(
|
||||
const ZipperArchive &arch, DynamicPrintConfig &profile_out)
|
||||
{
|
||||
DynamicPrintConfig profile_in, profile_use;
|
||||
ConfigSubstitutions config_substitutions =
|
||||
profile_in.load(arch.profile,
|
||||
ForwardCompatibilitySubstitutionRule::Enable);
|
||||
|
||||
if (profile_in.empty()) { // missing profile... do guess work
|
||||
// try to recover the layer height from the config.ini which was
|
||||
// present in all versions of sl1 files.
|
||||
if (auto lh_opt = arch.config.find("layerHeight");
|
||||
lh_opt != arch.config.not_found()) {
|
||||
auto lh_str = lh_opt->second.data();
|
||||
|
||||
size_t pos = 0;
|
||||
double lh = string_to_double_decimal_point(lh_str, &pos);
|
||||
if (pos) { // TODO: verify that pos is 0 when parsing fails
|
||||
profile_out.set("layer_height", lh);
|
||||
profile_out.set("initial_layer_height", lh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
return {profile_use, std::move(config_substitutions)};
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
struct EntryBuffer
|
||||
|
@ -28,6 +30,14 @@ ZipperArchive read_zipper_archive(const std::string &zipfname,
|
|||
const std::vector<std::string> &includes,
|
||||
const std::vector<std::string> &excludes);
|
||||
|
||||
// Extract the print profile form the archive onto 'out'.
|
||||
// Returns a profile that has correct parameters to use for model reconstruction
|
||||
// even if the needed parameters were not fully found in the archive's metadata.
|
||||
// The inout argument shall be a usable fallback profile if the archive
|
||||
// has totally corrupted metadata.
|
||||
std::pair<DynamicPrintConfig, ConfigSubstitutions> extract_profile(
|
||||
const ZipperArchive &arch, DynamicPrintConfig &inout);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // ZIPPERARCHIVEIMPORT_HPP
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <wx/filepicker.h>
|
||||
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/Format/SLAArchiveReader.hpp"
|
||||
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
|
@ -21,6 +23,52 @@
|
|||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
std::string get_readers_wildcard()
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
for (const char *archtype : SLAArchiveReader::registered_archives()) {
|
||||
ret += _utf8(SLAArchiveReader::get_description(archtype));
|
||||
ret += " (";
|
||||
auto extensions = SLAArchiveReader::get_extensions(archtype);
|
||||
for (const char * ext : extensions) {
|
||||
ret += "*.";
|
||||
ret += ext;
|
||||
ret += ", ";
|
||||
}
|
||||
// remove last ", "
|
||||
if (!extensions.empty()) {
|
||||
ret.pop_back();
|
||||
ret.pop_back();
|
||||
}
|
||||
|
||||
ret += ")|";
|
||||
|
||||
for (std::string ext : extensions) {
|
||||
boost::algorithm::to_lower(ext);
|
||||
ret += "*.";
|
||||
ret += ext;
|
||||
ret += ";";
|
||||
|
||||
boost::algorithm::to_upper(ext);
|
||||
ret += "*.";
|
||||
ret += ext;
|
||||
ret += ";";
|
||||
}
|
||||
|
||||
// remove last ';'
|
||||
if (!extensions.empty())
|
||||
ret.pop_back();
|
||||
|
||||
ret += "|";
|
||||
}
|
||||
|
||||
if (ret.back() == '|')
|
||||
ret.pop_back();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
class SLAImportDialog: public wxDialog, public SLAImportJobView {
|
||||
wxFilePickerCtrl *m_filepicker;
|
||||
wxComboBox *m_import_dropdown, *m_quality_dropdown;
|
||||
|
@ -34,7 +82,7 @@ public:
|
|||
|
||||
m_filepicker = new wxFilePickerCtrl(this, wxID_ANY,
|
||||
from_u8(wxGetApp().app_config->get_last_dir()), _(L("Choose SLA archive:")),
|
||||
"SL1 / SL1S archive files (*.sl1, *.sl1s, *.zip)|*.sl1;*.SL1;*.sl1s;*.SL1S;*.zip;*.ZIP|SL2 archive files (*.sl2)|*.sl2",
|
||||
get_readers_wildcard(),
|
||||
wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE | wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
szfilepck->Add(new wxStaticText(this, wxID_ANY, _L("Import file") + ": "), 0, wxALIGN_CENTER);
|
||||
|
|
|
@ -1212,7 +1212,7 @@ void MainFrame::init_menubar_as_editor()
|
|||
[this](wxCommandEvent&) { if (m_plater) m_plater->add_model(true); }, "import_plater", nullptr,
|
||||
[this](){return m_plater != nullptr; }, this);
|
||||
|
||||
append_menu_item(import_menu, wxID_ANY, _L("Import SL1 / SL1S Archive") + dots, _L("Load an SL1 / Sl1S archive"),
|
||||
append_menu_item(import_menu, wxID_ANY, _L("Import SLA Archive") + dots, _L("Load an SLA archive"),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->import_sl1_archive(); }, "import_plater", nullptr,
|
||||
[this](){return m_plater != nullptr && m_plater->get_ui_job_worker().is_idle(); }, this);
|
||||
|
||||
|
|
Loading…
Reference in a new issue