FreeCAD Logo FreeCAD 1.0
  • English Afrikaans Arabic Belarusian Catalan Czech German Greek Spanish Spanish Basque Finnish Filipino French Galician Croatian Hungarian Indonesian Italian Japanese Kabyle Korean Lithuanian Dutch Norwegian Bokmal Polish Portuguese Portuguese Romanian Russian Slovak Slovenian Serbian Swedish Turkish Ukrainian Valencian Vietnamese Chinese Chinese
  • Features
  • Download
  • Blog
  • Documentation
    Documentation index Getting started Users documentation The FreeCAD manual Workbenches documentation Python coding documentation C++ coding documentation Tutorials Frequently asked questions Privacy policy About FreeCAD
  • Contribute
    How to help Sponsor Report a bug Make a pull request Jobs and funding Contribution guidelines Developers handbook Translations
  • Community
    Code of conduct Forum The FPA GitHub GitLab Codeberg Mastodon Matrix IRC IRC via Webchat Gitter Discord Reddit Twitter Facebook LinkedIn Calendar
  • ♥ Donate

Donate

$
SEPA Information
Please set up your SEPA bank transfer to:
Beneficiary: The FreeCAD project association
IBAN: BE04 0019 2896 4531
BIC/SWIFT: GEBABEBBXXX
Bank agency: BNP Paribas Fortis
Address: Rue de la Station 64, 1360 Perwez, Belgium

While Stripe doesn't support monthly donations, you can still become a sponsor! Simply make a one-time donation equivalent to 12 months of support, and you'll gain access to the corresponding sponsoring tier. It's an easy and flexible way to contribute.

If you are not sure or not able to commit to a regular donation, but still want to help the project, you can do a one-time donation, of any amount.

Choose freely the amount you wish to donate one time only.

You can support FreeCAD by sponsoring it as an individual or organization through various platforms. Sponsorship provides a steady income for developers, allowing the FPA to plan ahead and enabling greater investment in FreeCAD. To encourage sponsorship, we offer different tiers, and unless you choose to remain anonymous, your name or company logo will be featured on our website accordingly.

from 1 USD / 1 EUR per month. You will not have your name displayed here, but you will have helped the project a lot anyway. Together, normal sponsors maintain the project on its feet as much as the bigger sponsors.

from 25 USD / 25 EUR per month. Your name or company name is displayed on this page.

from 100 USD / 100 EUR per month. Your name or company name is displayed on this page, with a link to your website, and a one-line description text.

from 200 USD / 200 EUR per month. Your name or company name and logo displayed on this page, with a link to your website and a custom description text. Companies that have helped FreeCAD early on also appear under Gold sponsors.

Instead of donating each month, you might find it more comfortable to make a one-time donation that, when divided by twelve, would give you right to enter a sponsoring tier. Don't hesitate to do so!

Choose freely the amount you wish to donate each month.

Please inform your forum name or twitter handle as a notein your transfer, or reach to us, so we can give you proper credits!

Creating and manipulating geometry
Creating interface tools
Manual start
  • Introduction
  • Discovering FreeCAD
    • What is FreeCAD?
    • Installing
      • Installing on Windows
      • Installing on Linux
      • Installing on Mac OS
      • Uninstalling
      • Setting basic preferences
      • Installing additional content
    • The FreeCAD interface
      • Workbenches
      • The interface
      • Customizing the interface
    • Navigating in the 3D view
      • A word about the 3D space
      • The FreeCAD 3D view
      • Selecting objects
    • The FreeCAD document
    • Parametric objects
    • Import and export to other filetypes
  • Working with FreeCAD
    • All workbenches at a glance
    • Traditional modeling, the CSG way
    • Traditional 2D drafting
    • Modeling for product design
    • Preparing models for 3D printing
      • Exporting to slicers
      • Converting objects to meshes
      • Using Slic3r
      • Using the Cura addon
      • Generating G-code
    • Generating 2D drawings
    • BIM modeling
    • Using spreadsheets
      • Reading properties
      • Writing properties
    • Creating FEM analyses
    • Creating renderings
  • Python scripting
    • A gentle introduction
      • Writing Python code
      • Manipulating FreeCAD objects
      • Vectors and Placements
    • Creating and manipulating geometry
    • Creating parametric objects
    • Creating interface tools
  • The community

In the previous chapter, we explored how to create Part geometry and display it on screen by attaching it to a "dumb" (non-parametric) document object. While effective, this approach becomes cumbersome when you need to modify the shape. Each change requires creating a new shape and reassigning it to the object, resulting in repetitive and inefficient workflows.

