From 3f2cad0490f220d3e62d32f99c3357522c6664d9 Mon Sep 17 00:00:00 2001 From: Ryan Schultz Date: Tue, 28 Oct 2025 22:24:40 -0500 Subject: [PATCH] Add suppress_zero_inches parameter to imperial_length formatting function --- .../ifcopenshell-python/selector_syntax.rst | 2 +- .../ifcopenshell/util/selector.py | 35 ++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst index 3dd4456fdc..67f7b792b3 100644 --- a/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst +++ b/src/ifcopenshell-python/docs/ifcopenshell-python/selector_syntax.rst @@ -251,7 +251,7 @@ nest formulas, for example ``concat(title("foo"), lower("Bar"))`` will produce "``int({{value}})``", "``int(3.123)``", "``3``", "Truncates the decimal part of the ``{{value}}``." "``number({{value}}[, {{decimal_separator}}[, {{thousands_separator}}]])``", "``number(1234.56, "","", ""."")``", "``1.234,56``", "Formats {{value}} with an optional custom {{decimal_separator}} and {{thousands_separator}}. The default separators are ``.`` and ``,``." "``metric_length({{value}}, {{precision}}, {{decimals}})``", "``metric_length(3.123, 0.1, 2)``", "``3.10``", "Rounds ``{{value}}`` to the nearest ``{{precision}}`` then displays using a certain amount of decimal places." - "``imperial_length({{value}}, {{precision}}, {{input_unit}}, {{output_unit}})``", "``imperial_length(3.22, 4, ""foot"")``", "``3' - 3 3/4""``", "``The {{value}}`` may be specified either as ``foot`` or ``inch`` depending on ``{{input_unit}}``. The ``{{value}}`` is then rounded to the nearest ``1/{{precision}}`` inch then formatted using fractional feet and inches if ``{{output_unit}}`` is set to ``foot`` or just inches if ``{{output_unit}}`` is set to ``inch``." + "``imperial_length({{value}}, {{precision}}, {{input_unit}}, {{output_unit}}, {{suppress_zero_inches}})``", "``imperial_length(3.0, 4, ""foot"", ""foot"", true)`` OR ``imperial_length(3.0, 4, ""foot"", ""foot"", false)``", "``3'`` OR ``3' - 0""``", "The ``{{value}}`` may be specified either as ``foot`` or ``inch`` depending on ``{{input_unit}}``. The ``{{value}}`` is then rounded to the nearest ``1/{{precision}}`` inch, then formatted using fractional feet and inches if ``{{output_unit}}`` is set to ``foot``, or just inches if ``{{output_unit}}`` is set to ``inch``. When ``{{suppress_zero_inches}}`` is ``true`` (default), measurements with zero inches will omit the inch portion (e.g., ``3'`` instead of ``3' - 0""``)." When using queries in an IfcAnnotation tag surround with backticks. Examples: diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index 8bb7955d91..0228fcfd94 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -148,13 +148,16 @@ format_grammar = lark.Lark( int: "int(" function ")" format_length: metric_length | imperial_length metric_length: "metric_length(" function "," NUMBER "," NUMBER ")" - imperial_length: "imperial_length(" function "," NUMBER ["," ESCAPED_STRING "," ESCAPED_STRING] ")" + imperial_length: "imperial_length(" function "," NUMBER ["," ESCAPED_STRING "," ESCAPED_STRING ["," boolean]] ")" lower: "lower(" function ")" upper: "upper(" function ")" title: "title(" function ")" concat: "concat(" function ("," function)* ")" substr: "substr(" function "," SIGNED_INT ["," SIGNED_INT] ")" + boolean: TRUE | FALSE + TRUE: "true" | "True" | "TRUE" + FALSE: "false" | "False" | "FALSE" // Embed common.lark for packaging DIGIT: "0".."9" HEXDIGIT: "a".."f"|"A".."F"|DIGIT @@ -218,6 +221,17 @@ class FormatTransformer(lark.Transformer): elif len(args) == 2: return str(args[0])[int(args[1]) :] + def boolean(self, args): + if not args: + return True + token = args[0] + if hasattr(token, 'type'): + return token.type == 'TRUE' + value = str(token).lower() + if hasattr(token, 'value'): + value = str(token.value).lower() + return value in ("true", "1", "yes") + def round(self, args): value = Decimal(0.0 if args[0] == "None" else args[0] or 0.0) nearest = Decimal(args[1]) @@ -248,13 +262,26 @@ class FormatTransformer(lark.Transformer): if len(args) == 2: input_unit, output_unit = "foot", "foot" value, precision = args - else: + suppress_zero_inches = True + elif len(args) == 3: + value, precision, suppress_zero_inches = args + input_unit, output_unit = "foot", "foot" + elif len(args) == 4: value, precision, input_unit, output_unit = args input_unit = "inch" if input_unit == "inch" else "foot" output_unit = "inch" if output_unit == "inch" else "foot" - + suppress_zero_inches = True + else: + value, precision, input_unit, output_unit, suppress_zero_inches = args + input_unit = "inch" if input_unit == "inch" else "foot" + output_unit = "inch" if output_unit == "inch" else "foot" + return ifcopenshell.util.unit.format_length( - float(value), int(precision), unit_system="imperial", input_unit=input_unit, output_unit=output_unit + float(value), int(precision), + suppress_zero_inches=suppress_zero_inches, + unit_system="imperial", + input_unit=input_unit, + output_unit=output_unit ) def int(self, args: list[str]) -> str: