How to Constrain Custom Length Property With Lower and Upper Bound?

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
gbroques
Posts: 167
Joined: Thu Jan 23, 2020 3:28 am
Location: St. Louis, Missouri

How to Constrain Custom Length Property With Lower and Upper Bound?

Post by gbroques »

I have a scripted object with custom length property using App::PropertyLength, and I'd like to set a lower and upper bound.

According to this wiki page:
A complete list of property attributes can be seen in the PropertyStandard C++ header file. For instance, if you want to allow the user to enter only a limited range of values (e.g. using PropertyIntegerConstraint), in Python you will assign a tuple containing not only the property value, but also the lower and upper limit as well as the stepsize, as below:

prop = (value, lower, upper, stepsize)
Here is some code I'm trying:

Code: Select all

class SomeObject:

    def __init__(self, obj):
        self.Type = 'SomeObject'

        obj.Proxy = self

        # Length property
        obj.addProperty('App::PropertyLength', 'Length', 'Base', 'Length tooltip')
        obj.Length = (300, 100, 1000, 1)  # I want a length property that defaults to 300, and can be between 100 - 1000 with a step-size of 1.
I get the following error:

Code: Select all

  File "/home/g/Projects/ose-universal-axis-macro/universal_axis/universal_axis_model.py", line 26, in __init__
    obj.Length = (300, 100, 1000, 1) 
<type 'exceptions.AttributeError'>: Attribute (Name: Length) error: 'wrong type as quantity: tuple'
I see App::PropertyLength extends App::PropertyQuantityConstraint. Do I need to use some other property type to achieve the desired effect?


FreeCAD version information:
OS: Linux
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.16093 (Git)
Build type: Unknown
Branch: master
Hash: 690774c0effe4fd7b8d2b5e2fb2b8c8d145e21ce
Python version: 2.7.12
Qt version: 4.8.7
Coin version: 4.0.0a
OCC version: 7.0.0
Locale: English/UnitedStates (en_US)
Last edited by gbroques on Sat Jan 25, 2020 9:53 pm, edited 1 time in total.
vocx
Veteran
Posts: 5197
Joined: Thu Oct 18, 2018 9:18 pm

Re: Constrain custom length property with lower and upper bound?

Post by vocx »

gbroques wrote: Fri Jan 24, 2020 2:01 am Python version: 2.7.12
Qt version: 4.8.7
You should use Python 3 and Qt5, as Python 2 and Qt4 are obsolete.

As for your particular issue, I went to PropertyStandard.h as it was mentioned in your post.

https://github.com/FreeCAD/FreeCAD/blob ... #L544-L552

Code: Select all

    /** setting the boundaries
     * This sets the constraint struct. It can be dynamcly 
     * allocated or set as an static in the class the property
     * blongs to:
     * \code
     * const Constraints percent = {0.0,100.0,1.0}
     * \endcode
     */
    void setConstraints(const Constraints* sConstrain);
Maybe you need to

Code: Select all

obj.Length.setConstraints(lower, upper, step)
Always add the important information to your posts if you need help. Also see Tutorials and Video tutorials.
To support the documentation effort, and code development, your donation is appreciated: liberapay.com/FreeCAD.
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: Constrain custom length property with lower and upper bound?

Post by DeepSOIC »

vocx wrote: Fri Jan 24, 2020 4:44 am Maybe you need to

Code: Select all

obj.Length.setConstraints(lower, upper, step)
Unfortunately, .Length attribute returns a Quantity (pretty much just a number). It does not return a reference to the property object; as far as I know, nothing does, and it would be really nice to have someone make that happen.

I want to do it, but I can't now (I have too much other stuff to worry about).
User avatar
gbroques
Posts: 167
Joined: Thu Jan 23, 2020 3:28 am
Location: St. Louis, Missouri

Re: Constrain custom length property with lower and upper bound?

Post by gbroques »

Both App::PropertyIntegerConstraint and App::PropertyFloatConstraint (defined in PropertyStandard.h) work when setting bounds like so:

Code: Select all

        x = obj.addProperty('App::PropertyFloatConstraint', 'Length', 'Base', 'tooltip')
        obj.Length = (300.0, 100.0, 1000.0, 1.0)
