Allow dimensions to use custom units from BBIM_Dimension Pset.

- Implementation of @theoryshaw PR #5922.
 - Note: `IfcPropertyEnumeration` allows multiple choices, but this is not
 applicable for this use case. Users must manually deselect other options;
 otherwise, it defaults to the first selected option.
This commit is contained in:
Bruno Perdigão
2025-03-11 11:49:11 -03:00
parent aa478ab359
commit db1d8d938f
5 changed files with 58 additions and 10 deletions
@@ -28,11 +28,13 @@ DATA;
#21=IFCSIMPLEPROPERTYTEMPLATE('1UDakJ5_f7kBhggNSW4$h5',$,'SymbolsPath','Default symbols SVG',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#22=IFCSIMPLEPROPERTYTEMPLATE('0d53LEtgLDQxnv__NfgH7i',$,'PatternsPath','Default patterns SVG',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#23=IFCSIMPLEPROPERTYTEMPLATE('26qFNMv7nCHgU6Jd7Anga5',$,'ShadingStylesPath','Default shading styles',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#24=IFCPROPERTYSETTEMPLATE('0I9merLinF5Ap$aZwaclgm',$,'BBIM_Dimension','',.PSET_TYPEDRIVENOVERRIDE.,'IfcAnnotation/DIMENSION,IfcTypeProduct',(#25,#26,#27,#28));
#24=IFCPROPERTYSETTEMPLATE('0I9merLinF5Ap$aZwaclgm',$,'BBIM_Dimension','',.PSET_TYPEDRIVENOVERRIDE.,'IfcAnnotation/DIMENSION,IfcAnnotation/RADIUS,IfcAnnotation/DIAMETER,IfcTypeProduct',(#25,#26,#27,#28,#30));
#25=IFCSIMPLEPROPERTYTEMPLATE('1rL2AbQsXD8RbpoWH5pYOV',$,'ShowDescriptionOnly','Hide the measurement values and show only annotation description',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
#26=IFCSIMPLEPROPERTYTEMPLATE('0SVyOfB0rC2xNfdRYf3XvY',$,'SuppressZeroInches','Suppress 0 inch values in dimension annotation text (for example: 12'' - 0" -> 12'')',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
#27=IFCSIMPLEPROPERTYTEMPLATE('2bUmj458PBqPAtUoI3MXsb',$,'TextPrefix','Text to add before annotation measurement value',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#28=IFCSIMPLEPROPERTYTEMPLATE('0bnzttUb9BPuN597uNTXOE',$,'TextSuffix','Text to add after annotation measurement value',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#29=IFCSIMPLEPROPERTYTEMPLATE('2pJmUDpB50VBdCOib1zcJJ',$,'Newline_At','',.P_SINGLEVALUE.,'IfcInteger',$,$,$,$,$,.READWRITE.);
#30=IFCSIMPLEPROPERTYTEMPLATE('2TJn72t_v2cvBUG916Dpev',$,'CustomUnit','Dimension''s custom unit',.P_ENUMERATEDVALUE.,'IfcText',$,#31,$,$,$,.READWRITE.);
#31=IFCPROPERTYENUMERATION('CustomUnit',(IFCTEXT('Feet and Inches - Fractional'),IFCTEXT('Feet - Decimal'),IFCTEXT('Inches - Fractional'),IFCTEXT('Inches - Decimal'),IFCTEXT('Meters'),IFCTEXT('Decimeters'),IFCTEXT('Centimeters'),IFCTEXT('Millimeters')),$);
ENDSEC;
END-ISO-10303-21;
@@ -386,6 +386,8 @@ class DecoratorData:
suppress_zero_inches = pset_data.get("SuppressZeroInches", False)
text_prefix = pset_data.get("TextPrefix", None) or ""
text_suffix = pset_data.get("TextSuffix", None) or ""
custom_unit_list = pset_data.get("CustomUnit", None) or ""
custom_unit = custom_unit_list[0] if custom_unit_list else ""
dimension_data = {
"dimension_style": dimension_style,
@@ -394,6 +396,7 @@ class DecoratorData:
"text_prefix": text_prefix,
"text_suffix": text_suffix,
"fill_bg": fill_bg,
"custom_unit": custom_unit,
}
cls.data[obj.name] = dimension_data
return dimension_data
@@ -495,14 +495,14 @@ class BaseDecorator:
self.draw_label(context, text=text, line_no=line_number_start, multiline=True, **draw_label_kwargs)
@lru_cache(maxsize=None)
def format_value(self, context, value):
def format_value(self, context, value, custom_unit=None):
drawing_pset_data = DrawingsData.data["active_drawing_pset_data"]
precision = drawing_pset_data.get("MetricPrecision", None)
if not precision:
precision = drawing_pset_data.get("ImperialPrecision", None)
decimal_places = drawing_pset_data.get("DecimalPlaces", None)
return format_distance(value, precision=precision, decimal_places=decimal_places)
return format_distance(value, precision=precision, decimal_places=decimal_places, suppress_zero_inches=True, custom_unit=custom_unit)
def draw_asterisk(self, context: bpy.types.Context, pos: Vector, rotation: float = 0.0, scale: float = 1.0) -> None:
"""`pos` is a world space position\n
@@ -737,7 +737,7 @@ class DimensionDecorator(BaseDecorator):
if not show_description_only:
length = (v1 - v0).length
text = self.format_value(context, length)
text = self.format_value(context, length, custom_unit=dimension_data["custom_unit"])
if isinstance(self, DiameterDecorator):
text = "D" + text
text = text_prefix + text + text_suffix
@@ -946,7 +946,7 @@ class RadiusDecorator(BaseDecorator):
def get_text():
length = (spline_points[-1] - spline_points[-2]).length
return "R" + self.format_value(context, length)
return "R" + self.format_value(context, length, custom_unit=dimension_data["custom_unit"])
self.draw_dimension_text(
context, get_text, description, dimension_data, pos=pos, text_dir=Vector((1, 0)), box_alignment="center"
+43 -4
View File
@@ -130,30 +130,52 @@ def format_distance(
decimal_places=None,
suppress_zero_inches=False,
in_unit_length=False,
custom_unit=None,
):
# Get Blender Scene Unit Settings
unit_scale = bpy.context.scene.unit_settings.scale_length
unit_system = bpy.context.scene.unit_settings.system
unit_length = bpy.context.scene.unit_settings.length_unit
area_unit_symbol = " m2" if unit_system == "METRIC" else " ft2"
# Get IFC Unit Settings
if tool.Ifc.get():
unit_scale = 1
if length_unit := ifcopenshell.util.unit.get_project_unit(tool.Ifc.get(), "LENGTHUNIT"):
unit_system = "METRIC" if length_unit.Name == "METRE" else "IMPERIAL"
unit_length = length_unit.Name
if hasattr(length_unit, "Prefix") and length_unit.Prefix:
unit_length = length_unit.Prefix + length_unit.Name
string_conversion = {
unit_length_mapping = {
"foot": "FEET",
"inch": "INCHES",
"METRE": "METERS",
"DECIMETRE": "DECIMETERS",
"CENTIMETRE": "CENTIMETERS",
"MILLIMETRE": "MILLIMETERS",
}
unit_length = string_conversion[unit_length]
unit_length = unit_length_mapping[unit_length]
# For now we only format area in IFC Units
if area_unit := ifcopenshell.util.unit.get_project_unit(tool.Ifc.get(), "AREAUNIT"):
area_unit_symbol = " " + ifcopenshell.util.unit.get_unit_symbol(area_unit)
unit_fraction = True if unit_system == "IMPERIAL" else False
# Custom Unit Settings
if custom_unit:
unit_mapping = {
"Feet and Inches - Fractional": ("IMPERIAL", "FEET", True),
"Feet - Decimal": ("IMPERIAL", "FEET", False),
"Inches - Fractional": ("IMPERIAL", "INCHES", True),
"Inches - Decimal": ("IMPERIAL", "INCHES", False),
"Meters": ("METRIC", "METERS", False),
"Decimeters": ("METRIC", "DECIMETERS", False),
"Centimeters": ("METRIC", "CENTIMETERS", False),
"Millimeters": ("METRIC", "MILLIMETERS", False),
}
if custom_unit in unit_mapping:
unit_system, unit_length, unit_fraction = unit_mapping[custom_unit]
value *= unit_scale
# Imperial Formatting
@@ -181,8 +203,11 @@ def format_distance(
decInches = value * toInches
# Separate ft and inches
# Unless Inches are the specified Length Unit
if unit_length != "INCHES":
# Unless Inches are the specified Length Unit or unit_fraction is False
if (unit_length == "FEET" and not unit_fraction):
feet = round(decInches / inPerFoot, 3) # keep decimal
decInches = 0
elif unit_length != "INCHES":
feet = int(decInches / inPerFoot) # remove decimal
decInches -= feet * inPerFoot
else:
@@ -217,6 +242,10 @@ def format_distance(
feet += 1
inches = 0
# Check whether decimal or fractional
if not unit_fraction:
inches = round(decInches, 3)
frac = None
if not isArea:
add_inches = bool(inches) or not suppress_zero_inches or (inches == 0 and frac)
tx_dist = ""
@@ -265,6 +294,8 @@ def format_distance(
# METRIC FORMATTING
elif unit_system == "METRIC":
if in_unit_length:
if unit_length == "DECIMETERS":
value = value / 10
if unit_length == "CENTIMETERS":
value = value / 100
if unit_length == "MILLIMETERS":
@@ -283,6 +314,14 @@ def format_distance(
if hide_units is False:
fmt += " m"
tx_dist = fmt % value
# Decimeters
elif unit_length == "DECIMETERS":
if decimal_places is None:
fmt = "%1.1f"
if hide_units is False:
fmt += " dm"
d_dm = value * (10)
tx_dist = fmt % d_dm
# Centimeters
elif unit_length == "CENTIMETERS":
if decimal_places is None:
@@ -1128,7 +1128,7 @@ class SvgWriter:
def get_text():
radius = (points[-1].co - points[-2].co).length
radius = helper.format_distance(radius, precision=self.precision, decimal_places=self.decimal_places)
radius = helper.format_distance(radius, precision=self.precision, decimal_places=self.decimal_places, custom_unit=dimension_data["custom_unit"])
text = f"R{radius}"
return text
@@ -1256,6 +1256,7 @@ class SvgWriter:
text_prefix=dimension_data["text_prefix"],
text_suffix=dimension_data["text_suffix"],
fill_bg=dimension_data["fill_bg"],
custom_unit=dimension_data["custom_unit"]
)
def draw_dimension_annotations(self, obj):
@@ -1280,6 +1281,7 @@ class SvgWriter:
text_prefix=dimension_data["text_prefix"],
text_suffix=dimension_data["text_suffix"],
fill_bg=dimension_data["fill_bg"],
custom_unit=dimension_data["custom_unit"],
)
def draw_measureit_arch_dimension_annotations(self):
@@ -1306,6 +1308,7 @@ class SvgWriter:
text_prefix="",
text_suffix="",
fill_bg=False,
custom_unit=None,
):
offset = Vector([self.raw_width, self.raw_height]) / 2
v0 = self.project_point_onto_camera(v0_global)
@@ -1339,6 +1342,7 @@ class SvgWriter:
precision=self.precision,
decimal_places=self.decimal_places,
suppress_zero_inches=suppress_zero_inches,
custom_unit=custom_unit,
)
text = text_prefix + str(dimension) + text_suffix
else: