Migrate from bcfplugin to new bcf library in the BlenderBIM Add-on

This commit is contained in:
Dion Moult
2020-12-18 16:28:17 +11:00
parent d08da0a61d
commit 7dd40149aa
8 changed files with 292 additions and 506 deletions
+24 -3
View File
@@ -30,8 +30,19 @@ class BcfXml:
self.logger = logging.getLogger("bcfxml")
self.author = "john@doe.com"
self.project = bcf.data.Project()
self.version = "2.1"
self.topics = {}
def new_project(self):
self.project.project_id = str(uuid.uuid4())
self.project.name = "New Project"
self.topics = {}
if self.filepath:
self.close_project()
self.filepath = tempfile.mkdtemp()
self.edit_project()
self.edit_version()
def get_project(self, filepath=None):
if not filepath:
return self.project
@@ -62,7 +73,15 @@ class BcfXml:
def get_version(self):
data = self._read_xml("bcf.version", "version.xsd")
return data["@VersionId"]
self.version = data["@VersionId"]
return self.version
def edit_version(self):
self.document = minidom.Document()
root = self._create_element(self.document, "Version", {"VersionId": self.version})
version = self._create_element(root, "DetailedVersion", text=self.version)
with open(os.path.join(self.filepath, "bcf.version"), "wb") as f:
f.write(self.document.toprettyxml(encoding="utf-8"))
def get_topics(self):
self.topics = {}
@@ -117,14 +136,15 @@ class BcfXml:
"priority": "Priority",
"index": "Index",
"labels": "Labels",
"reference_links": "ReferenceLink",
"modified_date": "ModifiedDate",
"modified_author": "ModifiedAuthor",
"due_date": "DueDate",
"assigned_to": "AssignedTo",
"stage": "Stage",
"description": "Description",
"topic_status": "TopicStatus",
"topic_type": "TopicType",
"topic_status": "@TopicStatus",
"topic_type": "@TopicType",
}
for key, value in optional_keys.items():
if value in data["Topic"]:
@@ -173,6 +193,7 @@ class BcfXml:
topic.title = "New Topic"
os.mkdir(os.path.join(self.filepath, topic.guid))
self.edit_topic(topic)
return topic
def edit_topic(self, topic):
if not topic.creation_date:
+10 -45
View File
@@ -138,57 +138,22 @@ endif
cp -r dist/working/pyparsing-2.4.5/pyparsing.py dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Required by bcfplugin
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/82/c3/534ddba230bd4fbbd3b7a3d35f3341d014cca213f369a9940925e7e5f691/pytz-2019.3.tar.gz
cd dist/working && tar -xzvf pytz*
cp -r dist/working/pytz-2019.3/pytz dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Required by bcfplugin
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/be/ed/5bbc91f03fa4c839c4c7360375da77f9659af5f7086b7a7bdda65771c8e0/python-dateutil-2.8.1.tar.gz
cd dist/working && tar -xzvf python-dateutil*
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Required by bcfplugin
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/21/9f/b251f7f8a76dec1d6651be194dfba8fb8d7781d10ab3987190de8391d08e/six-1.14.0.tar.gz
cd dist/working && tar -xzvf six*
cp -r dist/working/six-1.14.0/six.py dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Required by bcfplugin
# Required by bcf
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/bb/41/ad9ce53bb978b68af8ae415293cafc89b165b8ad55a593725299dca76729/xmlschema-1.1.1.tar.gz
cd dist/working && tar -xzvf xmlschema*
cp -r dist/working/xmlschema-1.1.1/xmlschema dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Required by bcfplugin
mkdir dist/working
cd dist/working && wget https://files.pythonhosted.org/packages/12/f9/f9960222d5274944b01391749e55e4dcdf28d8f0c108b64ac931ceff6fdb/elementpath-1.4.3.tar.gz
cd dist/working && tar -xzvf elementpath*
cp -r dist/working/elementpath-1.4.3/elementpath dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Provides bcfplugin functionality
mkdir dist/working
cd dist/working && wget https://github.com/podestplatz/bcf/archive/master.zip
cd dist/working && unzip master*
cp -r dist/working/bcf-master/bcfplugin dist/blenderbim/libs/site/packages/
rm -rf dist/working
# Required by bcfplugin
mkdir dist/working
cd dist/working && wget https://raw.githubusercontent.com/buildingSMART/BCF-XML/release_2_1/Schemas/project.xsd
cd dist/working && wget https://raw.githubusercontent.com/buildingSMART/BCF-XML/release_2_1/Extension%20Schemas/extensions.xsd
cd dist/working && wget https://raw.githubusercontent.com/buildingSMART/BCF-XML/release_2_1/Schemas/markup.xsd
cd dist/working && wget https://raw.githubusercontent.com/buildingSMART/BCF-XML/release_2_1/Schemas/version.xsd
cd dist/working && wget https://raw.githubusercontent.com/buildingSMART/BCF-XML/release_2_1/Schemas/visinfo.xsd
mkdir dist/blenderbim/libs/site/packages/bcfplugin/schemas/
cp -r dist/working/*.xsd dist/blenderbim/libs/site/packages/bcfplugin/schemas/
# Provides bcf functionality
mkdir dist/blenderbim/libs/site/packages/bcf
mkdir dist/blenderbim/libs/site/packages/bcf/xsd
cd dist/blenderbim/libs/site/packages/bcf && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/bcf/bcf/bcfxml.py
cd dist/blenderbim/libs/site/packages/bcf && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/bcf/bcf/data.py
cd dist/blenderbim/libs/site/packages/bcf/xsd && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/bcf/bcf/xsd/markup.xsd
cd dist/blenderbim/libs/site/packages/bcf/xsd && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/bcf/bcf/xsd/project.xsd
cd dist/blenderbim/libs/site/packages/bcf/xsd && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/bcf/bcf/xsd/version.xsd
cd dist/blenderbim/libs/site/packages/bcf/xsd && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/bcf/bcf/xsd/visinfo.xsd
rm -rf dist/working
# Required by IFCCSV and ifcopenshell.util.selector
@@ -27,15 +27,13 @@ if bpy is not None:
operator.SelectType,
operator.NewBcfProject,
operator.LoadBcfProject,
operator.LoadBcfTopics,
operator.SaveBcfProject,
operator.AddBcfTopic,
operator.ViewBcfTopic,
operator.ActivateBcfViewpoint,
operator.OpenBcfFileReference,
operator.OpenUri,
operator.OpenBcfReferenceLink,
operator.OpenBcfBimSnippetSchema,
operator.OpenBcfBimSnippetReference,
operator.OpenBcfDocumentReference,
operator.SelectFeaturesDir,
operator.SelectDiffJsonFile,
operator.SelectDiffNewFile,
@@ -260,12 +258,9 @@ if bpy is not None:
prop.Schedule,
prop.DrawingStyle,
prop.Sheet,
prop.BcfBimSnippet,
prop.BcfDocumentReference,
prop.BcfTopic,
prop.BcfTopicLabel,
prop.BcfTopicFile,
prop.BcfTopicLink,
prop.BcfTopicDocumentReference,
prop.BcfTopicRelatedTopic,
prop.Subcontext,
prop.PresentationLayer,
prop.BIMProperties,
@@ -1,4 +0,0 @@
class BcfStore:
topics = []
viewpoints = []
comments = []
@@ -0,0 +1,11 @@
import bcf
import bcf.bcfxml
class BcfStore:
bcfxml = None
@staticmethod
def get_bcfxml():
if not BcfStore.bcfxml:
BcfStore.bcfxml = bcf.bcfxml.BcfXml()
return BcfStore.bcfxml
+115 -131
View File
@@ -20,7 +20,7 @@ from . import svgwriter
from . import sheeter
from . import scheduler
from . import schema
from . import bcf
from . import bcfstore
from . import ifc
from . import annotation
from . import helper
@@ -512,16 +512,9 @@ class NewBcfProject(bpy.types.Operator):
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
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.new_project()
bpy.ops.bim.load_bcf_project()
return {"FINISHED"}
@@ -531,18 +524,12 @@ class LoadBcfProject(bpy.types.Operator):
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
def execute(self, context):
import bcfplugin
bcfplugin.openProject(self.filepath)
bcf.BcfStore.topics = bcfplugin.getTopics()
bcfxml = bcfstore.BcfStore.get_bcfxml()
if self.filepath:
bcfxml.get_project(self.filepath)
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]
bpy.context.scene.BCFProperties.is_editable = True
bpy.context.scene.BCFProperties.name = bcfxml.project.name
bpy.ops.bim.load_bcf_topics()
bpy.context.scene.BCFProperties.is_loaded = True
return {"FINISHED"}
@@ -551,14 +538,76 @@ class LoadBcfProject(bpy.types.Operator):
return {"RUNNING_MODAL"}
class LoadBcfTopics(bpy.types.Operator):
bl_idname = "bim.load_bcf_topics"
bl_label = "Load BCF Topics"
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.get_topics()
while len(bpy.context.scene.BCFProperties.topics) > 0:
bpy.context.scene.BCFProperties.topics.remove(0)
for topic in bcfxml.topics.values():
new = bpy.context.scene.BCFProperties.topics.add()
data_map = {
"name": topic.title,
"guid": topic.guid,
"type": topic.topic_type,
"status": topic.topic_status,
"priority": topic.priority,
"stage": topic.stage,
"creation_date": topic.creation_date,
"creation_author": topic.creation_author,
"modified_date": topic.modified_date,
"modified_author": topic.modified_author,
"assigned_to": topic.assigned_to,
"due_date": topic.due_date,
"description": topic.description
}
for key, value in data_map.items():
if value is not None:
setattr(new, key, str(value))
for reference_link in topic.reference_links:
new2 = new.reference_links.add()
new2.name = reference_link
for label in topic.labels:
new2 = new.labels.add()
new2.name = label
if topic.bim_snippet:
data_map = {
"type": topic.bim_snippet.snippet_type,
"is_external": topic.bim_snippet.is_external,
"reference": topic.bim_snippet.reference,
"schema": topic.bim_snippet.reference_schema
}
for key, value in data_map.items():
if value is not None:
setattr(new.bim_snippet, key, value)
for doc in topic.document_references:
new2 = new.document_references.add()
data_map = {
"reference": doc.referenced_document,
"description": doc.description,
"guid": doc.guid,
"is_external": doc.is_external
}
for key, value in data_map.items():
if value is not None:
setattr(new2, key, value)
for related_topic in topic.related_topics:
new2 = new.related_topics.add()
new2.name = related_topic.guid
return {"FINISHED"}
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)
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.save_project(self.filepath)
return {"FINISHED"}
def invoke(self, context, event):
@@ -571,13 +620,11 @@ class AddBcfTopic(bpy.types.Operator):
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
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.add_topic()
new = bpy.context.scene.BCFProperties.topics.add()
new.name = "New Topic"
bcf.BcfStore.topics = bcfplugin.getTopics()
bpy.context.scene.BCFProperties.is_editable = True
bpy.ops.bim.load_bcf_topics()
return {"FINISHED"}
@@ -587,8 +634,8 @@ class ViewBcfTopic(bpy.types.Operator):
topic_guid: bpy.props.StringProperty()
def execute(self, context):
for index, topic in enumerate(bcf.BcfStore.topics):
if str(topic[1].xmlId) == self.topic_guid:
for index, topic in enumerate(bpy.context.scene.BCFProperties.topics):
if topic.guid.lower() == self.topic_guid.lower():
bpy.context.scene.BCFProperties.active_topic_index = index
return {"FINISHED"}
@@ -598,18 +645,15 @@ class ActivateBcfViewpoint(bpy.types.Operator):
bl_label = "Activate BCF Viewpoint"
def execute(self, context):
import bcfplugin
topics = bcf.BcfStore.topics
if not topics:
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = bpy.context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.guid]
if not topic.viewpoints:
return {"FINISHED"}
topic = topics[bpy.context.scene.BCFProperties.active_topic_index][1]
viewpoints = bcf.BcfStore.viewpoints
if not viewpoints:
return {"FINISHED"}
viewpoint_reference = viewpoints[int(bpy.context.scene.BCFProperties.viewpoints)][1]
viewpoint = viewpoint_reference.viewpoint
viewpoint_guid = blender_topic.viewpoints
viewpoint = topic.viewpoints[viewpoint_guid]
obj = bpy.data.objects.get("Viewpoint")
if not obj:
obj = bpy.data.objects.new("Viewpoint", bpy.data.cameras.new("Viewpoint"))
@@ -620,13 +664,13 @@ class ActivateBcfViewpoint(bpy.types.Operator):
cam_height = bpy.context.scene.render.resolution_y
cam_aspect = cam_width / cam_height
if viewpoint_reference.snapshot:
if viewpoint.snapshot:
obj.data.show_background_images = True
while len(obj.data.background_images) > 0:
obj.data.background_images.remove(obj.data.background_images[0])
background = obj.data.background_images.new()
background.image = bpy.data.images.load(
os.path.join(bcfplugin.util.getBcfDir(), str(topic.xmlId), viewpoint_reference.snapshot.uri)
os.path.join(bcfxml.filepath, topic.guid, viewpoint.snapshot)
)
src_width = background.image.size[0]
src_height = background.image.size[1]
@@ -640,18 +684,18 @@ class ActivateBcfViewpoint(bpy.types.Operator):
area = next(area for area in bpy.context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].region_3d.view_perspective = "CAMERA"
if viewpoint.oCamera:
camera = viewpoint.oCamera
if viewpoint.orthogonal_camera:
camera = viewpoint.orthogonal_camera
obj.data.type = "ORTHO"
obj.data.ortho_scale = viewpoint.oCamera.viewWorldScale
elif viewpoint.pCamera:
camera = viewpoint.pCamera
obj.data.ortho_scale = viewpoint.orthogonal_camera.view_to_world_scale
elif viewpoint.perspective_camera:
camera = viewpoint.perspective_camera
obj.data.type = "PERSP"
if cam_aspect >= 1:
obj.data.angle = radians(camera.fieldOfView)
obj.data.angle = radians(camera.field_of_view)
else:
# https://blender.stackexchange.com/questions/23431/how-to-set-camera-horizontal-and-vertical-fov
obj.data.angle = 2 * atan((0.5 * cam_height) / (0.5 * cam_width / tan(radians(camera.fieldOfView) / 2)))
obj.data.angle = 2 * atan((0.5 * cam_height) / (0.5 * cam_width / tan(radians(camera.field_of_view) / 2)))
self.set_viewpoint_components(viewpoint)
@@ -662,37 +706,37 @@ class ActivateBcfViewpoint(bpy.types.Operator):
self.draw_lines(viewpoint)
self.delete_clipping_planes()
if viewpoint.clippingPlanes:
if viewpoint.clipping_planes:
self.create_clipping_planes(viewpoint)
self.delete_bitmaps()
if viewpoint.bitmaps:
self.create_bitmaps(viewpoint)
self.create_bitmaps(bcfxml, viewpoint, topic)
z_axis = Vector((-camera.direction.x, -camera.direction.y, -camera.direction.z)).normalized()
y_axis = Vector((camera.upVector.x, camera.upVector.y, camera.upVector.z)).normalized()
z_axis = Vector((-camera.camera_direction.x, -camera.camera_direction.y, -camera.camera_direction.z)).normalized()
y_axis = Vector((camera.camera_up_vector.x, camera.camera_up_vector.y, camera.camera_up_vector.z)).normalized()
x_axis = y_axis.cross(z_axis).normalized()
rotation = Matrix((x_axis, y_axis, z_axis))
rotation.invert()
location = Vector((camera.viewPoint.x, camera.viewPoint.y, camera.viewPoint.z))
location = Vector((camera.camera_view_point.x, camera.camera_view_point.y, camera.camera_view_point.z))
obj.matrix_world = rotation.to_4x4()
obj.location = location
return {"FINISHED"}
def set_viewpoint_components(self, viewpoint):
selected_global_ids = [s.ifcId for s in viewpoint.components.selection]
exception_global_ids = [v.ifcId for v in viewpoint.components.visibilityExceptions]
selected_global_ids = [s.ifc_guid for s in viewpoint.components.selection]
exception_global_ids = [v.ifc_guid for v in viewpoint.components.visibility.exceptions]
global_id_colours = {}
for colouring in viewpoint.components.colouring:
for component in colouring.components:
global_id_colours.setdefault(component.ifcId, colouring.colour)
for coloring in viewpoint.components.coloring:
for component in coloring.components:
global_id_colours.setdefault(component.ifc_guid, coloring.color)
for obj in bpy.data.objects:
global_id = obj.BIMObjectProperties.attributes.get("GlobalId")
if not global_id:
continue
global_id = global_id.string_value
is_visible = viewpoint.components.visibilityDefault
is_visible = viewpoint.components.visibility.default_visibility
if global_id in exception_global_ids:
is_visible = not is_visible
if not is_visible:
@@ -723,12 +767,12 @@ class ActivateBcfViewpoint(bpy.types.Operator):
stroke.points.add(len(viewpoint.lines) * 2)
coords = []
for l in viewpoint.lines:
coords.extend([l.start.x, l.start.y, l.start.z, l.end.x, l.end.y, l.end.z])
coords.extend([l.start_point.x, l.start_point.y, l.start_point.z, l.end_point.x, l.end_point.y, l.end_point.z])
stroke.points.foreach_set("co", coords)
def create_clipping_planes(self, viewpoint):
n = 0
for plane in viewpoint.clippingPlanes:
for plane in viewpoint.clipping_planes:
bpy.ops.bim.add_section_plane()
if n == 0:
obj = bpy.data.objects["Section"]
@@ -757,18 +801,14 @@ class ActivateBcfViewpoint(bpy.types.Operator):
for bitmap in collection.objects:
bpy.data.objects.remove(bitmap)
def create_bitmaps(self, viewpoint):
import bcfplugin
topics = bcf.BcfStore.topics
topic = topics[bpy.context.scene.BCFProperties.active_topic_index][1]
def create_bitmaps(self, bcfxml, viewpoint, topic):
collection = bpy.data.collections.get("Bitmaps")
if not collection:
collection = bpy.data.collections.new("Bitmaps")
for bitmap in viewpoint.bitmaps:
obj = bpy.data.objects.new("Bitmap", None)
obj.empty_display_type = "IMAGE"
image = bpy.data.images.load(os.path.join(bcfplugin.util.getBcfDir(), str(topic.xmlId), bitmap.reference))
image = bpy.data.images.load(os.path.join(bcfxml.filepath, topic.guid, bitmap.reference))
src_width = image.size[0]
src_height = image.size[1]
if src_height > src_width:
@@ -776,7 +816,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
else:
obj.empty_display_size = bitmap.height * (src_width / src_height)
obj.data = image
y = Vector((bitmap.upVector.x, bitmap.upVector.y, bitmap.upVector.z))
y = Vector((bitmap.up.x, bitmap.up.y, bitmap.up.z))
z = Vector((bitmap.normal.x, bitmap.normal.y, bitmap.normal.z))
x = y.cross(z)
obj.matrix_world = Matrix(
@@ -792,22 +832,13 @@ class ActivateBcfViewpoint(bpy.types.Operator):
return [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1]
class OpenBcfFileReference(bpy.types.Operator):
bl_idname = "bim.open_bcf_file_reference"
bl_label = "Open BCF File Reference"
data: bpy.props.StringProperty()
class OpenUri(bpy.types.Operator):
bl_idname = "bim.open_uri"
bl_label = "Open URI"
uri: bpy.props.StringProperty()
def execute(self, context):
if "/" not in self.data:
webbrowser.open(bpy.context.scene.BCFProperties.topic_files[int(self.data)].reference)
return {"FINISHED"}
import bcfplugin
topic_guid, index = self.data.split("/")
path = os.path.join(bcfplugin.util.getBcfDir(), topic_guid)
# bpy.context.scene.BCFProperties.topic_files[int(index)].reference)
# TODO - maybe allow immediate importing?
webbrowser.open(path)
webbrowser.open(self.uri)
return {"FINISHED"}
@@ -821,53 +852,6 @@ class OpenBcfReferenceLink(bpy.types.Operator):
return {"FINISHED"}
class OpenBcfBimSnippetSchema(bpy.types.Operator):
bl_idname = "bim.open_bcf_bim_snippet_schema"
bl_label = "Open BCF BIM Snippet Schema"
def execute(self, context):
webbrowser.open(bpy.context.scene.BCFProperties.topic_snippet_schema)
return {"FINISHED"}
class OpenBcfBimSnippetReference(bpy.types.Operator):
bl_idname = "bim.open_bcf_bim_snippet_reference"
bl_label = "Open BCF BIM Snippet Reference"
topic_guid: bpy.props.StringProperty()
def execute(self, context):
import bcfplugin
if bpy.context.scene.BCFProperties.topic_snippet_is_external:
webbrowser.open(bpy.context.scene.BCFProperties.topic_snippet_reference)
return {"FINISHED"}
webbrowser.open(
"file://"
+ os.path.join(
bcfplugin.util.getBcfDir(), self.topic_guid, bpy.context.scene.BCFProperties.topic_snippet_reference
)
)
return {"FINISHED"}
class OpenBcfDocumentReference(bpy.types.Operator):
bl_idname = "bim.open_bcf_document_reference"
bl_label = "Open BCF Document Reference"
data: bpy.props.StringProperty()
def execute(self, context):
import bcfplugin
topic_guid, index = self.data.split("/")
doc = bpy.context.scene.BCFProperties.topic_document_references[int(index)]
uri = doc.name
if doc.is_external:
webbrowser.open(uri)
return {"FINISHED"}
webbrowser.open("file://" + os.path.join(bcfplugin.util.getBcfDir(), topic_guid, uri))
return {"FINISHED"}
class SelectAudited(bpy.types.Operator):
bl_idname = "bim.select_audited"
bl_label = "Select Audited"
+45 -231
View File
@@ -5,7 +5,7 @@ import ifcopenshell.util.pset
from pathlib import Path
from . import export_ifc
from . import schema
from . import bcf
from . import bcfstore
from . import ifc
from . import annotation
from . import decoration
@@ -52,7 +52,7 @@ persons_enum = []
organisations_enum = []
sheets_enum = []
vector_styles_enum = []
bcfviewpoints_enum = []
bcfviewpoints_enum = None
@persistent
@@ -910,227 +910,64 @@ class Constraint(PropertyGroup):
user_defined_qualifier: StringProperty(name="Custom Qualifier")
def updateBcfProjectName(self, context):
import bcfplugin
bcfplugin.setProjectName(self.name)
def getBcfViewpoints(self, context):
global bcfviewpoints_enum
if bcfviewpoints_enum is None:
bcfviewpoints_enum = []
props = bpy.context.scene.BCFProperties
bcfxml = bcfstore.BcfStore.get_bcfxml()
topic = props.topics[props.active_topic_index]
viewpoints = bcfxml.get_viewpoints(topic.guid)
bcfviewpoints_enum.extend([(v, f"Viewpoint {i+1}", "") for i, v in enumerate(viewpoints.keys())])
return bcfviewpoints_enum
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]
if getattr(topic, name) != value:
setattr(topic, name, value)
bcfplugin.modifyElement(topic, props.author)
def updateBcfTopicName(self, context):
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)
def updateBcfTopicDescription(self, context):
updateBcfTopicAttribute(context, "description", self.topic_description)
class BcfTopic(PropertyGroup):
name: StringProperty(name="Name", update=updateBcfTopicName)
class BcfTopicLabel(PropertyGroup):
name: StringProperty(name="Name")
class BcfTopicLink(PropertyGroup):
name: StringProperty(name="Name")
class BcfTopicFile(PropertyGroup):
name: StringProperty(name="Name")
class BcfBimSnippet(PropertyGroup):
schema: StringProperty(name="Schema")
reference: StringProperty(name="Reference")
date: StringProperty(name="Date")
type: StringProperty(name="Type")
is_external: BoolProperty(name="Is External")
ifc_project: StringProperty(name="IFC Project")
ifc_spatial: StringProperty(name="IFC Spatial")
class BcfTopicDocumentReference(PropertyGroup):
name: StringProperty(name="Reference")
class BcfDocumentReference(PropertyGroup):
reference: StringProperty(name="Reference")
description: StringProperty(name="Description")
guid: StringProperty(name="GUID")
is_external: BoolProperty(name="Is External")
class BcfTopicRelatedTopic(PropertyGroup):
class BcfTopic(PropertyGroup):
name: StringProperty(name="Name")
guid: StringProperty(name="GUID")
guid: StringProperty(default="", name="GUID")
type: StringProperty(default="", name="Type")
status: StringProperty(default="", name="Status")
priority: StringProperty(default="", name="Priority")
stage: StringProperty(default="", name="Stage")
creation_date: StringProperty(default="", name="Date")
creation_author: StringProperty(default="", name="Author")
modified_date: StringProperty(default="", name="Modified Date")
modified_author: StringProperty(default="", name="Modified By")
assigned_to: StringProperty(default="", name="Assigned To")
due_date: StringProperty(default="", name="Due Date")
description: StringProperty(default="", name="Description")
viewpoints: EnumProperty(items=getBcfViewpoints, name="BCF Viewpoints")
files: CollectionProperty(name="Files", type=StrProperty)
reference_links: CollectionProperty(name="Reference Links", type=StrProperty)
labels: CollectionProperty(name="Labels", type=StrProperty)
bim_snippet: PointerProperty(type=BcfBimSnippet)
document_references: CollectionProperty(name="Document References", type=BcfDocumentReference)
related_topics: CollectionProperty(name="Related Topics", type=StrProperty)
def refreshBcfTopic(self, context):
RefreshBcfTopic.refresh(context)
class RefreshBcfTopic:
props: None
topic: None
@classmethod
def refresh(cls, context):
global bcfviewpoints_enum
cls.props = bpy.context.scene.BCFProperties
cls.topic = bcf.BcfStore.topics[cls.props.active_topic_index][1]
cls.load_topic_metadata()
cls.load_topic_labels()
cls.load_topic_files()
cls.load_topic_links()
cls.load_snippet()
cls.load_document_references()
cls.load_related_topics()
cls.load_viewpoints()
cls.load_comments()
@classmethod
def load_topic_metadata(cls):
cls.props.topic_guid = str(cls.topic.xmlId)
cls.props.topic_type = cls.topic.type
cls.props.topic_status = cls.topic.status
cls.props.topic_priority = cls.topic.priority
cls.props.topic_stage = cls.topic.stage
if cls.topic.date:
cls.props.topic_creation_date = cls.topic.date.strftime("%a %Y-%m-%d %H:%S")
else:
cls.props.topic_creation_date = ""
cls.props.topic_creation_author = cls.topic.author
if cls.topic.modDate:
cls.props.topic_modified_date = cls.topic.modDate.strftime("%a %Y-%m-%d %H:%S")
else:
cls.props.topic_modified_date = ""
cls.props.topic_modified_author = cls.topic.modAuthor
cls.props.topic_assigned_to = cls.topic.assignee
if cls.topic.dueDate:
cls.props.topic_due_date = cls.topic.dueDate.strftime("%a %Y-%m-%d %H:%S")
else:
cls.props.topic_due_date = ""
cls.props.topic_description = cls.topic.description
@classmethod
def load_topic_labels(cls):
while len(cls.props.topic_labels) > 0:
cls.props.topic_labels.remove(0)
for label in cls.topic.labels:
new = cls.props.topic_labels.add()
new.name = label.value
@classmethod
def load_topic_files(cls):
import bcfplugin
while len(cls.props.topic_files) > 0:
cls.props.topic_files.remove(0)
files = bcfplugin.getRelevantIfcFiles(cls.topic)
for f in files:
new = cls.props.topic_files.add()
new.name = f.filename
new.date = f.time.strftime("%a %Y-%m-%d %H:%S")
new.reference = f.reference.uri
new.ifc_project = f.ifcProjectId
new.ifc_spatial = f.ifcSpatialStructureElement
new.is_external = f.external
@classmethod
def load_topic_links(cls):
while len(cls.props.topic_links) > 0:
cls.props.topic_links.remove(0)
for link in cls.topic.referenceLinks:
new = cls.props.topic_links.add()
new.name = link.value
@classmethod
def load_snippet(cls):
cls.props.topic_has_snippet = bool(cls.topic.bimSnippet)
if cls.topic.bimSnippet:
cls.props.topic_snippet_reference = cls.topic.bimSnippet.reference.uri
if cls.topic.bimSnippet.schema.uri:
cls.props.topic_snippet_schema = cls.topic.bimSnippet.schema.uri
cls.props.topic_snippet_type = cls.topic.bimSnippet.type
if cls.topic.bimSnippet.external:
cls.props.topic_snippet_is_external = cls.topic.bimSnippet.external
else:
cls.props.topic_snippet_is_external = False
@classmethod
def load_document_references(cls):
while len(cls.props.topic_document_references) > 0:
cls.props.topic_document_references.remove(0)
for doc in cls.topic.docRefs:
new = cls.props.topic_document_references.add()
new.name = doc.reference.uri
new.description = doc.description
new.guid = str(doc.guid)
new.is_external = doc.external
@classmethod
def load_related_topics(cls):
import bcfplugin
while len(cls.props.topic_related_topics) > 0:
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.guid).title
new.guid = str(t.guid)
@classmethod
def load_viewpoints(cls):
import bcfplugin
bcfviewpoints_enum.clear()
bcf.BcfStore.viewpoints = bcfplugin.getViewpoints(cls.topic, realViewpoint=False)
for i, viewpoint in enumerate(bcf.BcfStore.viewpoints):
bcfviewpoints_enum.append((str(i), "View {}".format(i + 1), ""))
@classmethod
def load_comments(cls):
import bcfplugin
bcf.BcfStore.comments = bcfplugin.getComments(cls.topic)
comments = bpy.data.texts.get("BCF Comments")
if comments:
comments.clear()
else:
comments = bpy.data.texts.new("BCF Comments")
for i, comment in enumerate(bcf.BcfStore.comments):
comments.write("# Comment {} - {}\n".format(i + 1, comment[1].xmlId))
comments.write("# From: {} on {}\n".format(comment[1].author, comment[1].date))
if comment[1].modDate:
comments.write("# Modified by {} on {}\n".format(comment[1].modAuthor, comment[1].modDate))
comments.write(comment[1].comment)
comments.write("\n\n-----\n\n")
def getBcfViewpoints(self, context):
global bcfviewpoints_enum
return bcfviewpoints_enum
bcfviewpoints_enum = None
props = bpy.context.scene.BCFProperties
bcfxml = bcfstore.BcfStore.get_bcfxml()
topic = props.topics[props.active_topic_index]
header = bcfxml.get_header(topic.guid)
getBcfViewpoints(self, context)
class PropertySetTemplate(PropertyGroup):
@@ -1641,33 +1478,10 @@ 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)
name: StringProperty(default="", name="Project Name")
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", 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")
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", 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)
topic_has_snippet: BoolProperty(name="BCF Topic Has Snippet", default=False)
topic_snippet_reference: StringProperty(name="BIM Snippet Reference")
topic_snippet_schema: StringProperty(name="BIM Snippet Schema")
topic_snippet_type: StringProperty(name="BIM Snippet Type")
topic_snippet_is_external: BoolProperty(name="Is BIM Snippet External")
topic_document_references: CollectionProperty(name="BCF Topic Document References", type=BcfTopicDocumentReference)
topic_related_topics: CollectionProperty(name="BCF Topic Related Topics", type=BcfTopicRelatedTopic)
class MapConversion(PropertyGroup):
+83 -83
View File
@@ -1,4 +1,6 @@
import os
import bpy
from . import bcfstore
from bpy.types import Panel
from bpy.props import StringProperty
@@ -1681,97 +1683,95 @@ class BIM_PT_bcf(Panel):
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="")
row = layout.row()
row.prop(props, "viewpoints")
row.operator("bim.activate_bcf_viewpoint", icon="SCENE", text="")
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):
if props.active_topic_index < len(props.topics):
topic = props.topics[props.active_topic_index]
row = layout.row()
row.prop(f, "name", text="File {} Name".format(index + 1))
row.prop(topic, "description", text="")
row = layout.row()
row.prop(f, "reference", text="File {} URI".format(index + 1))
if f.is_external:
row.operator("bim.open_bcf_file_reference", icon="URL", text="").data = index
else:
row.operator("bim.open_bcf_file_reference", icon="FILE_FOLDER", text="").data = "{}/{}".format(
props.topic_guid, index
)
row = layout.row()
row.prop(f, "date", text="File {} Date".format(index + 1))
row = layout.row()
row.prop(f, "ifc_project", text="File {} Project".format(index + 1))
row = layout.row()
row.prop(f, "ifc_spatial", text="File {} Spatial".format(index + 1))
row.prop(topic, "viewpoints")
row.operator("bim.activate_bcf_viewpoint", icon="SCENE", text="")
layout.label(text="Reference Links:")
for index, label in enumerate(props.topic_links):
row = layout.row()
row.prop(label, "name", text="Link {}".format(index + 1))
row.operator("bim.open_bcf_reference_link", icon="URL", text="").index = index
col = layout.column(align=True)
col.prop(topic, "type")
col.prop(topic, "status")
col.prop(topic, "priority")
col.prop(topic, "stage")
col.prop(topic, "assigned_to")
col.prop(topic, "due_date")
layout.label(text="Labels:")
for index, label in enumerate(props.topic_labels):
row = layout.row(align=True)
row.prop(label, "name", text="")
col = layout.column(align=True)
col.enabled = False
col.prop(topic, "creation_date")
col.prop(topic, "creation_author")
col.prop(topic, "modified_date")
col.prop(topic, "modified_author")
layout.label(text="BIM Snippet:")
if props.topic_has_snippet:
row = layout.row(align=True)
row.prop(props, "topic_snippet_type")
if props.topic_snippet_schema:
row.operator("bim.open_bcf_bim_snippet_schema", icon="URL", text="")
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcf_topic = bcfxml.topics[topic.guid]
row = layout.row(align=True)
row.prop(props, "topic_snippet_reference")
if props.topic_snippet_is_external:
row.operator("bim.open_bcf_bim_snippet_reference", icon="URL", text="")
else:
row.operator(
"bim.open_bcf_bim_snippet_reference", icon="FILE_FOLDER", text=""
).topic_guid = props.topic_guid
if bcf_topic.header:
layout.label(text="Header Files:")
for index, f in enumerate(bcf_topic.header.files):
box = self.layout.box()
row = box.row(align=True)
row.label(text=f.filename, icon="FILE_BLANK")
if f.is_external:
row.operator("bim.open_uri", icon="URL", text="").uri = f.reference
else:
op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="")
op.uri = os.path.join(bcfxml.filepath, topic.guid, f.reference)
box.label(text=f.date)
#box.label(text=f.ifc_project)
#box.label(text=f.ifc_spatial_structure_element)
layout.label(text="Document References:")
for index, doc in enumerate(props.topic_document_references):
row = layout.row(align=True)
row.prop(doc, "name", text=f"File {index+1} URI")
if doc.is_external:
row.operator("bim.open_bcf_document_reference", icon="URL", text="").data = "{}/{}".format(
props.topic_guid, index
)
else:
row.operator("bim.open_bcf_document_reference", icon="FILE_FOLDER", text="").data = "{}/{}".format(
props.topic_guid, index
)
row = layout.row(align=True)
row.prop(doc, "description", text=f"File {index+1} Description:")
if topic.reference_links:
layout.label(text="Reference Links:")
for index, link in enumerate(topic.reference_links):
row = layout.row(align=True)
row.prop(link, "name")
row.operator("bim.open_uri", icon="URL", text="").uri = link.name
layout.label(text="Related Topics:")
for topic in props.topic_related_topics:
row = layout.row(align=True)
row.operator("bim.view_bcf_topic", text=topic.name).topic_guid = topic.guid
if topic.labels:
layout.label(text="Labels:")
for index, label in enumerate(topic.labels):
row = layout.row(align=True)
row.prop(label, "name", text="")
if topic.bim_snippet.schema:
layout.label(text="BIM Snippet:")
row = layout.row(align=True)
row.prop(topic.bim_snippet, "type")
if topic.bim_snippet.schema:
row.operator("bim.open_uri", icon="URL", text="").uri = topic.bim_snippet.schema
row = layout.row(align=True)
row.prop(topic.bim_snippet, "reference")
if topic.bim_snippet.is_external:
row.operator("bim.open_uri", icon="URL", text="").uri = topic.bim_snippet.reference
else:
op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="")
op.uri = os.path.join(bcfxml.filepath, topic.guid, topic.bim_snippet.reference)
if topic.document_references:
layout.label(text="Document References:")
for index, doc in enumerate(topic.document_references):
box = self.layout.box()
row = box.row(align=True)
row.prop(doc, "reference")
if doc.is_external:
row.operator("bim.open_uri", icon="URL", text="").uri = doc.reference
else:
op = row.operator("bim.open_uri", icon="FILE_FOLDER", text="")
op.uri = os.path.join(bcfxml.filepath, topic.guid, doc.reference)
row = box.row(align=True)
row.prop(doc, "description")
if topic.related_topics:
layout.label(text="Related Topics:")
for related_topic in topic.related_topics:
row = layout.row(align=True)
row.operator("bim.view_bcf_topic", text=related_topic.name).topic_guid = related_topic.name
class BIM_PT_qa(Panel):