#1153 Predefined type is now also included in CSS classes for drawings.

This commit is contained in:
Dion Moult
2022-04-16 18:32:17 +10:00
parent 1138ffee7e
commit eb19165ebc
4 changed files with 59 additions and 35 deletions
@@ -0,0 +1,16 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION((),'2;1');
FILE_NAME('EPset_Drawing.ifc','2020-01-01T00:00:00',(),(),'EPset_Drawing','EPset_Drawing',$);
FILE_SCHEMA(('IFC4'));
ENDSEC;
DATA;
#1=IFCPROPERTYSETTEMPLATE('2JhNIvqZrFnAgxfhK0XVQX',$,'EPset_Drawing','',.PSET_OCCURRENCEDRIVEN.,'IfcAnnotation',(#2,#3,#4,#5,#6,#7));
#2=IFCSIMPLEPROPERTYTEMPLATE('23JavTMk98ZxXhrUEnjAcf',$,'TargetView','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#3=IFCSIMPLEPROPERTYTEMPLATE('1yVWUt5H9DAOuu0OaMMLpe',$,'Scale','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#4=IFCSIMPLEPROPERTYTEMPLATE('3gsuPBtU93b8f0gg1pjkq6',$,'HumanScale','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
#5=IFCSIMPLEPROPERTYTEMPLATE('0AK5C2UpL4$eaac2LszAx$',$,'HasUnderlay','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
#6=IFCSIMPLEPROPERTYTEMPLATE('2j2ZEZR8X5tONm7kli5hM6',$,'HasLinework','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
#7=IFCSIMPLEPROPERTYTEMPLATE('1ttChRysH9UuEX2FeMj5Hu',$,'HasAnnotation','',.P_SINGLEVALUE.,'IfcBoolean',$,$,$,$,$,.READWRITE.);
ENDSEC;
END-ISO-10303-21;
@@ -23,10 +23,19 @@ text { fill: black; stroke: none; }
.cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; fill-rule: evenodd; } .cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; fill-rule: evenodd; }
.projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } .projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
.annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } .annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
.hidden { stroke-dasharray: 3, 2; }
.solid {} .solid {}
.leader { marker-end: url(#leader-marker); } .IfcAnnotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
.stair { marker-start: url(#stair-marker-start); marker-end: url(#stair-marker-end); } .PredefinedType-MISC { fill: red; stroke: blue; stroke-width: 1; }
.PredefinedType-GRID { marker-start: url(#grid-marker); marker-end: url(#grid-marker); }
.PredefinedType-SECTIONLEVEL { marker-start: url(#section-level-marker); stroke-dasharray: 12.5, 3, 3, 3; }
.PredefinedType-PLANLEVEL { marker-end: url(#plan-level-marker); }
.PredefinedType-DIMENSION { marker-start: url(#dimension-marker-start); marker-end: url(#dimension-marker-end); }
.PredefinedType-HIDDENLINE { stroke-dasharray: 3, 2; }
.PredefinedType-STAIR { marker-start: url(#stair-marker-start); marker-end: url(#stair-marker-end); }
.PredefinedType-BOUNDARY { fill: none; stroke: red; stroke-width: 1; stroke-dasharray: 12, 4, 3, 4, 3, 4; }
.PredefinedType-TEXT { fill: black; stroke: none; }
path.PredefinedType-TEXTLEADER { marker-end: url(#leader-marker); }
text.PredefinedType-TEXTLEADER { fill: black; stroke: none; }
.break { fill: white; } .break { fill: white; }
.breakline { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; marker-mid: url(#breakline-marker); } .breakline { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; marker-mid: url(#breakline-marker); }
.material-blank { fill: white; } .material-blank { fill: white; }
@@ -44,5 +53,4 @@ text { fill: black; stroke: none; }
.material-honeycomb { fill: url(#honeycomb); } .material-honeycomb { fill: url(#honeycomb); }
.material-sand { fill: url(#sand); } .material-sand { fill: url(#sand); }
.material-concrete { fill: url(#concrete); stroke-width: 0.5; } .material-concrete { fill: url(#concrete); stroke-width: 0.5; }
.material-boundary { fill: none; stroke: red; stroke-width: 1; stroke-dasharray: 12,4,3,4,3,4; }
.IfcSpace { fill: none; stroke: none; } .IfcSpace { fill: none; stroke: none; }
@@ -474,7 +474,7 @@ class CreateDrawing(bpy.types.Operator):
svg_writer.annotations["section_level_obj"] = obj svg_writer.annotations["section_level_obj"] = obj
elif element.ObjectType == "TEXT": elif element.ObjectType == "TEXT":
svg_writer.annotations.setdefault("text_objs", []).append(obj) svg_writer.annotations.setdefault("text_objs", []).append(obj)
elif element.ObjectType == "MISC": else:
svg_writer.annotations.setdefault("misc_objs", []).append(obj) svg_writer.annotations.setdefault("misc_objs", []).append(obj)
svg_writer.annotations["attributes"] = [a.name for a in drawing_style.attributes] svg_writer.annotations["attributes"] = [a.name for a in drawing_style.attributes]
@@ -24,6 +24,7 @@ import pystache
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import svgwrite import svgwrite
import ifcopenshell import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.representation import ifcopenshell.util.representation
import blenderbim.tool as tool import blenderbim.tool as tool
import blenderbim.bim.module.drawing.helper as helper import blenderbim.bim.module.drawing.helper as helper
@@ -153,8 +154,8 @@ class SvgWriter:
for grid_obj in self.annotations.get("grid_objs", []): for grid_obj in self.annotations.get("grid_objs", []):
matrix_world = grid_obj.matrix_world matrix_world = grid_obj.matrix_world
classes = self.get_attribute_classes(grid_obj)
for edge in grid_obj.data.edges: for edge in grid_obj.data.edges:
classes = ["annotation", "grid"]
v0_global = matrix_world @ grid_obj.data.vertices[edge.vertices[0]].co.xyz v0_global = matrix_world @ grid_obj.data.vertices[edge.vertices[0]].co.xyz
v1_global = matrix_world @ grid_obj.data.vertices[edge.vertices[1]].co.xyz v1_global = matrix_world @ grid_obj.data.vertices[edge.vertices[1]].co.xyz
v0 = self.project_point_onto_camera(v0_global) v0 = self.project_point_onto_camera(v0_global)
@@ -167,8 +168,6 @@ class SvgWriter:
start=tuple(start * self.scale), end=tuple(end * self.scale), class_=" ".join(classes) start=tuple(start * self.scale), end=tuple(end * self.scale), class_=" ".join(classes)
) )
) )
line["marker-start"] = "url(#grid-marker)"
line["marker-end"] = "url(#grid-marker)"
line["stroke-dasharray"] = "12.5, 3, 3, 3" line["stroke-dasharray"] = "12.5, 3, 3, 3"
axis_tag = tool.Ifc.get_entity(grid_obj).Name axis_tag = tool.Ifc.get_entity(grid_obj).Name
self.svg.add( self.svg.add(
@@ -201,13 +200,13 @@ class SvgWriter:
self.draw_ifc_annotation() self.draw_ifc_annotation()
for obj in self.annotations.get("misc_objs", []): for obj in self.annotations.get("misc_objs", []):
self.draw_misc_annotation(obj, ["IfcAnnotation"]) self.draw_misc_annotation(obj)
for obj_data in self.annotations.get("hidden_objs", []): for obj_data in self.annotations.get("hidden_objs", []):
self.draw_line_annotation(obj_data, ["hidden"]) self.draw_line_annotation(obj_data)
for obj_data in self.annotations.get("solid_objs", []): for obj_data in self.annotations.get("solid_objs", []):
self.draw_line_annotation(obj_data, ["solid"]) self.draw_line_annotation(obj_data)
self.draw_leader_annotations() self.draw_leader_annotations()
@@ -216,8 +215,8 @@ class SvgWriter:
if self.annotations.get("section_level_obj"): if self.annotations.get("section_level_obj"):
matrix_world = self.annotations["section_level_obj"].matrix_world matrix_world = self.annotations["section_level_obj"].matrix_world
classes = self.get_attribute_classes(self.annotations["section_level_obj"])
for spline in self.annotations["section_level_obj"].data.splines: for spline in self.annotations["section_level_obj"].data.splines:
classes = ["annotation", "section-level"]
points = self.get_spline_points(spline) points = self.get_spline_points(spline)
projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points]
d = " ".join( d = " ".join(
@@ -228,8 +227,6 @@ class SvgWriter:
) )
d = "M{}".format(d[1:]) d = "M{}".format(d[1:])
path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes))) path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes)))
path["marker-start"] = "url(#section-level-marker)"
path["stroke-dasharray"] = "12.5, 3, 3, 3"
text_position = Vector( text_position = Vector(
( (
(x_offset + projected_points[0].x) * self.scale, (x_offset + projected_points[0].x) * self.scale,
@@ -258,8 +255,8 @@ class SvgWriter:
if self.annotations.get("stair_obj"): if self.annotations.get("stair_obj"):
matrix_world = self.annotations["stair_obj"].matrix_world matrix_world = self.annotations["stair_obj"].matrix_world
classes = self.get_attribute_classes(self.annotations["stair_obj"])
for spline in self.annotations["stair_obj"].data.splines: for spline in self.annotations["stair_obj"].data.splines:
classes = ["annotation", "stair"]
points = self.get_spline_points(spline) points = self.get_spline_points(spline)
projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points]
d = " ".join( d = " ".join(
@@ -316,13 +313,13 @@ class SvgWriter:
) )
) )
def draw_misc_annotation(self, obj, classes): def draw_misc_annotation(self, obj):
# We have to decide whether this should come from Blender or from IFC. # We have to decide whether this should come from Blender or from IFC.
# For the moment, for convenience of experimenting with ideas, it comes # For the moment, for convenience of experimenting with ideas, it comes
# from Blender. In the future, it should probably come from IFC. # from Blender. In the future, it should probably come from IFC.
if not isinstance(obj.data, bpy.types.Mesh): if not isinstance(obj.data, bpy.types.Mesh):
return return
classes.extend(self.get_attribute_classes(obj)) classes = self.get_attribute_classes(obj)
if len(obj.data.polygons) == 0: if len(obj.data.polygons) == 0:
self.draw_edge_annotation(obj, classes) self.draw_edge_annotation(obj, classes)
return return
@@ -332,6 +329,7 @@ class SvgWriter:
for polygon in obj.data.polygons: for polygon in obj.data.polygons:
points = [obj.data.vertices[v] for v in polygon.vertices] points = [obj.data.vertices[v] for v in polygon.vertices]
projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points]
projected_points.append(projected_points[0])
d = " ".join( d = " ".join(
[ [
"L {} {}".format((x_offset + p.x) * self.scale, (y_offset - p.y) * self.scale) "L {} {}".format((x_offset + p.x) * self.scale, (y_offset - p.y) * self.scale)
@@ -342,12 +340,12 @@ class SvgWriter:
path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes))) path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes)))
def get_attribute_classes(self, obj): def get_attribute_classes(self, obj):
classes = [obj.name.split("/")[0]] element = tool.Ifc.get_entity(obj)
for slot in obj.material_slots: global_id = "GlobalId-{}".format(element.GlobalId)
if slot.material: predefined_type = "PredefinedType-" + self.canonicalise_class_name(
classes.append("material-{}".format(re.sub("[^0-9a-zA-Z]+", "", slot.material.name))) str(ifcopenshell.util.element.get_predefined_type(element))
global_id = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId )
classes.append("globalid-{}".format(global_id)) classes = [global_id, element.is_a(), predefined_type]
for attribute in self.annotations.get("attributes", []): for attribute in self.annotations.get("attributes", []):
result = self.get_obj_value(obj, attribute) result = self.get_obj_value(obj, attribute)
if result: if result:
@@ -356,6 +354,9 @@ class SvgWriter:
) )
return classes return classes
def canonicalise_class_name(self, name):
return re.sub("[^0-9a-zA-Z]+", "", name)
def get_obj_value(self, obj, key): def get_obj_value(self, obj, key):
# This is a duplicate implementation of the IFC selector key in Blender # This is a duplicate implementation of the IFC selector key in Blender
# In the future if all this becomes purely IFC based this can be deleted # In the future if all this becomes purely IFC based this can be deleted
@@ -381,14 +382,14 @@ class SvgWriter:
if result: if result:
return result.string_value return result.string_value
def draw_line_annotation(self, obj_data, classes): def draw_line_annotation(self, obj_data):
# TODO: properly scope these offsets # TODO: properly scope these offsets
x_offset = self.raw_width / 2 x_offset = self.raw_width / 2
y_offset = self.raw_height / 2 y_offset = self.raw_height / 2
obj, data = obj_data obj, data = obj_data
classes.extend(["annotation"]) classes = self.get_attribute_classes(obj)
matrix_world = obj.matrix_world matrix_world = obj.matrix_world
if isinstance(data, bpy.types.Curve): if isinstance(data, bpy.types.Curve):
@@ -424,7 +425,7 @@ class SvgWriter:
def draw_leader_annotations(self): def draw_leader_annotations(self):
for obj in self.annotations.get("leader_objs", []): for obj in self.annotations.get("leader_objs", []):
self.draw_line_annotation((obj, obj.data), ["leader"]) self.draw_line_annotation((obj, obj.data))
spline = obj.data.splines[0] spline = obj.data.splines[0]
spline_points = spline.bezier_points if spline.bezier_points else spline.points spline_points = spline.bezier_points if spline.bezier_points else spline.points
if spline_points: if spline_points:
@@ -437,7 +438,7 @@ class SvgWriter:
x_offset = self.raw_width / 2 x_offset = self.raw_width / 2
y_offset = self.raw_height / 2 y_offset = self.raw_height / 2
self.draw_line_annotation((obj, obj.data), ["solid"]) self.draw_line_annotation((obj, obj.data))
v1 = self.project_point_onto_camera(obj.matrix_world @ Vector((0, 0, 0))) v1 = self.project_point_onto_camera(obj.matrix_world @ Vector((0, 0, 0)))
v2 = self.project_point_onto_camera(obj.matrix_world @ Vector((0, 0, -1))) v2 = self.project_point_onto_camera(obj.matrix_world @ Vector((0, 0, -1)))
@@ -632,8 +633,8 @@ class SvgWriter:
x_offset = self.raw_width / 2 x_offset = self.raw_width / 2
y_offset = self.raw_height / 2 y_offset = self.raw_height / 2
matrix_world = obj.matrix_world matrix_world = obj.matrix_world
classes = self.get_attribute_classes(obj)
for spline in obj.data.splines: for spline in obj.data.splines:
classes = ["annotation", "plan-level"]
points = self.get_spline_points(spline) points = self.get_spline_points(spline)
projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points]
d = " ".join( d = " ".join(
@@ -644,7 +645,6 @@ class SvgWriter:
) )
d = "M{}".format(d[1:]) d = "M{}".format(d[1:])
path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes))) path = self.svg.add(self.svg.path(d=d, class_=" ".join(classes)))
path["marker-end"] = "url(#plan-level-marker)"
text_position = Vector( text_position = Vector(
( (
(x_offset + projected_points[0].x) * self.scale, (x_offset + projected_points[0].x) * self.scale,
@@ -676,6 +676,7 @@ class SvgWriter:
) )
def draw_dimension_annotations(self, dimension_obj, text_override=None): def draw_dimension_annotations(self, dimension_obj, text_override=None):
classes = self.get_attribute_classes(dimension_obj)
matrix_world = dimension_obj.matrix_world matrix_world = dimension_obj.matrix_world
for spline in dimension_obj.data.splines: for spline in dimension_obj.data.splines:
points = self.get_spline_points(spline) points = self.get_spline_points(spline)
@@ -684,7 +685,7 @@ class SvgWriter:
continue 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, text_override) self.draw_dimension_annotation(v0_global, v1_global, classes, text_override)
def draw_measureit_arch_dimension_annotations(self): def draw_measureit_arch_dimension_annotations(self):
try: try:
@@ -694,10 +695,11 @@ class SvgWriter:
except: except:
return return
for coord in coords: for coord in coords:
self.draw_dimension_annotation(Vector(coord[0]), Vector(coord[1])) self.draw_dimension_annotation(
Vector(coord[0]), Vector(coord[1]), ["IfcAnnotation", "PredefinedType-DIMENSION"]
)
def draw_dimension_annotation(self, v0_global, v1_global, text_override=None): def draw_dimension_annotation(self, v0_global, v1_global, classes, text_override=None):
classes = ["annotation", "dimension"]
x_offset = self.raw_width / 2 x_offset = self.raw_width / 2
y_offset = self.raw_height / 2 y_offset = self.raw_height / 2
v0 = self.project_point_onto_camera(v0_global) v0 = self.project_point_onto_camera(v0_global)
@@ -719,8 +721,6 @@ class SvgWriter:
line = self.svg.add( line = self.svg.add(
self.svg.line(start=tuple(start * self.scale), end=tuple(end * self.scale), class_=" ".join(classes)) self.svg.line(start=tuple(start * self.scale), end=tuple(end * self.scale), class_=" ".join(classes))
) )
line["marker-start"] = "url(#dimension-marker-start)"
line["marker-end"] = "url(#dimension-marker-end)"
if text_override is not None: if text_override is not None:
text = text_override text = text_override
else: else: