diff --git a/src/blenderbim/blenderbim/bim/module/drawing/operator.py b/src/blenderbim/blenderbim/bim/module/drawing/operator.py index d2bf5aca24..bf5256185f 100644 --- a/src/blenderbim/blenderbim/bim/module/drawing/operator.py +++ b/src/blenderbim/blenderbim/bim/module/drawing/operator.py @@ -529,28 +529,35 @@ class CreateDrawing(bpy.types.Operator): files = {context.scene.BIMProperties.ifc_file: tool.Ifc.get()} + for link in context.scene.BIMProjectProperties.links: + if link.name not in IfcStore.session_files: + IfcStore.session_files[link.name] = ifcopenshell.open(link.name) + files[link.name] = IfcStore.session_files[link.name] + + target_view = ifcopenshell.util.element.get_psets(self.camera_element)["EPset_Drawing"]["TargetView"] + self.setup_serialiser(target_view) + + tree = ifcopenshell.geom.tree() + tree.enable_face_styles(True) + for ifc_path, ifc in files.items(): # Don't use draw.main() just whilst we're prototyping and experimenting # TODO: hash paths are never used ifc_hash = hashlib.md5(ifc_path.encode("utf-8")).hexdigest() ifc_cache_path = os.path.join(context.scene.BIMProperties.data_dir, "cache", f"{ifc_hash}.h5") + self.serialiser.setFile(ifc) + drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element, ifc_file=ifc) + # Get all representation contexts to see what we're dealing with. # Drawings only draw bodies and annotations (and facetation, due to a Revit bug). # A drawing prioritises a target view context first, followed by a model view context as a fallback. # Specifically for PLAN_VIEW and REFLECTED_PLAN_VIEW, any Plan context is also prioritised. - target_view = ifcopenshell.util.element.get_psets(self.camera_element)["EPset_Drawing"]["TargetView"] contexts = self.get_linework_contexts(ifc, target_view) - drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element) - - self.setup_serialiser(ifc, target_view) - tree = ifcopenshell.geom.tree() - tree.enable_face_styles(True) - self.serialize_contexts_elements(ifc, tree, contexts, "body", drawing_elements, target_view) self.serialize_contexts_elements(ifc, tree, contexts, "annotation", drawing_elements, target_view) - if self.camera_element not in drawing_elements: + if tool.Ifc.get() == ifc and self.camera_element not in drawing_elements: with profile("Camera element"): # The camera must always be included, regardless of any include/exclude filters. geom_settings = ifcopenshell.geom.settings(DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True) @@ -865,13 +872,12 @@ class CreateDrawing(bpy.types.Operator): return svg_path - def setup_serialiser(self, ifc, target_view): + def setup_serialiser(self, target_view): self.svg_settings = ifcopenshell.geom.settings( DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True ) self.svg_buffer = ifcopenshell.geom.serializers.buffer() self.serialiser = ifcopenshell.geom.serializers.svg(self.svg_buffer, self.svg_settings) - self.serialiser.setFile(ifc) self.serialiser.setWithoutStoreys(True) self.serialiser.setPolygonal(True) self.serialiser.setUseHlrPoly(True) @@ -935,6 +941,18 @@ class CreateDrawing(bpy.types.Operator): self.is_manifold_cache[obj.data.name] = True return True + def get_element_by_guid(self, guid): + try: + return tool.Ifc.get().by_guid(guid) + except: + for link in bpy.context.scene.BIMProjectProperties.links: + if link.name not in IfcStore.session_files: + IfcStore.session_files[link.name] = ifcopenshell.open(link.name) + try: + return IfcStore.session_files[link.name].by_guid(guid) + except: + continue + def merge_linework_and_add_metadata(self, root): join_criteria = ifcopenshell.util.element.get_pset(self.camera_element, "EPset_Drawing", "JoinCriteria") if join_criteria: @@ -949,7 +967,7 @@ class CreateDrawing(bpy.types.Operator): ifc = tool.Ifc.get() for el in root.findall(".//{http://www.w3.org/2000/svg}g[@{http://www.ifcopenshell.org/ns}guid]"): - element = ifc.by_guid(el.get("{http://www.ifcopenshell.org/ns}guid")) + element = self.get_element_by_guid(el.get("{http://www.ifcopenshell.org/ns}guid")) if "projection" in el.get("class", "").split(): classes = self.get_svg_classes(element) @@ -962,6 +980,10 @@ class CreateDrawing(bpy.types.Operator): el.set("class", " ".join(classes)) obj = tool.Ifc.get_object(element) + + if not obj: # This is a linked model object. For now, do nothing. + continue + if not self.is_manifold(obj): continue diff --git a/src/blenderbim/blenderbim/tool/drawing.py b/src/blenderbim/blenderbim/tool/drawing.py index d2a8f96aca..01d2c2c51c 100644 --- a/src/blenderbim/blenderbim/tool/drawing.py +++ b/src/blenderbim/blenderbim/tool/drawing.py @@ -1625,11 +1625,17 @@ class Drawing(blenderbim.core.tool.Drawing): return ifcopenshell.util.element.get_psets(drawing).get("EPset_Drawing", {}).get("HasAnnotation", False) @classmethod - def get_drawing_elements(cls, drawing: ifcopenshell.entity_instance) -> set[ifcopenshell.entity_instance]: + def get_drawing_elements( + cls, drawing: ifcopenshell.entity_instance, ifc_file: Optional[ifcopenshell.file] = None + ) -> set[ifcopenshell.entity_instance]: """returns a set of elements that are included in the drawing""" - ifc_file = tool.Ifc.get() + if ifc_file is None: + ifc_file = tool.Ifc.get() + elements = cls.get_elements_in_camera_view(tool.Ifc.get_object(drawing), bpy.data.objects) + else: + # This can probably be smarter + elements = set(ifc_file.by_type("IfcElement")) pset = ifcopenshell.util.element.get_psets(drawing).get("EPset_Drawing", {}) - elements = cls.get_elements_in_camera_view(tool.Ifc.get_object(drawing), bpy.data.objects) include = pset.get("Include", None) if include: elements = ifcopenshell.util.selector.filter_elements(ifc_file, include)