mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-24 02:08:05 +00:00
Dimension description in viewport/option to hide the measurements #2918
same thing for diameter annotations since they are just reusing dimension annotations + some refactor along the way
This commit is contained in:
@@ -27,5 +27,7 @@ DATA;
|
|||||||
#20=IFCSIMPLEPROPERTYTEMPLATE('23tejOrxj859R_eCRp1AFP',$,'MarkersPath','Default markers SVG',.P_SINGLEVALUE.,'IfcURIReference',$,$,$,$,$,.READWRITE.);
|
#20=IFCSIMPLEPROPERTYTEMPLATE('23tejOrxj859R_eCRp1AFP',$,'MarkersPath','Default markers SVG',.P_SINGLEVALUE.,'IfcURIReference',$,$,$,$,$,.READWRITE.);
|
||||||
#21=IFCSIMPLEPROPERTYTEMPLATE('1UDakJ5_f7kBhggNSW4$h5',$,'SymbolsPath','Default symbols SVG',.P_SINGLEVALUE.,'IfcURIReference',$,$,$,$,$,.READWRITE.);
|
#21=IFCSIMPLEPROPERTYTEMPLATE('1UDakJ5_f7kBhggNSW4$h5',$,'SymbolsPath','Default symbols SVG',.P_SINGLEVALUE.,'IfcURIReference',$,$,$,$,$,.READWRITE.);
|
||||||
#22=IFCSIMPLEPROPERTYTEMPLATE('0d53LEtgLDQxnv__NfgH7i',$,'PatternsPath','Default patterns SVG',.P_SINGLEVALUE.,'IfcURIReference',$,$,$,$,$,.READWRITE.);
|
#22=IFCSIMPLEPROPERTYTEMPLATE('0d53LEtgLDQxnv__NfgH7i',$,'PatternsPath','Default patterns SVG',.P_SINGLEVALUE.,'IfcURIReference',$,$,$,$,$,.READWRITE.);
|
||||||
|
#23=IFCPROPERTYSETTEMPLATE('0I9merLinF5Ap$aZwaclgm',$,'BBIM_Dimension','',.PSET_OCCURRENCEDRIVEN.,'IfcAnnotation,IfcTypeProduct',(#24));
|
||||||
|
#24=IFCSIMPLEPROPERTYTEMPLATE('1rL2AbQsXD8RbpoWH5pYOV',$,'ShowDescriptionOnly','Hide the measurement values and show only annotation description',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
|
||||||
ENDSEC;
|
ENDSEC;
|
||||||
END-ISO-10303-21;
|
END-ISO-10303-21;
|
||||||
|
|||||||
@@ -259,15 +259,16 @@ class DecoratorData:
|
|||||||
cls.data[obj.name] = text_data
|
cls.data[obj.name] = text_data
|
||||||
return text_data
|
return text_data
|
||||||
|
|
||||||
# used by Ifc Annotations with ObjectType = "DIMENSION"
|
# used by Ifc Annotations with ObjectType = "DIMENSION" / "DIAMETER"
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_dimension_style(cls, obj):
|
def get_dimension_data(cls, obj):
|
||||||
result = cls.data.get(obj.name, None)
|
result = cls.data.get(obj.name, None)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
if not element or not element.is_a("IfcAnnotation") or element.ObjectType != "DIMENSION":
|
supported_object_types = ("DIMENSION", "DIAMETER")
|
||||||
|
if not element or not element.is_a("IfcAnnotation") or element.ObjectType not in supported_object_types:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
dimension_style = "arrow"
|
dimension_style = "arrow"
|
||||||
@@ -275,8 +276,13 @@ class DecoratorData:
|
|||||||
if classes and "oblique" in classes.lower().split():
|
if classes and "oblique" in classes.lower().split():
|
||||||
dimension_style = "oblique"
|
dimension_style = "oblique"
|
||||||
|
|
||||||
cls.data[obj.name] = dimension_style
|
show_description_only = (
|
||||||
return dimension_style
|
ifcopenshell.util.element.get_pset(element, "BBIM_Dimension", "ShowDescriptionOnly") or False
|
||||||
|
)
|
||||||
|
|
||||||
|
dimension_data = {"dimension_style": dimension_style, "show_description_only": show_description_only}
|
||||||
|
cls.data[obj.name] = dimension_data
|
||||||
|
return dimension_data
|
||||||
|
|
||||||
|
|
||||||
class AnnotationData:
|
class AnnotationData:
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ class DimensionDecorator(BaseDecorator):
|
|||||||
|
|
||||||
def decorate(self, context, obj):
|
def decorate(self, context, obj):
|
||||||
verts, idxs, _ = self.get_path_geom(obj, topo=False)
|
verts, idxs, _ = self.get_path_geom(obj, topo=False)
|
||||||
dimension_style = DecoratorData.get_dimension_style(obj)
|
dimension_style = DecoratorData.get_dimension_data(obj)["dimension_style"]
|
||||||
self.draw_lines(
|
self.draw_lines(
|
||||||
context, obj, verts, idxs, extra_float_kwargs={"use_oblique_style": float(dimension_style == "oblique")}
|
context, obj, verts, idxs, extra_float_kwargs={"use_oblique_style": float(dimension_style == "oblique")}
|
||||||
)
|
)
|
||||||
@@ -532,17 +532,30 @@ class DimensionDecorator(BaseDecorator):
|
|||||||
def draw_labels(self, context, obj, vertices, indices):
|
def draw_labels(self, context, obj, vertices, indices):
|
||||||
region = context.region
|
region = context.region
|
||||||
region3d = context.region_data
|
region3d = context.region_data
|
||||||
|
|
||||||
|
element = tool.Ifc.get_entity(obj)
|
||||||
|
description = element.Description
|
||||||
|
show_description_only = DecoratorData.get_dimension_data(obj)["show_description_only"]
|
||||||
|
|
||||||
for i0, i1 in indices:
|
for i0, i1 in indices:
|
||||||
v0 = Vector(vertices[i0])
|
v0 = Vector(vertices[i0])
|
||||||
v1 = Vector(vertices[i1])
|
v1 = Vector(vertices[i1])
|
||||||
p0 = location_3d_to_region_2d(region, region3d, v0)
|
p0 = location_3d_to_region_2d(region, region3d, v0)
|
||||||
p1 = location_3d_to_region_2d(region, region3d, v1)
|
p1 = location_3d_to_region_2d(region, region3d, v1)
|
||||||
dir = p1 - p0
|
text_dir = p1 - p0
|
||||||
if dir.length < 1:
|
if text_dir.length < 1:
|
||||||
continue
|
continue
|
||||||
length = (v1 - v0).length
|
|
||||||
text = self.format_value(context, length)
|
if not show_description_only:
|
||||||
self.draw_label(context, text, p0 + (dir) * 0.5, dir)
|
length = (v1 - v0).length
|
||||||
|
text = self.format_value(context, length)
|
||||||
|
|
||||||
|
self.draw_label(context, text, p0 + text_dir * 0.5, text_dir, box_alignment="bottom-middle")
|
||||||
|
if description:
|
||||||
|
self.draw_label(context, description, p0 + text_dir * 0.5, text_dir, box_alignment="top-middle")
|
||||||
|
|
||||||
|
elif show_description_only and description:
|
||||||
|
self.draw_label(context, description, p0 + text_dir * 0.5, text_dir, box_alignment="bottom-middle")
|
||||||
|
|
||||||
|
|
||||||
class AngleDecorator(BaseDecorator):
|
class AngleDecorator(BaseDecorator):
|
||||||
|
|||||||
@@ -454,11 +454,12 @@ class BIMAssignedProductProperties(PropertyGroup):
|
|||||||
|
|
||||||
|
|
||||||
# ObjectType: annotation_name, description, icon, data_type
|
# ObjectType: annotation_name, description, icon, data_type
|
||||||
|
# fmt: off
|
||||||
ANNOTATION_TYPES_DATA = {
|
ANNOTATION_TYPES_DATA = {
|
||||||
"DIMENSION": ("Dimension", "", "FIXED_SIZE", "curve"),
|
"DIMENSION": ("Dimension", "Add dimensions annotation.\nMeasurement values can be hidden through ShowDescriptionOnly property\nof BBIM_Dimension property set", "FIXED_SIZE", "curve"),
|
||||||
"ANGLE": ("Angle", "", "DRIVER_ROTATIONAL_DIFFERENCE", "curve"),
|
"ANGLE": ("Angle", "", "DRIVER_ROTATIONAL_DIFFERENCE", "curve"),
|
||||||
"RADIUS": ("Radius", "", "FORWARD", "curve"),
|
"RADIUS": ("Radius", "", "FORWARD", "curve"),
|
||||||
"DIAMETER": ("Diameter", "", "ARROW_LEFTRIGHT", "curve"),
|
"DIAMETER": ("Diameter", "Add diameter annotation.\nMeasurement values can be hidden through ShowDescriptionOnly property\nof BBIM_Dimension property set", "ARROW_LEFTRIGHT", "curve"),
|
||||||
"TEXT": ("Text", "", "SMALL_CAPS", "empty"),
|
"TEXT": ("Text", "", "SMALL_CAPS", "empty"),
|
||||||
"TEXT_LEADER": ("Leader", "", "TRACKING_BACKWARDS", "curve"),
|
"TEXT_LEADER": ("Leader", "", "TRACKING_BACKWARDS", "curve"),
|
||||||
"STAIR_ARROW": ("Stair Arrow", "Add stair arrow annotation.\nIf you have IfcStairFlight object selected, it will be used as a reference for the annotation", "SCREEN_BACK", "curve"),
|
"STAIR_ARROW": ("Stair Arrow", "Add stair arrow annotation.\nIf you have IfcStairFlight object selected, it will be used as a reference for the annotation", "SCREEN_BACK", "curve"),
|
||||||
@@ -471,6 +472,7 @@ ANNOTATION_TYPES_DATA = {
|
|||||||
"FILL_AREA": ("Fill Area", "", "NODE_TEXTURE", "mesh"),
|
"FILL_AREA": ("Fill Area", "", "NODE_TEXTURE", "mesh"),
|
||||||
"FALL": ("Fall", "", "SORT_ASC", "curve"),
|
"FALL": ("Fall", "", "SORT_ASC", "curve"),
|
||||||
}
|
}
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
annotation_classes = [(x, *ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(ANNOTATION_TYPES_DATA)]
|
annotation_classes = [(x, *ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(ANNOTATION_TYPES_DATA)]
|
||||||
|
|
||||||
|
|||||||
@@ -233,11 +233,7 @@ class SvgWriter:
|
|||||||
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
|
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
|
||||||
rl *= unit_scale
|
rl *= unit_scale
|
||||||
rl = "{:.3f}m".format(rl)
|
rl = "{:.3f}m".format(rl)
|
||||||
text_style = {
|
text_style = self.get_box_alignment_parameters("bottom-left")
|
||||||
"text-anchor": "start",
|
|
||||||
"alignment-baseline": "baseline",
|
|
||||||
"dominant-baseline": "baseline",
|
|
||||||
}
|
|
||||||
self.svg.add(self.svg.text(f"RL +{rl}", insert=tuple(text_position), class_="SECTIONLEVEL", **text_style))
|
self.svg.add(self.svg.text(f"RL +{rl}", insert=tuple(text_position), class_="SECTIONLEVEL", **text_style))
|
||||||
if tag:
|
if tag:
|
||||||
self.svg.add(self.svg.text(tag, insert=(text_position[0], text_position[1] - 5), **text_style))
|
self.svg.add(self.svg.text(tag, insert=(text_position[0], text_position[1] - 5), **text_style))
|
||||||
@@ -266,11 +262,7 @@ class SvgWriter:
|
|||||||
"UP",
|
"UP",
|
||||||
insert=tuple(text_position),
|
insert=tuple(text_position),
|
||||||
class_="STAIR",
|
class_="STAIR",
|
||||||
**{
|
**self.get_box_alignment_parameters("center"),
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -294,16 +286,13 @@ class SvgWriter:
|
|||||||
)
|
)
|
||||||
line["stroke-dasharray"] = "12.5, 3, 3, 3"
|
line["stroke-dasharray"] = "12.5, 3, 3, 3"
|
||||||
axis_tag = tool.Ifc.get_entity(obj).Name
|
axis_tag = tool.Ifc.get_entity(obj).Name
|
||||||
|
text_style = self.get_box_alignment_parameters("center")
|
||||||
self.svg.add(
|
self.svg.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
axis_tag,
|
axis_tag,
|
||||||
insert=tuple(start * self.svg_scale),
|
insert=tuple(start * self.svg_scale),
|
||||||
class_="GRID",
|
class_="GRID",
|
||||||
**{
|
**text_style,
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.svg.add(
|
self.svg.add(
|
||||||
@@ -311,11 +300,7 @@ class SvgWriter:
|
|||||||
axis_tag,
|
axis_tag,
|
||||||
insert=tuple(end * self.svg_scale),
|
insert=tuple(end * self.svg_scale),
|
||||||
class_="GRID",
|
class_="GRID",
|
||||||
**{
|
**text_style,
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -571,11 +556,7 @@ class SvgWriter:
|
|||||||
|
|
||||||
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
||||||
text_position = symbol_position_svg
|
text_position = symbol_position_svg
|
||||||
text_style = {
|
text_style = self.get_box_alignment_parameters("center")
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
}
|
|
||||||
self.svg.add(
|
self.svg.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
reference_id,
|
reference_id,
|
||||||
@@ -608,11 +589,7 @@ class SvgWriter:
|
|||||||
|
|
||||||
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
reference_id, sheet_id = self.get_reference_and_sheet_id_from_annotation(tool.Ifc.get_entity(obj))
|
||||||
text_position = symbol_position_svg
|
text_position = symbol_position_svg
|
||||||
text_style = {
|
text_style = self.get_box_alignment_parameters("center")
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
}
|
|
||||||
self.svg.add(
|
self.svg.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
reference_id, insert=(text_position[0], text_position[1] - 2.5), class_="ELEVATION", **text_style
|
reference_id, insert=(text_position[0], text_position[1] - 2.5), class_="ELEVATION", **text_style
|
||||||
@@ -639,6 +616,43 @@ class SvgWriter:
|
|||||||
return (reference_id, sheet_id)
|
return (reference_id, sheet_id)
|
||||||
return ("-", "-")
|
return ("-", "-")
|
||||||
|
|
||||||
|
def get_box_alignment_parameters(self, box_alignment):
|
||||||
|
"""Convenience method to get svg parameters for text alignment
|
||||||
|
in a readable way.
|
||||||
|
|
||||||
|
Metehod expecting values like:
|
||||||
|
|
||||||
|
`top-left`, `top-middle`, `top-right`,
|
||||||
|
|
||||||
|
`middle-left`, `center`, `middle-right`,
|
||||||
|
|
||||||
|
`bottom-left`, `bottom-middle`, `bottom-right`
|
||||||
|
"""
|
||||||
|
# reference for alignment values:
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alignment-baseline
|
||||||
|
vertical_alignment = {
|
||||||
|
"top": "hanging",
|
||||||
|
"bottom": "baseline",
|
||||||
|
"center": "middle",
|
||||||
|
"middle": "middle",
|
||||||
|
}
|
||||||
|
alignment_baseline = vertical_alignment[next(align for align in vertical_alignment if align in box_alignment)]
|
||||||
|
horizontal_alignment = {
|
||||||
|
"left": "start",
|
||||||
|
"right": "end",
|
||||||
|
"center": "middle",
|
||||||
|
"middle": "middle",
|
||||||
|
}
|
||||||
|
text_anchor = horizontal_alignment[next(align for align in horizontal_alignment if align in box_alignment)]
|
||||||
|
|
||||||
|
# using dominant-baseline because we plan to use <tspan> subtags
|
||||||
|
# otherwise alignment-baseline would be sufficient
|
||||||
|
return {
|
||||||
|
"dominant-baseline": alignment_baseline,
|
||||||
|
"text-anchor": text_anchor,
|
||||||
|
}
|
||||||
|
|
||||||
def draw_text_annotation(self, text_obj, position):
|
def draw_text_annotation(self, text_obj, position):
|
||||||
x_offset = self.raw_width / 2
|
x_offset = self.raw_width / 2
|
||||||
y_offset = self.raw_height / 2
|
y_offset = self.raw_height / 2
|
||||||
@@ -684,34 +698,6 @@ class SvgWriter:
|
|||||||
if not symbol_svg or not template_text_fields:
|
if not symbol_svg or not template_text_fields:
|
||||||
self.svg.add(self.svg.use(f"#{symbol}", insert=text_position_svg))
|
self.svg.add(self.svg.use(f"#{symbol}", insert=text_position_svg))
|
||||||
|
|
||||||
def get_box_alignment_parameters(box_alignment):
|
|
||||||
# reference for alignment values:
|
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor
|
|
||||||
# https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/alignment-baseline
|
|
||||||
vertical_alignment = {
|
|
||||||
"top": "hanging",
|
|
||||||
"bottom": "baseline",
|
|
||||||
"center": "middle",
|
|
||||||
"middle": "middle",
|
|
||||||
}
|
|
||||||
alignment_baseline = vertical_alignment[
|
|
||||||
next(align for align in vertical_alignment if align in box_alignment)
|
|
||||||
]
|
|
||||||
horizontal_alignment = {
|
|
||||||
"left": "start",
|
|
||||||
"right": "end",
|
|
||||||
"center": "middle",
|
|
||||||
"middle": "middle",
|
|
||||||
}
|
|
||||||
text_anchor = horizontal_alignment[next(align for align in horizontal_alignment if align in box_alignment)]
|
|
||||||
|
|
||||||
# using dominant-baseline because we plan to use <tspan> subtags
|
|
||||||
# otherwise alignment-baseline would be sufficient
|
|
||||||
return {
|
|
||||||
"dominant-baseline": alignment_baseline,
|
|
||||||
"text-anchor": text_anchor,
|
|
||||||
}
|
|
||||||
|
|
||||||
for text_literal in text_literals:
|
for text_literal in text_literals:
|
||||||
# after pretty indentation some redundant spaces can occur in svg tags
|
# after pretty indentation some redundant spaces can occur in svg tags
|
||||||
# this is why we apply "font-size: 0;" to the text tag to remove those spaces
|
# this is why we apply "font-size: 0;" to the text tag to remove those spaces
|
||||||
@@ -725,7 +711,7 @@ class SvgWriter:
|
|||||||
"transform": transform,
|
"transform": transform,
|
||||||
"style": "font-size: 0;",
|
"style": "font-size: 0;",
|
||||||
},
|
},
|
||||||
**get_box_alignment_parameters(text_literal.BoxAlignment),
|
**self.get_box_alignment_parameters(text_literal.BoxAlignment),
|
||||||
)
|
)
|
||||||
self.svg.add(text_tag)
|
self.svg.add(text_tag)
|
||||||
|
|
||||||
@@ -803,20 +789,15 @@ class SvgWriter:
|
|||||||
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
|
rl = ifcopenshell.util.geolocation.auto_z2e(tool.Ifc.get(), rl)
|
||||||
rl *= unit_scale
|
rl *= unit_scale
|
||||||
rl = "{:.3f}m".format(rl)
|
rl = "{:.3f}m".format(rl)
|
||||||
if projected_points[0].x > projected_points[-1].x:
|
|
||||||
text_anchor = "end"
|
box_alignment = "bottom-left" if projected_points[0].x <= projected_points[-1].x else "bottom-right"
|
||||||
else:
|
text_style = self.get_box_alignment_parameters(box_alignment)
|
||||||
text_anchor = "start"
|
|
||||||
self.svg.add(
|
self.svg.add(
|
||||||
self.svg.text(
|
self.svg.text(
|
||||||
"RL +{}".format(rl),
|
"RL +{}".format(rl),
|
||||||
insert=tuple(text_position),
|
insert=tuple(text_position),
|
||||||
class_="PLANLEVEL",
|
class_="PLANLEVEL",
|
||||||
**{
|
**text_style,
|
||||||
"text-anchor": text_anchor,
|
|
||||||
"alignment-baseline": "baseline",
|
|
||||||
"dominant-baseline": "baseline",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -932,12 +913,7 @@ class SvgWriter:
|
|||||||
text_offset = (text_position - center_position).xy.normalized() * 5
|
text_offset = (text_position - center_position).xy.normalized() * 5
|
||||||
text_position += text_offset
|
text_position += text_offset
|
||||||
|
|
||||||
text_style = {
|
text_style = self.get_box_alignment_parameters("center")
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
}
|
|
||||||
|
|
||||||
angle_text = abs(round(math.degrees(angle), 3))
|
angle_text = abs(round(math.degrees(angle), 3))
|
||||||
if is_reflex:
|
if is_reflex:
|
||||||
angle_text = 360 - angle_text
|
angle_text = 360 - angle_text
|
||||||
@@ -998,12 +974,7 @@ class SvgWriter:
|
|||||||
)
|
)
|
||||||
text_position += text_offset
|
text_position += text_offset
|
||||||
|
|
||||||
text_style = {
|
text_style = self.get_box_alignment_parameters("center")
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
}
|
|
||||||
|
|
||||||
radius = (points[-1].co - points[-2].co).length
|
radius = (points[-1].co - points[-2].co).length
|
||||||
radius = helper.format_distance(radius, precision=self.precision)
|
radius = helper.format_distance(radius, precision=self.precision)
|
||||||
tag = element.Description or f"R{radius}"
|
tag = element.Description or f"R{radius}"
|
||||||
@@ -1076,19 +1047,15 @@ class SvgWriter:
|
|||||||
)
|
)
|
||||||
text_position += text_offset
|
text_position += text_offset
|
||||||
|
|
||||||
text_style = {
|
text_style = self.get_box_alignment_parameters("center")
|
||||||
"text-anchor": "middle",
|
|
||||||
"alignment-baseline": "middle",
|
|
||||||
"dominant-baseline": "middle",
|
|
||||||
}
|
|
||||||
|
|
||||||
self.svg.add(self.svg.text(tag, insert=tuple(text_position), class_="RADIUS", **text_style))
|
self.svg.add(self.svg.text(tag, insert=tuple(text_position), class_="RADIUS", **text_style))
|
||||||
|
|
||||||
def draw_diameter_annotations(self, obj):
|
def draw_diameter_annotations(self, obj):
|
||||||
classes = self.get_attribute_classes(obj)
|
classes = self.get_attribute_classes(obj)
|
||||||
matrix_world = obj.matrix_world
|
matrix_world = obj.matrix_world
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
text_override = element.Description
|
dimension_text = element.Description
|
||||||
|
show_description_only = DecoratorData.get_dimension_data(obj)["show_description_only"]
|
||||||
for spline in obj.data.splines:
|
for spline in obj.data.splines:
|
||||||
points = self.get_spline_points(spline)
|
points = self.get_spline_points(spline)
|
||||||
for i, p in enumerate(points):
|
for i, p in enumerate(points):
|
||||||
@@ -1097,22 +1064,32 @@ class SvgWriter:
|
|||||||
v0_global = matrix_world @ points[i].co.xyz
|
v0_global = matrix_world @ points[i].co.xyz
|
||||||
v1_global = matrix_world @ points[i + 1].co.xyz
|
v1_global = matrix_world @ points[i + 1].co.xyz
|
||||||
self.draw_dimension_annotation(
|
self.draw_dimension_annotation(
|
||||||
v0_global, v1_global, classes, text_override, text_format=lambda x: "D" + x
|
v0_global,
|
||||||
|
v1_global,
|
||||||
|
classes,
|
||||||
|
dimension_text,
|
||||||
|
text_format=lambda x: "D" + x,
|
||||||
|
show_description_only=show_description_only,
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw_dimension_annotations(self, obj):
|
def draw_dimension_annotations(self, obj):
|
||||||
classes = self.get_attribute_classes(obj)
|
classes = self.get_attribute_classes(obj)
|
||||||
matrix_world = obj.matrix_world
|
matrix_world = obj.matrix_world
|
||||||
element = tool.Ifc.get_entity(obj)
|
element = tool.Ifc.get_entity(obj)
|
||||||
text_override = element.Description
|
dimension_text = element.Description
|
||||||
|
show_description_only = DecoratorData.get_dimension_data(obj)["show_description_only"]
|
||||||
for spline in obj.data.splines:
|
for spline in obj.data.splines:
|
||||||
points = self.get_spline_points(spline)
|
points = self.get_spline_points(spline)
|
||||||
for i, p in enumerate(points):
|
for i in range(len(points) - 1):
|
||||||
if i + 1 >= len(points):
|
|
||||||
continue
|
|
||||||
v0_global = matrix_world @ points[i].co.xyz
|
v0_global = matrix_world @ points[i].co.xyz
|
||||||
v1_global = matrix_world @ points[i + 1].co.xyz
|
v1_global = matrix_world @ points[i + 1].co.xyz
|
||||||
self.draw_dimension_annotation(v0_global, v1_global, classes, text_override)
|
self.draw_dimension_annotation(
|
||||||
|
v0_global,
|
||||||
|
v1_global,
|
||||||
|
classes,
|
||||||
|
dimension_text=dimension_text,
|
||||||
|
show_description_only=show_description_only,
|
||||||
|
)
|
||||||
|
|
||||||
def draw_measureit_arch_dimension_annotations(self):
|
def draw_measureit_arch_dimension_annotations(self):
|
||||||
try:
|
try:
|
||||||
@@ -1126,46 +1103,44 @@ class SvgWriter:
|
|||||||
Vector(coord[0]), Vector(coord[1]), ["IfcAnnotation", "PredefinedType-DIMENSION"]
|
Vector(coord[0]), Vector(coord[1]), ["IfcAnnotation", "PredefinedType-DIMENSION"]
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw_dimension_annotation(self, v0_global, v1_global, classes, text_override=None, text_format=lambda x: x):
|
def draw_dimension_annotation(
|
||||||
x_offset = self.raw_width / 2
|
self, v0_global, v1_global, classes, dimension_text=None, text_format=lambda x: x, show_description_only=False
|
||||||
y_offset = self.raw_height / 2
|
):
|
||||||
|
offset = Vector([self.raw_width, self.raw_height]) / 2
|
||||||
v0 = self.project_point_onto_camera(v0_global)
|
v0 = self.project_point_onto_camera(v0_global)
|
||||||
v1 = self.project_point_onto_camera(v1_global)
|
v1 = self.project_point_onto_camera(v1_global)
|
||||||
start = Vector(((x_offset + v0.x), (y_offset - v0.y)))
|
start = (offset + v0.xy * Vector((1, -1))) * self.svg_scale
|
||||||
end = Vector(((x_offset + v1.x), (y_offset - v1.y)))
|
end = (offset + v1.xy * Vector((1, -1))) * self.svg_scale
|
||||||
mid = ((end - start) / 2) + start
|
mid = ((end - start) / 2) + start
|
||||||
vector = end - start
|
vector = end - start
|
||||||
perpendicular = Vector((vector.y, -vector.x)).normalized()
|
perpendicular = Vector((vector.y, -vector.x)).normalized()
|
||||||
dimension = (v1_global - v0_global).length
|
dimension = (v1_global - v0_global).length
|
||||||
dimension = helper.format_distance(dimension, precision=self.precision)
|
dimension = helper.format_distance(dimension, precision=self.precision)
|
||||||
sheet_dimension = ((end * self.svg_scale) - (start * self.svg_scale)).length
|
sheet_dimension = (end - start).length
|
||||||
if sheet_dimension < 5: # annotation can't fit
|
|
||||||
# offset text to right of marker
|
# if annotation can't fit offset text to the right of marker
|
||||||
text_position = (end * self.svg_scale) + perpendicular + (3 * vector.normalized())
|
text_position = mid if sheet_dimension > 5 else (end + (3 * vector.normalized()))
|
||||||
else:
|
|
||||||
text_position = (mid * self.svg_scale) + perpendicular
|
|
||||||
rotation = math.degrees(vector.angle_signed(Vector((1, 0))))
|
rotation = math.degrees(vector.angle_signed(Vector((1, 0))))
|
||||||
line = self.svg.add(
|
|
||||||
self.svg.line(
|
line = self.svg.line(start=start, end=end, class_=" ".join(classes))
|
||||||
start=tuple(start * self.svg_scale), end=tuple(end * self.svg_scale), class_=" ".join(classes)
|
self.svg.add(line)
|
||||||
)
|
|
||||||
)
|
def create_text_tag(text, text_position, box_alignment):
|
||||||
if text_override is not None:
|
text_kwargs = {"transform": "rotate({} {} {})".format(rotation, text_position.x, text_position.y)}
|
||||||
text = text_override
|
return self.svg.text(
|
||||||
else:
|
text_format(text),
|
||||||
text = str(dimension)
|
insert=text_position,
|
||||||
text = text_format(text)
|
|
||||||
self.svg.add(
|
|
||||||
self.svg.text(
|
|
||||||
text,
|
|
||||||
insert=tuple(text_position),
|
|
||||||
class_="DIMENSION",
|
class_="DIMENSION",
|
||||||
**{
|
**(text_kwargs | self.get_box_alignment_parameters(box_alignment)),
|
||||||
"transform": "rotate({} {} {})".format(rotation, text_position.x, text_position.y),
|
|
||||||
"text-anchor": "middle",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
if not show_description_only:
|
||||||
|
self.svg.add(create_text_tag(str(dimension), text_position + perpendicular, "bottom-middle"))
|
||||||
|
if dimension_text:
|
||||||
|
self.svg.add(create_text_tag(dimension_text, text_position - perpendicular, "top-middle"))
|
||||||
|
|
||||||
|
elif show_description_only and dimension_text:
|
||||||
|
self.svg.add(create_text_tag(dimension_text, text_position + perpendicular, "bottom-middle"))
|
||||||
|
|
||||||
def project_point_onto_camera(self, point):
|
def project_point_onto_camera(self, point):
|
||||||
# TODO is this needlessly complex?
|
# TODO is this needlessly complex?
|
||||||
|
|||||||
Reference in New Issue
Block a user