mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-28 15:53:00 +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)
|
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):
|
class SectionViewDecorator(LevelDecorator):
|
||||||
objecttype = "SECTION"
|
objecttype = "SECTION"
|
||||||
|
|
||||||
@@ -1328,6 +1423,7 @@ class DecorationsHandler:
|
|||||||
StairDecorator,
|
StairDecorator,
|
||||||
BreakDecorator,
|
BreakDecorator,
|
||||||
SectionViewDecorator,
|
SectionViewDecorator,
|
||||||
|
ElevationDecorator,
|
||||||
TextDecorator,
|
TextDecorator,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,13 @@ def sync_references(ifc, collector, drawing_tool, drawing=None):
|
|||||||
should_delete_existing_annotation = False
|
should_delete_existing_annotation = False
|
||||||
should_create_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
|
should_delete_existing_annotation = True
|
||||||
|
|
||||||
if reference_obj and (should_delete_existing_annotation or not annotation):
|
if reference_obj and (should_delete_existing_annotation or not annotation):
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import bpy
|
import bpy
|
||||||
|
import math
|
||||||
import bmesh
|
import bmesh
|
||||||
import mathutils
|
import mathutils
|
||||||
import webbrowser
|
import webbrowser
|
||||||
@@ -407,6 +408,95 @@ class Drawing(blenderbim.core.tool.Drawing):
|
|||||||
def generate_reference_annotation(cls, drawing, reference_element, context):
|
def generate_reference_annotation(cls, drawing, reference_element, context):
|
||||||
if reference_element.is_a("IfcGridAxis"):
|
if reference_element.is_a("IfcGridAxis"):
|
||||||
return cls.generate_grid_axis_reference_annotation(drawing, reference_element, context)
|
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
|
@classmethod
|
||||||
def generate_grid_axis_reference_annotation(cls, drawing, reference_element, context):
|
def generate_grid_axis_reference_annotation(cls, drawing, reference_element, context):
|
||||||
|
|||||||
Reference in New Issue
Block a user