diff --git a/src/blenderbim/Makefile b/src/blenderbim/Makefile index fcb16804a4..06feae1f41 100644 --- a/src/blenderbim/Makefile +++ b/src/blenderbim/Makefile @@ -93,7 +93,7 @@ endif cp -r blenderbim/* dist/blenderbim/ # Provides IfcOpenShell Python functionality - cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-$(PYNUMBER)-v0.7.0-58ee049-$(PLATFORM)64.zip + cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-$(PYNUMBER)-v0.7.0-93c5906-$(PLATFORM)64.zip cd dist/working && unzip ifcblender* cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/ @@ -360,7 +360,7 @@ endif cd dist/working/ && patch ../blenderbim/libs/site/packages/behave/runner_util.py < runner_util.patch rm -rf dist/working - # Required by ids + # Required by ids - uh, not any more, but I'm trying it out in the drawing module mkdir dist/working cd dist/working && wget $(LXML_URL) cd dist/working && cp *.whl lxml.zip && unzip lxml.zip diff --git a/src/blenderbim/blenderbim/bim/data/styles/default.css b/src/blenderbim/blenderbim/bim/data/styles/default.css index a58513c437..8cd89c06c2 100644 --- a/src/blenderbim/blenderbim/bim/data/styles/default.css +++ b/src/blenderbim/blenderbim/bim/data/styles/default.css @@ -19,8 +19,8 @@ */ * { stroke-linecap: round; stroke-linejoin: round; } -*[id] { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; } text { fill: black; stroke: none; } +.cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; } .projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } .annotation { fill: none; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; } .hidden { stroke-dasharray: 3, 2; } diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index 79166da76f..7e20f657c5 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -149,6 +149,8 @@ class CreateDrawing(bpy.types.Operator): self.props = context.scene.DocProperties self.drawing_name = self.file.by_id(self.camera.BIMObjectProperties.ifc_definition_id).Name self.get_scale() + if self.camera.data.BIMCameraProperties.update_representation(self.camera): + bpy.ops.bim.update_representation(obj=self.camera.name, ifc_representation_class="") underlay_svg = self.generate_underlay(context) self.profile_code("Generate underlay") linework_svg = self.generate_linework(context) @@ -307,12 +309,43 @@ class CreateDrawing(bpy.types.Operator): iterators.append(ifcopenshell.geom.iterator(geom_settings, f, multiprocessing.cpu_count(), exclude=exclude)) - with open(svg_path, "w") as svg: - results = ifcopenshell.draw.main(draw_settings, files, iterators=iterators, merge_projection=False) - svg.write(str(results)) + results = ifcopenshell.draw.main(draw_settings, files, iterators=iterators, merge_projection=False) + + from lxml import etree + + root = etree.fromstring(results) + self.enrich_linework_with_metadata(root) + self.move_projection_to_bottom(root) + with open(svg_path, "wb") as svg: + svg.write(etree.tostring(root)) return svg_path + def enrich_linework_with_metadata(self, root): + ifc = tool.Ifc.get() + for el in root.findall('.//{http://www.w3.org/2000/svg}g[@{http://www.ifcopenshell.org/ns}guid]'): + classes = [] + element = ifc.by_guid(el.get("{http://www.ifcopenshell.org/ns}guid")) + material = ifcopenshell.util.element.get_material(element, should_skip_usage=True) + if material: + if material.is_a("IfcMaterialLayerSet"): + name = material.LayerSetName or "null" + else: + name = getattr(material, "Name", "null") + name = self.canonicalise_class_name(name) + classes.append(f"material-{name}") + if classes: + el.set("class", (el.get("class", "") + " " + " ".join(classes)).strip()) + + def move_projection_to_bottom(self, root): + # https://stackoverflow.com/questions/36018627/sorting-child-elements-with-lxml-based-on-attribute-value + group = root.find('{http://www.w3.org/2000/svg}g') + #group[:] = sorted(group, key=lambda e : "projection" in e.get("class")) + group[:] = reversed(group) + + def canonicalise_class_name(self, name): + return re.sub("[^0-9a-zA-Z]+", "", name) + def generate_annotation(self, context): if not self.props.has_annotation: return diff --git a/src/blenderbim/blenderbim/bim/module/drawing/prop.py b/src/blenderbim/blenderbim/bim/module/drawing/prop.py index 93ba539224..d88efdc7b2 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/prop.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/prop.py @@ -18,6 +18,7 @@ import os import bpy +import json import ifcopenshell import blenderbim.tool as tool import blenderbim.bim.module.drawing.annotation as annotation @@ -300,6 +301,7 @@ class DocProperties(PropertyGroup): class BIMCameraProperties(PropertyGroup): + representation: StringProperty(name="Representation") view_name: StringProperty(name="View Name") target_view: EnumProperty( items=[ @@ -332,6 +334,21 @@ class BIMCameraProperties(PropertyGroup): cut_objects_custom: StringProperty(name="Custom Cut") active_drawing_style_index: IntProperty(name="Active Drawing Style Index") + # For now, this JSON dump are all the parameters that determine a camera's "Block representation" + # By checking this, you will know whether or not the camera IFC representation needs to be refreshed + def update_representation(self, obj): + representation = json.dumps({ + "matrix": [list(x) for x in obj.matrix_world], + "raster_x": self.raster_x, + "raster_y": self.raster_y, + "ortho_scale": obj.data.ortho_scale, + "clip_end": obj.data.clip_end, + }) + if self.representation != representation: + self.representation = representation + return True + return False + class BIMTextProperties(PropertyGroup): font_size: EnumProperty( diff --git a/src/blenderbim/blenderbim/bim/module/geometry/operator.py b/src/blenderbim/blenderbim/bim/module/geometry/operator.py index 5c400d9da0..2efcccd4ba 100644 --- a/src/blenderbim/blenderbim/bim/module/geometry/operator.py +++ b/src/blenderbim/blenderbim/bim/module/geometry/operator.py @@ -383,14 +383,14 @@ class OverrideDelete(bpy.types.Operator): for obj in context.selected_objects: if obj.BIMObjectProperties.ifc_definition_id: element = file.by_id(obj.BIMObjectProperties.ifc_definition_id) - if element.FillsVoids: + if getattr(element, "FillsVoids", None): self.remove_filling(element) if element.is_a("IfcOpeningElement"): for rel in element.HasFillings: self.remove_filling(rel.RelatedBuildingElement) if element.VoidsElements: self.delete_opening_element(element) - elif element.HasOpenings: + elif getattr(element, "HasOpenings", None): for rel in element.HasOpenings: self.delete_opening_element(rel.RelatedOpeningElement) bpy.data.objects.remove(obj)