slic3r / Slic3r

Open Source toolpath generator for 3D printers
https://slic3r.org/
GNU Affero General Public License v3.0
3.29k stars 1.29k forks source link

[GSoC] Samir55 / 3MF file format #3934

Closed alranel closed 6 years ago

alranel commented 7 years ago

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.

Samir55 commented 7 years ago

I'm Samir, a computer engineering undergraduate student, I have some experience in CNC machines and G-code as I am working with my team this semester to make a machine like CNC machine (but we are using a touch screen stylus instead which draws any picture we send to it) . 3D printers are not so popular yet in our country :) so, I have little experience with 3D printers. I dealt with 3D model files (like: OBJ ) in the computer graphics game project .

Time Zone: Eastern European Time Zone (UTC+02:00)

Operating System : Ubuntu 14.04 and Mac OS Sierra .

Samir55 commented 7 years ago

Today's Task (5 May):

NateTG commented 7 years ago

If there are specs or references about the formats that you used, and those are available on-line, be sure to include links in the wiki.

Samir55 commented 7 years ago

I have made a draft about what file formats Slic3r support document. This is the link. I have some questions found in the comments. any help is really appreciated :)

Samir55 commented 7 years ago

This Week Task (From May 8):

Samir55 commented 7 years ago

Question No.1:


Does Slic3r use the loaded materials from OBJ files?
As I see in IO .cpp file in function OBJ::read the vector<tinyobj::material_t> materials 
is not used in this function? 
why it's declared?
Samir55 commented 7 years ago

@alexrj @lordofhyphens I am Studying now Slic3r:: Model and I want to write a documentation for it, I want to include Class Diagram, what each function in the class does, should I include something else? I mean also ModelMaterial, ModelObject, ModelVolume , ModelInstance classes

lordofhyphens commented 7 years ago

@Samir55 Regarding materials in OBJ files:

Odds are it's there for growth reasons or to make the reader/writer idempotent (read an obj -> write obj should not lose information).

If you're documenting Slic3r::Model, be sure to take a look at https://github.com/prusa3d/Slic3r/blob/master/xs/src/libslic3r/Model.hpp The patches didn't usually make it upstream because the author tended to also have code changes in the same areas, which makes for very messy PRs.

Personally, I'd prefer to inline the documentation and generate "nice" docs via something like doxygen, which does a decent job of diagramming C/C++.

If you do any documenting in the source, please do (and commit) that first.

alranel commented 7 years ago

@Samir55, writing documentation for Slic3r::Model is indeed a useful approach. It will help you a lot when working on 3MF. I agree with @lordofhyphens's suggestion about using Doxygen syntax. It's easy to learn, and it's a nice skill to have for coding C++ libraries.

Regarding your document about formats, a few notes:

alranel commented 7 years ago
alranel commented 7 years ago

To answer your question, the materials variable in OBJ::read() is declared because the tinyobj::LoadObj() function signature requires it, even if we discard the contents.

Samir55 commented 7 years ago

I have finished the Slic3r::Model documentation (Using Doxygen syntax) . Found Here in my fork Model.hpp. There are some functions I didn't quite understand what they are doing. So, These are the questions:

First Model Class

A.

What is the difference between TriangleMesh mesh() and TriangleMesh raw_mesh() ?

B.

What are these functions do?
 _arrange(const Pointfs &sizes, coordf_t dist, const BoundingBoxf* bb, Pointfs &out)
arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL)
duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
looks_like_multipart_object()
convert_multipart_object()

Second ModelMaterial Class

C.

What does DynamicPrintConfig object carry ?

Third ModelObject Class

D.

What is the difference between Printable and modifier volumes ?
What is the raw_bounding_box?
In scale_to_fit function , Which size is it ? is it of the viewport or the 3D canvas or what?

Forth ModelInstance Class

E.

Why the object may need repair? What are the reasons behind calling repair on meshes?
Samir55 commented 7 years ago

I am now working on Slic3r wiki page in my fork and I'll try to finish very soon. Sorry I and my team are very busy finishing the micro-controller project so, it's taking some considerable time.

lordofhyphens commented 7 years ago

Objects may need repair because STL is a terrible format. Additionally, the algorithms used tend to want manifold and valid files, so the repair() function is used as input sanitation.

lordofhyphens commented 7 years ago

A) Consult Model.cpp, lines 589-612. ModelObject::mesh() performs an extra transform (if the model was rotated or translated); ModelObject::raw_mesh() just gives you the mesh as-is without any extra processing. Right there in the source.

lordofhyphens commented 7 years ago

B) looks_like_multipart_object() does what it says--checks to see if the Model it belongs to has characteristics of having multiple parts (usually multiple volumes, etc).

convert_multipart_object() takes all of the volumes in the Model and combines them into one.

duplicate_objects_grid() replicates a single object and arranges them on a grid. It's only used by Simple.pm, which is used only in CLI mode.

The two arrangement functions attempt to move model instances around.

It's often helpful to employ a text search tool like grep to find the usages of functions in the code.

lordofhyphens commented 7 years ago

C) DyanmicPrintConfig inherits from DynamicConfig. Unlike a StaticConfig, the options map is mutable. It can carry anything you give it. See Config.hpp:671-673 (grep to the rescue, determined through the existing comments and looking at what DyanmicPrintConfig inherits from). grep -r DynamicPrintConfig . | grep -v -e "^Binary" -e "\.o:" -e "_build" -e "\/t\/" -e "tiny_obj_loader" -e "XS.c" for usage in the Slic3r codebase.

D) Printable and modifier volumes are both volumes, one just has a flag on it to indicate to the slicer that it represents a different PrintRegion.

raw_bounding_box() is the same as instance_bounding_box(this->instances.size()-1), at least from my examination of the source (614-636). It is probably a candidate for refactoring, at least to call instance_bounding_box() with the calculated reference to this->instances.front().

scale_to_fit is whatever size you pass to it. grep is your friend here (or Understand, or any other number of source navigation tools).

bubnikv commented 7 years ago

The 3MF format uses a ZIP format as a container. For reading / writing the ZIP files you may consider bundling the ZIP reader / writer by Disney, which I believe is self contained.

https://github.com/wdas/partio/blob/master/src/lib/io/ZIP.h https://github.com/wdas/partio/blob/master/src/lib/io/ZIP.cpp

We would have to ask @lordofhyphens to check the FSF policies though as it is critically important to include Richard Stallman approved stuff only.

Another possibility is to use the wxZipInputStream / wxZipOutputStream classes from the wxWidgets, which I have used in the Prusa3d fork of Slic3r to import the Prusa Control platter files, which are just bundles of STLs with a tiny XML describing the transformation matrices.

lordofhyphens commented 7 years ago

@bubnikv Slic3r is GPL3-licensed. We work within the rules around here, as @alexrj also prefers.

lordofhyphens commented 7 years ago

Avoid using wxwidgets in libslic3r code (things that go in xs/src/libslic3r).

Samir55 commented 7 years ago

I've finished the Slic3r supported format wiki document in my fork. tell me if there are any enhancements should be done. @alexrj Can I create the page in Slic3r wiki now?

@bubnikv Thanks for your help, I am also thinking about using minizip and in this thread there is a very simple example about reading a zip file.

lordofhyphens commented 7 years ago

@Samir55 Go ahead and make changes as you see fit. If @alexrj or I feel a page needs to move, we'll move it ;)

alranel commented 7 years ago

The Disney ZIP library uses the 3-clause BSD license, which is compatible with our GPL license (as open source software developers, we care about licenses). However, that library looks unmaintained (see this bug report) so it doesn't look reliable. That minizip one looks fine. Here's a comprehensive list.

alranel commented 7 years ago

Next steps:

Samir55 commented 7 years ago

