Page 1 of 2

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

Posted: Fri Jan 24, 2020 2:01 am
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)

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

Posted: Fri Jan 24, 2020 4:44 am
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)

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

Posted: Fri Jan 24, 2020 12:20 pm
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).

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

Posted: Sat Jan 25, 2020 9:41 pm
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?

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

Posted: Sat Jan 25, 2020 10:04 pm
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.

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

Posted: Sat Jan 25, 2020 10:09 pm
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.

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

Posted: Sat Jan 25, 2020 10:25 pm
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 :) )

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

Posted: Sat Jan 25, 2020 10:39 pm
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.

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

Posted: Sat Jan 25, 2020 10:41 pm
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)

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

Posted: Sat Jan 25, 2020 11:03 pm
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.