Compare commits

...

1 Commits

Author SHA1 Message Date
Ryan Schultz 0b71ffea32 Closes #7877:Add scale to reference view-title from SVG class
When a reference drawing is added to a sheet, the sheet
builder now reads the `scale-X` CSS class from the reference
SVG content and uses it to populate the {{Scale}} field in
the view-title. The scale denominator is resolved to a
human-readable string (e.g. "scale-4" → '3"=1\'-0"') using
the Blender scene unit system to pick imperial vs. metric.

Generated with the assistance of an AI coding tool.
2026-04-25 07:35:24 -05:00
2 changed files with 75 additions and 0 deletions
@@ -486,11 +486,29 @@ class SheetBuilder:
data.update({"Sheet" + k: v for k, v in sheet.get_info().items()})
if not data["Name"]:
data["Name"] = document.Name or "Unnamed"
if view.attrib.get("data-type") == "reference":
human_scale = self.get_scale_from_svg(os.path.join(self.layout_dir, path))
if human_scale:
data["Scale"] = human_scale
view.append(self.parse_embedded_svg(view_title, data))
for image in images:
view.remove(image)
def get_scale_from_svg(self, svg_path: str) -> str:
try:
tree = ET.parse(svg_path)
root = tree.getroot()
for g in root.iter(f"{SVG}g"):
for cls in g.attrib.get("class", "").split():
if cls.startswith("scale-"):
denominator = cls[6:]
if denominator.isdigit():
return tool.Drawing.get_human_scale_from_scale_denominator(denominator)
except Exception:
pass
return ""
def get_href(self, element: ET.Element) -> str:
return urllib.parse.unquote(element.attrib[f"{XLINK}href"]).replace("\\", "/")
+57
View File
@@ -2227,6 +2227,63 @@ class Drawing(bonsai.core.tool.Drawing):
pset = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing") or {}
return "NTS" if pset.get("IsNTS", False) else pset.get("HumanScale", "NTS")
@classmethod
def get_human_scale_from_scale_denominator(cls, denominator: str) -> str:
"""Return the human-readable scale string for a scale CSS class denominator.
E.g. denominator '4' returns '3"=1\'-0"' (imperial) or '' if not found.
"""
IMPERIAL_SCALES = {
"1": "1'=1'-0\"",
"2": '6"=1\'-0"',
"4": '3"=1\'-0"',
"8": '1-1/2"=1\'-0"',
"12": '1"=1\'-0"',
"16": '3/4"=1\'-0"',
"24": '1/2"=1\'-0"',
"32": '3/8"=1\'-0"',
"48": '1/4"=1\'-0"',
"64": '3/16"=1\'-0"',
"96": '1/8"=1\'-0"',
"128": '3/32"=1\'-0"',
"192": '1/16"=1\'-0"',
"384": '1/32"=1\'-0"',
"768": '1/64"=1\'-0"',
"1536": '1/128"=1\'-0"',
"120": "1\"=10'",
"240": "1\"=20'",
"360": "1\"=30'",
"480": "1\"=40'",
"600": "1\"=50'",
"720": "1\"=60'",
"840": "1\"=70'",
"960": "1\"=80'",
"1080": "1\"=90'",
"1200": "1\"=100'",
"1800": "1\"=150'",
"2400": "1\"=200'",
"3600": "1\"=300'",
"4800": "1\"=400'",
"6000": "1\"=500'",
}
METRIC_SCALES = {
"5000": "1:5000",
"2000": "1:2000",
"1000": "1:1000",
"500": "1:500",
"200": "1:200",
"100": "1:100",
"50": "1:50",
"20": "1:20",
"10": "1:10",
"5": "1:5",
"2": "1:2",
"1": "1:1",
}
import bpy
is_imperial = bpy.context.scene.unit_settings.system == "IMPERIAL"
return (IMPERIAL_SCALES if is_imperial else METRIC_SCALES).get(denominator, "")
@classmethod
def get_drawing_metadata(cls, drawing: ifcopenshell.entity_instance) -> list[str]:
pset_data = ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing")