Closed alranel closed 6 years ago
@alexrj @lordofhyphens I am working on getting the transformation matrix from scale, X and Y translation and z-axis rotation attributes found in ModelInstance as 3MF item element which represents ModelInstance is declared like this:
<item objectid="4" transform="5.96045e-008 0.999997 0 -0.999997 -9.40395e-007 0 0 0 1 126.999 -126.998 0.00197"/>
Yeah using a 3rd program that should be competently made will give you a useful crosscheck.
@alexrj @lordofhyphens I have opened 2 exported 3MF files on Microsoft 3D Builder. Here are some screenshots
Commit : Fix ContentTypes.xml file causing 3D Builder not to load the file. xmlns schema link added to < Types > element. Commit : Initialize partnumber to the ModelObject constructors. Commit : Remove the first extension from the exported file name. when I export to 3mf the resulted file name was m.obj.3mf. @lordofhyphens is there a reason for keeping this as 3D builder cannot load file with such name.
There is no reason to add an extra "obj" in the file name that I am aware of.
@Samir55, I really appreciate your dev log. Very good documentation of your progress. Do you have any open questions?
@alexrj Thank you :)
Write Slic3r custom configs data to ModelMaterials, ModelObject, ModelVolumes. I have done this according to this structure:
<slic3r:metadata type="version">1.3.0-dev</slic3r:metadata>
"<slic3r:material mid=\"" + to_string(material_index)
+ "\" type=\"" + key + "\">"
+ material.second->config.serialize(key)
+ "</slic3r:material>\n"
where "mid" is the index of the basematerial it points to from the
// Write Slic3r custom configs.
loop over key in object->config.keys :
Write -> ("<slic3r:object type=\"slic3r." + key + "\">"
+ object->config.serialize(key) + "</slic3r:object>\n");
<slic3r:volumes>
<slic3r:volume ts=" The start triangle index according to < triangles > element"
te=" The end triangle index of this volume " modifier="0 or 1">
<slic3r:metadata type="key"> key.serialize() </slic3r:metadata>
</slic3r:volume>
</slic3r:volumes>
@lordofhyphens @alexrj if you have any comments , please tell me.
Any particular reason why you are including the producing version?
So our volumes (primarily used as modifiers) would be ignored by other 3mf reading programs, then?
Consider a refactor to translate materials between 3mf and amf as a stretch goal. I wouldn't do much about it now.
So long as it works, meets the general requirements (preferably header-only, etc), and doesn't turn into a giant timesink, I don't think @alexrj or I care much about you rolling your own zip implementation. My suggestion is if you're going to go that route, make sure that the interface doesn't change from the wrapper you are using now. It will make debugging easier and you can deal with it after getting the kinks worked out of the main effort.
Any other open questions?
@lordofhyphens
file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl
<< "<amf unit=\"millimeter\">" << endl
<< " <metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>" << endl;
You mean there is no reason to write \<slic3r:volumes>, I will remove them. I did so cause I see in AMF we write whether volumes are modifiers or not and to save their config.keys (If they are found)
for (const std::string &key : volume->config.keys())
file << " <metadata type=\"slic3r." << key << "\">"
<< volume->config.serialize(key) << "</metadata>" << endl;
if (!volume->name.empty())
file << " <metadata type=\"name\">" << volume->name << "</metadata>" << endl;
if (volume->modifier)
file << " <metadata type=\"slic3r.modifier\">1</metadata>" << endl;
@Samir55
It came from IRC #slic3r....
[09:43] <Samir> Zip lib compiles fine with cmake (it works) and slic3r builds fine with Build.pl on mac os but I have encountered this error on Ubuntu 14.04 when running Build.pl, Here it is (https://pastebin.com/r5jQs4ep)
[09:44] <Samir> LoH: Can this be error be handled without changing in zip lib code?
[09:45] <LoH|Work> so is zip.c actually required to use the library?
[09:46] <Samir> LoH|Work : yes the Zip lib consists of (zip.h, zip.c and miniz.h)
[09:47] <LoH|Work> so there's part of the implementation in zip.c?
[09:48] <Samir> LoH|Work, yes the zip.c file is here (https://github.com/kuba--/zip/blob/master/src/zip.c)
[09:48] <LoH|Work> It looks like it is shadowing something in your standard include libs, so try removing the declaration and see if it breaks ;)
[09:49] <LoH|Work> I don't know offhand why it would compile with cmake and not with build.pl other than the cmake build may have different flags.
[10:43] <Samir> LoH|Work: I removed the words static and const from basename funtion declaration and it has worked , However on macOS Build.pl works fine without any modification and does not give any errors when compiling zip.c
[10:43] <LoH|Work> I'm not surprised, the conflict was with a system include libraryh
[10:44] <LoH|Work> it would probably only break on that or similar enough linux distros
[10:45] <Samir> LoH|Work: what do you recommend to do in this case?
[10:47] <LoH|Work> tweak zip.c. The problem will go away if you roll your own zip lib later.
[10:50] <Samir> LoH|Work : I will start implementing it today . I was only giving a last chance for including it. What is left in TMF::read is some refactoring and supporting Material Extension. Thanks LoH :)
Should I throw exceptions or leave return false in the functions if there was any error, for example, cannot open a file, cannot write to file, etc?
What does the AMF reader do?
@lordofhyphens It doesn't throw exceptions. O.K. I will continue like in AMF.
There was not code at those days I spent considerable time doing the following:
@alexrj I need some overall code review , I haven't finished yet but if you see something that needs improvements tell me.
// a. Add color group data member to Model Class.
ModelMaterialMap color_group;
///< Colors ModelMaterials specific to 3MF format read/write. This is a material group in the 3MF material extension.
// b. Add material group id to ModelMaterial Class. int material_group; ///< The material belong to which group. Specific to 3MF file format. By default = 0 which means it's a base material or AMF material. / I assume 1: means 3MF basematerials or AMF read materials. 2: means color group. 3:means composite materials. 4: means multiproperties. /
// c. Write color groups to the write_materials() function in TMF editor class.
for (const auto &material : model->color_group) {
if(!color_group_written){
append_buffer("<m:colorgroup id=\"2\">\n");
color_group_written = true;
}
append_buffer("<m:color color=\"" + material.second->attributes["color"] + "\" />\n");
}
// Close the material color group if it's open.
if(color_group_written)
append_buffer("</m:colorgroup>\n");
#### B. Composite Materials:
@alexrj @lordofhyphens Are composed materials supported in Slic3r ? Also, Do we need to support all those kinds of materials beside base materials in core specification?
* Composite Material is a mixture of 2 or more base materials.
* Currently I am working on implementing them like color group.
#### C. Texture 2d Group: I will ignore that group.
Currently we wouldn't do anything with materials. Treating them like colors is probably fine.
std::map<int, ModelMaterialMap> material_groups;
// It's a map of material groups <material_group_id, its_materials_map>
// For Example <1, color_group_materials>.
// This structure is needed as there may exist more than one "color group" or "composite materials" in the 3MF document.
std::map<int, std::string> material_groups_types; // The material group id is mapped to its type whether it's a color, composite materials or multi properties group.
@Samir55 I looked through your branch. My comments here going to be "craftsmanship" style comments.
Please pay more attention to what your editor is doing to whitespace and what you commit to your branch. I was browsing over the changes you committed to slic3r.cpp and noticed that they are all just to whitespace (and not productively). This tends to lead to more headaches when performing merges later.
Some of your comments are seemingly redundant in TMF.cpp "Constructor" is not, in my opinion, a useful code comment (that it is a constructor should be obvious from the method's signature). Same with "Convert to string" as a comment on a to_string
method is not a useful comment; explaining a special method for determing the string representation would be.
Is there a reason that TMFEditor is a struct
and not a class
? zip_archive
does require going through the class to do anything meaningful with it, so leaving a naked pointer out like that is not particularly good practice.
Is there a reason the template functions of TMFEditor are in the .cpp file (and that there is no header for it)? IIRC nonspecialized templates are a bit wonky in non-header files (and we don't like #include cpp
)
Does the 3mf-specific part number really need to be included as an class variable in Model? It's not necessarily wrong, I would like you to explain your reasoning as a confirmation that it is necessary ;) Is there enough information elsewhere to reconstruct it for export, or is it being included just for reflection purposes (export of imported file is same)?
Same with the color groups, etc.
@Samir55 if you open a pull request you can get the build server(s) to run your code.
You should probably pause implementing features and devise some basic I/O tests for each feature you have implemented so far, ensuring that they are read appropriately from a sample file and then written (and read), either as unit tests for TMFEditor or at the very minimum high level test cases for read()
and write()
.
@lordofhyphens Thanks for your review :)
Part numbers are intended as a way to keep track of objects which may have been modified during a toolchain.
When editing or processing a 3MF document, these part numbers SHOULD be preserved to the greatest degree possible, duplicating them for objects split into pieces, removing them from objects that are combined,
and maintaining them for objects that are modified.
SHOULD in 3MF document means it's recommended.
I have asked Sound about this and he asked:
interesting. so they are unique identifiers we should keep attached to objects.
let's add a property to ModelObjects, and make sure you document they are used for the 3MF part numbers
Regarding color groups, I have created one data structure found in the last dev log carrying all 3MF material extension groups ( color, composite materials , multi properties).
I will create a PR in the next minutes and I am working on today on test cases.
Commits solving the points above:
@Samir55 A struct
has all of its members public by default; this represents the interface of TMFEditor
. What I would like you to do is put some thought and consideration into the interface (what should be public and what should be private).
Are functions not called by TMFEditor
supposed to be messing with the contents of the pointer? If not, zip_archive
should be private.
@lordofhyphens Okay I will take this into consideration :).
Anything that is exposed via the public interface should be unit tested at a minimum.
<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02" xmlns:m="http://schemas.microsoft.com/3dmanufacturing/material/2015/02" xmlns:slic3r="http://link_to_Slic3r_schema.com/2017/06">
<slic3r:metadata type="version">1.3.0-dev</slic3r:metadata>
<resources>
<object id="1" type="model">
<mesh>
<vertices>
<vertex x="-1" y="-0.999998" z="0.999998"/>
<vertex x="-1" y="-0.999998" z="-1"/>
<vertex x="1" y="-1" z="-0.999998"/>
<vertex x="0.999996" y="-1" z="1"/>
<vertex x="-1" y="1" z="0.999997"/>
<vertex x="1" y="0.999998" z="1"/>
<vertex x="1" y="0.999998" z="-0.999998"/>
<vertex x="-0.999995" y="1" z="-1"/>
</vertices>
<triangles>
<triangle v1="0" v2="1" v3="2"/>
<triangle v1="0" v2="2" v3="3"/>
<triangle v1="4" v2="5" v3="6"/>
<triangle v1="4" v2="6" v3="7"/>
<triangle v1="0" v2="4" v3="7"/>
<triangle v1="0" v2="7" v3="1"/>
<triangle v1="1" v2="7" v3="6"/>
<triangle v1="1" v2="6" v3="2"/>
<triangle v1="2" v2="6" v3="5"/>
<triangle v1="2" v2="5" v3="3"/>
<triangle v1="4" v2="0" v3="3"/>
<triangle v1="4" v2="3" v3="5"/>
</triangles>
<slic3r:volumes>
<slic3r:volume ts="0" te="11" modifier="0" >
</slic3r:volume>
</slic3r:volumes>
</mesh>
</object>
</resources>
<build>
<item objectid="1" transform="1 0 0 -0 1 0 0 0 1 0 0 0"/></build>
</model>
* I have made only the 2 functions produce_TMF() and consume_TMF() only public functions and those are the ones I am going to implement unit tests for them.
* [Commit I](https://github.com/alexrj/Slic3r/pull/4046/commits/87b63eaf6c91d521953cffdab00e219674a88f1a)
Add remaining TMFParserContext functions (To be populated in the next days). Commit 1 Commit 2
A. How to manage the units (mm, etc) in the 3MF model? B. Regarding the vertices positions, Where is the origin point in Slic3r as 3MF spec assumes the origin point at the bottom front left corner ? C. What does XMLCALL macro do in expat? I didn't quite understand why it's been put in the handler functions?
static void XMLCALL startElement(void *userData, const char *name, const char **atts);
static void XMLCALL endElement(void *userData, const char *name);
static void XMLCALL characters(void *userData, const XML_Char *s, int len);
This was written in expat_external.h
/* Expat tries very hard to make the API boundary very specifically
defined. There are two macros defined to control this boundary;
each of these can be defined before including this header to
achieve some different behavior, but doing so it not recommended or
tested frequently.
XMLCALL - The calling convention to use for all calls across the
"library boundary." This will default to cdecl, and
try really hard to tell the compiler that's what we
want.
XMLIMPORT - Whatever magic is needed to note that a function is
to be imported from a dynamically loaded library
(.dll, .so, or .sl, depending on your platform).
The XMLCALL macro was added in Expat 1.95.7. The only one which is
expected to be directly useful in client code is XMLCALL.
Note that on at least some Unix versions, the Expat library must be
compiled with the cdecl calling convention as the default since
system headers may assume the cdecl convention.
*/
D. @alexrj @lordofhyphens Regarding reading the 3dmodel.model file, Can I extract it to a file and read it using boost::nowide::ofstream or there exists a better way?
A. Slic3r tends to assume everything is in mm, but it is generally unit less (so long as everything has the same units).
B. Origin point on a plate export is 0,0. On a solo model export I believe it is what was read in.
C. It is there to tell the compiler how to call functions (basically plumbing). You shouldn't have to use it yourself explicitly or write something similar.
D. Seems fine to me.
Today, I will be working on decomposing the affine 3d transformation matrix.
The problem in model materials is:
std::map<string, ModelMaterial*> // (material_id, material pointer)
/// In Model class.
++ std::vector<std::pair<int, ModelMaterialMap>> material_groups;
++ ///< It's a vector carrying pairs each has the material group type and its materials.
I know that currently Slic3r doesn't do anything with materials.
"3mf: group_type group_id material_index_in_that_group"
then we will be able to use that to read and write materials without much pain but this will need handling that change when writing AMF.
Continue using the current implementation but beside adding the material to it's material_gorup add it to the original ModelMaterials map (materials) and when we exporting to AMF we can ignore those material groups and accept base materials basematerials are like materials in amf.
Ignore the current implementation and read only basematerials and ignore the material extension groups, But this may in the future cause crash because of integer overflow in case of large number of base materials
@alexrj @lordofhyphens what's the best way to handle this?
(I haven't yet applied the transformation to the model instances).
Commits: Commit 1, Commit 2 I only did as the code found in this link "ETdoFresh answer" @lordofhyphens Is this method correct? It's as follows:
@alexrj @lordofhyphens I have a question regarding reading the item tag (which corresponds to creating the model instance of an object). I extracted the following parameters from the matrix in the item tag:
While what is found in ModelInstance:
3MF specification requires (is a must) applying the matrix. Do you recommend me to add those parameters to the ModelInstance or what's the case?
For reading the transformation matrix in component tag (An object is a part of a bigger object) desn't have the previous problem as I create a copy of the component object apply rotation, translation and scale to the copied object then get the mesh and add it to volumes of the big object.
// Create a copy of the current object.
ModelObject* object_copy = m_model.add_object(*component_object, true);
apply_transformation(object_copy, transformations);
// Get the mesh of this object.
component_mesh = object_copy->mesh();
// Delete the copy of the object.
m_model.delete_object(m_model.objects.size() - 1);
void
TMFParserContext::apply_transformation(ModelObject *object, std::vector<double> &transformations)
{
// Apply scale.
Pointf3 vec(transformations[3], transformations[4], transformations[5]);
object->scale(vec);
// Apply x, y & z rotation.
object->rotate(transformations[6], X);
object->rotate(transformations[7], Y);
object->rotate(transformations[8], Z);
// Apply translation.
object->translate(transformations[0], transformations[1], transformations[2]);
return;
}
@alexrj @lordofhyphens I need some overall code review. If there is something that needs modifications or improvements tell me.
This issue is dedicated to the GSoC student @Samir55 who proposed to implement support for the 3MF file format in Slic3r: https://summerofcode.withgoogle.com/projects/#6343944127381504
This topic was discussed in this original issue:
2811
@Samir55 already contributed to the Slic3r codebase by adding zoom commands (pull request #3864, merged).
@Samir55, welcome to Slic3r! Would you please introduce yourself to the Slic3r community? Please mention any experience with 3D printing or similar technologies, and include your time zone and operating system.