Throughout this manual, we’ve seen how parametric objects address this issue by allowing dynamic updates. By modifying a single property, the shape recalculates automatically, eliminating the need for manual updates. This recalculation process enables more efficient modeling and introduces adaptability to designs. Internally, parametric objects operate similarly to what we’ve already done: they recalculate the contents of their Shape property every time one of their properties changes. This iterative process is seamless and ensures that the object remains consistent with its defined parameters.

FreeCAD offers a user-friendly system for creating parametric objects entirely in Python. These objects are defined using a Python class, which:

  • Declares the necessary properties for the object.
  • Defines the behavior when any of these properties are modified.

The structure of such a parametric object is as simple as this:

class myParametricObject:

    def __init__(self, obj):
        obj.Proxy = self
        obj.addProperty("App::PropertyFloat", "MyLength")
        ...

    def execute(self,obj):
        print ("Recalculating the shape...")
        print ("The value of MyLength is:")
        print (obj.MyLength)
        ...

All Python classes typically have an __init__ method. This method is executed when a class is instantiated—that is, when a Python object is created from the class. You can think of a class as a "template" or blueprint used to create live instances of itself. Each instance of the class becomes an independent object with its own attributes and methods. In our __init__ method, we perform two crucial tasks:

  • Store the class itself in the Proxy attribute of the FreeCAD document object:

By assigning self to the Proxy attribute of the FreeCAD document object, we link the logic of our Python class to the FreeCAD object. This means the document object will "carry" the Python class code inside itself, allowing it to behave according to the logic defined in the class. This connection enables FreeCAD to know how to interact with and recalculate the parametric object.

  • Create all the properties the object needs:

Using the addProperty method, we define the custom properties required by the object. Properties act as parameters or variables for the object and can be accessed, modified, and displayed in FreeCAD's property editor. In the example, we add a floating-point property named MyLength. This property will later influence the shape or behavior of the object.

There are many types of properties available in FreeCAD, ranging from floating-point numbers to strings and even specialized types for geometry and materials. To explore the full list of available property types, you can type the following code in the Python console:

FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "dummy").supportedProperties()

The second key part of our class is the execute method. This method is automatically triggered whenever the object is marked for recomputation, which happens when one of its properties is modified. The execute method is where all the recalculations for the object take place, ensuring that its shape and behavior are updated to reflect any changes. Within the execute method, you perform all the necessary operations to generate the new geometry for your object. Typically, this involves recalculating the shape based on the current values of its properties and then assigning the updated shape to the object's Shape attribute using a statement like obj.Shape = myNewShape. The execute method takes a single argument, obj, which represents the FreeCAD document object associated with your parametric object. This allows you to directly manipulate the object within the method, such as accessing its properties, updating its geometry, or performing other operations.

In summary:

  • The execute method is called whenever the object needs to be updated.
  • It is responsible for recalculating the shape and assigning it to the object's Shape attribute.
  • The obj argument gives access to the FreeCAD document object, enabling you to make changes programmatically.

With this system, FreeCAD handles the rest—ensuring that the object is properly updated in the document and displayed correctly in the graphical interface.

One crucial thing to remember is that when you create parametric objects in a FreeCAD document, the Python code used to define them is not saved within the file. This is an intentional security measure. If FreeCAD files were allowed to store Python code, it could open the door for malicious actors to distribute files containing harmful scripts that might damage someone’s computer. As a result, when you share a FreeCAD file containing parametric objects created with custom Python code, the recipient must also have access to the code used to define those objects. Without it, FreeCAD won’t know how to recalculate or interact with the objects properly.

The simplest way to ensure this is to save the Python code in a macro file. When distributing your FreeCAD file, you can include the macro alongside it. Alternatively, you can share the macro on the FreeCAD macros repository, allowing others to easily download and use it. This approach ensures that your custom parametric objects remain functional on other systems while maintaining security best practices.

Below, we will do a small exercise, building a parametric object that is a simple parametric rectangular face. More complex examples are available on the parametric object example and in the FreeCAD source code itself.

We will give our object two properties: Length and Width, which we will use to construct a rectangle. Then, since our object will already have a pre-built Placement property (all geometric objects have one by default, no need to add it ourselves), we will displace our rectangle to the location/rotation set in the Placement, so the user will be able to move the rectangle anywhere by editing the Placement property.

