What's the easy way to make feature python objects?

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
llll
Posts: 173
Joined: Fri Nov 12, 2021 1:56 am

What's the easy way to make feature python objects?

Post by llll »

I would love some clarity right now on how to solve this problem with existing codebase... I need help to understand how to approach this.

Please is it possible someone can share an example of using existing code to make feature python objects? For example, using Draft WB\draftobjects\array.py (or any tool) - already written code - and adapting it into a feature python object?

It seems like all of the code is already there one just needs to know how to restructure it into a FPO to allow updating all settings and properties with python.

Please, an example would be really enlightening


Help greatly appreciated
:?
drmacro
Veteran
Posts: 9010
Joined: Sun Mar 02, 2014 4:35 pm

Re: What's the easy way to make feature python objects?

Post by drmacro »

Have a look at the WireFilter and other code available in Addon manager.
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
User avatar
onekk
Veteran
Posts: 6222
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: What's the easy way to make feature python objects?

Post by onekk »

Code: Select all

"""Test FeaturePython Object for Placement sharing.

file: Fpobj_pl.py

Author: Carlo Dormeletti
Copyright: 2022
Licence: LGPL
"""

from PySide2 import QtCore  # noqa

import FreeCAD
import FreeCADGui
from FreeCAD import Vector, Matrix  # noqa

import Part  # noqa


def get_type_prop():
    """Return a list of object properties. depending on Obj_Type."""
    prop_dict = {
        "Type_A": {
            "TA_NameExt":
            ["str", "Type_A Data", "Name of the Object", ""],
        },
        "Type_B": {
            "TB_Transparency":
            ["int", "Type_B Data", "Transparency", 100]
        },
        "Type_C": {
            "TC_Direction":
            ["lst", "Type_C Data", "Direction", ["xy", "xz", "zy"]]
        }
    }

    return prop_dict


def get_other_prop(obj_type):
    """Return a list of property names not in obj_type."""
    prop_dict = get_type_prop()
    exc_prop = []
    good_prop = prop_dict[obj_type].keys()
    # print(f"good: {good_prop}")
    for key, value in prop_dict.items():
        for sub_key in value.keys():
            if sub_key not in good_prop:
                exc_prop.append(sub_key)

    return exc_prop


def get_obj_types():
    """Return alist of objects types."""
    prop_dict = get_type_prop()
    prop_list = ["None"]
    for k in prop_dict.keys():
        prop_list.append(k)

    return prop_list


class FP_Object:
    """Create an FP_object."""

    def __init__(self, obj, sel):
        """Add properties."""
        obj.addProperty(
            "App::PropertyLink", "SourceObject", "FP_Prop",
            "Source Object").SourceObject = sel[0].Object

        obj.addProperty(
            "App::PropertyEnumeration", "Obj_Type", "FP_Prop",
            "Object Type").Obj_Type = get_obj_types()

        obj.Proxy = self

    def onChanged(self, obj, prop):
        """Execute when a property has changed."""
        print(f"obj: {obj}, prop: {prop}")
        if prop == "Obj_Type":
            self.set_properties(obj, obj.Obj_Type)
        elif prop == "SourceObject" and obj.SourceObject:
            if not obj.SourceObject.Placement.Matrix == obj.Placement.Matrix:
                obj.Placement = obj.SourceObject.Placement
            # obj.Placement = obj.SourceObject.Placement

    def execute(self, obj):
        """Create object."""
        ch_obj = obj.SourceObject
        obj.Shape = ch_obj.Shape
        ch_obj.ViewObject.Visibility = False
        if not obj.SourceObject.Placement.Matrix == obj.Placement.Matrix:
            obj.Placement = obj.SourceObject.Placement

        obj.Placement = obj.SourceObject.Placement


    def set_properties(self, obj, obj_type):
        """Set object properties based on dictionary."""
        # First remove properties of other obj_type if there is any
        self.remove_other_props(obj, obj_type)

        obj_props = get_type_prop()[obj_type]
        # print(obj_props)

        for key, value in obj_props.items():
            # print(f"{key}: Value: {value}")
            prop_dict = {
                "str": "App::PropertyString",
                "int": "App::PropertyInteger",
                "bol": "App::PropertyBool",
                "lst": "App::PropertyEnumeration"}

            if value[0] in prop_dict.keys():
                obj.addProperty(
                    prop_dict[value[0]],
                    key, value[1], value[2])
                setattr(obj, key, value[3])

        return


    def remove_other_props(sel, obj, obj_type):
        """Remove property not in obj_type."""
        p_list = get_other_prop(obj_type)
        # print(f"Bad: {p_list}")
        for prop_name in p_list:
            if prop_name in obj.PropertiesList:
                obj.removeProperty(prop_name)


def get_sel_objects(sel):
    """Return selected objects as list."""
    o_list = []
    for obj in sel:
        o_list.append(
            FreeCAD.ActiveDocument.getObject(obj.ObjectName))

    return o_list


class ViewProvider_FP(object):
    """ViewProvider Object."""

    def __init__(self, vobj):
        """Init things."""
        self.Object = vobj.Object
        vobj.Proxy = self


    def claimChildren(self):
        """Return objects that will be placed under it in the tree view."""
        return [self.Object.SourceObject]


    def __getstate__(self):
        """Get state."""
        return None

    def __setstate__(self, _state):
        """Set state."""
        return None


def makeFPObject(sel):
    """Command."""
    if FreeCAD.ActiveDocument is None:
        doc = FreeCAD.newDocument("FP_Doc")
        FreeCAD.setActiveDocument("FP_Doc")
    else:
        doc = FreeCAD.ActiveDocument

    obj = doc.addObject("Part::FeaturePython", "FP_Object")
    obj.Label = "FP_Object"
    FP_Object(obj, sel)

    ViewProvider_FP(obj.ViewObject)

    doc.recompute()


# Execute the action


selection = FreeCADGui.Selection.getSelectionEx()

l_sen = len(selection)

if l_sen != 1:
    msg = f"You have selected <b>{l_sen}</b> shape(s)<br>"
    msg += "You must select only 1 shape <br>"
    print(msg)
else:
    makeFPObject(selection)

Here a test code for a simple object that take a selected object and assign to the new FPO.

Same code placed also in the file attached

It could be a starting point.

The part that create the object must go in the execute(), so if you want to make anew object place code here.

If you are more precise in what you want to achieve, as example:
I want to create a cube with some properties
Probably we could be more precise in the code, or alternatively you could try to modify the above code and post a revised version and we could help you to achieve yours goals..

Regards

Carlo D.

Fpobj_pl.py
(4.97 KiB) Downloaded 8 times
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
Post Reply