mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 10:06:47 +00:00
#1153. You can now assign and remove drawings from sheets.
This commit is contained in:
@@ -33,6 +33,7 @@ classes = (
|
||||
operator.AddSheet,
|
||||
operator.BuildSchedule,
|
||||
operator.CleanWireframes,
|
||||
operator.ContractSheet,
|
||||
operator.CopyGrid,
|
||||
operator.CreateDrawing,
|
||||
operator.CreateSheets,
|
||||
@@ -45,12 +46,14 @@ classes = (
|
||||
operator.EditVectorStyle,
|
||||
operator.EnableEditingText,
|
||||
operator.EnableEditingTextProduct,
|
||||
operator.ExpandSheet,
|
||||
operator.GenerateReferences,
|
||||
operator.LoadDrawings,
|
||||
operator.LoadSheets,
|
||||
operator.OpenSheet,
|
||||
operator.OpenView,
|
||||
operator.RemoveDrawing,
|
||||
operator.RemoveDrawingFromSheet,
|
||||
operator.RemoveDrawingStyle,
|
||||
operator.RemoveDrawingStyleAttribute,
|
||||
operator.RemoveSchedule,
|
||||
|
||||
@@ -571,7 +571,6 @@ class AddDrawingToSheet(bpy.types.Operator):
|
||||
bl_idname = "bim.add_drawing_to_sheet"
|
||||
bl_label = "Add Drawing To Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
# TODO: check undo redo
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@@ -580,9 +579,78 @@ class AddDrawingToSheet(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.DocProperties
|
||||
active_drawing = props.drawings[props.active_drawing_index]
|
||||
active_sheet = props.sheets[props.active_sheet_index]
|
||||
drawing = tool.Ifc.get().by_id(active_drawing.ifc_definition_id)
|
||||
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
|
||||
if not sheet.is_a("IfcDocumentInformation"):
|
||||
return {"FINISHED"}
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
references = sheet.DocumentReferences or []
|
||||
else:
|
||||
references = sheet.HasDocumentReferences or []
|
||||
|
||||
has_drawing = False
|
||||
for reference in references:
|
||||
new = props.sheets.add()
|
||||
new.ifc_definition_id = reference.id()
|
||||
new.is_sheet = False
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
new.identification = reference.ItemReference or "X"
|
||||
element = [r for r in tool.Ifc.by_type("IfcRelAssociatesDocument") if r.RelatingDocument == reference][
|
||||
0
|
||||
].RelatedObjects[0]
|
||||
else:
|
||||
new.identification = reference.Identification or "X"
|
||||
element = reference.DocumentRefForObjects[0].RelatedObjects[0]
|
||||
if element == drawing:
|
||||
has_drawing = True
|
||||
break
|
||||
|
||||
if has_drawing:
|
||||
return {"FINISHED"}
|
||||
|
||||
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
attributes = {"ItemReference": str(len(sheet.DocumentReferences or []))}
|
||||
else:
|
||||
attributes = {"Identification": str(len(sheet.HasDocumentReferences or []))}
|
||||
tool.Ifc.run("document.edit_reference", reference=reference, attributes=attributes)
|
||||
tool.Ifc.run("document.assign_document", product=drawing, document=reference)
|
||||
sheet_builder = sheeter.SheetBuilder()
|
||||
sheet_builder.data_dir = context.scene.BIMProperties.data_dir
|
||||
sheet_builder.add_drawing(props.active_drawing.name, props.active_sheet.name)
|
||||
sheet_builder.add_drawing(drawing, sheet)
|
||||
|
||||
tool.Drawing.import_sheets()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveDrawingFromSheet(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_drawing_from_sheet"
|
||||
bl_label = "Remove Drawing From Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
reference: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
reference = tool.Ifc.get().by_id(self.reference)
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
sheet = reference.ReferenceToDocument[0]
|
||||
drawing = [r for r in tool.Ifc.by_type("IfcRelAssociatesDocument") if r.RelatingDocument == reference][
|
||||
0
|
||||
].RelatedObjects[0]
|
||||
else:
|
||||
sheet = reference.ReferencedDocument
|
||||
drawing = reference.DocumentRefForObjects[0].RelatedObjects[0]
|
||||
|
||||
tool.Ifc.run("document.unassign_document", product=drawing, document=reference)
|
||||
tool.Ifc.run("document.remove_reference", reference=reference)
|
||||
|
||||
sheet_builder = sheeter.SheetBuilder()
|
||||
sheet_builder.data_dir = context.scene.BIMProperties.data_dir
|
||||
sheet_builder.remove_drawing(drawing, sheet)
|
||||
tool.Drawing.import_sheets()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -598,7 +666,8 @@ class CreateSheets(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
props = scene.DocProperties
|
||||
name = props.active_sheet.name
|
||||
active_sheet = props.sheets[props.active_sheet_index]
|
||||
name = active_sheet.name
|
||||
sheet_builder = sheeter.SheetBuilder()
|
||||
sheet_builder.data_dir = scene.BIMProperties.data_dir
|
||||
sheet_builder.build(name)
|
||||
@@ -943,12 +1012,10 @@ class RemoveSheet(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_sheet"
|
||||
bl_label = "Remove Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
index: bpy.props.IntProperty()
|
||||
sheet: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
self.props = context.scene.DocProperties
|
||||
sheet = tool.Ifc.get().by_id(self.props.sheets[self.props.active_sheet_index].ifc_definition_id)
|
||||
core.remove_sheet(tool.Ifc, tool.Drawing, sheet=sheet)
|
||||
core.remove_sheet(tool.Ifc, tool.Drawing, sheet=tool.Ifc.get().by_id(self.sheet))
|
||||
|
||||
|
||||
class AddSchedule(bpy.types.Operator):
|
||||
@@ -1323,3 +1390,31 @@ class DisableEditingDrawings(bpy.types.Operator, Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
core.disable_editing_drawings(tool.Drawing)
|
||||
|
||||
|
||||
class ExpandSheet(bpy.types.Operator):
|
||||
bl_idname = "bim.expand_sheet"
|
||||
bl_label = "Expand Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
sheet: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.DocProperties
|
||||
for sheet in [s for s in props.sheets if s.ifc_definition_id == self.sheet]:
|
||||
sheet.is_expanded = True
|
||||
core.load_sheets(tool.Drawing)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ContractSheet(bpy.types.Operator):
|
||||
bl_idname = "bim.contract_sheet"
|
||||
bl_label = "Contract Sheet"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
sheet: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.DocProperties
|
||||
for sheet in [s for s in props.sheets if s.ifc_definition_id == self.sheet]:
|
||||
sheet.is_expanded = False
|
||||
core.load_sheets(tool.Drawing)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -221,8 +221,9 @@ class Sheet(PropertyGroup):
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
identification: StringProperty(name="Identification")
|
||||
name: StringProperty(name="Name", get=get_name, set=set_name)
|
||||
drawings: CollectionProperty(name="Drawings", type=Drawing)
|
||||
active_drawing_index: IntProperty(name="Active Drawing Index")
|
||||
is_sheet: BoolProperty(name="Is Sheet", default=False)
|
||||
reference_type: StringProperty(name="Reference Type")
|
||||
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
||||
|
||||
|
||||
class DrawingStyle(PropertyGroup):
|
||||
@@ -313,10 +314,6 @@ class DocProperties(PropertyGroup):
|
||||
def active_schedule(self):
|
||||
return self.schedules[self.active_schedule_index]
|
||||
|
||||
@property
|
||||
def active_sheet(self):
|
||||
return self.sheets[self.active_sheet_index]
|
||||
|
||||
|
||||
class BIMCameraProperties(PropertyGroup):
|
||||
representation: StringProperty(name="Representation")
|
||||
|
||||
@@ -16,11 +16,12 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import urllib.parse
|
||||
import pystache
|
||||
import ntpath
|
||||
import os
|
||||
import ntpath
|
||||
import pystache
|
||||
import urllib.parse
|
||||
import xml.etree.ElementTree as ET
|
||||
import blenderbim.tool as tool
|
||||
from shutil import copy
|
||||
from xml.dom import minidom
|
||||
|
||||
@@ -59,11 +60,16 @@ class SheetBuilder:
|
||||
with open(sheet_path, "w") as f:
|
||||
f.write(minidom.parseString(ET.tostring(root)).toprettyxml(indent=" "))
|
||||
|
||||
def add_drawing(self, view_name, sheet_name):
|
||||
sheet_path = os.path.join(self.data_dir, "sheets", sheet_name + ".svg")
|
||||
view_path = os.path.join(self.data_dir, "diagrams", view_name + ".svg")
|
||||
def add_drawing(self, drawing, sheet):
|
||||
filename = drawing.Name
|
||||
sheet_name = tool.Drawing.get_sheet_filename(sheet)
|
||||
sheet_dir = os.path.join(self.data_dir, "sheets")
|
||||
drawing_dir = os.path.join(self.data_dir, "diagrams")
|
||||
sheet_path = os.path.join(sheet_dir, sheet_name + ".svg")
|
||||
drawing_path = os.path.join(drawing_dir, filename + ".svg")
|
||||
underlay_path = os.path.join(drawing_dir, filename + ".png")
|
||||
|
||||
if not os.path.isfile(view_path):
|
||||
if not os.path.isfile(sheet_path):
|
||||
raise FileNotFoundError
|
||||
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
@@ -72,7 +78,7 @@ class SheetBuilder:
|
||||
sheet_tree = ET.parse(sheet_path)
|
||||
sheet_root = sheet_tree.getroot()
|
||||
|
||||
view_tree = ET.parse(view_path)
|
||||
view_tree = ET.parse(drawing_path)
|
||||
view_root = view_tree.getroot()
|
||||
|
||||
# The view is placed into a group with a background image element.
|
||||
@@ -80,26 +86,48 @@ class SheetBuilder:
|
||||
# here to accommodate browsers which do not nest images.
|
||||
view = ET.SubElement(sheet_root, "g")
|
||||
view.attrib["data-type"] = "drawing"
|
||||
view.attrib["data-guid"] = drawing.GlobalId
|
||||
view_width = self.convert_to_mm(view_root.attrib.get("width"))
|
||||
view_height = self.convert_to_mm(view_root.attrib.get("height"))
|
||||
|
||||
background = ET.SubElement(view, "image")
|
||||
background.attrib["xlink:href"] = "../diagrams/{}.png".format(view_name)
|
||||
background.attrib["x"] = "30"
|
||||
background.attrib["y"] = "30"
|
||||
background.attrib["width"] = str(view_width)
|
||||
background.attrib["height"] = str(view_height)
|
||||
if os.path.isfile(underlay_path):
|
||||
background = ET.SubElement(view, "image")
|
||||
background.attrib["xlink:href"] = os.path.relpath(underlay_path, sheet_dir)
|
||||
background.attrib["x"] = "30"
|
||||
background.attrib["y"] = "30"
|
||||
background.attrib["width"] = str(view_width)
|
||||
background.attrib["height"] = str(view_height)
|
||||
|
||||
foreground = ET.SubElement(view, "image")
|
||||
foreground.attrib["xlink:href"] = "../diagrams/{}.svg".format(view_name)
|
||||
foreground.attrib["x"] = "30"
|
||||
foreground.attrib["y"] = "30"
|
||||
foreground.attrib["width"] = str(view_width)
|
||||
foreground.attrib["height"] = str(view_height)
|
||||
if os.path.isfile(drawing_path):
|
||||
foreground = ET.SubElement(view, "image")
|
||||
foreground.attrib["xlink:href"] = os.path.relpath(drawing_path, sheet_dir)
|
||||
foreground.attrib["x"] = "30"
|
||||
foreground.attrib["y"] = "30"
|
||||
foreground.attrib["width"] = str(view_width)
|
||||
foreground.attrib["height"] = str(view_height)
|
||||
|
||||
self.add_view_title(30, view_height + 35, view)
|
||||
sheet_tree.write(sheet_path)
|
||||
|
||||
def remove_drawing(self, drawing, sheet):
|
||||
sheet_name = tool.Drawing.get_sheet_filename(sheet)
|
||||
sheet_dir = os.path.join(self.data_dir, "sheets")
|
||||
sheet_path = os.path.join(sheet_dir, sheet_name + ".svg")
|
||||
|
||||
ET.register_namespace("", "http://www.w3.org/2000/svg")
|
||||
|
||||
sheet_tree = ET.parse(sheet_path)
|
||||
sheet_root = sheet_tree.getroot()
|
||||
|
||||
print('removing drawing', sheet_root.findall("{http://www.w3.org/2000/svg}g"))
|
||||
for g in sheet_root.findall("{http://www.w3.org/2000/svg}g"):
|
||||
print('checking g', g)
|
||||
if g.attrib["data-type"] == "drawing" and g.attrib["data-guid"] == drawing.GlobalId:
|
||||
sheet_root.remove(g)
|
||||
break
|
||||
|
||||
sheet_tree.write(sheet_path)
|
||||
|
||||
def add_schedule(self, schedule_name, sheet_name):
|
||||
sheet_path = os.path.join(self.data_dir, "sheets", sheet_name + ".svg")
|
||||
view_path = os.path.join(self.data_dir, "schedules", schedule_name + ".svg")
|
||||
|
||||
@@ -246,14 +246,19 @@ class BIM_PT_sheets(Panel):
|
||||
row.operator("bim.add_sheet", text="", icon="ADD")
|
||||
row.operator("bim.disable_editing_sheets", text="", icon="CANCEL")
|
||||
|
||||
if self.props.sheets:
|
||||
if self.props.sheets and self.props.active_sheet_index < len(self.props.sheets):
|
||||
active_sheet = self.props.sheets[self.props.active_sheet_index]
|
||||
row = self.layout.row(align=True)
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.open_sheet", icon="URL", text="")
|
||||
row.operator("bim.add_drawing_to_sheet", icon="IMAGE_PLANE", text="")
|
||||
row.operator("bim.add_schedule_to_sheet", icon="PRESET_NEW", text="")
|
||||
row.operator("bim.create_sheets", icon="FILE_REFRESH", text="")
|
||||
row.operator("bim.remove_sheet", icon="X", text="").index = self.props.active_sheet_index
|
||||
if active_sheet.is_sheet:
|
||||
row.operator("bim.remove_sheet", icon="X", text="").sheet = active_sheet.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.remove_drawing_from_sheet", icon="X", text="")
|
||||
op.reference = active_sheet.ifc_definition_id
|
||||
|
||||
self.layout.template_list("BIM_UL_sheets", "", self.props, "sheets", self.props, "active_sheet_index")
|
||||
|
||||
@@ -388,9 +393,22 @@ class BIM_UL_sheets(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
split1 = row.split(factor=0.2)
|
||||
split1.label(text=item.identification or "X")
|
||||
split2 = split1.split(factor=0.8)
|
||||
split2.label(text=item.name or "Unnamed")
|
||||
|
||||
if item.is_sheet:
|
||||
if item.is_expanded:
|
||||
row.operator(
|
||||
"bim.contract_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
|
||||
).sheet = item.ifc_definition_id
|
||||
else:
|
||||
row.operator(
|
||||
"bim.expand_sheet", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
|
||||
).sheet = item.ifc_definition_id
|
||||
else:
|
||||
row.label(text="", icon="BLANK1")
|
||||
if item.reference_type == "DRAWING":
|
||||
row.label(text="", icon="IMAGE_DATA")
|
||||
|
||||
name = "{} - {}".format(item.identification or "X", item.name or "Unnamed")
|
||||
row.label(text=name)
|
||||
else:
|
||||
layout.label(text="", translate=False)
|
||||
|
||||
@@ -85,7 +85,7 @@ def open_sheet(drawing, sheet=None):
|
||||
|
||||
|
||||
def remove_sheet(ifc, drawing, sheet=None):
|
||||
ifc.run("document.remove_document", document=sheet)
|
||||
ifc.run("document.remove_information", information=sheet)
|
||||
drawing.import_sheets()
|
||||
|
||||
|
||||
|
||||
@@ -273,16 +273,45 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
|
||||
@classmethod
|
||||
def import_sheets(cls):
|
||||
bpy.context.scene.DocProperties.sheets.clear()
|
||||
props = bpy.context.scene.DocProperties
|
||||
expanded_sheets = {s.ifc_definition_id for s in props.sheets if s.is_expanded}
|
||||
props.sheets.clear()
|
||||
sheets = [d for d in tool.Ifc.get().by_type("IfcDocumentInformation") if d.Scope == "DOCUMENTATION"]
|
||||
for sheet in sheets:
|
||||
new = bpy.context.scene.DocProperties.sheets.add()
|
||||
new = props.sheets.add()
|
||||
new.ifc_definition_id = sheet.id()
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
new.identification = sheet.DocumentId
|
||||
else:
|
||||
new.identification = sheet.Identification
|
||||
new.name = sheet.Name
|
||||
new.is_sheet = True
|
||||
new.is_expanded = sheet.id() in expanded_sheets
|
||||
|
||||
if not new.is_expanded:
|
||||
continue
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
references = sheet.DocumentReferences or []
|
||||
else:
|
||||
references = sheet.HasDocumentReferences or []
|
||||
|
||||
for reference in references:
|
||||
new = props.sheets.add()
|
||||
new.ifc_definition_id = reference.id()
|
||||
new.is_sheet = False
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
new.identification = reference.ItemReference or "X"
|
||||
element = [
|
||||
r for r in tool.Ifc.by_type("IfcRelAssociatesDocument") if r.RelatingDocument == reference
|
||||
][0].RelatedObjects[0]
|
||||
else:
|
||||
new.identification = reference.Identification or "X"
|
||||
element = reference.DocumentRefForObjects[0].RelatedObjects[0]
|
||||
|
||||
new.name = element.Name
|
||||
new.reference_type = "DRAWING"
|
||||
|
||||
@classmethod
|
||||
def import_text_attributes(cls, obj):
|
||||
@@ -456,9 +485,6 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
# 1. Select the 4 +Z vertices local to the reference element. This is the cutting plane.
|
||||
verts_local_to_reference = [reference_obj.matrix_world.inverted() @ v for v in reference_mesh["verts"]]
|
||||
cutting_plane_verts = sorted(verts_local_to_reference, key=lambda x: x.z)[-4:]
|
||||
# Filter verts with the same XY coords
|
||||
#set([v.xy for v in cutting_plane_verts])
|
||||
|
||||
global_cutting_plane_verts = [reference_obj.matrix_world @ v for v in cutting_plane_verts]
|
||||
# 2. Project the cutting plane onto our viewing camera.
|
||||
verts_local_to_camera = [camera.matrix_world.inverted() @ v for v in global_cutting_plane_verts]
|
||||
@@ -640,14 +666,14 @@ class Drawing(blenderbim.core.tool.Drawing):
|
||||
depth = obj.data.clip_end
|
||||
|
||||
verts = (
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, -height /2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, -height /2, 0)),
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, height /2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, height /2, 0)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, -height /2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, -height /2, 0)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, height /2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, height /2, 0))
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, -height / 2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, -height / 2, 0)),
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, height / 2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((-width / 2, height / 2, 0)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, -height / 2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, -height / 2, 0)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, height / 2, -depth)),
|
||||
obj.matrix_world @ mathutils.Vector((width / 2, height / 2, 0)),
|
||||
)
|
||||
faces = [
|
||||
[0, 1, 3, 2],
|
||||
|
||||
Reference in New Issue
Block a user