class ParametricRectangle:

    def __init__(self,obj):
        obj.Proxy = self
        obj.addProperty("App::PropertyFloat", "Length")
        obj.addProperty("App::PropertyFloat", "Width")

    def execute(self, obj):
        # We need to import the FreeCAD module here too, because we might be running out of the Console
        # (in a macro, for example) where the FreeCAD module has not been imported automatically:
        import FreeCAD
        import Part

        # First we need to make sure the values of Length and Width are not 0
        # otherwise Part.LineSegment will complain that both points are equal:
        if (obj.Length == 0) or (obj.Width == 0):
            # If yes, exit this method without doing anything:
            return

        # We create 4 points for the 4 corners:
        v1 = FreeCAD.Vector(0, 0, 0)
        v2 = FreeCAD.Vector(obj.Length, 0, 0)
        v3 = FreeCAD.Vector(obj.Length,obj.Width, 0)
        v4 = FreeCAD.Vector(0, obj.Width, 0)

        # We create 4 edges:
        e1 = Part.LineSegment(v1, v2).toShape()
        e2 = Part.LineSegment(v2, v3).toShape()
        e3 = Part.LineSegment(v3, v4).toShape()
        e4 = Part.LineSegment(v4, v1).toShape()

        # We create a wire:
        w = Part.Wire([e1, e2, e3, e4])

        # We create a face:
        f = Part.Face(w)

        # All shapes have a Placement too. We give our shape the value of the placement
        # set by the user. This will move/rotate the face automatically.
        f.Placement = obj.Placement

        # All done, we can attribute our shape to the object!
        obj.Shape = f

Instead of pasting the above code in the Python console, we'd better save it somewhere, so we can reuse and modify it later. For example in a new macro (menu Macro -> Macros -> Create). Name it, for example, "ParamRectangle". However, FreeCAD macros are saved with a .FCMacro extension, which Python doesn't recognize when using import. So, before using the above code, we will need to rename the ParamRectangle.FCMacro file to ParamRectangle.py. This can be done simply from your file explorer, by navigating to the Macros folder indicated in menu Tools -> Macros.

Once that is done, we can now do this in the Python Console:

import ParamRectangle

By exploring the contents of ParamRectangle, we can verify that it contains our ParametricRectangle class.

To create a new parametric object using our ParametricRectangle class, we will use the following code. Observe that we use Part::FeaturePython instead of Part::Feature that we have been using in the previous chapters (The Python version allows to define our own parametric behaviour):

myObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Rectangle")
ParamRectangle.ParametricRectangle(myObj)
myObj.ViewObject.Proxy = 0 # This is mandatory unless we code the ViewProvider too.
FreeCAD.ActiveDocument.recompute()

Here is a quick breakdown of the previous commands:

  • myObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Rectangle"): Creates a new Part::FeaturePython object named Rectangle in the active FreeCAD document. This object is specifically designed for custom parametric behavior, allowing Python-defined logic to manage its properties and behavior.
  • ParamRectangle.ParametricRectangle(myObj): Initializes the object by associating it with the ParametricRectangle class from the ParamRectangle module or script. This links the custom Python-defined logic to the object, enabling it to act as a parametric object.
  • myObj.ViewObject.Proxy = 0: Resets the ViewObject.Proxy attribute to 0, ensuring that the object uses FreeCAD’s default view handling. This step is required unless you define a custom ViewProvider to manage the visual representation of the object.
  • FreeCAD.ActiveDocument.recompute(): Recomputes the document to update the geometry and reflect changes in the FreeCAD graphical interface, making the new object fully visible and functional

Nothing will appear on screen just yet, because the Length and Width properties are 0, which will trigger our "do-nothing" condition inside execute. We just need to change the values of Length and Width, and our object will magically appear and be recalculated on the fly.

Of course, it would be tedious to have to type these 4 lines of Python code each time we want to create a new parametric rectangle. A very simple way to solve this is placing the 4 lines above inside our ParamRectangle.py file, at the end, after the end of the ParametricRectange class (We can do this from the Macro editor).

Now, when we type import ParamRectangle, a new parametric rectangle will automatically be created. Even better, we can add a toolbar button that will do just that:

  • Open menu Tools -> Customize
  • Under the "Macros" tab, select our ParamRectangle.py macro, fill in the details as you wish, and press "Add":

  • Under the Toolbars tab, create a new custom toolbar in the workbench of your choice (or globally), select your macro and add it to the toolbar:

  • That's it, we now have a new toolbar button which, when clicked, will create a parametric rectangle.

Remember, if you want to distribute files created with this new tool to other people, they must have the ParamRectangle.py macro installed on their computers too.

Read more

  • The FreeCAD macros repository
  • Parametric object example
  • More examples in the FreeCAD code


Creating and manipulating geometry
Creating interface tools
Manual start

This page is retrieved from https://wiki.freecad.org/Manual:Creating_parametric_objects

Get in touch!
Forum GitHub Mastodon Matrix IRC Gitter.im Discord Reddit Twitter Facebook LinkedIn

© The FreeCAD Team. Homepage image credits (top to bottom): ppemawm, r-frank, epileftric, regis, rider_mortagnais, bejant.

This project is supported by: , KiCad Services Corp. and other sponsors

GitHubImprove this page on GitHub