This commit is contained in:
Andrej730
2025-07-28 11:48:20 +05:00
parent cdeeab4b31
commit 0cb6d9de72
10 changed files with 69 additions and 28 deletions
+2 -2
View File
@@ -366,7 +366,7 @@ BOOST_LOCATION = f"https://github.com/boostorg/boost/releases/download/boost-{BO
# Helper functions # Helper functions
def run_autoconf(arg1, configure_args, cwd): def run_autoconf(arg1: str, configure_args: "list[str]", cwd: str) -> None:
configure_path = os.path.realpath(os.path.join(cwd, "..", "configure")) configure_path = os.path.realpath(os.path.join(cwd, "..", "configure"))
if not os.path.exists(configure_path): if not os.path.exists(configure_path):
run( run(
@@ -392,7 +392,7 @@ def run_autoconf(arg1, configure_args, cwd):
) )
def run_cmake(arg1, cmake_args, cmake_dir=None, cwd=None): def run_cmake(arg1, cmake_args: "list[str]", cmake_dir: Union[str, None] = None, cwd: Union[str, None] = None):
if cmake_dir is None: if cmake_dir is None:
P = ".." P = ".."
else: else:
@@ -75,7 +75,8 @@ class DemonstrateRenameProject(bpy.types.Operator, tool.Ifc.Operator):
# properties. Generally, the inputs to the core function will come from # properties. Generally, the inputs to the core function will come from
# properties (such as an input field) or data from the scene (like the # properties (such as an input field) or data from the scene (like the
# actively selected object). # actively selected object).
core.demonstrate_rename_project(tool.Ifc, tool.Demo, name=bpy.context.scene.BIMDemoProperties.name) props = tool.Demo.get_demo_props()
core.demonstrate_rename_project(tool.Ifc, tool.Demo, name=props.name)
class SendWebUiDemoMessage(bpy.types.Operator): class SendWebUiDemoMessage(bpy.types.Operator):
@@ -89,5 +90,6 @@ class SendWebUiDemoMessage(bpy.types.Operator):
# and calling the operator connect_websocket_server if we aren't connected to a Web UI # and calling the operator connect_websocket_server if we aren't connected to a Web UI
if not context.scene.WebProperties.is_connected: if not context.scene.WebProperties.is_connected:
bpy.ops.bim.connect_websocket_server(page="demo") bpy.ops.bim.connect_websocket_server(page="demo")
core.send_webui_demo_message(tool.Web, message=bpy.context.scene.BIMDemoProperties.webui_message) props = tool.Demo.get_demo_props()
core.send_webui_demo_message(tool.Web, message=props.webui_message)
return {"FINISHED"} return {"FINISHED"}
+10
View File
@@ -30,6 +30,8 @@
# property. Properties are stored in the .blend file, so when your user closes # property. Properties are stored in the .blend file, so when your user closes
# their Blender session, and reopens it, things are how they left it. # their Blender session, and reopens it, things are how they left it.
from typing import TYPE_CHECKING
import bpy import bpy
from bpy.types import PropertyGroup from bpy.types import PropertyGroup
@@ -60,3 +62,11 @@ class BIMDemoProperties(PropertyGroup):
message: StringProperty(name="Message") message: StringProperty(name="Message")
show_hints: BoolProperty(name="Show Hints", default=False) show_hints: BoolProperty(name="Show Hints", default=False)
webui_message: StringProperty(name="Web UI Message", default="Hello, Web UI!") webui_message: StringProperty(name="Web UI Message", default="Hello, Web UI!")
# Type checking block is needed
# as type checker can't understand Blender props types by default.
if TYPE_CHECKING:
name: str
message: str
show_hints: bool
webui_message: str
+3 -2
View File
@@ -27,6 +27,7 @@
# panels, buttons, labels, and input fields are laid out. # panels, buttons, labels, and input fields are laid out.
import bpy import bpy
import bonsai.tool as tool
from bonsai.bim.module.demo.data import DemoData from bonsai.bim.module.demo.data import DemoData
@@ -70,7 +71,7 @@ class BIM_PT_demo(bpy.types.Panel):
# Interface panels often show properties. For convenience, define where # Interface panels often show properties. For convenience, define where
# the properties are stored for the module. # the properties are stored for the module.
self.props = context.scene.BIMDemoProperties self.props = tool.Demo.get_demo_props()
# This defines a new "row" in our layout. When a new row is defined, the # This defines a new "row" in our layout. When a new row is defined, the
# things on that row, like buttons, labels, and input fields, show on a # things on that row, like buttons, labels, and input fields, show on a
@@ -145,7 +146,7 @@ class BIM_PT_webui_demo(bpy.types.Panel):
bl_parent_id = "BIM_PT_demo" bl_parent_id = "BIM_PT_demo"
def draw(self, context): def draw(self, context):
self.props = context.scene.BIMDemoProperties self.props = tool.Demo.get_demo_props()
row = self.layout.row() row = self.layout.row()
# we create an input field for the property webui_message # we create an input field for the property webui_message
@@ -893,7 +893,7 @@ class ProductDecorator:
@classmethod @classmethod
def uninstall(cls): def uninstall(cls):
props = bpy.context.scene.BIMProductPreviewProperties # updated by model/polyline.py props = tool.Model.get_product_preview_props() # updated by model/polyline.py
props.verts.clear() props.verts.clear()
props.edges.clear() props.edges.clear()
props.tris.clear() props.tris.clear()
@@ -912,9 +912,9 @@ class ProductDecorator:
shader.uniform_float("color", color) shader.uniform_float("color", color)
batch.draw(shader) batch.draw(shader)
def get_product_preview_data(self, context): def get_product_preview_data(self, context) -> dict[str, Any]:
props = context.scene.BIMProductPreviewProperties props = tool.Model.get_product_preview_props()
data = {} data: dict[str, Any] = {}
data["verts"] = [(*v.value_3d,) for v in props.verts] data["verts"] = [(*v.value_3d,) for v in props.verts]
data["edges"] = [(int(e.value_2d[0]), int(e.value_2d[1])) for e in props.edges] data["edges"] = [(int(e.value_2d[0]), int(e.value_2d[1])) for e in props.edges]
data["tris"] = [(int(t.value_3d[0]), int(t.value_3d[1]), int(t.value_3d[2])) for t in props.tris] data["tris"] = [(int(t.value_3d[0]), int(t.value_3d[1]), int(t.value_3d[2])) for t in props.tris]
@@ -962,7 +962,7 @@ class PolylineOperator:
data = get_generic_product_preview_data(context, relating_type) data = get_generic_product_preview_data(context, relating_type)
# Update properties so it can be used by the decorator # Update properties so it can be used by the decorator
props = context.scene.BIMProductPreviewProperties props = tool.Model.get_product_preview_props()
props.verts.clear() props.verts.clear()
props.edges.clear() props.edges.clear()
props.tris.clear() props.tris.clear()
+25 -9
View File
@@ -29,16 +29,28 @@
# Blender's property systems, IFC's data structures, the filesystem, geometry # Blender's property systems, IFC's data structures, the filesystem, geometry
# processing, and more. # processing, and more.
from __future__ import annotations
import bpy import bpy
import ifcopenshell
import bonsai.core.tool import bonsai.core.tool
import bonsai.tool as tool import bonsai.tool as tool
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from bonsai.bim.module.demo.prop import BIMDemoProperties
# There is always one class in each tool file, which implements the interface # There is always one class in each tool file, which implements the interface
# defined by `core/tool.py`. # defined by `core/tool.py`.
class Demo(bonsai.core.tool.Demo): class Demo(bonsai.core.tool.Demo):
@classmethod @classmethod
def clear_name_field(cls): def get_demo_props(cls) -> BIMDemoProperties:
assert (scene := bpy.context.scene)
return scene.BIMDemoProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def clear_name_field(cls) -> None:
# In this concrete implementation, we see that "clear name field" # In this concrete implementation, we see that "clear name field"
# actually translates to "set this Blender string property to empty # actually translates to "set this Blender string property to empty
# string". In this case, it's pretty simple - but even simple scenarios # string". In this case, it's pretty simple - but even simple scenarios
@@ -47,20 +59,24 @@ class Demo(bonsai.core.tool.Demo):
# implementations separately from control flow. It also makes it easy to # implementations separately from control flow. It also makes it easy to
# refactor and share functions, where every tool function is captured by # refactor and share functions, where every tool function is captured by
# a function name that describes its intention. # a function name that describes its intention.
bpy.context.scene.BIMDemoProperties.name = "" props = cls.get_demo_props()
props.name = ""
@classmethod @classmethod
def get_project(cls): def get_project(cls) -> ifcopenshell.entity_instance:
return tool.Ifc.get().by_type("IfcProject")[0] return tool.Ifc.get().by_type("IfcProject")[0]
@classmethod @classmethod
def hide_user_hints(cls): def hide_user_hints(cls) -> None:
bpy.context.scene.BIMDemoProperties.show_hints = False props = cls.get_demo_props()
props.show_hints = False
@classmethod @classmethod
def set_message(cls, message): def set_message(cls, message) -> None:
bpy.context.scene.BIMDemoProperties.message = message props = cls.get_demo_props()
props.message = message
@classmethod @classmethod
def show_user_hints(cls): def show_user_hints(cls) -> None:
bpy.context.scene.BIMDemoProperties.show_hints = True props = cls.get_demo_props()
props.show_hints = True
+6
View File
@@ -66,6 +66,7 @@ if TYPE_CHECKING:
BIMRailingProperties, BIMRailingProperties,
BIMExternalParametricGeometryProperties, BIMExternalParametricGeometryProperties,
BIMPolylineProperties, BIMPolylineProperties,
BIMProductPreviewProperties,
) )
@@ -107,6 +108,11 @@ class Model(bonsai.core.tool.Model):
assert (scene := bpy.context.scene) assert (scene := bpy.context.scene)
return scene.BIMPolylineProperties # pyright: ignore[reportAttributeAccessIssue] return scene.BIMPolylineProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod
def get_product_preview_props(cls) -> BIMProductPreviewProperties:
assert (scene := bpy.context.scene)
return scene.BIMProductPreviewProperties # pyright: ignore[reportAttributeAccessIssue]
@classmethod @classmethod
def convert_si_to_unit(cls, value: T) -> T: def convert_si_to_unit(cls, value: T) -> T:
if isinstance(value, (tuple, list)): if isinstance(value, (tuple, list)):
+12 -8
View File
@@ -55,9 +55,10 @@ class TestImplementsTool(NewFile):
# these tests. # these tests.
class TestClearNameField(NewFile): class TestClearNameField(NewFile):
def test_run(self): def test_run(self):
bpy.context.scene.BIMDemoProperties.name = "name" props = tool.Demo.get_demo_props()
props.name = "name"
subject.clear_name_field() subject.clear_name_field()
assert bpy.context.scene.BIMDemoProperties.name == "" assert props.name == ""
class TestGetProject(NewFile): class TestGetProject(NewFile):
@@ -73,22 +74,25 @@ class TestGetProject(NewFile):
class TestHideUserHints(NewFile): class TestHideUserHints(NewFile):
def test_run(self): def test_run(self):
bpy.context.scene.BIMDemoProperties.show_hints = True props = tool.Demo.get_demo_props()
props.show_hints = True
subject.hide_user_hints() subject.hide_user_hints()
assert bpy.context.scene.BIMDemoProperties.show_hints == False assert props.show_hints == False
class TestSetMessage(NewFile): class TestSetMessage(NewFile):
def test_run(self): def test_run(self):
bpy.context.scene.BIMDemoProperties.message = "" props = tool.Demo.get_demo_props()
props.message = ""
subject.set_message("message") subject.set_message("message")
assert bpy.context.scene.BIMDemoProperties.message == "message" assert props.message == "message"
class TestShowUserHints(NewFile): class TestShowUserHints(NewFile):
def test_run(self): def test_run(self):
bpy.context.scene.BIMDemoProperties.show_hints = False props = tool.Demo.get_demo_props()
props.show_hints = False
subject.show_user_hints() subject.show_user_hints()
assert bpy.context.scene.BIMDemoProperties.show_hints == True assert props.show_hints == True
""" """
+2
View File
@@ -21,6 +21,7 @@ import os
import csv import csv
import numpy as np import numpy as np
import ifcopenshell import ifcopenshell
import ifcopenshell.api.pset
import ifcopenshell.api.root import ifcopenshell.api.root
import ifcopenshell.api.unit import ifcopenshell.api.unit
import ifcopenshell.api.style import ifcopenshell.api.style
@@ -30,6 +31,7 @@ import ifcopenshell.api.project
import ifcopenshell.api.spatial import ifcopenshell.api.spatial
import ifcopenshell.api.geometry import ifcopenshell.api.geometry
import ifcopenshell.api.aggregate import ifcopenshell.api.aggregate
import ifcopenshell.util.shape_builder
from itertools import cycle from itertools import cycle
from ifcopenshell.util.shape_builder import V from ifcopenshell.util.shape_builder import V