From 33bf7054bf849d77776e66aa8017677d1912acef Mon Sep 17 00:00:00 2001 From: QwiglyDee Date: Thu, 10 Dec 2020 23:49:35 +0700 Subject: [PATCH 01/26] ui and decorator handler --- .../blenderbim/bim/.gitignore | 2 + .../blenderbim/bim/decoration.py | 47 +++++++++++++++++++ src/ifcblenderexport/blenderbim/bim/prop.py | 10 ++++ src/ifcblenderexport/blenderbim/bim/ui.py | 7 ++- 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 src/ifcblenderexport/blenderbim/bim/.gitignore create mode 100644 src/ifcblenderexport/blenderbim/bim/decoration.py diff --git a/src/ifcblenderexport/blenderbim/bim/.gitignore b/src/ifcblenderexport/blenderbim/bim/.gitignore new file mode 100644 index 0000000000..4b1304fd48 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/.gitignore @@ -0,0 +1,2 @@ +# addon writes tmp stuff directly to its dir +/data/ \ No newline at end of file diff --git a/src/ifcblenderexport/blenderbim/bim/decoration.py b/src/ifcblenderexport/blenderbim/bim/decoration.py new file mode 100644 index 0000000000..9457e495c8 --- /dev/null +++ b/src/ifcblenderexport/blenderbim/bim/decoration.py @@ -0,0 +1,47 @@ +"""Viewport decorations""" +from bpy.types import SpaceView3D +import bpy +import blf + + +class ViewDecorator(object): + # class var for single handler + installed = None + + @classmethod + def install(cls, *args, **kwargs): + handler = cls(*args, **kwargs) + cls.installed = SpaceView3D.draw_handler_add(handler, (), 'WINDOW', 'POST_PIXEL') + + @classmethod + def uninstall(cls): + SpaceView3D.draw_handler_remove(cls.installed, 'WINDOW') + cls.installed = None + + +class DimensionDecorator(ViewDecorator): + """Decorates dimension curves + - outlines each segment with an arrow + - puts metric text next to each segment + """ + + def __init__(self, scene, context): + self.scene = scene + self.context = context + self.font_id = 0 + self.dpi = context.preferences.system.dpi + print("Created decorator", scene) + + def __call__(self): + # get active drawing, if any + if self.scene.active_drawing_index is None or len(self.scene.drawings) == 0: + return + drawing = self.scene.drawings[self.scene.active_drawing_index] + collection = bpy.data.collections.get("IfcGroup/" + drawing.name) + if 'IfcAnnotation/Dimension' not in collection.all_objects: + return + curve = collection.all_objects['IfcAnnotation/Dimension'].data + text = repr(curve) + blf.position(self.font_id, 100, 100, 0) + blf.size(self.font_id, 10, self.dpi) + blf.draw(self.font_id, text) diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 2d08aceda3..6985fa0fa8 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -8,6 +8,7 @@ from . import schema from . import bcf from . import ifc from . import annotation +from . import decoration import bpy from bpy.types import PropertyGroup from bpy.app.handlers import persistent @@ -357,6 +358,14 @@ def refreshTitleblocks(self, context): getTitleblocks(self, context) +def toggleDimDecorations(self, context): + toggle = self.dim_decorations + if toggle: + decoration.DimensionDecorator.install(self, context) + else: + decoration.DimensionDecorator.uninstall() + + def getScenarios(self, context): global scenarios_enum if len(scenarios_enum) < 1: @@ -668,6 +677,7 @@ class DocProperties(PropertyGroup): active_sheet_index: IntProperty(name="Active Sheet Index") ifc_files: CollectionProperty(name="IFCs", type=StrProperty) drawing_styles: CollectionProperty(name="Drawing Styles", type=DrawingStyle) + dim_decorations: BoolProperty(name="Decorate dimentions", update=toggleDimDecorations) class BIMCameraProperties(PropertyGroup): diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 8a5b86c016..08b4f36d2d 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -2352,6 +2352,9 @@ class BIM_PT_annotation_utilities(Panel): row.operator("bim.remove_drawing", icon="X", text="").index = props.active_drawing_index layout.template_list("BIM_UL_generic", "", props, "drawings", props, "active_drawing_index") + row = layout.row() + row.prop(props, 'dim_decorations') + class BIM_PT_qto_utilities(Panel): bl_idname = "BIM_PT_qto_utilities" @@ -2396,7 +2399,7 @@ class BIM_PT_clash_manager(Panel): row = layout.row() layout.label(text="Select output path for smart-grouped clashes:") - + row = layout.row(align=True) row.prop(props, "smart_grouped_clashes_path", text="") op = row.operator("bim.select_smart_grouped_clashes_path", icon="FILE_FOLDER", text="") @@ -2409,7 +2412,7 @@ class BIM_PT_clash_manager(Panel): row = layout.row(align=True) row.operator("bim.load_smart_groups_for_active_clash_set") - + layout.template_list('BIM_UL_smart_groups', '', props, 'smart_clash_groups', props, 'active_smart_group_index') row = layout.row(align=True) From cc5f34a705334ced9093f63f5c8ad0b07281f787 Mon Sep 17 00:00:00 2001 From: QwiglyDee Date: Fri, 11 Dec 2020 01:43:00 +0700 Subject: [PATCH 02/26] text drawing --- .../blenderbim/bim/decoration.py | 84 ++++++++++++++++--- 1 file changed, 73 insertions(+), 11 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/decoration.py b/src/ifcblenderexport/blenderbim/bim/decoration.py index 9457e495c8..67d0882eed 100644 --- a/src/ifcblenderexport/blenderbim/bim/decoration.py +++ b/src/ifcblenderexport/blenderbim/bim/decoration.py @@ -1,7 +1,10 @@ """Viewport decorations""" +import math from bpy.types import SpaceView3D +from mathutils import Vector import bpy import blf +from bpy_extras.view3d_utils import location_3d_to_region_2d class ViewDecorator(object): @@ -15,7 +18,10 @@ class ViewDecorator(object): @classmethod def uninstall(cls): - SpaceView3D.draw_handler_remove(cls.installed, 'WINDOW') + try: + SpaceView3D.draw_handler_remove(cls.installed, 'WINDOW') + except ValueError: + pass cls.installed = None @@ -25,23 +31,79 @@ class DimensionDecorator(ViewDecorator): - puts metric text next to each segment """ - def __init__(self, scene, context): - self.scene = scene + def __init__(self, props, context): self.context = context - self.font_id = 0 + self.props = props + self.font_id = 0 # TODO: take font from styles self.dpi = context.preferences.system.dpi - print("Created decorator", scene) def __call__(self): # get active drawing, if any - if self.scene.active_drawing_index is None or len(self.scene.drawings) == 0: + if self.props.active_drawing_index is None or len(self.props.drawings) == 0: return - drawing = self.scene.drawings[self.scene.active_drawing_index] + drawing = self.props.drawings[self.props.active_drawing_index] collection = bpy.data.collections.get("IfcGroup/" + drawing.name) + # get curve object if 'IfcAnnotation/Dimension' not in collection.all_objects: return - curve = collection.all_objects['IfcAnnotation/Dimension'].data - text = repr(curve) - blf.position(self.font_id, 100, 100, 0) - blf.size(self.font_id, 10, self.dpi) + curve = collection.all_objects['IfcAnnotation/Dimension'] + + for segm in self.iter_segments(curve): + self.draw_label(segm) + self.draw_arrow(segm) + + def iter_segments(self, curve): + """Yields each segment converted to world coords + (v0, v1, length) + """ + for spline in curve.data.splines: + points = [curve.matrix_world @ p.co for p in spline.points] + for i in range(len(points)-1): + p0 = points[i] + p1 = points[i+1] + length = (p1 - p0).length + yield (p0, p1, length) + + def draw_label(self, segm): + """Draw text of segment length + aligned and centered at segment middle + """ + p0, p1, length = segm + + # convert to view coords + region = self.context.region + region3d = self.context.region_data + p0 = location_3d_to_region_2d(region, region3d, p0) + p1 = location_3d_to_region_2d(region, region3d, p1) + + text = f"{length:.2f}" + + ang = -Vector((1, 0)).angle_signed(p1 - p0) + cos = math.cos(ang) + sin = math.sin(ang) + + # midpoint + pos = p0 + (p1 - p0) * .5 + + # TODO: take font size from styles + blf.size(self.font_id, 16, self.dpi) + w, h = blf.dimensions(self.font_id, text) + + # align centered + pos -= Vector((cos, sin)) * w * 0.5 + + # add padding + # TODO: take padding from styles and adjust to line width + pos += Vector((-sin, cos)) * 4 + + # TODO: handle overlapping of text with arrows for narrow segments + + blf.enable(self.font_id, blf.ROTATION) + blf.position(self.font_id, pos.x, pos.y, 0) + + blf.rotation(self.font_id, ang) blf.draw(self.font_id, text) + blf.disable(self.font_id, blf.ROTATION) + + def draw_arrow(self, segm): + pass \ No newline at end of file From f37283f61c9c5ef30fa071b11130d2c38b64d611 Mon Sep 17 00:00:00 2001 From: QwiglyDee Date: Fri, 11 Dec 2020 04:15:37 +0700 Subject: [PATCH 03/26] drawing arrows --- .../blenderbim/bim/decoration.py | 97 ++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/decoration.py b/src/ifcblenderexport/blenderbim/bim/decoration.py index 67d0882eed..f17e08ced8 100644 --- a/src/ifcblenderexport/blenderbim/bim/decoration.py +++ b/src/ifcblenderexport/blenderbim/bim/decoration.py @@ -1,10 +1,15 @@ """Viewport decorations""" import math +from functools import reduce from bpy.types import SpaceView3D from mathutils import Vector import bpy import blf from bpy_extras.view3d_utils import location_3d_to_region_2d +import gpu +import bgl +from gpu.types import GPUShader, GPUBatch, GPUIndexBuf, GPUVertBuf, GPUVertFormat +from gpu_extras.batch import batch_for_shader class ViewDecorator(object): @@ -31,11 +36,81 @@ class DimensionDecorator(ViewDecorator): - puts metric text next to each segment """ + VERT_GLSL = """ + uniform mat4 viewMatrix; + in vec3 pos; + out vec4 gl_Position; + + void main() { + gl_Position = viewMatrix * vec4(pos, 1.0); + } + """ + GEOM_GLSL = """ + layout(lines) in; + layout(line_strip, max_vertices=8) out; + + uniform float angle; + uniform float length; + + void main() { + vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position; + float c = cos(angle), s = sin(angle); + mat4 rot_a = mat4( c, -s, 0, 0, + +s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + mat4 rot_b = mat4( c, +s, 0, 0, + -s, c, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + + vec4 dir = normalize(p1 - p0); + + vec4 arr_a = rot_a * dir * length; + vec4 arr_b = rot_b * dir * length; + + gl_Position = p0; + EmitVertex(); + gl_Position = p1; + EmitVertex(); + EndPrimitive(); + + gl_Position = p0 + arr_a; + EmitVertex(); + gl_Position = p0; + EmitVertex(); + gl_Position = p0 + arr_b; + EmitVertex(); + EndPrimitive(); + + gl_Position = p1 - arr_a; + EmitVertex(); + gl_Position = p1; + EmitVertex(); + gl_Position = p1 - arr_b; + EmitVertex(); + EndPrimitive(); + } + """ + FRAG_GLSL = """ + uniform vec3 color; + out vec4 fragColor; + + void main() { + fragColor = vec4(color, 1.0); + } + """ + def __init__(self, props, context): self.context = context self.props = props self.font_id = 0 # TODO: take font from styles self.dpi = context.preferences.system.dpi + self.shader = self.create_shader() + + @classmethod + def create_shader(cls): + return GPUShader(vertexcode=cls.VERT_GLSL, fragcode=cls.FRAG_GLSL, geocode=cls.GEOM_GLSL) def __call__(self): # get active drawing, if any @@ -48,9 +123,10 @@ class DimensionDecorator(ViewDecorator): return curve = collection.all_objects['IfcAnnotation/Dimension'] - for segm in self.iter_segments(curve): + segments = list(self.iter_segments(curve)) + self.draw_arrows(segments) + for segm in segments: self.draw_label(segm) - self.draw_arrow(segm) def iter_segments(self, curve): """Yields each segment converted to world coords @@ -105,5 +181,18 @@ class DimensionDecorator(ViewDecorator): blf.draw(self.font_id, text) blf.disable(self.font_id, blf.ROTATION) - def draw_arrow(self, segm): - pass \ No newline at end of file + def draw_arrows(self, segments): + def coords(segm): + return [(segm[0].x, segm[0].y, segm[0].z), + (segm[1].x, segm[1].y, segm[1].z)] + points = list(reduce(lambda points, segm: points + coords(segm), + segments, [])) + batch = batch_for_shader(self.shader, 'LINES', {'pos': points}) + self.shader.bind() + matrix = self.context.region_data.perspective_matrix + self.shader.uniform_float("viewMatrix", matrix) + # TODO: get everything from styles + self.shader.uniform_float('color', (1.0, 1.0, 1.0)) + self.shader.uniform_float('angle', math.pi / 12) + self.shader.uniform_float('length', 0.05) + batch.draw(self.shader) From 48de2f77ab57f6338c2ecb5e0f2c9951c04e0a7c Mon Sep 17 00:00:00 2001 From: QwiglyDee Date: Fri, 11 Dec 2020 05:44:50 +0700 Subject: [PATCH 04/26] fix arrows heads --- .../blenderbim/bim/decoration.py | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/decoration.py b/src/ifcblenderexport/blenderbim/bim/decoration.py index f17e08ced8..be7ab835fd 100644 --- a/src/ifcblenderexport/blenderbim/bim/decoration.py +++ b/src/ifcblenderexport/blenderbim/bim/decoration.py @@ -47,12 +47,15 @@ class DimensionDecorator(ViewDecorator): """ GEOM_GLSL = """ layout(lines) in; - layout(line_strip, max_vertices=8) out; + layout(line_strip, max_vertices=10) out; uniform float angle; uniform float length; + uniform float aspect; void main() { + /** generates arrows from lines */ + vec4 p0 = gl_in[0].gl_Position, p1 = gl_in[1].gl_Position; float c = cos(angle), s = sin(angle); mat4 rot_a = mat4( c, -s, 0, 0, @@ -64,32 +67,46 @@ class DimensionDecorator(ViewDecorator): 0, 0, 1, 0, 0, 0, 0, 1); - vec4 dir = normalize(p1 - p0); + // converting to and from square-space coordinates to calculate arrows + mat4 clip2square = mat4(aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + mat4 square2clip = mat4(1/aspect, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + vec4 dir = normalize((p1 - p0) * clip2square) * length; + vec4 head = dir * square2clip; + vec4 arr_a = dir * rot_a * square2clip; + vec4 arr_b = dir * rot_b * square2clip; - vec4 arr_a = rot_a * dir * length; - vec4 arr_b = rot_b * dir * length; - - gl_Position = p0; + gl_Position = p0 + head; EmitVertex(); - gl_Position = p1; + gl_Position = p1 - head; EmitVertex(); EndPrimitive(); - gl_Position = p0 + arr_a; - EmitVertex(); gl_Position = p0; EmitVertex(); + gl_Position = p0 + arr_a; + EmitVertex(); gl_Position = p0 + arr_b; EmitVertex(); + gl_Position = p0; + EmitVertex(); EndPrimitive(); - gl_Position = p1 - arr_a; - EmitVertex(); gl_Position = p1; EmitVertex(); gl_Position = p1 - arr_b; EmitVertex(); + gl_Position = p1 - arr_a; + EmitVertex(); + gl_Position = p1; + EmitVertex(); EndPrimitive(); +/* + gl_Position = vec4(0, 0, 0, 1) * square2clip; + EmitVertex(); + gl_Position = vec4(0.25, 0.25, 0, 1) * square2clip; + EmitVertex(); + EndPrimitive(); +*/ } """ FRAG_GLSL = """ @@ -189,10 +206,13 @@ class DimensionDecorator(ViewDecorator): segments, [])) batch = batch_for_shader(self.shader, 'LINES', {'pos': points}) self.shader.bind() + matrix = self.context.region_data.perspective_matrix + aspect = self.context.region.width / self.context.region.height self.shader.uniform_float("viewMatrix", matrix) # TODO: get everything from styles + self.shader.uniform_float('aspect', aspect) self.shader.uniform_float('color', (1.0, 1.0, 1.0)) self.shader.uniform_float('angle', math.pi / 12) - self.shader.uniform_float('length', 0.05) + self.shader.uniform_float('length', 32 / self.context.region.height) batch.draw(self.shader) From d5e6721ac46a0375ed5a806dcdcad5cc300715bf Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 11 Dec 2020 11:13:48 +1100 Subject: [PATCH 05/26] Minor fix to support multiple dimension objects for decorations. See #1150. --- src/ifcblenderexport/blenderbim/bim/decoration.py | 13 +++++++------ src/ifcblenderexport/blenderbim/bim/prop.py | 6 +++--- src/ifcblenderexport/blenderbim/bim/ui.py | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/decoration.py b/src/ifcblenderexport/blenderbim/bim/decoration.py index be7ab835fd..f7830afa26 100644 --- a/src/ifcblenderexport/blenderbim/bim/decoration.py +++ b/src/ifcblenderexport/blenderbim/bim/decoration.py @@ -135,12 +135,12 @@ class DimensionDecorator(ViewDecorator): return drawing = self.props.drawings[self.props.active_drawing_index] collection = bpy.data.collections.get("IfcGroup/" + drawing.name) - # get curve object - if 'IfcAnnotation/Dimension' not in collection.all_objects: - return - curve = collection.all_objects['IfcAnnotation/Dimension'] - segments = list(self.iter_segments(curve)) + curves = [o for o in collection.objects if "IfcAnnotation/Dimension" in o.name] + segments = [] + for curve in curves: + segments.extend(list(self.iter_segments(curve))) + self.draw_arrows(segments) for segm in segments: self.draw_label(segm) @@ -150,7 +150,8 @@ class DimensionDecorator(ViewDecorator): (v0, v1, length) """ for spline in curve.data.splines: - points = [curve.matrix_world @ p.co for p in spline.points] + spline_points = spline.bezier_points if spline.bezier_points else spline.points + points = [curve.matrix_world @ p.co for p in spline_points] for i in range(len(points)-1): p0 = points[i] p1 = points[i+1] diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 6985fa0fa8..877ba07354 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -358,8 +358,8 @@ def refreshTitleblocks(self, context): getTitleblocks(self, context) -def toggleDimDecorations(self, context): - toggle = self.dim_decorations +def toggleDecorations(self, context): + toggle = self.should_draw_decorations if toggle: decoration.DimensionDecorator.install(self, context) else: @@ -677,7 +677,7 @@ class DocProperties(PropertyGroup): active_sheet_index: IntProperty(name="Active Sheet Index") ifc_files: CollectionProperty(name="IFCs", type=StrProperty) drawing_styles: CollectionProperty(name="Drawing Styles", type=DrawingStyle) - dim_decorations: BoolProperty(name="Decorate dimentions", update=toggleDimDecorations) + should_draw_decorations: BoolProperty(name="Should Draw Decorations", update=toggleDecorations) class BIMCameraProperties(PropertyGroup): diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 08b4f36d2d..3b3bbd7cfc 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -2353,7 +2353,7 @@ class BIM_PT_annotation_utilities(Panel): layout.template_list("BIM_UL_generic", "", props, "drawings", props, "active_drawing_index") row = layout.row() - row.prop(props, 'dim_decorations') + row.prop(props, "should_draw_decorations") class BIM_PT_qto_utilities(Panel): From 14c726008d9438e68db72a696f81428fbc7245ff Mon Sep 17 00:00:00 2001 From: Vincent Cadoret Date: Fri, 11 Dec 2020 19:50:15 -0500 Subject: [PATCH 06/26] Split out clashes that were not grouped so they so up individually. --- src/ifcclash/ifcclash.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ifcclash/ifcclash.py b/src/ifcclash/ifcclash.py index 819cafff4c..4b9b3c47e9 100644 --- a/src/ifcclash/ifcclash.py +++ b/src/ifcclash/ifcclash.py @@ -283,7 +283,9 @@ class IfcClasher: continue clashes = clash_set["clashes"] if len(clashes) == 0: + print(f"Skipping clash set [{clash_set['name']}] since it contains no clash results.") continue + count_of_input_clashes += len(clashes) positions = [] @@ -307,7 +309,13 @@ class IfcClasher: if len(pred) == len(clashes.values()): i = 0 for clash in clashes.values(): - clash["smart_group"] = int(pred[i]) + int_prediction = int(pred[i]) + if int_prediction == -1: + # ungroup this clash since it's a single clash that we were not able to group. + new_clash_group_number = np.amax(pred).item() + 1 + i + clash["smart_group"] = new_clash_group_number + else: + clash["smart_group"] = int_prediction i += 1 # Create JSON with smart_groups that contain GlobalIDs From f3269b732f3a7a3e7f751e598a987f9615cecfa3 Mon Sep 17 00:00:00 2001 From: Vincent Cadoret Date: Fri, 11 Dec 2020 20:46:07 -0500 Subject: [PATCH 07/26] More sensible names for the Smart Clash Groups --- src/ifcblenderexport/blenderbim/bim/operator.py | 4 ++-- src/ifcblenderexport/blenderbim/bim/prop.py | 2 +- src/ifcclash/ifcclash.py | 11 +++++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index e14d627ea0..05b0e56cc3 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -1963,7 +1963,7 @@ class SmartClashGroup(bpy.types.Operator): else: for smart_group, global_id_pairs in smart_groups[0].items(): new_group = bpy.context.scene.BIMProperties.smart_clash_groups.add() - new_group.number = smart_group + new_group.number = f"{smart_group}" for pair in global_id_pairs: for id in pair: @@ -1997,7 +1997,7 @@ class LoadSmartGroupsForActiveClashSet(bpy.types.Operator): else: for smart_group, global_id_pairs in smart_groups[0].items(): new_group = bpy.context.scene.BIMProperties.smart_clash_groups.add() - new_group.number = int(smart_group) + new_group.number = f"{smart_group}" for pair in global_id_pairs: for id in pair: new_global_id = new_group.global_ids.add() diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 877ba07354..03d6f2850a 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -814,7 +814,7 @@ class PresentationLayer(PropertyGroup): layer_blocked: BoolProperty(name="LayerBlocked", default=False) class SmartClashGroup(PropertyGroup): - number: IntProperty(name="Number") + number: StringProperty(name="Number") global_ids: CollectionProperty(name="GlobalIDs", type=StrProperty) diff --git a/src/ifcclash/ifcclash.py b/src/ifcclash/ifcclash.py index 4b9b3c47e9..449c881481 100644 --- a/src/ifcclash/ifcclash.py +++ b/src/ifcclash/ifcclash.py @@ -334,6 +334,17 @@ class IfcClasher: count_of_smart_groups += len(smart_groups) output_clash_sets[clash_set["name"]].append(smart_groups) + # Rename the clash groups to something more sensible + for clash_set, smart_groups in output_clash_sets.items(): + clash_set_name = clash_set + # Only select the clashes that correspond to the actively selected IFC Clash Set + i = 1 + new_smart_group_name = "" + for smart_group, global_id_pairs in list(smart_groups[0].items()): + new_smart_group_name = f"{clash_set_name} - {i}" + smart_groups[0][new_smart_group_name] = smart_groups[0].pop(smart_group) + i += 1 + count_of_final_clash_sets = len(output_clash_sets) print(f"Took {count_of_input_clashes} clashes in {count_of_clash_sets} clash sets and turned", f"them into {count_of_smart_groups} smart groups in {count_of_final_clash_sets} clash sets") From e39a997f5f1bb2728127138792711972c94cd121 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 13 Dec 2020 13:44:50 +1100 Subject: [PATCH 08/26] Bump to latest bcfplugin, new operator to save BCF projects --- .../blenderbim/bim/__init__.py | 2 +- .../blenderbim/bim/operator.py | 36 +++++++++++-------- src/ifcblenderexport/blenderbim/bim/prop.py | 5 ++- src/ifcblenderexport/blenderbim/bim/ui.py | 7 ++-- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 653cd10110..6aa9c7f1b8 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -25,7 +25,7 @@ if bpy is not None: operator.UnassignClass, operator.SelectClass, operator.SelectType, - operator.SelectBcfFile, + operator.SaveBcfProject, operator.GetBcfTopics, operator.ViewBcfTopic, operator.ActivateBcfViewpoint, diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 05b0e56cc3..d59c3f4217 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -510,11 +510,12 @@ class RejectElement(bpy.types.Operator): class GetBcfTopics(bpy.types.Operator): bl_idname = "bim.get_bcf_topics" bl_label = "Get BCF Topics" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") def execute(self, context): import bcfplugin - bcfplugin.openProject(bpy.context.scene.BCFProperties.bcf_file) + bcfplugin.openProject(self.filepath) bcf.BcfStore.topics = bcfplugin.getTopics() while len(bpy.context.scene.BCFProperties.topics) > 0: bpy.context.scene.BCFProperties.topics.remove(0) @@ -523,6 +524,25 @@ class GetBcfTopics(bpy.types.Operator): new.name = topic[0] return {"FINISHED"} + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + + +class SaveBcfProject(bpy.types.Operator): + bl_idname = "bim.save_bcf_project" + bl_label = "Save BCF Project" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + + def execute(self, context): + import bcfplugin + bcfplugin.saveProject(self.filepath) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {"RUNNING_MODAL"} + class ViewBcfTopic(bpy.types.Operator): bl_idname = "bim.view_bcf_topic" @@ -2030,20 +2050,6 @@ class SelectSmartGroup(bpy.types.Operator): return {"FINISHED"} -class SelectBcfFile(bpy.types.Operator): - bl_idname = "bim.select_bcf_file" - bl_label = "Select BCF File" - filepath: bpy.props.StringProperty(subtype="FILE_PATH") - - def execute(self, context): - bpy.context.scene.BCFProperties.bcf_file = self.filepath - return {"FINISHED"} - - def invoke(self, context, event): - context.window_manager.fileselect_add(self) - return {"RUNNING_MODAL"} - - class SelectFeaturesDir(bpy.types.Operator): bl_idname = "bim.select_features_dir" bl_label = "Select Features Directory" diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 03d6f2850a..7763c7ba0d 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -1057,8 +1057,8 @@ class RefreshBcfTopic: cls.props.topic_related_topics.remove(0) for t in cls.topic.relatedTopics: new = cls.props.topic_related_topics.add() - new.name = bcfplugin.getTopicFromUUID(t.value).title - new.guid = str(t.value) + new.name = bcfplugin.getTopicFromUUID(t.guid).title + new.guid = str(t.guid) @classmethod def load_viewpoints(cls): @@ -1599,7 +1599,6 @@ class BIMProperties(PropertyGroup): class BCFProperties(PropertyGroup): - bcf_file: StringProperty(default="", name="BCF File") topics: CollectionProperty(name="BCF Topics", type=BcfTopic) active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic) viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints") diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 3b3bbd7cfc..c2ed78824a 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1660,13 +1660,12 @@ class BIM_PT_bcf(Panel): scene = context.scene props = bpy.context.scene.BCFProperties - row = layout.row(align=True) - row.prop(props, "bcf_file") - row.operator("bim.select_bcf_file", icon="FILE_FOLDER", text="") - row = layout.row() row.operator("bim.get_bcf_topics") + row = layout.row() + row.operator("bim.save_bcf_project") + props = bpy.context.scene.BCFProperties layout.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") From 9dcf44fbea18c023834951f615c5499eff50ff3d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 13 Dec 2020 16:35:51 +1100 Subject: [PATCH 09/26] You can now view and edit the BCF project name --- src/ifcblenderexport/blenderbim/bim/__init__.py | 2 +- src/ifcblenderexport/blenderbim/bim/operator.py | 7 ++++--- src/ifcblenderexport/blenderbim/bim/prop.py | 6 ++++++ src/ifcblenderexport/blenderbim/bim/ui.py | 14 +++++++++++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 6aa9c7f1b8..6c908b6078 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -25,8 +25,8 @@ if bpy is not None: operator.UnassignClass, operator.SelectClass, operator.SelectType, + operator.LoadBcfProject, operator.SaveBcfProject, - operator.GetBcfTopics, operator.ViewBcfTopic, operator.ActivateBcfViewpoint, operator.OpenBcfFileReference, diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index d59c3f4217..b5476da13b 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -507,15 +507,16 @@ class RejectElement(bpy.types.Operator): return {"FINISHED"} -class GetBcfTopics(bpy.types.Operator): - bl_idname = "bim.get_bcf_topics" - bl_label = "Get BCF Topics" +class LoadBcfProject(bpy.types.Operator): + bl_idname = "bim.load_bcf_project" + bl_label = "Load BCF Project" filepath: bpy.props.StringProperty(subtype="FILE_PATH") def execute(self, context): import bcfplugin bcfplugin.openProject(self.filepath) + bpy.context.scene.BCFProperties.name = bcfplugin.getProjectName() bcf.BcfStore.topics = bcfplugin.getTopics() while len(bpy.context.scene.BCFProperties.topics) > 0: bpy.context.scene.BCFProperties.topics.remove(0) diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 7763c7ba0d..89ce641e59 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -947,6 +947,11 @@ def refreshBcfTopic(self, context): RefreshBcfTopic.refresh(context) +def setBcfProjectName(self, context): + import bcfplugin + bcfplugin.setProjectName(self.name) + + class RefreshBcfTopic: props: None topic: None @@ -1599,6 +1604,7 @@ class BIMProperties(PropertyGroup): class BCFProperties(PropertyGroup): + name: StringProperty(default="", name="Project Name", update=setBcfProjectName) topics: CollectionProperty(name="BCF Topics", type=BcfTopic) active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic) viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints") diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index c2ed78824a..8a898ee347 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1660,11 +1660,19 @@ class BIM_PT_bcf(Panel): scene = context.scene props = bpy.context.scene.BCFProperties - row = layout.row() - row.operator("bim.get_bcf_topics") + row = layout.row(align=True) + row.operator("bim.load_bcf_project") + + if not props.topics: + return + + row.operator("bim.save_bcf_project") row = layout.row() - row.operator("bim.save_bcf_project") + row.prop(props, "name") + + if not props.topics: + return props = bpy.context.scene.BCFProperties layout.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") From 6a06c292a10cacda2cef5ffe46dfad03a38c9e95 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 13 Dec 2020 16:54:11 +1100 Subject: [PATCH 10/26] Fix #1148. Fix crash when creating drawings on Windows with Blender >= 2.91 --- .../blenderbim/bim/cut_ifc.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/cut_ifc.py b/src/ifcblenderexport/blenderbim/bim/cut_ifc.py index 8734f7a286..7c54d2ca4c 100644 --- a/src/ifcblenderexport/blenderbim/bim/cut_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/cut_ifc.py @@ -482,13 +482,20 @@ class IfcCutter: import bpy - multiprocessing.set_executable(bpy.app.binary_path_python) - - with multiprocessing.Pool(9) as p: - results = p.map(do_cut, process_data) - for result in results: - polygons = [p for p in result if p["points"]] + if bpy.app.version > (2, 90, 0) and os.name == 'nt': + # See bug #1148 + for data in process_data: + results = do_cut(data) + polygons = [r for r in results if r["points"]] self.cut_polygons.extend(polygons) + else: + multiprocessing.set_executable(bpy.app.binary_path_python) + + with multiprocessing.Pool(9) as p: + results = p.map(do_cut, process_data) + for result in results: + polygons = [p for p in result if p["points"]] + self.cut_polygons.extend(polygons) def get_polygon_metadata(self, polygon, position): polygon["metadata"] = {"classes": self.get_classes(self.get_ifc_element(polygon["global_id"]), position)} From a62a32d414743a71adb91c114c768de7f1c2ac29 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 13 Dec 2020 21:56:04 +1100 Subject: [PATCH 11/26] Support for setting the BCF author. You can also now edit basic BCF topic metadata. --- .../blenderbim/bim/operator.py | 3 +- src/ifcblenderexport/blenderbim/bim/prop.py | 53 +++++++++++++++---- src/ifcblenderexport/blenderbim/bim/ui.py | 38 +++++++------ 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index b5476da13b..81da0e7dba 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -516,13 +516,14 @@ class LoadBcfProject(bpy.types.Operator): import bcfplugin bcfplugin.openProject(self.filepath) - bpy.context.scene.BCFProperties.name = bcfplugin.getProjectName() bcf.BcfStore.topics = bcfplugin.getTopics() while len(bpy.context.scene.BCFProperties.topics) > 0: bpy.context.scene.BCFProperties.topics.remove(0) for topic in bcf.BcfStore.topics: new = bpy.context.scene.BCFProperties.topics.add() new.name = topic[0] + # Note: set this last, as we use it to check whether or not the project has been loaded + bpy.context.scene.BCFProperties.name = bcfplugin.getProjectName() return {"FINISHED"} def invoke(self, context, event): diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 89ce641e59..ee4659832b 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -910,8 +910,43 @@ class Constraint(PropertyGroup): user_defined_qualifier: StringProperty(name="Custom Qualifier") +def updateBcfProjectName(self, context): + import bcfplugin + bcfplugin.setProjectName(self.name) + + +def updateBcfTopicAttribute(context, name, value): + import bcfplugin + props = bpy.context.scene.BCFProperties + topic = bcf.BcfStore.topics[props.active_topic_index][1] + if getattr(topic, name) != value: + setattr(topic, name, value) + bcfplugin.modifyElement(topic, props.author) + + +def updateBcfTopicName(self, context): + if bpy.context.scene.BCFProperties.name: + updateBcfTopicAttribute(context, "title", self.name) + + +def updateBcfTopicType(self, context): + updateBcfTopicAttribute(context, "type", self.topic_type) + + +def updateBcfTopicStatus(self, context): + updateBcfTopicAttribute(context, "status", self.topic_status) + + +def updateBcfTopicPriority(self, context): + updateBcfTopicAttribute(context, "priority", self.topic_priority) + + +def updateBcfTopicStage(self, context): + updateBcfTopicAttribute(context, "stage", self.topic_stage) + + class BcfTopic(PropertyGroup): - name: StringProperty(name="Name") + name: StringProperty(name="Name", update=updateBcfTopicName) class BcfTopicLabel(PropertyGroup): @@ -947,11 +982,6 @@ def refreshBcfTopic(self, context): RefreshBcfTopic.refresh(context) -def setBcfProjectName(self, context): - import bcfplugin - bcfplugin.setProjectName(self.name) - - class RefreshBcfTopic: props: None topic: None @@ -1604,15 +1634,16 @@ class BIMProperties(PropertyGroup): class BCFProperties(PropertyGroup): - name: StringProperty(default="", name="Project Name", update=setBcfProjectName) + name: StringProperty(default="", name="Project Name", update=updateBcfProjectName) + author: StringProperty(default="john@doe.com", name="Author Email") topics: CollectionProperty(name="BCF Topics", type=BcfTopic) active_topic_index: IntProperty(name="Active BCF Topic Index", update=refreshBcfTopic) viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints") topic_guid: StringProperty(default="", name="Topic GUID") - topic_type: StringProperty(default="", name="Topic Type") - topic_status: StringProperty(default="", name="Topic Status") - topic_priority: StringProperty(default="", name="Topic Priority") - topic_stage: StringProperty(default="", name="Topic Stage") + topic_type: StringProperty(default="", name="Topic Type", update=updateBcfTopicType) + topic_status: StringProperty(default="", name="Topic Status", update=updateBcfTopicStatus) + topic_priority: StringProperty(default="", name="Topic Priority", update=updateBcfTopicPriority) + topic_stage: StringProperty(default="", name="Topic Stage", update=updateBcfTopicStage) topic_creation_date: StringProperty(default="", name="Topic Date") topic_creation_author: StringProperty(default="", name="Topic Author") topic_modified_date: StringProperty(default="", name="Topic Modified Date") diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 8a898ee347..6e0eed1fd4 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1671,6 +1671,9 @@ class BIM_PT_bcf(Panel): row = layout.row() row.prop(props, "name") + row = layout.row() + row.prop(props, "author") + if not props.topics: return @@ -1684,26 +1687,21 @@ class BIM_PT_bcf(Panel): row.prop(props, "viewpoints") row.operator("bim.activate_bcf_viewpoint", icon="SCENE", text="") - row = layout.row() - row.prop(props, "topic_type", text="Type") - row = layout.row() - row.prop(props, "topic_status", text="Status") - row = layout.row() - row.prop(props, "topic_priority", text="Priority") - row = layout.row() - row.prop(props, "topic_stage", text="Stage") - row = layout.row() - row.prop(props, "topic_creation_date", text="Date") - row = layout.row() - row.prop(props, "topic_creation_author", text="Author") - row = layout.row() - row.prop(props, "topic_modified_date", text="Modified On") - row = layout.row() - row.prop(props, "topic_modified_author", text="Modified By") - row = layout.row() - row.prop(props, "topic_assigned_to", text="Assigned To") - row = layout.row() - row.prop(props, "topic_due_date", text="Due Date") + col = layout.column(align=True) + col.prop(props, "topic_type", text="Type") + col.prop(props, "topic_status", text="Status") + col.prop(props, "topic_priority", text="Priority") + col.prop(props, "topic_stage", text="Stage") + col.prop(props, "topic_assigned_to", text="Assigned To") + col.prop(props, "topic_due_date", text="Due Date") + + col = layout.column(align=True) + col.enabled = False + col.prop(props, "topic_creation_date", text="Date") + col.prop(props, "topic_creation_author", text="Author") + col.prop(props, "topic_modified_date", text="Modified On") + col.prop(props, "topic_modified_author", text="Modified By") + layout.label(text="Header Files:") for index, f in enumerate(props.topic_files): From e208dd0381cee46c38dc7854ab5137fcd46d7f7d Mon Sep 17 00:00:00 2001 From: Carlos Dias <57261862+c4rlosdias@users.noreply.github.com> Date: Sun, 13 Dec 2020 22:55:53 -0300 Subject: [PATCH 12/26] Update selector.py Changes fix problem with boolean values --- src/ifcopenshell-python/ifcopenshell/util/selector.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/selector.py b/src/ifcopenshell-python/ifcopenshell/util/selector.py index b42b7fd69f..416a178e8e 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/selector.py +++ b/src/ifcopenshell-python/ifcopenshell/util/selector.py @@ -204,7 +204,7 @@ class Selector: value = filter_rule.children[2].children[0][1:-1] for element in elements: element_value = self.get_element_value(element, key) - if not element_value: + if element_value is None: continue if not comparison or self.filter_element(element, element_value, comparison, value): results.append(element) From 4f2bf3a36f2a260f0ffcf7a4991f19b1e3f6db79 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 14 Dec 2020 13:29:52 +1100 Subject: [PATCH 13/26] You can now add new BCF topics to a BCF project --- .../blenderbim/bim/__init__.py | 1 + .../blenderbim/bim/operator.py | 20 +++++++++++++++++-- src/ifcblenderexport/blenderbim/bim/prop.py | 12 ++++++++--- src/ifcblenderexport/blenderbim/bim/ui.py | 5 ++++- 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 6c908b6078..07e5b318ce 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -27,6 +27,7 @@ if bpy is not None: operator.SelectType, operator.LoadBcfProject, operator.SaveBcfProject, + operator.AddBcfTopic, operator.ViewBcfTopic, operator.ActivateBcfViewpoint, operator.OpenBcfFileReference, diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 81da0e7dba..016c9e1a31 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -517,13 +517,14 @@ class LoadBcfProject(bpy.types.Operator): bcfplugin.openProject(self.filepath) bcf.BcfStore.topics = bcfplugin.getTopics() + bpy.context.scene.BCFProperties.is_editable = False + bpy.context.scene.BCFProperties.name = bcfplugin.getProjectName() while len(bpy.context.scene.BCFProperties.topics) > 0: bpy.context.scene.BCFProperties.topics.remove(0) for topic in bcf.BcfStore.topics: new = bpy.context.scene.BCFProperties.topics.add() new.name = topic[0] - # Note: set this last, as we use it to check whether or not the project has been loaded - bpy.context.scene.BCFProperties.name = bcfplugin.getProjectName() + bpy.context.scene.BCFProperties.is_editable = True return {"FINISHED"} def invoke(self, context, event): @@ -546,6 +547,21 @@ class SaveBcfProject(bpy.types.Operator): return {"RUNNING_MODAL"} +class AddBcfTopic(bpy.types.Operator): + bl_idname = "bim.add_bcf_topic" + bl_label = "Add BCF Topic" + + def execute(self, context): + import bcfplugin + bcfplugin.addTopic("New Topic", bpy.context.scene.BCFProperties.author) + bpy.context.scene.BCFProperties.is_editable = False + new = bpy.context.scene.BCFProperties.topics.add() + new.name = "New Topic" + bcf.BcfStore.topics = bcfplugin.getTopics() + bpy.context.scene.BCFProperties.is_editable = True + return {"FINISHED"} + + class ViewBcfTopic(bpy.types.Operator): bl_idname = "bim.view_bcf_topic" bl_label = "Get BCF Topic" diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index ee4659832b..15500500bb 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -916,6 +916,8 @@ def updateBcfProjectName(self, context): def updateBcfTopicAttribute(context, name, value): + if not bpy.context.scene.BCFProperties.is_editable: + return import bcfplugin props = bpy.context.scene.BCFProperties topic = bcf.BcfStore.topics[props.active_topic_index][1] @@ -925,8 +927,7 @@ def updateBcfTopicAttribute(context, name, value): def updateBcfTopicName(self, context): - if bpy.context.scene.BCFProperties.name: - updateBcfTopicAttribute(context, "title", self.name) + updateBcfTopicAttribute(context, "title", self.name) def updateBcfTopicType(self, context): @@ -945,6 +946,10 @@ def updateBcfTopicStage(self, context): updateBcfTopicAttribute(context, "stage", self.topic_stage) +def updateBcfTopicDescription(self, context): + updateBcfTopicAttribute(context, "description", self.topic_description) + + class BcfTopic(PropertyGroup): name: StringProperty(name="Name", update=updateBcfTopicName) @@ -1634,6 +1639,7 @@ class BIMProperties(PropertyGroup): class BCFProperties(PropertyGroup): + is_editable: BoolProperty(name="Is Editable", default=False) name: StringProperty(default="", name="Project Name", update=updateBcfProjectName) author: StringProperty(default="john@doe.com", name="Author Email") topics: CollectionProperty(name="BCF Topics", type=BcfTopic) @@ -1650,7 +1656,7 @@ class BCFProperties(PropertyGroup): topic_modified_author: StringProperty(default="", name="Topic Modified By") topic_assigned_to: StringProperty(default="", name="Topic Assigned To") topic_due_date: StringProperty(default="", name="Topic Due Date") - topic_description: StringProperty(default="", name="Topic Description") + topic_description: StringProperty(default="", name="Topic Description", update=updateBcfTopicDescription) topic_labels: CollectionProperty(name="BCF Topic Labels", type=BcfTopicLabel) topic_files: CollectionProperty(name="BCF Topic Files", type=BcfTopicFile) topic_links: CollectionProperty(name="BCF Topic Links", type=BcfTopicLink) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 6e0eed1fd4..67ede77508 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1678,7 +1678,10 @@ class BIM_PT_bcf(Panel): return props = bpy.context.scene.BCFProperties - layout.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") + row = layout.row() + row.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") + col = row.column(align=True) + col.operator("bim.add_bcf_topic", icon="ADD", text="") row = layout.row() row.prop(props, "topic_description", text="") From 17a8b3338749529cc5aad867b9962568b62e900c Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Mon, 14 Dec 2020 13:51:01 +1100 Subject: [PATCH 14/26] You can new create new BCF projects from scratch --- .../blenderbim/bim/__init__.py | 1 + .../blenderbim/bim/operator.py | 19 +++++++++++++++++++ src/ifcblenderexport/blenderbim/bim/prop.py | 1 + src/ifcblenderexport/blenderbim/bim/ui.py | 13 +++++++------ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 07e5b318ce..10327fbd87 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -25,6 +25,7 @@ if bpy is not None: operator.UnassignClass, operator.SelectClass, operator.SelectType, + operator.NewBcfProject, operator.LoadBcfProject, operator.SaveBcfProject, operator.AddBcfTopic, diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 016c9e1a31..0d67291e18 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -507,6 +507,24 @@ class RejectElement(bpy.types.Operator): return {"FINISHED"} +class NewBcfProject(bpy.types.Operator): + bl_idname = "bim.new_bcf_project" + bl_label = "New BCF Project" + + def execute(self, context): + import bcfplugin + bcfplugin.newProject("New BCF Project") + bcf.BcfStore.topics = bcfplugin.getTopics() + bpy.context.scene.BCFProperties.is_editable = False + bpy.context.scene.BCFProperties.name = bcfplugin.getProjectName() + while len(bpy.context.scene.BCFProperties.topics) > 0: + bpy.context.scene.BCFProperties.topics.remove(0) + bpy.context.scene.BCFProperties.is_editable = True + bpy.context.scene.BCFProperties.directory = bcfplugin.util.getBcfDir() + bpy.context.scene.BCFProperties.is_loaded = True + return {"FINISHED"} + + class LoadBcfProject(bpy.types.Operator): bl_idname = "bim.load_bcf_project" bl_label = "Load BCF Project" @@ -525,6 +543,7 @@ class LoadBcfProject(bpy.types.Operator): new = bpy.context.scene.BCFProperties.topics.add() new.name = topic[0] bpy.context.scene.BCFProperties.is_editable = True + bpy.context.scene.BCFProperties.is_loaded = True return {"FINISHED"} def invoke(self, context, event): diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 15500500bb..5b032daec9 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -1640,6 +1640,7 @@ class BIMProperties(PropertyGroup): class BCFProperties(PropertyGroup): is_editable: BoolProperty(name="Is Editable", default=False) + is_loaded: BoolProperty(name="Is Loaded", default=False) name: StringProperty(default="", name="Project Name", update=updateBcfProjectName) author: StringProperty(default="john@doe.com", name="Author Email") topics: CollectionProperty(name="BCF Topics", type=BcfTopic) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 67ede77508..c8fe83e02c 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1661,12 +1661,13 @@ class BIM_PT_bcf(Panel): props = bpy.context.scene.BCFProperties row = layout.row(align=True) - row.operator("bim.load_bcf_project") + row.operator("bim.new_bcf_project", text="New Project") + row.operator("bim.load_bcf_project", text="Load Project") - if not props.topics: + if not props.is_loaded: return - row.operator("bim.save_bcf_project") + row.operator("bim.save_bcf_project", text="Save Project") row = layout.row() row.prop(props, "name") @@ -1674,15 +1675,15 @@ class BIM_PT_bcf(Panel): row = layout.row() row.prop(props, "author") - if not props.topics: - return - props = bpy.context.scene.BCFProperties row = layout.row() row.template_list("BIM_UL_topics", "", props, "topics", props, "active_topic_index") col = row.column(align=True) col.operator("bim.add_bcf_topic", icon="ADD", text="") + if not props.topics: + return + row = layout.row() row.prop(props, "topic_description", text="") From d00da09cdca9c35033a74ac47447354bf9207896 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 15 Dec 2020 00:04:26 +0100 Subject: [PATCH 15/26] start translation into German and French with one step as well as the report --- .../bimtester/features/steps/ifcdata_de.py | 10 +++++ .../bimtester/features/steps/ifcdata_fr.py | 10 +++++ .../features/strings_template_de.json | 9 ++++ .../features/strings_template_en.json | 9 ++++ .../features/strings_template_fr.json | 9 ++++ .../bimtester/features/template.html | 16 +++---- src/ifcbimtester/bimtester/reports.py | 45 ++++++++++++++++--- 7 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 src/ifcbimtester/bimtester/features/steps/ifcdata_de.py create mode 100644 src/ifcbimtester/bimtester/features/steps/ifcdata_fr.py create mode 100644 src/ifcbimtester/bimtester/features/strings_template_de.json create mode 100644 src/ifcbimtester/bimtester/features/strings_template_en.json create mode 100644 src/ifcbimtester/bimtester/features/strings_template_fr.json diff --git a/src/ifcbimtester/bimtester/features/steps/ifcdata_de.py b/src/ifcbimtester/bimtester/features/steps/ifcdata_de.py new file mode 100644 index 0000000000..69e284a73f --- /dev/null +++ b/src/ifcbimtester/bimtester/features/steps/ifcdata_de.py @@ -0,0 +1,10 @@ +from behave import step + +# https://behave.readthedocs.io/en/latest/api.html#step-macro-calling-steps-from-other-steps + + +@step("Die IFC daten müssen das {schema} Schema benutzen") +def step_impl(context, schema): + context.execute_steps( + "* IFC data must use the {schema} schema".format(schema=schema) + ) diff --git a/src/ifcbimtester/bimtester/features/steps/ifcdata_fr.py b/src/ifcbimtester/bimtester/features/steps/ifcdata_fr.py new file mode 100644 index 0000000000..c7947f9719 --- /dev/null +++ b/src/ifcbimtester/bimtester/features/steps/ifcdata_fr.py @@ -0,0 +1,10 @@ +from behave import step + +# https://behave.readthedocs.io/en/latest/api.html#step-macro-calling-steps-from-other-steps + + +@step("Les données IFC doivent utiliser le schéma {schema}") +def step_impl(context, schema): + context.execute_steps( + "* IFC data must use the {aschema} schema".format(aschema=schema) + ) diff --git a/src/ifcbimtester/bimtester/features/strings_template_de.json b/src/ifcbimtester/bimtester/features/strings_template_de.json new file mode 100644 index 0000000000..cf6e29d294 --- /dev/null +++ b/src/ifcbimtester/bimtester/features/strings_template_de.json @@ -0,0 +1,9 @@ +{ + "tr_lang": "de", + "tr_success": "Bestanden", + "tr_failure": "Durchgefallen", + "tr_tests_passed": "Erfolgreiche Tests", + "tr_duration": "Dauer", + "tr_auditing": "OpenBIM auditing ist eine Funktionalität von", + "tr_and": "und" +} diff --git a/src/ifcbimtester/bimtester/features/strings_template_en.json b/src/ifcbimtester/bimtester/features/strings_template_en.json new file mode 100644 index 0000000000..745eb70a68 --- /dev/null +++ b/src/ifcbimtester/bimtester/features/strings_template_en.json @@ -0,0 +1,9 @@ +{ + "tr_lang": "en", + "tr_success": "Success", + "tr_failure": "Failure", + "tr_tests_passed": "Tests passed", + "tr_duration": "Duration", + "tr_auditing": "OpenBIM auditing is a feature of", + "tr_and": "and" +} diff --git a/src/ifcbimtester/bimtester/features/strings_template_fr.json b/src/ifcbimtester/bimtester/features/strings_template_fr.json new file mode 100644 index 0000000000..fa0a984bbb --- /dev/null +++ b/src/ifcbimtester/bimtester/features/strings_template_fr.json @@ -0,0 +1,9 @@ +{ + "tr_lang": "fr", + "tr_success": "Succès", + "tr_failure": "Échec", + "tr_tests_passed": "Tests réussis", + "tr_duration": "Durée", + "tr_auditing": "L'audit OpenBIM auditing est une fonctionnalité de", + "tr_and": "et" +} diff --git a/src/ifcbimtester/bimtester/features/template.html b/src/ifcbimtester/bimtester/features/template.html index 66a2ebb0ba..38b80077a1 100644 --- a/src/ifcbimtester/bimtester/features/template.html +++ b/src/ifcbimtester/bimtester/features/template.html @@ -1,10 +1,10 @@ - + - BlenderBIM + {{name}}