gtalarico / revitpythonwrapper

Python Wrapper for the Revit API
134 stars 32 forks source link

Add parameters display value to rpw.db.Parameter class #19

Closed CyrilWaechter closed 7 years ago

CyrilWaechter commented 7 years ago

Hello, I tried to used rpw.db.Parameter in my last script but I was unable to retrieve a suitable value as it was intend to be human readable. Here is a case : When you retrieve value from BuiltInParameter.VIEWER_VOLUME_OF_INTEREST_CROP storage type is ElementId which is not human readable. When you print it or pass in a str() function, it return a number or -1. In the script it is used to batch rename views, so I need a human readable value.

Do you find relevant to add a method display_value or alike in rpw.db.Parameter class ? If yes. Do you want me to send a pull request ?

gtalarico commented 7 years ago

Hi @CyrilWaechter Thanks for the suggestion, I am intrigued by it.

Given this simple example:

>>> e = rpw.db.Element(SomeRoom)
<rpw:Room % ..Architecture.Room | number:64 name:PRIVATE OFFICE id:229129>
>>> e.parameters['Level']
<rpw:Parameter % ..DB.Parameter | name:Level value:3616>
>>> e.parameters['Level'].type
<type 'ElementId'>
>>> e.parameters['Level'].value
<Autodesk.Revit.DB.ElementId object at 0x0000000000002E7D [3616]>

Can you show an example in code of what you are proposing? (as if you were writing an example or explanation for how to use the method) If Element is retrieved, which property of that element is shown (type?)

ps: this also made me realize parameter repr should include storage type: https://github.com/gtalarico/revitpythonwrapper/issues/20

CyrilWaechter commented 7 years ago

@gtalarico Function is used at line 114 in my script. The best if you want a concrete example is to install the extension I'm working on and use ViewRename script. If you transform it to be a method of rpw.db.Parameter, it would looks like :

def display_value(self, default=""):
    """
    Get human readable value of the parameter. You can use fore example to batch rename views, families etc.
    depending on their parameter values.
    >>> view.parameters.builtins[Revit.DB.BuiltInParameter.VIEWER_VOLUME_OF_INTEREST_CROP].display_value
    "Zone 1"
    # or "Z1" or "Z2" depending on your view scope box name
    :type default: str
    :param default: default value if no suitable value found
    :return: suitable display value (string) or default value
    """
    param = self.__revit__object
    if not param.HasValue:
        return default
    elif param.Value is None:
        return default
    elif param.StorageType == StorageType.String:
        return param.AsString()
    elif param.AsValueString() is not None:
        return param.AsValueString()
    else:
        return default
gtalarico commented 7 years ago

For string-like values, I have something similar to this here: https://github.com/gtalarico/revitpythonwrapper/blob/master/rpw/db/parameter.py#L236

But as we discussed before, if the storage type is Element, you will only get id. See suggestion below.

>>> wall = rpw.db.Element(SomeWallElement)
>>> for p in wall.parameters.all:
...     print(p) 
<rpw:Parameter % ..DB.Parameter | name:Category value:-2000011>
<rpw:Parameter % ..DB.Parameter | name:Image value:-1>
<rpw:Parameter % ..DB.Parameter | name:Top Constraint value:-1>
<rpw:Parameter % ..DB.Parameter | name:Design Option value:-1>
<rpw:Parameter % ..DB.Parameter | name:Top Offset value:0.0>
<rpw:Parameter % ..DB.Parameter | name:Phase Demolished value:-1>
<rpw:Parameter % ..DB.Parameter | name:Type Id value:1557>
<rpw:Parameter % ..DB.Parameter | name:Unconnected Height value:20.0>
<rpw:Parameter % ..DB.Parameter | name:Related to Mass value:0>
<rpw:Parameter % ..DB.Parameter | name:Enable Analytical Model value:0>
<rpw:Parameter % ..DB.Parameter | name:Top Extension Distance value:0.0>
<rpw:Parameter % ..DB.Parameter | name:Category value:-2000011>
<rpw:Parameter % ..DB.Parameter | name:Type Name value:None>
<rpw:Parameter % ..DB.Parameter | name:Type value:1557>
<rpw:Parameter % ..DB.Parameter | name:Comments value:None>
<rpw:Parameter % ..DB.Parameter | name:Base is Attached value:0>
<rpw:Parameter % ..DB.Parameter | name:Structural Usage value:0>
<rpw:Parameter % ..DB.Parameter | name:Length value:7.5>
<rpw:Parameter % ..DB.Parameter | name:Top is Attached value:0>
<rpw:Parameter % ..DB.Parameter | name:Mark value:None>
<rpw:Parameter % ..DB.Parameter | name:Base Extension Distance value:0.0>
<rpw:Parameter % ..DB.Parameter | name:Family and Type value:1557>
<rpw:Parameter % ..DB.Parameter | name:Volume value:100.0>
<rpw:Parameter % ..DB.Parameter | name:Location Line value:0>
<rpw:Parameter % ..DB.Parameter | name:Family Name value:None>
<rpw:Parameter % ..DB.Parameter | name:Structural value:0>
<rpw:Parameter % ..DB.Parameter | name:Phase Created value:3>
<rpw:Parameter % ..DB.Parameter | name:Base Offset value:0.0>
<rpw:Parameter % ..DB.Parameter | name:Room Bounding value:1>
<rpw:Parameter % ..DB.Parameter | name:Family value:1557>
<rpw:Parameter % ..DB.Parameter | name:Area value:150.0>
<rpw:Parameter % ..DB.Parameter | name:Base Constraint value:1526>
>>> 

