mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
@@ -21,7 +21,6 @@ class BaseDecorator():
|
||||
|
||||
DEF_GLSL = """
|
||||
#define PI 3.141592653589793
|
||||
#define COLOR vec4({color[0]}, {color[1]}, {color[2]}, {color[3]})
|
||||
#define MAX_POINTS 64
|
||||
#define CIRCLE_SEGS 24
|
||||
"""
|
||||
@@ -99,63 +98,28 @@ class BaseDecorator():
|
||||
"""
|
||||
|
||||
FRAG_GLSL = """
|
||||
uniform vec4 color;
|
||||
out vec4 fragColor;
|
||||
|
||||
void main() {
|
||||
fragColor = COLOR;
|
||||
fragColor = color;
|
||||
}
|
||||
"""
|
||||
|
||||
# class var for single handler
|
||||
installed = None
|
||||
|
||||
@classmethod
|
||||
def install(cls, *args, **kwargs):
|
||||
if cls.installed:
|
||||
cls.uninstall()
|
||||
handler = cls(*args, **kwargs)
|
||||
cls.installed = SpaceView3D.draw_handler_add(handler, (), 'WINDOW', 'POST_PIXEL')
|
||||
|
||||
@classmethod
|
||||
def uninstall(cls):
|
||||
try:
|
||||
SpaceView3D.draw_handler_remove(cls.installed, 'WINDOW')
|
||||
except ValueError:
|
||||
pass
|
||||
cls.installed = None
|
||||
|
||||
def __init__(self, props, context):
|
||||
self.context = context
|
||||
self.props = props
|
||||
self.shader = self.create_shader()
|
||||
self.font_id = 0
|
||||
self.font_size = 16
|
||||
self.dpi = context.preferences.system.dpi
|
||||
|
||||
def create_shader(self):
|
||||
defines = self.DEF_GLSL.format(color=self.props.decorations_colour)
|
||||
def __init__(self):
|
||||
# NB: libcode param doesn't work
|
||||
return GPUShader(vertexcode=self.VERT_GLSL,
|
||||
fragcode=self.FRAG_GLSL,
|
||||
geocode=self.LIB_GLSL + self.GEOM_GLSL,
|
||||
defines=defines)
|
||||
self.shader = GPUShader(vertexcode=self.VERT_GLSL,
|
||||
fragcode=self.FRAG_GLSL,
|
||||
geocode=self.LIB_GLSL + self.GEOM_GLSL,
|
||||
defines=self.DEF_GLSL)
|
||||
|
||||
def __call__(self):
|
||||
if self.props.active_drawing_index is None or len(self.props.drawings) == 0:
|
||||
return
|
||||
|
||||
for obj in self.get_objects():
|
||||
self.decorate(obj)
|
||||
|
||||
def get_objects(self):
|
||||
def get_objects(self, collection):
|
||||
"""find relevant objects
|
||||
using class.basename
|
||||
|
||||
returns: iterable of blender objects
|
||||
"""
|
||||
drawing = self.props.drawings[self.props.active_drawing_index]
|
||||
collection = bpy.data.collections.get("IfcGroup/" + drawing.name)
|
||||
return filter(lambda o: self.basename in o.name, collection.objects)
|
||||
return filter(lambda o: self.basename in o.name, collection.all_objects)
|
||||
|
||||
def get_path_geom(self, obj, topo=True):
|
||||
"""Parses path geometry into line segments
|
||||
@@ -223,13 +187,14 @@ class BaseDecorator():
|
||||
|
||||
return vertices, indices
|
||||
|
||||
def decorate(self, object):
|
||||
def decorate(self, context, object):
|
||||
"""perform actuall drawing stuff"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw_lines(self, obj, vertices, indices, topology=None):
|
||||
region = self.context.region
|
||||
region3d = self.context.region_data
|
||||
def draw_lines(self, context, obj, vertices, indices, topology=None):
|
||||
region = context.region
|
||||
region3d = context.region_data
|
||||
color = context.scene.DocProperties.decorations_colour
|
||||
|
||||
fmt = GPUVertFormat()
|
||||
fmt.attr_add(id="pos", comp_type='F32', len=3, fetch_mode='FLOAT')
|
||||
@@ -245,18 +210,20 @@ class BaseDecorator():
|
||||
|
||||
batch = GPUBatch(type='LINES', buf=vbo, elem=ibo)
|
||||
|
||||
self.shader.bind()
|
||||
self.shader.uniform_float
|
||||
self.shader.uniform_float("viewMatrix", region3d.perspective_matrix)
|
||||
self.shader.uniform_float("winsize", (region.width, region.height))
|
||||
|
||||
bgl.glEnable(bgl.GL_LINE_SMOOTH)
|
||||
bgl.glHint(bgl.GL_LINE_SMOOTH_HINT, bgl.GL_NICEST)
|
||||
bgl.glEnable(bgl.GL_BLEND)
|
||||
bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
self.shader.bind()
|
||||
self.shader.uniform_float
|
||||
self.shader.uniform_float("viewMatrix", region3d.perspective_matrix)
|
||||
self.shader.uniform_float("winsize", (region.width, region.height))
|
||||
self.shader.uniform_float("color", color)
|
||||
|
||||
batch.draw(self.shader)
|
||||
|
||||
def draw_label(self, text, pos, dir, gap=4, center=True, vcenter=False):
|
||||
def draw_label(self, context, text, pos, dir, gap=4, center=True, vcenter=False):
|
||||
"""Draw text label
|
||||
|
||||
Args:
|
||||
@@ -264,15 +231,21 @@ class BaseDecorator():
|
||||
|
||||
aligned and centered at segment middle
|
||||
"""
|
||||
font_id = 0
|
||||
font_size = 16
|
||||
dpi = context.preferences.system.dpi
|
||||
|
||||
color = context.scene.DocProperties.decorations_colour
|
||||
|
||||
ang = -Vector((1, 0)).angle_signed(dir)
|
||||
cos = math.cos(ang)
|
||||
sin = math.sin(ang)
|
||||
|
||||
blf.size(self.font_id, self.font_size, self.dpi)
|
||||
blf.size(font_id, font_size, dpi)
|
||||
|
||||
w, h = 0, 0
|
||||
if center or vcenter:
|
||||
w, h = blf.dimensions(self.font_id, text)
|
||||
w, h = blf.dimensions(font_id, text)
|
||||
|
||||
if center:
|
||||
# horizontal centering
|
||||
@@ -286,18 +259,18 @@ class BaseDecorator():
|
||||
# side-shifting
|
||||
pos += Vector((-sin, cos)) * gap
|
||||
|
||||
blf.enable(self.font_id, blf.ROTATION)
|
||||
blf.position(self.font_id, pos.x, pos.y, 0)
|
||||
blf.enable(font_id, blf.ROTATION)
|
||||
blf.position(font_id, pos.x, pos.y, 0)
|
||||
|
||||
blf.rotation(self.font_id, ang)
|
||||
blf.color(self.font_id, *self.props.decorations_colour)
|
||||
blf.draw(self.font_id, text)
|
||||
blf.disable(self.font_id, blf.ROTATION)
|
||||
blf.rotation(font_id, ang)
|
||||
blf.color(font_id, *color)
|
||||
blf.draw(font_id, text)
|
||||
blf.disable(font_id, blf.ROTATION)
|
||||
|
||||
def format_value(self, value):
|
||||
unit_system = bpy.context.scene.unit_settings.system
|
||||
def format_value(self, context, value):
|
||||
unit_system = context.scene.unit_settings.system
|
||||
if unit_system == 'IMPERIAL':
|
||||
precision = bpy.context.scene.BIMProperties.imperial_precision
|
||||
precision = context.scene.BIMProperties.imperial_precision
|
||||
if precision == "NONE":
|
||||
precision = 256
|
||||
elif precision == "1":
|
||||
@@ -318,7 +291,6 @@ class DimensionDecorator(BaseDecorator):
|
||||
- puts metric text next to each segment
|
||||
"""
|
||||
basename = "IfcAnnotation/Dimension"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define ARROW_ANGLE PI / 12.0
|
||||
@@ -382,14 +354,14 @@ class DimensionDecorator(BaseDecorator):
|
||||
}
|
||||
"""
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
verts, idxs, _ = self.get_path_geom(obj, topo=False)
|
||||
self.draw_lines(obj, verts, idxs)
|
||||
self.draw_labels(obj, verts, idxs)
|
||||
self.draw_lines(context, obj, verts, idxs)
|
||||
self.draw_labels(context, obj, verts, idxs)
|
||||
|
||||
def draw_labels(self, obj, vertices, indices):
|
||||
region = self.context.region
|
||||
region3d = self.context.region_data
|
||||
def draw_labels(self, context, obj, vertices, indices):
|
||||
region = context.region
|
||||
region3d = context.region_data
|
||||
for i0, i1 in indices:
|
||||
v0 = Vector(vertices[i0])
|
||||
v1 = Vector(vertices[i1])
|
||||
@@ -399,8 +371,8 @@ class DimensionDecorator(BaseDecorator):
|
||||
if dir.length < 1:
|
||||
continue
|
||||
length = (v1 - v0).length
|
||||
text = self.format_value(length)
|
||||
self.draw_label(text, p0 + (dir) * .5, dir)
|
||||
text = self.format_value(context, length)
|
||||
self.draw_label(context, text, p0 + (dir) * .5, dir)
|
||||
|
||||
|
||||
class EqualityDecorator(DimensionDecorator):
|
||||
@@ -410,11 +382,10 @@ class EqualityDecorator(DimensionDecorator):
|
||||
- puts 'EQ' label
|
||||
"""
|
||||
basename = "IfcAnnotation/Equal"
|
||||
installed = None
|
||||
|
||||
def draw_labels(self, obj, vertices, indices):
|
||||
region = self.context.region
|
||||
region3d = self.context.region_data
|
||||
def draw_labels(self, context, obj, vertices, indices):
|
||||
region = context.region
|
||||
region3d = context.region_data
|
||||
for i0, i1 in indices:
|
||||
v0 = Vector(vertices[i0])
|
||||
v1 = Vector(vertices[i1])
|
||||
@@ -423,7 +394,7 @@ class EqualityDecorator(DimensionDecorator):
|
||||
dir = p1 - p0
|
||||
if dir.length < 1:
|
||||
continue
|
||||
self.draw_label("EQ", p0 + (dir) * .5, dir)
|
||||
self.draw_label(context, "EQ", p0 + (dir) * .5, dir)
|
||||
|
||||
|
||||
class LeaderDecorator(BaseDecorator):
|
||||
@@ -432,7 +403,6 @@ class LeaderDecorator(BaseDecorator):
|
||||
- middle points w/out decorations
|
||||
"""
|
||||
basename = "IfcAnnotation/Leader"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define ARROW_ANGLE PI / 12.0
|
||||
@@ -489,9 +459,9 @@ class LeaderDecorator(BaseDecorator):
|
||||
}
|
||||
"""
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
verts, idxs, topo = self.get_path_geom(obj)
|
||||
self.draw_lines(obj, verts, idxs, topo)
|
||||
self.draw_lines(context, obj, verts, idxs, topo)
|
||||
|
||||
|
||||
class StairDecorator(BaseDecorator):
|
||||
@@ -501,7 +471,6 @@ class StairDecorator(BaseDecorator):
|
||||
- middle points w/out decorations
|
||||
"""
|
||||
basename = "IfcAnnotation/Stair"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define CIRCLE_SIZE 8.0
|
||||
@@ -575,14 +544,13 @@ class StairDecorator(BaseDecorator):
|
||||
}
|
||||
"""
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
verts, idxs, topo = self.get_path_geom(obj)
|
||||
self.draw_lines(obj, verts, idxs, topo)
|
||||
self.draw_lines(context, obj, verts, idxs, topo)
|
||||
|
||||
|
||||
class HiddenDecorator(BaseDecorator):
|
||||
basename = "IfcAnnotation/Hidden"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define DASH_SIZE 16.0
|
||||
@@ -624,6 +592,7 @@ class HiddenDecorator(BaseDecorator):
|
||||
"""
|
||||
|
||||
FRAG_GLSL = """
|
||||
uniform vec4 color;
|
||||
in vec2 gl_FragCoord;
|
||||
in float dist;
|
||||
out vec4 fragColor;
|
||||
@@ -631,21 +600,20 @@ class HiddenDecorator(BaseDecorator):
|
||||
void main() {
|
||||
uint bit = uint(fract(dist / DASH_SIZE) * 32);
|
||||
if ((DASH_PATTERN & (1U<<bit)) == 0U) discard;
|
||||
fragColor = COLOR;
|
||||
fragColor = color;
|
||||
}
|
||||
"""
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
if obj.data.is_editmode:
|
||||
verts, idxs = self.get_editmesh_geom(obj)
|
||||
else:
|
||||
verts, idxs = self.get_mesh_geom(obj)
|
||||
self.draw_lines(obj, verts, idxs)
|
||||
self.draw_lines(context, obj, verts, idxs)
|
||||
|
||||
|
||||
class MiscDecorator(HiddenDecorator):
|
||||
basename = "IfcAnnotation/Misc"
|
||||
installed = None
|
||||
|
||||
FRAG_GLSL = BaseDecorator.FRAG_GLSL
|
||||
|
||||
@@ -666,16 +634,15 @@ class LevelDecorator(BaseDecorator):
|
||||
continue
|
||||
yield [obj.matrix_world @ p.co for p in spline_points]
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
verts, idxs, topo = self.get_path_geom(obj)
|
||||
self.draw_lines(obj, verts, idxs, topo)
|
||||
self.draw_lines(context, obj, verts, idxs, topo)
|
||||
splines = self.get_splines(obj)
|
||||
self.draw_labels(obj, splines)
|
||||
self.draw_labels(context, obj, splines)
|
||||
|
||||
|
||||
class PlanDecorator(LevelDecorator):
|
||||
basename = "IfcAnnotation/Plan Level"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define CIRCLE_SIZE 8.0
|
||||
@@ -741,9 +708,9 @@ class PlanDecorator(LevelDecorator):
|
||||
}
|
||||
"""
|
||||
|
||||
def draw_labels(self, obj, splines):
|
||||
region = self.context.region
|
||||
region3d = self.context.region_data
|
||||
def draw_labels(self, context, obj, splines):
|
||||
region = context.region
|
||||
region3d = context.region_data
|
||||
for verts in splines:
|
||||
v0 = verts[0]
|
||||
v1 = verts[1]
|
||||
@@ -752,13 +719,12 @@ class PlanDecorator(LevelDecorator):
|
||||
dir = p1 - p0
|
||||
if dir.length < 1:
|
||||
continue
|
||||
text = "RL " + self.format_value(verts[-1].z)
|
||||
self.draw_label(text, p0, dir, gap=8, center=False)
|
||||
text = "RL " + self.format_value(context, verts[-1].z)
|
||||
self.draw_label(context, text, p0, dir, gap=8, center=False)
|
||||
|
||||
|
||||
class SectionDecorator(LevelDecorator):
|
||||
basename = "IfcAnnotation/Section Level"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define CALLOUT_GAP 8.0
|
||||
@@ -821,9 +787,9 @@ class SectionDecorator(LevelDecorator):
|
||||
}
|
||||
"""
|
||||
|
||||
def draw_labels(self, obj, splines):
|
||||
region = self.context.region
|
||||
region3d = self.context.region_data
|
||||
def draw_labels(self, context, obj, splines):
|
||||
region = context.region
|
||||
region3d = context.region_data
|
||||
for verts in splines:
|
||||
v0 = verts[0]
|
||||
v1 = verts[1]
|
||||
@@ -832,8 +798,8 @@ class SectionDecorator(LevelDecorator):
|
||||
dir = p1 - p0
|
||||
if dir.length < 1:
|
||||
continue
|
||||
text = "RL " + self.format_value(verts[-1].z)
|
||||
self.draw_label(text, p0 + dir.normalized() * 16, -dir, gap=16, center=False)
|
||||
text = "RL " + self.format_value(context, verts[-1].z)
|
||||
self.draw_label(context, text, p0 + dir.normalized() * 16, -dir, gap=16, center=False)
|
||||
|
||||
|
||||
class BreakDecorator(BaseDecorator):
|
||||
@@ -843,7 +809,6 @@ class BreakDecorator(BaseDecorator):
|
||||
Uses first two vertices in verts list.
|
||||
"""
|
||||
basename = "IfcAnnotation/Break"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define BREAK_LENGTH 32.0
|
||||
@@ -898,12 +863,12 @@ class BreakDecorator(BaseDecorator):
|
||||
}
|
||||
"""
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
if obj.data.is_editmode:
|
||||
verts = self.get_editmesh_geom(obj)
|
||||
else:
|
||||
verts = self.get_mesh_geom(obj)
|
||||
self.draw_lines(obj, verts, [(0, 1)])
|
||||
self.draw_lines(context, obj, verts, [(0, 1)])
|
||||
|
||||
def get_mesh_geom(self, obj):
|
||||
# first vertices only
|
||||
@@ -919,7 +884,6 @@ class BreakDecorator(BaseDecorator):
|
||||
|
||||
class GridDecorator(BaseDecorator):
|
||||
basename = "IfcGridAxis/"
|
||||
installed = None
|
||||
|
||||
DEF_GLSL = BaseDecorator.DEF_GLSL + """
|
||||
#define CIRCLE_SIZE 16.0
|
||||
@@ -988,6 +952,7 @@ class GridDecorator(BaseDecorator):
|
||||
"""
|
||||
|
||||
FRAG_GLSL = """
|
||||
uniform vec4 color;
|
||||
in vec2 gl_FragCoord;
|
||||
in float dist;
|
||||
out vec4 fragColor;
|
||||
@@ -995,7 +960,7 @@ class GridDecorator(BaseDecorator):
|
||||
void main() {
|
||||
uint bit = uint(fract(dist / DASH_SIZE) * 32);
|
||||
if ((DASH_PATTERN & (1U<<bit)) == 0U) discard;
|
||||
fragColor = COLOR;
|
||||
fragColor = color;
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -1010,36 +975,68 @@ class GridDecorator(BaseDecorator):
|
||||
vertices = [obj.matrix_world @ v.co for v in mesh.edges[0].verts]
|
||||
return vertices
|
||||
|
||||
def decorate(self, obj):
|
||||
def decorate(self, context, obj):
|
||||
if obj.data.is_editmode:
|
||||
verts = self.get_editmesh_geom(obj)
|
||||
else:
|
||||
verts = self.get_mesh_geom(obj)
|
||||
self.draw_lines(obj, verts, [(0, 1)])
|
||||
self.draw_labels(obj, verts)
|
||||
self.draw_lines(context, obj, verts, [(0, 1)])
|
||||
self.draw_labels(context, obj, verts)
|
||||
|
||||
def draw_labels(self, obj, vertices):
|
||||
region = self.context.region
|
||||
region3d = self.context.region_data
|
||||
def draw_labels(self, context, obj, vertices):
|
||||
region = context.region
|
||||
region3d = context.region_data
|
||||
v0 = Vector(vertices[0])
|
||||
v1 = Vector(vertices[1])
|
||||
p0 = location_3d_to_region_2d(region, region3d, v0)
|
||||
p1 = location_3d_to_region_2d(region, region3d, v1)
|
||||
dir = Vector((1, 0))
|
||||
text = obj.BIMObjectProperties.attributes['AxisTag'].string_value
|
||||
self.draw_label(text, p0, dir, vcenter=True, gap=0)
|
||||
self.draw_label(text, p1, dir, vcenter=True, gap=0)
|
||||
self.draw_label(context, text, p0, dir, vcenter=True, gap=0)
|
||||
self.draw_label(context, text, p1, dir, vcenter=True, gap=0)
|
||||
|
||||
|
||||
all_decorators = [
|
||||
DimensionDecorator,
|
||||
EqualityDecorator,
|
||||
GridDecorator,
|
||||
HiddenDecorator,
|
||||
LeaderDecorator,
|
||||
MiscDecorator,
|
||||
PlanDecorator,
|
||||
SectionDecorator,
|
||||
StairDecorator,
|
||||
BreakDecorator
|
||||
]
|
||||
class DecorationsHandler():
|
||||
decorators_classes = [
|
||||
DimensionDecorator,
|
||||
EqualityDecorator,
|
||||
GridDecorator,
|
||||
HiddenDecorator,
|
||||
LeaderDecorator,
|
||||
MiscDecorator,
|
||||
PlanDecorator,
|
||||
SectionDecorator,
|
||||
StairDecorator,
|
||||
BreakDecorator
|
||||
]
|
||||
|
||||
installed = None
|
||||
|
||||
@classmethod
|
||||
def install(cls, context):
|
||||
if cls.installed:
|
||||
cls.uninstall()
|
||||
handler = cls()
|
||||
cls.installed = SpaceView3D.draw_handler_add(handler, (context,), 'WINDOW', 'POST_PIXEL')
|
||||
|
||||
@classmethod
|
||||
def uninstall(cls):
|
||||
try:
|
||||
SpaceView3D.draw_handler_remove(cls.installed, 'WINDOW')
|
||||
except ValueError:
|
||||
pass
|
||||
cls.installed = None
|
||||
|
||||
def __init__(self):
|
||||
self.decorators = [cls() for cls in self.decorators_classes]
|
||||
|
||||
def __call__(self, context):
|
||||
props = context.scene.DocProperties
|
||||
if props.active_drawing_index is None or len(props.drawings) == 0:
|
||||
return
|
||||
drawing = props.drawings[props.active_drawing_index]
|
||||
collection = bpy.data.collections.get("IfcGroup/" + drawing.name)
|
||||
|
||||
for decorator in self.decorators:
|
||||
for obj in decorator.get_objects(collection):
|
||||
decorator.decorate(context, obj)
|
||||
|
||||
@@ -348,11 +348,9 @@ def refreshTitleblocks(self, context):
|
||||
def toggleDecorations(self, context):
|
||||
toggle = self.should_draw_decorations
|
||||
if toggle:
|
||||
for dec in decoration.all_decorators:
|
||||
dec.install(self, context)
|
||||
decoration.DecorationsHandler.install(context)
|
||||
else:
|
||||
for dec in decoration.all_decorators:
|
||||
dec.uninstall()
|
||||
decoration.DecorationsHandler.uninstall()
|
||||
|
||||
|
||||
def getScenarios(self, context):
|
||||
@@ -657,8 +655,7 @@ class DocProperties(PropertyGroup):
|
||||
drawing_styles: CollectionProperty(name="Drawing Styles", type=DrawingStyle)
|
||||
should_draw_decorations: BoolProperty(name="Should Draw Decorations", update=toggleDecorations)
|
||||
decorations_colour: FloatVectorProperty(name="Decorations Colour", subtype="COLOR", default=(1, 0, 0, 1),
|
||||
min=0.0, max=1.0, size=4,
|
||||
update=toggleDecorations)
|
||||
min=0.0, max=1.0, size=4)
|
||||
|
||||
|
||||
class BIMCameraProperties(PropertyGroup):
|
||||
|
||||
Reference in New Issue
Block a user