#1153. Elevation references are now auto generated when activating drawings.

This commit is contained in:
Dion Moult
2022-03-29 10:01:41 +11:00
parent 1b1fd1e6c5
commit a60dfd8dd5
3 changed files with 193 additions and 1 deletions
@@ -1125,6 +1125,101 @@ class GridDecorator(BaseDecorator):
self.draw_label(context, text, p1, dir, vcenter=True, gap=0)
class ElevationDecorator(LevelDecorator):
objecttype = "ELEVATION"
DEF_GLSL = (
BaseDecorator.DEF_GLSL
+ """
#define CIRCLE_SIZE 8.0
#define TRIANGLE_L 22.63
#define TRIANGLE_W 11.31
"""
)
GEOM_GLSL = """
uniform vec2 winsize;
uniform float viewportDrawingScale;
layout(lines) in;
layout(line_strip, max_vertices=MAX_POINTS) out;
void triangle_head(in vec4 side, in vec4 dir, in float length, in float width, in float radius, out vec4 head[5]) {
vec4 nose = side * length;
vec4 ear = dir * width;
head[0] = side * -radius;
head[1] = nose * -.5;
head[2] = vec4(0) + ear;
head[3] = nose * .5;
head[4] = side * radius;
}
void main() {
vec4 clip2win = matCLIP2WIN();
vec4 win2clip = matWIN2CLIP();
vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position;
vec4 p0w = CLIP2WIN(p0), p1w = CLIP2WIN(p1);
vec4 edge = p1w - p0w, dir = normalize(edge);
// vec4 dir = normalize(vec4(1, 0, 0, 0));
vec4 gap = dir * viewportDrawingScale * TRIANGLE_L * .5;
vec4 side = vec4(cross(vec3(dir.xy, 0), vec3(0, 0, 1)).xy, 0, 0);
vec4 p;
vec4 head[CIRCLE_SEGS];
circle_head(viewportDrawingScale * CIRCLE_SIZE, head);
vec4 head3[5];
// start edge circle
for(int i=0; i<CIRCLE_SEGS; i++) {
p = p0w + head[i];
gl_Position = WIN2CLIP(p);
EmitVertex();
}
p = p0w + head[0];
gl_Position = WIN2CLIP(p);
EmitVertex();
EndPrimitive();
// start edge triangle
triangle_head(side, dir, viewportDrawingScale * TRIANGLE_L, viewportDrawingScale * TRIANGLE_W, viewportDrawingScale * CIRCLE_SIZE, head3);
p = p0w + head3[0];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + head3[1];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + head3[2];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + head3[3];
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + head3[4];
gl_Position = WIN2CLIP(p);
EmitVertex();
EndPrimitive();
// reference divider
p = p0w + normalize(vec4(-1, 0, 0, 0)) * viewportDrawingScale * CIRCLE_SIZE;
gl_Position = WIN2CLIP(p);
EmitVertex();
p = p0w + normalize(vec4(1, 0, 0, 0)) * viewportDrawingScale * CIRCLE_SIZE;
gl_Position = WIN2CLIP(p);
EmitVertex();
EndPrimitive();
}
"""
def decorate(self, context, obj):
center = obj.matrix_world.translation
v1 = obj.matrix_world @ Vector((0, 0, 0))
v2 = obj.matrix_world @ Vector((0, 0, -1))
self.draw_lines(context, obj, [v1, v2], [(0, 1)])
class SectionViewDecorator(LevelDecorator):
objecttype = "SECTION"
@@ -1328,6 +1423,7 @@ class DecorationsHandler:
StairDecorator,
BreakDecorator,
SectionViewDecorator,
ElevationDecorator,
TextDecorator,
]
+7 -1
View File
@@ -173,7 +173,13 @@ def sync_references(ifc, collector, drawing_tool, drawing=None):
should_delete_existing_annotation = False
should_create_annotation = False
if annotation and (not reference_obj or ifc.is_moved(reference_obj) or ifc.is_edited(reference_obj)):
if annotation and (
not reference_obj
or ifc.is_moved(reference_obj)
or ifc.is_edited(reference_obj)
or ifc.is_deleted(reference_element)
or ifc.is_deleted(annotation)
):
should_delete_existing_annotation = True
if reference_obj and (should_delete_existing_annotation or not annotation):
+90
View File
@@ -19,6 +19,7 @@
import os
import re
import bpy
import math
import bmesh
import mathutils
import webbrowser
@@ -407,6 +408,95 @@ class Drawing(blenderbim.core.tool.Drawing):
def generate_reference_annotation(cls, drawing, reference_element, context):
if reference_element.is_a("IfcGridAxis"):
return cls.generate_grid_axis_reference_annotation(drawing, reference_element, context)
elif reference_element.is_a("IfcAnnotation") and reference_element.ObjectType == "DRAWING":
psets = ifcopenshell.util.element.get_psets(reference_element)
target_view = psets.get("EPset_Drawing", {}).get("TargetView", None)
if target_view == "ELEVATION_VIEW":
return cls.generate_elevation_reference_annotation(drawing, reference_element, context)
@classmethod
def generate_elevation_reference_annotation(cls, drawing, reference_element, context):
reference_obj = tool.Ifc.get_object(reference_element)
reference_obj.matrix_world
camera = tool.Ifc.get_object(drawing)
def is_perpendicular(a, b):
axes = [mathutils.Vector((1, 0, 0)), mathutils.Vector((0, 1, 0)), mathutils.Vector((0, 0, 1))]
a_quaternion = a.matrix_world.to_quaternion()
b_quaternion = b.matrix_world.to_quaternion()
for axis in axes:
if abs((a_quaternion @ axis).angle((b_quaternion @ axis)) - (math.pi / 2)) < 1e-5:
return True
return False
def get_camera_block(obj):
raster_x = obj.data.BIMCameraProperties.raster_x
raster_y = obj.data.BIMCameraProperties.raster_y
if raster_x > raster_y:
width = obj.data.ortho_scale
height = width / raster_x * raster_y
else:
height = obj.data.ortho_scale
width = height / raster_y * raster_x
depth = obj.data.clip_end
verts = (
obj.matrix_world @ mathutils.Vector((-width / 2, -height /2, -depth)),
obj.matrix_world @ mathutils.Vector((-width / 2, -height /2, 0)),
obj.matrix_world @ mathutils.Vector((-width / 2, height /2, -depth)),
obj.matrix_world @ mathutils.Vector((-width / 2, height /2, 0)),
obj.matrix_world @ mathutils.Vector((width / 2, -height /2, -depth)),
obj.matrix_world @ mathutils.Vector((width / 2, -height /2, 0)),
obj.matrix_world @ mathutils.Vector((width / 2, height /2, -depth)),
obj.matrix_world @ mathutils.Vector((width / 2, height /2, 0))
)
faces = [
[0, 1, 3, 2],
[2, 3, 7, 6],
[6, 7, 5, 4],
[4, 5, 1, 0],
[2, 6, 4, 0],
[7, 3, 1, 5],
]
return {"verts": verts, "faces": faces}
def is_intersecting(a, b):
a_block = get_camera_block(a)
a_tree = mathutils.bvhtree.BVHTree.FromPolygons(a_block["verts"], a_block["faces"])
b_block = get_camera_block(b)
b_tree = mathutils.bvhtree.BVHTree.FromPolygons(b_block["verts"], b_block["faces"])
return bool(a_tree.overlap(b_tree))
def to_camera_coords(camera, reference_obj):
mat = reference_obj.matrix_world.copy()
xyz = camera.matrix_world.inverted() @ reference_obj.matrix_world.translation
xyz[2] = 0
xyz = camera.matrix_world @ xyz
mat[0][3] = xyz[0]
mat[1][3] = xyz[1]
mat[2][3] = xyz[2]
annotation_offset = mathutils.Vector((0, 0, -camera.data.clip_start))
annotation_offset = camera.matrix_world.to_quaternion() @ annotation_offset
mat[0][3] += annotation_offset[0]
mat[1][3] += annotation_offset[1]
mat[2][3] += annotation_offset[2]
return mat
if is_perpendicular(camera, reference_obj) and is_intersecting(camera, reference_obj):
obj = bpy.data.objects.new(reference_obj.name, None)
obj.empty_display_size = 0.1
obj.matrix_world = to_camera_coords(camera, reference_obj)
element = cls.run_root_assign_class(
obj=obj,
ifc_class="IfcAnnotation",
predefined_type="ELEVATION",
should_add_representation=False,
context=context,
ifc_representation_class=None,
)
return element
@classmethod
def generate_grid_axis_reference_annotation(cls, drawing, reference_element, context):