Make BCF project UI (more) foolproof (#1662)

* Various code fixes and optimizations

* Prevent running operators if conditions not met
This commit is contained in:
Gorgious56
2021-08-16 23:52:55 +02:00
committed by GitHub
parent 1b4d0bf577
commit 06b43e7f80
@@ -7,6 +7,7 @@ import numpy as np
import ifcopenshell
import ifcopenshell.util.unit
from . import bcfstore
from blenderbim.bim.module.bcf.prop import getBcfViewpoints
from blenderbim.bim.ifc import IfcStore
from math import radians, degrees, atan, tan, cos, sin
from mathutils import Vector, Matrix, Euler, geometry
@@ -56,13 +57,10 @@ class LoadBcfTopics(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.get_topics()
while len(context.scene.BCFProperties.topics) > 0:
context.scene.BCFProperties.topics.remove(0)
index = 0
for topic_guid in bcfxml.topics.keys():
context.scene.BCFProperties.topics.clear()
for index, topic_guid in enumerate(bcfxml.topics.keys()):
new = context.scene.BCFProperties.topics.add()
bpy.ops.bim.load_bcf_topic(topic_guid = topic_guid, topic_index = index)
index += 1
return {"FINISHED"}
@@ -95,16 +93,17 @@ class LoadBcfTopic(bpy.types.Operator):
for key, value in data_map.items():
if value is not None:
setattr(new, key, str(value))
while len(new.reference_links) > 0:
new.reference_links.remove(0)
new.reference_links.clear()
for reference_link in topic.reference_links:
new2 = new.reference_links.add()
new2.name = reference_link
while len(new.labels) > 0:
new.labels.remove(0)
new_reference_link = new.reference_links.add()
new_reference_link.name = reference_link
new.labels.clear()
for label in topic.labels:
new2 = new.labels.add()
new2.name = label
new_label = new.labels.add()
new_label.name = label
if topic.bim_snippet:
data_map = {
"type": topic.bim_snippet.snippet_type,
@@ -115,10 +114,10 @@ class LoadBcfTopic(bpy.types.Operator):
for key, value in data_map.items():
if value is not None:
setattr(new.bim_snippet, key, value)
while len(new.document_references) > 0:
new.document_references.remove(0)
new.document_references.clear()
for doc in topic.document_references:
new2 = new.document_references.add()
new_document_references = new.document_references.add()
data_map = {
"reference": doc.referenced_document,
"description": doc.description,
@@ -127,12 +126,13 @@ class LoadBcfTopic(bpy.types.Operator):
}
for key, value in data_map.items():
if value is not None:
setattr(new2, key, value)
while len(new.related_topics) > 0:
new.related_topics.remove(0)
setattr(new_document_references, key, value)
new.related_topics.clear()
for related_topic in topic.related_topics:
new2 = new.related_topics.add()
new2.name = related_topic.guid
new_related_topic = new.related_topics.add()
new_related_topic.name = related_topic.guid
bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid)
return {"FINISHED"}
@@ -250,11 +250,13 @@ class AddBcfTopic(bpy.types.Operator):
bl_label = "Add BCF Topic"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.scene.BCFProperties.author
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
bcfxml.add_topic()
new = context.scene.BCFProperties.topics.add()
new.name = "New Topic"
bpy.ops.bim.load_bcf_topics()
return {"FINISHED"}
@@ -264,6 +266,15 @@ class AddBcfBimSnippet(bpy.types.Operator):
bl_label = "Add BCF BIM Snippet"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return all((getattr(props.topics[props.active_topic_index], attr, False) for attr in (
"bim_snippet_reference",
"bim_snippet_schema",
"bim_snippet_type"
)))
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
@@ -283,10 +294,16 @@ class AddBcfRelatedTopic(bpy.types.Operator):
bl_label = "Add BCF Related Topic"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
@classmethod
def poll(cls, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
if not blender_topic.related_topic:
return False
if blender_topic.related_topic == blender_topic.title:
# Prevent adding self as related topic
return False
related_topic = None
for topic in bcfxml.topics.values():
if topic.title == blender_topic.related_topic:
@@ -294,7 +311,18 @@ class AddBcfRelatedTopic(bpy.types.Operator):
related_topic.guid = topic.guid
break
if not related_topic:
return {"FINISHED"}
return False
if str(related_topic.guid) in [t.name for t in blender_topic.related_topics]:
# Prevent adding the same related topic more than once
return False
return True
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
related_topic = bcf.v2.data.RelatedTopic()
related_topic.guid = next((t for t in bcfxml.topics.values() if t.title == blender_topic.related_topic)).guid
topic = bcfxml.topics[blender_topic.name]
topic.related_topics.append(related_topic)
bcfxml.edit_topic(topic)
@@ -307,6 +335,11 @@ class AddBcfHeaderFile(bpy.types.Operator):
bl_label = "Add BCF Header File"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].file_reference
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
@@ -333,7 +366,7 @@ class ViewBcfTopic(bpy.types.Operator):
def execute(self, context):
for index, topic in enumerate(context.scene.BCFProperties.topics):
if topic.guid.lower() == self.topic_guid.lower():
if topic.name.lower() == self.topic_guid.lower():
context.scene.BCFProperties.active_topic_index = index
return {"FINISHED"}
@@ -343,45 +376,49 @@ class AddBcfViewpoint(bpy.types.Operator):
bl_label = "Add BCF Viewpoint"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.scene.camera
def execute(self, context):
if not context.scene.camera:
return {"FINISHED"}
bcfxml = bcfstore.BcfStore.get_bcfxml()
blender_camera = context.scene.camera
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
viewpoint = bcf.v2.data.Viewpoint()
if context.scene.camera.data.type == "ORTHO":
if blender_camera.data.type == "ORTHO":
camera = bcf.v2.data.OrthogonalCamera()
camera.view_to_world_scale = context.scene.camera.data.ortho_scale
camera.view_to_world_scale = blender_camera.data.ortho_scale
viewpoint.orthogonal_camera = camera
elif context.scene.camera.data.type == "PERSP":
elif blender_camera.data.type == "PERSP":
camera = bcf.v2.data.PerspectiveCamera()
camera.field_of_view = degrees(context.scene.camera.data.angle)
camera.field_of_view = degrees(blender_camera.data.angle)
viewpoint.perspective_camera = camera
camera.camera_view_point.x = context.scene.camera.location.x
camera.camera_view_point.y = context.scene.camera.location.y
camera.camera_view_point.z = context.scene.camera.location.z
direction = context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 0.0, -1.0))
camera.camera_view_point.x = blender_camera.location.x
camera.camera_view_point.y = blender_camera.location.y
camera.camera_view_point.z = blender_camera.location.z
direction = blender_camera.matrix_world.to_quaternion() @ Vector((0.0, 0.0, -1.0))
camera.camera_direction.x = direction.x
camera.camera_direction.y = direction.y
camera.camera_direction.z = direction.z
up = context.scene.camera.matrix_world.to_quaternion() @ Vector((0.0, 1.0, 0.0))
up = blender_camera.matrix_world.to_quaternion() @ Vector((0.0, 1.0, 0.0))
camera.camera_up_vector.x = up.x
camera.camera_up_vector.y = up.y
camera.camera_up_vector.z = up.z
old_file_format = context.scene.render.image_settings.file_format
context.scene.render.image_settings.file_format = "PNG"
old_filepath = context.scene.render.filepath
context.scene.render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png")
blender_render = context.scene.render
old_file_format = blender_render.image_settings.file_format
blender_render.image_settings.file_format = "PNG"
old_filepath = blender_render.filepath
blender_render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png")
bpy.ops.render.opengl(write_still=True)
viewpoint.snapshot = context.scene.render.filepath
viewpoint.snapshot = blender_render.filepath
bcfxml.add_viewpoint(topic, viewpoint)
context.scene.render.filepath = old_filepath
context.scene.render.image_settings.file_format = old_file_format
blender_render.filepath = old_filepath
blender_render.image_settings.file_format = old_file_format
props.active_topic_index = props.active_topic_index # refreshes the BCF Topic
return {"FINISHED"}
@@ -391,6 +428,10 @@ class RemoveBcfViewpoint(bpy.types.Operator):
bl_label = "Remove BCF Viewpoint"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return getBcfViewpoints(None, context)
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
@@ -423,13 +464,16 @@ class AddBcfReferenceLink(bpy.types.Operator):
bl_label = "Add BCF Reference Link"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].reference_link
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
if not blender_topic.reference_link:
return {"FINISHED"}
topic.reference_links.append(blender_topic.reference_link)
bcfxml.edit_topic(topic)
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
@@ -442,13 +486,16 @@ class AddBcfDocumentReference(bpy.types.Operator):
bl_label = "Add BCF Document Reference"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].document_reference
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
if not blender_topic.document_reference:
return {"FINISHED"}
document_reference = bcf.v2.data.DocumentReference()
document_reference.referenced_document = blender_topic.document_reference
document_reference.description = blender_topic.document_reference_description or None
@@ -464,13 +511,16 @@ class AddBcfLabel(bpy.types.Operator):
bl_label = "Add BCF Label"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
return props.topics[props.active_topic_index].label
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
if not blender_topic.label:
return {"FINISHED"}
new = blender_topic.labels.add()
new.name = blender_topic.label
topic.labels.append(blender_topic.label)
@@ -508,6 +558,8 @@ class EditBcfLabels(bpy.types.Operator):
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
for index, label in enumerate(blender_topic.labels):
if index >= len(topic.labels):
break
if label.name == topic.labels[index]:
continue
topic.labels[index] = blender_topic.labels[index].name
@@ -640,16 +692,24 @@ class AddBcfComment(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"}
comment_guid: bpy.props.StringProperty()
@classmethod
def poll(cls, context):
props = context.scene.BCFProperties
topic = props.topics[props.active_topic_index]
if not topic.comment:
return False
if topic.has_related_viewpoint and not getBcfViewpoints(None, context):
return False
return True
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
if not blender_topic.comment:
return {"FINISHED"}
comment = bcf.v2.data.Comment()
comment.comment = blender_topic.comment
if blender_topic.has_related_viewpoint and blender_topic.viewpoints:
if blender_topic.has_related_viewpoint:
comment.viewpoint = bcf.v2.data.Viewpoint()
comment.viewpoint.guid = blender_topic.viewpoints
bcfxml.add_comment(topic, comment)
@@ -662,14 +722,20 @@ class ActivateBcfViewpoint(bpy.types.Operator):
bl_label = "Activate BCF Viewpoint"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
return topic.viewpoints
def execute(self, context):
self.file = IfcStore.get_file()
bcfxml = bcfstore.BcfStore.get_bcfxml()
props = context.scene.BCFProperties
blender_topic = props.topics[props.active_topic_index]
topic = bcfxml.topics[blender_topic.name]
if not topic.viewpoints:
return {"FINISHED"}
viewpoint_guid = blender_topic.viewpoints
viewpoint = topic.viewpoints[viewpoint_guid]