Current Behavior

>>> p 
<rpw:Parameter % ..DB.Parameter | name:Base Constraint value:1526>  # display value is ElementId
>>> p.value
<Autodesk.Revit.DB.ElementId object at 0x000000000000021A [1526]>
>>> p.type
<type 'ElementId'>
>>> p.AsValueString()
'Level 1'
>>> 

Proposed Behavior

>>> p
<rpw:Parameter % ..DB.Parameter | name:Base Constraint value:1526 value_string: 'Level 1'>
# us value_string, as that maps to Revit's terminology, making it easier to know whats happening behind the scenes
>>> p.value
<Autodesk.Revit.DB.ElementId object at 0x000000000000021A [1526]>
>>> p.type
<type 'ElementId'>
>>> p.value_string
'Level 1'
>>> p.value_string == p.AsValueString()
True

Does that make sense? Would it help with what you are trying to achieve?

>>> wall = rpw.db.Element(s0)
>>> for p in wall.parameters.all:
...     print(p)
... 
<rpw:Parameter % ..DB.Parameter | value_string:No storage_type:<type 'int'> name:Related to Mass value:0>
<rpw:Parameter % ..DB.Parameter | value_string:Unconnected storage_type:<type 'ElementId'> name:Top Constraint value:-1>
<rpw:Parameter % ..DB.Parameter | value_string:None storage_type:<type 'str'> name:Mark value:None>
<rpw:Parameter % ..DB.Parameter | value_string:Level 1 storage_type:<type 'ElementId'> name:Base Constraint value:1526>
<rpw:Parameter % ..DB.Parameter | value_string:No storage_type:<type 'int'> name:Enable Analytical Model value:0>
<rpw:Parameter % ..DB.Parameter | value_string:0' - 0" storage_type:<type 'float'> name:Base Extension Distance value:0.0>
<rpw:Parameter % ..DB.Parameter | value_string:1557 storage_type:<type 'ElementId'> name:Type Id value:1557>
<rpw:Parameter % ..DB.Parameter | value_string:Wall 1 storage_type:<type 'ElementId'> name:Type value:1557>
<rpw:Parameter % ..DB.Parameter | value_string:<None> storage_type:<type 'ElementId'> name:Image value:-1>
<rpw:Parameter % ..DB.Parameter | value_string:0' - 0" storage_type:<type 'float'> name:Top Offset value:0.0>
<rpw:Parameter % ..DB.Parameter | value_string:None storage_type:<type 'str'> name:Type Name value:None>
<rpw:Parameter % ..DB.Parameter | value_string:None storage_type:<type 'str'> name:Family Name value:None>
<rpw:Parameter % ..DB.Parameter | value_string:100.00 CF storage_type:<type 'float'> name:Volume value:100.0>
<rpw:Parameter % ..DB.Parameter | value_string:-1 storage_type:<type 'ElementId'> name:Design Option value:-1>
<rpw:Parameter % ..DB.Parameter | value_string:20' - 0" storage_type:<type 'float'> name:Unconnected Height value:20.0>
<rpw:Parameter % ..DB.Parameter | value_string:Walls storage_type:<type 'ElementId'> name:Category value:-2000011>
<rpw:Parameter % ..DB.Parameter | value_string:Non-bearing storage_type:<type 'int'> name:Structural Usage value:0>
<rpw:Parameter % ..DB.Parameter | value_string:Yes storage_type:<type 'int'> name:Room Bounding value:1>
<rpw:Parameter % ..DB.Parameter | value_string:Basic Wall storage_type:<type 'ElementId'> name:Family value:1557>
<rpw:Parameter % ..DB.Parameter | value_string:150.00 SF storage_type:<type 'float'> name:Area value:150.0>
<rpw:Parameter % ..DB.Parameter | value_string:Walls storage_type:<type 'ElementId'> name:Category value:-2000011>
<rpw:Parameter % ..DB.Parameter | value_string:New Construction storage_type:<type 'ElementId'> name:Phase Created value:3>
<rpw:Parameter % ..DB.Parameter | value_string:None storage_type:<type 'str'> name:Comments value:None>
<rpw:Parameter % ..DB.Parameter | value_string:Wall Centerline storage_type:<type 'int'> name:Location Line value:0>
<rpw:Parameter % ..DB.Parameter | value_string:7' - 6" storage_type:<type 'float'> name:Length value:7.5>
<rpw:Parameter % ..DB.Parameter | value_string:0' - 0" storage_type:<type 'float'> name:Base Offset value:0.0>
<rpw:Parameter % ..DB.Parameter | value_string:No storage_type:<type 'int'> name:Top is Attached value:0>
<rpw:Parameter % ..DB.Parameter | value_string:None storage_type:<type 'ElementId'> name:Phase Demolished value:-1>
<rpw:Parameter % ..DB.Parameter | value_string:No storage_type:<type 'int'> name:Base is Attached value:0>
<rpw:Parameter % ..DB.Parameter | value_string:Basic Wall: Wall 1 storage_type:<type 'ElementId'> name:Family and Type value:1557>
<rpw:Parameter % ..DB.Parameter | value_string:No storage_type:<type 'int'> name:Structural value:0>
<rpw:Parameter % ..DB.Parameter | value_string:0' - 0" storage_type:<type 'float'> name:Top Extension Distance value:0.0>
gtalarico commented 7 years ago

