Merge remote-tracking branch 'origin/v0.8.0' into datamodel-v1.0

This commit is contained in:
Thomas Krijnen
2026-04-18 20:15:28 +02:00
1655 changed files with 105534 additions and 46934 deletions
+22
View File
@@ -0,0 +1,22 @@
# Build Bonsai .zip.
# Usage:
# # While in `bonsai` folder.
# docker build -t bonsai-dist .
# # Output zip file will be in `dist` folder.
# # See possible values for variables in `Makefile`'s `dist` target description.
# docker run --rm -v "$PWD/../../:/work" -w /work -e PLATFORM=win -e PYVERSION=py313 bonsai-dist
FROM ubuntu:24.04
RUN apt-get update
RUN apt-get install -y make git wget unzip zip
# Python
RUN apt-get install -y software-properties-common
RUN add-apt-repository ppa:deadsnakes/ppa
RUN apt-get update
RUN apt-get install -y python3.11 python3.11-venv
RUN apt-get install -y npm
WORKDIR /work
CMD cd src/bonsai && make dist PLATFORM=$PLATFORM PYVERSION=$PYVERSION
+50 -48
View File
@@ -48,18 +48,35 @@ VERSION_PATCH:=$(shell cat '../../VERSION' | cut -d '.' -f 3)
VERSION_DATE:=$(shell date '+%y%m%d')
LAST_COMMIT_HASH:=$(shell git rev-parse HEAD)
LAST_COMMIT_DATE:=$(shell git show -s --format=%cI)
PYVERSION:=py310
LAST_GIT_BRANCH:=$(shell git rev-parse --abbrev-ref HEAD)
PYPI_IMP:=cp
ifeq ($(PYVERSION), py311)
PYLIBDIR:=python3.11
PYNUMBER:=311
PYPI_VERSION:=3.11
ifdef PYVERSION
SUPPORTED_PYVERSIONS := py311 py312 py313
ifeq ($(filter $(PYVERSION),$(SUPPORTED_PYVERSIONS)),)
$(error Unsupported PYVERSION=$(PYVERSION). Must be one of $(SUPPORTED_PYVERSIONS))
endif
PYMINOR:=$(subst py3,,$(PYVERSION))
PYLIBDIR:=python3.$(PYMINOR)
PYNUMBER:=3$(PYMINOR)
PYPI_VERSION:=3.$(PYMINOR)
endif # def PYVERSION
IFCMERGE_VERSION:=2026-04-07
ifdef PLATFORM
SUPPORTED_PLATFORMS := linux macos macosm1 win
ifeq ($(filter $(PLATFORM),$(SUPPORTED_PLATFORMS)),)
$(error Unsupported PLATFORM=$(PLATFORM). Must be one of $(SUPPORTED_PLATFORMS))
endif
ifeq ($(PLATFORM),macos)
ifeq ($(PYVERSION),py313)
$(error Blender 5.1 with Python 3.13 doesn't support intel macOS.)
endif
ifeq ($(PYVERSION), py312)
PYLIBDIR:=python3.12
PYNUMBER:=312
PYPI_VERSION:=3.12
endif
ifeq ($(PLATFORM), linux)
@@ -86,8 +103,10 @@ PYPI_PLATFORM:=--platform win_amd64
BLENDER_PLATFORM:=windows-x64
endif
endif # def PLATFORM
# Current build commit hash.
OLD:=e8eb5e4
OLD:=1c5b825
.PHONY: bump
bump:
ifndef NEW
@@ -99,7 +118,10 @@ endif
.PHONY: dist
dist:
ifndef PLATFORM
$(error PLATFORM is not set)
$(error PLATFORM is not set. Example values: $(SUPPORTED_PLATFORMS).)
endif
ifndef PYVERSION
$(error PYVERSION is not set. Example values: $(SUPPORTED_PYVERSIONS). )
endif
rm -rf build
mkdir -p build
@@ -125,9 +147,6 @@ endif
cd ../ifc5d && make dist && mv dist/*.whl ../bonsai/build/wheels/
cd ../ifccityjson && make dist && mv dist/*.whl ../bonsai/build/wheels/
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download GitPython --dest=./wheels
# Provides audio playback for costing
# This is a REALLY IMPORTANT feature
cd build && . env/$(VENV_ACTIVATE) && $(PIP) wheel git+https://github.com/zdhoward/aud --wheel-dir=./wheels
# IfcOpenShell dependency - support for new typing features
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download typing_extensions --dest=./wheels
# Required by IfcCSV
@@ -189,7 +208,7 @@ endif
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download tzfpy $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
# pyradiance is using different platform versions than defaults in our makefile.
ifeq ($(PLATFORM), linux)
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance --platform manylinux_2_35_x86_64 --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance --platform manylinux_2_28_x86_64 --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
else ifeq ($(PLATFORM), macos)
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance --platform macosx_10_13_x86_64 --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
else
@@ -206,19 +225,8 @@ endif
cd build/bonsai/bim/data/gantt/ && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
# Provides IFCJSON functionality
cd build && wget -O ifc2json.zip https://github.com/IFCJSON-Team/IFC2JSON_python/archive/refs/heads/master.zip
cd build && unzip ifc2json.zip && rm ifc2json.zip
# IFCJSON doesn't have pyproject.toml, so we use python command.
cd build && . env/$(VENV_ACTIVATE) && cd IFC2JSON_python-*/file_converters && \
$(PYTHON) -c "from setuptools import setup; \
setup( \
name='ifcjson', \
version='0.0.1', \
author='Jan Brouwer', \
author_email='jan@brewsky.nl', \
packages=['ifcjson'], \
)" bdist_wheel
cp -r build/IFC2JSON_python-*/file_converters/dist/*.whl build/wheels/
# TODO: Use official repo, once https://github.com/IFCJSON-Team/IFC2JSON_python/pull/8 is merged.
cd build && . env/$(VENV_ACTIVATE) && $(PYTHON) -m pip wheel "git+https://github.com/Andrej730/IFC2JSON_python.git@pyproject_toml" --no-deps -w wheels/
# Brickschema requires pkg_resources which is provided by Blender.
# Provides Brickschema functionality
@@ -226,26 +234,16 @@ endif
cd build/bonsai/bim/data/brick/ && wget https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl
# Required for hipped roof generation
cd build && wget https://github.com/prochitecture/bpypolyskel/archive/refs/heads/master.zip
cd build && unzip master.zip && rm master.zip
cd build && . env/$(VENV_ACTIVATE) && cd bpypolyskel-master && \
$(PYTHON) -c "from setuptools import setup; \
setup( \
name='bpypolyskel', \
version='0.0.0', \
packages=['bpypolyskel'], \
)" bdist_wheel
cp -r build/bpypolyskel-master/dist/*.whl build/wheels/
cd build && . env/$(VENV_ACTIVATE) && $(PYTHON) -m pip wheel "git+https://github.com/prochitecture/bpypolyskel" --no-deps -w wheels/
# folder for executable files
mkdir -p build/bonsai/libs/bin
# required for three-way git merging
ifeq ($(PLATFORM), win)
cd build/bonsai/libs/bin && wget https://github.com/brunopostle/ifcmerge/releases/download/2025-01-26/ifcmerge.zip
cd build/bonsai/libs/bin && unzip ifcmerge.zip && rm ifcmerge.zip
cd build/bonsai/libs/bin && wget https://github.com/brunopostle/ifcmerge/releases/download/$(IFCMERGE_VERSION)/ifcmerge.exe
else
cd build/bonsai/libs/bin && wget https://raw.githubusercontent.com/brunopostle/ifcmerge/main/ifcmerge && chmod +x ifcmerge
cd build/bonsai/libs/bin && wget https://raw.githubusercontent.com/brunopostle/ifcmerge/$(IFCMERGE_VERSION)/ifcmerge && chmod +x ifcmerge
endif
# Generate translations module for Bonsai build
@@ -264,9 +262,15 @@ else
$(SED) "s/0.0.0/$(VERSION)-alpha$(VERSION_DATE)/" build/bonsai/blender_manifest.toml
$(SED) "s/8888888/$(LAST_COMMIT_HASH)/" build/bonsai/__init__.py
$(SED) "s/9999999/$(LAST_COMMIT_DATE)/" build/bonsai/__init__.py
$(SED) "s/7777777/$(LAST_GIT_BRANCH)/" build/bonsai/__init__.py
$(SED) 's/version = "0.0.0"/version = "$(VERSION)-alpha$(VERSION_DATE)"/' build/pyproject.toml
endif
# Blender 5.1+ requires Python 3.13.
ifeq ($(PYVERSION), py313)
$(SED) 's/blender_version_min = "4\.2\.0"/blender_version_min = "5.1.0"/' build/bonsai/blender_manifest.toml
endif
$(SED) "s/os-arch/$(BLENDER_PLATFORM)/" build/bonsai/blender_manifest.toml
# Provides bonsai Add-on functionality
@@ -288,12 +292,6 @@ endif
fi
mv build/wheels/*.whl build/bonsai/wheels/
# Temporary workaround for Blender not handling non-3.11 wheels #5743.
# Use '-n' as on macos x86-64 doesn't have a binary wheel and it autoincludes 'cp311'.
prev_whl_name=$$(find build/bonsai/wheels/tzfpy-*.whl); \
whl_name=$$(echo $$prev_whl_name | sed "s/-cp39-/-cp$(PYNUMBER)-/"); \
mv --update=none "$$prev_whl_name" "$$whl_name";
ifneq ($(PLATFORM), linux)
# Safeguard: in case one of `pip download` will break,
# it will produce a linux wheel for non-linux build (our github action machine is using linux).
@@ -336,7 +334,11 @@ test:
.PHONY: test-core
test-core:
ifndef MODULE
pytest -p no:pytest-blender test/core
else
pytest -p no:pytest-blender test/core/test_${MODULE}.py
endif
.PHONY: test-bim
test-bim:
@@ -351,7 +353,7 @@ test-tool:
ifndef MODULE
pytest test/tool
else
pytest test/tool/test_$(MODULE).py
pytest test/tool/test_$(MODULE).py --maxfail=1
endif
# Reregistering test is not added to the standard test suite because during unregister
+53 -40
View File
@@ -32,20 +32,18 @@ if IN_BLENDER:
# and then as a bonsai-package.
IN_PACKAGE = __package__ == "bonsai"
import re
import platform
import re
import traceback
import webbrowser
import uuid
import shutil
from collections import deque
from pathlib import Path
from typing import Union, Any
from collections.abc import Generator
from pathlib import Path
from typing import TYPE_CHECKING, Any, Union
last_commit_hash = "8888888"
last_commit_date = "9999999"
last_git_branch = "7777777"
def get_last_commit_hash() -> Union[str, None]:
@@ -63,6 +61,15 @@ def get_last_commit_date() -> Union[str, None]:
return last_commit_date
def get_git_branch() -> Union[str, None]:
# Using this weird way to write 7777777,
# so makefile won't accidentally replace it here
# we'll be able to distinguish branch from placeholder value.
if last_git_branch == str(7_777777):
return None
return last_git_branch
# Accessed from bonsai extension:
bbim_semver: dict[str, Any] = {}
@@ -74,6 +81,21 @@ REINSTALLED_BBIM_VERSION: Union[str, None] = None
REGISTERED_BBIM_PACKAGE: str
def is_registering() -> bool:
"""
During addon registration ``bpy.context`` and ``bpy.data`` are restricted
and you can't access their properties.
"""
import bpy
if TYPE_CHECKING or bpy.app.version >= (5, 0, 0):
import _bpy_restrict_state as bpy_restrict_state
else:
import bpy_restrict_state
return isinstance(bpy.context, bpy_restrict_state._RestrictContext)
def initialize_bbim_semver():
"""Initialize `bbim_semver` dictionary.
@@ -95,9 +117,13 @@ def initialize_bbim_semver():
bbim_semver["version"] = version_str
def get_debug_info():
def get_debug_info(*, bonsai_failed_to_load: bool = False) -> dict[str, Any]:
import bpy
bbim_version = bbim_semver["version"]
# All data here should be gettable even in case of `bpy.context` and `bpy.data` being inaccessible
# and Bonsai completely failed to load.
debug_info = {
"os": platform.system(),
"os_version": platform.version(),
@@ -109,10 +135,19 @@ def get_debug_info():
"bonsai_version": bbim_version,
"bonsai_commit_hash": get_last_commit_hash(),
"bonsai_commit_date": get_last_commit_date(),
"bonsai_git_branch": get_git_branch(),
"last_actions": last_actions,
"last_error": last_error,
}
# Can't access blend data or context during registration.
# If Bonsai failed to load we cannot safely access any of its properties or its tools
# as they may not be registered yet and acessing them will break Bonsai Fatal Error UI.
if is_registering() or bonsai_failed_to_load:
return debug_info
import bonsai.tool as tool
# Add .blend file save information
if bpy.data.is_saved:
debug_info["blend_file_path"] = bpy.data.filepath
@@ -133,7 +168,7 @@ def get_debug_info():
return debug_info
def format_debug_info(info: dict):
def format_debug_info(info: dict[str, Any]) -> str:
last_actions = ""
for action in info["last_actions"]:
last_actions += f"\n# {action['type']}: {action['name']}"
@@ -151,33 +186,10 @@ def get_binaries(path: Path) -> Generator[Path, None, None]:
yield from path.glob("**/*.so")
def safe_link_dlls() -> None:
# Blender 4.2+ has a problem on Windows for disabling/enabling/reinstalling extensions
# with loaded binary dependencies (on Windows you can't remove a binary if it's loaded by some program).
# To avoid this issue we temporary hard link dlls to our temp directory on unregister()
# (unregister is executed before Blender will try to uninstall dependencies and the issue will arise).
# Then, Blender won't have a problem unlinking unloaded dlls as they are still linked somewhere.
# On register() we clean up our temp directory with binaries.
#
# TODO: If user uninstalls Bonsai to never use it again, temporary directory won't be cleared.
#
# See: https://projects.blender.org/blender/blender/issues/125049
import bpy
ext_path = Path(bpy.utils.user_resource("EXTENSIONS"))
local_path = ext_path / ".local"
# We use random hash subfolder as user may try to enable/disable addon multiple times.
random_hash = uuid.uuid4().hex[:8]
temp_local = ext_path / ".local_temp" / random_hash
temp_local.mkdir(parents=True)
for filepath in get_binaries(local_path):
dest_path = temp_local / filepath.relative_to(local_path)
dest_path.parent.mkdir(exist_ok=True, parents=True)
os.link(filepath, dest_path)
# TODO: remove before 0.8.6 release.
# On Windows issues with removing extensions were resolved in Blender 4.3,
# but we removed our workaround that was producing some junk only in 0.8.5 release.
# So we're temporarily keeping the part that's cleaning up outputs from previous releases.
def clean_up_dlls_safe_links() -> None:
import bpy
@@ -207,6 +219,8 @@ def clean_up_dlls_safe_links() -> None:
if IN_BLENDER:
import bpy
initialize_bbim_semver()
def get_binary_info() -> dict[str, Any]:
@@ -248,10 +262,12 @@ if IN_BLENDER:
global last_commit_hash
global last_commit_date
global last_git_branch
path = Path(__file__).resolve().parent
repo = git.Repo(str(path), search_parent_directories=True)
last_commit_hash = repo.head.object.hexsha
last_commit_date = repo.head.object.committed_datetime.isoformat()
last_git_branch = repo.active_branch.name
except:
pass
@@ -298,9 +314,6 @@ if IN_BLENDER:
purge_cache()
def unregister():
if platform.system() == "Windows":
safe_link_dlls()
import bonsai.bim
bonsai.bim.unregister()
@@ -335,7 +348,7 @@ if IN_BLENDER:
bl_context = "scene"
def draw(self, context):
info = get_debug_info()
info = get_debug_info(bonsai_failed_to_load=True)
layout = self.layout
layout.alert = True
@@ -411,7 +424,7 @@ if IN_BLENDER:
bl_description = "Copies debugging information to your clipboard for use in bugreports"
def execute(self, context):
info = get_debug_info()
info = get_debug_info(bonsai_failed_to_load=True)
info.update(get_binary_info())
info = format_debug_info(info)
context.window_manager.clipboard = info
+15 -5
View File
@@ -16,14 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import importlib
import os
from collections.abc import Callable
from typing import Union
import bpy
import bpy.utils.previews
import importlib
from bpy_extras.io_utils import ImportHelper, ExportHelper
from . import handler, ui, prop, operator
from typing import Union
from collections.abc import Callable
from bpy_extras.io_utils import ExportHelper, ImportHelper
from . import handler, operator, prop, ui
try:
from bonsai.translations import translations_dict
@@ -120,6 +122,7 @@ classes = [
operator.OpenUri,
operator.ReloadIfcFile,
operator.RevertClippingPlaneCut,
operator.SaveBlendMetadataFile,
operator.SelectDir,
operator.SelectIfcFile,
operator.SelectURIAttribute,
@@ -129,12 +132,16 @@ classes = [
prop.StrProperty,
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
operator.BIM_OT_attribute_search_values,
operator.BIM_OT_manage_tab_visibility,
operator.BIM_OT_reset_ui_layout,
prop.ObjProperty,
prop.MultipleFileSelect,
prop.Attribute,
prop.ISODuration,
prop.BIMAreaProperties,
prop.BIMTabProperties,
prop.BIMTabVisibility, # Must be registered before BIMProperties
prop.BIMPanelVisibility, # Must be registered before BIMProperties
prop.BIMProperties,
prop.IfcParameter,
prop.PsetQto,
@@ -147,6 +154,8 @@ classes = [
prop.BIMSnapGroups,
ui.BIM_UL_clipping_plane,
ui.BIM_UL_generic,
ui.BIM_UL_tab_visibilities,
ui.BIM_UL_panel_visibilities,
ui.DocPreferences,
ui.GizmoPreferencesDoor, # Register before GizmoPreferences
ui.GizmoPreferencesWindow, # Register before GizmoPreferences
@@ -272,6 +281,7 @@ def register():
bpy.types.Curve.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
bpy.types.Camera.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
bpy.types.PointLight.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
if hasattr(bpy.types, "UI_MT_button_context_menu"):
bpy.types.UI_MT_button_context_menu.append(ui.draw_custom_context_menu)
bpy.types.STATUSBAR_HT_header.append(ui.draw_statusbar)
@@ -20,6 +20,8 @@
* { stroke-linecap: round; stroke-linejoin: round; }
text, tspan { /* 2.5mm */ fill: black; stroke: none; font-family: 'OpenGost Type B TT', 'DejaVu Sans Condensed', 'Liberation Sans', 'Arial Narrow', 'Arial'; font-size: 4.13px; }
a text, a tspan { fill: blue !important; text-decoration: underline;}
a:hover { cursor: pointer; }
.cut { fill: black; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; fill-rule: evenodd; }
.projection { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.25; }
.surface { stroke: none; fill: #fff; fill-rule: evenodd; }
@@ -1,6 +1,5 @@
import sys
import os
import sys
bonsai_lib_path = os.environ.get("BONSAI_LIB_PATH")
bonsai_version = os.environ.get("BONSAI_VERSION")
@@ -9,13 +8,14 @@ if bonsai_lib_path:
sys.path.insert(0, bonsai_lib_path)
import argparse
from aiohttp import web
import socketio
import pystache
import json
import base64
import json
import xml.etree.ElementTree as ET
import pystache
import socketio
from aiohttp import web
sio_port = 8080 # default port
sio = socketio.AsyncServer(cors_allowed_origins="*", async_mode="aiohttp", max_http_buffer_size=10000000)
+15 -22
View File
@@ -17,27 +17,23 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import os
import bpy
import json
import datetime
import zipfile
import json
import os
import tempfile
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.unit
import bonsai.tool as tool
import bonsai.core.geometry
import bonsai.core.aggregate
import bonsai.core.spatial
import bonsai.core.style
from bonsai.bim.ifc import IfcStore
from mathutils import Vector
from typing import Union
import zipfile
from logging import Logger
from math import radians
from typing import Union
import bpy
import ifcopenshell
import ifcopenshell.util.element
import ifcopenshell.util.unit
import bonsai.core.geometry
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
class IfcExporter:
@@ -49,7 +45,6 @@ class IfcExporter:
self.set_header()
IfcStore.update_cache()
self.sync_all_objects()
tool.Project.save_linked_models_to_ifc()
extension = self.ifc_export_settings.output_file.split(".")[-1].lower()
if extension == "ifczip":
with tempfile.TemporaryDirectory() as unzipped_path:
@@ -77,9 +72,7 @@ class IfcExporter:
def set_header(self):
self.file.header.file_name.name = os.path.basename(self.ifc_export_settings.output_file)
self.file.header.file_name.time_stamp = (
datetime.datetime.utcnow().replace(tzinfo=datetime.UTC).astimezone().replace(microsecond=0).isoformat()
)
self.file.header.file_name.time_stamp = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
self.file.header.file_name.preprocessor_version = "IfcOpenShell {}".format(ifcopenshell.version)
self.file.header.file_name.originating_system = "{} {}".format(
self.get_application_name(), tool.Blender.get_bonsai_version()
+24 -16
View File
@@ -17,39 +17,47 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import weakref
from collections.abc import Callable
from math import cos
from typing import Union
import bpy
import ifcopenshell.api.owner.settings
import ifcopenshell.util.element
import ifcopenshell.util.representation
import ifcopenshell.util.unit
import ifcopenshell.api.owner.settings
from bpy.app.handlers import persistent
from mathutils import Vector
import bonsai.bim
import bonsai.tool as tool
import weakref
from bpy.app.handlers import persistent
from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.model.data import AuthoringData
from bonsai.bim.module.aggregate.decorator import AggregateDecorator
from bonsai.bim.module.georeference.decorator import GeoreferenceDecorator
from bonsai.bim.module.model.decorator import WallAxisDecorator, SlabDirectionDecorator, BoundingBoxDecorator
from bonsai.bim.module.model.data import AuthoringData
from bonsai.bim.module.model.decorator import (
BoundingBoxDecorator,
SlabDirectionDecorator,
WallAxisDecorator,
)
from bonsai.bim.module.nest.decorator import NestDecorator
from mathutils import Vector
from math import cos
from typing import Union
from collections.abc import Callable
cwd = os.path.dirname(os.path.realpath(__file__))
global_subscription_owner = object()
# Separate owner for per-object msgbus subscriptions (name, active_material_index).
# Using a dedicated owner allows clearing all per-object subscriptions at once
# during undo/redo without affecting other global subscriptions.
object_subscription_owner = object()
def name_callback(obj: Union[bpy.types.Object, bpy.types.Material], data: str) -> None:
try:
obj.name
except:
# The object is invalid but somehow still has a callback. Clear all
# msgbus subscriptions to prevent useless further triggers.
bpy.msgbus.clear_by_owner(obj)
return # In case the object RNA is gone during an undo / redo operation
# The object is invalid but somehow still has a callback.
# This can occur during undo/redo when the Python wrapper is stale.
return
# Blender names are up to 63 UTF-8 bytes
if len(bytes(obj.name, "utf-8")) >= 63:
return
@@ -184,7 +192,7 @@ def subscribe_to(obj: bpy.types.ID, data_path: str, callback: Callable[[bpy.type
return
bpy.msgbus.subscribe_rna(
key=subscribe_to,
owner=obj,
owner=object_subscription_owner,
args=(
obj,
data_path,
@@ -202,8 +210,8 @@ def refresh_ui_data():
Note that calling non-ifc-operators by itself doesn't refresh the UI data
and it need to be refreshed manually if needed.
"""
from bonsai.bim import modules
import bonsai.bim.ui
from bonsai.bim import modules
bonsai.bim.ui.refresh()
+241 -19
View File
@@ -17,24 +17,30 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import importlib
import bpy
import json
from collections.abc import Callable, Iterable, Sequence
from types import EllipsisType
from typing import TYPE_CHECKING, Any, Optional, Union
import bpy
import ifcopenshell
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.attribute
import ifcopenshell.util.element
import ifcopenshell.util.unit
from ifcopenshell.util.doc import get_attribute_doc, get_predefined_type_doc, get_property_doc
from ifcopenshell.util.doc import (
get_attribute_doc,
get_predefined_type_doc,
get_property_doc,
)
import bonsai.tool as tool
from types import EllipsisType
from typing import Optional, Any, Union, TYPE_CHECKING
from collections.abc import Callable, Iterable, Sequence
if TYPE_CHECKING:
import bonsai.bim.prop
from bonsai.bim.prop import Attribute
from bonsai.bim.module.search.prop import BIMFilterGroup
from bonsai.bim.prop import Attribute
# ImportCallback return values:
# - None - property should be imported by default workflow
@@ -428,7 +434,11 @@ def get_enum_items(
else:
annotations_data = data
prop = annotations_data.__annotations__[prop_name]
try:
annotations = annotations_data.__annotations__
except AttributeError:
annotations = type(annotations_data).__annotations__
prop = annotations[prop_name]
items = prop.keywords.get("items")
if items is None:
return
@@ -498,6 +508,8 @@ def draw_filter(
if data.data["saved_searches"]:
row.operator("bim.load_search", text="", icon="IMPORT").module = module
row.operator("bim.save_search", text="", icon="EXPORT").module = module
if data.data["saved_searches"]:
row.operator("bim.remove_search", text="", icon="REMOVE").module = module
if module != "search":
if module == "drawing_include":
row.operator("bim.edit_element_filter", icon="CHECKMARK", text="").filter_mode = "INCLUDE"
@@ -505,62 +517,272 @@ def draw_filter(
row.operator("bim.edit_element_filter", icon="CHECKMARK", text="").filter_mode = "EXCLUDE"
row.operator("bim.enable_editing_element_filter", icon="CANCEL", text="").filter_mode = "NONE"
row = layout.row(align=True)
row.operator("bim.add_filter_group", text="Add Search Group", icon="ADD").module = module
row.operator("bim.edit_filter_query", text="", icon="FILTER").module = module
preferences = tool.Blender.get_addon_preferences()
if not preferences.chain_filter_with_set_operations:
row.operator("bim.add_filter_group", text="Add Search Group", icon="ADD").module = module
else:
row.prop(sprops, "facet", text="")
op = row.operator("bim.add_filter", text="Add Filter", icon="ADD")
op.type = sprops.facet
op.index = 0
op.module = module
op = row.operator("bim.edit_filter_query", text="", icon="FILTER")
if "module" in op.bl_rna.properties:
op.module = module
for i, filter_group in enumerate(filter_groups):
box = layout.box()
row = box.row(align=True)
row.prop(sprops, "facet", text="")
op = row.operator("bim.add_filter", text="Add Filter", icon="ADD")
op.type = sprops.facet
op.index = i
op.module = module
op = row.operator("bim.remove_filter_group", text="", icon="X")
op.index = i
op.module = module
preferences = tool.Blender.get_addon_preferences()
if not preferences.chain_filter_with_set_operations:
row = box.row(align=True)
row.prop(sprops, "facet", text="")
op = row.operator("bim.add_filter", text="Add Filter", icon="ADD")
op.type = sprops.facet
op.index = i
op.module = module
op = row.operator("bim.remove_filter_group", text="", icon="X")
op.index = i
op.module = module
for j, ifc_filter in enumerate(filter_group.filters):
if ifc_filter.type == "entity":
row = box.row(align=True)
preferences = tool.Blender.get_addon_preferences()
show_mode_toggle = preferences.chain_filter_with_set_operations and j > 0
if show_mode_toggle:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="FILE_3D")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "attribute":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "name", text="", icon="COPY_ID")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
op.suggestion_type = "attribute_name"
row.prop(ifc_filter, "value", text="")
if ifc_filter.name:
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
op.suggestion_type = "attribute_value"
elif ifc_filter.type == "type":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="FILE_VOLUME")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "material":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="MATERIAL")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "property":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "pset", text="", icon="PROPERTIES")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
op.suggestion_type = "pset"
row.prop(ifc_filter, "name", text="")
if ifc_filter.pset:
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
op.suggestion_type = "property_name"
row.prop(ifc_filter, "comparison", text="")
row.prop(ifc_filter, "value", text="")
if ifc_filter.pset and ifc_filter.name:
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
op.suggestion_type = "property_value"
elif ifc_filter.type == "classification":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="OUTLINER")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "location":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="PACKAGE")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "group":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="OUTLINER_COLLECTION")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "parent":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="FILE_PARENT")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
elif ifc_filter.type == "query":
row = box.row(align=True)
if tool.Blender.get_addon_preferences().chain_filter_with_set_operations and j > 0:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "name", text="", icon="POINTCLOUD_DATA")
row.prop(ifc_filter, "comparison", text="")
row.prop(ifc_filter, "value", text="")
elif ifc_filter.type == "instance":
row = box.row(align=True)
preferences = tool.Blender.get_addon_preferences()
show_mode_toggle = preferences.chain_filter_with_set_operations and j > 0
if show_mode_toggle:
mode_icons = {"ADD": "ADD", "SUBTRACT": "REMOVE", "FILTER": "FILTER"}
op = row.operator(
"bim.toggle_filter_inclusion",
icon=mode_icons.get(ifc_filter.filter_mode, "ADD"),
text="",
depress=ifc_filter.filter_mode != "ADD",
)
op.group_index = i
op.filter_index = j
op.module = module
row.prop(ifc_filter, "value", text="", icon="GRIP")
op = row.operator("bim.filter_value_suggestions", text="", icon="VIEWZOOM")
op.group_index = i
op.filter_index = j
op.module = module
op.filter_type = ifc_filter.type
op = row.operator("bim.select_filter_elements", text="", icon="EYEDROPPER")
op.group_index = i
op.index = j
+16 -19
View File
@@ -17,26 +17,28 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import os
import bpy
import uuid
import shutil
import hashlib
import zipfile
import os
import shutil
import tempfile
import traceback
import uuid
import zipfile
from collections.abc import Callable
from pathlib import Path
from typing import Literal, NotRequired, Optional, TypedDict, Union
import bpy
import ifcopenshell
import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper
from ifcopenshell.file import UndoSystemError
import bonsai
import bonsai.bim.handler
import bonsai.tool as tool
from ifcopenshell.file import UndoSystemError
from pathlib import Path
from bonsai.tool.brick import BrickStore
from typing import Union, Optional, TypedDict, NotRequired, Literal
from collections.abc import Callable
IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
@@ -314,11 +316,8 @@ class IfcStore:
del IfcStore.id_map[data["id"]]
if "guid" in data:
del IfcStore.guid_map[data["guid"]]
obj = IfcStore.get_object_by_name(data["obj"])
if obj is None:
# obj was just created during this step and didn't existed before.
return
bpy.msgbus.clear_by_owner(obj)
# Note: msgbus subscriptions are cleared globally during
# rebuild_element_maps which runs after every undo/redo.
@staticmethod
def commit_link_element(data: OperationData) -> None:
@@ -365,10 +364,8 @@ class IfcStore:
del IfcStore.id_map[data["id"]]
if "guid" in data:
del IfcStore.guid_map[data["guid"]]
obj = IfcStore.get_object_by_name(data["obj"])
# obj might be removed after unlink.
if not obj:
bpy.msgbus.clear_by_owner(obj)
# Note: msgbus subscriptions are cleared globally during
# rebuild_element_maps which runs after every undo/redo.
@staticmethod
def unlink_element(
+27 -20
View File
@@ -17,33 +17,35 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import time
import json
import ifcpatch
import logging
import traceback
import mathutils
import numpy as np
import numpy.typing as npt
import multiprocessing
import time
import traceback
from collections.abc import Iterable
from typing import Any, Literal, Optional, Union
import bpy
import ifcopenshell
import ifcopenshell.api.pset
import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.unit
import ifcopenshell.util.element
import ifcopenshell.util.geolocation
import ifcopenshell.util.placement
import ifcopenshell.util.representation
import ifcopenshell.util.shape
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
from bonsai.tool.loader import OBJECT_DATA_TYPE
from typing import Union, Optional, Any, Literal
from collections.abc import Iterable
import ifcopenshell.util.unit
import ifcpatch
import mathutils
import numpy as np
import numpy.typing as npt
from ifcopenshell.util.shape import MatrixType
import bonsai.tool as tool
from bonsai.bim.ifc import IFC_CONNECTED_TYPE, IfcStore
from bonsai.tool.loader import OBJECT_DATA_TYPE
class MaterialCreator:
mesh: bpy.types.Mesh
@@ -62,8 +64,8 @@ class MaterialCreator:
mesh: Union[OBJECT_DATA_TYPE, None],
shape_has_openings: bool,
) -> None:
if ((rep := getattr(element, "Representation", ...) is not ...) and not rep) or (
(rep := getattr(element, "RepresentationMaps", ...) is not ...) and not rep
if ((rep := getattr(element, "Representation", ...)) is not ... and not rep) or (
(rep := getattr(element, "RepresentationMaps", ...)) is not ... and not rep
):
return
@@ -82,7 +84,7 @@ class MaterialCreator:
if element.is_a("IfcTypeProduct"):
self.parse_element_type_material_styles(element)
self.parsed_meshes.add(self.mesh.name)
if not self.ifc_import_settings.load_indexed_maps:
if self.ifc_import_settings.load_indexed_maps:
self.load_texture_maps(shape_has_openings)
self.assign_material_slots_to_faces()
tool.Geometry.record_object_materials(obj)
@@ -114,7 +116,6 @@ class MaterialCreator:
for texture in texture_style.Textures or []:
if coords := getattr(texture, "IsMappedBy", None):
coords = coords[0]
# IfcTextureCoordinateGenerator handled in the style shader graph
if coords.is_a("IfcIndexedTextureMap"):
return coords
# TODO: support IfcTextureMap
@@ -132,6 +133,10 @@ class MaterialCreator:
if shape_has_openings and coords.is_a("IfcIndexedTextureMap"):
continue
tool.Loader.load_indexed_map(coords, self.mesh)
elif tool.Style.get_texture_style(material):
# No explicit coordinate mapping (e.g. IFC2X3 has no IsMappedBy,
# and IFC4 COORD uses generated UVs). Bake XY→UV as fallback.
tool.Loader.load_generated_uv_map(self.mesh)
def assign_material_slots_to_faces(self) -> None:
if not self.mesh["ios_materials"]:
@@ -742,6 +747,7 @@ class IfcImporter:
self.update_progress((percent_average / 100 * progress_range) + start_progress)
shape = iterator.get()
if shape:
assert isinstance(shape, W.TriangulationElement)
product = self.file.by_id(shape.id)
self.create_product(product, shape)
results.add(product)
@@ -1015,7 +1021,8 @@ class IfcImporter:
obj.hide_select = True
obj.hide_viewport = True
self.project["blender"].objects.link(obj)
self.project["blender"].BIMCollectionProperties.obj = obj
collection_props = tool.Blender.get_collection_props(self.project["blender"])
collection_props.obj = obj
props = tool.Blender.get_object_bim_props(obj)
props.collection = self.collections[project.GlobalId] = self.project["blender"]
@@ -1261,7 +1268,7 @@ class IfcImportSettings:
self.should_load_geometry = True
self.should_clean_mesh = False
self.should_cache = True
self.deflection_tolerance = 0.001
self.deflection_tolerance = 0.05 # Default is 0.001, but I find this to be more practical
self.angular_tolerance = 0.5
self.void_limit = 30
self.style_limit = 300
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.BIM_OT_add_aggregate,
@@ -16,11 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
import ifcopenshell.util.element
from typing import Union
import bpy
import ifcopenshell.util.element
import bonsai.tool as tool
def refresh():
AggregateData.is_loaded = False
@@ -19,14 +19,13 @@
import blf
import bpy
import gpu
import ifcopenshell
import ifcopenshell.util.element
import bonsai.tool as tool
from bpy.types import SpaceView3D
from bpy_extras import view3d_utils
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
from bonsai.bim.module.geometry.decorator import ItemDecorator
import bonsai.tool as tool
def transparent_color(color, alpha=0.1):
@@ -16,17 +16,17 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING
import bpy
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.api.group
import ifcopenshell.api.pset
import ifcopenshell.api.root
import ifcopenshell.util.element
import bonsai.tool as tool
import bonsai.core.aggregate as core
import bonsai.core.spatial
from typing import TYPE_CHECKING
import bonsai.tool as tool
class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator):
@@ -222,7 +222,7 @@ class BIM_OT_add_aggregate(bpy.types.Operator, tool.Ifc.Operator):
tool.Collector,
tool.Spatial,
container=current_container,
element_obj=aggregate,
objs=[aggregate],
)
core.assign_object(tool.Ifc, tool.Aggregate, tool.Collector, relating_obj=aggregate, related_obj=obj)
+30 -13
View File
@@ -16,24 +16,22 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING, Union
import bpy
import ifcopenshell.util.element
import bonsai.tool as tool
from bonsai.bim.prop import StrProperty, Attribute
from bonsai.bim.module.spatial.data import SpatialData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
PointerProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.module.aggregate.decorator import (
AggregateDecorator,
AggregateModeDecorator,
)
from bonsai.bim.module.aggregate.decorator import AggregateDecorator, AggregateModeDecorator
from typing import TYPE_CHECKING, Union
def can_aggregate(relating_obj: bpy.types.Object, related_obj: bpy.types.Object) -> bool:
@@ -75,6 +73,22 @@ def poll_related_object(self: "BIMObjectAggregateProperties", related_obj: bpy.t
return True
def update_relating_object(self, context):
if self.relating_object:
ifc_id = tool.Blender.get_object_bim_props(self.relating_object).ifc_definition_id
if ifc_id:
bpy.ops.bim.aggregate_assign_object(relating_object=ifc_id)
bpy.ops.bim.disable_editing_aggregate()
def update_related_object(self, context):
if self.related_object:
ifc_id = tool.Blender.get_object_bim_props(self.related_object).ifc_definition_id
if ifc_id:
bpy.ops.bim.aggregate_assign_object(related_object=ifc_id)
bpy.ops.bim.disable_editing_aggregate()
def update_aggregate_decorator(self, context):
if self.aggregate_decorator:
AggregateDecorator.install(bpy.context)
@@ -91,12 +105,15 @@ def update_aggregate_mode_decorator(self, context):
class BIMObjectAggregateProperties(PropertyGroup):
is_editing: BoolProperty(name="Is Editing")
relating_object: PointerProperty(name="Relating Whole", type=bpy.types.Object, poll=poll_relating_object)
relating_object: PointerProperty(
name="Relating Whole", type=bpy.types.Object, poll=poll_relating_object, update=update_relating_object
)
related_object: PointerProperty(
name="Related Part",
description="Related Part, will be used to derive the Relating Object",
type=bpy.types.Object,
poll=poll_related_object,
update=update_related_object,
)
if TYPE_CHECKING:
+3 -3
View File
@@ -17,10 +17,10 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from bpy.types import Panel
from bonsai.bim.module.aggregate.data import AggregateData
from bonsai.bim.module.group.data import GroupsData, ObjectGroupsData
from bonsai.bim.ifc import IfcStore
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.aggregate.data import AggregateData
class BIM_PT_aggregate(Panel):
@@ -18,26 +18,16 @@
# pyright: reportUnnecessaryTypeIgnoreComment=error
import os
import ifcopenshell.api.alignment
import time
import bpy
import json
import time
import calendar
import isodate
import bonsai.core.sequence as core
import bonsai.tool as tool
import bonsai.bim.module.sequence.helper as helper
import ifcopenshell.api.alignment
import ifcopenshell.api.spatial
import ifcopenshell.geom
import ifcopenshell.util.sequence
import ifcopenshell.util.selector
from datetime import datetime
from dateutil import parser, relativedelta
from bpy_extras.io_utils import ImportHelper
import bonsai.tool as tool
class ImportAlignmentCSV(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
bl_idname = "bim.import_alignment_csv"
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.EnableEditingAttributes,
@@ -18,6 +18,7 @@
import bpy
import ifcopenshell
import bonsai.tool as tool
@@ -16,22 +16,25 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
from typing import TYPE_CHECKING, Any, Literal, Union
import bpy
import ifcopenshell
import ifcopenshell.api.attribute
import ifcopenshell.guid
import ifcopenshell.util.element
import bonsai.bim.helper
import bonsai.tool as tool
import bonsai.core.attribute as core
import bonsai.core.spatial
from typing import TYPE_CHECKING, Any, Union, Literal
import bonsai.tool as tool
if TYPE_CHECKING:
from bonsai.bim.prop import Attribute
import bpy.stub_internal.rna_enums as rna_enums
from bonsai.bim.prop import Attribute
def get_objs_for_operation(
operator_properties: "AttributesOperator", context: bpy.types.Context
@@ -292,13 +295,13 @@ class ExplorerShowUIPopup(bpy.types.Operator):
bl_description = "Show Explorer UI to select element as attribute value or edit it."
bl_options = {"REGISTER", "UNDO"}
ifc_class: bpy.props.StringProperty() # pyright: ignore[reportRedeclaration]
ifc_class: bpy.props.StringProperty()
"""Element IFC class."""
attribute_name: bpy.props.StringProperty() # pyright: ignore[reportRedeclaration]
attribute_name: bpy.props.StringProperty()
"""IFC class attribute name."""
data_path: bpy.props.StringProperty() # pyright: ignore[reportRedeclaration]
data_path: bpy.props.StringProperty()
"""Full data path"""
preselect_ifc_id: bpy.props.IntProperty(options={"SKIP_SAVE"}) # pyright: ignore[reportRedeclaration]
preselect_ifc_id: bpy.props.IntProperty(options={"SKIP_SAVE"})
"""IFC id to preselect in the popup."""
if TYPE_CHECKING:
+19 -21
View File
@@ -16,22 +16,20 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from bonsai.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Union
import bpy
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
IntProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.prop import Attribute
class BIMAttributeProperties(PropertyGroup):
attributes: CollectionProperty(name="Attributes", type=Attribute)
@@ -43,7 +41,7 @@ class BIMAttributeProperties(PropertyGroup):
class ExplorerEntity(PropertyGroup):
ifc_definition_id: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
ifc_definition_id: bpy.props.IntProperty()
if TYPE_CHECKING:
ifc_definition_id: int
@@ -62,7 +60,7 @@ class BIMExplorerProperties(PropertyGroup):
self.property_unset("editing_entity_id")
self.entity_attributes.clear()
is_loaded: BoolProperty( # pyright: ignore[reportRedeclaration]
is_loaded: BoolProperty(
name="Toggle Explorer UI",
update=update_is_loaded,
)
@@ -78,15 +76,15 @@ class BIMExplorerProperties(PropertyGroup):
def update_ifc_class(self, context: object) -> None:
tool.Attribute.refresh_uilist_entities()
ifc_class: EnumProperty( # pyright: ignore[reportRedeclaration]
ifc_class: EnumProperty(
name="IFC Class To Search",
items=get_ifc_class,
update=update_ifc_class,
)
entities: CollectionProperty(type=ExplorerEntity) # pyright: ignore[reportRedeclaration]
active_entity_index: IntProperty() # pyright: ignore[reportRedeclaration]
editing_entity_id: IntProperty() # pyright: ignore[reportRedeclaration]
entity_attributes: CollectionProperty(type=Attribute) # pyright: ignore[reportRedeclaration]
entities: CollectionProperty(type=ExplorerEntity)
active_entity_index: IntProperty()
editing_entity_id: IntProperty()
entity_attributes: CollectionProperty(type=Attribute)
if TYPE_CHECKING:
is_loaded: bool
+7 -4
View File
@@ -17,12 +17,15 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bonsai.bim.helper
from typing import TYPE_CHECKING
import bpy.types
from bpy.types import Panel
from bonsai.bim.module.attribute.data import AttributesData
import bonsai.bim.helper
import bonsai.tool as tool
from typing import TYPE_CHECKING
from bonsai.bim.module.attribute.data import AttributesData
if TYPE_CHECKING:
from bonsai.bim.module.attribute.prop import BIMExplorerProperties, ExplorerEntity
@@ -58,7 +61,7 @@ def draw_ui(context: bpy.types.Context, layout: bpy.types.UILayout, attributes)
class BIM_PT_object_attributes(Panel):
bl_label = "Attributes"
bl_label = "Object Attributes"
bl_idname = "BIM_PT_object_attributes"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
prop.AuginProperties,
@@ -16,14 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import datetime
import os
import bpy
import string
import random
import shutil
import requests
import string
import tempfile
import datetime
import bpy
import requests
import bonsai.tool as tool
+11 -2
View File
@@ -16,8 +16,9 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy.props
import bpy.types
from typing import TYPE_CHECKING
import bpy
class AuginProperties(bpy.types.PropertyGroup):
@@ -27,3 +28,11 @@ class AuginProperties(bpy.types.PropertyGroup):
project_name: bpy.props.StringProperty(name="Project Name")
project_filename: bpy.props.StringProperty(name="IFC Filename")
is_success: bpy.props.BoolProperty(name="Is Successful Upload", default=False)
if TYPE_CHECKING:
username: str
password: str
token: str
project_name: str
project_filename: str
is_success: bool
+1
View File
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy.types
import bonsai.tool as tool
+2 -1
View File
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.ActivateBcfViewpoint,
+5 -5
View File
@@ -17,13 +17,13 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import bcf
import bcf.bcfxml
import bcf.v2.bcfxml
import bonsai.tool as tool
from typing import Union
import bcf.bcfxml
import bpy
import bonsai.tool as tool
class BcfStore:
bcfxml: Union[bcf.bcfxml.BcfXml, None] = None
+20 -23
View File
@@ -16,38 +16,35 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import bcf.v3
import tempfile
import uuid
import webbrowser
from math import atan, degrees, radians, tan
from pathlib import Path
import bcf.agnostic.topic
import bcf.agnostic.visinfo
import bcf.v2.bcfxml
import bcf.v2.model
import bcf.v2.topic
import bcf.v2.visinfo
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
import bcf.v2.bcfxml
import bcf.v2.model
import bcf.v2.topic
import bcf.v2.visinfo
import bcf.agnostic.topic
import bcf.agnostic.visinfo
import uuid
import numpy as np
import tempfile
import webbrowser
import ifcopenshell
import ifcopenshell.util.geolocation
import ifcopenshell.util.unit
import bonsai.tool as tool
import bonsai.bim.module.bcf.prop as bcf_prop
import bonsai.bim.module.bcf.bcfstore as bcfstore
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path
from math import radians, degrees, atan, tan, cos, sin
from mathutils import Vector, Matrix, Euler, geometry
import numpy as np
from bpy_extras.io_utils import ExportHelper, ImportHelper
from mathutils import Matrix, Vector
from xsdata.models.datatype import XmlDateTime
import bonsai.bim.module.bcf.bcfstore as bcfstore
import bonsai.tool as tool
class NewBcfProject(bpy.types.Operator):
bl_idname = "bim.new_bcf_project"
@@ -1256,8 +1253,8 @@ class ActivateBcfViewpoint(bpy.types.Operator):
else:
obj.data.show_background_images = False
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].region_3d.view_perspective = "CAMERA"
assert (space := tool.Blender.get_view3d_space())
space.region_3d.view_perspective = "CAMERA"
if self.file:
self.set_viewpoint_components(viewpoint, context)
+17 -17
View File
@@ -16,24 +16,24 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from . import bcfstore
from bonsai.bim.prop import StrProperty
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from bcf.agnostic.extensions import get_extensions_attributes
from typing import TYPE_CHECKING, Union
import bpy
from bcf.agnostic.extensions import get_extensions_attributes
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
IntProperty,
PointerProperty,
StringProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.prop import StrProperty
from . import bcfstore
bcfviewpoints_enum = None
@@ -230,7 +230,7 @@ class BcfTopic(PropertyGroup):
def get_related_topics(self: "BCFProperties", context: bpy.types.Context) -> list[tuple[str, str, str]]:
global RELATED_TOPICS_ENUM_ITEMS
global RELATED_TOPICS_ENUM_ITEMS # ty: ignore[unresolved-global]
props = self
active_topic = props.active_topic
active_related_topics = active_topic.related_topics.keys()
+9 -6
View File
@@ -17,15 +17,18 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import os
import bpy
import bonsai.tool as tool
from . import bcfstore
from bpy.types import Panel
from typing import TYPE_CHECKING
import bpy
from bpy.types import Panel
import bonsai.tool as tool
from . import bcfstore
if TYPE_CHECKING:
from bonsai.bim.module.bcf.prop import BcfTopic, BCFProperties
from bonsai.bim.module.bcf.prop import BCFProperties, BcfTopic
class BIM_PT_bcf(Panel):
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, operator, prop
from . import operator, prop, ui
classes = (
operator.AddBoundary,
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
@@ -16,13 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import gpu
import bmesh
import bonsai.tool as tool
import gpu
from bpy.types import SpaceView3D
from mathutils import Vector
from gpu_extras.batch import batch_for_shader
import bonsai.tool as tool
class BoundaryDecorator:
installed = None
@@ -16,34 +16,34 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bmesh
import logging
import shapely
import shapely.ops
import mathutils
import numpy as np
import multiprocessing
from math import acos, degrees, inf, pi, radians
from typing import Optional, Union
import bmesh
import bpy
import ifcopenshell.api
import ifcopenshell.api.boundary
import ifcopenshell.api.root
import ifcopenshell.geom
import ifcopenshell.util.unit
import ifcopenshell.util.shape
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.representation
import bonsai.tool as tool
import bonsai.bim.import_ifc as import_ifc
from math import pi, inf, degrees, acos, radians
from mathutils import Vector, Matrix
from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.model.decorator import ProfileDecorator
from bonsai.bim.module.boundary.decorator import BoundaryDecorator
import ifcopenshell.util.shape
import ifcopenshell.util.unit
import mathutils
import shapely
import shapely.ops
from ifcopenshell.util.shape_builder import ShapeBuilder
import bonsai.core
from mathutils import Matrix, Vector
import bonsai.bim.import_ifc as import_ifc
import bonsai.core.geometry
from typing import Union, Optional
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.boundary.decorator import BoundaryDecorator
from bonsai.bim.module.model.decorator import ProfileDecorator
def disable_editing_boundary_geometry(context):
@@ -377,6 +377,8 @@ class EnableEditingBoundary(bpy.types.Operator):
obj = tool.Ifc.get_object(entity)
if entity and obj:
setattr(bprops, blender_property, obj)
bprops.physical_or_virtual = boundary.PhysicalOrVirtualBoundary or "NOTDEFINED"
bprops.internal_or_external = boundary.InternalOrExternalBoundary or "NOTDEFINED"
return {"FINISHED"}
@@ -392,6 +394,8 @@ class DisableEditingBoundary(bpy.types.Operator):
bprops.is_editing = False
for ifc_attribute, blender_property in EDITABLE_ATTRIBUTES.items():
setattr(bprops, blender_property, None)
bprops.physical_or_virtual = "NOTDEFINED"
bprops.internal_or_external = "NOTDEFINED"
return {"FINISHED"}
@@ -411,6 +415,8 @@ class EditBoundaryAttributes(bpy.types.Operator, tool.Ifc.Operator):
obj = getattr(bprops, blender_property, None)
entity = tool.Ifc.get_entity(obj)
attributes[blender_property] = entity
attributes["physical_or_virtual"] = bprops.physical_or_virtual
attributes["internal_or_external"] = bprops.internal_or_external
ifcopenshell.api.boundary.edit_attributes(tool.Ifc.get(), entity=boundary, **attributes)
bpy.ops.bim.disable_editing_boundary()
return {"FINISHED"}
@@ -702,6 +708,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
while True:
tree.add_element(iterator.get_native())
shape = iterator.get()
assert isinstance(shape, W.TriangulationElement)
shapes[shape.id] = {
"verts": ifcopenshell.util.shape.get_vertices(shape.geometry),
"faces": ifcopenshell.util.shape.get_faces(shape.geometry),
+44 -14
View File
@@ -16,22 +16,19 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bpy.types import PropertyGroup
from bonsai.bim.prop import ObjProperty
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
import bonsai.tool as tool
from typing import TYPE_CHECKING, Union
import bpy
from bpy.props import (
BoolProperty,
EnumProperty,
PointerProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.prop import ObjProperty
def space_filter(self: "BIMObjectBoundaryProperties", object: bpy.types.Object) -> bool:
entity = tool.Ifc.get_entity(object)
@@ -54,12 +51,43 @@ def element_filter(self: "BIMObjectBoundaryProperties", object: bpy.types.Object
return False
def get_internal_or_external_items(
self: "BIMObjectBoundaryProperties", context: bpy.types.Context | None
) -> list[tuple[str, str, str]]:
items = [
("INTERNAL", "Internal", ""),
("EXTERNAL", "External", ""),
]
ifc = tool.Ifc.get()
if not ifc or ifc.schema != "IFC2X3":
items += [
("EXTERNAL_EARTH", "External Earth", ""),
("EXTERNAL_WATER", "External Water", ""),
("EXTERNAL_FIRE", "External Fire", ""),
]
items.append(("NOTDEFINED", "Not Defined", ""))
return items
class BIMObjectBoundaryProperties(PropertyGroup):
is_editing: BoolProperty(name="Is Editing")
relating_space: PointerProperty(name="RelatingSpace", type=bpy.types.Object, poll=space_filter)
related_building_element: PointerProperty(name="RelatedBuildingElement", type=bpy.types.Object, poll=element_filter)
parent_boundary: PointerProperty(name="ParentBoundary", type=bpy.types.Object, poll=boundary_filter)
corresponding_boundary: PointerProperty(name="CorrespondingBoundary", type=bpy.types.Object, poll=boundary_filter)
physical_or_virtual: EnumProperty(
name="PhysicalOrVirtualBoundary",
items=[
("PHYSICAL", "Physical", ""),
("VIRTUAL", "Virtual", ""),
("NOTDEFINED", "Not Defined", ""),
],
default="NOTDEFINED",
)
internal_or_external: EnumProperty(
name="InternalOrExternalBoundary",
items=get_internal_or_external_items,
)
if TYPE_CHECKING:
is_editing: bool
@@ -67,6 +95,8 @@ class BIMObjectBoundaryProperties(PropertyGroup):
related_building_element: Union[bpy.types.Object, None]
parent_boundary: Union[bpy.types.Object, None]
corresponding_boundary: Union[bpy.types.Object, None]
physical_or_virtual: str
internal_or_external: str # values depend on schema: IFC2X3 omits EXTERNAL_EARTH/WATER/FIRE
class BIMBoundaryProperties(PropertyGroup):
+13 -2
View File
@@ -16,8 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bpy.types import Panel, UIList
from bpy.types import Panel
import bonsai.tool as tool
from bonsai.bim.module.boundary.data import SpaceBoundariesData
@@ -77,6 +77,10 @@ class BIM_PT_Boundary(Panel):
self.draw_relation_editor(boundary, "RelatedBuildingElement", "related_building_element")
self.draw_relation_editor(boundary, "ParentBoundary", "parent_boundary")
self.draw_relation_editor(boundary, "CorrespondingBoundary", "corresponding_boundary")
row = self.layout.row()
row.prop(self.bprops, "physical_or_virtual")
row = self.layout.row()
row.prop(self.bprops, "internal_or_external")
else:
row = self.layout.row()
row.operator("bim.enable_editing_boundary", icon="GREASEPENCIL", text="Edit")
@@ -84,6 +88,8 @@ class BIM_PT_Boundary(Panel):
self.draw_relation_data(boundary, "RelatedBuildingElement")
self.draw_relation_data(boundary, "ParentBoundary")
self.draw_relation_data(boundary, "CorrespondingBoundary")
self.draw_enum_data(boundary, "PhysicalOrVirtualBoundary")
self.draw_enum_data(boundary, "InternalOrExternalBoundary")
if hasattr(boundary, "InnerBoundaries"):
for i, inner_boundary in enumerate(getattr(boundary, "InnerBoundaries", ())):
row = self.layout.row(align=True)
@@ -110,6 +116,11 @@ class BIM_PT_Boundary(Panel):
else:
row.label(text="")
def draw_enum_data(self, boundary, ifc_attribute: str):
row = self.layout.row(align=True)
row.label(text=ifc_attribute)
row.label(text=getattr(boundary, ifc_attribute, "") or "")
def draw_relation_editor(self, boundary, ifc_attribute: str, blender_property: str):
if hasattr(boundary, ifc_attribute):
row = self.layout.row(align=True)
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddBrick,
+4 -7
View File
@@ -17,11 +17,12 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from bonsai.tool.brick import BrickStore
try:
from rdflib import URIRef, BNode
from rdflib import BNode, URIRef
except:
# See #1860
print("Warning: brickschema not available.")
@@ -62,8 +63,7 @@ class BrickschemaData:
if namespace == "https://brickschema.org/schema/Brick":
return []
results = []
query = BrickStore.graph.query(
"""
query = BrickStore.graph.query("""
PREFIX brick: <https://brickschema.org/schema/Brick#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
@@ -80,10 +80,7 @@ class BrickschemaData:
}
}
GROUP BY ?object
""".replace(
"{uri}", uri
)
)
""".replace("{uri}", uri))
for row in query:
predicate_uri = row.get("predicate")
predicate_name = predicate_uri.toPython().split("#")[-1]
@@ -17,12 +17,13 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import ifcopenshell.api
import bonsai.tool as tool
import bonsai.core.brick as core
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bonsai.bim.handler
from bpy_extras.io_utils import ImportHelper, ExportHelper
import bonsai.core.brick as core
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from bonsai.tool.brick import BrickStore
+13 -14
View File
@@ -16,24 +16,23 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING
import bpy
from bonsai.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData
from bonsai.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
EnumProperty,
IntProperty,
StringProperty,
)
from bpy.types import PropertyGroup
import bonsai.core.brick as core
import bonsai.tool.brick as tool
from bonsai.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData
from bonsai.bim.prop import StrProperty
from bonsai.tool.brick import BrickStore
from typing import TYPE_CHECKING
def update_active_brick_index(self, context):
@@ -47,26 +46,26 @@ def get_libraries(self, context):
def get_namespaces(self, context):
global NAMESPACES_ENUM_ITEMS
global NAMESPACES_ENUM_ITEMS # ty: ignore[unresolved-global]
NAMESPACES_ENUM_ITEMS = [(uri, f"{alias}: {uri}", "") for alias, uri in BrickStore.namespaces]
return NAMESPACES_ENUM_ITEMS
def get_brick_entity_classes(self, context):
global ENTITY_CLASSES_ENUM_ITEMS
global ENTITY_CLASSES_ENUM_ITEMS # ty: ignore[unresolved-global]
entity = self.brick_entity_create_type
ENTITY_CLASSES_ENUM_ITEMS = [(uri, uri.split("#")[-1], "") for uri in BrickStore.entity_classes[entity]]
return ENTITY_CLASSES_ENUM_ITEMS
def get_brick_roots(self, context):
global BRICK_ROOTS_ENUM_ITEMS
global BRICK_ROOTS_ENUM_ITEMS # ty: ignore[unresolved-global]
BRICK_ROOTS_ENUM_ITEMS = [(root, root, "") for root in BrickStore.root_classes]
return BRICK_ROOTS_ENUM_ITEMS
def get_brick_relations(self, context):
global BRICK_RELATIONS_ENUM_ITEMS
global BRICK_RELATIONS_ENUM_ITEMS # ty: ignore[unresolved-global]
BRICK_RELATIONS_ENUM_ITEMS = [(uri, uri.split("#")[-1], "") for uri in BrickStore.relationships]
for relation in BrickschemaData.data["active_relations"]:
if relation["predicate_name"] == "label":
+14 -2
View File
@@ -16,8 +16,18 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bonsai.tool as tool
from __future__ import annotations
from typing import TYPE_CHECKING
import bpy
from bpy.types import Panel, UIList
import bonsai.tool as tool
if TYPE_CHECKING:
from bonsai.bim.module.brick.prop import Brick
from bonsai.bim.helper import prop_with_search
from bonsai.bim.module.brick.data import BrickschemaData, BrickschemaReferencesData
from bonsai.tool.brick import BrickStore
@@ -273,7 +283,9 @@ class BIM_PT_brickschema_viewport(Panel):
class BIM_UL_bricks(UIList):
split_screen = False
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self, context, layout: bpy.types.UILayout, data, item: Brick, icon, active_data, active_propname
) -> None:
if item:
split = layout.split(factor=0.85, align=True)
row = split.row()
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddBSDDProperties,
+1 -5
View File
@@ -16,12 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import ifcopenshell
import ifcopenshell.util.date
import ifcopenshell.util.classification
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
def refresh():
@@ -16,13 +16,14 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import textwrap
from typing import Any
import bpy
import bsdd
import bonsai.tool as tool
import ifcopenshell.api.pset
import ifcopenshell.util.element
import bonsai.tool as tool
from bonsai.core import bsdd as core
from typing import Any
class LoadBSDDDictionaries(bpy.types.Operator):
+12 -13
View File
@@ -16,23 +16,22 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING, Literal, Union
import bpy
import bonsai.tool as tool
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
IntProperty,
StringProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.module.bsdd.data import BSDDData
from bonsai.bim.module.classification.data import ClassificationsData
from bonsai.bim.prop import Attribute, StrProperty
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import Union, TYPE_CHECKING, Literal
from bonsai.bim.prop import Attribute
def get_active_dictionary(self: "BIMBSDDProperties", context: object) -> tool.Blender.BLENDER_ENUM_ITEMS:
+13 -5
View File
@@ -17,14 +17,22 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.tool as tool
from bonsai.bim.module.bsdd.data import BSDDData
from bpy.types import Panel, UIList
from typing import TYPE_CHECKING
import bpy
from bpy.types import Panel, UIList
import bonsai.tool as tool
from bonsai.bim.module.bsdd.data import BSDDData
if TYPE_CHECKING:
from bonsai.bim.module.bsdd.prop import BIMBSDDProperties, BSDDDictionary, BSDDClassification, BSDDProperty
from bonsai.bim.module.bsdd.prop import (
BIMBSDDProperties,
BSDDClassification,
BSDDDictionary,
BSDDProperty,
)
class BIM_PT_bsdd(Panel):
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import operator, prop, workspace
classes = (
+10 -9
View File
@@ -16,17 +16,16 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import math
import bmesh
import mathutils
import bpy_extras
import bonsai.tool as tool
from mathutils import Vector, Matrix
from math import pi, radians, sin, cos, sqrt
import ifcopenshell.util.unit
from typing import Union
from math import pi, sqrt
import bmesh
import bpy
import bpy_extras
import mathutils
from mathutils import Matrix, Vector
import bonsai.tool as tool
messages = {
"SHARED_VERTEX": "Shared Vertex, no intersection possible",
@@ -38,6 +37,7 @@ messages = {
class CadTrimExtend(bpy.types.Operator):
bl_idname = "bim.cad_trim_extend"
bl_label = "CAD Trim / Extend"
bl_description = "Extends/reduces element to 3D cursor"
@classmethod
def poll(cls, context):
@@ -83,6 +83,7 @@ class CadTrimExtend(bpy.types.Operator):
class CadMitre(bpy.types.Operator):
bl_idname = "bim.cad_mitre"
bl_label = "CAD Mitre"
bl_description = "Joins two non-parallel paths at their intersection"
@classmethod
def poll(cls, context):
+3 -3
View File
@@ -16,12 +16,12 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bonsai.bim.module.model.data import AuthoringData
from bpy.types import PropertyGroup
from math import pi
from typing import TYPE_CHECKING
import bpy
from bpy.types import PropertyGroup
class BIMCadProperties(PropertyGroup):
resolution: bpy.props.IntProperty(name="Arc Resolution", min=1, default=1)
+65 -27
View File
@@ -17,14 +17,14 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import bonsai.tool as tool
import bonsai.bim.module.type.prop as type_prop
import ifcopenshell.util.unit
from bpy.types import WorkSpaceTool
from bonsai.bim.module.model.data import AuthoringData, RailingData, RoofData
from functools import partial
import bpy
from bpy.types import WorkSpaceTool
import bonsai.tool as tool
from bonsai.bim.module.model.data import RailingData, RoofData
def load_custom_icons():
global custom_icon_previews, display_mode
@@ -106,23 +106,37 @@ class CadTool(WorkSpaceTool):
)
row = layout.row(align=True)
add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(
row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context
row, "Extend", "S_E", bpy.ops.bim.cad_trim_extend.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Fillet", "S_F", bpy.ops.bim.add_ifcarcindex_fillet.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Join", "S_T", bpy.ops.bim.cad_mitre.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Offset", "S_O", bpy.ops.bim.cad_offset.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Fillet", "S_F", bpy.ops.bim.add_ifcarcindex_fillet.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Rectangle", "S_R", bpy.ops.bim.add_rectangle.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Offset", "S_O", bpy.ops.bim.cad_offset.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Circle", "S_C", bpy.ops.bim.add_ifccircle.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Rectangle", "S_R", bpy.ops.bim.add_rectangle.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "3-Point Arc", "S_V", bpy.ops.bim.set_arc_index.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Circle", "S_C", bpy.ops.bim.add_ifccircle.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Reset Vertex", "S_X", bpy.ops.bim.reset_vertex.__doc__, ui_context)
add_layout_hotkey_operator(
row, "3-Point Arc", "S_V", bpy.ops.bim.set_arc_index.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(
row, "Reset Vertex", "S_X", bpy.ops.bim.reset_vertex.__doc__.split("\n", 1)[1].strip(), ui_context
)
elif (
isinstance(data, tool.Geometry.TYPES_WITH_MESH_PROPERTIES)
@@ -132,15 +146,21 @@ class CadTool(WorkSpaceTool):
layout, "Edit Axis", "bim.edit_extrusion_axis", "bim.disable_editing_extrusion_axis", ui_context
)
row = layout.row(align=True)
add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(
row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context
row, "Extend", "S_E", bpy.ops.bim.cad_trim_extend.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Fillet", "S_F", bpy.ops.bim.cad_fillet.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Join", "S_T", bpy.ops.bim.cad_mitre.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Offset", "S_O", bpy.ops.bim.cad_offset.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Fillet", "S_F", bpy.ops.bim.cad_fillet.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(
row, "Offset", "S_O", bpy.ops.bim.cad_offset.__doc__.split("\n", 1)[1].strip(), ui_context
)
else:
if (
@@ -168,19 +188,37 @@ class CadTool(WorkSpaceTool):
add_layout_hotkey_operator(row, "Set Gable Roof Angle", "S_R", "Set Gable Roof Angle", ui_context)
row = layout.row(align=True)
add_layout_hotkey_operator(row, "Extend", "S_E", "Extends/reduces element to 3D cursor", ui_context)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(
row, "Join", "S_T", "Joins two non-parallel paths at their intersection", ui_context
row, "Extend", "S_E", bpy.ops.bim.cad_trim_extend.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Fillet", "S_F", bpy.ops.bim.add_ifcarcindex_fillet.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Join", "S_T", bpy.ops.bim.cad_mitre.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "Offset", "S_O", bpy.ops.bim.cad_offset.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Fillet", "S_F", bpy.ops.bim.add_ifcarcindex_fillet.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "2-Point Arc", "S_C", bpy.ops.bim.cad_arc_from_2_points.__doc__, ui_context)
add_layout_hotkey_operator(
row, "Offset", "S_O", bpy.ops.bim.cad_offset.__doc__.split("\n", 1)[1].strip(), ui_context
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(row, "3-Point Arc", "S_V", bpy.ops.bim.cad_arc_from_3_points.__doc__, ui_context)
add_layout_hotkey_operator(
row,
"2-Point Arc",
"S_C",
bpy.ops.bim.cad_arc_from_2_points.__doc__.split("\n", 1)[1].strip(),
ui_context,
)
row = row if ui_context == "TOOL_HEADER" else layout.row(align=True)
add_layout_hotkey_operator(
row,
"3-Point Arc",
"S_V",
bpy.ops.bim.cad_arc_from_3_points.__doc__.split("\n", 1)[1].strip(),
ui_context,
)
class CadHotkey(bpy.types.Operator):
@@ -17,13 +17,15 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddClashSet,
operator.AddClashSource,
operator.ExecuteIfcClash,
operator.ExportClashSets,
operator.HideClash,
operator.ImportClashSets,
operator.LoadSmartGroupsForActiveClashSet,
operator.RemoveClashSet,
+1 -2
View File
@@ -16,9 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
import ifcopenshell.util.element
import bonsai.tool as tool
@@ -18,12 +18,12 @@
import blf
import gpu
import bmesh
import bonsai.tool as tool
from bpy.types import SpaceView3D
from mathutils import Vector
from gpu_extras.batch import batch_for_shader
from bpy_extras.view3d_utils import location_3d_to_region_2d
from gpu_extras.batch import batch_for_shader
from mathutils import Vector
import bonsai.tool as tool
class ClashDecorator:
+32 -20
View File
@@ -16,22 +16,21 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import bpy
import json
import tempfile
import bmesh
import logging
import numpy as np
import ifcopenshell
import bonsai.tool as tool
from pathlib import Path
from bpy_extras.io_utils import ExportHelper, ImportHelper
import tempfile
from math import radians
from pathlib import Path
from typing import TYPE_CHECKING
import bpy
import ifcopenshell
from bpy_extras.io_utils import ExportHelper, ImportHelper
from mathutils import Matrix, Vector
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
from bonsai.bim.module.clash.decorator import ClashDecorator
from typing import TYPE_CHECKING
class ExportClashSets(bpy.types.Operator, ExportHelper):
@@ -202,16 +201,10 @@ class ExecuteIfcClash(bpy.types.Operator, ExportHelper):
"ALT+click to run a quick clash without selecting a file to save."
)
filter_glob: bpy.props.StringProperty( # pyright: ignore[reportRedeclaration]
default="*.bcf;*.json", options={"HIDDEN"}
)
format: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
name="Format", items=[(i, i, "") for i in ("bcf", "json")]
)
filepath: bpy.props.StringProperty( # pyright: ignore[reportRedeclaration]
subtype="FILE_PATH", options={"SKIP_SAVE"}
)
quick_clash: bpy.props.BoolProperty( # pyright: ignore[reportRedeclaration]
filter_glob: bpy.props.StringProperty(default="*.bcf;*.json", options={"HIDDEN"})
format: bpy.props.EnumProperty(name="Format", items=[(i, i, "") for i in ("bcf", "json")])
filepath: bpy.props.StringProperty(subtype="FILE_PATH", options={"SKIP_SAVE"})
quick_clash: bpy.props.BoolProperty(
options={"SKIP_SAVE"},
)
@@ -443,6 +436,25 @@ class SelectClash(bpy.types.Operator):
return {"FINISHED"}
class HideClash(bpy.types.Operator):
bl_idname = "bim.hide_clash"
bl_label = "Hide Clash"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Hide the clash decorator"
@classmethod
def poll(cls, context):
if not ClashDecorator.is_installed:
cls.poll_message_set("No clash selected.")
return False
return True
def execute(self, context):
ClashDecorator.uninstall()
tool.Blender.update_all_viewports(context)
return {"FINISHED"}
class SmartClashGroup(bpy.types.Operator):
bl_idname = "bim.smart_clash_group"
bl_label = "Smart Group Clashes"
+15 -14
View File
@@ -16,32 +16,33 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING, Literal, Union
import bpy
import bonsai.tool as tool
from bonsai.bim.prop import StrProperty, Attribute, BIMFilterGroup
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
CollectionProperty,
EnumProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
IntProperty,
StringProperty,
)
from ifcopenshell.geom.main import ClashType, CLASH_TYPE_ITEMS
from bpy.types import PropertyGroup
from ifcopenshell.geom.main import CLASH_TYPE_ITEMS, ClashType
from mathutils import Vector
from typing import TYPE_CHECKING, Literal, Union
import bonsai.tool as tool
from bonsai.bim.prop import BIMFilterGroup, StrProperty
class ClashSource(PropertyGroup):
name: StringProperty( # pyright: ignore[reportRedeclaration]
name: StringProperty(
name="File",
description="Absolute filepath to existing .ifc file to use as a clash source.",
)
filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups") # pyright: ignore[reportRedeclaration]
mode: EnumProperty( # pyright: ignore[reportRedeclaration]
filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups")
mode: EnumProperty(
items=[
("a", "All Elements", "All elements will be used for clashing"),
("i", "Include", "Only the selected elements are included for clashing"),
@@ -61,7 +62,7 @@ class Clash(PropertyGroup):
b_global_id: StringProperty(name="B")
a_name: StringProperty(name="A Name")
b_name: StringProperty(name="B Name")
clash_type: EnumProperty( # pyright: ignore[reportRedeclaration]
clash_type: EnumProperty(
name="Clash Type",
items=tuple((i, i, "") for i in CLASH_TYPE_ITEMS),
)
+15 -6
View File
@@ -17,15 +17,23 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.tool as tool
import bonsai.bim.helper
from bpy.types import Panel
from bonsai.bim.module.clash.data import ClashData
from typing import TYPE_CHECKING, assert_never
import bpy
from bpy.types import Panel
import bonsai.bim.helper
import bonsai.tool as tool
from bonsai.bim.module.clash.data import ClashData
if TYPE_CHECKING:
from bonsai.bim.module.clash.prop import BIMClashProperties, ClashSet, SmartClashGroup, Clash
from bonsai.bim.module.clash.prop import (
BIMClashProperties,
Clash,
ClashSet,
SmartClashGroup,
)
class BIM_PT_ifcclash(Panel):
@@ -165,6 +173,7 @@ class BIM_PT_ifcclash(Panel):
layout.template_list("BIM_UL_clashes", "", props.active_clash_set, "clashes", props, "active_clash_index")
row = layout.row()
row.operator("bim.select_clash")
row.operator("bim.hide_clash", text="", icon="HIDE_ON")
else:
row.label(text="Clashes Are Not Loaded", icon="PIVOT_CURSOR")
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddClassification,
@@ -16,12 +16,14 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import Any, Literal, Union
import bpy
import ifcopenshell
import ifcopenshell.util.date
import ifcopenshell.util.classification
import ifcopenshell.util.date
import bonsai.tool as tool
from typing import Any, Literal, Union
from bonsai.bim.ifc import IfcStore
@@ -104,6 +106,7 @@ class ReferencesData:
if element:
for reference in ifcopenshell.util.classification.get_references(element):
data = reference.get_info()
data["ifcClassificationReference"] = reference
del data["ReferencedSource"]
results.append(data)
return results
@@ -18,14 +18,14 @@
import bpy
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.api.pset
import ifcopenshell.api.classification
import ifcopenshell.api.pset
import ifcopenshell.util.classification
import ifcopenshell.util.element
import bonsai.tool as tool
import bonsai.bim.helper
from bpy_extras.io_utils import ImportHelper
import bonsai.bim.helper
import bonsai.tool as tool
from bonsai.bim.ifc import IfcStore
@@ -257,7 +257,9 @@ class EnableEditingClassificationReference(bpy.types.Operator):
def execute(self, context):
props = tool.Classification.get_classification_reference_props()
props.reference_attributes.clear()
bonsai.bim.helper.import_attributes(tool.Ifc.get().by_id(self.reference), props.reference_attributes)
ifc_reference = tool.Ifc.get().by_id(self.reference)
bonsai.bim.helper.import_attributes(ifc_reference, props.reference_attributes)
props.classification_system_name = ifc_reference.ReferencedSource.Name or ""
props.active_reference_id = self.reference
return {"FINISHED"}
@@ -324,9 +326,13 @@ class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
props = tool.Classification.get_classification_reference_props()
attributes = bonsai.bim.helper.export_attributes(props.reference_attributes)
ifc_file = tool.Ifc.get()
reference_entity = ifc_file.by_id(props.active_reference_id)
referenced_source = reference_entity.ReferencedSource
if props.classification_system_name:
referenced_source.Name = props.classification_system_name
ifcopenshell.api.classification.edit_reference(
ifc_file,
reference=ifc_file.by_id(props.active_reference_id),
reference=reference_entity,
attributes=attributes,
)
bpy.ops.bim.disable_editing_classification_reference()
@@ -16,23 +16,25 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from bonsai.bim.prop import Attribute
from bonsai.bim.module.classification.data import ClassificationsData, ObjectClassificationsData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING
import bpy
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
IntProperty,
StringProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.module.classification.data import (
ClassificationsData,
ObjectClassificationsData,
)
from bonsai.bim.prop import Attribute
def get_available_classifications(
self: "BIMClassificationProperties", context: bpy.types.Context
@@ -95,6 +97,7 @@ class BIMClassificationReferenceProperties(PropertyGroup):
classifications: EnumProperty(items=get_classifications, name="Classifications")
reference_attributes: CollectionProperty(name="Reference Attributes", type=Attribute)
active_reference_id: IntProperty(name="Active Reference Id")
classification_system_name: StringProperty(name="Classification System Name")
if TYPE_CHECKING:
is_adding: bool
@@ -17,22 +17,28 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy
import bonsai.bim.helper
import bonsai.tool as tool
import bonsai.bim.module.classification.prop as classification_prop
from bpy.types import Panel, UIList
from bonsai.bim.module.classification.data import (
ClassificationsData,
ObjectClassificationsData,
MaterialClassificationsData,
CostClassificationsData,
ZoneClassificationsData,
)
from typing import TYPE_CHECKING, Any, Union
import bpy
import ifcopenshell.util.classification
from bpy.types import Panel, UIList
import bonsai.bim.helper
import bonsai.tool as tool
from bonsai.bim.module.classification.data import (
ClassificationsData,
CostClassificationsData,
MaterialClassificationsData,
ObjectClassificationsData,
ZoneClassificationsData,
)
if TYPE_CHECKING:
from bonsai.bim.module.classification.prop import BIMClassificationProperties, ClassificationReference
from bonsai.bim.module.classification.prop import (
BIMClassificationProperties,
ClassificationReference,
)
class BIM_PT_classifications(Panel):
@@ -152,7 +158,15 @@ class ReferenceUI:
row = self.layout.row(align=True)
row.label(text="No References")
for reference in self.data.data["references"]:
def get_classification_name(reference):
classification_entity = ifcopenshell.util.classification.get_classification(
reference["ifcClassificationReference"]
)
return classification_entity.Name if classification_entity else ""
sorted_references = sorted(self.data.data["references"], key=get_classification_name)
for reference in sorted_references:
if self.props.active_reference_id == reference["id"]:
self.draw_editable_ui()
else:
@@ -248,10 +262,20 @@ class ReferenceUI:
row = self.layout.row(align=True)
row.operator("bim.edit_classification_reference", text="Save changes", icon="CHECKMARK")
row.operator("bim.disable_editing_classification_reference", text="", icon="CANCEL")
row = self.layout.row()
row.prop(self.props, "classification_system_name", text="Classification System Name")
bonsai.bim.helper.draw_attributes(self.props.reference_attributes, self.layout)
def draw_reference_ui(self, reference: dict[str, Any]) -> None:
row = self.layout.row(align=True)
classification_entity = ifcopenshell.util.classification.get_classification(
reference["ifcClassificationReference"]
)
classification_name = classification_entity.Name if classification_entity else ""
row.label(text=classification_name, icon="OUTLINER_COLLECTION")
if self.file.schema == "IFC2X3":
name = reference["ItemReference"] or "No Identification"
else:
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.LoadObjectives,
@@ -17,9 +17,10 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from ifcopenshell.util.doc import get_entity_doc
import bonsai.tool as tool
def refresh():
ConstraintsData.is_loaded = False
@@ -16,12 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING
import bpy
import ifcopenshell.api
import ifcopenshell.api.constraint
import bonsai.bim.helper
import bonsai.tool as tool
from typing import TYPE_CHECKING
def get_active_object(context: bpy.types.Context, obj_name: str) -> bpy.types.Object:
+12 -16
View File
@@ -16,24 +16,20 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from ifcopenshell.util.doc import get_entity_doc
import bonsai.tool as tool
from bonsai.bim.prop import Attribute
from bonsai.bim.module.constraint.data import ConstraintsData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Literal
import bpy
from bpy.props import (
CollectionProperty,
EnumProperty,
IntProperty,
StringProperty,
)
from bpy.types import PropertyGroup
from bonsai.bim.module.constraint.data import ConstraintsData
from bonsai.bim.prop import Attribute
def get_available_constraint_types(self, context):
if not ConstraintsData.is_loaded:
+12 -5
View File
@@ -17,14 +17,21 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bonsai.tool as tool
from bpy.types import Panel, UIList
from bonsai.bim.helper import draw_attributes
from bonsai.bim.module.constraint.data import ConstraintsData, ObjectConstraintsData
from typing import TYPE_CHECKING
from bpy.types import Panel, UIList
import bonsai.tool as tool
from bonsai.bim.helper import draw_attributes
from bonsai.bim.module.constraint.data import ConstraintsData, ObjectConstraintsData
if TYPE_CHECKING:
from bonsai.bim.module.constraint.prop import BIMConstraintProperties, BIMObjectConstraintProperties, Constraint
from bonsai.bim.module.constraint.prop import (
BIMConstraintProperties,
BIMObjectConstraintProperties,
Constraint,
)
class BIM_PT_constraints(Panel):
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddContext,
+4 -3
View File
@@ -16,11 +16,12 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
import ifcopenshell
from typing import Any
import ifcopenshell
import bonsai.tool as tool
def refresh():
ContextData.is_loaded = False
@@ -17,8 +17,9 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
import bonsai.core.context as core
import bonsai.tool as tool
class AddContext(bpy.types.Operator, tool.Ifc.Operator):
+10 -14
View File
@@ -16,22 +16,18 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bonsai.bim.prop import StrProperty, Attribute
from bonsai.bim.module.context.data import ContextData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING
import bpy
from bpy.props import (
CollectionProperty,
EnumProperty,
IntProperty,
)
from bpy.types import PropertyGroup
from bonsai.bim.prop import Attribute
class BIMContextProperties(PropertyGroup):
contexts: EnumProperty(items=[("Model", "Model", ""), ("Plan", "Plan", "")], name="Contexts")
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.bim.helper
import bonsai.tool as tool
from bonsai.bim.module.context.data import ContextData
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddCostColumn,
+3 -3
View File
@@ -16,15 +16,15 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from typing import Any, Union
import ifcopenshell
import ifcopenshell.util.cost
import ifcopenshell.util.date
import ifcopenshell.util.element
import ifcopenshell.util.unit
import bonsai.tool as tool
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
from typing import Any, Union
def refresh():
+10 -10
View File
@@ -18,16 +18,16 @@
# pyright: reportUnnecessaryTypeIgnoreComment=error
import bpy
import textwrap
import ifcopenshell.api.nest
import bonsai.tool as tool
from bpy_extras.io_utils import ImportHelper, ExportHelper
import bonsai.tool as tool
import bonsai.core.cost as core
from pathlib import Path
from typing import TYPE_CHECKING, Literal, get_args
from typing import get_args, TYPE_CHECKING, Literal
import bpy
import ifcopenshell.api.nest
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bonsai.core.cost as core
import bonsai.tool as tool
class AddCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
@@ -87,7 +87,7 @@ class CopyCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
bl_label = "Copy Cost Schedule"
bl_description = "Create a duplicate of the provided cost schedule."
bl_options = {"REGISTER", "UNDO"}
cost_schedule: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
cost_schedule: bpy.props.IntProperty()
if TYPE_CHECKING:
cost_schedule: int
@@ -987,10 +987,10 @@ class ExportCostSchedulesToPDF(bpy.types.Operator, ExportHelper):
@classmethod
def poll(cls, context):
try:
import typst
import typst # noqa: F401
return True
except:
except ModuleNotFoundError:
cls.poll_message_set(
"Typst not available.\nIt can be installed from Quality and\nControl -> Debug and using 'typst' with Pip Install.\n(Run Blender as Administrator)"
)
+17 -14
View File
@@ -16,25 +16,28 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING, Literal, Union
import bpy
import ifcopenshell.api
import ifcopenshell.api.cost
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
FloatProperty,
IntProperty,
StringProperty,
)
from bpy.types import PropertyGroup
import bonsai.tool as tool
from bonsai.bim.module.classification.data import CostClassificationsData
from bonsai.bim.module.cost.data import CostSchedulesData, CostItemRatesData, CostItemQuantitiesData
from bonsai.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
from bonsai.bim.module.cost.data import (
CostItemQuantitiesData,
CostItemRatesData,
CostSchedulesData,
)
from typing import TYPE_CHECKING, Literal, Union
from bonsai.bim.prop import Attribute, StrProperty
def get_schedule_of_rates(self: "BIMCostProperties", context: bpy.types.Context) -> tool.Blender.BLENDER_ENUM_ITEMS:
+49 -17
View File
@@ -17,16 +17,20 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import TYPE_CHECKING, Any
import bpy
from bpy.types import Panel, UIList
import bonsai.bim.helper
import bonsai.bim.module.cost.prop as CostProp
import bonsai.tool as tool
from bpy.types import Panel, UIList
from bonsai.bim.module.cost.data import CostSchedulesData
from typing import Any, TYPE_CHECKING
from bonsai.bim.module.cost.data import CostItem, CostSchedulesData
if TYPE_CHECKING:
from bonsai.bim.module.cost.prop import BIMCostProperties, CostItemQuantity
from bonsai.bim.prop import StrProperty
class BIM_PT_cost_schedules(Panel):
@@ -395,8 +399,8 @@ class BIM_PT_cost_item_types(Panel):
op = row2.operator("bim.calculate_cost_item_resource_value", text="", icon="DISC")
op.cost_item = cost_item.ifc_definition_id
rtprops = context.scene.BIMResourceTreeProperties
rprops = tool.Resource.get_resource_props()
rtprops = rprops.tree
if rtprops.resources and rprops.active_resource_index < len(rtprops.resources):
if has_quantity_names:
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
@@ -658,9 +662,18 @@ class BIM_UL_cost_items_trait:
split2.alignment = "LEFT"
split2.label(text="Rate")
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMCostProperties,
item: CostProp.CostItem,
icon,
active_data,
active_propname,
) -> None:
if item:
self.props = tool.Cost.get_cost_props()
self.props = data
cost_item = CostSchedulesData.data["cost_items"][item.ifc_definition_id]
row = layout.row(align=True)
@@ -691,7 +704,7 @@ class BIM_UL_cost_items_trait:
# TODO: reimplement "bim.copy_cost_item_values" somewhere with better UX
def draw_parent_operator(self, row, cost_item_id):
def draw_parent_operator(self, row: bpy.types.UILayout, cost_item_id: int) -> None:
if self.props.active_cost_item_id:
if self.props.active_cost_item_id != cost_item_id:
op = row.operator("bim.change_parent_cost_item", text="", icon="LINKED", emboss=False).new_parent = (
@@ -700,7 +713,7 @@ class BIM_UL_cost_items_trait:
else:
row.label(text="", icon="BLANK1")
def draw_hierarchy(self, row, item):
def draw_hierarchy(self, row: bpy.types.UILayout, item: CostProp.CostItem) -> None:
for i in range(0, item.level_index):
row.label(text="", icon="BLANK1")
if item.has_children:
@@ -746,7 +759,7 @@ class BIM_UL_cost_items_trait:
else:
row.label(text="-")
def draw_value_column(self, layout, cost_item):
def draw_value_column(self, layout: bpy.types.UILayout, cost_item: CostItem) -> None:
if cost_item["TotalAppliedValue"]:
text = "{0:,.2f}".format(cost_item["TotalAppliedValue"]).replace(",", " ")
if cost_item["UnitBasisValueComponent"] not in [None, 1]:
@@ -757,13 +770,13 @@ class BIM_UL_cost_items_trait:
else:
layout.label(text="-")
def draw_total_cost_column(self, layout, cost_item):
def draw_total_cost_column(self, layout: bpy.types.UILayout, cost_item: CostItem) -> None:
format_numbers = "{0:,.2f}".format(cost_item["TotalCost"]).replace(",", " ")
currency = CostSchedulesData.data["currency"]
text = "{} {}".format(format_numbers, currency["name"]) if currency else format_numbers
layout.label(text=text)
def draw_order_operator(self, row, ifc_definition_id, cost_item):
def draw_order_operator(self, row: bpy.types.UILayout, ifc_definition_id: int, cost_item: CostItem) -> None:
if cost_item["NestingIndex"] is not None:
if cost_item["NestingIndex"] == 0:
op = row.operator("bim.reorder_cost_item_nesting", icon="TRIA_DOWN", text="")
@@ -790,12 +803,14 @@ class BIM_UL_cost_item_rates(BIM_UL_cost_items_trait, UIList):
def draw_quantity_column(self, layout, cost_item):
self.draw_uom_column(layout, cost_item)
def draw_total_cost_column(self, layout, cost_item):
def draw_total_cost_column(self, layout: bpy.types.UILayout, cost_item: CostItem) -> None:
pass # No such thing as a total cost in a schedule of rates
class BIM_UL_cost_columns(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self, context, layout: bpy.types.UILayout, data, item: StrProperty, icon, active_data, active_propname
) -> None:
if item:
row = layout.row(align=True)
row.prop(item, "name", emboss=False, text="")
@@ -803,9 +818,17 @@ class BIM_UL_cost_columns(UIList):
class BIM_UL_cost_item_types(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
props = tool.Cost.get_cost_props()
cost_item = props.cost_items[props.active_cost_item_index]
def draw_item(
self,
context,
layout: bpy.types.UILayout,
data: BIMCostProperties,
item: CostProp.CostItemType,
icon,
active_data,
active_propname,
) -> None:
cost_item = data.cost_items[data.active_cost_item_index]
if item:
row = layout.row(align=True)
@@ -841,7 +864,16 @@ class BIM_UL_cost_item_quantities(UIList):
class BIM_UL_product_cost_items(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
def draw_item(
self,
context,
layout: bpy.types.UILayout,
data,
item: CostItemQuantity,
icon,
active_data,
active_propname,
) -> None:
if item:
row = layout.row(align=True)
op = row.operator("bim.highlight_product_cost_item", text="", icon="STYLUS_PRESSURE")
@@ -17,6 +17,7 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import prop, workspace
classes = (
@@ -16,9 +16,10 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from typing import TYPE_CHECKING
import bpy
from bpy.types import PropertyGroup
from typing import TYPE_CHECKING
class BIMCoveringProperties(PropertyGroup):
@@ -18,13 +18,14 @@
import os
from functools import partial
import bpy
import ifcopenshell
from bpy.types import WorkSpaceTool
import bonsai.tool as tool
from bonsai.bim.helper import prop_with_search
from bonsai.bim.module.model.data import AuthoringData
from bpy.types import WorkSpaceTool
from functools import partial
class CoveringTool(WorkSpaceTool):
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
prop.CoveToolProject,
@@ -16,12 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
import ifcopenshell
from math import atan2, degrees
import bpy
import ifcopenshell.util.element
import bonsai.tool as tool
from math import degrees, atan2
from .api import Api
@@ -16,9 +16,10 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from typing import TYPE_CHECKING
import bpy
class CoveToolProject(bpy.types.PropertyGroup):
run_set: bpy.props.StringProperty(name="Run Set")
+6 -3
View File
@@ -17,12 +17,15 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import bpy.types
import bonsai.tool as tool
from typing import TYPE_CHECKING
import bpy.types
import bonsai.tool as tool
if TYPE_CHECKING:
from bonsai.bim.module.covetool.prop import CoveToolProperties, CoveToolProject
from bonsai.bim.module.covetool.prop import CoveToolProject, CoveToolProperties
class BIM_PT_covetool(bpy.types.Panel):
+2 -1
View File
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.AddCsvAttribute,
+8 -9
View File
@@ -17,20 +17,19 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
import os
import bpy
import json
import ifccsv
import logging
import tempfile
from collections import Counter
from typing import TYPE_CHECKING
import bpy
import ifcopenshell
import ifcopenshell.util.selector
import bonsai.tool as tool
import bonsai.bim.module.drawing.scheduler as scheduler
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bonsai.bim.module.drawing.scheduler as scheduler
import bonsai.tool as tool
from bonsai.bim.handler import refresh_ui_data
from typing import TYPE_CHECKING
from collections import Counter
if TYPE_CHECKING:
import pandas as pd
+11 -13
View File
@@ -16,21 +16,19 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bonsai.bim.prop import StrProperty, BIMFilterGroup
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Literal
import bpy
from bpy.props import (
BoolProperty,
CollectionProperty,
EnumProperty,
StringProperty,
)
from bpy.types import PropertyGroup
from bonsai.bim.prop import BIMFilterGroup
class CsvAttribute(PropertyGroup):
name: StringProperty(name="Query", default="class")
+2 -1
View File
@@ -16,9 +16,10 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
from bpy.types import Panel
import bonsai.bim.helper
import bonsai.tool as tool
from bpy.types import Panel
from bonsai.bim.module.search.data import SearchData
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.ChangeLogLevel,
+21 -20
View File
@@ -16,34 +16,35 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import bpy
import time
import random
import logging
import subprocess
import os
import platform
import random
import subprocess
import sys
import time
from collections import defaultdict
from pathlib import Path
from typing import TYPE_CHECKING, Any, Literal, Union, assert_never, get_args
import bpy
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.api.pset
import ifcopenshell.geom
import ifcopenshell.ifcopenshell_wrapper as W
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.unit
import bonsai.tool as tool
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bonsai.bim.handler
import bonsai.bim.import_ifc as import_ifc
import bonsai.core.debug as core
import bonsai.core.profile
import bonsai.core.type
import bonsai.bim.handler
import bonsai.bim.import_ifc as import_ifc
from collections import defaultdict
from bpy_extras.io_utils import ImportHelper, ExportHelper
from pathlib import Path
from bonsai import get_debug_info, format_debug_info
import bonsai.tool as tool
from bonsai import format_debug_info, get_debug_info
from bonsai.bim.ifc import IfcStore
from typing import get_args, Union, Any, TYPE_CHECKING, Literal, get_args, assert_never
if TYPE_CHECKING:
from bonsai.bim.prop import Attribute
@@ -259,14 +260,14 @@ class CreateAllShapes(bpy.types.Operator):
)
bl_options = {"REGISTER"}
geometry_library: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
geometry_library: bpy.props.EnumProperty(
name="Geometry Library",
description="Geometry library to use for testing shape creation.",
items=[(i, i, "") for i in get_args(ifcopenshell.geom.GEOMETRY_LIBRARY)],
# By default use the same library as used for importing ifc project.
default="hybrid-cgal-simple-opencascade",
)
custom_geometry_library: bpy.props.StringProperty( # pyright: ignore[reportRedeclaration]
custom_geometry_library: bpy.props.StringProperty(
name="Custom Geometry Library",
description="Provide a custom geometry library name, will override the 'geometry library' property.",
)
@@ -780,7 +781,7 @@ class PurgeUnusedObjects(bpy.types.Operator, tool.Ifc.Operator):
bl_label = "Purge Unused Objects"
bl_options = {"REGISTER", "UNDO"}
object_type: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
object_type: bpy.props.EnumProperty(
name="Object Type",
items=((s, s.capitalize(), "") for s in get_args(tool.Debug.PurgeMergeObjectType)),
)
@@ -826,7 +827,7 @@ class MergeIdenticalObjects(bpy.types.Operator, tool.Ifc.Operator):
)
bl_options = {"REGISTER", "UNDO"}
object_type: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
object_type: bpy.props.EnumProperty(
name="Object Type",
items=((s, s.capitalize(), "") for s in get_args(tool.Debug.PurgeMergeObjectType)),
)
@@ -1072,7 +1073,7 @@ class ChangeLogLevel(bpy.types.Operator):
bl_options = {"REGISTER"}
bl_description = "Change general log level across all Python code in Blender"
log_level: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
log_level: bpy.props.EnumProperty(
name="Log Level",
items=[(i, i, "") for i in get_args(LogLevelType)],
default="WARNING",
+11 -13
View File
@@ -16,21 +16,19 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from bonsai.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
)
from typing import TYPE_CHECKING, Literal, get_args
import bpy
from bpy.props import (
CollectionProperty,
EnumProperty,
IntProperty,
StringProperty,
)
from bpy.types import PropertyGroup
from bonsai.bim.prop import Attribute, StrProperty
DisplayType = Literal["BOUNDS", "WIRE", "SOLID", "TEXTURED"]
+2 -1
View File
@@ -17,9 +17,10 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import bonsai.tool as tool
from bpy.types import Panel
import bonsai.tool as tool
class BIM_PT_debug(Panel):
bl_label = "Debug"
@@ -28,7 +28,8 @@
# system when the add-on loads. This is where it happens.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
# You'll need to provide a list of every one of your classes here. If you forget
# to specify your class, it won't load and you won't be able to use that
@@ -28,8 +28,9 @@
# "Operators", since they correlate to a single user operation.
import bpy
import bonsai.tool as tool
import bonsai.core.demo as core
import bonsai.tool as tool
# Each button correlates to a class like the one below. In this case, we're
+2 -10
View File
@@ -32,21 +32,13 @@
from typing import TYPE_CHECKING
import bpy
from bpy.types import PropertyGroup
# Properties have many different data types. We won't use all of them in this
# demo module, but this is a list for your reference.
from bpy.props import (
PointerProperty,
StringProperty,
EnumProperty,
BoolProperty,
IntProperty,
FloatProperty,
FloatVectorProperty,
CollectionProperty,
StringProperty,
)
from bpy.types import PropertyGroup
# All properties must belong in a property group. Usually, you'd have a group
+1
View File
@@ -27,6 +27,7 @@
# panels, buttons, labels, and input fields are laid out.
import bpy
import bonsai.tool as tool
from bonsai.bim.module.demo.data import DemoData
@@ -17,7 +17,8 @@
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
from . import ui, prop, operator
from . import operator, prop, ui
classes = (
operator.ExecuteIfcDiff,
+3 -1
View File
@@ -16,8 +16,10 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
import bpy
import bonsai.tool as tool
@@ -16,15 +16,17 @@
# You should have received a copy of the GNU General Public License
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
import bpy
import json
import logging
import bpy
import ifcdiff
import ifcopenshell
from bpy_extras.io_utils import ExportHelper, ImportHelper
import bonsai.bim.handler
import bonsai.bim.import_ifc
import bonsai.tool as tool
from bpy_extras.io_utils import ImportHelper, ExportHelper
from bonsai.bim.ifc import IfcStore
@@ -96,8 +98,8 @@ class VisualiseDiff(bpy.types.Operator):
obj.color = (0.0, 1.0, 0.0, 1.0)
elif global_id in diff["changed"]:
obj.color = (0.0, 0.0, 1.0, 1.0)
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
area.spaces[0].shading.color_type = "OBJECT"
assert (space := tool.Blender.get_view3d_space())
space.shading.color_type = "OBJECT"
return {"FINISHED"}

Some files were not shown because too many files have changed in this diff Show More