Remove AMF export (functionality not available from GUI since 2.4.0)

This commit is contained in:
Lukas Matena 2024-10-16 12:20:22 +02:00
parent ccdfa73851
commit ccc7c350a0
5 changed files with 2 additions and 293 deletions

View File

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

View File

@ -8,7 +8,6 @@ namespace Slic3r {
namespace IO {
enum ExportFormat : int {
AMF,
OBJ,
STL,
// SVG,

View File

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

View File

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

View File

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