mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 10:33:20 +00:00
Merge branch 'v0.8.0' into ifcmax/initial-refresh
This commit is contained in:
@@ -5,11 +5,26 @@ on:
|
||||
|
||||
jobs:
|
||||
build_ifcopenshell:
|
||||
runs-on: windows-2022
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: ['x64']
|
||||
include:
|
||||
- arch: x64
|
||||
runs_on: windows-2022
|
||||
deps_dir: _deps-vs2022-x64-installed
|
||||
vcvars: '"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"'
|
||||
build_branch: windows-x64
|
||||
zip_suffix: win64
|
||||
|
||||
- arch: ARM64
|
||||
runs_on: windows-11-arm
|
||||
deps_dir: _deps-vs2022-ARM64-installed
|
||||
vcvars: '"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsarm64.bat"'
|
||||
build_branch: windows-arm64
|
||||
zip_suffix: win-arm64
|
||||
|
||||
runs-on: ${{ matrix.runs_on }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v6
|
||||
@@ -20,7 +35,7 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: IfcOpenShell/build-outputs
|
||||
path: _deps-vs2022-x64-installed
|
||||
path: ${{ matrix.deps_dir }}
|
||||
ref: windows-${{ matrix.arch }}
|
||||
lfs: true
|
||||
token: ${{ secrets.BUILD_REPO_TOKEN }}
|
||||
@@ -31,7 +46,7 @@ jobs:
|
||||
|
||||
- name: Unpack Dependencies
|
||||
run: |
|
||||
cd _deps-vs2022-x64-installed
|
||||
cd ${{ matrix.deps_dir }}
|
||||
Get-ChildItem -Path . -Filter 'cache-*.zip' | ForEach-Object {
|
||||
7z x $_.FullName
|
||||
}
|
||||
@@ -46,14 +61,16 @@ jobs:
|
||||
|
||||
- name: Run Build Script And Pack .zip Archives
|
||||
shell: cmd
|
||||
env:
|
||||
TARGET_ARCH: ${{ matrix.arch }} # lets the Python script know which arch to target (optional override)
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||
call ${{ matrix.vcvars }}
|
||||
cd win
|
||||
python build-all-win.py
|
||||
|
||||
- name: Pack Dependencies
|
||||
run: |
|
||||
cd _deps-vs2022-x64-installed
|
||||
cd ${{ matrix.deps_dir }}
|
||||
Get-ChildItem -Path . -Directory | ForEach-Object {
|
||||
$cacheFile = "cache-$($_.Name).zip"
|
||||
echo $cacheFile
|
||||
@@ -64,12 +81,13 @@ jobs:
|
||||
|
||||
- name: Commit and Push Changes to Build Repository
|
||||
run: |
|
||||
cd _deps-vs2022-x64-installed
|
||||
cd ${{ matrix.deps_dir }}
|
||||
git config user.name "IfcOpenBot"
|
||||
git config user.email "ifcopenbot@ifcopenshell.org"
|
||||
git checkout -B ${{ matrix.build_branch }}
|
||||
git add *.zip
|
||||
git commit -m "Update build artifacts [skip ci]" || echo "No changes to commit"
|
||||
git push || echo "Push failed"
|
||||
git push --set-upstream origin ${{ matrix.build_branch }} || echo "Push failed"
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
@@ -88,4 +106,4 @@ jobs:
|
||||
foreach ($zip in Get-ChildItem -Path "$env:USERPROFILE\output" -Filter *.zip) {
|
||||
aws s3 cp "$($zip.FullName)" s3://ifcopenshell-builds/ --debug
|
||||
Start-Sleep -Seconds 5
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,8 @@ jobs:
|
||||
id: syntax-errors
|
||||
run: |
|
||||
ERROR=0
|
||||
# Using 2 Python versions - one minimum required for IfcOpenShell
|
||||
# and other that's used by Blender currently.
|
||||
python3.10 -W error -m compileall -q src/ifcopenshell-python || ERROR=1
|
||||
python3.11 -W error -m compileall -q src/bonsai || ERROR=1
|
||||
exit $ERROR
|
||||
|
||||
@@ -181,6 +181,7 @@ jobs:
|
||||
"-DSCHEMA_VERSIONS=2x3;4;4x3_add2" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DWITH_ROCKSDB=On \
|
||||
-DBUILD_EXAMPLES=ON \
|
||||
../cmake
|
||||
sudo make -j $(nproc)
|
||||
sudo make install
|
||||
|
||||
+7
-1
@@ -2,7 +2,7 @@
|
||||
name = "IfcOpenShell"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"black==26.3.0",
|
||||
"black==26.3.1",
|
||||
"ruff==0.15.5",
|
||||
"poethepoet",
|
||||
"gersemi==0.26.0",
|
||||
@@ -28,6 +28,12 @@ extend-exclude = '''
|
||||
reportInvalidTypeForm = false
|
||||
disableBytesTypePromotions = true
|
||||
reportUnnecessaryTypeIgnoreComment = true
|
||||
# Pylance doesn't respect gitignore, so we have to exclude files manually here
|
||||
# to avoid VS Code slowing down.
|
||||
# https://github.com/microsoft/pylance-release/issues/5169
|
||||
exclude = [
|
||||
"_deps",
|
||||
]
|
||||
|
||||
# Define here general ruff settings,
|
||||
# then they will be inherited by projects' .toml files.
|
||||
|
||||
+4
-23
@@ -223,19 +223,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
|
||||
@@ -243,16 +232,8 @@ 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/
|
||||
# TODO: Use official repo once https://github.com/prochitecture/bpypolyskel/pull/22 is merged.
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PYTHON) -m pip wheel "git+https://github.com/Andrej730/bpypolyskel.git@pyproject_toml" --no-deps -w wheels/
|
||||
|
||||
# folder for executable files
|
||||
mkdir -p build/bonsai/libs/bin
|
||||
|
||||
@@ -35,12 +35,11 @@ IN_PACKAGE = __package__ == "bonsai"
|
||||
import platform
|
||||
import re
|
||||
import traceback
|
||||
import uuid
|
||||
import webbrowser
|
||||
from collections import deque
|
||||
from collections.abc import Generator
|
||||
from pathlib import Path
|
||||
from typing import Any, Union
|
||||
from typing import TYPE_CHECKING, Any, Union
|
||||
|
||||
last_commit_hash = "8888888"
|
||||
last_commit_date = "9999999"
|
||||
@@ -72,6 +71,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.
|
||||
|
||||
@@ -93,9 +107,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(),
|
||||
@@ -111,6 +129,14 @@ def get_debug_info():
|
||||
"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
|
||||
@@ -131,7 +157,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']}"
|
||||
@@ -149,33 +175,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
|
||||
|
||||
@@ -205,6 +208,8 @@ def clean_up_dlls_safe_links() -> None:
|
||||
|
||||
|
||||
if IN_BLENDER:
|
||||
import bpy
|
||||
|
||||
initialize_bbim_semver()
|
||||
|
||||
def get_binary_info() -> dict[str, Any]:
|
||||
@@ -296,9 +301,6 @@ if IN_BLENDER:
|
||||
purge_cache()
|
||||
|
||||
def unregister():
|
||||
if platform.system() == "Windows":
|
||||
safe_link_dlls()
|
||||
|
||||
import bonsai.bim
|
||||
|
||||
bonsai.bim.unregister()
|
||||
@@ -333,7 +335,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
|
||||
@@ -409,7 +411,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
|
||||
|
||||
@@ -747,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)
|
||||
@@ -1020,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"]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1253,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)
|
||||
|
||||
@@ -27,6 +27,7 @@ import ifcopenshell.api
|
||||
import ifcopenshell.api.boundary
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.ifcopenshell_wrapper as W
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.shape
|
||||
@@ -701,6 +702,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),
|
||||
|
||||
@@ -16,9 +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/>.
|
||||
|
||||
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
|
||||
@@ -274,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()
|
||||
|
||||
@@ -457,9 +457,7 @@ class HideClash(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
ClashDecorator.uninstall()
|
||||
for area in context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
tool.Blender.update_all_viewports(context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -26,10 +26,11 @@ from bpy.types import Panel, UIList
|
||||
import bonsai.bim.helper
|
||||
import bonsai.bim.module.cost.prop as CostProp
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim.module.cost.data import CostSchedulesData
|
||||
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):
|
||||
@@ -398,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")
|
||||
@@ -661,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)
|
||||
|
||||
@@ -694,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 = (
|
||||
@@ -703,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:
|
||||
@@ -749,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]:
|
||||
@@ -760,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="")
|
||||
@@ -793,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="")
|
||||
@@ -806,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)
|
||||
@@ -844,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")
|
||||
|
||||
@@ -98,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"}
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import json
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.util.element
|
||||
|
||||
import bonsai.core.document as core
|
||||
import bonsai.tool as tool
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import TYPE_CHECKING, Union
|
||||
from typing import TYPE_CHECKING, Literal, Union
|
||||
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
@@ -66,7 +66,7 @@ class Document(PropertyGroup):
|
||||
tree_depth: int
|
||||
has_children: bool
|
||||
is_expanded: bool
|
||||
document_type: str
|
||||
document_type: Literal["PROJECT", "INFORMATION", "REFERENCE"]
|
||||
|
||||
|
||||
class DocumentObject(PropertyGroup):
|
||||
|
||||
@@ -16,9 +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 __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.document.prop import (
|
||||
BIMDocumentProperties,
|
||||
Document,
|
||||
DocumentObject,
|
||||
)
|
||||
|
||||
from bonsai.bim.helper import draw_attributes
|
||||
from bonsai.bim.module.document.data import DocumentData, ObjectDocumentData
|
||||
|
||||
@@ -207,7 +220,16 @@ class BIM_PT_object_documents(Panel):
|
||||
|
||||
|
||||
class BIM_UL_documents(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMDocumentProperties,
|
||||
item: Document,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
indent_depth = 0
|
||||
@@ -252,16 +274,22 @@ class BIM_UL_documents(UIList):
|
||||
|
||||
|
||||
class BIM_UL_document_objects(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
def draw_item(
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: BIMDocumentProperties,
|
||||
item: DocumentObject,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.prop(item, "name", text="", emboss=False, icon="OBJECT_DATA")
|
||||
row.operator("bim.select_object", text="", icon="RESTRICT_SELECT_OFF").obj_name = item.name
|
||||
|
||||
props = tool.Document.get_document_props()
|
||||
if props.active_document:
|
||||
document = props.active_document
|
||||
|
||||
if document := data.active_document:
|
||||
op = row.operator("bim.unassign_document", text="", icon="X")
|
||||
op.document = document.ifc_definition_id
|
||||
op.obj = item.name
|
||||
|
||||
@@ -22,7 +22,9 @@ from pathlib import Path
|
||||
from typing import Any, Union
|
||||
|
||||
import bpy
|
||||
import ifcopenshell.util.classification
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.unit
|
||||
from natsort import natsorted
|
||||
|
||||
|
||||
@@ -70,9 +70,9 @@ class profile_consequential:
|
||||
cls.start_time = None
|
||||
lines = "\n".join(cls.lines)
|
||||
print(lines)
|
||||
import pyperclip
|
||||
|
||||
pyperclip.copy(lines)
|
||||
assert (wm := bpy.context.window_manager)
|
||||
wm.clipboard = lines
|
||||
cls.lines = []
|
||||
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ from bpy_extras.view3d_utils import (
|
||||
)
|
||||
from gpu_extras.batch import batch_for_shader
|
||||
from ifcopenshell.util.unit import si_conversions
|
||||
from mathutils import Matrix, Vector
|
||||
from mathutils import Matrix, Vector, geometry
|
||||
from mathutils.geometry import intersect_line_line
|
||||
from mathutils.kdtree import KDTree
|
||||
|
||||
@@ -1243,9 +1243,7 @@ class SnapManager:
|
||||
@staticmethod
|
||||
def _redraw_viewport() -> None:
|
||||
"""Force 3D viewport redraw."""
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
tool.Blender.update_all_viewports()
|
||||
|
||||
def build_snap_cache(
|
||||
self, context: bpy.types.Context, active_obj: bpy.types.Object, include_active: bool = False
|
||||
|
||||
@@ -42,6 +42,7 @@ import bmesh
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api.document
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.pset
|
||||
import ifcopenshell.api.style
|
||||
import ifcopenshell.geom
|
||||
|
||||
@@ -515,6 +515,8 @@ class BIM_PT_derived_coordinates(Panel):
|
||||
return context.active_object is not None
|
||||
|
||||
def draw(self, context):
|
||||
assert context.active_object
|
||||
props = tool.Model.get_model_props()
|
||||
if not DerivedCoordinatesData.is_loaded:
|
||||
DerivedCoordinatesData.load()
|
||||
|
||||
@@ -529,10 +531,8 @@ class BIM_PT_derived_coordinates(Panel):
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.enabled = False
|
||||
area_3d = next((area for area in context.screen.areas if area.type == "VIEW_3D"), None)
|
||||
space_3d = next((space for space in area_3d.spaces if space.type == "VIEW_3D"), None)
|
||||
|
||||
if bpy.context.scene.BIMModelProperties.show_bounding_box:
|
||||
if props.show_bounding_box:
|
||||
for axis, icon, idx in [("X", "STRIP_COLOR_01", 0), ("Y", "STRIP_COLOR_04", 1), ("Z", "STRIP_COLOR_05", 2)]:
|
||||
row.label(text="", icon=icon)
|
||||
row.prop(context.active_object, "dimensions", text=axis, index=idx)
|
||||
|
||||
@@ -16,6 +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/>.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import bpy
|
||||
from bpy.props import BoolProperty, CollectionProperty, EnumProperty, StringProperty
|
||||
from bpy.types import PropertyGroup
|
||||
|
||||
@@ -37,3 +40,13 @@ class BIMCityJsonProperties(PropertyGroup):
|
||||
lod: EnumProperty(name="LOD", description="", items=get_lods, options={"ANIMATABLE"}, default=None)
|
||||
is_lod_found: BoolProperty(name="Is LOD Found", default=False)
|
||||
load_after_convert: BoolProperty(name="Load After Converting", default=True)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
input: str
|
||||
output: str
|
||||
name: str
|
||||
split_lod: bool
|
||||
lods: bpy.types.bpy_prop_collection_idprop[StrProperty]
|
||||
lod: str
|
||||
is_lod_found: bool
|
||||
load_after_convert: bool
|
||||
|
||||
@@ -30,6 +30,7 @@ from typing import TYPE_CHECKING, Union
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.ifcopenshell_wrapper as W
|
||||
import ifcopenshell.util.geolocation
|
||||
import pyradiance as pr
|
||||
import requests
|
||||
@@ -106,9 +107,8 @@ class ExportOBJ(bpy.types.Operator):
|
||||
if iterator.initialize():
|
||||
while True:
|
||||
shape = iterator.get()
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
materials = shape.geometry.materials
|
||||
material_ids = shape.geometry.material_ids
|
||||
# material_names = shape.geometry.material_names
|
||||
|
||||
for material in materials:
|
||||
ifc_materials.append(material.name)
|
||||
|
||||
@@ -21,6 +21,11 @@ import bpy
|
||||
from . import operator, prop, ui
|
||||
|
||||
classes = (
|
||||
operator.ImportQuickFavorites,
|
||||
operator.RemoveQuickFavoritesItem,
|
||||
operator.MoveQuickFavoritesItem,
|
||||
operator.AddQuickFavoritesItem,
|
||||
operator.ConfirmQuickFavoriteOperator,
|
||||
operator.DrawSystemArrows,
|
||||
operator.GetConnectedSystemElements,
|
||||
operator.IfcSverchokUseBonsaiFile,
|
||||
@@ -28,8 +33,12 @@ classes = (
|
||||
operator.SetOverrideColour,
|
||||
operator.SnapSpacesTogether,
|
||||
operator.SplitAlongEdge,
|
||||
prop.QuickFavoriteEnumItem,
|
||||
prop.QuickFavoriteProperty,
|
||||
prop.QuickFavoritesItem,
|
||||
prop.BIMMiscProperties,
|
||||
ui.BIM_PT_misc_utilities,
|
||||
ui.BIM_PT_quick_favorites_manager,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# Bonsai is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Bonsai is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# 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
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def refresh() -> None:
|
||||
QuickFavoritesData.is_loaded = False
|
||||
|
||||
|
||||
class QuickFavoritesData:
|
||||
data: dict[str, Any] = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls) -> None:
|
||||
cls.data = {
|
||||
"operators": cls.operators(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def operators(cls) -> list[str]:
|
||||
items: list[str] = []
|
||||
for module_name in dir(bpy.ops):
|
||||
module = getattr(bpy.ops, module_name)
|
||||
for op_name in dir(module):
|
||||
op = getattr(module, op_name)
|
||||
bl_label = op.get_rna_type().name
|
||||
items.append(f"{module_name}.{op_name} - {bl_label}")
|
||||
return items
|
||||
@@ -30,6 +30,9 @@ import bonsai.core.misc as core
|
||||
import bonsai.core.root
|
||||
import bonsai.tool as tool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bpy.stub_internal import rna_enums
|
||||
|
||||
|
||||
class SetOverrideColour(bpy.types.Operator):
|
||||
bl_idname = "bim.set_override_colour"
|
||||
@@ -41,10 +44,11 @@ class SetOverrideColour(bpy.types.Operator):
|
||||
return context.selected_objects
|
||||
|
||||
def execute(self, context):
|
||||
props = tool.Misc.get_misc_props()
|
||||
for obj in context.selected_objects:
|
||||
obj.color = context.scene.BIMMiscProperties.override_colour
|
||||
area = next(area for area in context.screen.areas if area.type == "VIEW_3D")
|
||||
area.spaces[0].shading.color_type = "OBJECT"
|
||||
obj.color = props.override_colour
|
||||
assert (space := tool.Blender.get_view3d_space())
|
||||
space.shading.color_type = "OBJECT"
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -351,6 +355,151 @@ class DrawSystemArrows(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return matrix
|
||||
|
||||
|
||||
class ConfirmQuickFavoriteOperator(bpy.types.Operator):
|
||||
bl_idname = "bim.confirm_quick_favorite_operator"
|
||||
bl_label = "Confirm Operator"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
index: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
index: int
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Misc.get_misc_props()
|
||||
fav = props.quick_favorites[self.index]
|
||||
rna = fav.get_searched_operator()
|
||||
|
||||
if rna is None:
|
||||
self.report({"INFO"}, "No operator entered for search.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
fav.operator_id = tool.Blender.operator_idname_to_py(rna.identifier)
|
||||
fav.label = rna.name
|
||||
fav.properties.clear()
|
||||
has_skipped = False
|
||||
for p in rna.properties:
|
||||
# skip silently, e.g. `rna_type` is a PointerProperty
|
||||
if isinstance(p, bpy.types.PointerProperty):
|
||||
continue
|
||||
if isinstance(p, (bpy.types.FloatProperty, bpy.types.BoolProperty, bpy.types.IntProperty)) and p.is_array:
|
||||
print(f"Array property '{p.identifier}' is not supported, skipping.")
|
||||
has_skipped = True
|
||||
continue
|
||||
item = fav.properties.add()
|
||||
item.name = p.identifier
|
||||
item.display_name = p.name
|
||||
if isinstance(p, bpy.types.FloatProperty):
|
||||
item.value_prop = "float_value"
|
||||
item.float_value = p.default
|
||||
elif isinstance(p, bpy.types.BoolProperty):
|
||||
item.value_prop = "bool_value"
|
||||
item.bool_value = p.default
|
||||
elif isinstance(p, bpy.types.IntProperty):
|
||||
item.value_prop = "int_value"
|
||||
item.int_value = p.default
|
||||
elif isinstance(p, bpy.types.EnumProperty):
|
||||
item.value_prop = "enum_value"
|
||||
item.set_enum_items([(e.identifier, e.name, e.description) for e in p.enum_items])
|
||||
item.enum_value = p.default
|
||||
elif isinstance(p, bpy.types.StringProperty):
|
||||
item.value_prop = "string_value"
|
||||
item.string_value = p.default
|
||||
else:
|
||||
print(f"Unhandled property type {type(p).__name__} for '{p.identifier}', skipping.")
|
||||
has_skipped = True
|
||||
if has_skipped:
|
||||
self.report({"WARNING"}, "Some properties were skipped, see the system console for details.")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ImportQuickFavorites(bpy.types.Operator):
|
||||
bl_idname = "bim.import_quick_favorites"
|
||||
bl_label = "Import Quick Favorites"
|
||||
bl_description = "Import operators from Blender's Quick Favorites menu, including their configured properties"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Misc.get_misc_props()
|
||||
props.quick_favorites.clear()
|
||||
|
||||
has_missing_props = False
|
||||
for i, qf in enumerate(tool.Misc.QuickFavorites.get_quick_favorites()):
|
||||
fav = props.quick_favorites.add()
|
||||
fav.label = qf.ui_name
|
||||
fav.search = qf.op_idname_py
|
||||
bpy.ops.bim.confirm_quick_favorite_operator(index=i)
|
||||
fav.label = qf.ui_name or fav.label
|
||||
|
||||
for prop in fav.properties:
|
||||
prop.is_active = prop.name in qf.props
|
||||
|
||||
for key, value in qf.props.items():
|
||||
if key not in fav.properties:
|
||||
print(f"Property '{key}' not found in operator '{qf.op_idname_py}'.")
|
||||
has_missing_props = True
|
||||
continue
|
||||
item = fav.properties[key]
|
||||
item.set_value(value)
|
||||
|
||||
if has_missing_props:
|
||||
self.report(
|
||||
{"WARNING"}, "Some properties were not found during import, see the system console for details."
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class MoveQuickFavoritesItem(bpy.types.Operator):
|
||||
bl_idname = "bim.move_quick_favorites_item"
|
||||
bl_label = "Move Quick Favorites Item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
index: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
|
||||
direction: bpy.props.EnumProperty( # pyright: ignore[reportRedeclaration]
|
||||
items=[("UP", "Up", ""), ("DOWN", "Down", "")]
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
index: int
|
||||
direction: Literal["UP", "DOWN"]
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Misc.get_misc_props()
|
||||
total = len(props.quick_favorites)
|
||||
new_index = self.index - 1 if self.direction == "UP" else self.index + 1
|
||||
if 0 <= new_index < total:
|
||||
props.quick_favorites.move(self.index, new_index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveQuickFavoritesItem(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_quick_favorites_item"
|
||||
bl_label = "Remove Quick Favorites Item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
index: bpy.props.IntProperty() # pyright: ignore[reportRedeclaration]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
index: int
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Misc.get_misc_props()
|
||||
props.quick_favorites.remove(self.index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddQuickFavoritesItem(bpy.types.Operator):
|
||||
bl_idname = "bim.add_quick_favorites_item"
|
||||
bl_label = "Add Quick Favorites Item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Misc.get_misc_props()
|
||||
fav = props.quick_favorites.add()
|
||||
fav.search = "bim.select_query_elements"
|
||||
index = len(props.quick_favorites) - 1
|
||||
bpy.ops.bim.confirm_quick_favorite_operator(index=index)
|
||||
fav.properties["query"].string_value = "IfcWall"
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class IfcSverchokUseBonsaiFile(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.ifcsverchok_use_bonsai_file"
|
||||
bl_label = "Use Bonsai IFC File"
|
||||
|
||||
@@ -16,19 +16,140 @@
|
||||
# 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, Any, Literal, cast, get_args
|
||||
|
||||
import bpy
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
CollectionProperty,
|
||||
EnumProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
IntProperty,
|
||||
StringProperty,
|
||||
)
|
||||
from bpy.types import PropertyGroup
|
||||
|
||||
from bonsai.bim.module.misc.data import QuickFavoritesData
|
||||
|
||||
QuickFavoriteValueType = Literal["float_value", "bool_value", "int_value", "string_value", "enum_value"]
|
||||
|
||||
|
||||
class QuickFavoriteEnumItem(PropertyGroup):
|
||||
name: StringProperty(name="Name", default="") # pyright: ignore[reportRedeclaration]
|
||||
display_name: StringProperty(name="Display Name", default="") # pyright: ignore[reportRedeclaration]
|
||||
description: StringProperty(name="Description", default="") # pyright: ignore[reportRedeclaration]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
name: str
|
||||
display_name: str
|
||||
description: str
|
||||
|
||||
|
||||
def get_enum_items(self: "QuickFavoriteProperty", context: bpy.types.Context | None) -> list[tuple[str, str, str]]:
|
||||
return [(item.name, item.display_name, item.description) for item in self.enum_items]
|
||||
|
||||
|
||||
class QuickFavoriteProperty(PropertyGroup):
|
||||
name: StringProperty(name="Name", default="") # pyright: ignore[reportRedeclaration]
|
||||
display_name: StringProperty(name="Display Name", default="") # pyright: ignore[reportRedeclaration]
|
||||
value_prop: EnumProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Value Prop",
|
||||
items=tuple((v, v, "") for v in get_args(QuickFavoriteValueType)),
|
||||
)
|
||||
string_value: StringProperty(name="String Value", default="") # pyright: ignore[reportRedeclaration]
|
||||
float_value: FloatProperty(name="Float Value", default=0.0) # pyright: ignore[reportRedeclaration]
|
||||
int_value: IntProperty(name="Int Value", default=0) # pyright: ignore[reportRedeclaration]
|
||||
bool_value: BoolProperty(name="Bool Value", default=False) # pyright: ignore[reportRedeclaration]
|
||||
enum_value: EnumProperty(name="Enum Value", items=get_enum_items) # pyright: ignore[reportRedeclaration]
|
||||
enum_items: CollectionProperty(type=QuickFavoriteEnumItem) # pyright: ignore[reportRedeclaration]
|
||||
is_active: BoolProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Is Active",
|
||||
description="Only active properties will be added to the operator when invoked from Quick Favorites",
|
||||
default=False,
|
||||
)
|
||||
|
||||
def set_value(self, value: Any) -> None:
|
||||
setattr(self, self.value_prop, value)
|
||||
|
||||
def set_enum_items(self, items: list[tuple[str, str, str]]) -> None:
|
||||
self.enum_items.clear()
|
||||
for identifier, name, description in items:
|
||||
item = self.enum_items.add()
|
||||
item.name = identifier
|
||||
item.display_name = name
|
||||
item.description = description
|
||||
|
||||
if TYPE_CHECKING:
|
||||
name: str
|
||||
display_name: str
|
||||
value_prop: QuickFavoriteValueType
|
||||
string_value: str
|
||||
float_value: float
|
||||
int_value: int
|
||||
bool_value: bool
|
||||
enum_value: str
|
||||
enum_items: bpy.types.bpy_prop_collection_idprop[QuickFavoriteEnumItem]
|
||||
is_active: bool
|
||||
|
||||
|
||||
def get_operator_suggestions(self: "QuickFavoritesItem", context: bpy.types.Context, edit_text: str) -> list[str]:
|
||||
if not QuickFavoritesData.is_loaded:
|
||||
QuickFavoritesData.load()
|
||||
return QuickFavoritesData.data["operators"]
|
||||
|
||||
|
||||
class QuickFavoritesItem(PropertyGroup):
|
||||
is_expanded: BoolProperty(name="Is Expanded", default=False) # pyright: ignore[reportRedeclaration]
|
||||
search: StringProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Search",
|
||||
default="",
|
||||
search=get_operator_suggestions,
|
||||
# Resetting `search_options`, allowing users only to use suggestions.
|
||||
search_options=set(),
|
||||
)
|
||||
properties: CollectionProperty(type=QuickFavoriteProperty) # pyright: ignore[reportRedeclaration]
|
||||
operator_id: StringProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Operator ID",
|
||||
default="",
|
||||
)
|
||||
label: StringProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Label",
|
||||
description="Label that will be used in Quick Favorites for this operator",
|
||||
default="",
|
||||
)
|
||||
|
||||
def get_searched_operator(self) -> bpy.types.Struct | None:
|
||||
if not self.search:
|
||||
return None
|
||||
search_label = self.search
|
||||
name = search_label.split(" - ", 1)[0]
|
||||
module, func = name.split(".", 1)
|
||||
op = getattr(getattr(bpy.ops, module), func)
|
||||
rna = cast(bpy.types.Struct, op.get_rna_type())
|
||||
return rna
|
||||
|
||||
if TYPE_CHECKING:
|
||||
is_expanded: bool
|
||||
search: str
|
||||
"""Internal property set when confirming results of the search field"""
|
||||
properties: bpy.types.bpy_prop_collection_idprop[QuickFavoriteProperty]
|
||||
operator_id: str
|
||||
label: str
|
||||
|
||||
|
||||
class BIMMiscProperties(PropertyGroup):
|
||||
total_storeys: IntProperty(
|
||||
total_storeys: IntProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Total Storeys",
|
||||
description="Number of storeys above object's storey to take into account for resizing",
|
||||
default=1,
|
||||
)
|
||||
override_colour: FloatVectorProperty(
|
||||
override_colour: FloatVectorProperty( # pyright: ignore[reportRedeclaration]
|
||||
name="Override Colour", subtype="COLOR", default=(1, 0, 0, 1), min=0.0, max=1.0, size=4
|
||||
)
|
||||
quick_favorites: CollectionProperty(type=QuickFavoritesItem) # pyright: ignore[reportRedeclaration]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
total_storeys: int
|
||||
override_colour: tuple[float, float, float, float]
|
||||
quick_favorites: bpy.types.bpy_prop_collection_idprop[QuickFavoritesItem]
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
import bpy
|
||||
|
||||
import bonsai.tool as tool
|
||||
|
||||
|
||||
class BIM_PT_misc_utilities(bpy.types.Panel):
|
||||
bl_idname = "BIM_PT_misc_utilities"
|
||||
@@ -30,7 +32,8 @@ class BIM_PT_misc_utilities(bpy.types.Panel):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = context.scene.BIMMiscProperties
|
||||
assert layout
|
||||
props = tool.Misc.get_misc_props()
|
||||
row = layout.split(factor=0.2, align=True)
|
||||
row.prop(props, "override_colour", text="")
|
||||
row.operator("bim.set_override_colour")
|
||||
@@ -56,3 +59,72 @@ class BIM_PT_misc_utilities(bpy.types.Panel):
|
||||
row.operator("bim.disable_editing_sketch_extrusion_profile", text="", icon="CANCEL")
|
||||
row = layout.row()
|
||||
row.operator("bim.import_plot", text="Import Plot Coordinates", icon="FILE_FOLDER")
|
||||
|
||||
|
||||
class BIM_PT_quick_favorites_manager(bpy.types.Panel):
|
||||
bl_idname = "BIM_PT_quick_favorites_manager"
|
||||
bl_label = "Quick Favorites Manager"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "output"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_parent_id = "BIM_PT_tab_sandbox"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
assert layout
|
||||
props = tool.Misc.get_misc_props()
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.label(text="Quick Favorites:")
|
||||
row.operator("bim.add_quick_favorites_item", text="", icon="ADD")
|
||||
row.operator("bim.import_quick_favorites", text="", icon="BLENDER")
|
||||
op = row.operator("bim.show_description", text="", icon="INFO")
|
||||
op.attr_name = "Quick Favorites Manager"
|
||||
op.description = (
|
||||
"Blender does not support editing Quick Favorites natively. "
|
||||
"This manager allows you to load existing Quick Favorites operators, "
|
||||
"configure their properties and labels, and re-add them to the menu with customized settings."
|
||||
)
|
||||
|
||||
for fav in props.quick_favorites:
|
||||
if fav.operator_id:
|
||||
row = layout.row()
|
||||
op = row.operator(fav.operator_id, text=fav.label)
|
||||
for item in fav.properties:
|
||||
if item.is_active:
|
||||
setattr(op, item.name, getattr(item, item.value_prop))
|
||||
|
||||
layout.separator()
|
||||
|
||||
for i, fav in enumerate(props.quick_favorites):
|
||||
box = layout.box()
|
||||
row = box.row(align=True)
|
||||
row.prop(fav, "is_expanded", text="", icon="TRIA_DOWN" if fav.is_expanded else "TRIA_RIGHT", emboss=False)
|
||||
row.prop(fav, "label", text="")
|
||||
if i > 0:
|
||||
up = row.operator("bim.move_quick_favorites_item", text="", icon="TRIA_UP")
|
||||
up.index = i
|
||||
up.direction = "UP"
|
||||
if i < len(props.quick_favorites) - 1:
|
||||
down = row.operator("bim.move_quick_favorites_item", text="", icon="TRIA_DOWN")
|
||||
down.index = i
|
||||
down.direction = "DOWN"
|
||||
row.operator("bim.remove_quick_favorites_item", text="", icon="X").index = i
|
||||
if not fav.is_expanded:
|
||||
continue
|
||||
row = box.row(align=True)
|
||||
row.prop(fav, "search", text="")
|
||||
row.operator("bim.confirm_quick_favorite_operator", text="", icon="VIEWZOOM").index = i
|
||||
if not fav.operator_id:
|
||||
continue
|
||||
layout.separator()
|
||||
if fav.properties:
|
||||
box.label(text="Properties:")
|
||||
prop_box = box.box()
|
||||
for item in fav.properties:
|
||||
row = prop_box.row(align=True)
|
||||
row.prop(item, item.value_prop, text=item.display_name)
|
||||
row.prop(item, "is_active", text="", icon="RADIOBUT_ON" if item.is_active else "RADIOBUT_OFF")
|
||||
else:
|
||||
box.label(text="No Properties.")
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from math import cos, radians, sin, tan
|
||||
from math import cos, pi, radians, sin, tan
|
||||
from typing import Any, Literal
|
||||
|
||||
import blf
|
||||
@@ -27,6 +27,10 @@ import bmesh
|
||||
import bpy
|
||||
import gpu
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import mathutils
|
||||
from bpy.types import SpaceView3D
|
||||
from bpy_extras import view3d_utils
|
||||
@@ -35,6 +39,7 @@ from gpu_extras.batch import batch_for_shader
|
||||
from gpu_extras.presets import draw_circle_2d
|
||||
from mathutils import Matrix, Quaternion, Vector
|
||||
|
||||
import bonsai.core.geometry
|
||||
import bonsai.tool as tool
|
||||
from bonsai.bim.module.drawing.helper import format_distance
|
||||
|
||||
@@ -1566,7 +1571,7 @@ class ProductDecorator:
|
||||
obj_type,
|
||||
representation,
|
||||
)
|
||||
context.view_layer.update()
|
||||
bpy.context.view_layer.update()
|
||||
break
|
||||
|
||||
translate_mouse = Matrix.Translation(mouse_point)
|
||||
|
||||
@@ -733,6 +733,9 @@ class BIMStairProperties(PropertyGroup):
|
||||
class BIMSverchokProperties(PropertyGroup):
|
||||
node_group: bpy.props.PointerProperty(name="Node Group", type=NodeTree)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
node_group: bpy.types.NodeTree | None
|
||||
|
||||
|
||||
def window_type_prop_update(self, context):
|
||||
number_of_panels, panels_data = self.window_types_panels[self.window_type]
|
||||
|
||||
@@ -31,7 +31,7 @@ import bonsai.tool as tool
|
||||
|
||||
def update_sverchok_modifier(context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(obj)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
pset = psets.get("BBIM_Sverchok", None)
|
||||
@@ -69,10 +69,10 @@ class CreateNewSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
def _execute(self, context):
|
||||
import sverchok
|
||||
import sverchok.ui.sv_temporal_viewers
|
||||
|
||||
obj = context.active_object
|
||||
props = obj.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(obj)
|
||||
|
||||
node_group = bpy.data.node_groups.new("IfcNodeTree", type="SverchCustomTreeType")
|
||||
plane = node_group.nodes.new(type="SvPlaneNodeMk3")
|
||||
@@ -96,7 +96,7 @@ class DeleteSverchokGraph(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(obj)
|
||||
bpy.data.node_groups.remove(props.node_group)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -113,7 +113,8 @@ class UpdateDataFromSverchok(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
if not context.active_object.BIMSverchokProperties.node_group:
|
||||
props = tool.Model.get_sverchok_props(context.active_object)
|
||||
if not props.node_group:
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
return self._execute(context)
|
||||
|
||||
@@ -124,7 +125,7 @@ class UpdateDataFromSverchok(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(obj)
|
||||
node_group = props.node_group
|
||||
|
||||
if node_group:
|
||||
@@ -192,11 +193,11 @@ class ImportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ImportHelper):
|
||||
filename_ext = ".json"
|
||||
|
||||
def _execute(self, context):
|
||||
import sverchok
|
||||
import sverchok.utils.sv_json_import
|
||||
|
||||
importer = sverchok.utils.sv_json_import.JSONImporter.init_from_path(self.filepath)
|
||||
obj = context.active_object
|
||||
props = obj.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(obj)
|
||||
|
||||
node_group = context.scene.io_panel_properties.import_tree
|
||||
if not node_group:
|
||||
@@ -231,10 +232,10 @@ class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ExportHelper):
|
||||
compress: bpy.props.BoolProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
import sverchok
|
||||
import sverchok.utils.sv_json_export
|
||||
|
||||
obj = context.active_object
|
||||
props = obj.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(obj)
|
||||
ng = props.node_group
|
||||
destination_path = self.filepath
|
||||
if not destination_path.lower().endswith(".json"):
|
||||
@@ -273,7 +274,8 @@ class ExportSverchokGraph(bpy.types.Operator, tool.Ifc.Operator, ExportHelper):
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
graph_name = context.active_object.BIMSverchokProperties.node_group.name
|
||||
props = tool.Model.get_sverchok_props(context.active_object)
|
||||
graph_name = props.node_group.name
|
||||
self.layout.label(text=f'Save node tree "{graph_name}" into json:')
|
||||
|
||||
col = self.layout.column(heading="Options") # new syntax in >= 2.90
|
||||
|
||||
@@ -360,7 +360,7 @@ class BIM_PT_sverchok(bpy.types.Panel):
|
||||
self.layout.label(text="Requires Sverchok Add-on", icon="ERROR")
|
||||
return
|
||||
|
||||
props = context.active_object.BIMSverchokProperties
|
||||
props = tool.Model.get_sverchok_props(context.active_object)
|
||||
self.layout.prop_search(props, "node_group", bpy.data, "node_groups")
|
||||
self.layout.operator("bim.create_new_sverchok_graph", icon="ADD")
|
||||
|
||||
|
||||
@@ -215,8 +215,6 @@ class NestDecorator:
|
||||
self.draw_batch("LINES", line_z, color, [(0, 1)])
|
||||
else:
|
||||
self.draw_batch("POINTS", [location], color)
|
||||
# if context.scene.BIMNestProperties.in_aggregate_mode:
|
||||
# return
|
||||
components = ifcopenshell.util.element.get_components(tool.Ifc.get_entity(nest))
|
||||
components_objs = [tool.Ifc.get_object(p) for p in components]
|
||||
components_objs.append(nest)
|
||||
|
||||
@@ -2142,6 +2142,7 @@ class LoadLinkedProject(bpy.types.Operator, ImportHelper):
|
||||
if iterator.initialize():
|
||||
while True: # Main loop.
|
||||
shape = iterator.get()
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
results.add(self.file.by_id(shape.id))
|
||||
geometry = shape.geometry
|
||||
|
||||
@@ -2372,18 +2373,23 @@ class HideQueriedLinkedElement(bpy.types.Operator):
|
||||
bl_label = "Hide Queried Linked Element"
|
||||
bl_description = (
|
||||
"Hide geometry for currently queried linked element.\n\n"
|
||||
"ALT+Click (or ALT+H in Explore Tool) to unhide all geometry for currently selected linked model.\n"
|
||||
"(Not Yet Implemented) SHIFT+Click to hide everything but currently queried element."
|
||||
"SHIFT+Click (or SHIFT+H in Explore Tool) to hide everything "
|
||||
"in the currently selected model, but the queried element.\n"
|
||||
"ALT+Click (or ALT+H in Explore Tool) to unhide all geometry for currently selected linked model.\n\n"
|
||||
"Known limitation: doesn't work with UNDO."
|
||||
)
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
unhide_all: bpy.props.BoolProperty(options={"SKIP_SAVE"}) # pyright: ignore[reportRedeclaration]
|
||||
hide_all_except: bpy.props.BoolProperty(options={"SKIP_SAVE"}) # pyright: ignore[reportRedeclaration]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
unhide_all: bool
|
||||
hide_all_except: bool
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.unhide_all = event.alt
|
||||
self.hide_all_except = event.shift
|
||||
return self.execute(context)
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
@@ -2392,6 +2398,9 @@ class HideQueriedLinkedElement(bpy.types.Operator):
|
||||
if self.unhide_all:
|
||||
return self.run_unhide_all()
|
||||
|
||||
if self.hide_all_except:
|
||||
return self.run_hide_all_except()
|
||||
|
||||
obj = props.queried_obj
|
||||
if not obj:
|
||||
self.report({"INFO"}, "No object is queried to hide.")
|
||||
@@ -2413,6 +2422,21 @@ class HideQueriedLinkedElement(bpy.types.Operator):
|
||||
self.report({"INFO"}, "All linked model geometry is unhidden.")
|
||||
return {"FINISHED"}
|
||||
|
||||
def run_hide_all_except(self) -> set["rna_enums.OperatorReturnItems"]:
|
||||
props = tool.Project.get_project_props()
|
||||
obj = props.queried_obj
|
||||
if not obj:
|
||||
self.report({"INFO"}, "No object is queried.")
|
||||
return {"FINISHED"}
|
||||
link = props.active_link
|
||||
if not link:
|
||||
self.report({"INFO"}, "No linked model is currently selected.")
|
||||
return {"FINISHED"}
|
||||
guid = props.queried_guid
|
||||
tool.Project.Link.hide_all_elements_except(link, obj, guid)
|
||||
self.report({"INFO"}, "All other linked model geometry is now hidden.")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AppendInspectedLinkedElement(AppendLibraryElement):
|
||||
bl_idname = "bim.append_inspected_linked_element"
|
||||
@@ -2698,10 +2722,7 @@ class CreateClippingPlane(bpy.types.Operator):
|
||||
self.report({"INFO"}, "Maximum of six clipping planes allowed.")
|
||||
return {"FINISHED"}
|
||||
|
||||
assert context.screen
|
||||
for area in context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
tool.Blender.update_all_viewports(context)
|
||||
|
||||
assert context.region and context.region_data
|
||||
region = context.region
|
||||
|
||||
@@ -230,11 +230,11 @@ class Link(PropertyGroup):
|
||||
)
|
||||
georeferenced: EnumProperty(
|
||||
name="Georeferenced",
|
||||
description="Georeferencing status: compatibility between host and linked model",
|
||||
description="Georeferencing status, compatibility between host and linked model",
|
||||
items=[
|
||||
("NONE", "No Georef", "Linked model has no georeferencing"),
|
||||
("NOT_COMPATIBLE", "Not Compatible", "Has geo data but CRS differ from host"),
|
||||
("FULL_COMPATIBLE", "Full Compatible", "Both CRS name and vertical datum match host"),
|
||||
("NONE", "No Georef", "Linked model has no georeferencing", "QUESTION", 0),
|
||||
("NOT_COMPATIBLE", "Not Compatible", "Has geo data but CRS differ from host", "ERROR", 1),
|
||||
("FULL_COMPATIBLE", "Full Compatible", "Both CRS name and vertical datum match host", "WORLD", 2),
|
||||
],
|
||||
default="NONE",
|
||||
)
|
||||
|
||||
@@ -255,7 +255,7 @@ class BIM_PT_project(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.load_project_elements")
|
||||
|
||||
def draw_editing_buttons(self, context, row):
|
||||
def draw_editing_buttons(self, context: object, row: bpy.types.UILayout) -> None:
|
||||
pprops = self.props
|
||||
if tool.Ifc.get():
|
||||
if pprops.is_editing:
|
||||
@@ -619,12 +619,14 @@ class BIM_UL_links(UIList):
|
||||
):
|
||||
row = layout.row(align=True)
|
||||
if item.is_loaded:
|
||||
if item.georeferenced == "NONE":
|
||||
row.label(text="", icon="QUESTION")
|
||||
elif item.georeferenced == "NOT_COMPATIBLE":
|
||||
row.label(text="", icon="ERROR")
|
||||
elif item.georeferenced == "FULL_COMPATIBLE":
|
||||
row.label(text="", icon="WORLD")
|
||||
from bonsai.bim.module.project.prop import Link
|
||||
|
||||
s = Link.bl_rna
|
||||
geo_prop = s.properties["georeferenced"]
|
||||
assert isinstance(geo_prop, bpy.types.EnumProperty)
|
||||
enum_item = geo_prop.enum_items[item.georeferenced]
|
||||
op = row.operator("bim.show_description", text="", icon=enum_item.icon, emboss=False)
|
||||
op.description = f"{geo_prop.description}\n{enum_item.name}: {enum_item.description}"
|
||||
if item.has_transformation:
|
||||
row.label(text="", icon="OBJECT_ORIGIN")
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class ExploreTool(bpy.types.WorkSpaceTool):
|
||||
("bim.explore_hotkey", {"type": "M", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_M")]}),
|
||||
("bim.explore_hotkey", {"type": "S", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_S")]}),
|
||||
("bim.explore_hotkey", {"type": "H", "value": "PRESS"}, {"properties": [("hotkey", "H")]}),
|
||||
("bim.explore_hotkey", {"type": "H", "value": "PRESS", "shift": True}, {"properties": [("hotkey", "S_H")]}),
|
||||
("bim.explore_hotkey", {"type": "H", "value": "PRESS", "alt": True}, {"properties": [("hotkey", "A_H")]}),
|
||||
)
|
||||
|
||||
@@ -147,5 +148,8 @@ class ExploreHotkey(bpy.types.Operator):
|
||||
def hotkey_H(self) -> None:
|
||||
bpy.ops.bim.hide_queried_linked_element()
|
||||
|
||||
def hotkey_S_H(self) -> None:
|
||||
bpy.ops.bim.hide_queried_linked_element(hide_all_except=True)
|
||||
|
||||
def hotkey_A_H(self) -> None:
|
||||
bpy.ops.bim.hide_queried_linked_element(unhide_all=True)
|
||||
|
||||
@@ -188,7 +188,7 @@ class BIMResourceProperties(PropertyGroup):
|
||||
@property
|
||||
def productivity(self) -> "BIMResourceProductivity":
|
||||
assert bpy.context.scene
|
||||
productivity = bpy.context.scene.BIMResourceProductivity
|
||||
productivity = bpy.context.scene.BIMResourceProductivity # pyright: ignore[reportAttributeAccessIssue]
|
||||
assert isinstance(productivity, BIMResourceProductivity)
|
||||
return productivity
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ classes = (
|
||||
operator.SelectByProperty,
|
||||
operator.SelectFilterElements,
|
||||
operator.SelectGlobalId,
|
||||
operator.SelectQueryElements,
|
||||
operator.SelectIfcClass,
|
||||
operator.SelectSimilar,
|
||||
operator.ShowAllElements,
|
||||
|
||||
@@ -42,6 +42,8 @@ from bonsai.bim.ifc import IfcStore
|
||||
from bonsai.bim.prop import StrProperty
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bpy.stub_internal import rna_enums
|
||||
|
||||
from bonsai.bim.prop import BIMFacet
|
||||
|
||||
|
||||
@@ -791,6 +793,27 @@ class Search(Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectQueryElements(Operator):
|
||||
bl_idname = "bim.select_query_elements"
|
||||
bl_label = "Select Query Elements"
|
||||
bl_description = "Select elements matching an provided selector query"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
query: StringProperty(name="Query") # pyright: ignore[reportRedeclaration]
|
||||
|
||||
if TYPE_CHECKING:
|
||||
query: str
|
||||
|
||||
def execute(self, context) -> set["rna_enums.OperatorReturnItems"]:
|
||||
results = ifcopenshell.util.selector.filter_elements(tool.Ifc.get(), self.query)
|
||||
objs = [obj for e in results if isinstance(obj := tool.Ifc.get_object(e), bpy.types.Object)]
|
||||
active_object = context.active_object or next(iter(objs), None)
|
||||
selection = tool.Blender.validate_object_selection(context, active_object, objs)
|
||||
tool.Blender.set_objects_selection(*selection, clear_previous_selection=False)
|
||||
self.report({"INFO"}, f"{len(results)} Results, {len(selection.selected_objects)} Objects Selected")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SaveSearch(Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.save_search"
|
||||
bl_label = "Save Search"
|
||||
@@ -1053,8 +1076,8 @@ class ColourByProperty(Operator):
|
||||
colourscheme[str(values[index])]["total"] += 1
|
||||
obj.color = (*tool.Search.get_quantitative_palette(palette, value, min_value, max_value), 1)
|
||||
|
||||
if areas := [a for a in context.screen.areas if a.type == "VIEW_3D"]:
|
||||
areas[0].spaces[0].shading.color_type = "OBJECT"
|
||||
assert (space := tool.Blender.get_view3d_space())
|
||||
space.shading.color_type = "OBJECT"
|
||||
|
||||
props.colourscheme.clear()
|
||||
|
||||
@@ -1078,16 +1101,18 @@ class ColourByProperty(Operator):
|
||||
return (1, value)
|
||||
|
||||
def store_state(self, context):
|
||||
if areas := [a for a in context.screen.areas if a.type == "VIEW_3D"]:
|
||||
self.transaction_data = {"area": areas[0], "color_type": areas[0].spaces[0].shading.color_type}
|
||||
if space := tool.Blender.get_view3d_space():
|
||||
self.transaction_data = {"color_type": space.shading.color_type}
|
||||
|
||||
def rollback(self, data):
|
||||
if data:
|
||||
data["area"].spaces[0].shading.color_type = data["color_type"]
|
||||
assert (space := tool.Blender.get_view3d_space())
|
||||
space.shading.color_type = data["color_type"]
|
||||
|
||||
def commit(self, data):
|
||||
if data:
|
||||
data["area"].spaces[0].shading.color_type = "OBJECT"
|
||||
assert (space := tool.Blender.get_view3d_space())
|
||||
space.shading.color_type = "OBJECT"
|
||||
|
||||
|
||||
class SelectByProperty(Operator):
|
||||
|
||||
@@ -16,6 +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/>.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
import bpy
|
||||
@@ -37,8 +39,11 @@ from bonsai.bim.module.sequence.data import (
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.sequence.prop import (
|
||||
BIMTaskTreeProperties,
|
||||
BIMTaskTypeColor,
|
||||
BIMWorkScheduleProperties,
|
||||
Task,
|
||||
TaskProduct,
|
||||
TaskResource,
|
||||
)
|
||||
from bonsai.bim.prop import Attribute
|
||||
|
||||
@@ -799,23 +804,24 @@ class BIM_UL_task_columns(UIList):
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: "BIMWorkScheduleProperties",
|
||||
item: "Attribute",
|
||||
data: BIMWorkScheduleProperties,
|
||||
item: Attribute,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
):
|
||||
props = tool.Sequence.get_work_schedule_props()
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.prop(item, "name", emboss=False, text="")
|
||||
if props.sort_column == item.name:
|
||||
if data.sort_column == item.name:
|
||||
row.label(text="", icon="SORTALPHA")
|
||||
row.operator("bim.remove_task_column", text="", icon="X").name = item.name
|
||||
|
||||
|
||||
class BIM_UL_task_inputs(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: TaskProduct, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.select_product", text="", icon="RESTRICT_SELECT_OFF")
|
||||
@@ -825,7 +831,9 @@ class BIM_UL_task_inputs(UIList):
|
||||
|
||||
|
||||
class BIM_UL_task_resources(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: TaskResource, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.go_to_resource", text="", icon="STYLUS_PRESSURE").resource = item.ifc_definition_id
|
||||
@@ -834,7 +842,9 @@ class BIM_UL_task_resources(UIList):
|
||||
|
||||
|
||||
class BIM_UL_animation_colors(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: BIMTaskTypeColor, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row()
|
||||
row.prop(item, "color", text="")
|
||||
@@ -842,7 +852,9 @@ class BIM_UL_animation_colors(UIList):
|
||||
|
||||
|
||||
class BIM_UL_task_outputs(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: TaskProduct, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.select_product", text="", icon="RESTRICT_SELECT_OFF")
|
||||
@@ -851,7 +863,9 @@ class BIM_UL_task_outputs(UIList):
|
||||
|
||||
|
||||
class BIM_UL_product_input_tasks(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: TaskProduct, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.go_to_task", text="", icon="STYLUS_PRESSURE")
|
||||
@@ -861,7 +875,9 @@ class BIM_UL_product_input_tasks(UIList):
|
||||
|
||||
|
||||
class BIM_UL_product_output_tasks(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: TaskProduct, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.go_to_task", text="", icon="STYLUS_PRESSURE")
|
||||
@@ -886,8 +902,8 @@ class BIM_UL_tasks(UIList):
|
||||
self,
|
||||
context,
|
||||
layout: bpy.types.UILayout,
|
||||
data: "BIMTaskTreeProperties",
|
||||
item: "Task",
|
||||
data: BIMTaskTreeProperties,
|
||||
item: Task,
|
||||
icon,
|
||||
active_data,
|
||||
active_propname,
|
||||
|
||||
@@ -512,7 +512,7 @@ class SetContainerVisibility(bpy.types.Operator):
|
||||
containers -= set(tool.Ifc.get().by_type("IfcSpatialZone"))
|
||||
for container in containers:
|
||||
if obj := tool.Ifc.get_object(container):
|
||||
if collection := obj.BIMObjectProperties.collection:
|
||||
if collection := tool.Blender.get_object_bim_props(obj).collection:
|
||||
collection.hide_viewport = True
|
||||
should_hide = False
|
||||
else:
|
||||
@@ -523,7 +523,7 @@ class SetContainerVisibility(bpy.types.Operator):
|
||||
while queue:
|
||||
container = queue.pop()
|
||||
if obj := tool.Ifc.get_object(container):
|
||||
if collection := obj.BIMObjectProperties.collection:
|
||||
if collection := tool.Blender.get_object_bim_props(obj).collection:
|
||||
collection.hide_viewport = should_hide
|
||||
if self.should_include_children:
|
||||
queue.extend(ifcopenshell.util.element.get_parts(container))
|
||||
|
||||
@@ -357,7 +357,7 @@ class BIM_UL_elements(UIList):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.use_filter_show = True
|
||||
|
||||
def draw_toggle(self, row: bpy.types.UILayout, is_expanded: bool, index: int):
|
||||
def draw_toggle(self, row: bpy.types.UILayout, is_expanded: bool, index: int) -> None:
|
||||
icon_id = "DISCLOSURE_TRI_DOWN" if is_expanded else "DISCLOSURE_TRI_RIGHT"
|
||||
row.operator("bim.toggle_container_element", text="", emboss=False, icon=icon_id).element_index = index
|
||||
|
||||
|
||||
@@ -42,14 +42,10 @@ class ShowLoads(bpy.types.Operator):
|
||||
assert context.screen
|
||||
if event.type == "F5":
|
||||
LoadsDecorator.update()
|
||||
for area in context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
tool.Blender.update_all_viewports(context)
|
||||
if event.type == "ESC":
|
||||
LoadsDecorator.uninstall()
|
||||
for area in context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
tool.Blender.update_all_viewports(context)
|
||||
return {"FINISHED"}
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
@@ -69,9 +65,7 @@ class ShowLoads(bpy.types.Operator):
|
||||
raise exc
|
||||
context.window.cursor_modal_restore()
|
||||
context.window_manager.modal_handler_add(self)
|
||||
for area in context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
tool.Blender.update_all_viewports(context)
|
||||
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
@@ -102,7 +102,10 @@ def update_shading_styles(self: "BIMStylesProperties", context: bpy.types.Contex
|
||||
|
||||
|
||||
def update_shader_graph(self: Union["Texture", "BIMStylesProperties"], context: bpy.types.Context) -> None:
|
||||
props = self.id_data.BIMStylesProperties if isinstance(self, Texture) else self
|
||||
if isinstance(self, Texture):
|
||||
props = tool.Style.get_style_props()
|
||||
else:
|
||||
props = self
|
||||
|
||||
if not props.update_graph:
|
||||
return
|
||||
|
||||
@@ -123,7 +123,6 @@ class BIM_UL_units(UIList):
|
||||
active_data,
|
||||
active_propname,
|
||||
) -> None:
|
||||
props = tool.Unit.get_unit_props()
|
||||
if item:
|
||||
icon = tool.Unit.get_icon_for_unit_class(item.ifc_class)
|
||||
row = layout.row(align=True)
|
||||
@@ -137,10 +136,10 @@ class BIM_UL_units(UIList):
|
||||
op = row.operator("bim.assign_unit", text="", icon="KEYFRAME", emboss=False)
|
||||
op.unit = item.ifc_definition_id
|
||||
|
||||
if props.active_unit_id == item.ifc_definition_id:
|
||||
if data.active_unit_id == item.ifc_definition_id:
|
||||
row.operator("bim.edit_unit", text="", icon="CHECKMARK").unit = item.ifc_definition_id
|
||||
row.operator("bim.disable_editing_unit", text="", icon="CANCEL")
|
||||
elif props.active_unit_id:
|
||||
elif data.active_unit_id:
|
||||
row.operator("bim.remove_unit", text="", icon="X").unit = item.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.enable_editing_unit", text="", icon="GREASEPENCIL")
|
||||
|
||||
@@ -29,6 +29,8 @@ from bonsai.bim.module.void.data import BooleansData, VoidsData
|
||||
if TYPE_CHECKING:
|
||||
import bpy.stub_internal.rna_enums as rna_enums
|
||||
|
||||
from bonsai.bim.module.void.prop import Boolean
|
||||
|
||||
|
||||
OPENING_ICON = "SELECT_SUBTRACT"
|
||||
FILLING_ICON = "SELECT_INTERSECT"
|
||||
@@ -175,7 +177,9 @@ class BIM_PT_booleans(Panel):
|
||||
|
||||
|
||||
class BIM_UL_booleans(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: Boolean, icon, active_data, active_propname
|
||||
) -> None:
|
||||
if item:
|
||||
if item.operator == "DIFFERENCE":
|
||||
icon = "SELECT_DIFFERENCE"
|
||||
|
||||
@@ -70,7 +70,7 @@ class SetTab(bpy.types.Operator):
|
||||
if context.area.spaces.active.search_filter:
|
||||
return {"FINISHED"}
|
||||
tool.Blender.setup_tabs()
|
||||
aprops = tool.Blender.get_area_props(context)
|
||||
aprops = tool.Blender.get_active_area_props(context)
|
||||
aprops.tab = self.tab
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -85,7 +85,7 @@ class SwitchTab(bpy.types.Operator):
|
||||
if context.area.spaces.active.search_filter:
|
||||
return {"FINISHED"}
|
||||
tool.Blender.setup_tabs()
|
||||
aprops = tool.Blender.get_area_props(context)
|
||||
aprops = tool.Blender.get_active_area_props(context)
|
||||
aprops.tab = aprops.alt_tab
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ def update_is_visible(self: "BIMTabVisibility", context: bpy.types.Context) -> N
|
||||
def update_global_tab(self: "BIMTabProperties", context: bpy.types.Context) -> None:
|
||||
tool.Blender.setup_tabs()
|
||||
screen = context.id_data
|
||||
aprops = screen.BIMAreaProperties[screen.areas[:].index(context.area)]
|
||||
assert isinstance(screen, bpy.types.Screen)
|
||||
aprops = tool.Blender.get_area_props(screen)[screen.areas[:].index(context.area)]
|
||||
aprops.tab = self.tab
|
||||
|
||||
|
||||
|
||||
@@ -16,19 +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/>.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.pset
|
||||
|
||||
import bonsai
|
||||
import bonsai.tool as tool
|
||||
|
||||
if TYPE_CHECKING or bpy.app.version >= (5, 0, 0):
|
||||
import _bpy_restrict_state as bpy_restrict_state
|
||||
else:
|
||||
import bpy_restrict_state
|
||||
|
||||
|
||||
class IfcSchema:
|
||||
data_dir: str
|
||||
@@ -62,7 +55,7 @@ class IfcSchema:
|
||||
self.psetqto.get_by_name.cache_clear()
|
||||
|
||||
# During register we cannot access the context either way.
|
||||
if isinstance(bpy.context, bpy_restrict_state._RestrictContext):
|
||||
if bonsai.is_registering():
|
||||
return
|
||||
for path in tool.Blender.get_data_dir_paths("pset", "*.ifc"):
|
||||
self.psetqto.templates.append(ifcopenshell.open(path))
|
||||
|
||||
@@ -1031,8 +1031,7 @@ class BIM_PT_tabs(Panel):
|
||||
def draw(self, context):
|
||||
if not UIData.is_loaded:
|
||||
UIData.load()
|
||||
aprops = tool.Blender.get_area_props(context)
|
||||
addon_prefs = tool.Blender.get_addon_preferences()
|
||||
aprops = tool.Blender.get_active_area_props(context)
|
||||
|
||||
row = self.layout.row()
|
||||
row.alignment = "CENTER"
|
||||
@@ -1119,7 +1118,9 @@ class BIM_PT_tabs(Panel):
|
||||
op = row.operator("bim.open_uri", text="", icon="QUESTION")
|
||||
op.uri = "https://docs.bonsaibim.org/guides/troubleshooting.html#incompatible-blender-features"
|
||||
|
||||
def draw_tab_entry(self, row, icon, tab_name, enabled=True, highlight=True):
|
||||
def draw_tab_entry(
|
||||
self, row: bpy.types.UILayout, icon: int | str, tab_name: str, enabled: bool = True, highlight: bool = True
|
||||
) -> None:
|
||||
tab_entry = row.row(align=True)
|
||||
if isinstance(icon, int):
|
||||
tab_entry.operator("bim.set_tab", text="", emboss=highlight, icon_value=icon).tab = tab_name
|
||||
|
||||
@@ -99,6 +99,7 @@ class Blender:
|
||||
def get_object_bounding_box(cls, obj): pass
|
||||
def get_selected_objects(cls, include_active=False): pass
|
||||
def get_viewport_context(cls): pass
|
||||
def operator_idname_to_py(cls, idname): pass
|
||||
def is_ifc_class_active(cls, ifc_class): pass
|
||||
def is_ifc_object(cls, obj): pass
|
||||
def remove_object(cls, obj): pass
|
||||
|
||||
@@ -74,7 +74,13 @@ if TYPE_CHECKING:
|
||||
BIMSolarProperties,
|
||||
RadianceExporterProperties,
|
||||
)
|
||||
from bonsai.bim.prop import BIMObjectProperties, BIMProperties
|
||||
from bonsai.bim.prop import (
|
||||
BIMAreaProperties,
|
||||
BIMCollectionProperties,
|
||||
BIMObjectProperties,
|
||||
BIMProperties,
|
||||
BIMTabProperties,
|
||||
)
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@@ -138,17 +144,20 @@ class Blender(bonsai.core.tool.Blender):
|
||||
space.region_3d.view_perspective = "CAMERA"
|
||||
|
||||
@classmethod
|
||||
def get_area_props(cls, context: bpy.types.Context) -> bpy.types.PropertyGroup:
|
||||
def get_active_area_props(cls, context: bpy.types.Context) -> BIMAreaProperties | BIMTabProperties:
|
||||
FULLSCREEN_SUFFIX = "-nonnormal" # Ctrl-space temporary fullscreen
|
||||
assert (screen := context.screen)
|
||||
try:
|
||||
if context.screen.name.endswith("-nonnormal"): # Ctrl-space temporary fullscreen
|
||||
screen = bpy.data.screens[context.screen.name.removesuffix("-nonnormal")]
|
||||
if screen.name.endswith(FULLSCREEN_SUFFIX):
|
||||
screen = bpy.data.screens[screen.name.removesuffix(FULLSCREEN_SUFFIX)]
|
||||
# The original area object has its type changed to "EMPTY" apparently
|
||||
index = [a.type for a in screen.areas].index("EMPTY")
|
||||
return screen.BIMAreaProperties[index]
|
||||
return context.screen.BIMAreaProperties[context.screen.areas[:].index(context.area)]
|
||||
return cls.get_area_props(screen)[index]
|
||||
assert (area := context.area)
|
||||
return cls.get_area_props(screen)[screen.areas[:].index(area)]
|
||||
except IndexError:
|
||||
# Fallback in case areas aren't setup yet.
|
||||
return context.screen.BIMTabProperties
|
||||
return cls.get_tab_props(screen)
|
||||
|
||||
@classmethod
|
||||
def set_active_object(cls, obj: bpy.types.Object) -> None:
|
||||
@@ -165,15 +174,16 @@ class Blender(bonsai.core.tool.Blender):
|
||||
def setup_tabs(cls) -> None:
|
||||
# https://blender.stackexchange.com/questions/140644/how-can-make-the-state-of-a-boolean-property-relative-to-the-3d-view-area
|
||||
for screen in bpy.data.screens:
|
||||
if len(screen.BIMAreaProperties) == 20:
|
||||
area_props = cls.get_area_props(screen)
|
||||
if len(area_props) == 20:
|
||||
continue
|
||||
screen.BIMAreaProperties.clear()
|
||||
area_props.clear()
|
||||
for i in range(20): # 20 is an arbitrary value of split areas
|
||||
screen.BIMAreaProperties.add()
|
||||
area_props.add()
|
||||
|
||||
@classmethod
|
||||
def should_show_panel(cls, context: bpy.types.Context, tab: str, panel: str) -> bool:
|
||||
aprops = cls.get_area_props(context)
|
||||
aprops = cls.get_active_area_props(context)
|
||||
if aprops.path_from_id() == "BIMAreaProperties" and context.area.spaces.active.search_filter:
|
||||
return True
|
||||
if (is_bookmark_tab := aprops.tab == "BOOKMARK") or aprops.tab == tab:
|
||||
@@ -185,6 +195,7 @@ class Blender(bonsai.core.tool.Blender):
|
||||
return True
|
||||
elif panel_visibility.is_visible:
|
||||
return True
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def is_default_scene(cls) -> bool:
|
||||
@@ -330,15 +341,27 @@ class Blender(bonsai.core.tool.Blender):
|
||||
|
||||
@classmethod
|
||||
def get_view3d_area(cls) -> Union[bpy.types.Area, None]:
|
||||
for window in bpy.context.window_manager.windows:
|
||||
assert (wm := bpy.context.window_manager)
|
||||
for window in wm.windows:
|
||||
for area in window.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
return area
|
||||
|
||||
@classmethod
|
||||
def operator_idname_to_py(cls, idname: str) -> str:
|
||||
"""Convert a Blender internal operator idname to its Python equivalent.
|
||||
|
||||
Example: ``MESH_OT_primitive_cube_add`` -> ``mesh.primitive_cube_add``
|
||||
"""
|
||||
module, func = idname.split("_OT_", 1)
|
||||
return f"{module.lower()}.{func}"
|
||||
|
||||
@classmethod
|
||||
def get_view3d_space(cls) -> Union[bpy.types.SpaceView3D, None]:
|
||||
if area := cls.get_view3d_area():
|
||||
return area.spaces.active
|
||||
space = area.spaces.active
|
||||
assert isinstance(space, bpy.types.SpaceView3D)
|
||||
return space
|
||||
|
||||
@classmethod
|
||||
def get_blender_prop_default_value(cls, props: bpy.types.bpy_struct, prop_name: str) -> Any:
|
||||
@@ -459,6 +482,14 @@ class Blender(bonsai.core.tool.Blender):
|
||||
def update_viewport(cls) -> None:
|
||||
cls.get_viewport_context()["area"].tag_redraw()
|
||||
|
||||
@classmethod
|
||||
def update_all_viewports(cls, context: bpy.types.Context | None = None) -> None:
|
||||
context = context or bpy.context
|
||||
assert context.screen
|
||||
for area in context.screen.areas:
|
||||
if area.type == "VIEW_3D":
|
||||
area.tag_redraw()
|
||||
|
||||
@classmethod
|
||||
def force_depsgraph_update(cls) -> None:
|
||||
"""useful if you need to trigger callbacks like `depsgraph_update_pre`"""
|
||||
@@ -1489,7 +1520,7 @@ class Blender(bonsai.core.tool.Blender):
|
||||
def override_scene_panel(cls, original_panel: bpy.types.Panel) -> None:
|
||||
@classmethod
|
||||
def poll_check_blender_tab(cls, context):
|
||||
aprops = tool.Blender.get_area_props(context)
|
||||
aprops = tool.Blender.get_active_area_props(context)
|
||||
if aprops.path_from_id() == "BIMAreaProperties" and context.area.spaces.active.search_filter:
|
||||
return True
|
||||
return aprops.tab == "BLENDER"
|
||||
@@ -1829,6 +1860,18 @@ class Blender(bonsai.core.tool.Blender):
|
||||
assert (scene := bpy.context.scene)
|
||||
return scene.BIMProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_area_props(cls, screen: bpy.types.Screen) -> bpy.types.bpy_prop_collection_idprop[BIMAreaProperties]:
|
||||
return screen.BIMAreaProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_tab_props(cls, screen: bpy.types.Screen) -> BIMTabProperties:
|
||||
return screen.BIMTabProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_collection_props(cls, collection: bpy.types.Collection) -> BIMCollectionProperties:
|
||||
return collection.BIMCollectionProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_object_bim_props(cls, obj: bpy.types.Object) -> BIMObjectProperties:
|
||||
return obj.BIMObjectProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
@@ -1882,19 +1925,21 @@ class Blender(bonsai.core.tool.Blender):
|
||||
@classmethod
|
||||
def clear_undo_history(cls) -> None:
|
||||
"""Clears the Blender history, Bonsai history, and IfcOpenShell history"""
|
||||
old_undo_steps = bpy.context.preferences.edit.undo_steps
|
||||
bpy.context.preferences.edit.undo_steps = 2
|
||||
assert (preferences := bpy.context.preferences)
|
||||
old_undo_steps = preferences.edit.undo_steps
|
||||
preferences.edit.undo_steps = 2
|
||||
for i in range(3):
|
||||
bpy.ops.ed.undo_push(message="Undo history cleared")
|
||||
bpy.context.preferences.edit.undo_steps = old_undo_steps
|
||||
preferences.edit.undo_steps = old_undo_steps
|
||||
tool.Ifc.clear_history()
|
||||
old_history_size = tool.Ifc.get().history_size
|
||||
tool.Ifc.get().set_history_size(0)
|
||||
tool.Ifc.get().set_history_size(old_history_size)
|
||||
|
||||
@classmethod
|
||||
def get_unit_scale(cls):
|
||||
unit_length = bpy.context.scene.unit_settings.length_unit
|
||||
def get_unit_scale(cls) -> float:
|
||||
assert (scene := bpy.context.scene)
|
||||
unit_length = scene.unit_settings.length_unit
|
||||
unit_scale = 1.0
|
||||
if unit_length == "CENTIMETERS":
|
||||
unit_scale = 0.01
|
||||
|
||||
@@ -841,7 +841,7 @@ class Cad:
|
||||
return new_verts
|
||||
|
||||
@classmethod
|
||||
def region_2d_to_vector_3d_np(cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3d, coord: Vector) -> Vector:
|
||||
def region_2d_to_vector_3d_np(cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3D, coord: Vector) -> Vector:
|
||||
"""
|
||||
Numpy version of view3d_utils.region_2d_to_vector_3d
|
||||
Return a direction vector from the viewport at the specific 2d region
|
||||
@@ -880,7 +880,7 @@ class Cad:
|
||||
|
||||
@classmethod
|
||||
def region_2d_to_location_3d_np(
|
||||
cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3d, coord: Vector, depth_location: Vector
|
||||
cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3D, coord: Vector, depth_location: Vector
|
||||
) -> Vector:
|
||||
"""
|
||||
Numpy version of view3d_utils.region_2d_to_location_3d
|
||||
@@ -913,7 +913,7 @@ class Cad:
|
||||
|
||||
@classmethod
|
||||
def region_2d_to_origin_3d_np(
|
||||
cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3d, coord: Vector, *, clamp: float = None
|
||||
cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3D, coord: Vector, *, clamp: float = None
|
||||
) -> Vector:
|
||||
"""
|
||||
Numpy version of view3d_utils.region_2d_to_origin_3d
|
||||
@@ -971,7 +971,7 @@ class Cad:
|
||||
|
||||
@classmethod
|
||||
def location_3d_to_region_2d_np(
|
||||
cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3d, coord: Vector, *, default=None
|
||||
cls, region: bpy.types.Region, rv3d: bpy.types.RegionView3D, coord: Vector, *, default=None
|
||||
) -> Vector:
|
||||
"""
|
||||
Numpy version of view3d_utils.location_3d_to_region_2d
|
||||
|
||||
@@ -157,7 +157,8 @@ class Collector(bonsai.core.tool.Collector):
|
||||
return
|
||||
collection = bpy.data.collections.new(obj.name)
|
||||
props.collection = collection
|
||||
collection.BIMCollectionProperties.obj = obj
|
||||
collection_props = tool.Blender.get_collection_props(collection)
|
||||
collection_props.obj = obj
|
||||
return collection
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1070,11 +1070,6 @@ class Loader(bonsai.core.tool.Loader):
|
||||
layer_set = material.ForLayerSet
|
||||
offset = usage.OffsetFromReferenceLine * cls.unit_scale
|
||||
sense_factor = 1 if usage.DirectionSense == "POSITIVE" else -1
|
||||
elif material.is_a("IfcMaterialLayerSet"):
|
||||
usage = None
|
||||
layer_set = material
|
||||
offset = 0
|
||||
sense_factor = 1
|
||||
else:
|
||||
return mesh
|
||||
if len(layer_set.MaterialLayers) == 1:
|
||||
@@ -1082,11 +1077,7 @@ class Loader(bonsai.core.tool.Loader):
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(mesh)
|
||||
prev_co = None
|
||||
if not usage:
|
||||
sense_factor = 1 # Assume the extrusion vector points in the direction sense
|
||||
no = cls.get_extrusion_vector(element).normalized()
|
||||
co = Vector((0.0, 0.0, offset))
|
||||
elif usage.LayerSetDirection == "AXIS2":
|
||||
if usage.LayerSetDirection == "AXIS2":
|
||||
co = Vector((0.0, offset, 0.0))
|
||||
no = cls.get_extrusion_vector(element).normalized()
|
||||
no = no.cross(Vector([1.0, 0.0, 0.0]))
|
||||
|
||||
@@ -16,7 +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 Union
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple, Union
|
||||
|
||||
import bmesh
|
||||
import bpy
|
||||
@@ -30,8 +33,164 @@ import bonsai.core.root
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from bonsai.bim.module.misc.prop import BIMMiscProperties
|
||||
|
||||
|
||||
class Misc(bonsai.core.tool.Misc):
|
||||
|
||||
class BlenderCStructs:
|
||||
|
||||
class ListBase(ctypes.Structure):
|
||||
_fields_ = [("first", ctypes.c_void_p), ("last", ctypes.c_void_p)]
|
||||
|
||||
class bUserMenu(ctypes.Structure):
|
||||
pass
|
||||
|
||||
bUserMenu._fields_ = [
|
||||
("next", ctypes.c_void_p),
|
||||
("prev", ctypes.c_void_p),
|
||||
("space_type", ctypes.c_int8),
|
||||
("_pad0", ctypes.c_int8 * 7),
|
||||
("context", ctypes.c_char * 64),
|
||||
("items", ListBase),
|
||||
]
|
||||
|
||||
class bUserMenuItem(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("next", ctypes.c_void_p),
|
||||
("prev", ctypes.c_void_p),
|
||||
("ui_name", ctypes.c_char * 64),
|
||||
("type", ctypes.c_int8),
|
||||
("_pad0", ctypes.c_int8 * 7),
|
||||
]
|
||||
|
||||
class bUserMenuItem_Op(ctypes.Structure):
|
||||
pass
|
||||
|
||||
bUserMenuItem_Op._fields_ = [
|
||||
("item", bUserMenuItem),
|
||||
("op_idname", ctypes.c_char * 64),
|
||||
("prop", ctypes.c_void_p),
|
||||
("op_prop_enum", ctypes.c_char * 64),
|
||||
("opcontext", ctypes.c_int8),
|
||||
("_pad0", ctypes.c_int8 * 7),
|
||||
]
|
||||
|
||||
class IDPropertyData(ctypes.Structure):
|
||||
pass
|
||||
|
||||
IDPropertyData._fields_ = [
|
||||
("pointer", ctypes.c_void_p),
|
||||
("group", ListBase),
|
||||
("children_map", ctypes.c_void_p),
|
||||
("val", ctypes.c_int),
|
||||
("val2", ctypes.c_int),
|
||||
]
|
||||
|
||||
class IDProperty(ctypes.Structure):
|
||||
pass
|
||||
|
||||
IDProperty._fields_ = [
|
||||
("next", ctypes.c_void_p),
|
||||
("prev", ctypes.c_void_p),
|
||||
("type", ctypes.c_int8),
|
||||
("subtype", ctypes.c_int8),
|
||||
("flag", ctypes.c_int16),
|
||||
("name", ctypes.c_char * 64),
|
||||
("_pad0", ctypes.c_int8 * 4),
|
||||
("data", IDPropertyData),
|
||||
("len", ctypes.c_int),
|
||||
("totallen", ctypes.c_int),
|
||||
("ui_data", ctypes.c_void_p),
|
||||
]
|
||||
|
||||
class QuickFavorites:
|
||||
"""Blender doesn't provide a good way to access or manage Quick Favorites
|
||||
from the Python API. We use c-structs (ctypes) to read data directly from memory.
|
||||
This is fragile and can break between Blender versions. We only use this for
|
||||
reading data and never writing, to avoid the possibility of corrupting user preferences.
|
||||
"""
|
||||
|
||||
OFFSET_USER_MENUS: dict[tuple[int, int], int] = {
|
||||
(4, 5): 10032,
|
||||
(5, 0): 10032,
|
||||
(5, 1): 10032,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def _read_idprop_value(cls, prop_ptr: int) -> Any:
|
||||
IDP_STRING = 0
|
||||
IDP_INT = 1
|
||||
IDP_FLOAT = 2
|
||||
IDP_BOOLEAN = 10
|
||||
|
||||
p = Misc.BlenderCStructs.IDProperty.from_address(prop_ptr)
|
||||
if p.type == IDP_INT:
|
||||
return p.data.val
|
||||
elif p.type == IDP_BOOLEAN:
|
||||
return bool(p.data.val)
|
||||
elif p.type == IDP_FLOAT:
|
||||
return ctypes.c_float.from_buffer_copy(ctypes.c_int(p.data.val)).value
|
||||
elif p.type == IDP_STRING:
|
||||
return ctypes.string_at(p.data.pointer).decode()
|
||||
return f"<type={p.type}>"
|
||||
|
||||
@classmethod
|
||||
def _read_idprop_group(cls, group_ptr: int) -> dict[str, Any]:
|
||||
root = Misc.BlenderCStructs.IDProperty.from_address(group_ptr)
|
||||
result: dict[str, Any] = {}
|
||||
child_ptr = root.data.group.first
|
||||
while child_ptr:
|
||||
child = Misc.BlenderCStructs.IDProperty.from_address(child_ptr)
|
||||
result[child.name.decode()] = cls._read_idprop_value(child_ptr)
|
||||
child_ptr = child.next
|
||||
return result
|
||||
|
||||
class QuickFavoritesOperator(NamedTuple):
|
||||
ui_name: str
|
||||
op_idname_py: str
|
||||
props: dict[str, Any]
|
||||
|
||||
@classmethod
|
||||
def get_quick_favorites(cls) -> list[QuickFavoritesOperator]:
|
||||
assert bpy.context.preferences
|
||||
blender_version = bpy.app.version[:2]
|
||||
offset = cls.OFFSET_USER_MENUS[blender_version]
|
||||
prefs_address = bpy.context.preferences.as_pointer()
|
||||
user_menus = Misc.BlenderCStructs.ListBase.from_address(prefs_address + offset)
|
||||
|
||||
result: list[cls.QuickFavoritesOperator] = []
|
||||
SPACE_VIEW3D = 4
|
||||
|
||||
node = user_menus.first
|
||||
while node:
|
||||
user_menu = Misc.BlenderCStructs.bUserMenu.from_address(node)
|
||||
if user_menu.space_type != SPACE_VIEW3D:
|
||||
node = user_menu.next
|
||||
continue
|
||||
item_ptr = user_menu.items.first
|
||||
while item_ptr:
|
||||
umi = Misc.BlenderCStructs.bUserMenuItem.from_address(item_ptr)
|
||||
if umi.type == 2: # OPERATOR
|
||||
op = Misc.BlenderCStructs.bUserMenuItem_Op.from_address(item_ptr)
|
||||
props = cls._read_idprop_group(op.prop) if op.prop else {}
|
||||
result.append(
|
||||
cls.QuickFavoritesOperator(
|
||||
ui_name=op.item.ui_name.decode(),
|
||||
op_idname_py=tool.Blender.operator_idname_to_py(op.op_idname.decode()),
|
||||
props=props,
|
||||
)
|
||||
)
|
||||
item_ptr = umi.next
|
||||
node = user_menu.next
|
||||
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_misc_props(cls) -> BIMMiscProperties:
|
||||
return bpy.context.scene.BIMMiscProperties
|
||||
|
||||
@classmethod
|
||||
def get_object_storey(cls, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
@@ -76,6 +76,7 @@ if TYPE_CHECKING:
|
||||
BIMRailingProperties,
|
||||
BIMRoofProperties,
|
||||
BIMStairProperties,
|
||||
BIMSverchokProperties,
|
||||
BIMWindowProperties,
|
||||
)
|
||||
|
||||
@@ -87,23 +88,27 @@ class Model(bonsai.core.tool.Model):
|
||||
|
||||
@classmethod
|
||||
def get_door_props(cls, obj: bpy.types.Object) -> BIMDoorProperties:
|
||||
return obj.BIMDoorProperties
|
||||
return obj.BIMDoorProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_window_props(cls, obj: bpy.types.Object) -> BIMWindowProperties:
|
||||
return obj.BIMWindowProperties
|
||||
return obj.BIMWindowProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_stair_props(cls, obj: bpy.types.Object) -> BIMStairProperties:
|
||||
return obj.BIMStairProperties
|
||||
return obj.BIMStairProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_roof_props(cls, obj: bpy.types.Object) -> BIMRoofProperties:
|
||||
return obj.BIMRoofProperties
|
||||
return obj.BIMRoofProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_railing_props(cls, obj: bpy.types.Object) -> BIMRailingProperties:
|
||||
return obj.BIMRailingProperties
|
||||
return obj.BIMRailingProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_sverchok_props(cls, obj: bpy.types.Object) -> BIMSverchokProperties:
|
||||
return obj.BIMSverchokProperties # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
@classmethod
|
||||
def get_array_props(cls, obj: bpy.types.Object) -> BIMArrayProperties:
|
||||
|
||||
@@ -123,11 +123,11 @@ class Nest(bonsai.core.tool.Nest):
|
||||
return {"FINISHED"}
|
||||
|
||||
@classmethod
|
||||
def disable_nest_mode(cls):
|
||||
context = bpy.context
|
||||
props = context.scene.BIMNestProperties
|
||||
def disable_nest_mode(cls) -> None:
|
||||
props = cls.get_nest_props()
|
||||
for obj_prop in props.not_editing_objects:
|
||||
obj = obj_prop.obj
|
||||
assert obj and obj.original
|
||||
obj.original.display_type = obj_prop.previous_display_type
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
@@ -135,7 +135,7 @@ class Nest(bonsai.core.tool.Nest):
|
||||
|
||||
components = ifcopenshell.util.element.get_components(tool.Ifc.get_entity(props.editing_nest))
|
||||
objs = [tool.Ifc.get_object(component) for component in components]
|
||||
if context.space_data.local_view:
|
||||
if bpy.context.space_data.local_view:
|
||||
bpy.ops.view3d.localview()
|
||||
|
||||
props.in_nest_mode = False
|
||||
|
||||
@@ -24,7 +24,15 @@ import shutil
|
||||
from collections import defaultdict
|
||||
from math import radians
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, NamedTuple, Optional
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Literal,
|
||||
NamedTuple,
|
||||
NotRequired,
|
||||
Optional,
|
||||
TypedDict,
|
||||
)
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
@@ -35,7 +43,7 @@ import ifcopenshell.util.shape_builder
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from ifcopenshell.api.project.append_asset import APPENDABLE_ASSET_TYPES
|
||||
from mathutils import Matrix
|
||||
from mathutils import Matrix, Vector
|
||||
|
||||
import bonsai.bim.schema
|
||||
import bonsai.core.aggregate
|
||||
@@ -600,6 +608,49 @@ class Project(bonsai.core.tool.Project):
|
||||
class Link:
|
||||
"""Tools for working with linked models."""
|
||||
|
||||
class LinkedObjectChunk(TypedDict):
|
||||
"""There's actually no dictionary with those keys,
|
||||
just using this class to document what keys we do assign to the objects
|
||||
that represent chunks of the linked models.
|
||||
"""
|
||||
|
||||
guids: list[str]
|
||||
"""List of guids present in the object."""
|
||||
|
||||
guid_ids: list[int]
|
||||
"""Number of faces that belong to each guid.
|
||||
|
||||
E.g. if chunk consists of two 12 tris cubes:
|
||||
```
|
||||
guids = ["aaa", "bbb"]
|
||||
# Meaning object has 24 polygons
|
||||
# [0;11] is part of "aaa", [12:23] is part of "bbb".
|
||||
guid_ids = [12, 24]
|
||||
```
|
||||
"""
|
||||
|
||||
db: str
|
||||
"""Absolute filepath to .ifc.cache.sqlite."""
|
||||
|
||||
ifc_filepath: str
|
||||
"""Absolute filepath to .ifc."""
|
||||
|
||||
# Only added when object is queried.
|
||||
selected_vertices: NotRequired[list[tuple[int, int, int]]]
|
||||
selected_edges: NotRequired[list[tuple[int, int]]]
|
||||
selected_tris: NotRequired[list[tuple[int, int, int]]]
|
||||
|
||||
hidden_indices: NotRequired[list[int]]
|
||||
"""List of hidden indices in "guids".
|
||||
Note that entire object also can be hidden by ``hide_viewport`` and then "hidden_indices" won't be set.
|
||||
|
||||
```
|
||||
guids = ["aaa", "bbb", "ccc"]
|
||||
# guid "bbb" is hidden.
|
||||
hidden_indices = [1]
|
||||
```
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def is_linked_element(cls, obj: bpy.types.Object) -> bool:
|
||||
return "guids" in obj
|
||||
@@ -670,11 +721,17 @@ class Project(bonsai.core.tool.Project):
|
||||
return slice(guid_start_index, guid_end_index)
|
||||
|
||||
@classmethod
|
||||
def hide_linked_element(cls, obj: bpy.types.Object, guid: str) -> None:
|
||||
verts = tool.Project.Link.get_linked_element_verts(obj, guid)
|
||||
|
||||
def setup_hide_modifier(
|
||||
cls,
|
||||
obj: bpy.types.Object,
|
||||
hide_type: Literal["hide_selected", "hide_unselected"],
|
||||
) -> bpy.types.VertexGroup:
|
||||
# `MeshPolygon.hide` works only in EDIT mode,
|
||||
# so we use vertex groups + Mask modifier.
|
||||
# But since for hiding we're modifying object in a linked model,
|
||||
# then those changes are ephemeral and not fully supported by Blender
|
||||
# e.g. they're not tracked by UNDO system.
|
||||
|
||||
MODIFIER_VG_NAME = "BBIM_HIDE_LINKED_GEOMETRY"
|
||||
|
||||
vertex_groups = obj.vertex_groups
|
||||
@@ -688,8 +745,15 @@ class Project(bonsai.core.tool.Project):
|
||||
modifier = modifiers.new(MODIFIER_VG_NAME, "MASK")
|
||||
assert isinstance(modifier, bpy.types.MaskModifier)
|
||||
modifier.vertex_group = MODIFIER_VG_NAME
|
||||
modifier.invert_vertex_group = True
|
||||
# Mask modifier by default shows only geometry from the provided vertex group.
|
||||
modifier.invert_vertex_group = hide_type == "hide_selected"
|
||||
return vertex_group
|
||||
|
||||
@classmethod
|
||||
def hide_linked_element(cls, obj: bpy.types.Object, guid: str) -> None:
|
||||
verts = tool.Project.Link.get_linked_element_verts(obj, guid)
|
||||
|
||||
vertex_group = cls.setup_hide_modifier(obj, "hide_selected")
|
||||
vertex_group.add(verts, 1.0, "REPLACE")
|
||||
|
||||
hidden_indices: list[int] = list(obj.get("hidden_indices") or [])
|
||||
@@ -706,12 +770,45 @@ class Project(bonsai.core.tool.Project):
|
||||
assert col
|
||||
|
||||
for obj_ in col.objects:
|
||||
obj_.hide_viewport = False
|
||||
|
||||
if "hidden_indices" not in obj_:
|
||||
continue
|
||||
obj_.vertex_groups.clear()
|
||||
obj_.modifiers.clear()
|
||||
del obj_["hidden_indices"]
|
||||
|
||||
@classmethod
|
||||
def hide_all_elements_except(cls, link: Link, queried_obj: bpy.types.Object, queried_guid: str) -> None:
|
||||
handle = tool.Project.get_link_empty_handle(link)
|
||||
assert handle
|
||||
col = handle.instance_collection
|
||||
assert col
|
||||
|
||||
for obj_ in col.objects:
|
||||
if "guids" not in obj_:
|
||||
continue
|
||||
if obj_ != queried_obj:
|
||||
# Just hide the entire chunk, if queried guid is not part of it.
|
||||
obj_.hide_viewport = True
|
||||
continue
|
||||
|
||||
guids: list[str] = obj_["guids"]
|
||||
queried_guid_index = guids.index(queried_guid)
|
||||
|
||||
# Get vertices for the queried element before modifying hidden_indices.
|
||||
queried_verts = cls.get_linked_element_verts(obj_, queried_guid)
|
||||
vertex_group = cls.setup_hide_modifier(obj_, "hide_unselected")
|
||||
|
||||
assert isinstance(mesh := obj_.data, bpy.types.Mesh)
|
||||
# Clean up possible previously hidden elements.
|
||||
vertex_group.remove(range(len(mesh.vertices)))
|
||||
|
||||
vertex_group.add(queried_verts, 1.0, "REPLACE")
|
||||
|
||||
# Mark all guids as hidden except the queried one.
|
||||
obj_["hidden_indices"] = [i for i in range(len(guids)) if i != queried_guid_index]
|
||||
|
||||
@classmethod
|
||||
def select_linked_element_geom(cls, obj: bpy.types.Object, guid: str) -> None:
|
||||
slice_ = cls.get_linked_element_geom_slice(obj, guid)
|
||||
|
||||
@@ -24,6 +24,7 @@ from typing import TYPE_CHECKING, Any, Literal, Union
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.unit
|
||||
from lark import Lark, Transformer
|
||||
|
||||
import bonsai.bim.helper
|
||||
|
||||
@@ -273,8 +273,8 @@ if BPY_IS_LOADED:
|
||||
f"Couldn't find locale path in the source directory, creating dummy directory: {source_locale_path}.",
|
||||
)
|
||||
|
||||
from ui_translate.settings import (
|
||||
settings as ui_translate_settings, # pyright: ignore[reportMissingImports]
|
||||
from ui_translate.settings import ( # pyright: ignore[reportMissingImports]
|
||||
settings as ui_translate_settings,
|
||||
)
|
||||
from ui_translate.update_ui import ( # pyright: ignore[reportMissingImports]
|
||||
UI_OT_i18n_updatetranslation_init_settings,
|
||||
|
||||
@@ -24,6 +24,7 @@ import bpy
|
||||
import ifcopenshell
|
||||
import pytest
|
||||
|
||||
import bonsai
|
||||
import bonsai.core.tool
|
||||
import bonsai.tool as tool
|
||||
from bonsai.tool.blender import Blender as subject
|
||||
@@ -144,3 +145,25 @@ class TestGetSelectedFiles(NewFile):
|
||||
assert subject.get_selected_files(Path(g.name).parent, [file], use_relative_path=True) == [
|
||||
Path(g.name).name
|
||||
]
|
||||
|
||||
|
||||
class TestGetDebugInfo(NewFile):
|
||||
# Only keys that are safe to set if Bonsai fails to load.
|
||||
EXPECTED_KEYS = {
|
||||
"os",
|
||||
"os_version",
|
||||
"python_version",
|
||||
"architecture",
|
||||
"machine",
|
||||
"processor",
|
||||
"blender_version",
|
||||
"bonsai_version",
|
||||
"bonsai_commit_hash",
|
||||
"bonsai_commit_date",
|
||||
"last_actions",
|
||||
"last_error",
|
||||
}
|
||||
|
||||
def test_failed_to_load_returns_only_base_keys(self):
|
||||
info = bonsai.get_debug_info(bonsai_failed_to_load=True)
|
||||
assert set(info.keys()) == self.EXPECTED_KEYS
|
||||
|
||||
@@ -171,6 +171,12 @@ class TestScaleObjectToHeight(test.bim.bootstrap.NewFile):
|
||||
assert list(obj.scale) == [1.0, 1.0, 1.0]
|
||||
|
||||
|
||||
class TestQuickFavoritesOffsetUserMenus(test.bim.bootstrap.NewFile):
|
||||
def test_current_blender_version_is_supported(self):
|
||||
version = bpy.app.version[:2]
|
||||
assert version in subject.QuickFavorites.OFFSET_USER_MENUS
|
||||
|
||||
|
||||
class TestSplitObjectsWithCutter(test.bim.bootstrap.NewFile):
|
||||
def test_run(self):
|
||||
bpy.ops.mesh.primitive_cube_add()
|
||||
|
||||
@@ -403,13 +403,6 @@ class TestLoadingIfcSqlite(NewFile):
|
||||
|
||||
|
||||
class TestGettingLinkedElementGeomSlice:
|
||||
def __init__(self):
|
||||
self.test_get_first_element()
|
||||
self.test_get_middle_element()
|
||||
self.test_skip_hidden_first_element()
|
||||
self.test_skip_hidden_middle_element()
|
||||
self.test_handle_hidden_non_first_element()
|
||||
|
||||
TEST_OBJ = {
|
||||
"guids": ["aaa", "bbb", "ccc"],
|
||||
"guid_ids": [5, 10, 15],
|
||||
|
||||
@@ -23,6 +23,7 @@ import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.api.system
|
||||
import ifcopenshell.util.system
|
||||
import ifcopenshell.util.unit
|
||||
import numpy as np
|
||||
from mathutils import Euler, Matrix, Vector
|
||||
|
||||
@@ -19,6 +19,11 @@ dependencies = [
|
||||
"ifcopenshell",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
advanced = [
|
||||
"scikit-learn",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "http://ifcopenshell.org"
|
||||
Documentation = "https://docs.ifcopenshell.org"
|
||||
|
||||
@@ -29,10 +29,8 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcAxis2PlacementLinear* inst)
|
||||
Logger::Error(std::runtime_error("Location must be IfcPointByDistanceExpression for IfcAxis2PlacementLinear"));
|
||||
}
|
||||
|
||||
Eigen::Vector3d o, axis(0, 0, 1), refDirection;
|
||||
|
||||
taxonomy::matrix4::ptr m = taxonomy::cast<taxonomy::matrix4>(map(inst->Location()));
|
||||
o = m->components().col(3).head<3>();
|
||||
Eigen::Vector3d o = m->components().col(3).head<3>();
|
||||
|
||||
// From 8.9.3.4 IfcAxis2PlacementLinear there are 4 cases that need to be considered
|
||||
// 1) Axis is given but not RefDirection
|
||||
@@ -40,43 +38,12 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcAxis2PlacementLinear* inst)
|
||||
// 3) Neither Axis or RefDirection are provided
|
||||
// 4) Both Axis and RefDirection are provided
|
||||
|
||||
const bool hasAxis = inst->Axis() != nullptr;
|
||||
const bool hasRef = inst->RefDirection() != nullptr;
|
||||
Eigen::Vector3d z = inst->Axis() ? *taxonomy::cast<taxonomy::direction3>(map(inst->Axis()))->components_ : Eigen::Vector3d(0,0,1); // Axis is (0,0,1) when omitted
|
||||
Eigen::Vector3d rd = inst->RefDirection() ? *taxonomy::cast<taxonomy::direction3>(map(inst->RefDirection()))->components_ : m->components().col(0).head<3>(); // RefDirection is the curve tangent when omitted
|
||||
Eigen::Vector3d y = z.cross(rd);
|
||||
Eigen::Vector3d x = y.cross(z);
|
||||
|
||||
/*
|
||||
if (hasAxis != hasRef) {
|
||||
Logger::Warning("Axis and RefDirection should be specified together", inst);
|
||||
}
|
||||
*/
|
||||
|
||||
if (hasAxis && !hasRef) {
|
||||
taxonomy::direction3::ptr a = taxonomy::cast<taxonomy::direction3>(map(inst->Axis()));
|
||||
axis = *a->components_;
|
||||
|
||||
refDirection = m->components().col(0).head<3>(); // RefDirection is the curve tangent when omitted
|
||||
// refDirection is not necessarily orthogonal to axis.
|
||||
// axis.cross(refDirection) gives y. y.cross(axis) gives x=refDirection
|
||||
refDirection = axis.cross(refDirection).cross(axis);
|
||||
} else if (!hasAxis && hasRef) {
|
||||
taxonomy::direction3::ptr r = taxonomy::cast<taxonomy::direction3>(map(inst->RefDirection()));
|
||||
refDirection = *r->components_;
|
||||
Eigen::Vector3d up(0, 0, 1);
|
||||
axis = refDirection.cross(up.cross(refDirection));
|
||||
} else if (!hasAxis && !hasRef) {
|
||||
refDirection = m->components().col(0).head<3>(); // RefDirection is the curve tangent when omitted
|
||||
Eigen::Vector3d up(0, 0, 1);
|
||||
axis = refDirection.cross(up.cross(refDirection));
|
||||
} else {
|
||||
taxonomy::direction3::ptr a = taxonomy::cast<taxonomy::direction3>(map(inst->Axis()));
|
||||
axis = *a->components_;
|
||||
|
||||
taxonomy::direction3::ptr r = taxonomy::cast<taxonomy::direction3>(map(inst->RefDirection()));
|
||||
refDirection = *r->components_;
|
||||
refDirection = axis.cross(refDirection).cross(axis); // refDirection needs to be orthogonal to axis
|
||||
}
|
||||
|
||||
// axis and refDirection need to be orthogonal
|
||||
return taxonomy::make<taxonomy::matrix4>(o, axis, refDirection);
|
||||
return taxonomy::make<taxonomy::matrix4>(o, z, x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ would be with the use of templates as shown below.
|
||||
#include "ifcparse/Ifc4.h"
|
||||
#include "ifcparse/Ifc4x3_add2.h"
|
||||
|
||||
#define IFC_SCHEMA_SEQ (4x3_rc2)(4)(2x3) // TODO: Enumerate through all IFC schemas you want to be able to process
|
||||
#define IFC_SCHEMA_SEQ (4x3_add2)(4)(2x3) // TODO: Enumerate through all IFC schemas you want to be able to process
|
||||
#define EXPAND_AND_CONCATENATE(elem) Ifc##elem
|
||||
#define PROCESS_FOR_SCHEMA(r, data, elem) if (schema_version == BOOST_PP_STRINGIZE(elem)) { parseIfc<EXPAND_AND_CONCATENATE(elem)>(file); } else
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@ from __future__ import annotations
|
||||
import math
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
|
||||
|
||||
import bmesh
|
||||
import bpy.types
|
||||
import bmesh # pyright: ignore[reportMissingImports]
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mathutils import Matrix, Vector
|
||||
from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports]
|
||||
|
||||
import ifcopenshell.util.shape_builder
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
@@ -22,7 +22,7 @@ from typing import TYPE_CHECKING, Any, Optional
|
||||
import ifcopenshell
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import bpy
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
|
||||
|
||||
def add_surface_textures(
|
||||
|
||||
@@ -33,14 +33,14 @@ def _has_occ():
|
||||
# Previous versions (pythonocc<=0.17.3) are using just OCC.
|
||||
|
||||
try:
|
||||
import OCC.Core.BRepTools
|
||||
import OCC.Core.BRepTools # pyright: ignore[reportMissingImports]
|
||||
|
||||
return True
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
import OCC.BRepTools # noqa: F401
|
||||
import OCC.BRepTools # noqa: F401 # pyright: ignore[reportMissingImports]
|
||||
|
||||
return True
|
||||
except ImportError:
|
||||
|
||||
@@ -28,7 +28,7 @@ from ..file import file
|
||||
from . import has_occ
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from OCC.Core import TopoDS
|
||||
from OCC.Core import TopoDS # pyright: ignore[reportMissingImports]
|
||||
|
||||
IteratorOutput = Union["ShapeElementType", "utils.shape_tuple"]
|
||||
|
||||
@@ -47,9 +47,9 @@ if has_occ:
|
||||
from . import occ_utils as utils
|
||||
|
||||
try:
|
||||
from OCC.Core import TopoDS
|
||||
from OCC.Core import TopoDS # pyright: ignore[reportMissingImports]
|
||||
except ImportError:
|
||||
from OCC import TopoDS
|
||||
from OCC import TopoDS # pyright: ignore[reportMissingImports]
|
||||
|
||||
def wrap_shape_creation(settings: settings, shape: ifcopenshell_wrapper.Element):
|
||||
if getattr(settings, "use_python_opencascade", False):
|
||||
|
||||
@@ -26,17 +26,17 @@ import warnings
|
||||
from collections.abc import Iterable
|
||||
from typing import NamedTuple, Union
|
||||
|
||||
import OCC
|
||||
import OCC # pyright: ignore[reportMissingImports]
|
||||
from typing_extensions import assert_never
|
||||
|
||||
import ifcopenshell.ifcopenshell_wrapper as ifcopenshell_wrapper
|
||||
|
||||
try:
|
||||
from OCC.Core import AIS, BRepTools, Graphic3d, Quantity, TopoDS, V3d, gp
|
||||
from OCC.Core import AIS, BRepTools, Graphic3d, Quantity, TopoDS, V3d, gp # pyright: ignore[reportMissingImports]
|
||||
|
||||
USE_OCCT_HANDLE = False
|
||||
except ImportError:
|
||||
from OCC import AIS, BRepTools, Graphic3d, Quantity, TopoDS, V3d, gp
|
||||
from OCC import AIS, BRepTools, Graphic3d, Quantity, TopoDS, V3d, gp # pyright: ignore[reportMissingImports]
|
||||
|
||||
USE_OCCT_HANDLE = True
|
||||
|
||||
@@ -68,7 +68,7 @@ DEFAULT_STYLES = {
|
||||
|
||||
|
||||
def initialize_display():
|
||||
import OCC.Display.SimpleGui
|
||||
import OCC.Display.SimpleGui # pyright: ignore[reportMissingImports]
|
||||
|
||||
global handle, main_loop, add_menu, add_function_to_menu
|
||||
handle, main_loop, add_menu, add_function_to_menu = OCC.Display.SimpleGui.init_display()
|
||||
|
||||
Submodule src/ifcopenshell-python/ifcopenshell/simple_spf updated: 30317826f8...ed50b756c4
@@ -40,7 +40,7 @@ if TYPE_CHECKING:
|
||||
# NOTE: mathutils is never used at runtime in ifcopenshell,
|
||||
# only for type checking to ensure methods are compatible with
|
||||
# Blender vectors.
|
||||
from mathutils import Vector
|
||||
from mathutils import Vector # pyright: ignore[reportMissingImports]
|
||||
|
||||
# Support both numpy arrays and python sequences as inputs.
|
||||
VectorType = Union[Sequence[float], Vector, np.ndarray]
|
||||
|
||||
@@ -60,7 +60,6 @@ from typing import TYPE_CHECKING, Any, Optional, Union
|
||||
import ifcopenshell
|
||||
import ifcopenshell.express.rule_executor
|
||||
import ifcopenshell.ifcopenshell_wrapper
|
||||
import ifcopenshell.ifcopenshell_wrapper as W
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import ifcopenshell.simple_spf
|
||||
@@ -705,10 +704,10 @@ def validate_ifc_header(
|
||||
log_error(header_entity, name, index, STRING_TYPE, type(value).__name__)
|
||||
|
||||
# Ignore header.file_schema as file won't load to IfcOpenShell with invalid file_schema.
|
||||
file_description: W.FileDescription = header.file_description
|
||||
file_description = header.file_description
|
||||
validate_attribute(file_description, "description", 0, aggregate=True)
|
||||
validate_attribute(file_description, "implementation_level", 1)
|
||||
file_name: W.FileName = header.file_name
|
||||
file_name = header.file_name
|
||||
validate_attribute(file_name, "name", 0)
|
||||
validate_attribute(file_name, "time_stamp", 1)
|
||||
validate_attribute(file_name, "author", 2, aggregate=True)
|
||||
|
||||
@@ -17,8 +17,18 @@ REPO_PATH_SRC = REPO_PATH / "src"
|
||||
assert REPO_PATH_SRC.exists(), f"'{REPO_PATH_SRC}' doesn't exist."
|
||||
|
||||
packages = {
|
||||
"bcf": REPO_PATH_SRC / "bcf" / "bcf",
|
||||
"bsdd.py": REPO_PATH_SRC / "bsdd" / "bsdd.py",
|
||||
"ifc4d": REPO_PATH_SRC / "ifc4d" / "ifc4d",
|
||||
"ifc5d": REPO_PATH_SRC / "ifc5d" / "ifc5d",
|
||||
"ifccityjson": REPO_PATH_SRC / "ifccityjson" / "ifccityjson",
|
||||
"ifcclash": REPO_PATH_SRC / "ifcclash" / "ifcclash",
|
||||
"ifccsv.py": REPO_PATH_SRC / "ifccsv" / "ifccsv.py",
|
||||
"ifcdiff.py": REPO_PATH_SRC / "ifcdiff" / "ifcdiff.py",
|
||||
"ifcfm": REPO_PATH_SRC / "ifcfm" / "ifcfm",
|
||||
"ifcopenshell": REPO_PATH_SRC / "ifcopenshell-python" / "ifcopenshell",
|
||||
"ifcpatch": REPO_PATH_SRC / "ifcpatch" / "ifcpatch",
|
||||
"ifctester": REPO_PATH_SRC / "ifctester" / "ifctester",
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +45,12 @@ for package, repo_package_path in packages.items():
|
||||
continue
|
||||
package_path.unlink()
|
||||
if package_path.exists():
|
||||
# I guess it's a directory.
|
||||
shutil.rmtree(package_path)
|
||||
if package_path.is_dir():
|
||||
shutil.rmtree(package_path)
|
||||
else:
|
||||
package_path.unlink()
|
||||
print(f"Symlinking {package_path} -> {repo_package_path}")
|
||||
package_path.symlink_to(repo_package_path, True)
|
||||
package_path.symlink_to(repo_package_path, target_is_directory=repo_package_path.is_dir())
|
||||
|
||||
|
||||
PACKAGE_PATH = SITE / "ifcopenshell"
|
||||
|
||||
@@ -215,11 +215,11 @@ def _extract_docs(cls: type, method_name: str, boilerplate_args: Union[Sequence[
|
||||
|
||||
input_data = inputs[input_name]
|
||||
# E.g. list[str].
|
||||
if isinstance(type_hint, typing.GenericAlias):
|
||||
if isinstance(type_hint, typing.GenericAlias): # pyright: ignore[reportAttributeAccessIssue]
|
||||
input_data["generic_type"] = type_hint.__name__
|
||||
type_hint = typing.get_args(type_hint)[0]
|
||||
|
||||
if isinstance(type_hint, typing._UnionGenericAlias):
|
||||
if isinstance(type_hint, typing._UnionGenericAlias): # pyright: ignore[reportAttributeAccessIssue]
|
||||
inputs[input_name]["type"] = [t.__name__ for t in typing.get_args(type_hint)]
|
||||
elif type_hint.__name__ == "Literal":
|
||||
inputs[input_name]["type"] = "Literal"
|
||||
|
||||
@@ -67,9 +67,9 @@ class Patcher:
|
||||
|
||||
def patch(self) -> None:
|
||||
import bonsai.tool as tool
|
||||
import bpy
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
import ifcopenshell.util.element
|
||||
from mathutils import Matrix, Vector
|
||||
from mathutils import Matrix, Vector # pyright: ignore[reportMissingImports]
|
||||
|
||||
if len(bpy.data.objects) > 0:
|
||||
bpy.data.batch_remove(bpy.data.objects)
|
||||
|
||||
@@ -18,11 +18,15 @@
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.shape_builder
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
|
||||
|
||||
class Patcher:
|
||||
def __init__(
|
||||
@@ -109,12 +113,14 @@ class Patcher:
|
||||
self.should_create_edges = should_create_edges
|
||||
|
||||
def patch(self) -> None:
|
||||
import bmesh
|
||||
import bmesh # pyright: ignore[reportMissingImports]
|
||||
import bonsai.tool as tool
|
||||
import bpy
|
||||
import ifcopenshell.util.shape_builder
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
import ifcopenshell.util.schema
|
||||
import ifcopenshell.util.unit
|
||||
|
||||
bpy.context.scene.BIMProjectProperties.should_use_native_meshes = True
|
||||
props = tool.Project.get_project_props()
|
||||
props.should_use_native_meshes = True
|
||||
bpy.ops.bim.load_project(filepath=self.filepath)
|
||||
|
||||
old_history_size = tool.Ifc.get().history_size
|
||||
@@ -125,7 +131,7 @@ class Patcher:
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
|
||||
for obj in bpy.data.objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id or not obj.data:
|
||||
if not tool.Blender.get_ifc_definition_id(obj) or not obj.data:
|
||||
continue
|
||||
if not obj.data.polygons:
|
||||
continue
|
||||
@@ -159,14 +165,14 @@ class Patcher:
|
||||
|
||||
self.file = tool.Ifc.get()
|
||||
|
||||
def create_edges(self, obj):
|
||||
import bmesh
|
||||
def create_edges(self, obj: bpy.types.Object) -> None:
|
||||
import bmesh # pyright: ignore[reportMissingImports]
|
||||
import bonsai.tool as tool
|
||||
import bpy
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.schema
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
data = obj.data
|
||||
@@ -224,16 +230,16 @@ class Patcher:
|
||||
ifcopenshell.util.schema.reassign_class(tool.Ifc.get(), element2, "IfcVirtualElement")
|
||||
bm.free()
|
||||
|
||||
def create_face_sampleable_object(self, obj):
|
||||
def create_face_sampleable_object(self, obj: bpy.types.Object) -> None:
|
||||
# No sharp faces
|
||||
from math import degrees
|
||||
|
||||
import bmesh
|
||||
import bmesh # pyright: ignore[reportMissingImports]
|
||||
import bonsai.tool as tool
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.shape_builder
|
||||
|
||||
print("working on ", obj.name)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -271,17 +277,17 @@ class Patcher:
|
||||
|
||||
bm.free()
|
||||
|
||||
def create_edge_sampleable_object(self, obj):
|
||||
def create_edge_sampleable_object(self, obj: bpy.types.Object) -> None:
|
||||
# This is crazy but we need a sharp face per island
|
||||
from math import degrees, radians, sin
|
||||
|
||||
import bmesh
|
||||
import bmesh # pyright: ignore[reportMissingImports]
|
||||
import bonsai.tool as tool
|
||||
import ifcopenshell.api.geometry
|
||||
import ifcopenshell.api.root
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
from mathutils import Matrix
|
||||
import ifcopenshell.util.shape_builder
|
||||
from mathutils import Matrix # pyright: ignore[reportMissingImports]
|
||||
|
||||
# Get the active object (assumed to have a mesh)
|
||||
mesh = obj.data
|
||||
@@ -430,7 +436,6 @@ class Patcher:
|
||||
bm.free()
|
||||
|
||||
print("Added a triangle to", islands_count, "mesh island(s).")
|
||||
return
|
||||
|
||||
def create_curves_from_curve_ifc2x3(
|
||||
self, is_2d: bool = False, curve_object_data=None
|
||||
|
||||
@@ -80,9 +80,9 @@ class Patcher:
|
||||
def patch(self) -> None:
|
||||
from math import degrees
|
||||
|
||||
import bmesh
|
||||
import bmesh # pyright: ignore[reportMissingImports]
|
||||
import bonsai.tool as tool
|
||||
import bpy
|
||||
import bpy # pyright: ignore[reportMissingImports]
|
||||
|
||||
props = tool.Project.get_project_props()
|
||||
props.should_use_native_meshes = True
|
||||
|
||||
Generated
+6
-6
@@ -1533,9 +1533,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/devalue": {
|
||||
"version": "5.6.3",
|
||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz",
|
||||
"integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==",
|
||||
"version": "5.6.4",
|
||||
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.4.tgz",
|
||||
"integrity": "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
@@ -2951,9 +2951,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.5.10",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz",
|
||||
"integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==",
|
||||
"version": "7.5.11",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz",
|
||||
"integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
|
||||
+14
-4
@@ -5,11 +5,21 @@ but also archives them to '~/outputs'.
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from zipfile import ZipFile
|
||||
|
||||
|
||||
def is_arm64() -> bool:
|
||||
arch = os.environ.get("TARGET_ARCH", "").lower()
|
||||
if arch in ("arm64", "aarch64"):
|
||||
return True
|
||||
if arch in ("x64", "amd64", "x86_64"):
|
||||
return False
|
||||
return platform.machine().lower() in ("arm64", "aarch64")
|
||||
|
||||
assert Path.cwd() == Path(__file__).parent, "Run this script from the 'win' directory."
|
||||
|
||||
PYTHON_VERSIONS = ["3.10.3", "3.11.8", "3.12.1", "3.13.0", "3.14.0"]
|
||||
@@ -23,7 +33,7 @@ else:
|
||||
OUTPUT_DIR = Path.home() / "output"
|
||||
OUTPUT_DIR.mkdir(exist_ok=True)
|
||||
print("Output directory:", OUTPUT_DIR)
|
||||
ZIP_TEMPLATE = f"{{package_name}}-v{VERSION}-{SHA}-win64.zip"
|
||||
ZIP_TEMPLATE = f"{{package_name}}-v{VERSION}-{SHA}-{'win-arm64' if is_arm64() else 'win64'}.zip"
|
||||
|
||||
|
||||
def run(command: list[str]) -> None:
|
||||
@@ -52,7 +62,7 @@ def build() -> None:
|
||||
os.environ["PYTHON_VERSION"] = python_version
|
||||
print(f"Building for Python {python_version}...")
|
||||
subprocess.run(
|
||||
[str(REPO_WIN / "build-deps.cmd"), "vs2022-x64", "Release"],
|
||||
[str(REPO_WIN / "build-deps.cmd"), "vs2022-ARM64" if is_arm64() else "vs2022-x64", "Release"],
|
||||
check=True,
|
||||
text=True,
|
||||
input="y\n",
|
||||
@@ -61,13 +71,13 @@ def build() -> None:
|
||||
run(
|
||||
[
|
||||
str(REPO_WIN / "run-cmake.bat"),
|
||||
"vs2022-x64",
|
||||
"vs2022-ARM64" if is_arm64() else "vs2022-x64",
|
||||
"-DENABLE_BUILD_OPTIMIZATIONS=ON",
|
||||
"-DGLTF_SUPPORT=ON",
|
||||
]
|
||||
)
|
||||
restore_env(*OLD_ADD_COMMIT_SHA)
|
||||
run([str(REPO_WIN / "install-ifcopenshell.bat"), "vs2022-x64", "Release"])
|
||||
run([str(REPO_WIN / "install-ifcopenshell.bat"), "vs2022-ARM64" if is_arm64() else "vs2022-x64", "Release"])
|
||||
|
||||
|
||||
def archive_executables() -> None:
|
||||
|
||||
+43
-12
@@ -132,7 +132,7 @@ call cecho.cmd 0 10 "Script configuration:"
|
||||
call cecho.cmd 0 13 "* CMake Generator`t= '`"%GENERATOR%`'`t
|
||||
echo - Passed to CMake -G option.
|
||||
call cecho.cmd 0 13 "* Target Architecture`t= %TARGET_ARCH%"
|
||||
echo - Whether were doing 32-bit (x86) or 64-bit (x64) build.
|
||||
echo - Whether were doing 32-bit (x86) or 64-bit (x64, arm64) build.
|
||||
call cecho.cmd 0 13 "* Target Platform`t= %VS_PLATFORM%"
|
||||
echo - Passed to CMake -A option.
|
||||
call cecho.cmd 0 13 "* Target Toolset`t= %VS_TOOLSET%"
|
||||
@@ -187,8 +187,15 @@ IF DEFINED PYTHON_VERSION (
|
||||
)
|
||||
|
||||
:: VERSION DERIVATIONS
|
||||
for /f "tokens=1,2,3 delims=." %%a in ("%PYTHON_VERSION%") do (
|
||||
set PY_VER_MAJOR_MINOR=%%a%%b
|
||||
)
|
||||
IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" (
|
||||
set PYTHONHOME=%DEPS_DIR%\python.%PYTHON_VERSION%\tools
|
||||
IF /I "%TARGET_ARCH%"=="arm64" (
|
||||
set PYTHONHOME=%DEPS_DIR%\pythonarm64.%PYTHON_VERSION%\tools
|
||||
) ELSE (
|
||||
set PYTHONHOME=%DEPS_DIR%\python.%PYTHON_VERSION%\tools
|
||||
)
|
||||
)
|
||||
|
||||
:: Cache last used CMake generator and configurable dependency dirs for other scripts to use
|
||||
@@ -312,6 +319,11 @@ powershell -c "get-content %~dp0patches\mpir.patch | %%{$_ -replace \"sdk\",\"%U
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
if NOT "%USE_STATIC_RUNTIME%"=="FALSE" git apply "%~dp0patches\mpir_runtime.patch" --unidiff-zero --ignore-whitespace
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
IF /I "%VS_PLATFORM%"=="ARM64" (
|
||||
echo "Applying ARM64 Patches for Mpir"
|
||||
git apply "%~dp0patches\mpir-arm64-changes.patch" --unidiff-zero --ignore-whitespace
|
||||
)
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
cd msvc
|
||||
cd vs%VS_VER:~2,2%
|
||||
call .\msbuild.bat gc LIB %VS_PLATFORM% %DEBUG_OR_RELEASE%
|
||||
@@ -338,6 +350,10 @@ powershell -c "get-content %~dp0patches\mpfr.patch | %%{$_ -replace \"sdk\",\"%U
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
if NOT "%USE_STATIC_RUNTIME%"=="FALSE" git apply "%~dp0patches\mpfr_runtime.patch" --unidiff-zero --ignore-whitespace
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
IF /I "%VS_PLATFORM%"=="ARM64" (
|
||||
echo "Applying ARM64 Patches for Mpfr"
|
||||
git apply "%~dp0patches\mpfr-arm64-changes.patch" --unidiff-zero --ignore-whitespace
|
||||
)
|
||||
if "%VS_VER%"=="2017" (
|
||||
set mpfr_sln=build.vc15
|
||||
set orig_platform_toolset=v141
|
||||
@@ -406,6 +422,7 @@ cd "%DEPS_DIR%"
|
||||
call :DownloadFile https://github.com/boostorg/boost/releases/download/boost-%BOOST_VERSION%/%BOOST_ZIP% "%DEPS_DIR%" %BOOST_ZIP%
|
||||
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
cd "%DEPS_DIR%"
|
||||
call :ExtractArchive %BOOST_ZIP% "%DEPS_DIR%" %DEPENDENCY_DIR%
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
|
||||
@@ -429,13 +446,21 @@ if not exist "%DEPENDENCY_DIR%\project-config.jam". (
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
)
|
||||
|
||||
if /I "%TARGET_ARCH%"=="x64" (
|
||||
set B2_ARCH_FEATURE=x86
|
||||
) else if /I "%TARGET_ARCH%"=="arm64" (
|
||||
set B2_ARCH_FEATURE=arm
|
||||
) else (
|
||||
echo "Failed to identify architecture"
|
||||
GOTO :Error
|
||||
)
|
||||
set BOOST_LIBS=--with-system --with-regex --with-thread --with-program_options --with-date_time --with-iostreams --with-filesystem
|
||||
:: NOTE Boost is fast to build with limited set of libraries so build it always.
|
||||
cd "%DEPENDENCY_DIR%"
|
||||
call cecho.cmd 0 13 "Building %DEPENDENCY_NAME% %BOOST_LIBS% Please be patient, this will take a while."
|
||||
IF EXIST "%DEPENDENCY_DIR%\bin.v2\project-cache.jam" del "%DEPENDENCY_DIR%\bin.v2\project-cache.jam"
|
||||
|
||||
call .\b2 toolset=%BOOST_TOOLSET% runtime-link=shared address-model=%ARCH_BITS% --abbreviate-paths -j%IFCOS_NUM_BUILD_PROCS% ^
|
||||
call .\b2 toolset=%BOOST_TOOLSET% architecture=%B2_ARCH_FEATURE% runtime-link=shared address-model=%ARCH_BITS% --abbreviate-paths -j%IFCOS_NUM_BUILD_PROCS% ^
|
||||
variant=%DEBUG_OR_RELEASE_LOWERCASE% %BOOST_WIN_API% %BOOST_LIBS% stage --stagedir=%DEPENDENCY_INSTALL_DIR%
|
||||
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
@@ -561,9 +586,10 @@ SET COMPILE_WITH_WPO=FALSE
|
||||
:Python
|
||||
set DEPENDENCY_NAME=Python %PYTHON_VERSION%
|
||||
set DEPENDENCY_DIR=N/A
|
||||
set PYTHON_AMD64_POSTFIX=-amd64
|
||||
IF NOT %TARGET_ARCH%==x64 set PYTHON_AMD64_POSTFIX=
|
||||
set PYTHON_INSTALLER=python-%PYTHON_VERSION%%PYTHON_AMD64_POSTFIX%.exe
|
||||
set PYTHON_AMD64_POSTFIX=
|
||||
IF /I "%TARGET_ARCH%"=="x64" set "PYTHON_AMD64_POSTFIX=-amd64"
|
||||
IF /I "%TARGET_ARCH%"=="arm64" set "PYTHON_AMD64_POSTFIX=-arm64"
|
||||
set "PYTHON_INSTALLER=python-%PYTHON_VERSION%%PYTHON_AMD64_POSTFIX%.exe"
|
||||
|
||||
IF NOT "%IFCOS_INSTALL_PYTHON%"=="TRUE" (
|
||||
call cecho.cmd 0 13 "IFCOS_INSTALL_PYTHON not 'TRUE', skipping installation of Python."
|
||||
@@ -571,22 +597,25 @@ IF NOT "%IFCOS_INSTALL_PYTHON%"=="TRUE" (
|
||||
)
|
||||
|
||||
:: nuget doesn't support providing architecture for packages.
|
||||
if NOT %TARGET_ARCH%==x64 (
|
||||
IF /I NOT "%TARGET_ARCH%"=="x64" IF /I NOT "%TARGET_ARCH%"=="arm64" (
|
||||
call cecho.cmd 0 12 "Automatic insallation of Python for x86 builds is not supported,"
|
||||
call cecho.cmd 0 12 "please install Python %PYTHON_VERSION% manually and ensure that it is available in PATH."
|
||||
call cecho.cmd 0 12 "https://www.python.org/ftp/python/%PYTHON_VERSION%/%PYTHON_INSTALLER%"
|
||||
goto :Error
|
||||
)
|
||||
|
||||
|
||||
if EXIST "%PYTHONHOME%" (
|
||||
echo Found existing '%PYTHONHOME%', skipping installation.
|
||||
goto :SWIG
|
||||
)
|
||||
|
||||
"%NUGET_EXE%" install Python -Version %PYTHON_VERSION% -OutputDirectory "%DEPS_DIR%"
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
|
||||
IF /I "%TARGET_ARCH%"=="x64" (
|
||||
"%NUGET_EXE%" install Python -Version %PYTHON_VERSION% -OutputDirectory "%DEPS_DIR%"
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
) ELSE (
|
||||
"%NUGET_EXE%" install pythonarm64 -Version %PYTHON_VERSION% -OutputDirectory "%DEPS_DIR%"
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
)
|
||||
|
||||
:SWIG
|
||||
set DEPENDENCY_NAME=SWIG
|
||||
@@ -723,6 +752,9 @@ call :RunCMake -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%\%DEPENDENCY_INSTALL_NAME%"
|
||||
-DWITH_CORE_TOOLS=OFF ^
|
||||
-DROCKSDB_BUILD_SHARED=OFF ^
|
||||
-DWITH_ZSTD=On ^
|
||||
-DZSTD_INCLUDE_DIR="%ZSTD_INCLUDE%" ^
|
||||
-DZSTD_LIBRARY_DEBUG="%ZSTD_LIB_DEBUG%" ^
|
||||
-DZSTD_LIBRARY_RELEASE="%ZSTD_LIB_RELEASE%" ^
|
||||
-DPORTABLE=1 ^
|
||||
-DCMAKE_DEBUG_POSTFIX="_d"
|
||||
IF NOT %ERRORLEVEL%==0 GOTO :Error
|
||||
@@ -960,4 +992,3 @@ echo - https://msdn.microsoft.com/en-us/library/ms229859(v=vs.110).aspx
|
||||
echo.
|
||||
echo NB: This script needs to be ran from the directory directly containing it.
|
||||
echo.
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,519 @@
|
||||
diff --git a/msvc/postbuild.bat b/msvc/postbuild.bat
|
||||
index 1c301d1a..7d5362be 100644
|
||||
--- a/msvc/postbuild.bat
|
||||
+++ b/msvc/postbuild.bat
|
||||
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
rem %1 = full target path
|
||||
-rem %2 = last two digits of the Visual Studio version number (e.g. 17)
|
||||
+rem %2 = last two digits of the Visual Studio version number (e.g. 17 or 22)
|
||||
|
||||
set vs_ver=%2
|
||||
set str=%~1
|
||||
@@ -20,11 +20,13 @@ goto dele
|
||||
set str=%str_confirmed%
|
||||
echo "Final subpath %str%"
|
||||
|
||||
-rem we now have: msvc.\vs<nn>\<project_directory>\<win32|x64>\<debug|release>\mpir.<lib|dll>
|
||||
-rem extract: project_directory, platform (plat=<win32|x64>), configuration (conf=<debug|release>) and file name
|
||||
+rem we now have: msvc\vs<nn>\<project>\<plat>\<conf>\mpir(.xx).<lib|dll>
|
||||
+rem extract: project_directory, platform (plat), configuration (conf) and file name
|
||||
|
||||
set file=
|
||||
-for /f "tokens=1,2,3,4,5,6 delims=\" %%a in ("%str%") do set tloc=%%c&set plat=%%d&set conf=%%e&set file=%%f
|
||||
+for /f "tokens=1,2,3,4,5,6 delims=\" %%a in ("%str%") do (
|
||||
+ set tloc=%%c&set plat=%%d&set conf=%%e&set file=%%f
|
||||
+)
|
||||
if /i "%file%" NEQ "" (goto next)
|
||||
call :seterr & echo ERROR: %1 is not supported & exit /b %errorlevel%
|
||||
|
||||
@@ -42,9 +44,9 @@ call :seterr & echo "postbuild copy error ERROR: target=%tloc%, plat=%plat%, con
|
||||
|
||||
:is2nd:
|
||||
rem set the target and final binary output directories
|
||||
-set tgt_dir="vs%vs_ver%\%loc%%plat%\%conf%\"
|
||||
-set bin_dir="..\%extn%\%plat%\%conf%\"
|
||||
-set hdr_dir="..\%extn%\%plat%\%conf%\"
|
||||
+set "tgt_dir=vs%vs_ver%\%loc%%plat%\%conf%"
|
||||
+set "bin_dir=..\%extn%\%plat%\%conf%"
|
||||
+set "hdr_dir=..\%extn%\%plat%\%conf%"
|
||||
|
||||
rem output parametrers for the MPIR tests
|
||||
if /i "%filename%" EQU "mpirxx" goto skip
|
||||
@@ -66,43 +68,42 @@ rem %1 = target (build output) directory
|
||||
rem %2 = binary destination directory
|
||||
rem %3 = configuration (debug/release)
|
||||
rem %4 = library (lib/dll)
|
||||
-rem %5 = file name
|
||||
+rem %5 = file name (mpir | mpirxx)
|
||||
:copyb
|
||||
if "%4" EQU "dll" (
|
||||
- copy %1mpir.dll %2mpir.dll > nul 2>&1
|
||||
- copy %1mpir.exp %2mpir.exp > nul 2>&1
|
||||
- copy %1mpir.lib %2mpir.lib > nul 2>&1
|
||||
- if exist %1mpir.pdb (copy %1mpir.pdb %2mpir.pdb > nul 2>&1)
|
||||
+ copy "%~1\mpir.dll" "%~2\mpir.dll" > nul 2>&1
|
||||
+ copy "%~1\mpir.exp" "%~2\mpir.exp" > nul 2>&1
|
||||
+ copy "%~1\mpir.lib" "%~2\mpir.lib" > nul 2>&1
|
||||
+ if exist "%~1\mpir.pdb" copy "%~1\mpir.pdb" "%~2\mpir.pdb" > nul 2>&1
|
||||
) else if "%4" EQU "lib" (
|
||||
if "%5" EQU "mpir" (
|
||||
- if exist %1mpir.lib (
|
||||
- copy %1mpir.lib %2mpir.lib > nul 2>&1
|
||||
- if exist %1mpir.pdb (copy %1mpir.pdb %2mpir.pdb > nul 2>&1)
|
||||
+ if exist "%~1\mpir.lib" (
|
||||
+ copy "%~1\mpir.lib" "%~2\mpir.lib" > nul 2>&1
|
||||
+ if exist "%~1\mpir.pdb" copy "%~1\mpir.pdb" "%~2\mpir.pdb" > nul 2>&1
|
||||
+ ) else (
|
||||
+ echo "Not Found MPIR at location" "%~1\mpir.lib"
|
||||
)
|
||||
) else if "%5" EQU "mpirxx" (
|
||||
- if exist %1mpirxx.lib (
|
||||
- copy %1mpirxx.lib %2mpirxx.lib > nul 2>&1
|
||||
- if exist %1mpirxx.pdb (copy %1mpirxx.pdb %2mpirxx.pdb > nul 2>&1)
|
||||
+ if exist "%~1\mpirxx.lib" (
|
||||
+ copy "%~1\mpirxx.lib" "%~2\mpirxx.lib" > nul 2>&1
|
||||
+ if exist "%~1\mpirxx.pdb" copy "%~1\mpirxx.pdb" "%~2\mpirxx.pdb" > nul 2>&1
|
||||
)
|
||||
)
|
||||
) else (
|
||||
- call :seterr & echo ERROR: illegal library type %4 & exit /b %errorlevel%
|
||||
+ call :seterr & echo ERROR: illegal library type %4 & exit /b %errorlevel%
|
||||
)
|
||||
-
|
||||
-rem set configuration for the tests
|
||||
-call gen_test_config_props %plat% %conf% %vs_ver%
|
||||
exit /b 0
|
||||
|
||||
rem copy headers to final destination directory
|
||||
:copyh
|
||||
-copy ..\config.h %1config.h > nul 2>&1
|
||||
-copy ..\gmp-mparam.h %1gmp-mparam.h > nul 2>&1
|
||||
-copy ..\mpir.h %1mpir.h > nul 2>&1
|
||||
-copy ..\mpir.h %1gmp.h > nul 2>&1
|
||||
-copy ..\gmp-impl.h %1gmp-impl.h > nul 2>&1
|
||||
-copy ..\longlong.h %1longlong.h > nul 2>&1
|
||||
-copy ..\mpirxx.h %1mpirxx.h > nul 2>&1
|
||||
-copy ..\mpirxx.h %1gmpxx.h > nul 2>&1
|
||||
+copy "..\config.h" "%~1\config.h" > nul 2>&1
|
||||
+copy "..\gmp-mparam.h" "%~1\gmp-mparam.h" > nul 2>&1
|
||||
+copy "..\mpir.h" "%~1\mpir.h" > nul 2>&1
|
||||
+copy "..\mpir.h" "%~1\gmp.h" > nul 2>&1
|
||||
+copy "..\gmp-impl.h" "%~1\gmp-impl.h" > nul 2>&1
|
||||
+copy "..\longlong.h" "%~1\longlong.h" > nul 2>&1
|
||||
+copy "..\mpirxx.h" "%~1\mpirxx.h" > nul 2>&1
|
||||
+copy "..\mpirxx.h" "%~1\gmpxx.h" > nul 2>&1
|
||||
exit /b 0
|
||||
|
||||
:seterr
|
||||
diff --git a/msvc/prebuild.bat b/msvc/prebuild.bat
|
||||
index 243d054f..c1d49c67 100644
|
||||
--- a/msvc/prebuild.bat
|
||||
+++ b/msvc/prebuild.bat
|
||||
@@ -1,29 +1,56 @@
|
||||
@echo off
|
||||
-rem %1 = mpn directory (generic, x86\... or x86_64\...)
|
||||
-rem %2 = platform (win32 or x64)
|
||||
+rem %1 = mpn directory (generic, x86\... or x86_64\... or arm64\...)
|
||||
+rem %2 = platform (win32, x64/amd64, or arm64)
|
||||
rem %3 = MSVC version number (e.g. 14)
|
||||
|
||||
-if /i "%2" EQU "win32" ((set platform=win32) & (set bdir=x86w\)) else ((set platform=x64) & (set bdir=x86_64w\))
|
||||
-set sdir=
|
||||
-if /i "%1" EQU "gc" ((set sdir=generic) & (set bdir=generic)) else (set sdir=%bdir%%1)
|
||||
-if not exist ..\mpn\%sdir% (call :seterr & echo ERROR: %1 is not supported & exit /b %errorlevel%)
|
||||
+set "platform="
|
||||
+set "bdir="
|
||||
+
|
||||
+if /i "%2"=="win32" (
|
||||
+ set "platform=win32"
|
||||
+ set "bdir=x86w\"
|
||||
+) else if /i "%2"=="x64" (
|
||||
+ set "platform=x64"
|
||||
+ set "bdir=x86_64w\"
|
||||
+) else if /i "%2"=="arm64" (
|
||||
+ set "platform=arm64"
|
||||
+ set "bdir=arm64w\"
|
||||
+) else (
|
||||
+ call :seterr & echo ERROR: Unsupported platform "%2" (expected win32, x64/amd64, or arm64) & exit /b %errorlevel%
|
||||
+)
|
||||
+
|
||||
+set "sdir="
|
||||
+if /i "%1"=="gc" (
|
||||
+ rem Generic C (portable) implementation
|
||||
+ set "sdir=generic"
|
||||
+ set "bdir=generic"
|
||||
+) else (
|
||||
+ set "sdir=%bdir%%~1"
|
||||
+)
|
||||
+
|
||||
+if not exist "..\mpn\%sdir%" (
|
||||
+ call :seterr & echo ERROR: %1 is not supported & exit /b %errorlevel%
|
||||
+)
|
||||
|
||||
echo building MPIR for %1 (%platform%) from directory mpn\%sdir%
|
||||
|
||||
-set cdir=vs%3\cdata\mpn\%sdir%\
|
||||
-set sdir=..\mpn\%sdir%\
|
||||
-set bdir=..\mpn\%bdir%\
|
||||
+set "cdir=vs%3\cdata\mpn\%sdir%\"
|
||||
+set "sdir=..\mpn\%sdir%\"
|
||||
+set "bdir=..\mpn\%bdir%\"
|
||||
|
||||
call gen_mpir_h %platform%
|
||||
call gen_config_h %cdir%
|
||||
|
||||
-if exist %sdir%\gmp-mparam.h (call out_copy_rename %sdir%\gmp-mparam.h ..\ gmp-mparam.h) else (
|
||||
- call out_copy_rename %bdir%\gmp-mparam.h ..\ gmp-mparam.h)
|
||||
+if exist "%sdir%\gmp-mparam.h" (
|
||||
+ call out_copy_rename "%sdir%\gmp-mparam.h" "..\" "gmp-mparam.h"
|
||||
+) else (
|
||||
+ call out_copy_rename "%bdir%\gmp-mparam.h" "..\" "gmp-mparam.h"
|
||||
+)
|
||||
|
||||
-type ..\longlong_pre.h >tmp.h
|
||||
-type %bdir%\longlong_inc.h >>tmp.h
|
||||
-type ..\longlong_post.h >>tmp.h
|
||||
-call out_copy_rename tmp.h ..\ longlong.h
|
||||
+type "..\longlong_pre.h" > tmp.h
|
||||
+type "%bdir%\longlong_inc.h" >> tmp.h
|
||||
+type "..\longlong_post.h" >> tmp.h
|
||||
+call out_copy_rename tmp.h "..\" "longlong.h"
|
||||
del tmp.h
|
||||
|
||||
exit /b 0
|
||||
diff --git a/msvc/vs22/lib_mpir_cxx/lib_mpir_cxx.vcxproj b/msvc/vs22/lib_mpir_cxx/lib_mpir_cxx.vcxproj
|
||||
index 0aca0c6e..e4bcf619 100644
|
||||
--- a/msvc/vs22/lib_mpir_cxx/lib_mpir_cxx.vcxproj
|
||||
+++ b/msvc/vs22/lib_mpir_cxx/lib_mpir_cxx.vcxproj
|
||||
@@ -1,6 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="19.30.30401" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
+ <ProjectConfiguration Include="Debug|ARM64">
|
||||
+ <Configuration>Debug</Configuration>
|
||||
+ <Platform>ARM64</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
+ <ProjectConfiguration Include="Release|ARM64">
|
||||
+ <Configuration>Release</Configuration>
|
||||
+ <Platform>ARM64</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
@@ -40,11 +48,21 @@
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <UseDebugLibraries>false</UseDebugLibraries>
|
||||
+ <PlatformToolset>v143</PlatformToolset>
|
||||
+ </PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <UseDebugLibraries>true</UseDebugLibraries>
|
||||
+ <PlatformToolset>v143</PlatformToolset>
|
||||
+ </PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
@@ -58,17 +76,27 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
<Import Project="..\..\mpir_release_lib.props" />
|
||||
</ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
+ <Import Project="..\..\mpir_release_lib.props" />
|
||||
+ </ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
<Import Project="..\..\mpir_debug_lib.props" />
|
||||
</ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
+ <Import Project="..\..\mpir_debug_lib.props" />
|
||||
+ </ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.21006.1</_ProjectFileVersion>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mpirxx</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mpirxx</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mpirxx</TargetName>
|
||||
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">mpirxx</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mpirxx</TargetName>
|
||||
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">mpirxx</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
@@ -99,6 +127,17 @@ postbuild "$(TargetPath)" 22
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
+postbuild "$(TargetPath)" 22
|
||||
+ </Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
+ <ClCompile>
|
||||
+ <AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>NDEBUG;WIN32;_LIB;HAVE_CONFIG_H;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ </ClCompile>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>cd ..\..\
|
||||
postbuild "$(TargetPath)" 22
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
@@ -110,6 +149,17 @@ postbuild "$(TargetPath)" 22
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
+postbuild "$(TargetPath)" 22
|
||||
+ </Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
+ <ClCompile>
|
||||
+ <AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>_DEBUG;WIN32;_LIB;HAVE_CONFIG_H;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ </ClCompile>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>cd ..\..\
|
||||
postbuild "$(TargetPath)" 22
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
@@ -141,7 +191,7 @@ postbuild "$(TargetPath)" 22
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
-<ItemGroup>
|
||||
+ <ItemGroup>
|
||||
<None Include="..\..\..\gmp-h.in" />
|
||||
- </ItemGroup>
|
||||
-</Project>
|
||||
+ </ItemGroup>
|
||||
+</Project>
|
||||
\ No newline at end of file
|
||||
diff --git a/msvc/vs22/lib_mpir_gc/lib_mpir_gc.vcxproj b/msvc/vs22/lib_mpir_gc/lib_mpir_gc.vcxproj
|
||||
index 350ee110..faf49ac3 100644
|
||||
--- a/msvc/vs22/lib_mpir_gc/lib_mpir_gc.vcxproj
|
||||
+++ b/msvc/vs22/lib_mpir_gc/lib_mpir_gc.vcxproj
|
||||
@@ -1,6 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="19.30.30401" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
+ <ProjectConfiguration Include="Debug|ARM64">
|
||||
+ <Configuration>Debug</Configuration>
|
||||
+ <Platform>ARM64</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
+ <ProjectConfiguration Include="Release|ARM64">
|
||||
+ <Configuration>Release</Configuration>
|
||||
+ <Platform>ARM64</Platform>
|
||||
+ </ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
@@ -40,11 +48,21 @@
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <UseDebugLibraries>false</UseDebugLibraries>
|
||||
+ <PlatformToolset>v143</PlatformToolset>
|
||||
+ </PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
+ <ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
+ <UseDebugLibraries>true</UseDebugLibraries>
|
||||
+ <PlatformToolset>v143</PlatformToolset>
|
||||
+ </PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
@@ -58,23 +76,32 @@
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
<Import Project="..\..\mpir_release_lib.props" />
|
||||
</ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
+ <Import Project="..\..\mpir_release_lib.props" />
|
||||
+ </ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
<Import Project="..\..\mpir_debug_lib.props" />
|
||||
</ImportGroup>
|
||||
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
|
||||
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
|
||||
+ <Import Project="..\..\mpir_debug_lib.props" />
|
||||
+ </ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.21006.1</_ProjectFileVersion>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mpir</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mpir</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mpir</TargetName>
|
||||
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">mpir</TargetName>
|
||||
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mpir</TargetName>
|
||||
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">mpir</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<PreBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-prebuild gc Win32 22
|
||||
- </Command>
|
||||
+prebuild gc $(Platform) 22</Command>
|
||||
</PreBuildEvent>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
@@ -82,15 +109,13 @@ prebuild gc Win32 22
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-postbuild "$(TargetPath)" 22
|
||||
- </Command>
|
||||
+postbuild "$(TargetPath)" 22</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<PreBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-prebuild gc Win32 22
|
||||
- </Command>
|
||||
+prebuild gc $(Platform) 22</Command>
|
||||
</PreBuildEvent>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
@@ -98,15 +123,27 @@ prebuild gc Win32 22
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-postbuild "$(TargetPath)" 22
|
||||
- </Command>
|
||||
+postbuild "$(TargetPath)" 22</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<PreBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-prebuild gc x64 22
|
||||
- </Command>
|
||||
+prebuild gc $(Platform) 22</Command>
|
||||
+ </PreBuildEvent>
|
||||
+ <ClCompile>
|
||||
+ <AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>NDEBUG;WIN32;_LIB;HAVE_CONFIG_H;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ </ClCompile>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>cd ..\..\
|
||||
+postbuild "$(TargetPath)" 22</Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
+ <PreBuildEvent>
|
||||
+ <Command>cd ..\..\
|
||||
+prebuild gc $(Platform) 22</Command>
|
||||
</PreBuildEvent>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
@@ -114,15 +151,13 @@ prebuild gc x64 22
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-postbuild "$(TargetPath)" 22
|
||||
- </Command>
|
||||
+postbuild "$(TargetPath)" 22</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<PreBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-prebuild gc x64 22
|
||||
- </Command>
|
||||
+prebuild gc $(Platform) 22</Command>
|
||||
</PreBuildEvent>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
@@ -130,8 +165,21 @@ prebuild gc x64 22
|
||||
</ClCompile>
|
||||
<PostBuildEvent>
|
||||
<Command>cd ..\..\
|
||||
-postbuild "$(TargetPath)" 22
|
||||
- </Command>
|
||||
+postbuild "$(TargetPath)" 22</Command>
|
||||
+ </PostBuildEvent>
|
||||
+ </ItemDefinitionGroup>
|
||||
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
+ <PreBuildEvent>
|
||||
+ <Command>cd ..\..\
|
||||
+prebuild gc $(Platform) 22</Command>
|
||||
+ </PreBuildEvent>
|
||||
+ <ClCompile>
|
||||
+ <AdditionalIncludeDirectories>..\..\..\</AdditionalIncludeDirectories>
|
||||
+ <PreprocessorDefinitions>_DEBUG;WIN32;_LIB;HAVE_CONFIG_H;_WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
+ </ClCompile>
|
||||
+ <PostBuildEvent>
|
||||
+ <Command>cd ..\..\
|
||||
+postbuild "$(TargetPath)" 22</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ImportGroup>
|
||||
@@ -667,7 +715,7 @@ postbuild "$(TargetPath)" 22
|
||||
<ItemGroup>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
-<ItemGroup>
|
||||
+ <ItemGroup>
|
||||
<None Include="..\..\..\gmp-h.in" />
|
||||
- </ItemGroup>
|
||||
-</Project>
|
||||
+ </ItemGroup>
|
||||
+</Project>
|
||||
\ No newline at end of file
|
||||
diff --git a/msvc/vs22/msbuild.bat b/msvc/vs22/msbuild.bat
|
||||
index f119c3e9..36bfe28b 100644
|
||||
--- a/msvc/vs22/msbuild.bat
|
||||
+++ b/msvc/vs22/msbuild.bat
|
||||
@@ -1,7 +1,7 @@
|
||||
@echo off
|
||||
rem %1 = architecture
|
||||
rem %2 = library type (LIB|DLL)
|
||||
-rem %3 = platform (Win32|x64)
|
||||
+rem %3 = platform (Win32|x64|ARM64)
|
||||
rem %4 = configuration (Release|Debug)
|
||||
rem %5 = Windows SDK Version
|
||||
rem %6 = build tests (|+tests)
|
||||
@@ -31,15 +31,21 @@ if not exist !msb_exe! (
|
||||
|
||||
if "%4" NEQ "" if "%3" NEQ "" if "%2" NEQ "" if "%1" NEQ "" goto cont
|
||||
call :get_architectures -
|
||||
-echo usage: msbuild architecture=^<%architectures:|=^|%^> library_type=^<LIB^|DLL^> platform=^<Win32^|x64^> configuration=^<Release^|Debug^> [Windows_SDK_Version=^<n^>] [+tests]
|
||||
+echo usage: msbuild architecture=^<%architectures:|=^|%^> library_type=^<LIB^|DLL^> platform=^<Win32^|x64^|ARM64^> configuration=^<Release^|Debug^> [Windows_SDK_Version=^<n^>] [+tests]
|
||||
goto :eof
|
||||
|
||||
:cont
|
||||
rem example use: msbuild sandybridge_ivybridge dll x64 release
|
||||
if not exist "lib_mpir_%1" (call :get_architectures & call :seterr & echo ERROR: architecture is one of ^(%architectures%^) ^(not %1^) & exit /b %errorlevel%)
|
||||
if /i "%2" EQU "DLL" (set libp=dll) else (if /i "%2" EQU "LIB" (set libp=lib) else ((call :seterr & echo ERROR: library type is "lib" or "dll" ^(not "%2"^) & exit /b %errorlevel%)))
|
||||
-if /i "%3" EQU "x64" (set plat=x64) else (if /i "%3" EQU "Win32" (set plat=win32) else (call :seterr & echo ERROR: platform is "Win32" or "x64" ^(not "%3"^) & exit /b %errorlevel%))
|
||||
-if /i "%4" EQU "Debug" (set conf=Debug) else (if /i "%4" EQU "Release" (set conf=Release) else (call :seterr & echo ERROR: configuration is "Release" or "Debug" ^(not "%4"^) & exit /b %errorlevel%))
|
||||
+if /i "%3" EQU "x64" (set plat=x64) else (
|
||||
+ if /i "%3" EQU "Win32" (set plat=win32) else (
|
||||
+ if /i "%3" EQU "ARM64" (set plat=ARM64) else (
|
||||
+ call :seterr & echo ERROR: platform is "Win32", "x64", or "ARM64" ^(not %3^) & exit /b %errorlevel%
|
||||
+ )
|
||||
+ )
|
||||
+)
|
||||
+if /i "%4" EQU "Debug" (set conf=Debug) else (if /i "%4" EQU "Release" (set conf=Release) else (call :seterr & echo ERROR: configuration is "Release" or "Debug" ^(not %4^) & exit /b %errorlevel%))
|
||||
if /i "%5" NEQ "" if "%5" EQU "+tests" (set run_tests=y) else (set win_sdk=%5)
|
||||
if /i "%6" NEQ "" if "%6" EQU "+tests" (set run_tests=y)
|
||||
|
||||
Reference in New Issue
Block a user