From 13c642c6ab0f1ed5076cc7cc6d895ae9c2f8f4a9 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 14 May 2021 17:48:53 +1000 Subject: [PATCH] A little progress on refactoring the old drawing module into an IfcConvert based system. See #1153. --- src/blenderbim/blenderbim/bim/__init__.py | 1 - src/blenderbim/blenderbim/bim/helper.py | 139 ---------------- .../blenderbim/bim/module/drawing/__init__.py | 1 + .../bim/{ => module/drawing}/annotation.py | 0 .../blenderbim/bim/module/drawing/helper.py | 141 +++++++++++++++++ .../blenderbim/bim/module/drawing/operator.py | 148 ++++++++++++++++-- .../bim/{ => module/drawing}/svgwriter.py | 91 ++++++----- src/blenderbim/blenderbim/bim/operator.py | 29 ---- src/blenderbim/blenderbim/bim/prop.py | 2 +- 9 files changed, 328 insertions(+), 224 deletions(-) rename src/blenderbim/blenderbim/bim/{ => module/drawing}/annotation.py (100%) create mode 100644 src/blenderbim/blenderbim/bim/module/drawing/helper.py rename src/blenderbim/blenderbim/bim/{ => module/drawing}/svgwriter.py (89%) diff --git a/src/blenderbim/blenderbim/bim/__init__.py b/src/blenderbim/blenderbim/bim/__init__.py index 65618371a3..eff052bcc9 100644 --- a/src/blenderbim/blenderbim/bim/__init__.py +++ b/src/blenderbim/blenderbim/bim/__init__.py @@ -86,7 +86,6 @@ if bpy is not None: operator.AddIfcFile, operator.RemoveIfcFile, operator.SelectDocIfcFile, - operator.AddAnnotation, operator.GenerateReferences, operator.ResizeText, operator.AddVariable, diff --git a/src/blenderbim/blenderbim/bim/helper.py b/src/blenderbim/blenderbim/bim/helper.py index 46eaf2040b..b8337d1c57 100644 --- a/src/blenderbim/blenderbim/bim/helper.py +++ b/src/blenderbim/blenderbim/bim/helper.py @@ -78,145 +78,6 @@ def export_attributes(props, callback=None): # TODO: migrate the below helper functions into the drawing module, since it is specific to that module -# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py -# MeasureIt-ARCH is GPL-v3 -# In the future I will need to rewrite this to allow the user to have custom -# settings for each annotation object, not read from Blender. -def format_distance(value, isArea=False, hide_units=True): - s_code = "\u00b2" # Superscript two THIS IS LEGACY (but being kept for when Area Measurements are re-implimented) - - # Get Scene Unit Settings - scaleFactor = bpy.context.scene.unit_settings.scale_length - unit_system = bpy.context.scene.unit_settings.system - unit_length = bpy.context.scene.unit_settings.length_unit - - toInches = 39.3700787401574887 - inPerFoot = 11.999 - - if isArea: - toInches = 1550 - inPerFoot = 143.999 - - value *= scaleFactor - - # Imperial Formating - if unit_system == "IMPERIAL": - precision = bpy.context.scene.BIMProperties.imperial_precision - if precision == "NONE": - precision = 256 - elif precision == "1": - precision = 1 - elif "/" in precision: - precision = int(precision.split("/")[1]) - - base = int(precision) - decInches = value * toInches - - # Seperate ft and inches - # Unless Inches are the specified Length Unit - if unit_length != "INCHES": - feet = math.floor(decInches / inPerFoot) - decInches -= feet * inPerFoot - else: - feet = 0 - - # Seperate Fractional Inches - inches = math.floor(decInches) - if inches != 0: - frac = round(base * (decInches - inches)) - else: - frac = round(base * (decInches)) - - # Set proper numerator and denominator - if frac != base: - numcycles = int(math.log2(base)) - for i in range(numcycles): - if frac % 2 == 0: - frac = int(frac / 2) - base = int(base / 2) - else: - break - else: - frac = 0 - inches += 1 - - # Check values and compose string - if inches == 12: - feet += 1 - inches = 0 - - if not isArea: - tx_dist = "" - if feet: - tx_dist += str(feet) + "'" - if feet and inches: - tx_dist += " - " - if inches: - tx_dist += str(inches) - if inches and frac: - tx_dist += " " - if frac: - tx_dist += str(frac) + "/" + str(base) - if inches or frac: - tx_dist += '"' - else: - tx_dist = str("%1.3f" % (value * toInches / inPerFoot)) + " sq. ft." - - # METRIC FORMATING - elif unit_system == "METRIC": - precision = bpy.context.scene.BIMProperties.metric_precision - if precision != 0: - value = precision * round(float(value) / precision) - - # Meters - if unit_length == "METERS": - fmt = "%1.3f" - if hide_units is False: - fmt += " m" - tx_dist = fmt % value - # Centimeters - elif unit_length == "CENTIMETERS": - fmt = "%1.1f" - if hide_units is False: - fmt += " cm" - d_cm = value * (100) - tx_dist = fmt % d_cm - # Millimeters - elif unit_length == "MILLIMETERS": - fmt = "%1.0f" - if hide_units is False: - fmt += " mm" - d_mm = value * (1000) - tx_dist = fmt % d_mm - - # Otherwise Use Adaptive Units - else: - if round(value, 2) >= 1.0: - fmt = "%1.3f" - if hide_units is False: - fmt += " m" - tx_dist = fmt % value - else: - if round(value, 2) >= 0.01: - fmt = "%1.1f" - if hide_units is False: - fmt += " cm" - d_cm = value * (100) - tx_dist = fmt % d_cm - else: - fmt = "%1.0f" - if hide_units is False: - fmt += " mm" - d_mm = value * (1000) - tx_dist = fmt % d_mm - if isArea: - tx_dist += s_code - else: - tx_dist = fmt % value - - return tx_dist - - def parse_diagram_scale(camera): """Returns numeric value of scale""" if camera.BIMCameraProperties.diagram_scale == "CUSTOM": diff --git a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py index 5fd4cf69cc..0a161e652e 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/__init__.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/__init__.py @@ -4,6 +4,7 @@ from . import ui, operator classes = ( operator.AddDrawing, operator.CreateDrawing, + operator.AddAnnotation, ui.BIM_PT_camera, ) diff --git a/src/blenderbim/blenderbim/bim/annotation.py b/src/blenderbim/blenderbim/bim/module/drawing/annotation.py similarity index 100% rename from src/blenderbim/blenderbim/bim/annotation.py rename to src/blenderbim/blenderbim/bim/module/drawing/annotation.py diff --git a/src/blenderbim/blenderbim/bim/module/drawing/helper.py b/src/blenderbim/blenderbim/bim/module/drawing/helper.py new file mode 100644 index 0000000000..c45ea17820 --- /dev/null +++ b/src/blenderbim/blenderbim/bim/module/drawing/helper.py @@ -0,0 +1,141 @@ +import bpy +import math + + +# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py +# MeasureIt-ARCH is GPL-v3 +# In the future I will need to rewrite this to allow the user to have custom +# settings for each annotation object, not read from Blender. +def format_distance(value, isArea=False, hide_units=True): + s_code = "\u00b2" # Superscript two THIS IS LEGACY (but being kept for when Area Measurements are re-implimented) + + # Get Scene Unit Settings + scaleFactor = bpy.context.scene.unit_settings.scale_length + unit_system = bpy.context.scene.unit_settings.system + unit_length = bpy.context.scene.unit_settings.length_unit + + toInches = 39.3700787401574887 + inPerFoot = 11.999 + + if isArea: + toInches = 1550 + inPerFoot = 143.999 + + value *= scaleFactor + + # Imperial Formating + if unit_system == "IMPERIAL": + precision = bpy.context.scene.BIMProperties.imperial_precision + if precision == "NONE": + precision = 256 + elif precision == "1": + precision = 1 + elif "/" in precision: + precision = int(precision.split("/")[1]) + + base = int(precision) + decInches = value * toInches + + # Seperate ft and inches + # Unless Inches are the specified Length Unit + if unit_length != "INCHES": + feet = math.floor(decInches / inPerFoot) + decInches -= feet * inPerFoot + else: + feet = 0 + + # Seperate Fractional Inches + inches = math.floor(decInches) + if inches != 0: + frac = round(base * (decInches - inches)) + else: + frac = round(base * (decInches)) + + # Set proper numerator and denominator + if frac != base: + numcycles = int(math.log2(base)) + for i in range(numcycles): + if frac % 2 == 0: + frac = int(frac / 2) + base = int(base / 2) + else: + break + else: + frac = 0 + inches += 1 + + # Check values and compose string + if inches == 12: + feet += 1 + inches = 0 + + if not isArea: + tx_dist = "" + if feet: + tx_dist += str(feet) + "'" + if feet and inches: + tx_dist += " - " + if inches: + tx_dist += str(inches) + if inches and frac: + tx_dist += " " + if frac: + tx_dist += str(frac) + "/" + str(base) + if inches or frac: + tx_dist += '"' + else: + tx_dist = str("%1.3f" % (value * toInches / inPerFoot)) + " sq. ft." + + # METRIC FORMATING + elif unit_system == "METRIC": + precision = bpy.context.scene.BIMProperties.metric_precision + if precision != 0: + value = precision * round(float(value) / precision) + + # Meters + if unit_length == "METERS": + fmt = "%1.3f" + if hide_units is False: + fmt += " m" + tx_dist = fmt % value + # Centimeters + elif unit_length == "CENTIMETERS": + fmt = "%1.1f" + if hide_units is False: + fmt += " cm" + d_cm = value * (100) + tx_dist = fmt % d_cm + # Millimeters + elif unit_length == "MILLIMETERS": + fmt = "%1.0f" + if hide_units is False: + fmt += " mm" + d_mm = value * (1000) + tx_dist = fmt % d_mm + + # Otherwise Use Adaptive Units + else: + if round(value, 2) >= 1.0: + fmt = "%1.3f" + if hide_units is False: + fmt += " m" + tx_dist = fmt % value + else: + if round(value, 2) >= 0.01: + fmt = "%1.1f" + if hide_units is False: + fmt += " cm" + d_cm = value * (100) + tx_dist = fmt % d_cm + else: + fmt = "%1.0f" + if hide_units is False: + fmt += " mm" + d_mm = value * (1000) + tx_dist = fmt % d_mm + if isArea: + tx_dist += s_code + else: + tx_dist = fmt % value + + return tx_dist diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 909f654996..4475d41851 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -3,6 +3,9 @@ import bpy import json import subprocess import webbrowser +import blenderbim.bim.module.drawing.svgwriter as svgwriter +import blenderbim.bim.module.drawing.annotation as annotation +from mathutils import Vector, Matrix, Euler, geometry from blenderbim.bim.operator import open_with_user_command from blenderbim.bim.ifc import IfcStore from ifcopenshell.api.group.data import Data as GroupData @@ -57,33 +60,156 @@ class CreateDrawing(bpy.types.Operator): bl_label = "Create Drawing" def execute(self, context): + base_svg = self.ifc_to_svg(context) + annotation_svg = self.annotation_to_svg(context) + svg_path = self.combine_svgs(context, base_svg, annotation_svg) + open_with_user_command(bpy.context.preferences.addons["blenderbim"].preferences.svg_command, svg_path) + return {"FINISHED"} + + def combine_svgs(self, context, base, annotation): + # Hacky :) + svg_path = context.scene.BIMProperties.ifc_file[0:-4] + ".svg" + with open(svg_path, 'w') as outfile: + with open(base) as infile: + for line in infile: + if "" in line: + continue + outfile.write(line) + with open(annotation) as infile: + for i, line in enumerate(infile): + if i == 0 or i == 1: + continue + outfile.write(line) + return svg_path + + def ifc_to_svg(self, context): + svg_path = context.scene.BIMProperties.ifc_file[0:-4] + "-base.svg" ifcconvert_path = os.path.join(cwd, "..", "..", "..", "libs", "IfcConvert") subprocess.run( [ ifcconvert_path, context.scene.BIMProperties.ifc_file, "-yv", - context.scene.BIMProperties.ifc_file[0:-4] + ".svg", + svg_path, "--plan", "--model", - "--section-height-from-storeys", - "--section-height=1.2", - "--door-arcs", - "--print-space-names", - "--print-space-areas", - "--bounds=1024x1024", "--elevation-ref=DRAWING", "--svg-xmlns", "--svg-project", "--svg-poly", + "--svg-without-storeys", "--exclude", "entities", "IfcSpace", "IfcOpeningElement", ] ) - open_with_user_command( - bpy.context.preferences.addons["blenderbim"].preferences.svg_command, - context.scene.BIMProperties.ifc_file[0:-4] + ".svg", - ) + return svg_path + + def annotation_to_svg(self, context): + camera = context.scene.camera + + if not (camera.type == "CAMERA" and camera.data.type == "ORTHO"): + return + + svg_writer = svgwriter.SvgWriter() + + if camera.data.BIMCameraProperties.diagram_scale == "CUSTOM": + human_scale, fraction = camera.data.BIMCameraProperties.custom_diagram_scale.split("|") + else: + human_scale, fraction = camera.data.BIMCameraProperties.diagram_scale.split("|") + + numerator, denominator = fraction.split("/") + + if camera.data.BIMCameraProperties.is_nts: + svg_writer.human_scale = "NTS" + else: + svg_writer.human_scale = human_scale + + drawing_style = bpy.context.scene.DocProperties.drawing_styles[ + camera.data.BIMCameraProperties.active_drawing_style_index + ] + + render = bpy.context.scene.render + if self.is_landscape(): + width = camera.data.ortho_scale + height = width / render.resolution_x * render.resolution_y + else: + height = camera.data.ortho_scale + width = height / render.resolution_y * render.resolution_x + + svg_writer.scale = float(numerator) / float(denominator) + svg_writer.output = context.scene.BIMProperties.ifc_file[0:-4] + "-annotation.svg" + svg_writer.data_dir = bpy.context.scene.BIMProperties.data_dir + svg_writer.vector_style = drawing_style.vector_style + svg_writer.camera = camera + svg_writer.camera_width = width + svg_writer.camera_height = height + svg_writer.camera_projection = tuple(camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))) + + for obj in camera.users_collection[0].objects: + if "IfcGrid" in obj.name: + svg_writer.annotations.setdefault("grid_objs", []).append(obj) + elif obj.type == "CAMERA": + continue + + if "IfcAnnotation/" not in obj.name: + continue + + if "Leader" in obj.name: + svg_writer.annotations["leader_obj"] = (obj, obj.data) + elif "Stair" in obj.name: + svg_writer.annotations["stair_obj"] = obj + elif "Equal" in obj.name: + svg_writer.annotations.setdefault("equal_objs", []).append(obj) + elif "Dimension" in obj.name: + svg_writer.annotations.setdefault("dimension_objs", []).append(obj) + elif "Break" in obj.name: + svg_writer.annotations["break_obj"] = obj + elif "Hidden" in obj.name: + svg_writer.annotations.setdefault("hidden_objs", []).append((obj, obj.data)) + elif "Solid" in obj.name: + svg_writer.annotations.setdefault("solid_objs", []).append((obj, obj.data)) + elif "Plan Level" in obj.name: + svg_writer.annotations["plan_level_obj"] = obj + elif "Section Level" in obj.name: + svg_writer.annotations["section_level_obj"] = obj + elif obj.type == "FONT": + svg_writer.annotations.setdefault("text_objs", []).append(obj) + else: + svg_writer.annotations.setdefault("misc_objs", []).append(obj) + + svg_writer.annotations["attributes"] = [a.name for a in drawing_style.attributes] + + svg_writer.write() + return svg_writer.output + + def is_landscape(self): + return bpy.context.scene.render.resolution_x > bpy.context.scene.render.resolution_y + + +class AddAnnotation(bpy.types.Operator): + bl_idname = "bim.add_annotation" + bl_label = "Add Annotation" + obj_name: bpy.props.StringProperty() + data_type: bpy.props.StringProperty() + + def execute(self, context): + if not bpy.context.scene.camera: + return {"FINISHED"} + if self.data_type == "text": + if bpy.context.selected_objects: + for selected_object in bpy.context.selected_objects: + obj = annotation.Annotator.add_text(related_element=selected_object) + else: + obj = annotation.Annotator.add_text() + else: + obj = annotation.Annotator.get_annotation_obj(self.obj_name, self.data_type) + if self.obj_name == "Break": + obj = annotation.Annotator.add_plane_to_annotation(obj) + else: + obj = annotation.Annotator.add_line_to_annotation(obj) + bpy.ops.object.select_all(action="DESELECT") + bpy.context.view_layer.objects.active = obj + bpy.ops.object.mode_set(mode="EDIT") return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/svgwriter.py b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py similarity index 89% rename from src/blenderbim/blenderbim/bim/svgwriter.py rename to src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py index 8275c6439f..752f4dd3fb 100644 --- a/src/blenderbim/blenderbim/bim/svgwriter.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/svgwriter.py @@ -6,8 +6,8 @@ import pystache import xml.etree.ElementTree as ET import svgwrite import ifcopenshell -from . import annotation -from . import helper +import blenderbim.bim.module.drawing.helper as helper +import blenderbim.bim.module.drawing.annotation as annotation from mathutils import Vector from mathutils import geometry from blenderbim.bim.ifc import IfcStore @@ -39,14 +39,16 @@ class External(svgwrite.container.Group): class SvgWriter: - def __init__(self, ifc_cutter): - self.ifc_cutter = ifc_cutter + def __init__(self): + self.output = "out.svg" + self.data_dir = None + self.vector_style = None self.human_scale = "NTS" + self.annotations = {} self.scale = 1 / 100 # 1:100 def write(self): self.calculate_scale() - self.output = os.path.join(self.ifc_cutter.data_dir, "diagrams", self.ifc_cutter.diagram_name + ".svg") self.svg = svgwrite.Drawing( self.output, debug=False, @@ -60,42 +62,43 @@ class SvgWriter: self.add_markers() self.add_symbols() self.add_patterns() - self.draw_background_image() - self.draw_background_elements() - self.draw_cut_polygons() + # self.draw_background_image() + # self.draw_background_elements() + # self.draw_cut_polygons() self.draw_annotations() self.svg.save(pretty=True) def calculate_scale(self): self.scale *= 1000 # IFC is in meters, SVG is in mm - self.raw_width = self.ifc_cutter.section_box["x"] - self.raw_height = self.ifc_cutter.section_box["y"] + self.raw_width = self.camera_width + self.raw_height = self.camera_height self.width = self.raw_width * self.scale self.height = self.raw_height * self.scale def add_stylesheet(self): - with open("{}styles/{}.css".format(self.ifc_cutter.data_dir, self.ifc_cutter.vector_style), "r") as stylesheet: + with open("{}styles/{}.css".format(self.data_dir, self.vector_style), "r") as stylesheet: self.svg.defs.add(self.svg.style(stylesheet.read())) def add_markers(self): - tree = ET.parse("{}templates/markers.svg".format(self.ifc_cutter.data_dir)) + tree = ET.parse("{}templates/markers.svg".format(self.data_dir)) root = tree.getroot() for child in root.getchildren(): self.svg.defs.add(External(child)) def add_symbols(self): - tree = ET.parse("{}templates/symbols.svg".format(self.ifc_cutter.data_dir)) + tree = ET.parse("{}templates/symbols.svg".format(self.data_dir)) root = tree.getroot() for child in root.getchildren(): self.svg.defs.add(External(child)) def add_patterns(self): - tree = ET.parse("{}templates/patterns.svg".format(self.ifc_cutter.data_dir)) + tree = ET.parse("{}templates/patterns.svg".format(self.data_dir)) root = tree.getroot() for child in root.getchildren(): self.svg.defs.add(External(child)) def draw_background_image(self): + return # TODO reimplement for artistic drawing options self.svg.add( self.svg.image( os.path.join("..", "diagrams", os.path.basename(self.ifc_cutter.background_image)), @@ -104,6 +107,7 @@ class SvgWriter: ) def draw_background_elements(self): + return # TODO purge? for element in self.ifc_cutter.background_elements: if element["type"] == "polygon": self.draw_polygon(element, "background") @@ -116,16 +120,16 @@ class SvgWriter: x_offset = self.raw_width / 2 y_offset = self.raw_height / 2 - for obj in self.ifc_cutter.equal_objs: + for obj in self.annotations.get("equal_objs", []): self.draw_dimension_annotations(obj, text_override="EQ") - for obj in self.ifc_cutter.dimension_objs: + for obj in self.annotations.get("dimension_objs", []): self.draw_dimension_annotations(obj) self.draw_measureit_arch_dimension_annotations() - if self.ifc_cutter.break_obj: - self.draw_break_annotations(self.ifc_cutter.break_obj) + if self.annotations.get("break_obj"): + self.draw_break_annotations(self.annotations["break_obj"]) - for grid_obj in self.ifc_cutter.grid_objs: + for grid_obj in self.annotations.get("grid_objs", []): matrix_world = grid_obj.matrix_world for edge in grid_obj.data.edges: classes = ["annotation", "grid"] @@ -174,21 +178,21 @@ class SvgWriter: self.draw_ifc_annotation() - for obj in self.ifc_cutter.misc_objs: + for obj in self.annotations.get("misc_objs", []): self.draw_misc_annotation(obj, ["IfcAnnotation"]) - for obj_data in self.ifc_cutter.hidden_objs: + for obj_data in self.annotations.get("hidden_objs", []): self.draw_line_annotation(obj_data, ["hidden"]) - for obj_data in self.ifc_cutter.solid_objs: + for obj_data in self.annotations.get("solid_objs", []): self.draw_line_annotation(obj_data, ["solid"]) - if self.ifc_cutter.leader_obj: - self.draw_line_annotation(self.ifc_cutter.leader_obj, ["leader"]) + if self.annotations.get("leader_obj"): + self.draw_line_annotation(self.annotations["leader_obj"], ["leader"]) - if self.ifc_cutter.plan_level_obj: - matrix_world = self.ifc_cutter.plan_level_obj.matrix_world - for spline in self.ifc_cutter.plan_level_obj.data.splines: + if self.annotations.get("plan_level_obj"): + matrix_world = self.annotations["plan_level_obj"].matrix_world + for spline in self.annotations["plan_level_obj"].data.splines: classes = ["annotation", "plan-level"] points = self.get_spline_points(spline) projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] @@ -208,7 +212,7 @@ class SvgWriter: ) ) # TODO: allow metric to be configurable - rl = ((matrix_world @ points[0].co).xyz + self.ifc_cutter.plan_level_obj.location).z + rl = ((matrix_world @ points[0].co).xyz + self.annotations["plan_level_obj"].location).z if bpy.context.scene.unit_settings.system == "IMPERIAL": rl = helper.format_distance(rl) else: @@ -231,9 +235,9 @@ class SvgWriter: ) ) - if self.ifc_cutter.section_level_obj: - matrix_world = self.ifc_cutter.section_level_obj.matrix_world - for spline in self.ifc_cutter.section_level_obj.data.splines: + if self.annotations.get("section_level_obj"): + matrix_world = self.annotations["section_level_obj"].matrix_world + for spline in self.annotations["section_level_obj"].data.splines: classes = ["annotation", "section-level"] points = self.get_spline_points(spline) projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] @@ -273,9 +277,9 @@ class SvgWriter: ) ) - if self.ifc_cutter.stair_obj: - matrix_world = self.ifc_cutter.stair_obj.matrix_world - for spline in self.ifc_cutter.stair_obj.data.splines: + if self.annotations.get("stair_obj"): + matrix_world = self.annotations["stair_obj"].matrix_world + for spline in self.annotations["stair_obj"].data.splines: classes = ["annotation", "stair"] points = self.get_spline_points(spline) projected_points = [self.project_point_onto_camera(matrix_world @ p.co.xyz) for p in points] @@ -308,7 +312,7 @@ class SvgWriter: def draw_ifc_annotation(self): x_offset = self.raw_width / 2 y_offset = self.raw_height / 2 - for annotation in self.ifc_cutter.annotation_objs: + for annotation in self.annotations.get("annotation_objs", []): for edge in annotation["edges"]: v0_global = annotation["vertices"][edge[0]] v1_global = annotation["vertices"][edge[1]] @@ -357,7 +361,7 @@ class SvgWriter: classes.append("material-{}".format(re.sub("[^0-9a-zA-Z]+", "", slot.material.name))) global_id = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId classes.append("globalid-{}".format(global_id)) - for attribute in self.ifc_cutter.attributes: + for attribute in self.annotations.get("attributes", []): result = self.get_obj_value(obj, attribute) if result: classes.append( @@ -435,7 +439,7 @@ class SvgWriter: x_offset = self.raw_width / 2 y_offset = self.raw_height / 2 - for text_obj in self.ifc_cutter.text_objs: + for text_obj in self.annotations.get("text_objs", []): text_position = self.project_point_onto_camera(text_obj.location) text_position = Vector(((x_offset + text_position.x), (y_offset - text_position.y))) @@ -473,8 +477,8 @@ class SvgWriter: alignment_baseline = "baseline" text_body = text_obj.data.body - if text_obj.name in self.ifc_cutter.template_variables: - text_body = pystache.render(text_body, self.ifc_cutter.template_variables[text_obj.name]) + if text_obj.name in self.annotations.get("template_variables", {}): + text_body = pystache.render(text_body, self.annotations["template_variables"][text_obj.name]) for line_number, text_line in enumerate(text_body.split("\n")): self.svg.add( @@ -587,17 +591,18 @@ class SvgWriter: ) def project_point_onto_camera(self, point): - return self.ifc_cutter.camera_obj.matrix_world.inverted() @ geometry.intersect_line_plane( + return self.camera.matrix_world.inverted() @ geometry.intersect_line_plane( point.xyz, - point.xyz - Vector(self.ifc_cutter.section_box["projection"]), - self.ifc_cutter.camera_obj.location, - Vector(self.ifc_cutter.section_box["projection"]), + point.xyz - Vector(self.camera_projection), + self.camera.location, + Vector(self.camera_projection), ) def get_spline_points(self, spline): return spline.bezier_points if spline.bezier_points else spline.points def draw_cut_polygons(self): + return # deprecate? for polygon in self.ifc_cutter.cut_polygons: self.draw_polygon(polygon, "cut") diff --git a/src/blenderbim/blenderbim/bim/operator.py b/src/blenderbim/blenderbim/bim/operator.py index 6514d2bc54..dbdea5c904 100644 --- a/src/blenderbim/blenderbim/bim/operator.py +++ b/src/blenderbim/blenderbim/bim/operator.py @@ -16,12 +16,10 @@ import numpy as np from . import export_ifc from . import import_ifc from . import cut_ifc -from . import svgwriter from . import sheeter from . import scheduler from . import schema from . import ifc -from . import annotation from . import helper from bpy_extras.io_utils import ImportHelper from mathutils import Vector, Matrix, Euler, geometry @@ -1102,33 +1100,6 @@ class SelectDocIfcFile(bpy.types.Operator): return {"RUNNING_MODAL"} -class AddAnnotation(bpy.types.Operator): - bl_idname = "bim.add_annotation" - bl_label = "Add Annotation" - obj_name: bpy.props.StringProperty() - data_type: bpy.props.StringProperty() - - def execute(self, context): - if not bpy.context.scene.camera: - return {"FINISHED"} - if self.data_type == "text": - if bpy.context.selected_objects: - for selected_object in bpy.context.selected_objects: - obj = annotation.Annotator.add_text(related_element=selected_object) - else: - obj = annotation.Annotator.add_text() - else: - obj = annotation.Annotator.get_annotation_obj(self.obj_name, self.data_type) - if self.obj_name == "Break": - obj = annotation.Annotator.add_plane_to_annotation(obj) - else: - obj = annotation.Annotator.add_line_to_annotation(obj) - bpy.ops.object.select_all(action="DESELECT") - bpy.context.view_layer.objects.active = obj - bpy.ops.object.mode_set(mode="EDIT") - return {"FINISHED"} - - class GenerateReferences(bpy.types.Operator): bl_idname = "bim.generate_references" bl_label = "Generate References" diff --git a/src/blenderbim/blenderbim/bim/prop.py b/src/blenderbim/blenderbim/bim/prop.py index 4c5b493919..cf7dce508a 100644 --- a/src/blenderbim/blenderbim/bim/prop.py +++ b/src/blenderbim/blenderbim/bim/prop.py @@ -6,7 +6,7 @@ import ifcopenshell from . import export_ifc from . import schema from . import ifc -from . import annotation +import blenderbim.bim.module.drawing.annotation as annotation from . import decoration import bpy from blenderbim.bim.handler import purge_module_data