mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
#1153. Elevation references are now auto generated when activating drawings.
This commit is contained in:
@@ -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,
|
||||
]
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user