Clean IO::AMF::write()

This commit is contained in:
Alessandro Ranellucci 2017-03-17 20:51:36 +01:00
parent 4c78e54a46
commit a6609682fc
2 changed files with 88 additions and 74 deletions

View File

@ -1,4 +1,6 @@
#include "../IO.hpp" #include "../IO.hpp"
#include <iostream>
#include <fstream>
#include <string.h> #include <string.h>
#include <map> #include <map>
#include <string> #include <string>
@ -495,109 +497,121 @@ AMF::read(std::string input_file, Model* model)
bool bool
AMF::write(Model& model, std::string output_file) AMF::write(Model& model, std::string output_file)
{ {
FILE *file = ::fopen(output_file.c_str(), "wb"); using namespace std;
if (file == NULL)
return false; ofstream file;
file.open(output_file, ios::out | ios::trunc);
fprintf(file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
fprintf(file, "<amf unit=\"millimeter\">\n"); file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl
fprintf(file, "<metadata type=\"cad\">Slic3r %s</metadata>\n", SLIC3R_VERSION); << "<amf unit=\"millimeter\">" << endl
<< "<metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>" << endl;
for (const auto &material : model.materials) { for (const auto &material : model.materials) {
if (material.first.empty()) if (material.first.empty())
continue; continue;
// note that material-id must never be 0 since it's reserved by the AMF spec // note that material-id must never be 0 since it's reserved by the AMF spec
fprintf(file, " <material id=\"%s\">\n", material.first.c_str()); file << " <material id=\"" << material.first << "\">" << endl;
for (const auto &attr : material.second->attributes) for (const auto &attr : material.second->attributes)
fprintf(file, " <metadata type=\"%s\">%s</metadata>\n", attr.first.c_str(), attr.second.c_str()); file << " <metadata type=\"" << attr.first << "\">" << attr.second << "</metadata>" << endl;
for (const std::string &key : material.second->config.keys()) for (const std::string &key : material.second->config.keys())
fprintf(file, " <metadata type=\"slic3r.%s\">%s</metadata>\n", key.c_str(), material.second->config.serialize(key).c_str()); file << " <metadata type=\"slic3r." << key << "\">"
fprintf(file, " </material>\n"); << material.second->config.serialize(key) << "</metadata>" << endl;
file << " </material>" << endl;
} }
std::string instances;
for (size_t object_id = 0; object_id < model.objects.size(); ++ object_id) { ostringstream instances;
for (size_t object_id = 0; object_id < model.objects.size(); ++object_id) {
ModelObject *object = model.objects[object_id]; ModelObject *object = model.objects[object_id];
fprintf(file, " <object id=\"%zu\">\n", object_id); file << " <object id=\"" << object_id << "\">" << endl;
for (const std::string &key : object->config.keys()) for (const std::string &key : object->config.keys())
fprintf(file, " <metadata type=\"slic3r.%s\">%s</metadata>\n", key.c_str(), object->config.serialize(key).c_str()); file << " <metadata type=\"slic3r." << key << "\">"
if (! object->name.empty()) << object->config.serialize(key) << "</metadata>" << endl;
fprintf(file, " <metadata type=\"name\">%s</metadata>\n", object->name.c_str());
if (!object->name.empty())
file << " <metadata type=\"name\">" << object->name << "</metadata>" << endl;
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges) //FIXME: Store the layer height ranges (ModelObject::layer_height_ranges)
fprintf(file, " <mesh>\n"); file << " <mesh>" << endl;
fprintf(file, " <vertices>\n"); file << " <vertices>" << endl;
std::vector<int> vertices_offsets;
int num_vertices = 0; std::vector<size_t> vertices_offsets;
size_t num_vertices = 0;
for (ModelVolume *volume : object->volumes) { for (ModelVolume *volume : object->volumes) {
volume->mesh.check_topology(); volume->mesh.require_shared_vertices();
vertices_offsets.push_back(num_vertices); vertices_offsets.push_back(num_vertices);
auto &stl = volume->mesh.stl; const auto &stl = volume->mesh.stl;
if (stl.v_shared == NULL) for (size_t i = 0; i < stl.stats.shared_vertices; ++i)
stl_generate_shared_vertices(&stl);
for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) {
// Subtract origin_translation in order to restore the coordinates of the parts // Subtract origin_translation in order to restore the coordinates of the parts
// before they were imported. Otherwise, when this AMF file is reimported parts // before they were imported. Otherwise, when this AMF file is reimported parts
// will be placed in the plater correctly, but we will have lost origin_translation // will be placed in the plater correctly, but we will have lost origin_translation
// thus any additional part added will not align with the others. // thus any additional part added will not align with the others.
// In order to do this we compensate for this translation in the instance placement // In order to do this we compensate for this translation in the instance placement
// below. // below.
fprintf(file, " <vertex>\n"); file << " <vertex>" << endl
fprintf(file, " <coordinates>\n"); << " <coordinates>" << endl
fprintf(file, " <x>%f</x>\n", stl.v_shared[i].x - object->origin_translation.x); << " <x>" << (stl.v_shared[i].x - object->origin_translation.x) << "</x>" << endl
fprintf(file, " <y>%f</y>\n", stl.v_shared[i].y - object->origin_translation.y); << " <y>" << (stl.v_shared[i].y - object->origin_translation.y) << "</y>" << endl
fprintf(file, " <z>%f</z>\n", stl.v_shared[i].z - object->origin_translation.z); << " <z>" << (stl.v_shared[i].z - object->origin_translation.z) << "</z>" << endl
fprintf(file, " </coordinates>\n"); << " </coordinates>" << endl
fprintf(file, " </vertex>\n"); << " </vertex>" << endl;
}
num_vertices += stl.stats.shared_vertices; num_vertices += stl.stats.shared_vertices;
} }
fprintf(file, " </vertices>\n"); file << " </vertices>" << endl;
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++ i_volume) {
for (size_t i_volume = 0; i_volume < object->volumes.size(); ++i_volume) {
ModelVolume *volume = object->volumes[i_volume]; ModelVolume *volume = object->volumes[i_volume];
int vertices_offset = vertices_offsets[i_volume]; int vertices_offset = vertices_offsets[i_volume];
if (volume->material_id().empty()) if (volume->material_id().empty())
fprintf(file, " <volume>\n"); file << " <volume>" << endl;
else else
fprintf(file, " <volume materialid=\"%s\">\n", volume->material_id().c_str()); file << " <volume materialid=\"" << volume->material_id() << "\">" << endl;
for (const std::string &key : volume->config.keys()) for (const std::string &key : volume->config.keys())
fprintf(file, " <metadata type=\"slic3r.%s\">%s</metadata>\n", key.c_str(), volume->config.serialize(key).c_str()); file << " <metadata type=\"slic3r." << key << "\">"
if (! volume->name.empty()) << volume->config.serialize(key) << "</metadata>" << endl;
fprintf(file, " <metadata type=\"name\">%s</metadata>\n", volume->name.c_str());
if (!volume->name.empty())
file << " <metadata type=\"name\">" << volume->name << "</metadata>" << endl;
if (volume->modifier) if (volume->modifier)
fprintf(file, " <metadata type=\"slic3r.modifier\">1</metadata>\n"); file << " <metadata type=\"slic3r.modifier\">1</metadata>" << endl;
for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++ i) {
fprintf(file, " <triangle>\n"); for (int i = 0; i < volume->mesh.stl.stats.number_of_facets; ++i) {
file << " <triangle>" << endl;
for (int j = 0; j < 3; ++ j) for (int j = 0; j < 3; ++ j)
fprintf(file, " <v%d>%d</v%d>\n", j+1, volume->mesh.stl.v_indices[i].vertex[j] + vertices_offset, j+1); file << " <v" << (j+1) << ">"
fprintf(file, " </triangle>\n"); << (volume->mesh.stl.v_indices[i].vertex[j] + vertices_offset)
<< "</v" << (j+1) << ">" << endl;
file << " </triangle>" << endl;
} }
fprintf(file, " </volume>\n"); file << " </volume>" << endl;
}
fprintf(file, " </mesh>\n");
fprintf(file, " </object>\n");
for (const ModelInstance* instance : object->instances) {
char buf[512];
sprintf(buf,
" <instance objectid=\"%zu\">\n"
" <deltax>%lf</deltax>\n"
" <deltay>%lf</deltay>\n"
" <rz>%lf</rz>\n"
" <scale>%lf</scale>\n"
" </instance>\n",
object_id,
instance->offset.x + object->origin_translation.x,
instance->offset.y + object->origin_translation.y,
instance->rotation,
instance->scaling_factor);
instances.append(buf);
} }
file << " </mesh>" << endl;
file << " </object>" << endl;
for (const ModelInstance* instance : object->instances)
instances
<< " <instance objectid=\"" << object_id << "\">" << endl
<< " <deltax>" << instance->offset.x + object->origin_translation.x << "</deltax>" << endl
<< " <deltay>" << instance->offset.y + object->origin_translation.y << "</deltay>" << endl
<< " <rz>%" << instance->rotation << "</rz>" << endl
<< " <scale>" << instance->scaling_factor << "</scale>" << endl
<< " </instance>" << endl;
} }
if (! instances.empty()) {
fprintf(file, " <constellation id=\"1\">\n"); std::string instances_str = instances.str();
fwrite(instances.data(), instances.size(), 1, file); if (!instances_str.empty())
fprintf(file, " </constellation>\n"); file << " <constellation id=\"1\">" << endl
} << instances_str
fprintf(file, "</amf>\n"); << " </constellation>" << endl;
fclose(file);
file << "</amf>" << endl;
file.close();
return true; return true;
} }

View File

@ -58,6 +58,7 @@ class TriangleMesh
bool needed_repair() const; bool needed_repair() const;
size_t facets_count() const; size_t facets_count() const;
void extrude_tin(float offset); void extrude_tin(float offset);
void require_shared_vertices();
static TriangleMesh make_cube(double x, double y, double z); static TriangleMesh make_cube(double x, double y, double z);
static TriangleMesh make_cylinder(double r, double h, double fa=(2*PI/360)); static TriangleMesh make_cylinder(double r, double h, double fa=(2*PI/360));
@ -67,7 +68,6 @@ class TriangleMesh
bool repaired; bool repaired;
private: private:
void require_shared_vertices();
friend class TriangleMeshSlicer<X>; friend class TriangleMeshSlicer<X>;
friend class TriangleMeshSlicer<Y>; friend class TriangleMeshSlicer<Y>;
friend class TriangleMeshSlicer<Z>; friend class TriangleMeshSlicer<Z>;