mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 14:31:39 +00:00
You can now choose both input and output units for imperial formatting
This commit is contained in:
@@ -120,7 +120,7 @@ format_grammar = lark.Lark(
|
|||||||
round: "round(" function "," NUMBER ")"
|
round: "round(" function "," NUMBER ")"
|
||||||
format_length: metric_length | imperial_length
|
format_length: metric_length | imperial_length
|
||||||
metric_length: "metric_length(" function "," NUMBER "," NUMBER ")"
|
metric_length: "metric_length(" function "," NUMBER "," NUMBER ")"
|
||||||
imperial_length: "imperial_length(" function "," NUMBER ["," ESCAPED_STRING] ")"
|
imperial_length: "imperial_length(" function "," NUMBER ["," ESCAPED_STRING "," ESCAPED_STRING] ")"
|
||||||
lower: "lower(" function ")"
|
lower: "lower(" function ")"
|
||||||
upper: "upper(" function ")"
|
upper: "upper(" function ")"
|
||||||
title: "title(" function ")"
|
title: "title(" function ")"
|
||||||
@@ -195,17 +195,15 @@ class FormatTransformer(lark.Transformer):
|
|||||||
|
|
||||||
def imperial_length(self, args):
|
def imperial_length(self, args):
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
imperial_unit = "foot"
|
input_unit = "foot"
|
||||||
value, precision = args
|
value, precision = args
|
||||||
else:
|
else:
|
||||||
value, precision, imperial_unit = args
|
value, precision, input_unit, output_unit = args
|
||||||
if imperial_unit == "inch":
|
input_unit = "inch" if input_unit == "inch" else "foot"
|
||||||
imperial_unit = "inch"
|
output_unit = "inch" if output_unit == "inch" else "foot"
|
||||||
else:
|
|
||||||
imperial_unit = "foot"
|
|
||||||
|
|
||||||
return ifcopenshell.util.unit.format_length(
|
return ifcopenshell.util.unit.format_length(
|
||||||
float(value), int(precision), unit_system="imperial", imperial_unit=imperial_unit
|
float(value), int(precision), unit_system="imperial", input_unit=input_unit, output_unit=output_unit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -821,7 +819,7 @@ class Selector:
|
|||||||
key = "LayerSetName" # This oddity in the IFC spec is annoying so we account for it.
|
key = "LayerSetName" # This oddity in the IFC spec is annoying so we account for it.
|
||||||
|
|
||||||
if isinstance(key, re.Pattern):
|
if isinstance(key, re.Pattern):
|
||||||
attribute = None # Should we support regex attributes? Probably not for now.
|
attribute = None # Should we support regex attributes? Probably not for now.
|
||||||
else:
|
else:
|
||||||
attribute = getattr(value, key, None)
|
attribute = getattr(value, key, None)
|
||||||
|
|
||||||
|
|||||||
@@ -548,12 +548,18 @@ def calculate_unit_scale(ifc_file):
|
|||||||
|
|
||||||
|
|
||||||
def format_length(
|
def format_length(
|
||||||
value, precision, decimal_places=2, suppress_zero_inches=True, unit_system="imperial", imperial_unit="foot"
|
value,
|
||||||
|
precision,
|
||||||
|
decimal_places=2,
|
||||||
|
suppress_zero_inches=True,
|
||||||
|
unit_system="imperial",
|
||||||
|
input_unit="foot",
|
||||||
|
output_unit="foot",
|
||||||
):
|
):
|
||||||
"""Formats a length for readability and imperial formatting
|
"""Formats a length for readability and imperial formatting
|
||||||
|
|
||||||
:param value: The value in meters if metric, or either decimal feet or
|
:param value: The value in meters if metric, or either decimal feet or
|
||||||
inches if imperial depending on imperial_unit.
|
inches if imperial depending on input_unit.
|
||||||
:type value: float
|
:type value: float
|
||||||
:param precision: How precise the format should be. I.e. round to nearest.
|
:param precision: How precise the format should be. I.e. round to nearest.
|
||||||
For imperial, it is 1/Nth. E.g. 12 means to the nearest 1/12th of an
|
For imperial, it is 1/Nth. E.g. 12 means to the nearest 1/12th of an
|
||||||
@@ -566,15 +572,18 @@ def format_length(
|
|||||||
:type suppress_zero_inches: bool
|
:type suppress_zero_inches: bool
|
||||||
:param unit_system: Choose whether your value is "metric" or "imperial"
|
:param unit_system: Choose whether your value is "metric" or "imperial"
|
||||||
:type unit_system: str
|
:type unit_system: str
|
||||||
:param imperial_unit: If imperial, specify whether your value is "foot" or
|
:param input_unit: If imperial, specify whether your value is "foot" or
|
||||||
"inch".
|
"inch".
|
||||||
:type imperial_unit: str
|
:type input_unit: str
|
||||||
|
:param output_unit: If imperial, specify whether your value is "foot" to
|
||||||
|
format as both feet and inches, or "inch" if only inches should be
|
||||||
|
shown.
|
||||||
"""
|
"""
|
||||||
if unit_system == "imperial":
|
if unit_system == "imperial":
|
||||||
if imperial_unit == "foot":
|
if input_unit == "foot":
|
||||||
feet = int(value)
|
feet = int(value)
|
||||||
inches = (value - feet) * 12
|
inches = (value - feet) * 12
|
||||||
elif imperial_unit == "inch":
|
elif input_unit == "inch":
|
||||||
inches = value % 12
|
inches = value % 12
|
||||||
feet = int(round((value - inches) / 12))
|
feet = int(round((value - inches) / 12))
|
||||||
|
|
||||||
@@ -587,13 +596,21 @@ def format_length(
|
|||||||
# If fraction is a whole number, format it accordingly
|
# If fraction is a whole number, format it accordingly
|
||||||
if frac.denominator == 1:
|
if frac.denominator == 1:
|
||||||
if suppress_zero_inches and frac.numerator == 0:
|
if suppress_zero_inches and frac.numerator == 0:
|
||||||
return f"{feet}'"
|
if output_unit == "foot":
|
||||||
return f"{feet}' - {frac.numerator}\""
|
return f"{feet}'"
|
||||||
|
return f'{feet * 12}"'
|
||||||
|
if output_unit == "foot":
|
||||||
|
return f"{feet}' - {frac.numerator}\""
|
||||||
|
return f'{(feet * 12) + frac.numerator}"'
|
||||||
if frac.numerator > frac.denominator:
|
if frac.numerator > frac.denominator:
|
||||||
remainder = frac.numerator % frac.denominator
|
remainder = frac.numerator % frac.denominator
|
||||||
whole = int((frac.numerator - remainder) / frac.denominator)
|
whole = int((frac.numerator - remainder) / frac.denominator)
|
||||||
return f"{feet}' - {whole} {remainder}/{frac.denominator}\""
|
if output_unit == "foot":
|
||||||
return f"{feet}' - {frac.numerator}/{frac.denominator}\""
|
return f"{feet}' - {whole} {remainder}/{frac.denominator}\""
|
||||||
|
return f'{(feet * 12) + whole} {remainder}/{frac.denominator}"'
|
||||||
|
if output_unit == "foot":
|
||||||
|
return f"{feet}' - {frac.numerator}/{frac.denominator}\""
|
||||||
|
return f'{feet * 12} {frac.numerator}/{frac.denominator}"'
|
||||||
elif unit_system == "metric":
|
elif unit_system == "metric":
|
||||||
rounded_val = round(value / precision) * precision
|
rounded_val = round(value / precision) * precision
|
||||||
return f"{rounded_val:.{decimal_places}f}"
|
return f"{rounded_val:.{decimal_places}f}"
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ class TestFormat():
|
|||||||
assert subject.format('imperial_length(3.123, 1)') == "3' - 1\""
|
assert subject.format('imperial_length(3.123, 1)') == "3' - 1\""
|
||||||
assert subject.format('imperial_length(3.123, 2)') == "3' - 1 1/2\""
|
assert subject.format('imperial_length(3.123, 2)') == "3' - 1 1/2\""
|
||||||
assert subject.format('imperial_length(\"3.123\", 2)') == "3' - 1 1/2\""
|
assert subject.format('imperial_length(\"3.123\", 2)') == "3' - 1 1/2\""
|
||||||
assert subject.format('imperial_length(\"123.123\", 2, \"inch\")') == "10' - 3\""
|
assert subject.format('imperial_length(\"123.123\", 2, \"inch\", \"foot\")') == "10' - 3\""
|
||||||
|
assert subject.format('imperial_length(\"123.123\", 2, \"inch\", \"inch\")') == "123\""
|
||||||
|
|
||||||
|
|
||||||
class TestGetElementValue(test.bootstrap.IFC4):
|
class TestGetElementValue(test.bootstrap.IFC4):
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# IfcOpenShell - IFC toolkit and geometry engine
|
||||||
|
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of IfcOpenShell.
|
||||||
|
#
|
||||||
|
# IfcOpenShell is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# IfcOpenShell is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import test.bootstrap
|
||||||
|
import ifcopenshell.api
|
||||||
|
import ifcopenshell.util.unit as subject
|
||||||
|
|
||||||
|
|
||||||
|
class TestFormatLength(test.bootstrap.IFC4):
|
||||||
|
def test_run(self):
|
||||||
|
assert subject.format_length(1, 1, decimal_places=0, unit_system="metric") == "1"
|
||||||
|
assert subject.format_length(1, 1, decimal_places=2, unit_system="metric") == "1.00"
|
||||||
|
assert subject.format_length(3, 5, decimal_places=2, unit_system="metric") == "5.00"
|
||||||
|
assert subject.format_length(3.123, 0.01, decimal_places=2, unit_system="metric") == "3.12"
|
||||||
|
|
||||||
|
assert subject.format_length(3, 1, unit_system="imperial", input_unit="foot") == "3'"
|
||||||
|
assert subject.format_length(3.5, 1, unit_system="imperial", input_unit="foot") == "3' - 6\""
|
||||||
|
assert subject.format_length(3.123, 1, unit_system="imperial", input_unit="foot") == "3' - 1\""
|
||||||
|
assert subject.format_length(3.123, 2, unit_system="imperial", input_unit="foot") == "3' - 1 1/2\""
|
||||||
|
assert subject.format_length(3.123, 4, unit_system="imperial", input_unit="foot") == "3' - 1 1/2\""
|
||||||
|
assert subject.format_length(3.123, 32, unit_system="imperial", input_unit="foot") == "3' - 1 15/32\""
|
||||||
|
assert subject.format_length(24, 1, unit_system="imperial", input_unit="inch") == "2'"
|
||||||
|
assert subject.format_length(25.23, 1, unit_system="imperial", input_unit="inch") == "2' - 1\""
|
||||||
|
assert subject.format_length(25.23, 4, unit_system="imperial", input_unit="inch") == "2' - 1 1/4\""
|
||||||
|
|
||||||
|
assert subject.format_length(3, 1, unit_system="imperial", input_unit="foot", output_unit="inch") == '36"'
|
||||||
|
assert subject.format_length(3.5, 1, unit_system="imperial", input_unit="foot", output_unit="inch") == '42"'
|
||||||
|
assert subject.format_length(3.123, 1, unit_system="imperial", input_unit="foot", output_unit="inch") == '37"'
|
||||||
|
assert (
|
||||||
|
subject.format_length(3.123, 2, unit_system="imperial", input_unit="foot", output_unit="inch") == '37 1/2"'
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
subject.format_length(3.123, 4, unit_system="imperial", input_unit="foot", output_unit="inch") == '37 1/2"'
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
subject.format_length(3.123, 32, unit_system="imperial", input_unit="foot", output_unit="inch")
|
||||||
|
== '37 15/32"'
|
||||||
|
)
|
||||||
|
assert subject.format_length(24, 1, unit_system="imperial", input_unit="inch", output_unit="inch") == '24"'
|
||||||
|
assert subject.format_length(25.23, 1, unit_system="imperial", input_unit="inch", output_unit="inch") == '25"'
|
||||||
|
assert (
|
||||||
|
subject.format_length(25.23, 4, unit_system="imperial", input_unit="inch", output_unit="inch") == '25 1/4"'
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user