This Week Task (From May 17):

lordofhyphens commented 7 years ago

With regards to including a library, take a look at how admesh and poly2tri are included, although if you can set it up as a submodule I would be happier.

http://stackoverflow.com/questions/6238590/set-git-submodule-to-shallow-clone-sparse-checkout

https://github.com/madler/zlib/tree/master/contrib/minizip looks like it's the same module and involves less code duplication for us.

Samir55 commented 7 years ago

@alexrj @lordofhyphens I've finished 3MF Core Specification Report and it's found in my fork wiki 3MF Document Core Specification.

lordofhyphens commented 7 years ago

You can edit the main wiki as you need to. It is a wiki, after all

Samir55 commented 7 years ago

OK :) Added to the main wiki.

Samir55 commented 7 years ago

@alexrj @lordofhyphens I have a problem with including library mini zip. First I couldn't include only the minizip folder found in /contrib/ in zlib library, spent alot of time searching and found out that the best way to fork the zlib and remove the unnecessary folders and keep the ones you need then include this repo as a submodule. Sparsecheckout won't work in this case I've tried but I didn't reach a solution. So, I tried(temporary to include it statically), created a header file that includes "unzip.h" but I've found those errors when running Build.pl ( ). I don't know what to do. And inorder not to waste more time I've learned how to read from a zip file using minizip and I've run a prebuilt Xcode project to read a zip file.

lordofhyphens commented 7 years ago

It is probably because it's C being compiled as C++.

Samir55 commented 7 years ago

Yes It seems so, What Should I do? @lordofhyphens When I run these commands at the /xs/src/minizip/ directory

cc -c -O -I../.. ioapi..c
cc -c -O -I../.. unzip.c
cc -c -O -I../.. zip.c

ioapi.o zip.o and unzip.o are successfully build but when I run this command (this is the command invoked at during Slic3r perl Build.pl) at /xs/

cc -I/Users/ASamir/perl5/perlbrew/perls/threaded-perl-blead/lib/5.26.0/darwin-thread-multi-2level/CORE -mmacosx-version-min=10.12 -fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -fstack-protector-strong -I/usr/local/include -xc++ -Isrc/libslic3r -I/Users/ASamir/boost_1_63_0 -D_GLIBCXX_USE_C99 -DHAS_BOOL -DNOGDI -DSLIC3RXS -DBOOST_ASIO_DISABLE_KQUEUE -U__STRICT_ANSI__ -std=c++11 -stdlib=libc++ -DBOOST_THREAD_DONT_USE_CHRONO -DBOOST_NO_CXX11_RVALUE_REFERENCES -DBOOST_THREAD_USES_MOVE -DBOOST_LIBS -DNDEBUG -Isrc -Ibuildtmp -c -mmacosx-version-min=10.12 -fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -fstack-protector-strong -I/usr/local/include -O3 -o src/minizip/zip.o src/minizip/zip.c

Errors are generated

lordofhyphens commented 7 years ago

Fix the errors, make sure the tests pass, and submit a patch upstream. Point your module to a fork in the meantime.

ledvinap commented 7 years ago

@Samir55 : See https://stackoverflow.com/questions/1041866/in-c-source-what-is-the-effect-of-extern-c

Samir55 commented 7 years ago

@ledvinap Thanks for your help. @alexrj I have completed the search about zip libraries the results are in this link, I'd prefer using zipper or Zip libraries. Do you want me to see other ones, I've found another ones but they don't have a GitHub repository (So we couldn't include them as submodules)

lordofhyphens commented 7 years ago

@Samir55 https://help.github.com/articles/about-git-subtree-merges/ may be useful instead of submodules.

