diff --git a/src/blenderbim/blenderbim/bim/module/drawing/data.py b/src/blenderbim/blenderbim/bim/module/drawing/data.py index 5ce3aeab2b..e861a57c2e 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/data.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/data.py @@ -115,6 +115,7 @@ class DecoratorData: # stores 1 type of data per object data = {} + # used by Ifc Annotations with ObjectType = "BATTING" @classmethod def get_batting_thickness(cls, obj): result = cls.data.get(obj.name, None) @@ -128,6 +129,7 @@ class DecoratorData: cls.data[obj.name] = thickness return thickness + # used by Ifc Annotations with ObjectType = "SECTION" @classmethod def get_section_markers_display_data(cls, obj): result = cls.data.get(obj.name, None) @@ -169,6 +171,7 @@ class DecoratorData: cls.data[obj.name] = display_data return display_data + # used by Ifc Annotations with ObjectType = "TEXT" @classmethod def get_ifc_text_data(cls, obj): """returns font size in mm for current ifc text object""" @@ -214,3 +217,22 @@ class DecoratorData: text_data = {"Literals": literals_data, "FontSize": font_size} cls.data[obj.name] = text_data return text_data + + # used by Ifc Annotations with ObjectType = "DIMENSION" + @classmethod + def get_dimension_style(cls, obj): + result = cls.data.get(obj.name, None) + if result is not None: + return result + + element = tool.Ifc.get_entity(obj) + if not element or not element.is_a("IfcAnnotation") or element.ObjectType != "DIMENSION": + return None + + dimension_style = "arrow" + classes = ifcopenshell.util.element.get_pset(element, "EPset_Annotation", "Classes") + if classes and "oblique" in classes.lower().split(): + dimension_style = "oblique" + + cls.data[obj.name] = dimension_style + return dimension_style diff --git a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py index 1184e7629b..1f1d85f396 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/decoration.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/decoration.py @@ -442,7 +442,7 @@ class BaseDecorator: box_alignment_offset += Vector((0, h)) else: # middle / center - box_alignment_offset += Vector((0, h / 2)) + box_alignment_offset += Vector((0, h / 2)) if "left" in box_alignment: pass @@ -451,7 +451,7 @@ class BaseDecorator: else: # middle / center box_alignment_offset += Vector((w / 2, 0)) - + pos -= rotation_matrix.transposed() @ box_alignment_offset else: if center: @@ -506,6 +506,10 @@ class DimensionDecorator(BaseDecorator): DEF_GLSL = ( BaseDecorator.DEF_GLSL + """ + #define OBLIQUE_SYMBOL_ANGLE PI / 4.0 + #define OLBIQUE_SYMBOL_SIZE 10.0 + #define OBLIQUE_HEAD_VERTS 7 + #define ARROW_ANGLE PI / 12.0 #define ARROW_SIZE 16.0 """ @@ -514,10 +518,23 @@ class DimensionDecorator(BaseDecorator): GEOM_GLSL = """ uniform vec2 winsize; uniform float viewportDrawingScale; + uniform float use_oblique_style; layout(lines) in; layout(line_strip, max_vertices=MAX_POINTS) out; + void oblique_dimension_head(in vec4 dir, in float size, in float angle, out vec4 head[OBLIQUE_HEAD_VERTS]) { + float c = cos(angle), s = sin(angle); + vec4 ortho = vec4(-dir.y, dir.x, 0, 0); + head[0] = -dir * size*0.66; + head[1] = vec4(0); + head[2] = ortho * size; + head[3] = -ortho * size; + head[4] = vec4(0); + head[5] = vec4((mat2(c, +s, -s, c) * dir.xy) * size * 0.47, 0, 0); + head[6] = -head[5]; + } + void main() { vec4 clip2win = matCLIP2WIN(); vec4 win2clip = matWIN2CLIP(); @@ -529,49 +546,78 @@ class DimensionDecorator(BaseDecorator): vec4 p; - vec4 head[3]; - arrow_head(dir, viewportDrawingScale * ARROW_SIZE, ARROW_ANGLE, head); + if (use_oblique_style > 0) { + vec4 head[OBLIQUE_HEAD_VERTS]; + oblique_dimension_head(dir, viewportDrawingScale * OLBIQUE_SYMBOL_SIZE, OBLIQUE_SYMBOL_ANGLE, head); - // start edge arrow - gl_Position = p0; - EmitVertex(); - p = p0w + head[1]; - gl_Position = WIN2CLIP(p); - EmitVertex(); - p = p0w + head[2]; - gl_Position = WIN2CLIP(p); - EmitVertex(); - gl_Position = p0; - EmitVertex(); - EndPrimitive(); + // start edge arrow + for (int i = 0; i < OBLIQUE_HEAD_VERTS; i++) { + gl_Position = WIN2CLIP((p0w + head[i])); + EmitVertex(); + } + EndPrimitive(); - // end edge arrow - gl_Position = p1; - EmitVertex(); - p = p1w - head[1]; - gl_Position = WIN2CLIP(p); - EmitVertex(); - p = p1w - head[2]; - gl_Position = WIN2CLIP(p); - EmitVertex(); - gl_Position = p1; - EmitVertex(); - EndPrimitive(); + // end edge arrow + for (int i = 0; i < OBLIQUE_HEAD_VERTS; i++) { + gl_Position = WIN2CLIP((p1w - head[i])); + EmitVertex(); + } + EndPrimitive(); - // stem, with gaps for arrows - p = p0w + head[0]; - gl_Position = WIN2CLIP(p); - EmitVertex(); - p = p1w - head[0]; - gl_Position = WIN2CLIP(p); - EmitVertex(); - EndPrimitive(); + // stem + gl_Position = p0; + EmitVertex(); + gl_Position = p1; + EmitVertex(); + EndPrimitive(); + } else { + vec4 head[3]; + arrow_head(dir, viewportDrawingScale * ARROW_SIZE, ARROW_ANGLE, head); + + // start edge arrow + gl_Position = p0; + EmitVertex(); + p = p0w + head[1]; + gl_Position = WIN2CLIP(p); + EmitVertex(); + p = p0w + head[2]; + gl_Position = WIN2CLIP(p); + EmitVertex(); + gl_Position = p0; + EmitVertex(); + EndPrimitive(); + + // end edge arrow + gl_Position = p1; + EmitVertex(); + p = p1w - head[1]; + gl_Position = WIN2CLIP(p); + EmitVertex(); + p = p1w - head[2]; + gl_Position = WIN2CLIP(p); + EmitVertex(); + gl_Position = p1; + EmitVertex(); + EndPrimitive(); + + // stem, with gaps for arrows + p = p0w + head[0]; + gl_Position = WIN2CLIP(p); + EmitVertex(); + p = p1w - head[0]; + gl_Position = WIN2CLIP(p); + EmitVertex(); + EndPrimitive(); + } } """ def decorate(self, context, obj): verts, idxs, _ = self.get_path_geom(obj, topo=False) - self.draw_lines(context, obj, verts, idxs) + dimension_style = DecoratorData.get_dimension_style(obj) + self.draw_lines( + context, obj, verts, idxs, extra_float_kwargs={"use_oblique_style": float(dimension_style == "oblique")} + ) self.draw_labels(context, obj, verts, idxs) def draw_labels(self, context, obj, vertices, indices): @@ -806,7 +852,7 @@ class LeaderDecorator(BaseDecorator): props = obj.BIMTextProperties text_data = props.get_text_edited_data() if props.is_editing else DecoratorData.get_ifc_text_data(obj) - text = text_data["Literals"][0]['CurrentValue'] + text = text_data["Literals"][0]["CurrentValue"] self.draw_label(context, text, pos, dir, gap=0, center=False, vcenter=False) @@ -1336,11 +1382,11 @@ class PlanLevelDecorator(LevelDecorator): dir = p1 - p0 if dir.length < 1: continue - + if dir.x > 0: box_alignment = "bottom-left" else: - box_alignment = 'bottom-right' + box_alignment = "bottom-right" dir *= -1 z = verts[-1].z / unit_scale @@ -2098,7 +2144,7 @@ class TextDecorator(BaseDecorator): def matrix_only_rotation(m): return m.to_3x3().normalized().to_4x4() - text_dir = Vector((1,0)) + text_dir = Vector((1, 0)) text_dir_world = matrix_only_rotation(region3d.perspective_matrix.inverted()) @ text_dir.to_3d() text_dir_world_rotated = matrix_only_rotation(obj.matrix_world) @ text_dir_world text_dir = (matrix_only_rotation(region3d.perspective_matrix) @ text_dir_world_rotated).to_2d().normalized()