bonsai bcf v3 - support working with viewpoints #2790

Also fixed a bug when removing viewpoint always removed the last viewpoint
This commit is contained in:
Andrej730
2024-08-20 18:18:37 +05:00
parent 8eae997053
commit 64b96633c2
4 changed files with 148 additions and 48 deletions
+3
View File
@@ -3,5 +3,8 @@ import bcf.v3.model
from typing import Union
BimSnippet = Union[bcf.v2.model.BimSnippet, bcf.v3.model.BimSnippet]
BitMap = Union[bcf.v2.model.VisualizationInfoBitmap, bcf.v3.model.Bitmap]
DocumentReference = Union[bcf.v2.model.TopicDocumentReference, bcf.v3.model.DocumentReference]
HeaderFile = Union[bcf.v2.model.HeaderFile, bcf.v3.model.File]
Topic = Union[bcf.v2.model.Topic, bcf.v3.model.Topic]
ViewPoint = Union[bcf.v2.model.ViewPoint, bcf.v3.model.ViewPoint]
+10 -2
View File
@@ -15,7 +15,7 @@ TopicHandler = Union[bcf.v2.topic.TopicHandler, bcf.v3.topic.TopicHandler]
def extract_file(
topic: TopicHandler,
entity: Union[mdl.HeaderFile, mdl.BimSnippet, mdl.DocumentReference],
entity: Union[mdl.HeaderFile, mdl.BimSnippet, mdl.DocumentReference, mdl.BitMap],
bcfxml: Optional[Union[bcf.v2.bcfxml.BcfXml, bcf.v3.bcfxml.BcfXml]] = None,
outfile: Optional[Path] = None,
) -> Union[Path, str, None]:
@@ -47,7 +47,8 @@ def extract_file(
return None
# For v3 document references external documents are detected by empty document_guid.
if not isinstance(entity, bcf.v3.model.DocumentReference) and entity.is_external:
# External bitmaps are not supported by bcf.
if not isinstance(entity, (bcf.v3.model.DocumentReference, mdl.BitMap)) and entity.is_external:
return reference
if isinstance(entity, bcf.v3.model.DocumentReference):
@@ -72,6 +73,13 @@ def extract_file(
assert isinstance(bytes_data, bytes)
elif isinstance(entity, mdl.HeaderFile):
bytes_data = topic.reference_files[reference]
elif isinstance(entity, mdl.BitMap):
bytes_data = next(
byte_data
for vp in topic.viewpoints.values()
for data_reference, byte_data in vp.bitmaps.items()
if data_reference == reference
)
elif isinstance(entity, bcf.v2.model.TopicDocumentReference):
assert isinstance(topic, bcf.v2.topic.TopicHandler)
bytes_data = topic.document_references[reference]
+102 -46
View File
@@ -22,6 +22,7 @@ import bcf.v3.bcfxml
import bcf.v3.document
import bcf.v3.model
import bcf.v3.topic
import bcf.v3.visinfo
import bpy
import bcf
import bcf.bcfxml
@@ -29,8 +30,8 @@ import bcf.v2.bcfxml
import bcf.v2.model
import bcf.v2.topic
import bcf.v2.visinfo
import bcf.agnostic.visinfo
import bcf.agnostic.topic
import bcf.agnostic.visinfo
import uuid
import numpy as np
import tempfile
@@ -532,13 +533,11 @@ class AddBcfViewpoint(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
if not (version := (bcfxml.version.version_id or "")).startswith("2"):
self.report({"INFO"}, f"BCF {version} is not yet supported: {self.bl_rna.bl_idname}.")
return {"FINISHED"}
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
blender_camera = context.scene.camera
assert blender_camera
props = context.scene.BCFProperties
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
@@ -546,32 +545,66 @@ class AddBcfViewpoint(bpy.types.Operator):
direction = blender_camera.matrix_world.to_quaternion() @ Vector((0.0, 0.0, -1.0))
up = blender_camera.matrix_world.to_quaternion() @ Vector((0.0, 1.0, 0.0))
camera_view_point = bcf.v2.model.Point(
x=blender_camera.location.x, y=blender_camera.location.y, z=blender_camera.location.z
)
camera_direction = bcf.v2.model.Direction(x=direction.x, y=direction.y, z=direction.z)
camera_up_vector = bcf.v2.model.Direction(x=up.x, y=up.y, z=up.z)
if blender_camera.data.type == "ORTHO":
camera = bcf.v2.model.OrthogonalCamera(
view_to_world_scale=blender_camera.data.ortho_scale,
camera_view_point=camera_view_point,
camera_direction=camera_direction,
camera_up_vector=camera_up_vector,
blender_render = context.scene.render
assert isinstance(blender_camera.data, bpy.types.Camera)
visinfo_guid = str(uuid.uuid4())
if bcf_v2:
camera_view_point = bcf.v2.model.Point(
x=blender_camera.location.x, y=blender_camera.location.y, z=blender_camera.location.z
)
visualization_info = bcf.v2.model.VisualizationInfo(orthogonal_camera=camera)
elif blender_camera.data.type == "PERSP":
camera = bcf.v2.model.PerspectiveCamera(
field_of_view=degrees(blender_camera.data.angle),
camera_view_point=camera_view_point,
camera_direction=camera_direction,
camera_up_vector=camera_up_vector,
camera_direction = bcf.v2.model.Direction(x=direction.x, y=direction.y, z=direction.z)
camera_up_vector = bcf.v2.model.Direction(x=up.x, y=up.y, z=up.z)
if blender_camera.data.type == "ORTHO":
camera = bcf.v2.model.OrthogonalCamera(
view_to_world_scale=blender_camera.data.ortho_scale,
camera_view_point=camera_view_point,
camera_direction=camera_direction,
camera_up_vector=camera_up_vector,
)
visualization_info = bcf.v2.model.VisualizationInfo(guid=visinfo_guid, orthogonal_camera=camera)
elif blender_camera.data.type == "PERSP":
camera = bcf.v2.model.PerspectiveCamera(
field_of_view=degrees(blender_camera.data.angle),
camera_view_point=camera_view_point,
camera_direction=camera_direction,
camera_up_vector=camera_up_vector,
)
visualization_info = bcf.v2.model.VisualizationInfo(guid=visinfo_guid, perspective_camera=camera)
else:
self.report({"INFO"}, f"Unsupported camera type: '{blender_camera.data.type}'.")
return {"FINISHED"}
else:
camera_view_point = bcf.v3.model.Point(
x=blender_camera.location.x, y=blender_camera.location.y, z=blender_camera.location.z
)
visualization_info = bcf.v2.model.VisualizationInfo(guid=str(uuid.uuid4()), perspective_camera=camera)
camera_direction = bcf.v3.model.Direction(x=direction.x, y=direction.y, z=direction.z)
camera_up_vector = bcf.v3.model.Direction(x=up.x, y=up.y, z=up.z)
cam_aspect = blender_render.resolution_x / blender_render.resolution_y
if blender_camera.data.type == "ORTHO":
camera = bcf.v3.model.OrthogonalCamera(
view_to_world_scale=blender_camera.data.ortho_scale,
camera_view_point=camera_view_point,
camera_direction=camera_direction,
camera_up_vector=camera_up_vector,
aspect_ratio=cam_aspect,
)
visualization_info = bcf.v3.model.VisualizationInfo(guid=visinfo_guid, orthogonal_camera=camera)
elif blender_camera.data.type == "PERSP":
camera = bcf.v3.model.PerspectiveCamera(
field_of_view=degrees(blender_camera.data.angle),
camera_view_point=camera_view_point,
camera_direction=camera_direction,
camera_up_vector=camera_up_vector,
aspect_ratio=cam_aspect,
)
visualization_info = bcf.v3.model.VisualizationInfo(guid=visinfo_guid, perspective_camera=camera)
else:
self.report({"INFO"}, f"Unsupported camera type: '{blender_camera.data.type}'.")
return {"FINISHED"}
# TODO allow the user to enable or disable snapshotting
snapshot = None
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
@@ -581,11 +614,26 @@ class AddBcfViewpoint(bpy.types.Operator):
snapshot = f.read()
# viewpoint.snapshot = blender_render.filepath
vizinfo = bcf.v2.visinfo.VisualizationInfoHandler(visualization_info=visualization_info, snapshot=snapshot)
topic.viewpoints[vizinfo.guid + ".bcfv"] = vizinfo
topic.markup.viewpoints.append(
bcf.v2.model.ViewPoint(viewpoint=vizinfo.guid + ".bcfv", guid=vizinfo.guid, snapshot=vizinfo.guid + ".png")
)
if isinstance(visualization_info, bcf.v2.model.VisualizationInfo):
vizinfo = bcf.v2.visinfo.VisualizationInfoHandler(visualization_info=visualization_info, snapshot=snapshot)
assert isinstance(topic, bcf.v2.topic.TopicHandler)
topic.viewpoints[vizinfo.guid + ".bcfv"] = vizinfo
viewpoints = tool.Bcf.get_topic_viewpoints(topic)
viewpoint = bcf.v2.model.ViewPoint(
viewpoint=vizinfo.guid + ".bcfv", guid=vizinfo.guid, snapshot=vizinfo.guid + ".png"
)
assert tool.Bcf.is_list_of(viewpoints, bcf.v2.model.ViewPoint)
viewpoints.append(viewpoint)
else:
vizinfo = bcf.v3.visinfo.VisualizationInfoHandler(visualization_info=visualization_info, snapshot=snapshot)
assert isinstance(topic, bcf.v3.topic.TopicHandler)
topic.viewpoints[vizinfo.guid + ".bcfv"] = vizinfo
viewpoints = tool.Bcf.get_topic_viewpoints(topic)
viewpoint = bcf.v3.model.ViewPoint(
viewpoint=vizinfo.guid + ".bcfv", guid=vizinfo.guid, snapshot=vizinfo.guid + ".png"
)
assert tool.Bcf.is_list_of(viewpoints, bcf.v3.model.ViewPoint)
viewpoints.append(viewpoint)
def get_ifc_elements(objs: list[bpy.types.Object]) -> list[ifcopenshell.entity_instance]:
elements = []
@@ -615,27 +663,35 @@ class RemoveBcfViewpoint(bpy.types.Operator):
@classmethod
def poll(cls, context):
return bcf_prop.getBcfViewpoints(None, context)
bcfxml = bcfstore.BcfStore.get_bcfxml()
if not bcfxml:
return False
props = context.scene.BCFProperties
topic = props.active_topic
if not topic:
return False
topic = props.topics[topic.name]
if not tool.Blender.get_enum_safe(topic, "viewpoints"):
cls.poll_message_set("No viewpoint selected.")
return False
return True
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
if not (version := (bcfxml.version.version_id or "")).startswith("2"):
self.report({"INFO"}, f"BCF {version} is not yet supported: {self.bl_rna.bl_idname}.")
return {"FINISHED"}
props = context.scene.BCFProperties
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
for key, viewpoint in topic.viewpoints.items():
if viewpoint.guid == blender_topic.viewpoints:
break
del topic.viewpoints[key]
for i, viewpoint in enumerate(topic.markup.viewpoints):
if viewpoint.guid == blender_topic.viewpoints:
break
del topic.markup.viewpoints[i]
del topic.viewpoints[blender_topic.viewpoints]
viewpoints = tool.Bcf.get_topic_viewpoints(topic)
# Only guid is required attribute for a viewpoint.
vp_index = next(i for i, vp in enumerate(viewpoints) if vp.guid in blender_topic.viewpoints)
del viewpoints[vp_index]
tool.Bcf.set_topic_viewpoints(topic, viewpoints)
props.refresh_topic(context)
return {"FINISHED"}
@@ -716,8 +772,8 @@ class AddBcfDocumentReference(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
bcf_v2 = (bcfxml.version.version_id or "").startswith("2")
props = context.scene.BCFProperties
blender_topic = props.active_topic
topic = bcfxml.topics[blender_topic.name]
@@ -1102,6 +1158,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
if blender_topic is None:
return False
bcfxml = bcfstore.BcfStore.get_bcfxml()
assert bcfxml
topic = bcfxml.topics[blender_topic.name]
return topic.viewpoints
@@ -1386,9 +1443,8 @@ class ActivateBcfViewpoint(bpy.types.Operator):
obj = bpy.data.objects.new("Bitmap", None)
obj.empty_display_type = "IMAGE"
# image = bpy.data.images.load(os.path.join(bcfxml.filepath, topic.guid, bitmap.reference))
# TODO: suuport bcf v3.
with tempfile.NamedTemporaryFile(delete=False) as f:
topic.extract_file(bitmap, f.name)
bcf.agnostic.topic.extract_file(topic, bitmap, outfile=Path(f.name))
# f.write(bitmap.what)
image = bpy.data.images.load(f.name)
src_width = image.size[0]
+33
View File
@@ -219,6 +219,39 @@ class Bcf(bonsai.core.tool.Bcf):
topic_.related_topics = (topic_related_topics := bcf.v3.model.TopicRelatedTopics())
topic_related_topics.related_topic = related_topics
@classmethod
def get_topic_viewpoints(
cls, topic: bcf.agnostic.topic.TopicHandler
) -> Union[list[bcf.v2.model.ViewPoint], list[bcf.v3.model.ViewPoint]]:
if isinstance(topic, bcf.v2.topic.TopicHandler):
assert topic.markup
viewpoints = topic.markup.viewpoints
else:
topic_viewpoints = topic.topic.viewpoints
if not topic_viewpoints:
return []
viewpoints = topic_viewpoints.view_point
return viewpoints
@classmethod
def set_topic_viewpoints(
cls,
topic: bcf.agnostic.topic.TopicHandler,
viewpoints: Union[list[bcf.v2.model.ViewPoint], list[bcf.v3.model.ViewPoint]],
) -> None:
if isinstance(topic, bcf.v2.topic.TopicHandler):
assert topic.markup
assert cls.is_list_of(viewpoints, bcf.v2.model.ViewPoint)
topic.markup.viewpoints = viewpoints
else:
topic_viewpoints = topic.topic.viewpoints
if not topic_viewpoints:
if not viewpoints:
return
topic.topic.viewpoints = (topic_viewpoints := bcf.v3.model.TopicViewpoints())
assert cls.is_list_of(viewpoints, bcf.v3.model.ViewPoint)
topic_viewpoints.view_point = viewpoints
## visinfo
@classmethod
def get_viewpoint_bitmaps(