3mf import/export of config data
This commit is contained in:
parent
33553e1c50
commit
8885f5e344
@ -628,8 +628,19 @@ sub load_files {
|
|||||||
my $input_file = $input_files->[$i];
|
my $input_file = $input_files->[$i];
|
||||||
$process_dialog->Update(100. * $i / @$input_files, "Processing input file\n" . basename($input_file));
|
$process_dialog->Update(100. * $i / @$input_files, "Processing input file\n" . basename($input_file));
|
||||||
|
|
||||||
my $model = eval { Slic3r::Model->read_from_file($input_file, 0) };
|
my $model;
|
||||||
Slic3r::GUI::show_error($self, $@) if $@;
|
if ($input_file =~ /.3[mM][fF]$/)
|
||||||
|
{
|
||||||
|
$model = eval { Slic3r::Model->read_from_archive($input_file, wxTheApp->{preset_bundle}, 0) };
|
||||||
|
Slic3r::GUI::show_error($self, $@) if $@;
|
||||||
|
$_->load_current_preset for (values %{$self->GetFrame->{options_tabs}});
|
||||||
|
wxTheApp->{app_config}->update_config_dir(dirname($input_file));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$model = eval { Slic3r::Model->read_from_file($input_file, 0) };
|
||||||
|
Slic3r::GUI::show_error($self, $@) if $@;
|
||||||
|
}
|
||||||
|
|
||||||
next if ! defined $model;
|
next if ! defined $model;
|
||||||
|
|
||||||
@ -1555,7 +1566,7 @@ sub export_3mf {
|
|||||||
return if !@{$self->{objects}};
|
return if !@{$self->{objects}};
|
||||||
# Ask user for a file name to write into.
|
# Ask user for a file name to write into.
|
||||||
my $output_file = $self->_get_export_file('3MF') or return;
|
my $output_file = $self->_get_export_file('3MF') or return;
|
||||||
my $res = $self->{model}->store_3mf($output_file);
|
my $res = $self->{model}->store_3mf($output_file, $self->{print});
|
||||||
if ($res)
|
if ($res)
|
||||||
{
|
{
|
||||||
$self->statusbar->SetStatusText("3MF file exported to $output_file");
|
$self->statusbar->SetStatusText("3MF file exported to $output_file");
|
||||||
|
@ -324,7 +324,7 @@ void ConfigBase::setenv_()
|
|||||||
void ConfigBase::load(const std::string &file)
|
void ConfigBase::load(const std::string &file)
|
||||||
{
|
{
|
||||||
if (boost::iends_with(file, ".gcode") || boost::iends_with(file, ".g"))
|
if (boost::iends_with(file, ".gcode") || boost::iends_with(file, ".g"))
|
||||||
this->load_from_gcode(file);
|
this->load_from_gcode_file(file);
|
||||||
else
|
else
|
||||||
this->load_from_ini(file);
|
this->load_from_ini(file);
|
||||||
}
|
}
|
||||||
@ -349,10 +349,10 @@ void ConfigBase::load(const boost::property_tree::ptree &tree)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the config keys from the tail of a G-code.
|
// Load the config keys from the tail of a G-code file.
|
||||||
void ConfigBase::load_from_gcode(const std::string &file)
|
void ConfigBase::load_from_gcode_file(const std::string &file)
|
||||||
{
|
{
|
||||||
// 1) Read a 64k block from the end of the G-code.
|
// Read a 64k block from the end of the G-code.
|
||||||
boost::nowide::ifstream ifs(file);
|
boost::nowide::ifstream ifs(file);
|
||||||
{
|
{
|
||||||
const char slic3r_gcode_header[] = "; generated by Slic3r ";
|
const char slic3r_gcode_header[] = "; generated by Slic3r ";
|
||||||
@ -365,30 +365,39 @@ void ConfigBase::load_from_gcode(const std::string &file)
|
|||||||
auto file_length = ifs.tellg();
|
auto file_length = ifs.tellg();
|
||||||
auto data_length = std::min<std::fstream::streampos>(65535, file_length);
|
auto data_length = std::min<std::fstream::streampos>(65535, file_length);
|
||||||
ifs.seekg(file_length - data_length, ifs.beg);
|
ifs.seekg(file_length - data_length, ifs.beg);
|
||||||
std::vector<char> data(size_t(data_length) + 1, 0);
|
std::vector<char> data(size_t(data_length) + 1, 0);
|
||||||
ifs.read(data.data(), data_length);
|
ifs.read(data.data(), data_length);
|
||||||
ifs.close();
|
ifs.close();
|
||||||
|
|
||||||
// 2) Walk line by line in reverse until a non-configuration key appears.
|
load_from_gcode_string(data.data());
|
||||||
char *data_start = data.data();
|
}
|
||||||
|
|
||||||
|
// Load the config keys from the given string.
|
||||||
|
void ConfigBase::load_from_gcode_string(const char* str)
|
||||||
|
{
|
||||||
|
if (str == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Walk line by line in reverse until a non-configuration key appears.
|
||||||
|
char *data_start = const_cast<char*>(str);
|
||||||
// boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved.
|
// boost::nowide::ifstream seems to cook the text data somehow, so less then the 64k of characters may be retrieved.
|
||||||
char *end = data_start + strlen(data.data());
|
char *end = data_start + strlen(str);
|
||||||
size_t num_key_value_pairs = 0;
|
size_t num_key_value_pairs = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Extract next line.
|
// Extract next line.
|
||||||
for (-- end; end > data_start && (*end == '\r' || *end == '\n'); -- end);
|
for (--end; end > data_start && (*end == '\r' || *end == '\n'); --end);
|
||||||
if (end == data_start)
|
if (end == data_start)
|
||||||
break;
|
break;
|
||||||
char *start = end;
|
char *start = end;
|
||||||
*(++ end) = 0;
|
*(++end) = 0;
|
||||||
for (; start > data_start && *start != '\r' && *start != '\n'; -- start);
|
for (; start > data_start && *start != '\r' && *start != '\n'; --start);
|
||||||
if (start == data_start)
|
if (start == data_start)
|
||||||
break;
|
break;
|
||||||
// Extracted a line from start to end. Extract the key = value pair.
|
// Extracted a line from start to end. Extract the key = value pair.
|
||||||
if (end - (++ start) < 10 || start[0] != ';' || start[1] != ' ')
|
if (end - (++start) < 10 || start[0] != ';' || start[1] != ' ')
|
||||||
break;
|
break;
|
||||||
char *key = start + 2;
|
char *key = start + 2;
|
||||||
if (! (*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
|
if (!(*key >= 'a' && *key <= 'z') || (*key >= 'A' && *key <= 'Z'))
|
||||||
// A key must start with a letter.
|
// A key must start with a letter.
|
||||||
break;
|
break;
|
||||||
char *sep = strchr(key, '=');
|
char *sep = strchr(key, '=');
|
||||||
@ -402,8 +411,8 @@ void ConfigBase::load_from_gcode(const std::string &file)
|
|||||||
break;
|
break;
|
||||||
*key_end = 0;
|
*key_end = 0;
|
||||||
// The key may contain letters, digits and underscores.
|
// The key may contain letters, digits and underscores.
|
||||||
for (char *c = key; c != key_end; ++ c)
|
for (char *c = key; c != key_end; ++c)
|
||||||
if (! ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) {
|
if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '_')) {
|
||||||
key = nullptr;
|
key = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -411,8 +420,9 @@ void ConfigBase::load_from_gcode(const std::string &file)
|
|||||||
break;
|
break;
|
||||||
try {
|
try {
|
||||||
this->set_deserialize(key, value);
|
this->set_deserialize(key, value);
|
||||||
++ num_key_value_pairs;
|
++num_key_value_pairs;
|
||||||
} catch (UnknownOptionException & /* e */) {
|
}
|
||||||
|
catch (UnknownOptionException & /* e */) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
end = start;
|
end = start;
|
||||||
|
@ -1049,7 +1049,8 @@ public:
|
|||||||
void setenv_();
|
void setenv_();
|
||||||
void load(const std::string &file);
|
void load(const std::string &file);
|
||||||
void load_from_ini(const std::string &file);
|
void load_from_ini(const std::string &file);
|
||||||
void load_from_gcode(const std::string &file);
|
void load_from_gcode_file(const std::string &file);
|
||||||
|
void load_from_gcode_string(const char* str);
|
||||||
void load(const boost::property_tree::ptree &tree);
|
void load(const boost::property_tree::ptree &tree);
|
||||||
void save(const std::string &file) const;
|
void save(const std::string &file) const;
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#include "../libslic3r.h"
|
#include "../libslic3r.h"
|
||||||
#include "../Model.hpp"
|
#include "../Model.hpp"
|
||||||
|
#include "../Utils.hpp"
|
||||||
|
#include "../GCode.hpp"
|
||||||
|
#include "../slic3r/GUI/PresetBundle.hpp"
|
||||||
|
|
||||||
#include "3mf.hpp"
|
#include "3mf.hpp"
|
||||||
|
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
|
|
||||||
@ -17,6 +21,7 @@ const std::string MODEL_EXTENSION = ".model";
|
|||||||
const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
|
const std::string MODEL_FILE = "3D/3dmodel.model"; // << this is the only format of the string which works with CURA
|
||||||
const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
|
const std::string CONTENT_TYPES_FILE = "[Content_Types].xml";
|
||||||
const std::string RELATIONSHIPS_FILE = "_rels/.rels";
|
const std::string RELATIONSHIPS_FILE = "_rels/.rels";
|
||||||
|
const std::string CONFIG_FILE = "Metadata/Slic3r_PE.config";
|
||||||
|
|
||||||
const char* MODEL_TAG = "model";
|
const char* MODEL_TAG = "model";
|
||||||
const char* RESOURCES_TAG = "resources";
|
const char* RESOURCES_TAG = "resources";
|
||||||
@ -217,7 +222,7 @@ namespace Slic3r {
|
|||||||
_3MF_Importer();
|
_3MF_Importer();
|
||||||
~_3MF_Importer();
|
~_3MF_Importer();
|
||||||
|
|
||||||
bool load_model_from_file(const std::string& filename, Model& model);
|
bool load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle);
|
||||||
|
|
||||||
const std::vector<std::string>& get_errors() const;
|
const std::vector<std::string>& get_errors() const;
|
||||||
|
|
||||||
@ -225,8 +230,9 @@ namespace Slic3r {
|
|||||||
void _destroy_xml_parser();
|
void _destroy_xml_parser();
|
||||||
void _stop_xml_parser();
|
void _stop_xml_parser();
|
||||||
|
|
||||||
bool _load_model_from_file_miniz(const std::string& filename, Model& model);
|
bool _load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle);
|
||||||
bool _extract_model_from_archive_miniz(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
|
bool _extract_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename);
|
||||||
|
|
||||||
void _handle_start_xml_element(const char* name, const char** attributes);
|
void _handle_start_xml_element(const char* name, const char** attributes);
|
||||||
void _handle_end_xml_element(const char* name);
|
void _handle_end_xml_element(const char* name);
|
||||||
@ -331,7 +337,7 @@ namespace Slic3r {
|
|||||||
_destroy_xml_parser();
|
_destroy_xml_parser();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model)
|
bool _3MF_Importer::load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle)
|
||||||
{
|
{
|
||||||
m_model = &model;
|
m_model = &model;
|
||||||
m_unit_factor = 1.0f;
|
m_unit_factor = 1.0f;
|
||||||
@ -341,7 +347,7 @@ namespace Slic3r {
|
|||||||
m_instances.clear();
|
m_instances.clear();
|
||||||
m_errors.clear();
|
m_errors.clear();
|
||||||
|
|
||||||
return _load_model_from_file_miniz(filename, model);
|
return _load_model_from_file(filename, model, bundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& _3MF_Importer::get_errors() const
|
const std::vector<std::string>& _3MF_Importer::get_errors() const
|
||||||
@ -364,7 +370,7 @@ namespace Slic3r {
|
|||||||
XML_StopParser(m_xml_parser, false);
|
XML_StopParser(m_xml_parser, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Importer::_load_model_from_file_miniz(const std::string& filename, Model& model)
|
bool _3MF_Importer::_load_model_from_file(const std::string& filename, Model& model, PresetBundle& bundle)
|
||||||
{
|
{
|
||||||
mz_zip_archive archive;
|
mz_zip_archive archive;
|
||||||
mz_zip_zero_struct(&archive);
|
mz_zip_zero_struct(&archive);
|
||||||
@ -384,21 +390,28 @@ namespace Slic3r {
|
|||||||
if (mz_zip_reader_file_stat(&archive, i, &stat))
|
if (mz_zip_reader_file_stat(&archive, i, &stat))
|
||||||
{
|
{
|
||||||
std::string name(stat.m_filename);
|
std::string name(stat.m_filename);
|
||||||
std::transform(name.begin(), name.end(), name.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); });
|
|
||||||
std::replace(name.begin(), name.end(), '\\', '/');
|
std::replace(name.begin(), name.end(), '\\', '/');
|
||||||
|
|
||||||
std::string lc_model_folder(MODEL_FOLDER);
|
if (boost::algorithm::istarts_with(name, MODEL_FOLDER) && boost::algorithm::iends_with(name, MODEL_EXTENSION))
|
||||||
std::transform(lc_model_folder.begin(), lc_model_folder.end(), lc_model_folder.begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); });
|
|
||||||
|
|
||||||
if ((name.find(lc_model_folder) == 0) && (name.rfind(MODEL_EXTENSION) == name.length() - MODEL_EXTENSION.length()))
|
|
||||||
{
|
{
|
||||||
if (!_extract_model_from_archive_miniz(archive, stat))
|
// valid model name -> extract model
|
||||||
|
if (!_extract_model_from_archive(archive, stat))
|
||||||
{
|
{
|
||||||
mz_zip_reader_end(&archive);
|
mz_zip_reader_end(&archive);
|
||||||
m_errors.push_back("Archive does not contain a valid model");
|
m_errors.push_back("Archive does not contain a valid model");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (boost::algorithm::iequals(name, CONFIG_FILE))
|
||||||
|
{
|
||||||
|
// extract slic3r config file
|
||||||
|
if (!_extract_config_from_archive(archive, stat, bundle, filename))
|
||||||
|
{
|
||||||
|
mz_zip_reader_end(&archive);
|
||||||
|
m_errors.push_back("Archive does not contain a valid config");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +419,7 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Importer::_extract_model_from_archive_miniz(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
bool _3MF_Importer::_extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
||||||
{
|
{
|
||||||
_destroy_xml_parser();
|
_destroy_xml_parser();
|
||||||
|
|
||||||
@ -430,7 +443,7 @@ namespace Slic3r {
|
|||||||
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0);
|
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, parser_buffer, (size_t)stat.m_uncomp_size, 0);
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
{
|
{
|
||||||
m_errors.push_back("Error while reading data to buffer");
|
m_errors.push_back("Error while reading model data to buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,6 +458,25 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _3MF_Importer::_extract_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, PresetBundle& bundle, const std::string& archive_filename)
|
||||||
|
{
|
||||||
|
if (stat.m_uncomp_size > 0)
|
||||||
|
{
|
||||||
|
std::vector<char> buffer((size_t)stat.m_uncomp_size + 1, 0);
|
||||||
|
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
|
||||||
|
if (res == 0)
|
||||||
|
{
|
||||||
|
m_errors.push_back("Error while reading config data to buffer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.back() = '\0';
|
||||||
|
bundle.load_config_string(buffer.data(), archive_filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void _3MF_Importer::_handle_start_xml_element(const char* name, const char** attributes)
|
void _3MF_Importer::_handle_start_xml_element(const char* name, const char** attributes)
|
||||||
{
|
{
|
||||||
if (m_xml_parser == nullptr)
|
if (m_xml_parser == nullptr)
|
||||||
@ -994,18 +1026,19 @@ namespace Slic3r {
|
|||||||
std::vector<std::string> m_errors;
|
std::vector<std::string> m_errors;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool save_model_to_file(const std::string& filename, Model& model);
|
bool save_model_to_file(const std::string& filename, Model& model, const Print& print);
|
||||||
|
|
||||||
const std::vector<std::string>& get_errors() const;
|
const std::vector<std::string>& get_errors() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _save_model_to_file_miniz(const std::string& filename, Model& model);
|
bool _save_model_to_file(const std::string& filename, Model& model, const Print& print);
|
||||||
bool _add_content_types_file_to_archive_miniz(mz_zip_archive& archive);
|
bool _add_content_types_file_to_archive(mz_zip_archive& archive);
|
||||||
bool _add_relationships_file_to_archive_miniz(mz_zip_archive& archive);
|
bool _add_relationships_file_to_archive(mz_zip_archive& archive);
|
||||||
bool _add_model_file_to_archive_miniz(mz_zip_archive& archive, Model& model);
|
bool _add_model_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items);
|
bool _add_object_to_model_stream(std::stringstream& stream, unsigned int& object_id, ModelObject& object, BuildItemsList& build_items);
|
||||||
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object);
|
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object);
|
||||||
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
||||||
|
bool _add_config_file_to_archive(mz_zip_archive& archive, const Print& print);
|
||||||
};
|
};
|
||||||
|
|
||||||
_3MF_Exporter::BuildItem::BuildItem(unsigned int id, const Matrix4x4& matrix)
|
_3MF_Exporter::BuildItem::BuildItem(unsigned int id, const Matrix4x4& matrix)
|
||||||
@ -1014,9 +1047,9 @@ namespace Slic3r {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model)
|
bool _3MF_Exporter::save_model_to_file(const std::string& filename, Model& model, const Print& print)
|
||||||
{
|
{
|
||||||
return _save_model_to_file_miniz(filename, model);
|
return _save_model_to_file(filename, model, print);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& _3MF_Exporter::get_errors() const
|
const std::vector<std::string>& _3MF_Exporter::get_errors() const
|
||||||
@ -1024,7 +1057,7 @@ namespace Slic3r {
|
|||||||
return m_errors;
|
return m_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_save_model_to_file_miniz(const std::string& filename, Model& model)
|
bool _3MF_Exporter::_save_model_to_file(const std::string& filename, Model& model, const Print& print)
|
||||||
{
|
{
|
||||||
mz_zip_archive archive;
|
mz_zip_archive archive;
|
||||||
mz_zip_zero_struct(&archive);
|
mz_zip_zero_struct(&archive);
|
||||||
@ -1037,7 +1070,7 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adds content types file
|
// adds content types file
|
||||||
if (!_add_content_types_file_to_archive_miniz(archive))
|
if (!_add_content_types_file_to_archive(archive))
|
||||||
{
|
{
|
||||||
mz_zip_writer_end(&archive);
|
mz_zip_writer_end(&archive);
|
||||||
boost::filesystem::remove(filename);
|
boost::filesystem::remove(filename);
|
||||||
@ -1045,7 +1078,7 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adds relationships file
|
// adds relationships file
|
||||||
if (!_add_relationships_file_to_archive_miniz(archive))
|
if (!_add_relationships_file_to_archive(archive))
|
||||||
{
|
{
|
||||||
mz_zip_writer_end(&archive);
|
mz_zip_writer_end(&archive);
|
||||||
boost::filesystem::remove(filename);
|
boost::filesystem::remove(filename);
|
||||||
@ -1053,7 +1086,15 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adds model file
|
// adds model file
|
||||||
if (!_add_model_file_to_archive_miniz(archive, model))
|
if (!_add_model_file_to_archive(archive, model))
|
||||||
|
{
|
||||||
|
mz_zip_writer_end(&archive);
|
||||||
|
boost::filesystem::remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// adds slic3r config file
|
||||||
|
if (!_add_config_file_to_archive(archive, print))
|
||||||
{
|
{
|
||||||
mz_zip_writer_end(&archive);
|
mz_zip_writer_end(&archive);
|
||||||
boost::filesystem::remove(filename);
|
boost::filesystem::remove(filename);
|
||||||
@ -1073,7 +1114,7 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_add_content_types_file_to_archive_miniz(mz_zip_archive& archive)
|
bool _3MF_Exporter::_add_content_types_file_to_archive(mz_zip_archive& archive)
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
@ -1093,7 +1134,7 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_add_relationships_file_to_archive_miniz(mz_zip_archive& archive)
|
bool _3MF_Exporter::_add_relationships_file_to_archive(mz_zip_archive& archive)
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
@ -1112,7 +1153,7 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_add_model_file_to_archive_miniz(mz_zip_archive& archive, Model& model)
|
bool _3MF_Exporter::_add_model_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||||
{
|
{
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||||
@ -1298,13 +1339,30 @@ namespace Slic3r {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load_3mf(const char* path, Model* model)
|
bool _3MF_Exporter::_add_config_file_to_archive(mz_zip_archive& archive, const Print& print)
|
||||||
{
|
{
|
||||||
if ((path == nullptr) || (model == nullptr))
|
char buffer[1024];
|
||||||
|
sprintf(buffer, "; %s\n\n", header_slic3r_generated().c_str());
|
||||||
|
std::string out = buffer;
|
||||||
|
|
||||||
|
GCode::append_full_config(print, out);
|
||||||
|
|
||||||
|
if (!mz_zip_writer_add_mem(&archive, CONFIG_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
|
||||||
|
{
|
||||||
|
m_errors.push_back("Unable to add config file to archive");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool load_3mf(const char* path, PresetBundle* bundle, Model* model)
|
||||||
|
{
|
||||||
|
if ((path == nullptr) || (bundle == nullptr) || (model == nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_3MF_Importer importer;
|
_3MF_Importer importer;
|
||||||
bool res = importer.load_model_from_file(path, *model);
|
bool res = importer.load_model_from_file(path, *model, *bundle);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
const std::vector<std::string>& errors = importer.get_errors();
|
const std::vector<std::string>& errors = importer.get_errors();
|
||||||
@ -1312,13 +1370,13 @@ namespace Slic3r {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool store_3mf(const char* path, Model* model)
|
bool store_3mf(const char* path, Model* model, Print* print)
|
||||||
{
|
{
|
||||||
if ((path == nullptr) || (model == nullptr))
|
if ((path == nullptr) || (model == nullptr) || (print == nullptr))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_3MF_Exporter exporter;
|
_3MF_Exporter exporter;
|
||||||
bool res = exporter.save_model_to_file(path, *model);
|
bool res = exporter.save_model_to_file(path, *model, *print);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
const std::vector<std::string>& errors = exporter.get_errors();
|
const std::vector<std::string>& errors = exporter.get_errors();
|
||||||
|
@ -4,13 +4,16 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
|
class Print;
|
||||||
|
class PresetBundle;
|
||||||
|
|
||||||
// Load a 3mf file into the given model.
|
// Load the content of a 3mf file into the given model and preset bundle.
|
||||||
extern bool load_3mf(const char* path, Model* model);
|
extern bool load_3mf(const char* path, PresetBundle* bundle, Model* model);
|
||||||
|
|
||||||
// Save the given model into a 3mf file.
|
// Save the given model and the config data contained in the given Print into a 3mf file.
|
||||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||||
extern bool store_3mf(const char* path, Model* model);
|
extern bool store_3mf(const char* path, Model* model, Print* print);
|
||||||
|
|
||||||
}; // namespace Slic3r
|
}; // namespace Slic3r
|
||||||
|
|
||||||
#endif /* slic3r_Format_3mf_hpp_ */
|
#endif /* slic3r_Format_3mf_hpp_ */
|
||||||
|
@ -802,13 +802,10 @@ void GCode::_do_export(Print &print, FILE *file)
|
|||||||
// Append full config.
|
// Append full config.
|
||||||
_write(file, "\n");
|
_write(file, "\n");
|
||||||
{
|
{
|
||||||
StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config };
|
std::string full_config = "";
|
||||||
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++ i) {
|
append_full_config(print, full_config);
|
||||||
StaticPrintConfig *cfg = configs[i];
|
if (!full_config.empty())
|
||||||
for (const std::string &key : cfg->keys())
|
_write(file, full_config);
|
||||||
if (key != "compatible_printers")
|
|
||||||
_write_format(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1372,6 +1369,24 @@ void GCode::apply_print_config(const PrintConfig &print_config)
|
|||||||
m_config.apply(print_config);
|
m_config.apply(print_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCode::append_full_config(const Print& print, std::string& str)
|
||||||
|
{
|
||||||
|
char buff[1024];
|
||||||
|
|
||||||
|
const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config };
|
||||||
|
for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) {
|
||||||
|
const StaticPrintConfig *cfg = configs[i];
|
||||||
|
for (const std::string &key : cfg->keys())
|
||||||
|
{
|
||||||
|
if (key != "compatible_printers")
|
||||||
|
{
|
||||||
|
sprintf(buff, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str());
|
||||||
|
str += buff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||||
{
|
{
|
||||||
m_writer.set_extruders(extruder_ids);
|
m_writer.set_extruders(extruder_ids);
|
||||||
|
@ -155,6 +155,9 @@ public:
|
|||||||
void set_layer_count(unsigned int value) { m_layer_count = value; }
|
void set_layer_count(unsigned int value) { m_layer_count = value; }
|
||||||
void apply_print_config(const PrintConfig &print_config);
|
void apply_print_config(const PrintConfig &print_config);
|
||||||
|
|
||||||
|
// append full config to the given string
|
||||||
|
static void append_full_config(const Print& print, std::string& str);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _do_export(Print &print, FILE *file);
|
void _do_export(Print &print, FILE *file);
|
||||||
|
|
||||||
|
@ -54,10 +54,8 @@ Model Model::read_from_file(const std::string &input_file, bool add_default_inst
|
|||||||
else if (boost::algorithm::iends_with(input_file, ".prusa"))
|
else if (boost::algorithm::iends_with(input_file, ".prusa"))
|
||||||
result = load_prus(input_file.c_str(), &model);
|
result = load_prus(input_file.c_str(), &model);
|
||||||
#endif /* SLIC3R_PRUS */
|
#endif /* SLIC3R_PRUS */
|
||||||
else if (boost::algorithm::iends_with(input_file, ".3mf"))
|
|
||||||
result = load_3mf(input_file.c_str(), &model);
|
|
||||||
else
|
else
|
||||||
throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml), .3mf or .prusa extension.");
|
throw std::runtime_error("Unknown file format. Input file must have .stl, .obj, .amf(.xml) or .prusa extension.");
|
||||||
|
|
||||||
if (! result)
|
if (! result)
|
||||||
throw std::runtime_error("Loading of a model file failed.");
|
throw std::runtime_error("Loading of a model file failed.");
|
||||||
@ -74,6 +72,31 @@ Model Model::read_from_file(const std::string &input_file, bool add_default_inst
|
|||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model Model::read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances)
|
||||||
|
{
|
||||||
|
Model model;
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
if (boost::algorithm::iends_with(input_file, ".3mf"))
|
||||||
|
result = load_3mf(input_file.c_str(), bundle, &model);
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Unknown file format. Input file must have .3mf extension.");
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
throw std::runtime_error("Loading of a model file failed.");
|
||||||
|
|
||||||
|
if (model.objects.empty())
|
||||||
|
throw std::runtime_error("The supplied file couldn't be read because it's empty");
|
||||||
|
|
||||||
|
for (ModelObject *o : model.objects)
|
||||||
|
o->input_file = input_file;
|
||||||
|
|
||||||
|
if (add_default_instances)
|
||||||
|
model.add_default_instances();
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
ModelObject* Model::add_object()
|
ModelObject* Model::add_object()
|
||||||
{
|
{
|
||||||
this->objects.emplace_back(new ModelObject(this));
|
this->objects.emplace_back(new ModelObject(this));
|
||||||
|
@ -19,6 +19,7 @@ class ModelInstance;
|
|||||||
class ModelMaterial;
|
class ModelMaterial;
|
||||||
class ModelObject;
|
class ModelObject;
|
||||||
class ModelVolume;
|
class ModelVolume;
|
||||||
|
class PresetBundle;
|
||||||
|
|
||||||
typedef std::string t_model_material_id;
|
typedef std::string t_model_material_id;
|
||||||
typedef std::string t_model_material_attribute;
|
typedef std::string t_model_material_attribute;
|
||||||
@ -239,6 +240,7 @@ public:
|
|||||||
~Model() { this->clear_objects(); this->clear_materials(); }
|
~Model() { this->clear_objects(); this->clear_materials(); }
|
||||||
|
|
||||||
static Model read_from_file(const std::string &input_file, bool add_default_instances = true);
|
static Model read_from_file(const std::string &input_file, bool add_default_instances = true);
|
||||||
|
static Model read_from_archive(const std::string &input_file, PresetBundle* bundle, bool add_default_instances = true);
|
||||||
|
|
||||||
ModelObject* add_object();
|
ModelObject* add_object();
|
||||||
ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh);
|
ModelObject* add_object(const char *name, const char *path, const TriangleMesh &mesh);
|
||||||
|
@ -280,8 +280,8 @@ void PresetBundle::load_config_file(const std::string &path)
|
|||||||
if (boost::iends_with(path, ".gcode") || boost::iends_with(path, ".g")) {
|
if (boost::iends_with(path, ".gcode") || boost::iends_with(path, ".g")) {
|
||||||
DynamicPrintConfig config;
|
DynamicPrintConfig config;
|
||||||
config.apply(FullPrintConfig::defaults());
|
config.apply(FullPrintConfig::defaults());
|
||||||
config.load_from_gcode(path);
|
config.load_from_gcode_file(path);
|
||||||
Preset::normalize(config);
|
Preset::normalize(config);
|
||||||
load_config_file_config(path, true, std::move(config));
|
load_config_file_config(path, true, std::move(config));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -320,6 +320,18 @@ void PresetBundle::load_config_file(const std::string &path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PresetBundle::load_config_string(const char* str, const char* source_filename)
|
||||||
|
{
|
||||||
|
if (str != nullptr)
|
||||||
|
{
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
config.apply(FullPrintConfig::defaults());
|
||||||
|
config.load_from_gcode_string(str);
|
||||||
|
Preset::normalize(config);
|
||||||
|
load_config_file_config((source_filename == nullptr) ? "" : source_filename, true, std::move(config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load a config file from a boost property_tree. This is a private method called from load_config_file.
|
// Load a config file from a boost property_tree. This is a private method called from load_config_file.
|
||||||
void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config)
|
void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config)
|
||||||
{
|
{
|
||||||
|
@ -55,6 +55,11 @@ public:
|
|||||||
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
|
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
|
||||||
void load_config_file(const std::string &path);
|
void load_config_file(const std::string &path);
|
||||||
|
|
||||||
|
// Load an external config source containing the print, filament and printer presets.
|
||||||
|
// The given string must contain the full set of parameters (same as those exported to gcode).
|
||||||
|
// If the string is parsed successfully, its print / filament / printer profiles will be activated.
|
||||||
|
void load_config_string(const char* str, const char* source_filename = nullptr);
|
||||||
|
|
||||||
// Load a config bundle file, into presets and store the loaded presets into separate files
|
// Load a config bundle file, into presets and store the loaded presets into separate files
|
||||||
// of the local configuration directory.
|
// of the local configuration directory.
|
||||||
// Load settings into the provided settings instance.
|
// Load settings into the provided settings instance.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
%{
|
%{
|
||||||
#include <xsinit.h>
|
#include <xsinit.h>
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "libslic3r/Slicing.hpp"
|
#include "libslic3r/Slicing.hpp"
|
||||||
#include "libslic3r/Format/AMF.hpp"
|
#include "libslic3r/Format/AMF.hpp"
|
||||||
@ -10,6 +11,7 @@
|
|||||||
#include "libslic3r/Format/OBJ.hpp"
|
#include "libslic3r/Format/OBJ.hpp"
|
||||||
#include "libslic3r/Format/PRUS.hpp"
|
#include "libslic3r/Format/PRUS.hpp"
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
|
#include "slic3r/GUI/PresetBundle.hpp"
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%name{Slic3r::Model} class Model {
|
%name{Slic3r::Model} class Model {
|
||||||
@ -25,6 +27,15 @@
|
|||||||
}
|
}
|
||||||
%};
|
%};
|
||||||
|
|
||||||
|
%name{read_from_archive} Model(std::string input_file, PresetBundle* bundle, bool add_default_instances = true)
|
||||||
|
%code%{
|
||||||
|
try {
|
||||||
|
RETVAL = new Model(Model::read_from_archive(input_file, bundle, add_default_instances));
|
||||||
|
} catch (std::exception& e) {
|
||||||
|
croak("Error while opening %s: %s\n", input_file.c_str(), e.what());
|
||||||
|
}
|
||||||
|
%};
|
||||||
|
|
||||||
Clone<Model> clone()
|
Clone<Model> clone()
|
||||||
%code%{ RETVAL = THIS; %};
|
%code%{ RETVAL = THIS; %};
|
||||||
|
|
||||||
@ -92,8 +103,8 @@
|
|||||||
%code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %};
|
%code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %};
|
||||||
bool store_amf(char *path)
|
bool store_amf(char *path)
|
||||||
%code%{ RETVAL = Slic3r::store_amf(path, THIS); %};
|
%code%{ RETVAL = Slic3r::store_amf(path, THIS); %};
|
||||||
bool store_3mf(char *path)
|
bool store_3mf(char *path, Print* print)
|
||||||
%code%{ RETVAL = Slic3r::store_3mf(path, THIS); %};
|
%code%{ RETVAL = Slic3r::store_3mf(path, THIS, print); %};
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
@ -139,12 +150,13 @@ load_amf(CLASS, path)
|
|||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
Model*
|
Model*
|
||||||
load_3mf(CLASS, path)
|
load_3mf(CLASS, bundle, path)
|
||||||
char* CLASS;
|
char* CLASS;
|
||||||
|
PresetBundle* bundle;
|
||||||
char* path;
|
char* path;
|
||||||
CODE:
|
CODE:
|
||||||
RETVAL = new Model();
|
RETVAL = new Model();
|
||||||
if (! load_3mf(path, RETVAL)) {
|
if (! load_3mf(path, bundle, RETVAL)) {
|
||||||
delete RETVAL;
|
delete RETVAL;
|
||||||
RETVAL = NULL;
|
RETVAL = NULL;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user