DeepSOIC is right. When using App::PropertyLength and accessing the property (i.e. obj.Length), you get a Quantity object.

I'm assuming any property extending PropertyQuantityConstraint would also suffer from not being able to set bounds:
  • PropertyLength
  • PropertyArea
  • PropertyVolume
  • PropertyAngle
DeepSOIC, can you propose how the Python API might look, and provide guidance to how one could accomplish this?

I'm new the FreeCAD codebase, but familiar with C++ / Python, and willing to get my hands dirty.

Personally, I think the Python API for setting bounds of all properties should be similar to avoid confusion.

--------------------------

Unless someone knows of a different way to have a property with units and custom bounds?
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: How to Constrain Custom Length Property With Lower and Upper Bound?

Post by DeepSOIC »

gbroques wrote: Sat Jan 25, 2020 9:41 pm DeepSOIC, can you propose how the Python API might look
Like so:

Code: Select all

obj.Property("Length").UpperLimit = somethingsomething
That is, .Property("Length") should give access to property object.

As for bindings, it is tricky in that the lifetime of property objects is managed by C++ in a way that is somewhat incompatible with python. The easiest solution (IMO) would be to have a PropertyRef py-binding object, that holds a python reference to host object + the name of the property, and looks up the actual property every time something is accessed. It's slower than it can be, but I think it shouldn't be a big deal.
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: How to Constrain Custom Length Property With Lower and Upper Bound?

Post by DeepSOIC »

a viable alternative is to copy the way it is done for DocumentObject.

DocumentObject creates a py twin, and has a reference to the twin, keeping it alive as long as the object is alive. Then, when the object is deleted, it sets the twin into a zombie state, where accessing anything raises an error. And releases the reference. If there are no references remaining, the twin is deleted. But if there are, the twin remains in this zombie state.
User avatar
gbroques
Posts: 167
Joined: Thu Jan 23, 2020 3:28 am
Location: St. Louis, Missouri

Re: How to Constrain Custom Length Property With Lower and Upper Bound?

Post by gbroques »

DeepSOIC wrote: Sat Jan 25, 2020 10:04 pm Like so:

Code: Select all

obj.Property("Length").UpperLimit = somethingsomething
That is, .Property("Length") should give access to property object.
What you're proposing is a breaking change, right? Shouldn't we try to minimize breaking changes?

What about a new property called App::PropertyLengthConstraint that works as you suggest, and gives a reference to the property object?

(Also, thanks for the pointers on the possible implementation :) )
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: How to Constrain Custom Length Property With Lower and Upper Bound?

Post by DeepSOIC »

gbroques wrote: Sat Jan 25, 2020 10:25 pm What you're proposing is a breaking change, right?
No. .Length attribute remains, and still returns the value, not the object.
User avatar
DeepSOIC
Veteran
Posts: 7896
Joined: Fri Aug 29, 2014 12:45 am
Location: used to be Saint-Petersburg, Russia

Re: How to Constrain Custom Length Property With Lower and Upper Bound?

Post by DeepSOIC »

gbroques wrote: Sat Jan 25, 2020 10:25 pm What about a new property called App::PropertyLengthConstraint that works as you suggest, and gives a reference to the property object?
What about all other properties, then? There's more useful stuff about having the object. One example is a "touched" flag, which is only available in c++ so far (I think)
User avatar
gbroques
Posts: 167
Joined: Thu Jan 23, 2020 3:28 am
Location: St. Louis, Missouri

Re: How to Constrain Custom Length Property With Lower and Upper Bound?

Post by gbroques »

DeepSOIC wrote: Sat Jan 25, 2020 10:39 pm No. .Length attribute remains, and still returns the value, not the object.
Gotcha. I was misunderstanding.

You're saying to add a new mechanism to get the entire property object.

Maybe a new Property attribute on Part::PartFeature or parent class of it.

There is a getPropertyByName method on Part::PartFeature already. So naming it Property might be confusing if we don't properly distinguish the two.

---
DeepSOIC wrote: Sat Jan 25, 2020 10:41 pm What about all other properties, then? There's more useful stuff about having the object. One example is a "touched" flag, which is only available in c++ so far (I think)
Yes, you have a good point. There will likely be other useful things on property object we want access to like the touched flag.
Post Reply