Zipper looks fine (it's a wrapper around minizip but looks like it has nicer syntactic sugar). Whatever you end up using, the current mechanism for libraries is to put them in xs/src/, and update the include list.

alranel commented 7 years ago

We talked about this over IRC. Minizip has a bunch of .c files and it's build on top of zlib. I'd prefer a header-only or a single file library like miniz. Since the task is fairly simple, I would not add any wrapper for syntactic sugar and just use the lower level API of miniz. A single file library does not need to be added as submodule, we can just import it into the repository like we do for the other ones.

I also recommended @Samir55 to work with the C++-only code (src/) since it allows for faster compilation with CMake and there's no Perl or XS involved. Goal will be to have slic3r.cpp support an --export-3mf option for command line conversion.

lordofhyphens commented 7 years ago

Generally works for me; part of what I am interested in is cleaner lines of association.

I am currently experimenting with subtrees for including vcglib, although that is lower priority than putting out build fires or xsgui.

Samir55 commented 7 years ago

I've updated the project plan found in this link included the 3 milestones (if you want me to modify something tell me. Yesterday I've done a simple task include miniz lib and add it to the CMakeLists.txt (I was studying for today's electronics exam). Today I am working on these few tasks (till June 4th) :

Samir55 commented 7 years ago

Dev Log (30-31 May) :

Samir55 commented 7 years ago

I- Why do we call the write function in OBJ that takes a TriangleMesh not a Model class? II- Why isn't there an --export-amf option?

lordofhyphens commented 7 years ago
  1. A Model can contain multiple meshes. Triangle mesh is exactly what it says on the tin. There is no real reason why an overload of the function couldn't accept a Model (and simplify it to meet the requirements of the export function).
  2. Probably an oversight.
Samir55 commented 7 years ago

Dev Log (2 - June) :

All commits are here gsoc-3mf and also here gsoc-tmf

  1. Commit: Call IO::TMF:write function with the read model and the output file in slic3r.cpp & Fix miniz.c error (This was a try but I have committed another working solution later in another commit):

    • Miniz source functions were included more than once (once during TMF.cpp and once during compiling miniz.c in /xs/src/miniz "if you run perl Build.pl, cmake doesn't complain).
    • Miniz is a header file library.
    • Solution was to add #define MINIZ_HEADER_FILE_ONLY to include the header part of the single header library miniz.c.
  2. Commit: Create a Zip archive containing a 3dmodel.model file containing a basic string "TEST" & Remove #define MINIZ_HEADER_FILE_ONLY in the previous commit ( It's not the solution).

  3. Commit: Write Model metadata elements to the 3MF zip file.

  4. Commit: (solution to Miniz problem in the first commit) Renaming miniz.c to miniz.h, if you want to include it in other files use #define MINIZ_HEADER_FILE_ONLY before including it to avoid redefining the functions.

Notes perl Build.pl command builds Slic3r successfully after the forth commit.

Problems arose Now I put all the string to be written to 3dmodel.model in a string(which is not practical) because of the following probelm: I couldn't find in Miniz library a function to append some text to a perviously created entry in the zip file (same issue found in this thread stackoverflow). For example, to create a file called a.txt in the zip archive and include in it some text stored in a string called buff you have to call

 mz_zip_writer_add_mem(&(zip_archive), "a.txt", buff.c_str(), buff.size(), MZ_BEST_COMPRESSION );

and I tried calling this function again but it's creating a new file in the zip carrying the new buffer only. I searched for this in library and I have found an implementation for this Zip in zip_entry_write function but it seems quite difficult to understand this.

Samir55 commented 7 years ago

Dev Log (4 - June) :

Samir55 commented 7 years ago

Dev Log(5 - June):

Currently I work in gsoc-tmf branch where I've included zip library statically, I will include it later as a subtree.

I have some questions about writing material:

lordofhyphens commented 7 years ago

Either create a new structure or refactor so we can use the same one for AMF.

Samir55 commented 7 years ago

Dev Log(7 - June):

Samir55 commented 7 years ago

Dev Log(8 - June):

Samir55 commented 7 years ago

Dev Log(12 - June):

Samir55 commented 7 years ago

Dev Log(14 - June):