gumyr / build123d

A python CAD programming library
Apache License 2.0
432 stars 81 forks source link

Import/Export #153

Closed gumyr closed 10 months ago

gumyr commented 1 year ago

Currently there are 5 export methods (export_gltf to come):

  1. Shape.export_stl,
  2. Shape.export_step,
  3. Shape.export_brep,
  4. Shape.export_svg, and
  5. Shape.export_dxf

In addition, there are several import methods:

  1. Shape.import_brep,
  2. Compound.import_step,
  3. Face.import_stl, and
  4. SVG.import_svg,

The export methods are easy to use: my_shape.export_... but the imports require too much knowledge of the architecture - users will be hunting around for the correct Class.method to get the import they are looking for.

I'm proposing changing the import methods to import functions. Therefore the user would enter: my_shape = import_... thus avoiding having to determine the appropriate class. Does the community prefer classmethods for exporter? Opinions?

In addition, the import/export methods/functions could be generalized to a single import function and export method where the type of file is determined by the file name. Unfortunately there are unique parameters in each one so combining them would likely make a complex API.

Jojain commented 1 year ago

+1 For the separates methods. You could put them in a importers and exporters module. Maybe you can make a import and export method that would take only the file name and use presets value for the parameters. This will be in addition of import_FILETYPE which would be specific to each filetype and expose parameters.

This way of doing it would provide a very easy solution for people that don't understand what are the parameters of the importers of exporters while letting them export a good enough model for their use case.

jdegenstein commented 1 year ago

I would also like to request a 3mf exporter. 3mf is nice because typically all objects are guaranteed to be manifold. CQ has an implementation here: https://github.com/CadQuery/cadquery/blob/master/cadquery/occ_impl/exporters/threemf.py

gumyr commented 1 year ago

You could put them in a importers and exporters module.

Unfortunately, without monkey-patching, the export_... methods can't be instance methods of Shape if they are located in another module, they would have to be class methods which would make this: image much more difficult for the user.

This is my number one pet peeve with Python - just let me add methods to a class from another file already!

The parameters of the import/export methods need to be cleaned up a little to make them more consistent but they (mostly) have appropriate default values so that new users shouldn't have to worry about them.

gumyr commented 1 year ago

3mf exporter

Check, I'll do that.

Jojain commented 1 year ago

@gumyr I don't understand your point. Why do you need the functions to be method of Shape class ?

Just make a import function in a specific modules that returns a Shape ?

BTW if you want to add methods to a class from another file just use multiple inheritance you could have a Exporter class that Shape would inherit from (it would let you split your files) but in this situation why not just use a classic function?

jdegenstein commented 1 year ago

@gumyr Have you looked at this link for several different approaches to spread a class over multiple files? http://www.qtrac.eu/pyclassmulti.html

gumyr commented 1 year ago

Moving the importers to a separate file/module and making them simple functions seems like the best way to go. I'll give that a try.

@jdegenstein, thanks for the pointer. The "definitive" technique described here is to use Mixin classes and place them into other files - which is fine. However - and I don't know if this is inherent to the application or just my lack of skill - the circular import problem always gets me. As direct_api is defining a topology of classes, they all depend on each other which results in circular imports whenever a meaningful amount of code is separated from the "horde". CadQuery partially solved this problem by separating geometric objects from topological objects which helped but resulted in the limitation that there couldn't be a method to convert a Vector into a Vertex for example.

Here are the class and dependency diagrams - if anyone has another suggestion: build123d_classes

build123d_dependencies

Jojain commented 1 year ago

To convert a Vector in Vertex can't you just make the __init__ of the Vertex take a Vector ? The topo module can import the geom module (since geom is like lower level) but the geometry cannot import topo (which isn't needed normally)

Edit : I missed read your message. Well it's normal that you cannot convert a vector in a vertex. While it's technically similar. It's conceptually not and a vertex is a vector enhanced by topological data. So a vertex is a super set of a vector ( actually it should be a Point) I think it would be a design flaw to make this possible

gumyr commented 1 year ago

The primary reason for converting a Vector to a Vertex is to display them (as points). @Jojain you are correct in that there are other ways to do the conversion.

I'm going to try to separate the geometry objects from the topological objects and see how much this helps.

gumyr commented 10 months ago

There are now separate topology.py and geometry.py modules with a few monkey patches to work around the circular import problem.

The Vertex class takes an Iterable - i.e. a Vector - so the conversion can be done with Vertex(Vector(1,1,1)).

The import/exports have been significantly changed as well with importers.py and exporters.py modules. This section in the docs (https://build123d.readthedocs.io/en/latest/import_export.html) provides a comprehensive description of the various import/export capabilities.