Also interesting that some type:ElementId parameters have helpful AsStringValue and others don't:

Also seems that for AsValueString, Element is retrieved from ElementId, and if the element has a .Name property, that's used.

tuples below are parameters attributes: (name, HasValue, AsStringValue, type, value)

Example where AsStringValue is just elementId: ('Type Id', True, '12420', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BD [12420]>)

Example where AsStringValue is an attribute of the the elementId, in this case Category.Name ('Category', True, 'Furniture', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B4 [-2000080]>)

>>> for i in [(p.HasValue, p.AsValueString(), p.type, p.value) for p in e.parameters.all]:
...     print(i)
... 
>>> for i in [(p.name, p.HasValue, p.AsValueString(), p.type, p.value) for p in e.parameters.all]:
...     print(i)
... 
('Category', True, 'Furniture', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B4 [-2000080]>)
('Host Id', True, '-1', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B5 [-1]>)
('Category', True, 'Furniture', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B6 [-2000080]>)
('Moves With Nearby Elements', True, 'No', <type 'int'>, 0)
('Type Name', False, None, <type 'str'>, None)
('Level', True, 'Level 1', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B7 [1526]>)
('Level', True, 'Level 1', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B8 [1526]>)
('Family and Type', True, 'desk: 72" x 36"', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012B9 [12420]>)
('Comments', False, None, <type 'str'>, None)
('Volume', True, '20.33 CF', <type 'float'>, 20.334056712959185)
('Phase Created', True, 'New Construction', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BA [3]>)
('Image', False, '<None>', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BB [-1]>)
('Mark', False, None, <type 'str'>, None)
('Type', True, '72" x 36"', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BC [12420]>)
('Type Id', True, '12420', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BD [12420]>)
('Area', True, '57.47 SF', <type 'float'>, 57.468115801547569)
('Family', True, 'desk', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BE [12420]>)
('Family Name', False, None, <type 'str'>, None)
('Phase Demolished', True, 'None', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012BF [-1]>)
('Design Option', True, '-1', <type 'ElementId'>, <Autodesk.Revit.DB.ElementId object at 0x00000000000012C0 [-1]>)
('Host', True, None, <type 'str'>, 'Level : Level 1')
CyrilWaechter commented 7 years ago

I'm not sure : If p.value_string == p.AsValueString() then no, it not usefull. if p.value_string == p.AsValueString() or p.value_string == p.AsString() then yes. Because if StorageType is String then method AsValueString() return None. I was talking about a function that always return a valid string from AsValueString() or AsString().

gtalarico commented 7 years ago

That seems reasonable. I will add what you suggested as useful.