Parametric objects - guidance please

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
tomkcook
Posts: 87
Joined: Wed Jul 20, 2016 3:39 pm

Parametric objects - guidance please

Post by tomkcook »

I have a module which constructs the geometry of a certain class of yacht hull from a handful of parameters. So far, this exists as a FreeCAD workbench with a single command. This command displays a panel where a user can set parameters of the hull. As the parameters are changed, the generated geometry is displayed in the 3D view. Once the panel's 'OK' button is pressed, the user is left with a bit of a hierarchy of objects in the model which together make up the hull & decks. You can find the code for this stage here: https://github.com/tomkcook/free-cad-hulls. The defaults are rather exaggerated in various ways and I realise it doesn't produce a very good hull!

I'd now like to convert this into a tool which creates a parametric "Hull" parameter, so that the parameters can later be varied & the resulting geometry changed, rather than having to go back and recreate the object from scratch to change the geometry. I found the tutorial at https://www.freecadweb.org/wiki/Manual: ... ic_objects. It seems to suggest that if I create a new class to represent the object with properties (added with

Code: Select all

obj.addProperty()
) to represent the parameters of the geometry, move the geometry creation code into that class's

Code: Select all

execute()
method and assign the resulting geometry to

Code: Select all

obj.Shape
, this should just work. Have I got the right end of the stick here?

Secondly, I'd like, eventually, for this object to have sub-objects to represent the hull geometry and the deck geometry. But I'm not sure what's the best way forward here. Is there a way for a parametric object to have sub-objects in this way? Or would I be better off to keep it as a single object, with a command to replace that single object with two separate objects representing the two different parts of the geometry?

Thanks for any advice,
Tom
User avatar
Joel_graff
Veteran
Posts: 1949
Joined: Fri Apr 28, 2017 4:23 pm
Contact:

Re: Parametric objects - guidance please

Post by Joel_graff »

tomkcook wrote: Mon Jun 03, 2019 7:53 pm I found the tutorial at https://www.freecadweb.org/wiki/Manual: ... ic_objects
I would suggest exploring FeaturePython objects. Here's a wiki page that has a tutorial on creating a basic one:

https://www.freecadweb.org/wiki/FeaturePython_Objects

It's complete (two pages), but probably needs a little work. Still, it will show you what it takes to create a custom parametric object.

tomkcook wrote: Mon Jun 03, 2019 7:53 pm Secondly, I'd like, eventually, for this object to have sub-objects to represent the hull geometry and the deck geometry. But I'm not sure what's the best way forward here. Is there a way for a parametric object to have sub-objects in this way? Or would I be better off to keep it as a single object, with a command to replace that single object with two separate objects representing the two different parts of the geometry?
Yes and no. That is, it's possible to group objects together, and you can even create custom groups, but in the end, your objects will probably all end up being siblings to one another. In my experience, keeping your hierarchies flat is generally better. You can contain properties common to both objects in a "master sketch" or master object.
FreeCAD Trails workbench for transportation engineering: https://www.github.com/joelgraff/freecad.trails

pivy_trackers 2D coin3D library: https://www.github.com/joelgraff/pivy_trackers
tomkcook
Posts: 87
Joined: Wed Jul 20, 2016 3:39 pm

Re: Parametric objects - guidance please

Post by tomkcook »

Thanks! Believe it or not, I followed the instructions and it worked first time.
User avatar
Joel_graff
Veteran
Posts: 1949
Joined: Fri Apr 28, 2017 4:23 pm
Contact:

Re: Parametric objects - guidance please

Post by Joel_graff »

tomkcook wrote: Fri Jun 14, 2019 4:52 pm Thanks! Believe it or not, I followed the instructions and it worked first time.
Sweet! Given that I wrote them, that actually means a lot! Thanks! :lol:
FreeCAD Trails workbench for transportation engineering: https://www.github.com/joelgraff/freecad.trails

pivy_trackers 2D coin3D library: https://www.github.com/joelgraff/pivy_trackers
User avatar
Joel_graff
Veteran
Posts: 1949
Joined: Fri Apr 28, 2017 4:23 pm
Contact:

Re: Parametric objects - guidance please

Post by Joel_graff »

BTW, as you work through it, don't hesitate to ask more questions. Mastering FeaturePython objects really unlocks a lot of the cool things you can do with FreeCAD in Python. :)
FreeCAD Trails workbench for transportation engineering: https://www.github.com/joelgraff/freecad.trails

pivy_trackers 2D coin3D library: https://www.github.com/joelgraff/pivy_trackers
tomkcook
Posts: 87
Joined: Wed Jul 20, 2016 3:39 pm

Re: Parametric objects - guidance please

Post by tomkcook »

The only problem I'm having is that the resulting document can't be saved.

To simplify slightly, I have:

Code: Select all

class ParametricHull():
    def __init__(self, obj):
        self.Type = 'hull'
        obj.Proxy = self
        self.Object = obj
        ParametricHullViewProvider(obj.ViewObject)

        obj.addProperty('App::PropertyLength', 'Length', 'Dimensions', 'Length overall').Length = 12000
        ...

    def create_geometry(self, **params):
        ... generate a shape, see note below ...
        return shape

    def execute(self, obj):
        half = self.create_geometry(...params...)
        hull = Part.makeCompound([half, half.mirror(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,1,0))])
        obj.Shape = hull

obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'Hull')
fpo = ParametricHull(obj)
The result of the `create_geometry` call comes from a C++ function which ends with `return Py::asObject(new Part::TopoShapeFacePy(new Part::TopoShape(builder.Face())));`. `builder` is a `BRepFill_Filling` object.

This results in this message whenever the file is saved:

Code: Select all

$ Traceback (most recent call last):
  File "/usr/lib/python2.7/json/__init__.py", line 244, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python2.7/json/encoder.py", line 270, in iterencode
    return _iterencode(o, 0)
  File "/usr/lib/python2.7/json/encoder.py", line 184, in default
    raise TypeError(repr(o) + " is not JSON serializable")
<type 'exceptions.TypeError'>: <Part::PartFeature> is not JSON serializable
I'm not absolutely clear that I'm creating a Part::PartFeature object anywhere, though it's possible that something I've created resolves to that. But it's a surprise that PartFeature is not serializable.

Am I doing something obviously wrong?
User avatar
Chris_G
Veteran
Posts: 2601
Joined: Tue Dec 31, 2013 4:10 pm
Location: France
Contact:

Re: Parametric objects - guidance please

Post by Chris_G »

One possible reason is this line in your Proxy's init :

Code: Select all

self.Object = obj
It is usually easy to avoid this line, because all the special methods of the Proxy (execute(), onChanged(), etc) receive the FeaturePython object as first argument, so you can pass this reference to your other custom methods, without needing to store the FeaturePython object in your proxy.
tomkcook
Posts: 87
Joined: Wed Jul 20, 2016 3:39 pm

Re: Parametric objects - guidance please

Post by tomkcook »

Chris_G wrote: Sun Jun 30, 2019 3:27 pm One possible reason is this line in your Proxy's init :

Code: Select all

self.Object = obj
It is usually easy to avoid this line, because all the special methods of the Proxy (execute(), onChanged(), etc) receive the FeaturePython object as first argument, so you can pass this reference to your other custom methods, without needing to store the FeaturePython object in your proxy.
Yep, that's it, thanks. Actually that object field was never used again, it's just there because it's on the wiki page.

I was going to update the wiki with this... but it seems I can't create an account? And can't edit without one?
kisolre
Veteran
Posts: 4166
Joined: Wed Nov 21, 2018 1:13 pm

Re: Parametric objects - guidance please

Post by kisolre »

tomkcook wrote: Sun Jun 30, 2019 3:52 pm I was going to update the wiki with this... but it seems I can't create an account? And can't edit without one?
How to get wiki editing permissions
User avatar
Joel_graff
Veteran
Posts: 1949
Joined: Fri Apr 28, 2017 4:23 pm
Contact:

Re: Parametric objects - guidance please

Post by Joel_graff »

Chris_G wrote: Sun Jun 30, 2019 3:27 pm It is usually easy to avoid this line, because all the special methods of the Proxy (execute(), onChanged(), etc) receive the FeaturePython object as first argument, so you can pass this reference to your other custom methods, without needing to store the FeaturePython object in your proxy.
The error about JSON serialization has always been an issue of not implementing __getstate__() and __setstate__() in my experience. Not assigning the obj to the proxy Object attribute has generally made FPO's more unstable for me. Thus, I'm concerned removing it from the wiki will create potential for instabilities, typically as non-responsive events / properties.

In any case, since I added this specifically to the wiki for stability reasons, I'd like to know if it's really necessary and if not, why it has been a practice in the past.
FreeCAD Trails workbench for transportation engineering: https://www.github.com/joelgraff/freecad.trails

pivy_trackers 2D coin3D library: https://www.github.com/joelgraff/pivy_trackers
Post Reply