Source code for revitron.parameter

#-*- coding: UTF-8 -*-
""" 
Besides the ``element`` and the ``filter`` submodules, 
this submodule is one of the most elementary submodules of the **Revitron** package.
It contains all classes related to parameters, built-in parameters and value providers.
"""
import re
import numbers


[docs]class Parameter: """ A wrapper class for interacting with element parameters. Note: In most cases it is not required to actually create a **Parameter** class instance in order to access paramter values of a given element. The fastest way of getting or setting parameter values is using the ``_(element).get('parameter')`` shortcut `function <revitron.html#working-with-elements>`_ or an instance of the :doc:`revitron.element` class. """
[docs] def __init__(self, element, name): """ Init a new parameter instance. Getting a parameter by name visible to the user:: value = revitron.Parameter(element, 'parameterName').get() Or the short version:: value = _(element).get('parameterName') To be **language independent** it is possible to get a parameter value by its **built-in** parameter name like for example the view scale:: scale = _(view).get('VIEW_SCALE') Args: element (object): Revit element name (string): The parameter name or the name of a built-Iin parameter """ self.element = element self.name = name self.parameter = element.LookupParameter(name) if not self.exists(): try: import revitron self.parameter = element.get_Parameter( getattr(revitron.DB.BuiltInParameter, name) ) except: pass
[docs] def exists(self): """ Checks if a parameter exists. Returns: boolean: True if existing """ return (self.parameter != None)
[docs] def hasValue(self): """ Checks if parameter has a value. Returns: boolean: True if the parameter has a value """ if self.exists(): return (self.parameter.HasValue)
[docs] def get(self): """ Return the parameter value. Note: As mentioned above, the fastest way of getting a parameter value is to use the `get <revitron.element.html#revitron.element.Element.get>`_ method of the ``revitron.Element`` class. Returns: mixed: The value """ if self.exists(): storageType = str(self.parameter.StorageType) else: storageType = 'String' switcher = { 'String': self.getString, 'ValueString': self.getValueString, 'Integer': self.getInteger, 'Double': self.getDouble, 'ElementId': self.getElementId } value = switcher.get(storageType) return value()
[docs] def getString(self): """ Return the parameter value as string. Returns: string: The value """ if self.hasValue(): return self.parameter.AsString() return ''
[docs] def getValueString(self): """ Return the parameter value as value string. Returns: string: The value """ if self.hasValue(): return self.parameter.AsValueString() return ''
[docs] def getInteger(self): """ Return the parameter value as integer. Returns: integer: The value """ if self.hasValue(): return self.parameter.AsInteger() return 0
[docs] def getDouble(self): """ Return the parameter value as double. Returns: double: The value """ if self.hasValue(): return self.parameter.AsDouble() return 0.0
[docs] def getElementId(self): """ Return the parameter value as ElementId. Returns: object: The value """ if self.hasValue(): return self.parameter.AsElementId() return 0
[docs] def set(self, value, paramType=False): """ Set a parameter value for an element. The parameter will be automatically created if not existing. The parameter type can be specified. If not type is given, it will be determined automatically in case of text, integer or float values. Note: As mentioned above, the fastest way of setting a parameter value is to use the `set <revitron.element.html#revitron.element.Element.set>`_ method of the ``revitron.Element`` class. Example:: _(element).set('name', 'value', 'type') Some possible parameter types are: - ``Text`` - ``Integer`` - ``Number`` - ``Length`` - ``Angle`` - ``Material`` - ``YesNo`` - ``MultilineText`` - ``FamilyType`` You can find a list of all types `here <https://www.revitapidocs.com/2019/f38d847e-207f-b59a-3bd6-ebea80d5be63.htm>`_. Args: value (string): The value paramType (string, optional): The `parameter type <https://www.revitapidocs.com/2019/f38d847e-207f-b59a-3bd6-ebea80d5be63.htm>`_ """ if not self.name: return False if not paramType: paramType = 'Text' if isinstance(value, numbers.Integral): paramType = 'Integer' if isinstance(value, float): paramType = 'Number' if self.parameter == None: from revitron import _ if ParameterUtils.bind( self.element.Category.Name, self.name, paramType, _(self.element).isType() ): self.parameter = self.element.LookupParameter(self.name) else: print('Error setting value of parameter "{}"'.format(self.name)) return False if not self.parameter.IsReadOnly: self.parameter.Set(value)
@property def definitionType(self): """ The definition parameter type. Returns: string: The definition parameter type name """ return ParameterUtils.getParameterTypeFromDefinition(self.parameter.Definition) @property def unit(self): """ The displayed unit type of a parameter. Note that since Revit 2021 the preferred return value is of type ``ForgeTypeId``. Returns: mixed: The displayed unit type (ForgeTypeId or DisplayUnitType) """ try: return self.parameter.GetUnitTypeId() except: return self.parameter.DisplayUnitType
[docs]class ParameterUtils: """ A collection of static parameter utilities. """
[docs] @staticmethod def bind(category, paramName, paramType='Text', typeBinding=False): """ Bind a new parameter to a category. Args: category (string): The built-in category paramName (string): The parameter name paramType (string): The parameter type (see `here <https://www.revitapidocs.com/2019/f38d847e-207f-b59a-3bd6-ebea80d5be63.htm>`_) Defaults to "Text". typeBinding (bool): Bind parameter to type instead of instance. Defaults to False. Returns: boolean: Returns True on success and False on error. """ import revitron paramFile = revitron.APP.OpenSharedParameterFile() if paramFile is None: print('Please define a shared parameters file.') return False definition = None # Try to get an existing parameter definition with the given name. for group in paramFile.Groups: definition = group.Definitions.get_Item(paramName) if definition: break group = None # If the definition hasn't been created yet, create it in the REVITRON group. if not definition: group = paramFile.Groups.get_Item('REVITRON') if not group: group = paramFile.Groups.Create('REVITRON') options = ParameterUtils.externalDefinitionCreationOptions( paramName, paramType ) definition = group.Definitions.Create(options) # Try to get the parameter binding for the definition. binding = revitron.DOC.ParameterBindings[definition] # Add the given category to the categories list as the initial item # and try to access currently bound categories to add them as well. # In case the given category is already among the bound categories, # stop the further execution and return False. # In case the category is not bound yet, remove the binding from the parameter # binding map. categories = [revitron.Category(category).get()] try: for _cat in binding.Categories: categories.append(_cat) if _cat.Name == category: return False revitron.DOC.ParameterBindings.Remove(definition) except: pass # Create a new category set and add all categories, the given and the previously bound ones. categorySet = revitron.APP.Create.NewCategorySet() for _cat in categories: categorySet.Insert(_cat) # Create the binding. if typeBinding: binding = revitron.APP.Create.NewTypeBinding(categorySet) else: binding = revitron.APP.Create.NewInstanceBinding(categorySet) revitron.DOC.ParameterBindings.Insert(definition, binding) return True
[docs] @staticmethod def externalDefinitionCreationOptions(paramName, paramType): """ Create proper definition creation options based on a given name and type, that is passed as string. Args: paramName (string): The name of the parameter definition paramType (string): The name of the type Returns: ExternalDefinitionCreationOptions: The ExternalDefinitionCreationOptions object """ import revitron dataType = None try: dataType = getattr(revitron.DB.SpecTypeId, paramType) except: pass try: dataType = getattr(revitron.DB.SpecTypeId.String, paramType) except: pass try: dataType = getattr(revitron.DB.SpecTypeId.Int, paramType) except: pass try: dataType = getattr(revitron.DB.SpecTypeId.Boolean, paramType) except: pass try: dataType = getattr(revitron.DB.SpecTypeId.Reference, paramType) except: pass if dataType: try: return revitron.DB.ExternalDefinitionCreationOptions(paramName, dataType) except: pass try: return revitron.DB.ExternalDefinitionCreationOptions( paramName, getattr(revitron.DB.ParameterType, paramType) ) except: pass
[docs] @staticmethod def getParameterTypeFromDefinition(definition): """ Get the parameter type as string from a definition. Args: definition (object): The parameter definition Returns: string: The name of the type """ try: return definition.ParameterType.ToString() except: pass try: import revitron return revitron.DB.LabelUtils.GetLabelForSpec(definition.GetDataType() ).replace('/', '') except: pass
[docs] @staticmethod def getStorageType(name): """ Get the storage type of a parameter definition by name. Args: name (string): The parameter name Returns: string: The storage type """ from revitron import DOC # Try first project and shared parameters. definition = ParameterUtils._findProjectParameterDefinition(name) if not definition: definition = ParameterUtils._findSharedParameterDefinition(name) if definition: storageType = ParameterUtils._convertParameterTypeToStorageType( ParameterUtils.getParameterTypeFromDefinition(definition) ) if storageType: return storageType try: # Try built-in parameters. return str(DOC.TypeOfStorage[ParameterUtils._findBuiltInParameter(name)]) except: # Fall back to very slow search in all elements. return ParameterUtils._findStorageTypeInElements(name)
@staticmethod def _findProjectParameterDefinition(name): """ Find a custom parameter in a document. Args: name (string): The parameter name Returns: object: The parameter object """ from revitron import DOC it = DOC.ParameterBindings.ForwardIterator() while it.MoveNext(): if it.Key.Name == name: return it.Key return None @staticmethod def _findBuiltInParameter(name): """ Find a built-in parameter by name. Args: name (string): The parameter name Returns: object: The built-in parameter """ from revitron import DB for item in dir(DB.BuiltInParameter): try: bip = getattr(DB.BuiltInParameter, item) if DB.LabelUtils.GetLabelFor(bip) == name: return bip except: pass return None @staticmethod def _findSharedParameterDefinition(name): """ Find a shared parameter definition by name. Args: name (string): The parameter name Returns: object: The shared parameter definition """ from revitron import Filter, DB sharedParameters = Filter().byClass(DB.SharedParameterElement).getElements() for parameter in sharedParameters: definition = parameter.GetDefinition() if name == definition.Name: return definition return None @staticmethod def _convertParameterTypeToStorageType(paramType): """ Convert parameter type to storage type in a map of known types. Note that this map may be incomplete and therefore ``None`` may be returned. Args: paramType (string): The name of the parameter type to be converted Returns: string: The storage type """ typeMap = { 'Angle': 'Double', 'Area': 'Double', 'Currency': 'Double', 'ElectricalPotential': 'Double', 'ElectricalPowerDensity': 'Double', 'HVACAirflow': 'Double', 'HVACAirflowDensity': 'Double', 'HVACAreaDividedByCoolingLoad': 'Double', 'HVACAreaDividedByHeatingLoad': 'Double', 'HVACCoefficientOfHeatTransfer': 'Double', 'HVACCoolingLoad': 'Double', 'HVACCoolingLoadDividedByArea': 'Double', 'HVACFactor': 'Double', 'HVACHeatGain': 'Double', 'HVACHeatingLoad': 'Double', 'HVACHeatingLoadDividedByArea': 'Double', 'HVACRoughness': 'Double', 'HVACTemperature': 'Double', 'HVACThermalMass': 'Double', 'HVACThermalResistance': 'Double', 'Image': 'ElementId', 'Integer': 'Integer', 'Invalid': 'ElementId', 'Length': 'Double', 'Material': 'ElementId', 'MultilineText': 'String', 'Number': 'Double', 'PipingDensity': 'Double', 'PipingPressure': 'Double', 'PipingRoughness': 'Double', 'PipingTemperature': 'Double', 'PipingViscosity': 'Double', 'ReinforcementCover': 'Double', 'Text': 'String', 'URL': 'String', 'Volume': 'Double', 'YesNo': 'Integer' } if paramType in typeMap: return typeMap[paramType] @staticmethod def _findStorageTypeInElements(paramName): """ Find a storage type of a parameter by iterating a list of all elements in a document and testing if an element contains a parameter with a given name. Note: This is a very slow way of finding the correct storage type and should only be used in edge cases where there is no other way of finding out the storage type of a parameter! Args: paramName (string): The name of the parameter Returns: string: The storage type """ from revitron import Filter for element in Filter().getElements(): parameter = element.LookupParameter(paramName) if parameter: return parameter.StorageType.ToString()
[docs]class ParameterNameList: """ A helper class for listing all parameter names in the active document. """
[docs] def __init__(self): """ Inits a new ParameterNameList instance including all parameter names in the document. """ import revitron self.parameters = [] for name in BuiltInParameterNameMap().map: self.parameters.append(name) for param in revitron.Filter().byClass(revitron.DB.SharedParameterElement ).getElements(): self.parameters.append(param.GetDefinition().Name) for param in revitron.Filter().byClass(revitron.DB.ParameterElement ).getElements(): self.parameters.append(param.GetDefinition().Name) self.parameters = sorted(list(set(self.parameters)))
[docs] def get(self): """ Returns the parameter list. Returns: list: The list with all parameters in the document. """ return self.parameters
[docs]class ParameterValueProviders: """ A wrapper for parameter value providers used for filtering elements. """
[docs] def __init__(self, name): """ Inits a new ParameterValueProviders instance by name. Such an instance consists of a list of value providers matching a parameters with a name visible to the user. Note that this list can have more than one value provider, since a parameter name possible matches multiple built-in parameters. Args: name (string): Name """ import revitron self.providers = [] paramIds = [] it = revitron.DOC.ParameterBindings.ForwardIterator() while it.MoveNext(): if it.Key.Name == name: paramIds.append(it.Key.Id) if not paramIds: try: paramIds = BuiltInParameterNameMap().get(name) except: pass for paramId in paramIds: self.providers.append(revitron.DB.ParameterValueProvider(paramId))
[docs] def get(self): """ Returns the list of value providers. Returns: list: The list of value providers """ return self.providers
[docs]class BuiltInParameterNameMap: """ A helper class for mapping lists of built-in parameter names to their representation visible to the user. """
[docs] def __init__(self): """ Inits a new BuiltInParameterNameMap instance. The map is a dictionary where the key is a parameter name that is visible to the user and the value is a list of built-in parameters represented by that name. """ import revitron self.map = dict() for item in dir(revitron.DB.BuiltInParameter): try: bip = getattr(revitron.DB.BuiltInParameter, item) name = revitron.DB.LabelUtils.GetLabelFor(bip) if name not in self.map: self.map[name] = [] self.map[name].append(revitron.DB.ElementId(int(bip))) except: pass
[docs] def get(self, name): """ Return the list of matching built-in parameters for a given name. Args: name (string): The parameter name visible to the user Returns: list: The list of built-in parameter ids """ return self.map[name]
[docs]class ParameterTemplate: """ Create a string based on a parameter template where parameter names are wrapped in :code:`{...}` and get substituted with their value:: This sheet has the number {Sheet Number} It is also possible to get parameter values from the project information instead by wrapping the parameter names in :code:`{%...%}` instead:: This sheet of the project {%Project Name%} has the number {Sheet Number} """
[docs] def __init__(self, element, template, sanitize=True): """ Inits a new ParameterTemplate instance. Args: element (object): A Revit element template (string): A template string sanitize (bool, optional): Optionally sanitize the returned string. Defaults to True. """ import revitron self.projectInfo = revitron.DOC.ProjectInformation self.element = element self.template = template self.sanitize = sanitize
[docs] def reCallback(self, match): """ The callback function used by the ``get()`` method. Args: match (object): The regex match object Returns: string: The processed string """ import revitron parameter = match.group(1) try: match = re.match('^%(.+?)%$', parameter) parameter = match.group(1) string = str(revitron.Element(self.projectInfo).get(parameter)) except: string = str(revitron.Element(self.element).get(parameter)) if self.sanitize: string = revitron.String.sanitize(string) return string
[docs] def render(self): """ Returns the rendered template string. Returns: string: The rendered string """ return re.sub('\{(.+?)\}', self.reCallback, self.template)