mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-31 04:01:59 +08:00
Remove AMF export (functionality not available from GUI since 2.4.0)
This commit is contained in:
parent
ccdfa73851
commit
ccc7c350a0
@ -606,9 +606,6 @@ int CLI::run(int argc, char **argv)
|
||||
model.add_default_instances();
|
||||
if (! this->export_models(IO::OBJ))
|
||||
return 1;
|
||||
} else if (opt_key == "export_amf") {
|
||||
if (! this->export_models(IO::AMF))
|
||||
return 1;
|
||||
} else if (opt_key == "export_3mf") {
|
||||
if (! this->export_models(IO::TMF))
|
||||
return 1;
|
||||
@ -955,7 +952,6 @@ bool CLI::export_models(IO::ExportFormat format)
|
||||
const std::string path = this->output_filepath(model, format);
|
||||
bool success = false;
|
||||
switch (format) {
|
||||
case IO::AMF: success = Slic3r::store_amf(path.c_str(), &model, nullptr, false); break;
|
||||
case IO::OBJ: success = Slic3r::store_obj(path.c_str(), &model); break;
|
||||
case IO::STL: success = Slic3r::store_stl(path.c_str(), &model, true); break;
|
||||
case IO::TMF: success = Slic3r::store_3mf(path.c_str(), &model, nullptr, false); break;
|
||||
@ -975,7 +971,6 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co
|
||||
{
|
||||
std::string ext;
|
||||
switch (format) {
|
||||
case IO::AMF: ext = ".zip.amf"; break;
|
||||
case IO::OBJ: ext = ".obj"; break;
|
||||
case IO::STL: ext = ".stl"; break;
|
||||
case IO::TMF: ext = ".3mf"; break;
|
||||
|
@ -8,7 +8,6 @@ namespace Slic3r {
|
||||
|
||||
namespace IO {
|
||||
enum ExportFormat : int {
|
||||
AMF,
|
||||
OBJ,
|
||||
STL,
|
||||
// SVG,
|
||||
|
@ -1101,283 +1101,4 @@ bool load_amf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionCo
|
||||
return false;
|
||||
}
|
||||
|
||||
bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources)
|
||||
{
|
||||
if ((path == nullptr) || (model == nullptr))
|
||||
return false;
|
||||
|
||||
// forces ".zip.amf" extension
|
||||
std::string export_path = path;
|
||||
if (!boost::iends_with(export_path, ".zip.amf"))
|
||||
export_path = boost::filesystem::path(export_path).replace_extension(".zip.amf").string();
|
||||
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
|
||||
if (!open_zip_writer(&archive, export_path)) return false;
|
||||
|
||||
std::stringstream stream;
|
||||
// https://en.cppreference.com/w/cpp/types/numeric_limits/max_digits10
|
||||
// Conversion of a floating-point value to text and back is exact as long as at least max_digits10 were used (9 for float, 17 for double).
|
||||
// It is guaranteed to produce the same floating-point value, even though the intermediate text representation is not exact.
|
||||
// The default value of std::stream precision is 6 digits only!
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
|
||||
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
||||
stream << "<amf unit=\"millimeter\">\n";
|
||||
stream << "<metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>\n";
|
||||
stream << "<metadata type=\"" << SLIC3RPE_AMF_VERSION << "\">" << VERSION_AMF << "</metadata>\n";
|
||||
|
||||
if (config != nullptr)
|
||||
{
|
||||
std::string str_config = "\n";
|
||||
for (const std::string &key : config->keys())
|
||||
if (key != "compatible_printers")
|
||||
str_config += "; " + key + " = " + config->opt_serialize(key) + "\n";
|
||||
stream << "<metadata type=\"" << SLIC3R_CONFIG_TYPE << "\">" << xml_escape(str_config) << "</metadata>\n";
|
||||
}
|
||||
|
||||
for (const auto &material : model->materials) {
|
||||
if (material.first.empty())
|
||||
continue;
|
||||
// note that material-id must never be 0 since it's reserved by the AMF spec
|
||||
stream << " <material id=\"" << material.first << "\">\n";
|
||||
for (const auto &attr : material.second->attributes)
|
||||
stream << " <metadata type=\"" << attr.first << "\">" << attr.second << "</metadata>\n";
|
||||
for (const std::string &key : material.second->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << material.second->config.opt_serialize(key) << "</metadata>\n";
|
||||
stream << " </material>\n";
|
||||
}
|
||||
std::string instances;
|
||||
for (size_t object_id = 0; object_id < model->objects.size(); ++ object_id) {
|
||||
ModelObject *object = model->objects[object_id];
|
||||
stream << " <object id=\"" << object_id << "\">\n";
|
||||
for (const std::string &key : object->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << object->config.opt_serialize(key) << "</metadata>\n";
|
||||
if (!object->name.empty())
|
||||
stream << " <metadata type=\"name\">" << xml_escape(object->name) << "</metadata>\n";
|
||||
const std::vector<double> &layer_height_profile = object->layer_height_profile.get();
|
||||
if (layer_height_profile.size() >= 4 && (layer_height_profile.size() % 2) == 0) {
|
||||
// Store the layer height profile as a single semicolon separated list.
|
||||
stream << " <metadata type=\"slic3r.layer_height_profile\">";
|
||||
stream << layer_height_profile.front();
|
||||
for (size_t i = 1; i < layer_height_profile.size(); ++i)
|
||||
stream << ";" << layer_height_profile[i];
|
||||
stream << "\n </metadata>\n";
|
||||
}
|
||||
|
||||
// Export layer height ranges including the layer range specific config overrides.
|
||||
const t_layer_config_ranges& config_ranges = object->layer_config_ranges;
|
||||
if (!config_ranges.empty())
|
||||
{
|
||||
// Store the layer config range as a single semicolon separated list.
|
||||
stream << " <layer_config_ranges>\n";
|
||||
size_t layer_counter = 0;
|
||||
for (const auto &range : config_ranges) {
|
||||
stream << " <range id=\"" << layer_counter << "\">\n";
|
||||
|
||||
stream << " <metadata type=\"slic3r.layer_height_range\">";
|
||||
stream << range.first.first << ";" << range.first.second << "</metadata>\n";
|
||||
|
||||
for (const std::string& key : range.second.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << range.second.opt_serialize(key) << "</metadata>\n";
|
||||
|
||||
stream << " </range>\n";
|
||||
layer_counter++;
|
||||
}
|
||||
|
||||
stream << " </layer_config_ranges>\n";
|
||||
}
|
||||
|
||||
|
||||
const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
|
||||
if (!sla_support_points.empty()) {
|
||||
// Store the SLA supports as a single semicolon separated list.
|
||||
stream << " <metadata type=\"slic3r.sla_support_points\">";
|
||||
for (size_t i = 0; i < sla_support_points.size(); ++i) {
|
||||
if (i != 0)
|
||||
stream << ";";
|
||||
stream << sla_support_points[i].pos(0) << ";" << sla_support_points[i].pos(1) << ";" << sla_support_points[i].pos(2) << ";" << sla_support_points[i].head_front_radius << ";" << sla_support_points[i].is_new_island;
|
||||
}
|
||||
stream << "\n </metadata>\n";
|
||||
}
|
||||
|
||||
stream << " <mesh>\n";
|
||||
stream << " <vertices>\n";
|
||||
std::vector<int> vertices_offsets;
|
||||
int num_vertices = 0;
|
||||
for (ModelVolume *volume : object->volumes) {
|
||||
vertices_offsets.push_back(num_vertices);
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
const Transform3d& matrix = volume->get_matrix();
|
||||
for (size_t i = 0; i < its.vertices.size(); ++i) {
|
||||
stream << " <vertex>\n";
|
||||
stream << " <coordinates>\n";
|
||||
Vec3f v = (matrix * its.vertices[i].cast<double>()).cast<float>();
|
||||
stream << " <x>" << v(0) << "</x>\n";
|
||||
stream << " <y>" << v(1) << "</y>\n";
|
||||
stream << " <z>" << v(2) << "</z>\n";
|
||||
stream << " </coordinates>\n";
|
||||
stream << " </vertex>\n";
|
||||
}
|
||||
num_vertices += (int)its.vertices.size();
|
||||
}
|
||||
stream << " </vertices>\n";
|
||||
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
|
||||
ModelVolume *volume = object->volumes[i_volume];
|
||||
int vertices_offset = vertices_offsets[i_volume];
|
||||
if (volume->material_id().empty())
|
||||
stream << " <volume>\n";
|
||||
else
|
||||
stream << " <volume materialid=\"" << volume->material_id() << "\">\n";
|
||||
for (const std::string &key : volume->config.keys())
|
||||
stream << " <metadata type=\"slic3r." << key << "\">" << volume->config.opt_serialize(key) << "</metadata>\n";
|
||||
if (!volume->name.empty())
|
||||
stream << " <metadata type=\"name\">" << xml_escape(volume->name) << "</metadata>\n";
|
||||
if (volume->is_modifier())
|
||||
stream << " <metadata type=\"slic3r.modifier\">1</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.volume_type\">" << ModelVolume::type_to_string(volume->type()) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.matrix\">";
|
||||
const Transform3d& matrix = volume->get_matrix() * volume->source.transform.get_matrix();
|
||||
stream << std::setprecision(std::numeric_limits<double>::max_digits10);
|
||||
for (int r = 0; r < 4; ++r) {
|
||||
for (int c = 0; c < 4; ++c) {
|
||||
stream << matrix(r, c);
|
||||
if (r != 3 || c != 3)
|
||||
stream << " ";
|
||||
}
|
||||
}
|
||||
stream << "</metadata>\n";
|
||||
if (!volume->source.input_file.empty()) {
|
||||
std::string input_file = xml_escape(fullpath_sources ? volume->source.input_file : boost::filesystem::path(volume->source.input_file).filename().string());
|
||||
stream << " <metadata type=\"slic3r.source_file\">" << input_file << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_object_id\">" << volume->source.object_idx << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_volume_id\">" << volume->source.volume_idx << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_offset_x\">" << volume->source.mesh_offset(0) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_offset_y\">" << volume->source.mesh_offset(1) << "</metadata>\n";
|
||||
stream << " <metadata type=\"slic3r.source_offset_z\">" << volume->source.mesh_offset(2) << "</metadata>\n";
|
||||
}
|
||||
assert(! volume->source.is_converted_from_inches || ! volume->source.is_converted_from_meters);
|
||||
if (volume->source.is_converted_from_inches)
|
||||
stream << " <metadata type=\"slic3r.source_in_inches\">1</metadata>\n";
|
||||
else if (volume->source.is_converted_from_meters)
|
||||
stream << " <metadata type=\"slic3r.source_in_meters\">1</metadata>\n";
|
||||
if (volume->source.is_from_builtin_objects)
|
||||
stream << " <metadata type=\"slic3r.source_is_builtin_volume\">1</metadata>\n";
|
||||
stream << std::setprecision(std::numeric_limits<float>::max_digits10);
|
||||
const indexed_triangle_set &its = volume->mesh().its;
|
||||
for (size_t i = 0; i < its.indices.size(); ++i) {
|
||||
stream << " <triangle>\n";
|
||||
for (int j = 0; j < 3; ++j)
|
||||
stream << " <v" << j + 1 << ">" << its.indices[i][j] + vertices_offset << "</v" << j + 1 << ">\n";
|
||||
stream << " </triangle>\n";
|
||||
}
|
||||
stream << " </volume>\n";
|
||||
}
|
||||
stream << " </mesh>\n";
|
||||
stream << " </object>\n";
|
||||
if (!object->instances.empty()) {
|
||||
for (ModelInstance *instance : object->instances) {
|
||||
std::stringstream buf;
|
||||
buf << " <instance objectid=\"" << object_id << "\">\n"
|
||||
<< " <deltax>" << instance->get_offset(X) << "</deltax>\n"
|
||||
<< " <deltay>" << instance->get_offset(Y) << "</deltay>\n"
|
||||
<< " <deltaz>" << instance->get_offset(Z) << "</deltaz>\n"
|
||||
<< " <rx>" << instance->get_rotation(X) << "</rx>\n"
|
||||
<< " <ry>" << instance->get_rotation(Y) << "</ry>\n"
|
||||
<< " <rz>" << instance->get_rotation(Z) << "</rz>\n"
|
||||
<< " <scalex>" << instance->get_scaling_factor(X) << "</scalex>\n"
|
||||
<< " <scaley>" << instance->get_scaling_factor(Y) << "</scaley>\n"
|
||||
<< " <scalez>" << instance->get_scaling_factor(Z) << "</scalez>\n"
|
||||
<< " <mirrorx>" << instance->get_mirror(X) << "</mirrorx>\n"
|
||||
<< " <mirrory>" << instance->get_mirror(Y) << "</mirrory>\n"
|
||||
<< " <mirrorz>" << instance->get_mirror(Z) << "</mirrorz>\n"
|
||||
<< " <printable>" << instance->printable << "</printable>\n"
|
||||
<< " </instance>\n";
|
||||
|
||||
//FIXME missing instance->scaling_factor
|
||||
instances.append(buf.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! instances.empty()) {
|
||||
stream << " <constellation id=\"1\">\n";
|
||||
stream << instances;
|
||||
stream << " </constellation>\n";
|
||||
}
|
||||
|
||||
if (!model->custom_gcode_per_print_z.gcodes.empty())
|
||||
{
|
||||
std::string out = "";
|
||||
pt::ptree tree;
|
||||
|
||||
pt::ptree& main_tree = tree.add("custom_gcodes_per_height", "");
|
||||
|
||||
for (const CustomGCode::Item& code : model->custom_gcode_per_print_z.gcodes)
|
||||
{
|
||||
pt::ptree& code_tree = main_tree.add("code", "");
|
||||
// store custom_gcode_per_print_z gcodes information
|
||||
code_tree.put("<xmlattr>.print_z" , code.print_z );
|
||||
code_tree.put("<xmlattr>.type" , static_cast<int>(code.type));
|
||||
code_tree.put("<xmlattr>.extruder" , code.extruder );
|
||||
code_tree.put("<xmlattr>.color" , code.color );
|
||||
code_tree.put("<xmlattr>.extra" , code.extra );
|
||||
|
||||
// add gcode field data for the old version of the PrusaSlicer
|
||||
std::string gcode = code.type == CustomGCode::ColorChange ? config->opt_string("color_change_gcode") :
|
||||
code.type == CustomGCode::PausePrint ? config->opt_string("pause_print_gcode") :
|
||||
code.type == CustomGCode::Template ? config->opt_string("template_custom_gcode") :
|
||||
code.type == CustomGCode::ToolChange ? "tool_change" : code.extra;
|
||||
code_tree.put("<xmlattr>.gcode" , gcode );
|
||||
}
|
||||
|
||||
pt::ptree& mode_tree = main_tree.add("mode", "");
|
||||
// store mode of a custom_gcode_per_print_z
|
||||
mode_tree.put("<xmlattr>.value",
|
||||
model->custom_gcode_per_print_z.mode == CustomGCode::Mode::SingleExtruder ? CustomGCode::SingleExtruderMode :
|
||||
model->custom_gcode_per_print_z.mode == CustomGCode::Mode::MultiAsSingle ?
|
||||
CustomGCode::MultiAsSingleMode : CustomGCode::MultiExtruderMode);
|
||||
|
||||
if (!tree.empty())
|
||||
{
|
||||
std::ostringstream oss;
|
||||
pt::write_xml(oss, tree);
|
||||
out = oss.str();
|
||||
|
||||
size_t del_header_pos = out.find("<custom_gcodes_per_height");
|
||||
if (del_header_pos != std::string::npos)
|
||||
out.erase(out.begin(), out.begin() + del_header_pos);
|
||||
|
||||
// Post processing("beautification") of the output string
|
||||
boost::replace_all(out, "><code", ">\n <code");
|
||||
boost::replace_all(out, "><mode", ">\n <mode");
|
||||
boost::replace_all(out, "><", ">\n<");
|
||||
|
||||
stream << out << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
stream << "</amf>\n";
|
||||
|
||||
std::string internal_amf_filename = boost::ireplace_last_copy(boost::filesystem::path(export_path).filename().string(), ".zip.amf", ".amf");
|
||||
std::string out = stream.str();
|
||||
|
||||
if (!mz_zip_writer_add_mem(&archive, internal_amf_filename.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
|
||||
{
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(export_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mz_zip_writer_finalize_archive(&archive))
|
||||
{
|
||||
close_zip_writer(&archive);
|
||||
boost::filesystem::remove(export_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
close_zip_writer(&archive);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
@ -17,9 +17,8 @@ class DynamicPrintConfig;
|
||||
// Load the content of an amf file into the given model and configuration.
|
||||
extern bool load_amf(const char* path, DynamicPrintConfig* config, ConfigSubstitutionContext* config_substitutions, Model* model, bool check_version);
|
||||
|
||||
// Save the given model and the config data into an amf file.
|
||||
// The model could be modified during the export process if meshes are not repaired or have no shared vertices
|
||||
extern bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config, bool fullpath_sources);
|
||||
// Function to save AMF has been removed in 2.9.0, we no longer support saving data in AMF format.
|
||||
// The option has been missing in the UI since 2.4.0 (except for CLI).
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -5521,11 +5521,6 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
def->tooltip = L("Export the model(s) as 3MF.");
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("export_amf", coBool);
|
||||
def->label = L("Export AMF");
|
||||
def->tooltip = L("Export the model(s) as AMF.");
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("export_stl", coBool);
|
||||
def->label = L("Export STL");
|
||||
def->tooltip = L("Export the model(s) as STL.");
|
||||
|
Loading…
x
Reference in New Issue
Block a user