Compare commits
339 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 773605330b | |||
| a9a45f886b | |||
| 6b6f70694e | |||
| 9a5e37c82b | |||
| 5625f62bf5 | |||
| d12f59fa72 | |||
| 13fcc62406 | |||
| 538859f60a | |||
| 75da994faf | |||
| 99827df89a | |||
| 054a900779 | |||
| e800f8b93d | |||
| 7163697362 | |||
| 29600711ae | |||
| 1d0ee61ba7 | |||
| fb909ace1a | |||
| 6ae5dbacf4 | |||
| 52bffa7f9c | |||
| e9a502ccec | |||
| f3d4eed19e | |||
| d260298ab2 | |||
| c7d0cff300 | |||
| 631deeb094 | |||
| 953a49f9ae | |||
| 2e94a7c3f1 | |||
| 68f10e1502 | |||
| 625a57c6de | |||
| 4348b9bff9 | |||
| 28ee1a7781 | |||
| d40119d617 | |||
| 774533911c | |||
| 7597b1b29c | |||
| bd8a2736d4 | |||
| aafb4b6147 | |||
| 2066ebcc11 | |||
| 795ebc0ac1 | |||
| 7612cf92c0 | |||
| db1f4d126a | |||
| b15820dd10 | |||
| f8f7884278 | |||
| 3318de7f6d | |||
| 726bf40d58 | |||
| 3860884db3 | |||
| 5784e3103d | |||
| 2a1d1d6e10 | |||
| 485643863f | |||
| c03777cfe6 | |||
| be442ff1be | |||
| 95e7910f69 | |||
| d5592ed2eb | |||
| a29806ef9e | |||
| 3a9d79dcd3 | |||
| b9c2e312e3 | |||
| f1db51df1a | |||
| 312a58ddce | |||
| 1e71708aba | |||
| ad6e00571e | |||
| c8d05951b0 | |||
| 0f8c3b3c83 | |||
| 25071dfec6 | |||
| cc28f5a92b | |||
| a57a7041ac | |||
| 17b90c3241 | |||
| 90089f91c6 | |||
| 37dd2a5607 | |||
| bc70130123 | |||
| 8d53141d5a | |||
| 0ffc62fbf3 | |||
| 4350e3df82 | |||
| 2ad601ed34 | |||
| f9e8d6d478 | |||
| 65cc5bf4c1 | |||
| 73e5985777 | |||
| de14e92720 | |||
| 09ad47d11b | |||
| debe63c1af | |||
| 6f2eb6c54a | |||
| 56ca431965 | |||
| 74e8b80fb4 | |||
| 7ecfe372ad | |||
| b017ab7596 | |||
| bd3905fe76 | |||
| 0c8048c14d | |||
| 77f72ecdfa | |||
| 723701f1b8 | |||
| bf96c63f7d | |||
| cef8251458 | |||
| 547981f32c | |||
| a3cc0245ca | |||
| 5d934a2baa | |||
| 4409a35441 | |||
| f637ef8016 | |||
| 5e2cefee12 | |||
| 67b01dcd0f | |||
| bc0efd7389 | |||
| 4b4e6fa7e2 | |||
| 17a0face6e | |||
| a3b2860789 | |||
| f8f22257b4 | |||
| 8284ed0cdb | |||
| d995e010cf | |||
| fcfc070825 | |||
| 55552770a6 | |||
| 350df4eee5 | |||
| 04a273c720 | |||
| 61641acf56 | |||
| 10035662dd | |||
| 056df7758b | |||
| 0522adac63 | |||
| 1f781e5cab | |||
| a30fd7cab4 | |||
| 94ca2423e9 | |||
| 2938c1fd0b | |||
| ab8710bd1e | |||
| a791abe23e | |||
| e70122f354 | |||
| 96fdced471 | |||
| 1c95f6cc3f | |||
| 0f03e412c3 | |||
| 6ca3e2a6db | |||
| 079446a4b6 | |||
| e706e568bd | |||
| 526a2a6a80 | |||
| 3e7a2c1b83 | |||
| 9bb04d3ffc | |||
| 7c4d45ab32 | |||
| dafec70097 | |||
| eca1d47d06 | |||
| 9671be1734 | |||
| 644f32d11c | |||
| 1626dd85f4 | |||
| 3c0103b4da | |||
| f9c4b6a98f | |||
| b01e93161e | |||
| ffbd3e50c5 | |||
| 98c4a1d110 | |||
| e2c4bcb217 | |||
| 7e60b6888e | |||
| bbf8ebcb52 | |||
| c1936b871e | |||
| 31d67b5e62 | |||
| 683e168ca1 | |||
| cbc0b4837f | |||
| 02ff6c00ef | |||
| 78f664e892 | |||
| d745265048 | |||
| 917991feab | |||
| 4877ab4426 | |||
| 48c5100d3b | |||
| 72caf7525e | |||
| 242d91bc17 | |||
| afb22ce7d5 | |||
| e45a670ff5 | |||
| 45042aa5e0 | |||
| 07aec0730f | |||
| 7e6da3edb3 | |||
| 4f0eafa92d | |||
| de75eded09 | |||
| f2b4bea4de | |||
| 4f28b2506d | |||
| 281da8ed77 | |||
| bdf4258895 | |||
| 385d9b9df7 | |||
| 0e40df4fa3 | |||
| b0c132f73a | |||
| 4fd802bf3d | |||
| e461040e17 | |||
| 43b574011e | |||
| 9bae914b51 | |||
| 945070bdff | |||
| d2b4afe1be | |||
| 3760f8fafe | |||
| b9e5cefddf | |||
| 9f5f757ccf | |||
| 3a147d7f62 | |||
| 9f1d14e5a7 | |||
| bce71f3797 | |||
| 253dca730d | |||
| e0f33a56ec | |||
| 2287931e9c | |||
| 1f7a498606 | |||
| a9e366b238 | |||
| 1ca0dfb1e0 | |||
| c11ba23a3d | |||
| 556c769b40 | |||
| 78173dd546 | |||
| 2196c16097 | |||
| 7af5db7cd4 | |||
| c58672cc25 | |||
| 85e022d76e | |||
| 872f40933f | |||
| 4491018f5e | |||
| a21c440b5b | |||
| 143e094db8 | |||
| 94e9e945d7 | |||
| 5e56115050 | |||
| 1ad654aab3 | |||
| 596ffb093b | |||
| 3576362fd8 | |||
| 2c949bb39a | |||
| 34faa0617b | |||
| 15f6b3803f | |||
| 8514a426bb | |||
| 2062324294 | |||
| 90c6218210 | |||
| 321bb7178d | |||
| 42dda0a07a | |||
| adb17d91f9 | |||
| 646cc59687 | |||
| 38759348cd | |||
| ff44f4f395 | |||
| a31051a937 | |||
| 5cfd69f337 | |||
| f4100f7951 | |||
| 785d5118d0 | |||
| fddd85817a | |||
| a689fc6377 | |||
| 8e5a7ed24e | |||
| 788217c73c | |||
| 1abc3a1422 | |||
| c31c34b7d2 | |||
| b22ecba179 | |||
| 22bc98b48b | |||
| cf70026570 | |||
| 3c4a865e0b | |||
| 8523bb317a | |||
| 4b00b268c0 | |||
| f0ca34d107 | |||
| 3834ecb06a | |||
| 047c9e3ee9 | |||
| 786b796f37 | |||
| 3fd8be72c2 | |||
| cb80081473 | |||
| 5ac84e2be7 | |||
| c8466e0606 | |||
| db5167bbaf | |||
| 7d6e26bfd5 | |||
| 2fd339ac6b | |||
| 6f6dc08696 | |||
| 6cb063ebd2 | |||
| fb95e3eb51 | |||
| 17a061f917 | |||
| 51db65b868 | |||
| faab9e04a3 | |||
| bea92455dd | |||
| 6be1b80a82 | |||
| 2927eadada | |||
| 4c5e90dc77 | |||
| f860973172 | |||
| 94ed0cd59c | |||
| 93ea1f98ac | |||
| b68a92f251 | |||
| 902da2e720 | |||
| d384aaeb9c | |||
| 133494af97 | |||
| 64fc9462b6 | |||
| 3d86e5fff3 | |||
| a24bb069aa | |||
| 159355d63a | |||
| 598cf4ba79 | |||
| c86a4c88a9 | |||
| 6a9e76c2af | |||
| 2070071c49 | |||
| 9bbf3bcaba | |||
| 0395c0c6c7 | |||
| a175ec4d28 | |||
| 139627b6ec | |||
| 6f2eb0a116 | |||
| d26561acee | |||
| de0374bdbd | |||
| 51463ab674 | |||
| 6012695cfe | |||
| 081b3fcf33 | |||
| 27a2c94b4a | |||
| b9f76042bb | |||
| e7ef307984 | |||
| 1f68e52ac2 | |||
| 87dfb75c21 | |||
| 8afb1b8b30 | |||
| 5572991a7c | |||
| 653b9288c0 | |||
| 233b0856af | |||
| ec29e3d60b | |||
| 70bc32b3df | |||
| ca781655b0 | |||
| 03e2cb70bb | |||
| c7c95e1f9d | |||
| b040c5e25b | |||
| 60b007d28a | |||
| 52130a3eb6 | |||
| 5e849d7b81 | |||
| a7a28f613b | |||
| 46b3bfecd1 | |||
| 11b62a0fdc | |||
| 732bb93826 | |||
| a0bda1afd3 | |||
| e0790601df | |||
| a9a4b0ccf0 | |||
| f8848051ca | |||
| b81031eecf | |||
| 95a7ea8dce | |||
| 98edb5a34c | |||
| 8ca2a55616 | |||
| 74141bec73 | |||
| f60c4fd3c5 | |||
| d9ee3522bc | |||
| 2538c47d01 | |||
| ec3dc71c0e | |||
| e5edd9a34d | |||
| f72359918d | |||
| dfd505a794 | |||
| 4a311fe4de | |||
| 9d4493e1da | |||
| a1d8fbdbe9 | |||
| 952abde48e | |||
| 168718063f | |||
| 4abcbbb4f9 | |||
| 1ac1b289c1 | |||
| c25173aa12 | |||
| ea8d303883 | |||
| 9d79337fa7 | |||
| 82a6ddb01c | |||
| a7152bdef0 | |||
| 6484a529b0 | |||
| 6e1e653ceb | |||
| 0488e4cccb | |||
| 3cf92fd508 | |||
| fb2bb7554e | |||
| be7661a83b | |||
| 9684e21d93 | |||
| ee5c401823 | |||
| 4aa3ffb765 | |||
| c9affcc622 | |||
| bddb8d1e56 | |||
| c4d3dad639 | |||
| adbf9093d3 | |||
| c8defbb77f | |||
| a14fc0a7f5 | |||
| 8d2717d25b |
@@ -1,85 +0,0 @@
|
||||
name: ci-blenderbim-daily
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-blenderbim-daily.yml'
|
||||
- 'src/blenderbim/**'
|
||||
- 'src/ifcopenshell-python/ifcopenshell/**'
|
||||
- 'src/bcf/bcf/**'
|
||||
- 'src/ifcclash/ifcclash/**'
|
||||
- 'src/ifccobie/**'
|
||||
- 'src/ifcdiff/**'
|
||||
- 'src/ifccsv/**'
|
||||
- 'src/ifcpatch/ifcpatch/**'
|
||||
- 'src/ifc4d/ifc4d/**'
|
||||
- 'src/ifc5d/ifc5d/**'
|
||||
- 'src/ifccityjson/**'
|
||||
branches:
|
||||
- v0.8.0
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
steps:
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
build:
|
||||
needs: activate
|
||||
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310, py311, py312]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
short_name: win,
|
||||
}
|
||||
- {
|
||||
name: "Linux Build",
|
||||
short_name: linux,
|
||||
}
|
||||
- {
|
||||
name: "MacOS Build",
|
||||
short_name: macos,
|
||||
}
|
||||
- {
|
||||
name: "MacOS ARM Build",
|
||||
short_name: macosm1,
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.11'
|
||||
- name: Get current version
|
||||
id: version
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cd src/blenderbim && make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
- name: Find zip file name
|
||||
id: find_zip
|
||||
run: |
|
||||
filepath=$(ls src/blenderbim/dist/blenderbim_*.zip)
|
||||
echo "filepath=$filepath" >> $GITHUB_OUTPUT
|
||||
echo "filename=$(basename $filepath)" >> $GITHUB_OUTPUT
|
||||
- name: Upload zip file to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ${{ steps.find_zip.outputs.filepath }}
|
||||
asset_name: ${{ steps.find_zip.outputs.filename }}
|
||||
release_name: "blenderbim-${{steps.version.outputs.version}}-alpha${{steps.date.outputs.date}} (unstable)"
|
||||
tag: "blenderbim-${{steps.version.outputs.version}}-alpha${{steps.date.outputs.date}}"
|
||||
overwrite: true
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Publish-blenderbim-chocolatey package
|
||||
name: ci-bonsai-choco
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -9,11 +9,12 @@ on:
|
||||
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||
# * * * * *
|
||||
- cron: "30 0 * * *" # 30min past utc midnight
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
major: 0
|
||||
minor: 0
|
||||
name: blenderbim
|
||||
name: bonsai
|
||||
choco_version: 1.1.0
|
||||
CHOCO_TOKEN: ${{ secrets.CHOCO_TOKEN }}
|
||||
|
||||
@@ -41,5 +42,6 @@ jobs:
|
||||
- name: Check in release tags if we should do a choco release and perform the release if needed
|
||||
id: do_choco_release
|
||||
run: |
|
||||
cd /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/ &&
|
||||
pip install pygithub
|
||||
cd /home/runner/work/IfcOpenShell/IfcOpenShell/choco/bonsai/ &&
|
||||
python3 choco_release.py
|
||||
@@ -0,0 +1,149 @@
|
||||
name: ci-bonsai-daily
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-bonsai-daily.yml'
|
||||
- 'src/bonsai/**'
|
||||
- 'src/ifcopenshell-python/ifcopenshell/**'
|
||||
- 'src/bcf/bcf/**'
|
||||
- 'src/ifcclash/ifcclash/**'
|
||||
- 'src/ifccobie/**'
|
||||
- 'src/ifcdiff/**'
|
||||
- 'src/ifccsv/**'
|
||||
- 'src/ifcpatch/ifcpatch/**'
|
||||
- 'src/ifc4d/ifc4d/**'
|
||||
- 'src/ifc5d/ifc5d/**'
|
||||
- 'src/ifccityjson/**'
|
||||
branches:
|
||||
- v0.8.0
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
steps:
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
build:
|
||||
needs: activate
|
||||
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py311, py312]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
short_name: win,
|
||||
}
|
||||
- {
|
||||
name: "Linux Build",
|
||||
short_name: linux,
|
||||
}
|
||||
- {
|
||||
name: "MacOS Build",
|
||||
short_name: macos,
|
||||
}
|
||||
- {
|
||||
name: "MacOS ARM Build",
|
||||
short_name: macosm1,
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.11'
|
||||
- name: Get current version
|
||||
id: version
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cd src/bonsai && make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
- name: Find zip file name
|
||||
id: find_zip
|
||||
run: |
|
||||
filepath=$(ls src/bonsai/dist/bonsai_*.zip)
|
||||
echo "filepath=$filepath" >> $GITHUB_OUTPUT
|
||||
echo "filename=$(basename $filepath)" >> $GITHUB_OUTPUT
|
||||
- name: Upload zip file to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ${{ steps.find_zip.outputs.filepath }}
|
||||
asset_name: ${{ steps.find_zip.outputs.filename }}
|
||||
release_name: "bonsai-${{steps.version.outputs.version}}-alpha${{steps.date.outputs.date}} (unstable)"
|
||||
tag: "bonsai-${{steps.version.outputs.version}}-alpha${{steps.date.outputs.date}}"
|
||||
overwrite: true
|
||||
body: "See README in https://github.com/IfcOpenShell/bonsai_unstable_repo/ on how to setup autoupdates for daily Bonsai builds."
|
||||
|
||||
update-extensions-repo-and-run-tests:
|
||||
needs: [build]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout bonsai_unstable_repo repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: IfcOpenShell/bonsai_unstable_repo
|
||||
token: ${{ secrets.IOS_TO_BLENDER_REPO }}
|
||||
path: bonsai_unstable_repo
|
||||
|
||||
- name: Update index.json on extensions repo
|
||||
run: |
|
||||
set -x -e
|
||||
|
||||
# Download Blender.
|
||||
wget -q -O blender.tar.xz https://ftp.nluug.nl/pub/graphics/blender/release/Blender4.2/blender-4.2.0-linux-x64.tar.xz
|
||||
tar -xf blender.tar.xz
|
||||
|
||||
# Setup Blender.
|
||||
BLENDER_PATH=$(find blender-*/ -maxdepth 0 -exec readlink -f {} \;)
|
||||
export PATH="$PATH:$BLENDER_PATH"
|
||||
blender --version
|
||||
|
||||
cd bonsai_unstable_repo
|
||||
pip install -r requirements.txt
|
||||
python setup_extensions_repo.py --last-tag
|
||||
git config --global user.name 'IfcOpenBot'
|
||||
git config --global user.email 'IfcOpenBot@users.noreply.github.com'
|
||||
git add index.json
|
||||
git add readme.md
|
||||
git commit -m "Update index.json"
|
||||
git push
|
||||
- name: Run bonsai tests
|
||||
run: |
|
||||
set -x -e
|
||||
BLENDER_PATH=$(find blender-*/ -maxdepth 0 -exec readlink -f {} \;)
|
||||
export PATH="$PATH:$BLENDER_PATH"
|
||||
bonsai_zip="$(pwd)/$(ls bonsai_unstable_repo/bonsai_py311*-linux-x64.zip)"
|
||||
blender --version
|
||||
blender --command extension install-file -r user_default -e $bonsai_zip
|
||||
blender --command extension list
|
||||
|
||||
wget -q -O sverchok.zip https://github.com/nortikin/sverchok/archive/refs/heads/master.zip
|
||||
# ifcsverchok expecting sverchok to be named "sverchok" and not "sverchok-master".
|
||||
unzip -q sverchok.zip
|
||||
mv sverchok-master sverchok
|
||||
zip -q -r sverchok.zip sverchok
|
||||
rm -r sverchok
|
||||
blender --command extension install-file -r user_default sverchok.zip
|
||||
|
||||
git clone https://github.com/IfcOpenShell/IfcOpenShell.git IfcOpenShell
|
||||
cd IfcOpenShell/src/ifcsverchok
|
||||
make dist
|
||||
sverchok_zip="$(pwd)/dist/$(ls dist)"
|
||||
blender --command extension install-file -r user_default $sverchok_zip
|
||||
|
||||
cd ../bonsai
|
||||
pip install pytest-blender
|
||||
blender --background --python scripts/setup_pytest.py
|
||||
blender --python-expr "import bonsai; print(bonsai.bbim_semver); import ifcopenshell; print(ifcopenshell.version)" --background
|
||||
make test
|
||||
@@ -1,6 +1,6 @@
|
||||
name: ci-blenderbim
|
||||
name: ci-bonsai
|
||||
|
||||
# Differences from ci-blenderbim-daily.yml:
|
||||
# Differences from ci-bonsai-daily.yml:
|
||||
# - make has IS_STABLE=TRUE
|
||||
# - action is never triggered and executed only manually
|
||||
# - doesn't add a current date to the release and tag
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310, py311, py312]
|
||||
pyver: [py310, py311, py312]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
@@ -53,12 +53,12 @@ jobs:
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cd src/blenderbim &&
|
||||
cd src/bonsai &&
|
||||
make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }} IS_STABLE=TRUE
|
||||
- name: Find zip file name
|
||||
id: find_zip
|
||||
run: |
|
||||
filepath=$(ls src/blenderbim/dist/blenderbim_*.zip)
|
||||
filepath=$(ls src/bonsai/dist/bonsai_*.zip)
|
||||
echo "filepath=$filepath" >> $GITHUB_OUTPUT
|
||||
echo "filename=$(basename $filepath)" >> $GITHUB_OUTPUT
|
||||
- name: Upload zip file to release
|
||||
@@ -67,6 +67,6 @@ jobs:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: ${{ steps.find_zip.outputs.filepath }}
|
||||
asset_name: ${{ steps.find_zip.outputs.filename }}
|
||||
release_name: "blenderbim-${{steps.version.outputs.version}}"
|
||||
tag: "blenderbim-${{steps.version.outputs.version}}"
|
||||
release_name: "bonsai-${{steps.version.outputs.version}}"
|
||||
tag: "bonsai-${{steps.version.outputs.version}}"
|
||||
overwrite: true
|
||||
@@ -47,6 +47,7 @@ jobs:
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil shapely
|
||||
pip install mathutils
|
||||
pip install src/bcf --no-deps
|
||||
pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
|
||||
@@ -106,7 +107,7 @@ jobs:
|
||||
|
||||
- name: Run IfcConvert on Sample files
|
||||
run: |
|
||||
(find test/input src/blenderbim/test/files -name '*.ifc' | while read i; do \
|
||||
(find test/input src/bonsai/test/files -name '*.ifc' | while read i; do \
|
||||
echo $i | tee -a log; \
|
||||
timeout 1m "$(which IfcConvert)" -yv "$i" "$i.obj" --validate >> log 2>&1; \
|
||||
echo $i $? >> statuses; \
|
||||
@@ -125,4 +126,11 @@ jobs:
|
||||
python tests.py
|
||||
cd ../src/ifcopenshell-python
|
||||
mv ifcopenshell ifcopenshell-local # Force testing on installed module
|
||||
make test-safe
|
||||
make test
|
||||
cd ../bcf && make test
|
||||
pip install requests
|
||||
cd ../bsdd && make test
|
||||
pip install deepdiff
|
||||
cd ../ifcdiff && make test
|
||||
cd ../ifcpatch && make test
|
||||
cd ../ifctester && make test
|
||||
|
||||
@@ -8,12 +8,12 @@ on:
|
||||
jobs:
|
||||
activate:
|
||||
if: github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- run: echo ok go
|
||||
build:
|
||||
needs: activate
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@@ -52,8 +52,8 @@ jobs:
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.10 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.10.so \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES=/usr/lib/x86_64-linux-gnu/libxml2.so \
|
||||
-DGLTF_SUPPORT=On \
|
||||
|
||||
@@ -73,19 +73,19 @@ src/ifcopenshell-python/test/build
|
||||
# mypy cache
|
||||
.mypy_cache
|
||||
|
||||
# blenderbim libs
|
||||
src/blenderbim/blenderbim/libs
|
||||
# bonsai libs
|
||||
src/bonsai/bonsai/libs
|
||||
|
||||
# blenderbim i18n
|
||||
src/blenderbim/blenderbim/translations.py
|
||||
# bonsai i18n
|
||||
src/bonsai/bonsai/translations.py
|
||||
|
||||
# blenderbim test temp files
|
||||
src/blenderbim/test/files/temp
|
||||
src/blenderbim/test/files/basic.ifc.cache.blend
|
||||
src/blenderbim/test/files/basic.ifc.cache.sqlite
|
||||
# bonsai test temp files
|
||||
src/bonsai/test/files/temp
|
||||
src/bonsai/test/files/basic.ifc.cache.blend
|
||||
src/bonsai/test/files/basic.ifc.cache.sqlite
|
||||
|
||||
src/blenderbim/drawings
|
||||
src/blenderbim/layouts
|
||||
src/bonsai/drawings
|
||||
src/bonsai/layouts
|
||||
|
||||
# ifcopenshell swig and compiled files
|
||||
src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper.so
|
||||
@@ -100,4 +100,4 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
|
||||
.cache
|
||||
|
||||
# Brickschema
|
||||
src/blenderbim/blenderbim/bim/schema/Brick.ttl
|
||||
src/bonsai/bonsai/bim/schema/Brick.ttl
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- mode: Dockerfile -*-
|
||||
|
||||
FROM ubuntu:focal
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ARG CHANNEL
|
||||
ENV CHANNEL=${CHANNEL:-latest}
|
||||
@@ -23,7 +23,7 @@ RUN echo "deb http://archive.ubuntu.com/ubuntu focal-proposed main restricted" |
|
||||
echo "deb http://archive.ubuntu.com/ubuntu focal-proposed multiverse" | tee -a /etc/apt/sources.list; \
|
||||
apt-get -qq update; \
|
||||
apt-get -y install tzdata dos2unix rsync; \
|
||||
apt-get -y install python3 libxml2 libpython3.8 \
|
||||
apt-get -y install python3 libxml2 libpython3.10 \
|
||||
libboost-all-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev \
|
||||
libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
|
||||
@@ -22,10 +22,10 @@ For more information, see:
|
||||
* [IfcOpenShell C++ Installation](https://docs.ifcopenshell.org/ifcopenshell/installation.html)
|
||||
* [IfcOpenShell Python Installation](https://docs.ifcopenshell.org/ifcopenshell-python/installation.html)
|
||||
* [IfcOpenShell Python Hello World Tutorial](https://docs.ifcopenshell.org/ifcopenshell-python/hello_world.html)
|
||||
* [BlenderBIM Add-on Website](https://blenderbim.org)
|
||||
* [BlenderBIM Add-on Documentation](https://docs.blenderbim.org/index.html)
|
||||
* [Add-on Installation](https://docs.blenderbim.org/users/installation.html)
|
||||
* [Exploring an IFC model](https://docs.blenderbim.org/users/exploring_an_ifc_model.html)
|
||||
* [Bonsai Website](https://bonsaibim.org)
|
||||
* [Bonsai Documentation](https://docs.bonsaibim.org/index.html)
|
||||
* [Add-on Installation](https://docs.bonsaibim.org/users/installation.html)
|
||||
* [Exploring an IFC model](https://docs.bonsaibim.org/users/exploring_an_ifc_model.html)
|
||||
|
||||
Development is sponsored through your generous donations!
|
||||
|
||||
@@ -37,7 +37,7 @@ Contents
|
||||
| Name | Description | License | Service |
|
||||
| ------------------------- | --------------------------------------------------------------------- | ------------------- | ------- |
|
||||
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later | [](https://pypi.org/project/bcf-client/) |
|
||||
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later | [](https://blenderbim.org/download.html) [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=blenderbim&expanded=true) [](https://community.chocolatey.org/packages/blenderbim-nightly/) |
|
||||
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later | [](https://bonsaibim.org/download.html) [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=blenderbim&expanded=true) [](https://community.chocolatey.org/packages/blenderbim-nightly/) |
|
||||
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later | [](https://pypi.org/project/bsdd/) |
|
||||
| ifc2ca | Utility to convert IFC structural analysis models to Code_Aster | LGPL-3.0-or-later |
|
||||
| ifc4d | Convert to and from IFC and project management software | LGPL-3.0-or-later | [](https://pypi.org/project/ifc4d/) |
|
||||
@@ -46,12 +46,12 @@ Contents
|
||||
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later\* |
|
||||
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifccityjson/) |
|
||||
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later | [](https://pypi.org/project/ifcclash/) |
|
||||
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcconvert/installation.html)
|
||||
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcconvert/installation.html) [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcconvert&expanded=true)
|
||||
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifccsv/) |
|
||||
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later | [](https://pypi.org/project/ifcdiff/) |
|
||||
| ifcfm | Extract IFC data for FM handover requirements | LGPL-3.0-or-later | [](https://pypi.org/project/ifcfm/) |
|
||||
| ifcmax | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcmax.html)
|
||||
| ifcopenshell-python | Python library for IFC manipulation | LGPL-3.0-or-later\* | [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcopenshell-python&expanded=true) [](https://pypi.org/project/ifcopenshell/) [](https://anaconda.org/conda-forge/ifcopenshell) [](https://anaconda.org/ifcopenshell/ifcopenshell) [](https://hub.docker.com/r/aecgeeks/ifcopenshell) [](https://aur.archlinux.org/packages/ifcopenshell) [](https://aur.archlinux.org/packages/ifcopenshell-git) |
|
||||
| ifcopenshell-python | Python library for IFC manipulation | LGPL-3.0-or-later\* | [](https://docs.ifcopenshell.org/ifcopenshell-python/installation.html) [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcopenshell-python&expanded=true) [](https://pypi.org/project/ifcopenshell/) [](https://anaconda.org/conda-forge/ifcopenshell) [](https://anaconda.org/ifcopenshell/ifcopenshell) [](https://hub.docker.com/r/aecgeeks/ifcopenshell) [](https://aur.archlinux.org/packages/ifcopenshell) [](https://aur.archlinux.org/packages/ifcopenshell-git) |
|
||||
| ifcpatch | Utility to run pre-packaged scripts to manipulate IFCs | LGPL-3.0-or-later | [](https://pypi.org/project/ifcpatch/) |
|
||||
| ifcsverchok | Blender Add-on for visual node programming with IFC | GPL-3.0-or-later | [](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcsverchok&expanded=true)
|
||||
| ifctester | Library, CLI and webapp for IDS model auditing | LGPL-3.0-or-later | [](https://pypi.org/project/ifctester/) |
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<licenseUrl>https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.8.0/COPYING</licenseUrl>
|
||||
<requireLicenseAcceptance>true</requireLicenseAcceptance>
|
||||
<projectSourceUrl>https://github.com/IfcOpenShell/IfcOpenShell</projectSourceUrl>
|
||||
<docsUrl>https://docs.blenderbim.org/</docsUrl>
|
||||
<docsUrl>https://docs.bonsaibim.org/</docsUrl>
|
||||
<!--<mailingListUrl></mailingListUrl>-->
|
||||
<bugTrackerUrl>https://github.com/IfcOpenShell/IfcOpenShell/issues</bugTrackerUrl>
|
||||
<tags>blender bim blenderbim ifc python opensource foss</tags>
|
||||
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
@@ -14,9 +14,11 @@ import os
|
||||
import pathlib
|
||||
import re
|
||||
from urllib import request
|
||||
from github import Github
|
||||
from typing import NoReturn
|
||||
|
||||
|
||||
def get_repo_tag_names():
|
||||
def get_repo_tag_names() -> list[str]:
|
||||
git_return = os.popen("git tag -l").read()
|
||||
tag_names = [tag_name for tag_name in git_return.split("\n") if tag_name]
|
||||
print(f"{len(tag_names)} tag_names found in repo")
|
||||
@@ -43,7 +45,7 @@ def get_latest_choco_blender_version() -> list:
|
||||
return re.findall(RE_BLENDER_VERSION_MIN_MAJ_PAT, html_txt)
|
||||
|
||||
|
||||
def get_file_sha256_hash(file_path):
|
||||
def get_file_sha256_hash(file_path: str) -> str:
|
||||
BLOCKSIZE = 65536
|
||||
hasher = hashlib.sha256()
|
||||
|
||||
@@ -56,16 +58,29 @@ def get_file_sha256_hash(file_path):
|
||||
return hasher.hexdigest()
|
||||
|
||||
|
||||
def quit_with_error_message(message: str):
|
||||
def quit_with_error_message(message: str) -> NoReturn:
|
||||
print(f"ERROR: {message}")
|
||||
quit(0)
|
||||
|
||||
|
||||
def get_release_zip(tag: str) -> tuple[str, str]:
|
||||
g = Github()
|
||||
repo = g.get_repo("IfcOpenShell/IfcOpenShell")
|
||||
release = repo.get_release(tag)
|
||||
for asset in release.get_assets():
|
||||
asset_name = asset.name
|
||||
if python_version not in asset_name:
|
||||
continue
|
||||
if TARGET_OS not in asset_name:
|
||||
continue
|
||||
return (asset_name, asset.browser_download_url)
|
||||
raise Exception(f"Couldn't find the release matching '{python_version}' and '{TARGET_OS}' in tag '{tag}'.")
|
||||
|
||||
|
||||
start = datetime.datetime.now()
|
||||
|
||||
URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
|
||||
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
|
||||
URL_IFCOS_RELEASES = "https://github.com/IfcOpenShell/IfcOpenShell/releases/download/"
|
||||
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
|
||||
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
|
||||
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
|
||||
@@ -79,7 +94,7 @@ os.chdir(BLENDERBIM_DIR)
|
||||
blenderbim_date_yesterday = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%y%m%d")
|
||||
should_release = False
|
||||
target_release_tag = ""
|
||||
target_os = "win"
|
||||
TARGET_OS = "windows-x64"
|
||||
|
||||
git_status = os.popen("git status").read()
|
||||
print(git_status)
|
||||
@@ -130,10 +145,7 @@ print(f"{python_version=}")
|
||||
blenderbim_build_version = target_release_tag.replace("blenderbim-", "")
|
||||
|
||||
# url_blenderbim_py3x_win_zip
|
||||
release_zip_file_name = f"{target_release_tag}-{python_version}-{target_os}.zip"
|
||||
|
||||
# download release
|
||||
url_blenderbim_py3x_win_zip = f"{URL_IFCOS_RELEASES}{target_release_tag}/{release_zip_file_name}"
|
||||
release_zip_file_name, url_blenderbim_py3x_win_zip = get_release_zip(target_release_tag)
|
||||
os.popen(f"wget {url_blenderbim_py3x_win_zip} --no-verbose").read()
|
||||
|
||||
# sha256sum_blenderbim_py310_win_zip
|
||||
@@ -221,10 +221,11 @@ endif()
|
||||
|
||||
if(GLTF_SUPPORT OR CITYJSON_SUPPORT)
|
||||
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
|
||||
find_file(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann)
|
||||
find_path(json_header_path "nlohmann/json.hpp" HINTS ${JSON_INCLUDE_DIR})
|
||||
set(JSON_INCLUDE_DIR ${json_header_path})
|
||||
|
||||
if(json_hpp)
|
||||
message(STATUS "JSON for Modern C++ header file found")
|
||||
if(json_header_path)
|
||||
message(STATUS "JSON for Modern C++ header file found in ${JSON_INCLUDE_DIR}")
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to find JSON for Modern C++ header file, aborting")
|
||||
endif()
|
||||
|
||||
@@ -76,14 +76,14 @@ about:
|
||||
For more information, see:
|
||||
|
||||
* [IfcOpenShell Website](http://ifcopenshell.org)
|
||||
* [IfcOpenShell Documentation](http://blenderbim.org/docs-python)
|
||||
* [IfcOpenShell C++ Installation](https://blenderbim.org/docs-python/ifcopenshell/installation.html)
|
||||
* [IfcOpenShell Python Installation](https://blenderbim.org/docs-python/ifcopenshell-python/installation.html)
|
||||
* [IfcOpenShell Python Hello World Tutorial](https://blenderbim.org/docs-python/ifcopenshell-python/hello_world.html)
|
||||
* [BlenderBIM Add-on Website](https://blenderbim.org)
|
||||
* [BlenderBIM Add-on Documentation](http://blenderbim.org/docs)
|
||||
* [Add-on Installation](https://blenderbim.org/docs/users/installation.html)
|
||||
* [Exploring an IFC model](https://blenderbim.org/docs/users/exploring_an_ifc_model.html)
|
||||
* [IfcOpenShell Documentation](http://bonsaibim.org/docs-python)
|
||||
* [IfcOpenShell C++ Installation](https://bonsaibim.org/docs-python/ifcopenshell/installation.html)
|
||||
* [IfcOpenShell Python Installation](https://bonsaibim.org/docs-python/ifcopenshell-python/installation.html)
|
||||
* [IfcOpenShell Python Hello World Tutorial](https://bonsaibim.org/docs-python/ifcopenshell-python/hello_world.html)
|
||||
* [Bonsai Website](https://bonsaibim.org)
|
||||
* [Bonsai Documentation](http://bonsaibim.org/docs)
|
||||
* [Add-on Installation](https://bonsaibim.org/docs/users/installation.html)
|
||||
* [Exploring an IFC model](https://bonsaibim.org/docs/users/exploring_an_ifc_model.html)
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
|
||||
@@ -1,7 +1,34 @@
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
include = 'src/(bcf|bcfserver|blenderbim|bsdd|foundationserver|ifc2ca|ifc4d|ifc5d|ifcbimtester|ifcblender|ifccityjson|ifcclash|ifccsv|ifcdiff|ifcfm|ifcpatch|ifctester|ifcopenshell-python|ifcsverchok|opencdeserver)/.*.py$'
|
||||
extend-exclude = '(src/ifcopenshell-python/ifcopenshell/express/*|src/ifc2ca/templates/*)'
|
||||
include = '''
|
||||
src/(
|
||||
bcf
|
||||
|bcfserver
|
||||
|blenderbim
|
||||
|bsdd
|
||||
|foundationserver
|
||||
|ifc2ca
|
||||
|ifc4d
|
||||
|ifc5d
|
||||
|ifcbimtester
|
||||
|ifcblender
|
||||
|ifccityjson
|
||||
|ifcclash
|
||||
|ifccsv
|
||||
|ifcdiff
|
||||
|ifcfm
|
||||
|ifcpatch
|
||||
|ifctester
|
||||
|ifcopenshell-python
|
||||
|ifcsverchok
|
||||
|opencdeserver
|
||||
)/.*.py$
|
||||
'''
|
||||
extend-exclude = '''
|
||||
src/ifcopenshell-python/ifcopenshell/express/*
|
||||
|src/ifcopenshell-python/ifcopenshell/mvd/*
|
||||
|src/ifc2ca/templates/*
|
||||
'''
|
||||
|
||||
[tool.pyright]
|
||||
reportInvalidTypeForm = false
|
||||
|
||||
@@ -30,8 +30,12 @@ license:
|
||||
# TODO: make this based on xsd file presence
|
||||
.PHONY: models
|
||||
models:
|
||||
cd src && xsdata generate -p bcf.v2.model --unnest-classes --kw-only --slots -ds Google bcf/v2/xsd
|
||||
cd src && xsdata generate -p bcf.v3.model --unnest-classes --kw-only --slots -ds Google bcf/v3/xsd
|
||||
xsdata generate -p bcf.v2.model --unnest-classes --kw-only --slots -ds Google bcf/v2/xsd
|
||||
xsdata generate -p bcf.v3.model --unnest-classes --kw-only --slots -ds Google bcf/v3/xsd
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
pytest -p no:pytest-blender tests
|
||||
|
||||
# .PHONY
|
||||
# api:
|
||||
|
||||
@@ -3,3 +3,7 @@
|
||||
A simple Python implementation of the BCF standard. Manipulation of BCF-XML is
|
||||
available via `bcfxml.py` and manipulation of BCF-API is available via
|
||||
`bcfapi.py`.
|
||||
|
||||
Python files in 'model' folder are automatically generated from .xsd files (located in 'xsd' folder).
|
||||
To regenerate them you can use `make models`.
|
||||
The only exception is 'v2/model/extensions.py', see it's note for the details.
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import bcf.v2.model.extensions
|
||||
import bcf.v3.model.extensions
|
||||
from typing import NamedTuple, Union
|
||||
from dataclasses import fields
|
||||
|
||||
|
||||
class AttributeData(NamedTuple):
|
||||
attr_type: type
|
||||
subattr_name: str
|
||||
subattr_xsd_name: str
|
||||
|
||||
|
||||
Extensions = Union[bcf.v2.model.extensions.Extensions, bcf.v3.model.extensions.Extensions]
|
||||
|
||||
|
||||
def get_extensions_attributes(extensions: Extensions) -> dict[str, AttributeData]:
|
||||
"""Return mapping of xsd attribute name to a tuple that consists of:
|
||||
- Extensions attribute name
|
||||
- Extensions attribute type type
|
||||
- subattribute name"""
|
||||
possible_attributes = {}
|
||||
for field in fields(type(extensions)):
|
||||
field_type = field.type.__args__[0] # type: ignore [reportAttributeAccessIssue]
|
||||
subfield = next(iter(fields(field_type)))
|
||||
xsd_name = subfield.metadata["name"]
|
||||
possible_attributes[field.name] = AttributeData(field_type, subfield.name, xsd_name)
|
||||
|
||||
return possible_attributes
|
||||
@@ -0,0 +1,5 @@
|
||||
import bcf.v2.topic
|
||||
import bcf.v3.topic
|
||||
from typing import Union
|
||||
|
||||
TopicHandler = Union[bcf.v2.topic.TopicHandler, bcf.v3.topic.TopicHandler]
|
||||
@@ -0,0 +1,5 @@
|
||||
import bcf.v2.visinfo
|
||||
import bcf.v3.visinfo
|
||||
from typing import Union
|
||||
|
||||
VisualizationInfoHandler = Union[bcf.v2.visinfo.VisualizationInfoHandler, bcf.v3.visinfo.VisualizationInfoHandler]
|
||||
@@ -30,9 +30,10 @@ from bcf.v3.model import Version as Version3
|
||||
from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer
|
||||
|
||||
|
||||
def load(
|
||||
filepath: Path, xml_handler: Optional[AbstractXmlParserSerializer] = None
|
||||
) -> Optional[Union[BcfXml2, BcfXml3]]:
|
||||
BcfXml = Union[BcfXml2, BcfXml3]
|
||||
|
||||
|
||||
def load(filepath: Path, xml_handler: Optional[AbstractXmlParserSerializer] = None) -> Optional[BcfXml]:
|
||||
"""
|
||||
Load a BCF file.
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ from numpy.typing import NDArray
|
||||
|
||||
|
||||
def camera_vectors_from_element_placement(
|
||||
elem_placement: NDArray[np.float_],
|
||||
) -> tuple[NDArray[np.float_], NDArray[np.float_], NDArray[np.float_]]:
|
||||
elem_placement: NDArray[np.float64],
|
||||
) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]:
|
||||
"""
|
||||
Calculate the vectors of a camera pointing to an element.
|
||||
|
||||
@@ -21,8 +21,8 @@ def camera_vectors_from_element_placement(
|
||||
|
||||
|
||||
def camera_vectors_from_target_position(
|
||||
target_position: NDArray[np.float_], offset: Optional[NDArray[np.float_]] = None
|
||||
) -> tuple[NDArray[np.float_], NDArray[np.float_], NDArray[np.float_]]:
|
||||
target_position: NDArray[np.float64], offset: Optional[NDArray[np.float64]] = None
|
||||
) -> tuple[NDArray[np.float64], NDArray[np.float64], NDArray[np.float64]]:
|
||||
"""
|
||||
Calculate the vectors of a camera pointing to a target point.
|
||||
|
||||
@@ -50,7 +50,7 @@ def camera_vectors_from_target_position(
|
||||
# return camera_position, -mat[:3, 2], mat[:3, 1]
|
||||
|
||||
|
||||
def unit_vector(v: NDArray[np.float_]) -> NDArray[np.float_]:
|
||||
def unit_vector(v: NDArray[np.float64]) -> NDArray[np.float64]:
|
||||
"""
|
||||
Return the unit vector of a vector.
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@ import zipfile
|
||||
from pathlib import Path
|
||||
from typing import Any, NoReturn, Optional, TypeVar
|
||||
|
||||
import bcf.agnostic.extensions
|
||||
import bcf.v2.model as mdl
|
||||
import bcf.v2.model.extensions as mdl_extensions
|
||||
from bcf.inmemory_zipfile import InMemoryZipFile, ZipFileInterface
|
||||
from bcf.v2.topic import TopicHandler
|
||||
from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer
|
||||
@@ -24,7 +26,8 @@ class BcfXml:
|
||||
self._xml_handler = xml_handler or XmlParserSerializer()
|
||||
self._version: Optional[mdl.Version] = None
|
||||
self._project_info: Optional[mdl.ProjectExtension] = None
|
||||
self._topics: dict[str, TopicHandler] = {}
|
||||
self._extensions: Optional[mdl_extensions.Extensions] = None
|
||||
self._topics: Optional[dict[str, TopicHandler]] = None
|
||||
self._extension_schema: Optional[bytes] = None
|
||||
self._zip_file = self._load_zip_file()
|
||||
|
||||
@@ -85,24 +88,63 @@ class BcfXml:
|
||||
def extension_schema(self, value: bytes) -> None:
|
||||
self._extension_schema = value
|
||||
|
||||
@property
|
||||
def extensions(self) -> Optional[mdl_extensions.Extensions]:
|
||||
"""BCF extensions."""
|
||||
|
||||
if not self._extensions and self.extension_schema:
|
||||
import io
|
||||
from xml.etree import ElementTree as etree
|
||||
|
||||
extensions = mdl_extensions.Extensions()
|
||||
|
||||
xs = "{http://www.w3.org/2001/XMLSchema}"
|
||||
root = etree.parse(io.BytesIO((self.extension_schema)))
|
||||
|
||||
attrs = bcf.agnostic.extensions.get_extensions_attributes(extensions)
|
||||
xsd_to_attrs = {v.subattr_xsd_name: k for k, v in attrs.items()}
|
||||
for node in root.findall(f".//{xs}restriction"):
|
||||
attr_type = node.attrib.get("base")
|
||||
if not attr_type:
|
||||
continue
|
||||
attr_name = xsd_to_attrs.get(attr_type)
|
||||
if attr_name is None:
|
||||
continue
|
||||
values = []
|
||||
for enum in node.findall(f".//{xs}enumeration"):
|
||||
values.append(enum.attrib["value"])
|
||||
if not values:
|
||||
continue
|
||||
attr_data = attrs[attr_name]
|
||||
attr = attr_data.attr_type()
|
||||
setattr(attr, attr_data.subattr_name, values)
|
||||
setattr(extensions, attr_name, attr)
|
||||
|
||||
self._extensions = extensions
|
||||
return self._extensions
|
||||
|
||||
@extensions.setter
|
||||
def extensions(self, value: Optional[mdl_extensions.Extensions]) -> None:
|
||||
self._extensions = value
|
||||
|
||||
@property
|
||||
def topics(self) -> dict[str, TopicHandler]:
|
||||
"""BCF topics."""
|
||||
if not self._topics and self._zip_file:
|
||||
self._topics = self._load_topics(self._zip_file, self._xml_handler)
|
||||
if self._topics is None:
|
||||
self._topics = self._load_topics()
|
||||
return self._topics
|
||||
|
||||
def _load_topics(
|
||||
self, zip_file: zipfile.ZipFile, xml_handler: AbstractXmlParserSerializer
|
||||
) -> dict[str, TopicHandler]:
|
||||
def _load_topics(self) -> dict[str, TopicHandler]:
|
||||
topics = {}
|
||||
for topic_dir in zipfile.Path(zip_file).iterdir():
|
||||
if self._zip_file is None:
|
||||
return topics
|
||||
for topic_dir in zipfile.Path(self._zip_file).iterdir():
|
||||
if not topic_dir.is_dir():
|
||||
continue
|
||||
markup_path = topic_dir.joinpath("markup.bcf")
|
||||
if not markup_path.exists():
|
||||
continue
|
||||
topics[topic_dir.name] = TopicHandler(topic_dir, xml_handler)
|
||||
topics[topic_dir.name] = TopicHandler(topic_dir, self._xml_handler)
|
||||
return topics
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
# NOTE: This file is not generated from
|
||||
# https://github.com/buildingSMART/BCF-XML/blob/release_2_1/Extension%20Schemas/extensions.xsd
|
||||
# because in bcf 2.1 there is no extensions.xml - I guess, the schema assumes that each .bcf
|
||||
# will use their own schema patched by it's own extensions.xsd.
|
||||
#
|
||||
# To make things simpler we just mimic extensions structures from bcf 3, so they'll have common API,
|
||||
# and parse extensions.xsd inside .bcf as .xml and fill our structures.
|
||||
#
|
||||
# Preferably if we could generate some kind of extensions.xml from extensions.xsd
|
||||
# and leave all the handling to xsdata.
|
||||
#
|
||||
# We also don't add it to __init__.py not to mess with generator.
|
||||
#
|
||||
# Currently extensions support for v2 is only read-only.
|
||||
|
||||
|
||||
from dataclasses import dataclass, field, fields
|
||||
from typing import List, NamedTuple, Optional
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsPriorities:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
priority: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "Priority",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsSnippetTypes:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
snippet_type: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "SnippetType",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsStages:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
stage: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "Stage",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsTopicLabels:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
topic_label: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "TopicLabel",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsTopicStatuses:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
topic_status: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "TopicStatus",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsTopicTypes:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
topic_type: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "TopicType",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class ExtensionsUsers:
|
||||
class Meta:
|
||||
global_type = False
|
||||
|
||||
user: List[str] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "UserIdType",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True, kw_only=True)
|
||||
class Extensions:
|
||||
topic_types: Optional[ExtensionsTopicTypes] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "TopicTypes",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
topic_statuses: Optional[ExtensionsTopicStatuses] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "TopicStatuses",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
priorities: Optional[ExtensionsPriorities] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Priorities",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
topic_labels: Optional[ExtensionsTopicLabels] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "TopicLabels",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
users: Optional[ExtensionsUsers] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Users",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
snippet_types: Optional[ExtensionsSnippetTypes] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "SnippetTypes",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
stages: Optional[ExtensionsStages] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Stages",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
},
|
||||
)
|
||||
@@ -5,7 +5,7 @@ import tempfile
|
||||
import uuid
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import Any, NoReturn, Optional
|
||||
from typing import Any, NoReturn, Optional, Union
|
||||
|
||||
import numpy as np
|
||||
from ifcopenshell import entity_instance
|
||||
@@ -27,9 +27,9 @@ class TopicHandler:
|
||||
xml_handler: Optional[AbstractXmlParserSerializer] = None,
|
||||
) -> None:
|
||||
self._markup: Optional[mdl.Markup] = None
|
||||
self._viewpoints: dict[str, VisualizationInfoHandler] = {}
|
||||
self._reference_files: dict[str, bytes] = {}
|
||||
self._document_references: dict[str, bytes] = {}
|
||||
self._viewpoints: Optional[dict[str, VisualizationInfoHandler]] = None
|
||||
self._reference_files: Optional[dict[str, bytes]] = None
|
||||
self._document_references: Optional[dict[str, bytes]] = None
|
||||
self._bim_snippet: Optional[bytes] = None
|
||||
self._xml_handler = xml_handler or XmlParserSerializer()
|
||||
self._topic_dir = topic_dir
|
||||
@@ -80,14 +80,24 @@ class TopicHandler:
|
||||
|
||||
@property
|
||||
def viewpoints(self) -> dict[str, VisualizationInfoHandler]:
|
||||
if not self._viewpoints and self._topic_dir:
|
||||
if self._viewpoints is None:
|
||||
self._viewpoints = self._load_viewpoints()
|
||||
return self._viewpoints
|
||||
|
||||
def _load_viewpoints(self) -> dict[str, VisualizationInfoHandler]:
|
||||
if self._topic_dir and self.markup and (viewpoints := self.markup.viewpoints):
|
||||
return VisualizationInfoHandler.from_topic_viewpoints(self._topic_dir, viewpoints)
|
||||
return {}
|
||||
|
||||
@property
|
||||
def reference_files(self) -> dict[str, bytes]:
|
||||
if self._reference_files or not self.header:
|
||||
if self._reference_files is not None:
|
||||
return self._reference_files
|
||||
|
||||
self._reference_files = {}
|
||||
if not self.header:
|
||||
return self._reference_files
|
||||
|
||||
for ref in self.header.file:
|
||||
if ref.is_external:
|
||||
continue
|
||||
@@ -99,8 +109,13 @@ class TopicHandler:
|
||||
|
||||
@property
|
||||
def document_references(self) -> dict[str, bytes]:
|
||||
if self._document_references or not self.topic:
|
||||
if self._document_references is not None:
|
||||
return self._document_references
|
||||
|
||||
self._document_references = {}
|
||||
if not self.topic:
|
||||
return self._document_references
|
||||
|
||||
for doc in self.topic.document_reference:
|
||||
if doc.is_external or not doc.referenced_document:
|
||||
continue
|
||||
@@ -118,11 +133,6 @@ class TopicHandler:
|
||||
return bim_snippet_path.read_bytes()
|
||||
return None
|
||||
|
||||
def _load_viewpoints(self) -> dict[str, VisualizationInfoHandler]:
|
||||
if self.markup and (viewpoints := self.markup.viewpoints):
|
||||
return VisualizationInfoHandler.from_topic_viewpoints(self._topic_dir, viewpoints)
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
def create_new(
|
||||
cls,
|
||||
@@ -220,7 +230,9 @@ class TopicHandler:
|
||||
real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part)
|
||||
destination_zip.writestr(real_path.at, self.document_references[doc.referenced_document])
|
||||
|
||||
def extract_file(self, entity, outfile: Optional[Path] = None) -> Path:
|
||||
def extract_file(
|
||||
self, entity: Union[mdl.HeaderFile, mdl.BimSnippet, mdl.TopicDocumentReference], outfile: Optional[Path] = None
|
||||
) -> Union[Path, str, None]:
|
||||
"""Extracts an element with a file into a temporary directory
|
||||
|
||||
These include header files, bim snippets, document references, and
|
||||
@@ -228,11 +240,9 @@ class TopicHandler:
|
||||
URI reference is returned.
|
||||
|
||||
:param entity: The entity with a file reference to extract
|
||||
:type entity: bcf.v2.model.HeaderFile,bcf.v2.model.BimSnippet,bcf.v2.model.TopicDocumentReference
|
||||
:param outfile: If provided, save the header file to that location.
|
||||
Otherwise, a temporary directory is created and the filename is
|
||||
derived from the header's original filename.
|
||||
:type outfile: pathlib.Path,optional
|
||||
:return: The filepath of the extracted file. It may be a URL if the
|
||||
header file is external.
|
||||
:rtype: Path
|
||||
@@ -268,7 +278,7 @@ class TopicHandler:
|
||||
|
||||
return outfile
|
||||
|
||||
def add_viewpoint(self, element: entity_instance) -> None:
|
||||
def add_viewpoint(self, element: entity_instance) -> VisualizationInfoHandler:
|
||||
"""Add a viewpoint pointed at the placement of an IFC element to the topic.
|
||||
|
||||
Args:
|
||||
@@ -278,7 +288,9 @@ class TopicHandler:
|
||||
self.add_visinfo_handler(new_viewpoint)
|
||||
return new_viewpoint
|
||||
|
||||
def add_viewpoint_from_point_and_guids(self, position: NDArray[np.float_], *guids: str) -> None:
|
||||
def add_viewpoint_from_point_and_guids(
|
||||
self, position: NDArray[np.float64], *guids: str
|
||||
) -> VisualizationInfoHandler:
|
||||
"""Add a viewpoint pointing at an XYZ point in space
|
||||
|
||||
Args:
|
||||
@@ -291,9 +303,17 @@ class TopicHandler:
|
||||
self.add_visinfo_handler(vi_handler)
|
||||
return vi_handler
|
||||
|
||||
def add_visinfo_handler(self, new_viewpoint: VisualizationInfoHandler) -> None:
|
||||
def add_visinfo_handler(
|
||||
self, new_viewpoint: VisualizationInfoHandler, snapshot_filename: Optional[str] = None
|
||||
) -> mdl.ViewPoint:
|
||||
self.viewpoints[new_viewpoint.guid + ".bcfv"] = new_viewpoint
|
||||
self.markup.viewpoints.append(mdl.ViewPoint(viewpoint=new_viewpoint.guid + ".bcfv", guid=new_viewpoint.guid))
|
||||
viewpoint = mdl.ViewPoint(
|
||||
viewpoint=new_viewpoint.guid + ".bcfv",
|
||||
snapshot=snapshot_filename,
|
||||
guid=new_viewpoint.guid,
|
||||
)
|
||||
self.markup.viewpoints.append(viewpoint)
|
||||
return viewpoint
|
||||
|
||||
def __eq__(self, other: object) -> bool | NoReturn:
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import uuid
|
||||
import zipfile
|
||||
from functools import lru_cache
|
||||
from typing import Any, Iterable, Optional
|
||||
from typing import Any, Iterable, Optional, Literal, Union
|
||||
|
||||
import numpy as np
|
||||
from ifcopenshell import entity_instance
|
||||
@@ -134,6 +133,15 @@ class VisualizationInfoHandler:
|
||||
self._save_bitmaps(bcf_zip, topic_dir)
|
||||
|
||||
def _save_snapshot(self, bcf_zip: ZipFileInterface, topic_dir: str, filename: Optional[str]) -> None:
|
||||
if bool(self.snapshot) ^ bool(filename):
|
||||
data = ["data (VisualizationInfoHandler.snapshot)", "filename (ViewPoint.snapshot)"]
|
||||
provided_data, missing_data = data if self.snapshot else data[::-1]
|
||||
print(
|
||||
f"WARNING. Snapshot with viewpoint guid '{self.guid}' won't be saved to bcf. "
|
||||
f"Only snapshot {provided_data} is provided but snapshot {missing_data} is missing."
|
||||
)
|
||||
return
|
||||
|
||||
if self.snapshot and filename:
|
||||
bcf_zip.writestr(f"{topic_dir}/{filename}", self.snapshot)
|
||||
|
||||
@@ -176,7 +184,7 @@ class VisualizationInfoHandler:
|
||||
@classmethod
|
||||
def create_from_point_and_guids(
|
||||
cls,
|
||||
position: NDArray[np.float_],
|
||||
position: NDArray[np.float64],
|
||||
*guids: str,
|
||||
xml_handler: Optional[AbstractXmlParserSerializer] = None,
|
||||
) -> "VisualizationInfoHandler":
|
||||
@@ -196,13 +204,110 @@ class VisualizationInfoHandler:
|
||||
visualization_info=build_viewpoint_from_position_and_guids(position, *guids), xml_handler=xml_handler
|
||||
)
|
||||
|
||||
def get_selected_guids(self) -> Union[list[str], None]:
|
||||
"""
|
||||
Return viewpoint selected elements IFC guids.
|
||||
|
||||
Returns:
|
||||
If viewpoint has no selection settings, return `None`.
|
||||
Otherwise return a list of selected elements IFC guids.
|
||||
"""
|
||||
visualization_info = self.visualization_info
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
return None
|
||||
|
||||
selection = components.selection
|
||||
if not selection:
|
||||
return None
|
||||
return [guid for c in selection.component if (guid := c.ifc_guid)]
|
||||
|
||||
def set_selected_elements(self, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||
visualization_info = self.visualization_info
|
||||
|
||||
guids = [e.GlobalId for e in elements]
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
visibility = mdl.ComponentVisibility(default_visibility=True)
|
||||
components = mdl.Components(visibility=visibility)
|
||||
visualization_info.components = components
|
||||
|
||||
selection = components.selection
|
||||
components_list = [mdl.Component(ifc_guid=guid) for guid in guids]
|
||||
if not selection:
|
||||
selection = mdl.ComponentSelection()
|
||||
components.selection = selection
|
||||
selection.component = components_list
|
||||
|
||||
def set_visible_elements(self, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||
self.set_visibility(elements, elements_visibility="VISIBLE")
|
||||
|
||||
def set_hidden_elements(self, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||
self.set_visibility(elements, elements_visibility="HIDDEN")
|
||||
|
||||
def set_visibility(
|
||||
self, elements: list[ifcopenshell.entity_instance], elements_visibility: Literal["VISIBLE", "HIDDEN"]
|
||||
) -> None:
|
||||
visualization_info = self.visualization_info
|
||||
default_visibility = elements_visibility == "HIDDEN"
|
||||
|
||||
guids = [e.GlobalId for e in elements]
|
||||
components_list = [mdl.Component(ifc_guid=guid) for guid in guids]
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
visibility = mdl.ComponentVisibility(default_visibility=default_visibility)
|
||||
components = mdl.Components(visibility=visibility)
|
||||
visualization_info.components = components
|
||||
|
||||
visibility = components.visibility
|
||||
if not visibility:
|
||||
visibility = mdl.ComponentVisibility(default_visibility=default_visibility)
|
||||
components.visibility = visibility
|
||||
elif visibility.default_visibility != default_visibility:
|
||||
visibility.default_visibility = default_visibility
|
||||
|
||||
exceptions = visibility.exceptions
|
||||
if not exceptions:
|
||||
exceptions = mdl.ComponentVisibilityExceptions()
|
||||
visibility.exceptions = exceptions
|
||||
exceptions.component = components_list
|
||||
|
||||
def get_elements_visibility(self) -> Union[tuple[bool, list[str]], None]:
|
||||
"""
|
||||
Return viewpoint elements visibility settings.
|
||||
|
||||
Returns:
|
||||
If viewpoint has no visibility settings, return `None`.
|
||||
Otherwise return a tuple containing the default visibility
|
||||
and a list of IFC element GUIDs listed as exceptions.
|
||||
|
||||
If default visibility is `True`, all elements are visible except the exceptions.
|
||||
|
||||
If default visibility is `False`, all elements are hidden except the exceptions.
|
||||
"""
|
||||
|
||||
visualization_info = self.visualization_info
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
return None
|
||||
|
||||
visibility = components.visibility
|
||||
if not visibility:
|
||||
return None
|
||||
default_visibility = visibility.default_visibility or False
|
||||
|
||||
exceptions = visibility.exceptions
|
||||
if not exceptions:
|
||||
return default_visibility, []
|
||||
guids = [guid for c in exceptions.component if (guid := c.ifc_guid)]
|
||||
return default_visibility, guids
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
"""
|
||||
Return a BCF viewpoint of an IFC element.
|
||||
|
||||
This function is cached to speedudp the creation of multiple BCF topics regarding the same element.
|
||||
This function is cached to speed up the creation of multiple BCF topics regarding the same element.
|
||||
|
||||
Args:
|
||||
element: The IFC element to point at.
|
||||
@@ -224,11 +329,11 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
)
|
||||
|
||||
|
||||
def build_viewpoint_from_position_and_guids(position: NDArray[np.float_], *guids: str) -> mdl.VisualizationInfo:
|
||||
def build_viewpoint_from_position_and_guids(position: NDArray[np.float64], *guids: str) -> mdl.VisualizationInfo:
|
||||
"""
|
||||
Return a BCF viewpoint of an IFC element.
|
||||
|
||||
This function is cached to speedudp the creation of multiple BCF topics regarding the same element.
|
||||
This function is cached to speed up the creation of multiple BCF topics regarding the same element.
|
||||
|
||||
Args:
|
||||
position: target point coordinates.
|
||||
@@ -249,7 +354,7 @@ def build_components(*guids: str) -> mdl.Components:
|
||||
Return the BCF components from an IFC element GUID.
|
||||
|
||||
Args:
|
||||
*guids: One or more IFC element GUID.
|
||||
*guids: One or more selected IFC element GUID.
|
||||
|
||||
Returns:
|
||||
The BCF components definition.
|
||||
@@ -261,7 +366,7 @@ def build_components(*guids: str) -> mdl.Components:
|
||||
)
|
||||
|
||||
|
||||
def build_camera(elem_placement: NDArray[np.float_]) -> mdl.PerspectiveCamera:
|
||||
def build_camera(elem_placement: NDArray[np.float64]) -> mdl.PerspectiveCamera:
|
||||
"""
|
||||
Return a BCF camera for an IFC element placement matrix.
|
||||
|
||||
@@ -275,7 +380,7 @@ def build_camera(elem_placement: NDArray[np.float_]) -> mdl.PerspectiveCamera:
|
||||
|
||||
|
||||
def build_camera_from_vectors(
|
||||
camera_position: NDArray[np.float_], camera_dir: NDArray[np.float_], camera_up: NDArray[np.float_]
|
||||
camera_position: NDArray[np.float64], camera_dir: NDArray[np.float64], camera_up: NDArray[np.float64]
|
||||
) -> mdl.PerspectiveCamera:
|
||||
"""
|
||||
Return a BCF camera for an IFC element placement matrix.
|
||||
|
||||
@@ -26,7 +26,7 @@ class BcfXml:
|
||||
self._version: Optional[mdl.Version] = None
|
||||
self._project_info: Optional[mdl.ProjectInfo] = None
|
||||
self._extensions: Optional[mdl.Extensions] = None
|
||||
self._topics: dict[str, TopicHandler] = {}
|
||||
self._topics: Optional[dict[str, TopicHandler]] = None
|
||||
self._documents: Optional[DocumentsHandler] = None
|
||||
self._zip_file = self._load_zip_file()
|
||||
|
||||
@@ -91,18 +91,22 @@ class BcfXml:
|
||||
@property
|
||||
def topics(self) -> dict[str, TopicHandler]:
|
||||
"""BCF topics."""
|
||||
if not self._topics and self._zip_file:
|
||||
self._load_topics()
|
||||
if self._topics is None:
|
||||
self._topics = self._load_topics()
|
||||
return self._topics
|
||||
|
||||
def _load_topics(self) -> None:
|
||||
def _load_topics(self) -> dict[str, TopicHandler]:
|
||||
topics = {}
|
||||
if self._zip_file is None:
|
||||
return topics
|
||||
for topic_dir in zipfile.Path(self._zip_file).iterdir():
|
||||
if not topic_dir.is_dir():
|
||||
continue
|
||||
markup_path = topic_dir.joinpath("markup.bcf")
|
||||
if not markup_path.exists():
|
||||
continue
|
||||
self._topics[topic_dir.name] = TopicHandler(topic_dir, self._xml_handler)
|
||||
topics[topic_dir.name] = TopicHandler(topic_dir, self._xml_handler)
|
||||
return topics
|
||||
|
||||
@property
|
||||
def documents(self) -> Optional[DocumentsHandler]:
|
||||
|
||||
@@ -26,7 +26,7 @@ class TopicHandler:
|
||||
xml_handler: Optional[AbstractXmlParserSerializer] = None,
|
||||
) -> None:
|
||||
self._markup: Optional[mdl.Markup] = None
|
||||
self._viewpoints: dict[str, VisualizationInfoHandler] = {}
|
||||
self._viewpoints: Optional[dict[str, VisualizationInfoHandler]] = None
|
||||
self._bim_snippet: Optional[bytes] = None
|
||||
self._xml_handler = xml_handler or XmlParserSerializer()
|
||||
self._topic_dir = topic_dir
|
||||
@@ -77,15 +77,15 @@ class TopicHandler:
|
||||
|
||||
@property
|
||||
def viewpoints(self) -> dict[str, "VisualizationInfoHandler"]:
|
||||
if (
|
||||
not self._viewpoints
|
||||
and self._topic_dir
|
||||
and self.topic.viewpoints
|
||||
and (viewpoints := self.topic.viewpoints.view_point)
|
||||
):
|
||||
self._viewpoints = VisualizationInfoHandler.from_topic_viewpoints(self._topic_dir, viewpoints)
|
||||
if self._viewpoints is None:
|
||||
self._viewpoints = self._load_viewpoints()
|
||||
return self._viewpoints
|
||||
|
||||
def _load_viewpoints(self) -> dict[str, "VisualizationInfoHandler"]:
|
||||
if self._topic_dir and self.topic.viewpoints and (viewpoints := self.topic.viewpoints.view_point):
|
||||
return VisualizationInfoHandler.from_topic_viewpoints(self._topic_dir, viewpoints)
|
||||
return {}
|
||||
|
||||
def _load_bim_snippet(self) -> Optional[bytes]:
|
||||
bim_snippet_obj = self.topic.bim_snippet
|
||||
if bim_snippet_obj and not bim_snippet_obj.is_external and self._topic_dir:
|
||||
@@ -165,7 +165,7 @@ class TopicHandler:
|
||||
if self.bim_snippet:
|
||||
destination_zip.writestr(f"{self.topic.guid}/{ref_filename}", self.bim_snippet)
|
||||
|
||||
def add_viewpoint(self, element: entity_instance) -> None:
|
||||
def add_viewpoint(self, element: entity_instance) -> VisualizationInfoHandler:
|
||||
"""
|
||||
Add a viewpoint tergeting an IFC element to the topic.
|
||||
|
||||
@@ -174,8 +174,11 @@ class TopicHandler:
|
||||
"""
|
||||
new_viewpoint = VisualizationInfoHandler.create_new(element, self._xml_handler)
|
||||
self.add_visinfo_handler(new_viewpoint)
|
||||
return new_viewpoint
|
||||
|
||||
def add_viewpoint_from_point_and_guids(self, position: NDArray[np.float_], *guids: str) -> None:
|
||||
def add_viewpoint_from_point_and_guids(
|
||||
self, position: NDArray[np.float64], *guids: str
|
||||
) -> VisualizationInfoHandler:
|
||||
"""
|
||||
Add a viewpoint tergeting an IFC element to the topic.
|
||||
|
||||
@@ -186,14 +189,21 @@ class TopicHandler:
|
||||
position, *guids, xml_handler=self._xml_handler
|
||||
)
|
||||
self.add_visinfo_handler(vi_handler)
|
||||
return vi_handler
|
||||
|
||||
def add_visinfo_handler(self, new_viewpoint: VisualizationInfoHandler) -> None:
|
||||
def add_visinfo_handler(
|
||||
self, new_viewpoint: VisualizationInfoHandler, snapshot_filename: Optional[str] = None
|
||||
) -> mdl.ViewPoint:
|
||||
self.viewpoints[new_viewpoint.guid + ".bcfv"] = new_viewpoint
|
||||
if self.topic.viewpoints is None:
|
||||
self.topic.viewpoints = mdl.TopicViewpoints()
|
||||
self.topic.viewpoints.view_point.append(
|
||||
mdl.ViewPoint(viewpoint=new_viewpoint.guid + ".bcfv", guid=new_viewpoint.guid)
|
||||
viewpoint = mdl.ViewPoint(
|
||||
viewpoint=new_viewpoint.guid + ".bcfv",
|
||||
snapshot=snapshot_filename,
|
||||
guid=new_viewpoint.guid,
|
||||
)
|
||||
self.topic.viewpoints.view_point.append(viewpoint)
|
||||
return viewpoint
|
||||
|
||||
def __eq__(self, other: object) -> bool | NoReturn:
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import uuid
|
||||
import zipfile
|
||||
from functools import lru_cache
|
||||
from typing import Any, Iterable, Optional
|
||||
from typing import Any, Iterable, Optional, Literal, Union
|
||||
|
||||
import numpy as np
|
||||
from ifcopenshell import entity_instance
|
||||
from ifcopenshell.util import placement
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.placement
|
||||
from numpy.typing import NDArray
|
||||
|
||||
import bcf.v3.model as mdl
|
||||
@@ -133,6 +133,15 @@ class VisualizationInfoHandler:
|
||||
self._save_bitmaps(bcf_zip, topic_dir)
|
||||
|
||||
def _save_snapshot(self, bcf_zip: ZipFileInterface, topic_dir: str, filename: Optional[str]) -> None:
|
||||
if bool(self.snapshot) ^ bool(filename):
|
||||
data = ["data (VisualizationInfoHandler.snapshot)", "filename (ViewPoint.snapshot)"]
|
||||
provided_data, missing_data = data if self.snapshot else data[::-1]
|
||||
print(
|
||||
f"WARNING. Snapshot with viewpoint guid '{self.guid}' won't be saved to bcf. "
|
||||
f"Only snapshot {provided_data} is provided but snapshot {missing_data} is missing."
|
||||
)
|
||||
return
|
||||
|
||||
if self.snapshot and filename:
|
||||
bcf_zip.writestr(f"{topic_dir}/{filename}", self.snapshot)
|
||||
|
||||
@@ -175,7 +184,7 @@ class VisualizationInfoHandler:
|
||||
@classmethod
|
||||
def create_from_point_and_guids(
|
||||
cls,
|
||||
position: NDArray[np.float_],
|
||||
position: NDArray[np.float64],
|
||||
*guids: str,
|
||||
xml_handler: Optional[AbstractXmlParserSerializer] = None,
|
||||
) -> "VisualizationInfoHandler":
|
||||
@@ -195,13 +204,110 @@ class VisualizationInfoHandler:
|
||||
visualization_info=build_viewpoint_from_position_and_guids(position, *guids), xml_handler=xml_handler
|
||||
)
|
||||
|
||||
def get_selected_guids(self) -> Union[list[str], None]:
|
||||
"""
|
||||
Return viewpoint selected elements IFC guids.
|
||||
|
||||
Returns:
|
||||
If viewpoint has no selection settings, return `None`.
|
||||
Otherwise return a list of selected elements IFC guids.
|
||||
"""
|
||||
visualization_info = self.visualization_info
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
return None
|
||||
|
||||
selection = components.selection
|
||||
if not selection:
|
||||
return None
|
||||
return [guid for c in selection.component if (guid := c.ifc_guid)]
|
||||
|
||||
def set_selected_elements(self, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||
visualization_info = self.visualization_info
|
||||
|
||||
guids = [e.GlobalId for e in elements]
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
visibility = mdl.ComponentVisibility(default_visibility=True)
|
||||
components = mdl.Components(visibility=visibility)
|
||||
visualization_info.components = components
|
||||
|
||||
selection = components.selection
|
||||
components_list = [mdl.Component(ifc_guid=guid) for guid in guids]
|
||||
if not selection:
|
||||
selection = mdl.ComponentSelection()
|
||||
components.selection = selection
|
||||
selection.component = components_list
|
||||
|
||||
def set_visible_elements(self, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||
self.set_visibility(elements, elements_visibility="VISIBLE")
|
||||
|
||||
def set_hidden_elements(self, elements: list[ifcopenshell.entity_instance]) -> None:
|
||||
self.set_visibility(elements, elements_visibility="HIDDEN")
|
||||
|
||||
def set_visibility(
|
||||
self, elements: list[ifcopenshell.entity_instance], elements_visibility: Literal["VISIBLE", "HIDDEN"]
|
||||
) -> None:
|
||||
visualization_info = self.visualization_info
|
||||
default_visibility = elements_visibility == "HIDDEN"
|
||||
|
||||
guids = [e.GlobalId for e in elements]
|
||||
components_list = [mdl.Component(ifc_guid=guid) for guid in guids]
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
visibility = mdl.ComponentVisibility(default_visibility=default_visibility)
|
||||
components = mdl.Components(visibility=visibility)
|
||||
visualization_info.components = components
|
||||
|
||||
visibility = components.visibility
|
||||
if not visibility:
|
||||
visibility = mdl.ComponentVisibility(default_visibility=default_visibility)
|
||||
components.visibility = visibility
|
||||
elif visibility.default_visibility != default_visibility:
|
||||
visibility.default_visibility = default_visibility
|
||||
|
||||
exceptions = visibility.exceptions
|
||||
if not exceptions:
|
||||
exceptions = mdl.ComponentVisibilityExceptions()
|
||||
visibility.exceptions = exceptions
|
||||
exceptions.component = components_list
|
||||
|
||||
def get_elements_visibility(self) -> Union[tuple[bool, list[str]], None]:
|
||||
"""
|
||||
Return viewpoint elements visibility settings.
|
||||
|
||||
Returns:
|
||||
If viewpoint has no visibility settings, return `None`.
|
||||
Otherwise return a tuple containing the default visibility
|
||||
and a list of IFC element GUIDs listed as exceptions.
|
||||
|
||||
If default visibility is `True`, all elements are visible except the exceptions.
|
||||
|
||||
If default visibility is `False`, all elements are hidden except the exceptions.
|
||||
"""
|
||||
|
||||
visualization_info = self.visualization_info
|
||||
components = visualization_info.components
|
||||
if not components:
|
||||
return None
|
||||
|
||||
visibility = components.visibility
|
||||
if not visibility:
|
||||
return None
|
||||
default_visibility = visibility.default_visibility or False
|
||||
|
||||
exceptions = visibility.exceptions
|
||||
if not exceptions:
|
||||
return default_visibility, []
|
||||
guids = [guid for c in exceptions.component if (guid := c.ifc_guid)]
|
||||
return default_visibility, guids
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
"""
|
||||
Return a BCF viewpoint of an IFC element.
|
||||
|
||||
This function is cached to speedudp the creation of multiple BCF topics regarding the same element.
|
||||
This function is cached to speed up the creation of multiple BCF topics regarding the same element.
|
||||
|
||||
Args:
|
||||
element: The IFC element to point at.
|
||||
@@ -209,7 +315,12 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
Returns:
|
||||
The BCF viewpoint definition.
|
||||
"""
|
||||
elem_placement = placement.get_local_placement(element.ObjectPlacement)
|
||||
ifc_file = element.wrapped_data.file
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
elem_placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
elem_placement[0][3] *= unit_scale
|
||||
elem_placement[1][3] *= unit_scale
|
||||
elem_placement[2][3] *= unit_scale
|
||||
|
||||
return mdl.VisualizationInfo(
|
||||
guid=str(uuid.uuid4()),
|
||||
@@ -218,11 +329,11 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
)
|
||||
|
||||
|
||||
def build_viewpoint_from_position_and_guids(position: NDArray[np.float_], *guids: str) -> mdl.VisualizationInfo:
|
||||
def build_viewpoint_from_position_and_guids(position: NDArray[np.float64], *guids: str) -> mdl.VisualizationInfo:
|
||||
"""
|
||||
Return a BCF viewpoint of an IFC element.
|
||||
|
||||
This function is cached to speedudp the creation of multiple BCF topics regarding the same element.
|
||||
This function is cached to speed up the creation of multiple BCF topics regarding the same element.
|
||||
|
||||
Args:
|
||||
position: target point coordinates.
|
||||
@@ -243,7 +354,7 @@ def build_components(*guids: str) -> mdl.Components:
|
||||
Return the BCF components from an IFC element GUID.
|
||||
|
||||
Args:
|
||||
*guids: One or more IFC element GUID.
|
||||
*guids: One or more selected IFC element GUID.
|
||||
|
||||
Returns:
|
||||
The BCF components definition.
|
||||
@@ -255,7 +366,7 @@ def build_components(*guids: str) -> mdl.Components:
|
||||
)
|
||||
|
||||
|
||||
def build_camera(elem_placement: NDArray[np.float_]) -> mdl.PerspectiveCamera:
|
||||
def build_camera(elem_placement: NDArray[np.float64]) -> mdl.PerspectiveCamera:
|
||||
"""
|
||||
Return a BCF camera for an IFC element placement matrix.
|
||||
|
||||
@@ -269,7 +380,7 @@ def build_camera(elem_placement: NDArray[np.float_]) -> mdl.PerspectiveCamera:
|
||||
|
||||
|
||||
def build_camera_from_vectors(
|
||||
camera_position: NDArray[np.float_], camera_dir: NDArray[np.float_], camera_up: NDArray[np.float_]
|
||||
camera_position: NDArray[np.float64], camera_dir: NDArray[np.float64], camera_up: NDArray[np.float64]
|
||||
) -> mdl.PerspectiveCamera:
|
||||
"""
|
||||
Return a BCF camera for an IFC element placement matrix.
|
||||
|
||||
@@ -55,9 +55,32 @@ def test_save_maximum_information() -> None:
|
||||
|
||||
def assert_everything_in_place(bcf: BcfXml):
|
||||
assert bcf.version.version_id == "2.1"
|
||||
assert bcf.project
|
||||
assert bcf.project.name == "BCF API Implementation"
|
||||
assert bcf.project_info
|
||||
assert bcf.project_info.extension_schema == "extensions.xsd"
|
||||
|
||||
assert bcf.extensions
|
||||
assert bcf.extensions.topic_types
|
||||
assert bcf.extensions.topic_types.topic_type == ["Architecture", "Hidden Type", "Structural"]
|
||||
assert bcf.extensions.topic_statuses
|
||||
assert bcf.extensions.topic_statuses.topic_status == ["Finished status", "Open", "Closed"]
|
||||
assert bcf.extensions.priorities
|
||||
assert bcf.extensions.priorities.priority == ["Low", "High", "Medium"]
|
||||
assert bcf.extensions.topic_labels
|
||||
assert bcf.extensions.topic_labels.topic_label == [
|
||||
"Architecture",
|
||||
"IT Development",
|
||||
"Management",
|
||||
"Mechanical",
|
||||
"Structural",
|
||||
]
|
||||
assert bcf.extensions.users
|
||||
assert bcf.extensions.users.user == ["dangl@iabi.eu", "linhard@iabi.eu"]
|
||||
assert bcf.extensions.snippet_types
|
||||
assert bcf.extensions.snippet_types.snippet_type == ["IFC2X3", "PDF", "XLSX"]
|
||||
assert bcf.extensions.stages is None
|
||||
|
||||
assert len(bcf.topics) == 2
|
||||
assert_first_topic_handler(bcf.topics["7ddc3ef0-0ab7-43f1-918a-45e38b42369c"])
|
||||
second_th = bcf.topics["d1068c81-af04-4546-b63c-348810f6c716"]
|
||||
|
||||
@@ -39,6 +39,22 @@ def assert_everything_in_place(bcf: BcfXml):
|
||||
assert bcf.project.name == "BCF 3.0 test cases"
|
||||
assert bcf.project.project_id == "de894a86-3a08-4ea0-b2d1-6c222b5602d1"
|
||||
|
||||
assert bcf.extensions
|
||||
assert bcf.extensions.topic_types
|
||||
assert bcf.extensions.topic_types.topic_type == ["ERROR", "WARNING", "INFORMATION", "CLASH", "OTHER"]
|
||||
assert bcf.extensions.topic_statuses
|
||||
assert bcf.extensions.topic_statuses.topic_status == ["OPEN", "IN_PROGRESS", "SOLVED", "CLOSED"]
|
||||
assert bcf.extensions.priorities
|
||||
assert bcf.extensions.priorities.priority == ["LOW", "MEDIUM", "HIGH", "CRITICAL"]
|
||||
assert bcf.extensions.topic_labels
|
||||
assert bcf.extensions.topic_labels.topic_label == []
|
||||
assert bcf.extensions.users
|
||||
assert bcf.extensions.users.user == ["Architect@example.com", "Engineer@example.com", "MEPDesigner@example.com"]
|
||||
assert bcf.extensions.snippet_types
|
||||
assert bcf.extensions.snippet_types.snippet_type == []
|
||||
assert bcf.extensions.stages
|
||||
assert bcf.extensions.stages.stage == []
|
||||
|
||||
assert len(bcf.topics) == 1
|
||||
topic_handler = bcf.topics["8ac9822a-761a-4deb-9f39-f61286acbf6a"]
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# BlenderBIM Add-on
|
||||
|
||||
An add-on to Blender to allow BIM functionality.
|
||||
|
||||
More information on the [BlenderBIM Add-on website](https://blenderbim.org).
|
||||
@@ -1,319 +0,0 @@
|
||||
:root {
|
||||
--font-family: Arial, sans-serif;
|
||||
--margin-small: 0.625rem;
|
||||
--margin-medium: 1.25rem;
|
||||
--margin-large: 2.5rem;
|
||||
--padding-small: 0.125rem;
|
||||
--padding-medium: 1rem;
|
||||
--font-size-small: 1rem;
|
||||
--font-size-large: 1.2rem;
|
||||
--logo-height: 2.5rem;
|
||||
--folder-collapse-font-size: 0.75rem;
|
||||
--folder-collapse-font-family: Courier, "Courier New", monospace;
|
||||
--box-shadow: 0 0 0.7rem #5f5f5f66;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
--bg-color: #252525;
|
||||
--primary-text-color: #e0e0e0;
|
||||
--secondary-text-color: #c7c7c7;
|
||||
--nav-bg-color: #121212;
|
||||
--nav-border-color: #25682a;
|
||||
--nav-link-color: #fff;
|
||||
--nav-link-hover-color: #3fb449;
|
||||
--warning-color: #FFDB8F;
|
||||
--border-color: #464444;
|
||||
--hover-bg-color: #3a3a3a;
|
||||
--highlight-color: #009136;
|
||||
--task-complete-bg-color: #777777;
|
||||
--milestone-border-color: #ffffff;
|
||||
--group-item-bg-color: #4b4b4b;
|
||||
--input-bg-color: #3b3b3b;
|
||||
--input-border-color: #000;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
color-scheme: light;
|
||||
--bg-color: #ffffff;
|
||||
--primary-text-color: #000000;
|
||||
--nav-bg-color: #f8f8f8;
|
||||
--nav-border-color: #cccccc;
|
||||
--nav-link-color: #000000;
|
||||
--nav-link-hover-color: #38a63d;
|
||||
--warning-color: #FF4500;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--primary-text-color);
|
||||
margin: 0;
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
|
||||
#container {
|
||||
margin-top: var(--margin-medium);
|
||||
margin-left: var(--margin-small);
|
||||
margin-right: var(--margin-small);
|
||||
margin-bottom: var(--margin-medium);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: var(--nav-bg-color);
|
||||
padding: var(--padding-medium) 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-bottom: 2px solid var(--nav-border-color);
|
||||
}
|
||||
|
||||
nav .logo {
|
||||
margin-left: var(--margin-large);
|
||||
height: var(--logo-height);
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
margin-left: 0.0625rem;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
margin-right: 3.125rem;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
text-decoration: none;
|
||||
color: var(--nav-link-color);
|
||||
font-size: var(--font-size-large);
|
||||
}
|
||||
|
||||
nav ul li a:hover,
|
||||
nav ul li a.active {
|
||||
color: var(--nav-link-hover-color);
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: var(--warning-color);
|
||||
margin-bottom: var(--margin-small);
|
||||
padding: var(--padding-small);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.table-description {
|
||||
margin-bottom: var(--margin-medium);
|
||||
width: 50%;
|
||||
background-color: transparent;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
border-color: var(--border-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.25rem;
|
||||
box-shadow: var(--box-shadow);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-description tr {
|
||||
display: table-row;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
#toggle-theme {
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-large);
|
||||
margin-right: var(--margin-medium);
|
||||
}
|
||||
|
||||
#toggle-theme:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.gantt-info {
|
||||
margin: 0.5rem;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0.5rem;
|
||||
font-size: var(--font-size-small);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------ Overwriting JSGantt CSS rules ------------ */
|
||||
:root.dark div.gantt {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
:root.dark .gantt table,
|
||||
:root.dark .gantt td {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
/* Headings and cell defaults */
|
||||
:root.dark .gmajorheading,
|
||||
:root.dark .gminorheading,
|
||||
:root.dark .gminorheadingwkend,
|
||||
:root.dark .gtaskcell,
|
||||
:root.dark .gtaskcellcurrent,
|
||||
:root.dark .gtaskcellwkend,
|
||||
:root.dark .gname,
|
||||
:root.dark .ggroupitem,
|
||||
:root.dark .gtaskheading {
|
||||
background-color: var(--bg-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
:root.dark .gtaskheading,
|
||||
:root.dark .gname,
|
||||
:root.dark .gtaskname,
|
||||
:root.dark .gres,
|
||||
:root.dark .gdur,
|
||||
:root.dark .gcomp,
|
||||
:root.dark .gstartdate,
|
||||
:root.dark .gplanstartdate,
|
||||
:root.dark .gplanenddate,
|
||||
:root.dark .gcost,
|
||||
:root.dark .gchartlbl,
|
||||
:root.dark .gcontainercol,
|
||||
:root.dark .genddate {
|
||||
color: var(--secondary-text-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
:root.dark .gtaskname>div {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
:root.dark .gtaskbarcontainer.gplan,
|
||||
:root.dark .gchartlbl.gcontainercol {
|
||||
background: var(--bg-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
:root.dark .gtaskname div,
|
||||
:root.dark .gtaskheading div,
|
||||
:root.dark .gtaskname span {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
:root.dark .gtasklist,
|
||||
:root.dark .gadditional {
|
||||
border: var(--border-color) 1px solid;
|
||||
}
|
||||
|
||||
:root.dark .gchartgrid {
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
:root.dark .glistgrid,
|
||||
:root.dark .glistlbl {
|
||||
background-color: var(--bg-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
/* .gTaskInfo {
|
||||
background-color: #2e2e2e;
|
||||
color: #c7c7c7;
|
||||
border-color: #c7c7c7;;
|
||||
} */
|
||||
|
||||
/* Dark mode scrollbar */
|
||||
:root.dark .frame::-webkit-scrollbar-thumb,
|
||||
:root.dark .frame::-webkit-scrollbar-track {
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
/* Highlight row */
|
||||
:root.dark .gitemhighlight td {
|
||||
background-color: var(--highlight-color);
|
||||
color: var(--nav-link-color);
|
||||
}
|
||||
|
||||
/* Differentiate Group, Milestone and Ordinary task items (applied to row) */
|
||||
:root.dark .ggroupitem {
|
||||
background-color: var(--bg-color);
|
||||
font-weight: bold;
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
:root.dark .gmileitem,
|
||||
:root.dark .glineitem {
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
/* Task bar caption text styles */
|
||||
:root.dark .gmilecaption,
|
||||
:root.dark .ggroupcaption,
|
||||
:root.dark .gcaption {
|
||||
color: var(--nav-link-color);
|
||||
}
|
||||
|
||||
/* Task complete %age bar */
|
||||
:root.dark .gtaskcomplete {
|
||||
background-color: var(--task-complete-bg-color);
|
||||
}
|
||||
|
||||
/* Milestones */
|
||||
:root.dark .gmdtop,
|
||||
:root.dark .gmdbottom {
|
||||
border-bottom: 5px solid var(--milestone-border-color);
|
||||
}
|
||||
|
||||
:root.dark .gfoldercollapse {
|
||||
color: var(--secondary-text-color);
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
font-size: var(--folder-collapse-font-size);
|
||||
font-family: var(--folder-collapse-font-family);
|
||||
}
|
||||
|
||||
/* Highlight for collapsible row */
|
||||
:root.dark .gname.ggroupitem {
|
||||
background-color: var(--group-item-bg-color);
|
||||
}
|
||||
|
||||
/* Form label and selected highlighting */
|
||||
:root.dark .gformlabel {
|
||||
background-color: var(--formlabel-bg-color);
|
||||
color: var(--secondary-text-color);
|
||||
border: var(--formlabel-border-color) 1px solid;
|
||||
}
|
||||
|
||||
:root.dark span.gformlabel:hover {
|
||||
background-color: var(--hover-bg-color);
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
:root.dark span.gselected {
|
||||
background-color: var(--formlabel-selected-bg-color);
|
||||
border-color: var(--task-complete-bg-color);
|
||||
color: var(--nav-link-color);
|
||||
}
|
||||
|
||||
:root.dark .gantt-inputtable {
|
||||
background-color: var(--input-bg-color);
|
||||
box-sizing: border-box;
|
||||
border: 1px solid var(--input-border-color);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
:root {
|
||||
--font-family: Arial, sans-serif;
|
||||
--margin-small: 0.625rem;
|
||||
--margin-medium: 1.25rem;
|
||||
--margin-large: 2.5rem;
|
||||
--padding-small: 0.125rem;
|
||||
--padding-medium: 1rem;
|
||||
--font-size-large: 1.2rem;
|
||||
--logo-height: 2.5rem;
|
||||
}
|
||||
|
||||
:root.dark {
|
||||
color-scheme: dark;
|
||||
--bg-color: #252525;
|
||||
--text-color: #e0e0e0;
|
||||
--nav-bg-color: #121212;
|
||||
--nav-border-color: #25682a;
|
||||
--nav-link-color: #fff;
|
||||
--nav-link-hover-color: #3fb449;
|
||||
--warning-color: #FFDB8F;
|
||||
}
|
||||
|
||||
:root.light {
|
||||
color-scheme: light;
|
||||
--bg-color: #ffffff;
|
||||
--text-color: #000000;
|
||||
--nav-bg-color: #f8f8f8;
|
||||
--nav-border-color: #cccccc;
|
||||
--nav-link-color: #000000;
|
||||
--nav-link-hover-color: #38a63d;
|
||||
--warning-color: #FF4500;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
font-family: var(--font-family);
|
||||
}
|
||||
|
||||
#container {
|
||||
margin-top: var(--margin-medium);
|
||||
margin-left: var(--margin-small);
|
||||
margin-right: var(--margin-small);
|
||||
margin-bottom: var(--margin-medium);
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-bottom: var(--margin-large);
|
||||
}
|
||||
|
||||
.csv-table {
|
||||
margin-top: var(--margin-small);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: var(--nav-bg-color);
|
||||
padding: var(--padding-medium) 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-bottom: 2px solid var(--nav-border-color);
|
||||
}
|
||||
|
||||
nav .logo {
|
||||
margin-left: var(--margin-large);
|
||||
height: var(--logo-height);
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
margin-left: 0.0625rem;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
margin-right: 3.125rem;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
text-decoration: none;
|
||||
color: var(--nav-link-color);
|
||||
font-size: var(--font-size-large);
|
||||
}
|
||||
|
||||
nav ul li a:hover,
|
||||
nav ul li a.active {
|
||||
color: var(--nav-link-hover-color);
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: var(--warning-color);
|
||||
margin-bottom: var(--margin-small);
|
||||
padding: var(--padding-small);
|
||||
display: none;
|
||||
}
|
||||
|
||||
#toggle-theme {
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-large);
|
||||
margin-right: var(--margin-medium);
|
||||
}
|
||||
|
||||
#toggle-theme:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ------------ Overwriting Tabulator CSS rules ------------ */
|
||||
|
||||
:root.light .tabulator-header,
|
||||
:root.light .tabulator .tabulator-header .tabulator-col {
|
||||
background: var(--nav-bg-color) !important;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
:root.light .tabulator {
|
||||
border-top: 1px solid #222;
|
||||
border-bottom: 2px solid #222;
|
||||
}
|
||||
@@ -1,384 +0,0 @@
|
||||
// keeps track of blenders connected in form of
|
||||
// shown:bool, workSchedule: {}, ganttTasks: {},
|
||||
const connectedClients = {};
|
||||
let socket;
|
||||
|
||||
// print options
|
||||
const pageSizes = [
|
||||
{ value: "210,297", text: "A4 Portrait" },
|
||||
{ value: "297,210", text: "A4 Landscape" },
|
||||
{ value: "297,420", text: "A3 Portrait" },
|
||||
{ value: "420,297", text: "A3 Landscape" },
|
||||
{ value: "420,594", text: "A2 Portrait" },
|
||||
{ value: "594,420", text: "A2 Landscape" },
|
||||
{ value: "594,841", text: "A1 Portrait" },
|
||||
{ value: "841,594", text: "A1 Landscape" },
|
||||
{ value: "841,1189", text: "A0 Portrait" },
|
||||
{ value: "1189,841", text: "A0 Landscape" },
|
||||
];
|
||||
|
||||
// Document ready function
|
||||
$(document).ready(function () {
|
||||
var systemTheme = window.matchMedia("(prefers-color-scheme: light)").matches
|
||||
? "light"
|
||||
: "dark";
|
||||
var theme = localStorage.getItem("theme") || systemTheme;
|
||||
setTheme(theme);
|
||||
|
||||
connectSocket();
|
||||
});
|
||||
|
||||
// Function to connect to Socket.IO server
|
||||
function connectSocket() {
|
||||
const url = "ws://localhost:" + SOCKET_PORT + "/web";
|
||||
socket = io(url);
|
||||
console.log("socket: ", socket);
|
||||
|
||||
// Register socket event handlers
|
||||
socket.on("blender_connect", handleBlenderConnect);
|
||||
socket.on("blender_disconnect", handleBlenderDisconnect);
|
||||
socket.on("gantt_data", handleGanttData);
|
||||
socket.on("default_data", handleDefaultData);
|
||||
}
|
||||
|
||||
// Function to handle 'blender_connect' event
|
||||
function handleBlenderConnect(blenderId) {
|
||||
console.log("blender_connect: ", blenderId);
|
||||
if (!connectedClients.hasOwnProperty(blenderId)) {
|
||||
connectedClients[blenderId] = {
|
||||
shown: false,
|
||||
workSchedule: {},
|
||||
ganttTasks: {},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Function to handle 'blender_disconnect' event
|
||||
function handleBlenderDisconnect(blenderId) {
|
||||
console.log("blender_disconnect: ", blenderId);
|
||||
if (connectedClients.hasOwnProperty(blenderId)) {
|
||||
delete connectedClients[blenderId];
|
||||
removeGanttElement(blenderId);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to handle 'gantt_data' event
|
||||
function handleGanttData(data) {
|
||||
const blenderId = data["blenderId"];
|
||||
|
||||
console.log(data);
|
||||
|
||||
const filename = data["data"]["ifc_file"];
|
||||
const ganttTasks = data["data"]["gantt_data"]["tasks"];
|
||||
const ganttWorkSched = data["data"]["gantt_data"]["work_schedule"];
|
||||
// const ganttWorkSched = {};
|
||||
|
||||
if (connectedClients.hasOwnProperty(blenderId)) {
|
||||
if (!connectedClients[blenderId].shown) {
|
||||
connectedClients[blenderId] = {
|
||||
shown: true,
|
||||
ganttTasks: ganttTasks,
|
||||
workSchedule: ganttWorkSched,
|
||||
};
|
||||
addGanttElement(blenderId, ganttTasks, ganttWorkSched, filename);
|
||||
} else {
|
||||
updateGanttElement(blenderId, ganttTasks, ganttWorkSched, filename);
|
||||
connectedClients[blenderId].workSchedule = ganttWorkSched;
|
||||
connectedClients[blenderId].ganttTasks = ganttTasks;
|
||||
}
|
||||
} else {
|
||||
connectedClients[blenderId] = {
|
||||
shown: true,
|
||||
ganttTasks: ganttTasks,
|
||||
workSchedule: ganttWorkSched,
|
||||
};
|
||||
addGanttElement(blenderId, ganttTasks, ganttWorkSched, filename);
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefaultData(data) {
|
||||
const blenderId = data["blenderId"];
|
||||
const isDirty = data["data"]["is_dirty"];
|
||||
showWarning(blenderId, isDirty);
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
// Function to add a new gantt with data and filename
|
||||
function addGanttElement(blenderId, tasks, workSched, filename) {
|
||||
const ganttContainer = $("<div></div>")
|
||||
.addClass("gantt-container")
|
||||
.attr("id", "container-" + blenderId);
|
||||
|
||||
const ganttTitle = $("<h3></h3>")
|
||||
.attr("id", "title-" + blenderId)
|
||||
.text(filename)
|
||||
.addClass("no-print")
|
||||
.css("margin-bottom", "10px");
|
||||
|
||||
const warning = $("<div></div>")
|
||||
.attr("id", "warning-" + blenderId)
|
||||
.html(
|
||||
"⚠ Warning: This Gantt Chart may contain outdated data due to recent changes in Blender."
|
||||
)
|
||||
.addClass("warning no-print");
|
||||
|
||||
const workSchedDiv = $("<div></div>").attr("id", "workSched" + blenderId);
|
||||
|
||||
const scheduleTable = $("<table></table>")
|
||||
.addClass("no-print table-description")
|
||||
.attr("id", "workSchedTable-" + blenderId)
|
||||
.hide();
|
||||
|
||||
$.each(workSched, (key, value) => {
|
||||
value = value ? value : "null";
|
||||
$("<tr></tr>")
|
||||
.append($("<td></td>").text(key))
|
||||
.append($("<td></td>").text(value))
|
||||
.appendTo(scheduleTable);
|
||||
});
|
||||
|
||||
const toggleButton = $("<button></button>")
|
||||
.text("Show Schedule Info")
|
||||
.addClass("btn no-print")
|
||||
.on("click", function () {
|
||||
scheduleTable.toggle();
|
||||
const buttonText = scheduleTable.is(":visible")
|
||||
? "Hide Schedule Info"
|
||||
: "Show Schedule Info";
|
||||
toggleButton.text(buttonText);
|
||||
});
|
||||
|
||||
var ganttInfoDiv = $("<div></div>")
|
||||
.addClass("gantt-info")
|
||||
.attr("id", "gantt-info-" + blenderId);
|
||||
|
||||
const scheduleName = $("<span></span>").text("Schedule: " + workSched.Name);
|
||||
|
||||
const createdOn = $("<span></span>")
|
||||
.text("Created: " + new Date(workSched.CreationDate).toLocaleDateString())
|
||||
.css("float", "right");
|
||||
|
||||
const ganttDiv = $("<div></div>")
|
||||
.addClass("gantt-chart")
|
||||
.attr("id", "gantt-" + blenderId);
|
||||
|
||||
ganttInfoDiv.append(scheduleName);
|
||||
ganttInfoDiv.append(createdOn);
|
||||
|
||||
workSchedDiv.append(toggleButton);
|
||||
workSchedDiv.append(scheduleTable);
|
||||
|
||||
ganttContainer.append(ganttTitle);
|
||||
ganttContainer.append(warning);
|
||||
ganttContainer.append(workSchedDiv);
|
||||
ganttContainer.append(ganttInfoDiv);
|
||||
ganttContainer.append(ganttDiv);
|
||||
|
||||
$("#container").append(ganttContainer);
|
||||
|
||||
let g = new JSGantt.GanttChart($("#gantt-" + blenderId)[0], "week");
|
||||
g.setOptions({
|
||||
vCaptionType: "Caption", // Set to Show Caption : None,Caption,Resource,Duration,Complete,
|
||||
vQuarterColWidth: 36,
|
||||
vDateTaskDisplayFormat: "day dd month yyyy", // Shown in tool tip box
|
||||
vDayMajorDateDisplayFormat: "mon yyyy - Week ww", // Set format to dates in the "Major" header of the "Day" view
|
||||
vWeekMinorDateDisplayFormat: "dd mon", // Set format to display dates in the "Minor" header of the "Week" view
|
||||
vLang: "en",
|
||||
vShowTaskInfoLink: 1, // Show link in tool tip (0/1)
|
||||
vShowEndWeekDate: 0, // Show/Hide the date for the last day of the week in header for daily
|
||||
vUseSingleCell: 10000, // Set the threshold cell per table row (Helps performance for large data.
|
||||
vFormatArr: ["Day", "Week", "Month", "Quarter"], // Even with setUseSingleCell using Hour format on such a large chart can cause issues in some browsers,
|
||||
vShowRes: true, // Disable the resource column.
|
||||
vShowComp: false, // Disable the completion column.
|
||||
vShowDur: false, // Disable the duration column, because jsgantt doesn't calculate durations the way we want.
|
||||
vAdditionalHeaders: {
|
||||
ifcduration: { title: "Duration" },
|
||||
resourceUsage: { title: "Resource Usage" },
|
||||
},
|
||||
vUseToolTip: true, // Disable tooltips.
|
||||
vTooltipTemplate: generateTooltip,
|
||||
vTotalHeight: 900,
|
||||
|
||||
vEventsChange: {
|
||||
taskname: editValue, // if you need to use the this scope, do: editValue.bind(this)
|
||||
res: editValue,
|
||||
dur: editValue,
|
||||
comp: editValue,
|
||||
start: editValue,
|
||||
end: editValue,
|
||||
planstart: editValue,
|
||||
planend: editValue,
|
||||
cost: editValue,
|
||||
additional_category: editValue,
|
||||
},
|
||||
});
|
||||
JSGantt.addJSONTask(g, tasks);
|
||||
g.setEditable(true);
|
||||
g.Draw();
|
||||
|
||||
connectedClients[blenderId]["gantt"] = g;
|
||||
|
||||
let printButton = $("<button>", {
|
||||
id: "print-btn-" + blenderId,
|
||||
html: "Print",
|
||||
class: "btn no-print",
|
||||
});
|
||||
|
||||
let printOptions = $("<select>", {
|
||||
id: "print-options-" + blenderId,
|
||||
class: "no-print",
|
||||
});
|
||||
|
||||
$.each(pageSizes, function (index, size) {
|
||||
printOptions.append(
|
||||
$("<option>", {
|
||||
value: size.value,
|
||||
text: size.text,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
printButton.on("click", function () {
|
||||
// make it only the corresponding gantt chart is printed
|
||||
$(".gantt-chart").removeClass("no-print");
|
||||
$(".gantt-chart")
|
||||
.not("#gantt-" + blenderId)
|
||||
.addClass("your-css-class");
|
||||
|
||||
var values = $("#print-options-" + blenderId)
|
||||
.val()
|
||||
.split(",");
|
||||
|
||||
g.setEditable(false);
|
||||
g.setTotalHeight("");
|
||||
g.Draw();
|
||||
|
||||
addEventListener("afterprint", (event) => {
|
||||
g.setEditable(true);
|
||||
});
|
||||
|
||||
let css =
|
||||
"@media print {\n" +
|
||||
" @page {\n" +
|
||||
" size: " +
|
||||
values[0] +
|
||||
"mm " +
|
||||
values[1] +
|
||||
"mm;\n" +
|
||||
" }\n" +
|
||||
" /* Make all text black */\n" +
|
||||
" body, p, span, h1, h2, h3, h4, h5, h6, div, a, li, td, th, * {\n" +
|
||||
" color: black !important;\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
g.printChart(values[0], values[1], css);
|
||||
g.setTotalHeight(900);
|
||||
g.Draw();
|
||||
});
|
||||
|
||||
ganttContainer.append(printOptions);
|
||||
ganttContainer.append(printButton);
|
||||
}
|
||||
|
||||
// Function to update gantt and filename
|
||||
function updateGanttElement(blenderId, tasks, workSched, filename) {
|
||||
// update work schedule table
|
||||
const table = $("#workSchedTable-" + blenderId);
|
||||
table.empty();
|
||||
$.each(workSched, (key, value) => {
|
||||
value = value ? value : "null";
|
||||
$("<tr></tr>")
|
||||
.append($("<td></td>").text(key))
|
||||
.append($("<td></td>").text(value))
|
||||
.appendTo(table);
|
||||
});
|
||||
|
||||
// update gantt chart with new data
|
||||
let g = connectedClients[blenderId]["gantt"];
|
||||
g.ClearTasks();
|
||||
g.Draw();
|
||||
JSGantt.addJSONTask(g, tasks);
|
||||
g.Draw();
|
||||
|
||||
$("#title-" + blenderId).text(filename);
|
||||
$("#warning-" + blenderId).css("display", "none");
|
||||
}
|
||||
|
||||
// Function to remove gantt element
|
||||
function removeGanttElement(blenderId) {
|
||||
$("#container-" + blenderId).remove();
|
||||
}
|
||||
|
||||
function showWarning(blenderId, isDirty) {
|
||||
$("#warning-" + blenderId).css("display", "block");
|
||||
}
|
||||
|
||||
// Utility function to create a tooltip for the gantt chars
|
||||
function generateTooltip(task) {
|
||||
var dataObject = task.getDataObject();
|
||||
var numberResources = dataObject.resourceUsage
|
||||
? dataObject.resourceUsage
|
||||
: "NULL";
|
||||
return `
|
||||
<dl>
|
||||
<dt>Name:</dt><dd>{{pName}}</dd>
|
||||
<dt>Start:</dt><dd>{{pStart}}</dd>
|
||||
<dt>End:</dt><dd>{{pEnd}}</dd>
|
||||
<dt>Duration:</dt><dd>${dataObject.ifcduration}</dd>
|
||||
<dt>Number of Resources:</dt><dd>${numberResources}</dd>
|
||||
<dt>Resources:</dt><dd>{{pRes}}</dd>
|
||||
</dl>
|
||||
`;
|
||||
}
|
||||
|
||||
// Event handlers for editing gantt table data
|
||||
function editValue(list, task, event, cell, column) {
|
||||
console.log("editValue function called with the following parameters:");
|
||||
console.log("list:", list);
|
||||
console.log("task:", task);
|
||||
console.log("event:", event);
|
||||
console.log("cell:", cell);
|
||||
console.log("column:", column);
|
||||
|
||||
const ganttId = task.getGantt()["vDiv"].id;
|
||||
const index = ganttId.indexOf("-") + 1;
|
||||
const blenderId = ganttId.substring(index);
|
||||
const workSchedId = connectedClients[blenderId].workSchedule.id;
|
||||
|
||||
// update data object reprsenting the task
|
||||
const dataObj = task.getDataObject();
|
||||
dataObj[column] = event.target.value;
|
||||
task.setDataObject(dataObj);
|
||||
|
||||
const msg = {
|
||||
sourcePage: "gantt",
|
||||
blenderId: blenderId,
|
||||
operator: {
|
||||
type: "editTask",
|
||||
workScheduleId: workSchedId,
|
||||
taskId: task.getOriginalID(),
|
||||
column: column,
|
||||
value: event.target.value,
|
||||
},
|
||||
};
|
||||
socket.emit("web_operator", msg);
|
||||
}
|
||||
|
||||
function setTheme(theme) {
|
||||
if (theme === "light") {
|
||||
$("html").removeClass("dark").addClass("light");
|
||||
$("#toggle-theme").html('<i class="fas fa-sun"></i>');
|
||||
} else {
|
||||
$("html").removeClass("light").addClass("dark");
|
||||
$("#toggle-theme").html('<i class="fas fa-moon"></i>');
|
||||
}
|
||||
localStorage.setItem("theme", theme);
|
||||
}
|
||||
|
||||
function toggleTheme() {
|
||||
if ($("html").hasClass("dark")) {
|
||||
setTheme("light");
|
||||
} else {
|
||||
setTheme("dark");
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Web Client</title>
|
||||
<link rel="stylesheet" type="text/css" href="/jsgantt/jsgantt.css" />
|
||||
<link rel="stylesheet" href="/static/css/gantt.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://code.jquery.com/jquery-3.6.0.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.socket.io/4.0.0/socket.io.min.js"
|
||||
></script>
|
||||
<script type="text/javascript" src="./jsgantt/jsgantt.js"></script>
|
||||
<script>
|
||||
var SOCKET_PORT = {{port}};
|
||||
</script>
|
||||
<script defer src="./static/js/gantt.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="no-print">
|
||||
<img
|
||||
src="https://blenderbim.org/assets/images/blender/blender-logo.png"
|
||||
alt="Logo"
|
||||
class="logo"
|
||||
/>
|
||||
<ul>
|
||||
<li><a href="/">IFC Data</a></li>
|
||||
<li><a href="/gantt" class="active">Gantt Chart</a></li>
|
||||
</ul>
|
||||
<button id="toggle-theme" onclick="toggleTheme()">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<div id="container"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,51 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Web Client</title>
|
||||
<link rel="stylesheet" href="/static/css/index.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
id="tabulator-stylesheet"
|
||||
href="https://unpkg.com/tabulator-tables/dist/css/tabulator_site_dark.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
||||
/>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://code.jquery.com/jquery-3.6.0.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.socket.io/4.0.0/socket.io.min.js"
|
||||
></script>
|
||||
<script>
|
||||
var SOCKET_PORT = {{port}};
|
||||
</script>
|
||||
<script defer src="./static/js/index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<img
|
||||
src="https://blenderbim.org/assets/images/blender/blender-logo.png"
|
||||
alt="Logo"
|
||||
class="logo"
|
||||
/>
|
||||
<ul>
|
||||
<li><a href="/" class="active">IFC Data</a></li>
|
||||
<li><a href="/gantt">Gantt Chart</a></li>
|
||||
</ul>
|
||||
<button id="toggle-theme" onclick="toggleTheme()">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<div id="container"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,104 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
def add_georeferencing(georeference):
|
||||
georeference.add_georeferencing()
|
||||
|
||||
|
||||
def enable_editing_georeferencing(georeference):
|
||||
georeference.import_projected_crs()
|
||||
georeference.import_coordinate_operation()
|
||||
georeference.enable_editing()
|
||||
|
||||
|
||||
def remove_georeferencing(ifc):
|
||||
ifc.run("georeference.remove_georeferencing")
|
||||
|
||||
|
||||
def disable_editing_georeferencing(georeference):
|
||||
georeference.disable_editing()
|
||||
|
||||
|
||||
def edit_georeferencing(ifc, georeference):
|
||||
ifc.run(
|
||||
"georeference.edit_georeferencing",
|
||||
projected_crs=georeference.get_projected_crs_attributes(),
|
||||
coordinate_operation=georeference.get_coordinate_operation_attributes(),
|
||||
)
|
||||
georeference.disable_editing()
|
||||
georeference.set_model_origin()
|
||||
|
||||
|
||||
def get_cursor_location(georeference):
|
||||
georeference.set_coordinates("local", georeference.get_cursor_location())
|
||||
|
||||
|
||||
def convert_local_to_global(georeference):
|
||||
coordinates = georeference.xyz2enh(georeference.get_coordinates("local"))
|
||||
georeference.set_coordinates("map", coordinates)
|
||||
georeference.set_cursor_location()
|
||||
|
||||
|
||||
def convert_global_to_local(georeference):
|
||||
coordinates = georeference.enh2xyz(georeference.get_coordinates("map"))
|
||||
georeference.set_coordinates("local", coordinates)
|
||||
georeference.set_cursor_location()
|
||||
|
||||
|
||||
def convert_angle_to_coord(georeference, type):
|
||||
vector_coordinates = georeference.angle2coords(georeference.get_angle(type), type)
|
||||
georeference.set_vector_coordinates(vector_coordinates, type)
|
||||
|
||||
|
||||
def import_plot(georeference, filepath):
|
||||
georeference.import_plot(filepath)
|
||||
|
||||
|
||||
def enable_editing_wcs(georeference):
|
||||
georeference.import_wcs()
|
||||
georeference.enable_editing_wcs()
|
||||
|
||||
|
||||
def disable_editing_wcs(georeference):
|
||||
georeference.disable_editing_wcs()
|
||||
|
||||
|
||||
def edit_wcs(ifc, georeference):
|
||||
wcs = georeference.export_wcs()
|
||||
georeference.set_wcs(wcs)
|
||||
georeference.disable_editing_wcs()
|
||||
georeference.set_model_origin()
|
||||
|
||||
|
||||
def enable_editing_true_north(georeference):
|
||||
georeference.import_true_north()
|
||||
georeference.enable_editing_true_north()
|
||||
|
||||
|
||||
def disable_editing_true_north(georeference):
|
||||
georeference.disable_editing_true_north()
|
||||
|
||||
|
||||
def edit_true_north(ifc, georeference):
|
||||
ifc.run("georeference.edit_true_north", true_north=georeference.get_true_north_attributes())
|
||||
georeference.disable_editing_true_north()
|
||||
|
||||
|
||||
def remove_true_north(ifc):
|
||||
ifc.run("georeference.edit_true_north", true_north=None)
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Wrapper script to launch BlenderBIM.
|
||||
|
||||
# If the `blender` executable can't be found in your PATH environment, set
|
||||
# BLENDER_EXE to the location of your preferred `blender` executable.
|
||||
|
||||
#BLENDER_EXE=/opt/blender-3.3/blender
|
||||
|
||||
: ${BLENDER_EXE:=blender}
|
||||
|
||||
if [[ $# -eq 1 && -f "$@" ]]; then
|
||||
"${BLENDER_EXE}" --python-expr 'import bpy; bpy.data.batch_remove(bpy.data.objects); bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True); bpy.ops.bim.load_project(filepath="'"$@"'")'
|
||||
else
|
||||
"${BLENDER_EXE}" --python-expr 'import bpy; bpy.data.batch_remove(bpy.data.objects); bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True); bpy.ops.bim.create_project()'
|
||||
fi;
|
||||
@@ -1,9 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Terminal=false
|
||||
Exec=blenderbim %f
|
||||
Name=BlenderBIM
|
||||
Icon=blenderbim
|
||||
X-Desktop-File-Install-Version=0.26
|
||||
GenericName=Blender BIM add-on
|
||||
MimeType=application/x-ifc;
|
||||
|
Before Width: | Height: | Size: 4.9 KiB |
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-ifc">
|
||||
<sub-class-of type="text/plain"/>
|
||||
<comment xml:lang="en">Industry Foundation Classes</comment>
|
||||
<magic priority="50">
|
||||
<match type="string" value="ISO-10303-21;" offset="0"/>
|
||||
</magic>
|
||||
<generic-icon name="x-ifc"/>
|
||||
<glob pattern="*.ifc"/>
|
||||
<glob pattern="*.ifczip"/>
|
||||
<glob pattern="*.ifcxml"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
@@ -1,64 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from blenderbim.tool.aggregate import Aggregate
|
||||
from blenderbim.tool.blender import Blender
|
||||
from blenderbim.tool.boundary import Boundary
|
||||
from blenderbim.tool.brick import Brick
|
||||
from blenderbim.tool.bsdd import Bsdd
|
||||
from blenderbim.tool.cad import Cad
|
||||
from blenderbim.tool.clash import Clash
|
||||
from blenderbim.tool.classification import Classification
|
||||
from blenderbim.tool.collector import Collector
|
||||
from blenderbim.tool.context import Context
|
||||
from blenderbim.tool.debug import Debug
|
||||
from blenderbim.tool.demo import Demo
|
||||
from blenderbim.tool.document import Document
|
||||
from blenderbim.tool.drawing import Drawing
|
||||
from blenderbim.tool.geometry import Geometry
|
||||
from blenderbim.tool.georeference import Georeference
|
||||
from blenderbim.tool.ifc import Ifc
|
||||
from blenderbim.tool.ifcgit import IfcGit
|
||||
from blenderbim.tool.ifcgit import IfcGitRepo
|
||||
from blenderbim.tool.library import Library
|
||||
from blenderbim.tool.loader import Loader
|
||||
from blenderbim.tool.material import Material
|
||||
from blenderbim.tool.misc import Misc
|
||||
from blenderbim.tool.model import Model
|
||||
from blenderbim.tool.nest import Nest
|
||||
from blenderbim.tool.owner import Owner
|
||||
from blenderbim.tool.patch import Patch
|
||||
from blenderbim.tool.project import Project
|
||||
from blenderbim.tool.profile import Profile
|
||||
from blenderbim.tool.pset import Pset
|
||||
from blenderbim.tool.qto import Qto
|
||||
from blenderbim.tool.resource import Resource
|
||||
from blenderbim.tool.root import Root
|
||||
from blenderbim.tool.sequence import Sequence
|
||||
from blenderbim.tool.spatial import Spatial
|
||||
from blenderbim.tool.covering import Covering
|
||||
from blenderbim.tool.structural import Structural
|
||||
from blenderbim.tool.style import Style
|
||||
from blenderbim.tool.surveyor import Surveyor
|
||||
from blenderbim.tool.system import System
|
||||
from blenderbim.tool.tester import Tester
|
||||
from blenderbim.tool.type import Type
|
||||
from blenderbim.tool.unit import Unit
|
||||
from blenderbim.tool.search import Search
|
||||
from blenderbim.tool.cost import Cost
|
||||
from blenderbim.tool.web import Web
|
||||
@@ -1,55 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
import shapely
|
||||
import ifcopenshell
|
||||
import blenderbim.core.tool
|
||||
import blenderbim.core.root
|
||||
import blenderbim.core.spatial
|
||||
import blenderbim.core.geometry
|
||||
import blenderbim.tool as tool
|
||||
import json
|
||||
from math import pi
|
||||
from mathutils import Vector, Matrix
|
||||
from shapely import Polygon, MultiPolygon
|
||||
|
||||
|
||||
class Covering(blenderbim.core.tool.Covering):
|
||||
@classmethod
|
||||
def get_z_from_ceiling_height(cls):
|
||||
props = bpy.context.scene.BIMCoveringProperties
|
||||
return props.ceiling_height
|
||||
|
||||
|
||||
# def toggle_spaces_visibility_wired_and_textured(cls, spaces):
|
||||
# first_obj = tool.Ifc.get_object(spaces[0])
|
||||
# if bpy.data.objects[first_obj.name].display_type == "TEXTURED":
|
||||
# for space in spaces:
|
||||
# obj = tool.Ifc.get_object(space)
|
||||
# bpy.data.objects[obj.name].show_wire = True
|
||||
# bpy.data.objects[obj.name].display_type = "WIRE"
|
||||
# return
|
||||
#
|
||||
# elif bpy.data.objects[first_obj.name].display_type == "WIRE":
|
||||
# for space in spaces:
|
||||
# obj = tool.Ifc.get_object(space)
|
||||
# bpy.data.objects[obj.name].show_wire = False
|
||||
# bpy.data.objects[obj.name].display_type = "TEXTURED"
|
||||
# return
|
||||
@@ -1,45 +0,0 @@
|
||||
System support
|
||||
==============
|
||||
|
||||
The BlenderBIM Add-on officially supports all major 64-bit platforms, as well as
|
||||
the Python version shipped by the Blender Foundation for the most recent three
|
||||
major Blender versions:
|
||||
|
||||
- 64-bit Linux on Python 3.10
|
||||
- 64-bit Linux on Python 3.11
|
||||
- 64-bit MacOS Intel on Python 3.10
|
||||
- 64-bit MacOS Intel on Python 3.11
|
||||
- 64-bit MacOS Silicon on Python 3.10
|
||||
- 64-bit MacOS Silicon on Python 3.11
|
||||
- 64-bit Windows on Python 3.10
|
||||
- 64-bit Windows on Python 3.11
|
||||
|
||||
Note that developer builds may exist for older versions of Python but there will
|
||||
be no guarantee of the uptime or stability of these builds.
|
||||
|
||||
Other system specifications match the `Blender Requirements
|
||||
<https://www.blender.org/download/requirements/>`_.
|
||||
|
||||
Add-on compatibility
|
||||
--------------------
|
||||
|
||||
The BlenderBIM Add-on is a non-trivial add-on. By turning Blender into a
|
||||
graphical front-end to a native IFC authoring platform, some fundamental Blender
|
||||
features (such as hotkeys for basic functionality like object deletion or
|
||||
duplication) have been patched and many dependencies have been introduced.
|
||||
|
||||
Other add-ons may no longer work as intended when the BlenderBIM Add-on is
|
||||
enabled, or vice versa, the BlenderBIM Add-on may no longer work as intended
|
||||
when other add-ons are enabled.
|
||||
|
||||
Known scenarios which will lead to add-on incompatibility include:
|
||||
|
||||
- The add-on also overrides the same hotkeys. For example, if an add-on
|
||||
overrides the "X" key to delete an object, you will need to manually trigger
|
||||
(either via menu or custom hotkey) the BlenderBIM Add-on equivalent operator
|
||||
(e.g. IFC Delete).
|
||||
- The add-on uses object deletion or duplication macros with dictionary
|
||||
override. Note that this is also deprecated in Blender, so the other add-on
|
||||
should be updated to fix this.
|
||||
- The add-on requires a conflicting dependency, or a conflicting version of the
|
||||
same dependency. Neither add-on may work simultaneously.
|
||||
@@ -1,70 +0,0 @@
|
||||
@echo off
|
||||
|
||||
echo SETUP BLENDERBIM ADD-ON LIVE DEVELOPMENT ENVIRONMENT
|
||||
echo Update BLENDER, BLENDER_VERSION, PYTHON_VERSION, BBIM_REPO, BLENDER_USER_NAME in the script bellow.
|
||||
echo Put the script at the root of your IfcOpenShell git repository
|
||||
echo This script needs to be run as administrator (to create symbolic links)
|
||||
echo Make sure you have followed these steps before proceeding :)
|
||||
|
||||
pause
|
||||
|
||||
SET BLENDER_VERSION=4.2
|
||||
SET PYTHON_VERSION=3.11
|
||||
SET BBIM_REPO=user_default
|
||||
rem Can be useful e.g. if you're running script from administrator account
|
||||
rem and need to setup dev environment for some other user.
|
||||
SET BLENDER_USER_NAME=%USERNAME%
|
||||
|
||||
SET BLENDER=%HOMEDRIVE%\Users\%BLENDER_USER_NAME%\AppData\Roaming\Blender Foundation\Blender\%BLENDER_VERSION%
|
||||
SET BLENDER_LOCAL=%BLENDER%\extensions\.local\lib\python%PYTHON_VERSION%\site-packages
|
||||
SET BLENDERBIM=%BLENDER_LOCAL%\blenderbim
|
||||
SET BLENDER_EXT=%BLENDER%\extensions\%BBIM_REPO%\blenderbim
|
||||
|
||||
echo Removing the Blender add-on Python code...
|
||||
del "%BLENDER_EXT%\__init__.py"
|
||||
rd /S /Q "%BLENDERBIM%"
|
||||
|
||||
echo Replacing them with links to the Git repository...
|
||||
mklink "%BLENDER_EXT%\__init__.py" "%CD%\src\blenderbim\blenderbim\__init__.py"
|
||||
mklink /D "%BLENDERBIM%" "%CD%\src\blenderbim\blenderbim"
|
||||
|
||||
echo Copy over compiled IfcOpenShell files...
|
||||
copy "%BLENDER_LOCAL%\ifcopenshell\*_wrapper*" "%CD%\src\ifcopenshell-python\ifcopenshell\"
|
||||
|
||||
echo Remove the IfcOpenShell dependency...
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcopenshell"
|
||||
|
||||
echo Replace them with links to the Git repository...
|
||||
mklink /D "%BLENDER_LOCAL%\ifcopenshell" "%CD%\src\ifcopenshell-python\ifcopenshell"
|
||||
|
||||
echo Remove and link other IfcOpenShell utilities...
|
||||
del "%BLENDER_LOCAL%\ifccsv.py"
|
||||
del "%BLENDER_LOCAL%\ifcdiff.py"
|
||||
del "%BLENDER_LOCAL%\bsdd.py"
|
||||
rd /S /Q "%BLENDER_LOCAL%\bcf"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifc4d"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifc5d"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifccityjson"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcclash"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcpatch"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifctester"
|
||||
rd /S /Q "%BLENDER_LOCAL%\ifcfm"
|
||||
|
||||
mklink "%BLENDER_LOCAL%\ifccsv.py" "%CD%\src\ifccsv\ifccsv.py"
|
||||
mklink "%BLENDER_LOCAL%\ifcdiff.py" "%CD%\src\ifcdiff\ifcdiff.py"
|
||||
mklink "%BLENDER_LOCAL%\bsdd.py" "%CD%\src\bsdd\bsdd.py"
|
||||
mklink /D "%BLENDER_LOCAL%\bcf" "%CD%\src\bcf\bcf"
|
||||
mklink /D "%BLENDER_LOCAL%\ifc4d" "%CD%\src\ifc4d\ifc4d"
|
||||
mklink /D "%BLENDER_LOCAL%\ifc5d" "%CD%\src\ifc5d\ifc5d"
|
||||
mklink /D "%BLENDER_LOCAL%\ifccityjson" "%CD%\src\ifccityjson\ifccityjson"
|
||||
mklink /D "%BLENDER_LOCAL%\ifcclash" "%CD%\src\ifcclash\ifcclash"
|
||||
mklink /D "%BLENDER_LOCAL%\ifcpatch" "%CD%\src\ifcpatch\ifcpatch"
|
||||
mklink /D "%BLENDER_LOCAL%\ifctester" "%CD%\src\ifctester\ifctester"
|
||||
mklink /D "%BLENDER_LOCAL%\ifcfm" "%CD%\src\ifcfm\ifcfm"
|
||||
|
||||
echo Manually downloading some third party dependencies...
|
||||
curl https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js -o "%BLENDERBIM%\bim\data\gantt\jsgantt.js"
|
||||
curl https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css -o "%BLENDERBIM%\bim\data\gantt\jsgantt.css"
|
||||
curl -L https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl -o "%BLENDERBIM%\bim\schema\Brick.ttl"
|
||||
|
||||
pause
|
||||
@@ -1,60 +0,0 @@
|
||||
git clone https://github.com/IfcOpenShell/IfcOpenShell.git
|
||||
cd IfcOpenShell
|
||||
|
||||
# path to BlenderBIM addon
|
||||
# default path on Mac: "/Users/$USER/Library/Application Support/Blender/X.X/scripts/addons/blenderbim"
|
||||
# default path on Linux: "$HOME/.config/blender/X.X/"
|
||||
BLENDER_ADDON_PATH="/path/to/blender/X.XX/scripts/addons/blenderbim"
|
||||
|
||||
# Remove the Blender add-on Python code
|
||||
rm -r $BLENDER_ADDON_PATH/core/
|
||||
rm -r $BLENDER_ADDON_PATH/tool/
|
||||
rm -r $BLENDER_ADDON_PATH/bim/
|
||||
|
||||
# Replace them with links to the Git repository
|
||||
ln -s $PWD/src/blenderbim/blenderbim/core $BLENDER_ADDON_PATH/core
|
||||
ln -s $PWD/src/blenderbim/blenderbim/tool $BLENDER_ADDON_PATH/tool
|
||||
ln -s $PWD/src/blenderbim/blenderbim/bim $BLENDER_ADDON_PATH/bim
|
||||
|
||||
# Copy over compiled IfcOpenShell files
|
||||
cp $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell/*_wrapper* $PWD/src/ifcopenshell-python/ifcopenshell/
|
||||
|
||||
# Remove the IfcOpenShell dependency
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell
|
||||
|
||||
# Replace them with links to the Git repository
|
||||
ln -s $PWD/src/ifcopenshell-python/ifcopenshell $BLENDER_ADDON_PATH/libs/site/packages/ifcopenshell
|
||||
|
||||
# Remove and link other IfcOpenShell utilities
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifccsv.py
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcdiff.py
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/bsdd.py
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/bcf
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifc4d
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifc5d
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifccityjson
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcclash
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcpatch
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifctester
|
||||
rm -r $BLENDER_ADDON_PATH/libs/site/packages/ifcfm
|
||||
rm -r $BLENDER_ADDON_PATH/libs/Desktop
|
||||
|
||||
ln -s $PWD/src/ifccsv/ifccsv.py $BLENDER_ADDON_PATH/libs/site/packages/ifccsv.py
|
||||
ln -s $PWD/src/ifcdiff/ifcdiff.py $BLENDER_ADDON_PATH/libs/site/packages/ifcdiff.py
|
||||
ln -s $PWD/src/bsdd/bsdd.py $BLENDER_ADDON_PATH/libs/site/packages/bsdd.py
|
||||
ln -s $PWD/src/bcf/bcf $BLENDER_ADDON_PATH/libs/site/packages/bcf
|
||||
ln -s $PWD/src/ifc4d/ifc4d $BLENDER_ADDON_PATH/libs/site/packages/ifc4d
|
||||
ln -s $PWD/src/ifc5d/ifc5d $BLENDER_ADDON_PATH/libs/site/packages/ifc5d
|
||||
ln -s $PWD/src/ifccityjson/ifccityjson $BLENDER_ADDON_PATH/libs/site/packages/ifccityjson
|
||||
ln -s $PWD/src/ifcclash/ifcclash $BLENDER_ADDON_PATH/libs/site/packages/ifcclash
|
||||
ln -s $PWD/src/ifcpatch/ifcpatch $BLENDER_ADDON_PATH/libs/site/packages/ifcpatch
|
||||
ln -s $PWD/src/ifctester/ifctester $BLENDER_ADDON_PATH/libs/site/packages/ifctester
|
||||
ln -s $PWD/src/ifcfm/ifcfm $BLENDER_ADDON_PATH/libs/site/packages/ifcfm
|
||||
ln -s $PWD/src/blenderbim/blenderbim/libs/desktop $BLENDER_ADDON_PATH/libs/Desktop
|
||||
|
||||
# Manually download some third party dependencies
|
||||
cd $BLENDER_ADDON_PATH/bim/data/gantt
|
||||
wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
cd $BLENDER_ADDON_PATH/bim/schema
|
||||
wget https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl
|
||||
@@ -1,122 +0,0 @@
|
||||
@aggregate
|
||||
Feature: Aggregate
|
||||
Covers element and spatial aggregation
|
||||
|
||||
Scenario: Enable editing aggregate
|
||||
Given an empty IFC project
|
||||
And the object "IfcSite/My Site" is selected
|
||||
When I press "bim.enable_editing_aggregate"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Disable editing aggregate
|
||||
Given an empty IFC project
|
||||
And the object "IfcSite/My Site" is selected
|
||||
And I press "bim.enable_editing_aggregate"
|
||||
When I press "bim.disable_editing_aggregate"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Assign object
|
||||
Given an empty IFC project
|
||||
And the object "IfcSite/My Site" is selected
|
||||
And the object "IfcBuildingStorey/My Storey" is selected
|
||||
And I press "bim.enable_editing_aggregate"
|
||||
And the variable "relating_object" is "tool.Ifc.get().by_type('IfcSite')[0].id()"
|
||||
When I press "bim.aggregate_assign_object(relating_object={relating_object})"
|
||||
Then the object "IfcSite/My Site" is in the collection "IfcSite/My Site"
|
||||
And the object "IfcBuildingStorey/My Storey" is in the collection "IfcBuildingStorey/My Storey"
|
||||
And the collection "IfcBuildingStorey/My Storey" is in the collection "IfcSite/My Site"
|
||||
|
||||
Scenario: Unassign object
|
||||
Given an empty IFC project
|
||||
And the object "IfcBuildingStorey/My Storey" is selected
|
||||
And I press "bim.enable_editing_aggregate"
|
||||
And the variable "relating_object" is "tool.Ifc.get().by_type('IfcSite')[0].id()"
|
||||
And I press "bim.aggregate_assign_object(relating_object={relating_object})"
|
||||
And the object "IfcBuildingStorey/My Storey" is selected
|
||||
When I press "bim.aggregate_unassign_object"
|
||||
Then the object "IfcSite/My Site" is in the collection "IfcSite/My Site"
|
||||
And the object "IfcBuildingStorey/My Storey" is in the collection "IfcBuildingStorey/My Storey"
|
||||
And the collection "IfcBuildingStorey/My Storey" is in the collection "IfcProject/My Project"
|
||||
|
||||
Scenario: Unassign object - multiple objects are contained again to their indirect container
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcMember"
|
||||
And I press "bim.assign_class"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcCovering"
|
||||
And I press "bim.assign_class"
|
||||
And the object "IfcMember/Cube" is selected
|
||||
And additionally the object "IfcCovering/Cube" is selected
|
||||
And I press "bim.add_aggregate(ifc_class='IfcWall')"
|
||||
And the object "IfcMember/Cube" is selected
|
||||
And additionally the object "IfcCovering/Cube" is selected
|
||||
When I press "bim.aggregate_unassign_object"
|
||||
Then the object "IfcMember/Cube" is in the collection "IfcBuildingStorey/My Storey"
|
||||
And the object "IfcCovering/Cube" is in the collection "IfcBuildingStorey/My Storey"
|
||||
|
||||
Scenario: Add aggregate
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And the object "IfcWall/Cube" is selected
|
||||
When I press "bim.add_aggregate"
|
||||
Then the object "IfcWall/Cube" is in the collection "IfcElementAssembly/Assembly"
|
||||
And the object "IfcElementAssembly/Assembly" is in the collection "IfcElementAssembly/Assembly"
|
||||
And the collection "IfcElementAssembly/Assembly" is in the collection "IfcBuildingStorey/My Storey"
|
||||
|
||||
Scenario: Add aggregate - with the aggregate inheriting the existing spatial collection
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And the object "IfcWall/Cube" is placed in the collection "IfcBuildingStorey/My Storey"
|
||||
And the object "IfcWall/Cube" is selected
|
||||
When I press "bim.add_aggregate"
|
||||
Then the object "IfcWall/Cube" is in the collection "IfcElementAssembly/Assembly"
|
||||
And the object "IfcElementAssembly/Assembly" is in the collection "IfcElementAssembly/Assembly"
|
||||
And the collection "IfcElementAssembly/Assembly" is in the collection "IfcBuildingStorey/My Storey"
|
||||
|
||||
Scenario: Add aggregate - add a nested aggregate
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And the object "IfcWall/Cube" is placed in the collection "IfcBuildingStorey/My Storey"
|
||||
And the object "IfcWall/Cube" is selected
|
||||
When I press "bim.add_aggregate"
|
||||
And the object "IfcWall/Cube" is selected
|
||||
And I press "bim.add_aggregate"
|
||||
Then the object "IfcWall/Cube" is in the collection "IfcElementAssembly/Assembly.001"
|
||||
And the object "IfcElementAssembly/Assembly.001" is in the collection "IfcElementAssembly/Assembly.001"
|
||||
And the collection "IfcElementAssembly/Assembly.001" is in the collection "IfcElementAssembly/Assembly"
|
||||
And the collection "IfcElementAssembly/Assembly" is in the collection "IfcBuildingStorey/My Storey"
|
||||
|
||||
Scenario: Add aggregate - add multiple elements to a custom aggregate class
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcMember"
|
||||
And I press "bim.assign_class"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcCovering"
|
||||
And I press "bim.assign_class"
|
||||
And the object "IfcMember/Cube" is selected
|
||||
And additionally the object "IfcCovering/Cube" is selected
|
||||
When I press "bim.add_aggregate(ifc_class='IfcWall')"
|
||||
Then the object "IfcMember/Cube" is in the collection "IfcWall/Assembly"
|
||||
And the object "IfcCovering/Cube" is in the collection "IfcWall/Assembly"
|
||||
And the object "IfcWall/Assembly" is in the collection "IfcWall/Assembly"
|
||||
And the collection "IfcWall/Assembly" is in the collection "IfcBuildingStorey/My Storey"
|
||||
@@ -1,9 +0,0 @@
|
||||
@bimtester
|
||||
Feature: Bimtester
|
||||
|
||||
Scenario: Execute Bimtester
|
||||
Given an empty IFC project
|
||||
When I set "scene.BimTesterProperties.should_load_from_memory" to "True"
|
||||
And I set "scene.BimTesterProperties.feature" to "{cwd}/test/files/sample.feature"
|
||||
And I press "bim.execute_bim_tester"
|
||||
Then nothing happens
|
||||
@@ -1,15 +0,0 @@
|
||||
@covering
|
||||
Feature: Covering
|
||||
Covers covering tool.
|
||||
|
||||
Scenario: Execute generate flooring coverings from walls
|
||||
Given an empty IFC project
|
||||
And I load the demo construction library
|
||||
And I set "scene.BIMModelProperties.ifc_class" to "IfcWallType"
|
||||
And the variable "element_type" is "[e for e in {ifc}.by_type('IfcWallType') if e.Name == 'WAL100'][0].id()"
|
||||
And I set "scene.BIMModelProperties.relating_type_id" to "{element_type}"
|
||||
And I press "bim.add_constr_type_instance"
|
||||
And the object "IfcWall/Wall" is selected
|
||||
When I press "bim.add_instance_flooring_coverings_from_walls"
|
||||
Then nothing happens
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
@georeference
|
||||
Feature: Georeference
|
||||
|
||||
Scenario: Add georeferencing
|
||||
Given an empty IFC project
|
||||
When I press "bim.add_georeferencing"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Enable editing georeferencing
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
When I press "bim.enable_editing_georeferencing"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Remove georeferencing
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
When I press "bim.remove_georeferencing"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Edit georeferencing
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
And I press "bim.enable_editing_georeferencing"
|
||||
When I press "bim.edit_georeferencing"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Disable editing georeferencing
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
And I press "bim.enable_editing_georeferencing"
|
||||
When I press "bim.disable_editing_georeferencing"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set IFC grid north
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
And I press "bim.enable_editing_georeferencing"
|
||||
When I press "bim.set_ifc_grid_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set Blender grid north
|
||||
Given an empty IFC project
|
||||
And I press "bim.add_georeferencing"
|
||||
And I press "bim.enable_editing_georeferencing"
|
||||
And I press "bim.set_ifc_grid_north"
|
||||
When I press "bim.set_blender_grid_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Get cursor location
|
||||
Given an empty IFC project
|
||||
When I press "bim.get_cursor_location"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set IFC true north
|
||||
Given an empty IFC project
|
||||
When I press "bim.set_ifc_true_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Set Blender true north
|
||||
Given an empty IFC project
|
||||
And I press "bim.set_ifc_true_north"
|
||||
When I press "bim.set_blender_true_north"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Convert local to global
|
||||
Given an empty IFC project
|
||||
When I set "scene.BIMGeoreferenceProperties.local_coordinates" to "0,0,0"
|
||||
And I press "bim.convert_local_to_global"
|
||||
Then "scene.BIMGeoreferenceProperties.map_coordinates" is "0.0,0.0,0.0"
|
||||
|
||||
Scenario: Convert global to local
|
||||
Given an empty IFC project
|
||||
When I set "scene.BIMGeoreferenceProperties.map_coordinates" to "0,0,0"
|
||||
And I press "bim.convert_global_to_local"
|
||||
Then "scene.BIMGeoreferenceProperties.local_coordinates" is "0.0,0.0,0.0"
|
||||
@@ -1,25 +0,0 @@
|
||||
@patch
|
||||
Feature: Patch
|
||||
|
||||
Scenario: Execute IFC Patch - file in memory
|
||||
Given an empty IFC project
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_recipes" to "OffsetObjectPlacements"
|
||||
And I set "scene.BIMPatchProperties.should_load_from_memory" to "True"
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_output" to "{cwd}/test/files/temp/basic-patched.ifc"
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_args" to "[123454321,0,0,0]"
|
||||
When I press "bim.execute_ifc_patch(use_json_for_args=True)"
|
||||
Then the file "{cwd}/test/files/temp/basic-patched.ifc" should contain "123454321"
|
||||
|
||||
Scenario: Execute IFC Patch - file from disk
|
||||
Given an empty IFC project
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_recipes" to "OffsetObjectPlacements"
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_input" to "{cwd}/test/files/basic.ifc"
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_output" to "{cwd}/test/files/temp/basic-patched.ifc"
|
||||
And I set "scene.BIMPatchProperties.ifc_patch_args" to "[123454321,0,0,0]"
|
||||
When I press "bim.execute_ifc_patch(use_json_for_args=True)"
|
||||
Then the file "{cwd}/test/files/temp/basic-patched.ifc" should contain "123454321"
|
||||
|
||||
Scenario: Run migrate patch
|
||||
Given an empty Blender session
|
||||
When I press "bim.run_migrate_patch(infile='{cwd}/test/files/ifc2x3.ifc', outfile='{cwd}/test/files/temp/ifc2x3-migrated.ifc', schema='IFC4')"
|
||||
Then the file "{cwd}/test/files/temp/ifc2x3-migrated.ifc" should contain "IFC4"
|
||||
@@ -1,94 +0,0 @@
|
||||
@style
|
||||
Feature: Style
|
||||
|
||||
Scenario: Update style colours
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
And I press "bim.add_style"
|
||||
When I press "bim.update_style_colours"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Remove style
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
And I press "bim.add_style"
|
||||
And the variable "style" is "{ifc}.by_type('IfcSurfaceStyle')[0].id()"
|
||||
When I press "bim.remove_style(style={style})"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Add style to current blender material
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
When I press "bim.add_style"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Unlink style
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
And I press "bim.add_style"
|
||||
When I press "bim.unlink_style"
|
||||
Then the material "Material" is not an IFC style
|
||||
|
||||
Scenario: Add a new style
|
||||
Given an empty IFC project
|
||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
And I press "bim.enable_adding_presentation_style"
|
||||
When I press "bim.add_presentation_style"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Disable adding a new style
|
||||
Given an empty IFC project
|
||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
When I press "bim.disable_adding_presentation_style"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Edit style
|
||||
Given an empty IFC project
|
||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
And I press "bim.enable_adding_presentation_style"
|
||||
And I press "bim.add_presentation_style"
|
||||
And the variable "style" is "{ifc}.by_type('IfcSurfaceStyle')[0].id()"
|
||||
And I press "bim.enable_editing_style(style={style})"
|
||||
When I press "bim.edit_style"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Disable editing style
|
||||
Given an empty IFC project
|
||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
And I press "bim.enable_adding_presentation_style"
|
||||
And I press "bim.add_presentation_style"
|
||||
And the variable "style" is "{ifc}.by_type('IfcSurfaceStyle')[0].id()"
|
||||
And I press "bim.enable_editing_style(style={style})"
|
||||
When I press "bim.disable_editing_style"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Load styles
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
And I press "bim.add_style"
|
||||
When I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Disable editing styles
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
And I press "bim.add_style"
|
||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
When I press "bim.disable_editing_styles"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Select by style
|
||||
Given an empty IFC project
|
||||
And I add a cube
|
||||
And I add a material
|
||||
And I press "bim.add_style"
|
||||
And I press "bim.load_styles(style_type='IfcSurfaceStyle')"
|
||||
And the variable "style" is "{ifc}.by_type('IfcSurfaceStyle')[0].id()"
|
||||
When I press "bim.select_by_style(style={style})"
|
||||
Then nothing happens
|
||||
@@ -1,17 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -1,17 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -1,112 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2022 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import blenderbim.core.georeference as subject
|
||||
from test.core.bootstrap import ifc, georeference
|
||||
|
||||
|
||||
class TestAddGeoreferencing:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("georeference.add_georeferencing").should_be_called()
|
||||
subject.add_georeferencing(ifc)
|
||||
|
||||
|
||||
class TestEnableGeoreferencing:
|
||||
def test_run(self, georeference):
|
||||
georeference.import_projected_crs().should_be_called()
|
||||
georeference.import_map_conversion().should_be_called()
|
||||
georeference.import_true_north().should_be_called()
|
||||
georeference.enable_editing().should_be_called()
|
||||
subject.enable_editing_georeferencing(georeference)
|
||||
|
||||
|
||||
class TestRemoveGeoreferencing:
|
||||
def test_run(self, ifc):
|
||||
ifc.run("georeference.remove_georeferencing").should_be_called()
|
||||
subject.remove_georeferencing(ifc)
|
||||
|
||||
|
||||
class TestEditGeoreferencing:
|
||||
def test_run(self, ifc, georeference):
|
||||
georeference.get_projected_crs_attributes().should_be_called().will_return("projected_crs_attributes")
|
||||
georeference.get_map_conversion_attributes().should_be_called().will_return("map_conversion_attributes")
|
||||
georeference.get_true_north_attributes().should_be_called().will_return("true_north_attributes")
|
||||
ifc.run(
|
||||
"georeference.edit_georeferencing",
|
||||
projected_crs="projected_crs_attributes",
|
||||
map_conversion="map_conversion_attributes",
|
||||
true_north="true_north_attributes",
|
||||
).should_be_called()
|
||||
georeference.disable_editing().should_be_called()
|
||||
subject.edit_georeferencing(ifc, georeference)
|
||||
|
||||
|
||||
class TestSetIfcGridNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_ifc_grid_north().should_be_called()
|
||||
subject.set_ifc_grid_north(georeference)
|
||||
|
||||
|
||||
class TestSetBlenderGridNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_blender_grid_north().should_be_called()
|
||||
subject.set_blender_grid_north(georeference)
|
||||
|
||||
|
||||
class TestSetIfcTrueNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_ifc_true_north().should_be_called()
|
||||
subject.set_ifc_true_north(georeference)
|
||||
|
||||
|
||||
class TestSetBlenderTrueNorth:
|
||||
def test_run(self, georeference):
|
||||
georeference.set_blender_true_north().should_be_called()
|
||||
subject.set_blender_true_north(georeference)
|
||||
|
||||
|
||||
class TestGetCursorLocation:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_cursor_location().should_be_called().will_return("coordinates")
|
||||
georeference.set_coordinates("input", "coordinates").should_be_called()
|
||||
subject.get_cursor_location(georeference)
|
||||
|
||||
|
||||
class TestSetCursorLocation:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_coordinates("output").should_be_called().will_return("coordinates")
|
||||
georeference.set_cursor_location("coordinates").should_be_called()
|
||||
subject.set_cursor_location(georeference)
|
||||
|
||||
|
||||
class TestConvertLocalToGlobal:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_coordinates("input").should_be_called().will_return("coordinates")
|
||||
georeference.xyz2enh("coordinates").should_be_called().will_return("enh")
|
||||
georeference.set_coordinates("output", "enh").should_be_called()
|
||||
georeference.set_cursor_location("enh").should_be_called()
|
||||
subject.convert_local_to_global(georeference)
|
||||
|
||||
|
||||
class TestConvertGlobalToLocal:
|
||||
def test_run(self, georeference):
|
||||
georeference.get_coordinates("input").should_be_called().will_return("coordinates")
|
||||
georeference.enh2xyz("coordinates").should_be_called().will_return("xyz")
|
||||
georeference.set_coordinates("output", "xyz").should_be_called()
|
||||
georeference.set_cursor_location("xyz").should_be_called()
|
||||
subject.convert_global_to_local(georeference)
|
||||
@@ -1,17 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on 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.
|
||||
#
|
||||
# BlenderBIM Add-on 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
@@ -2,7 +2,7 @@
|
||||
# Visit https://bit.ly/cffinit to generate yours today!
|
||||
|
||||
cff-version: 1.2.0
|
||||
title: BlenderBIM Add-on
|
||||
title: Bonsai
|
||||
message: >-
|
||||
If you use this software, please cite it using the
|
||||
metadata from this file.
|
||||
@@ -10,9 +10,9 @@ type: software
|
||||
authors:
|
||||
- name: "IfcOpenShell contributors"
|
||||
repository-code: >-
|
||||
https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.8.0/src/blenderbim
|
||||
url: 'https://blenderbim.org/'
|
||||
repository-artifact: 'https://blenderbim.org/download.html'
|
||||
https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.8.0/src/bonsai
|
||||
url: 'https://bonsaibim.org/'
|
||||
repository-artifact: 'https://bonsaibim.org/download.html'
|
||||
abstract: >-
|
||||
Add-on to Blender providing a graphical native IFC
|
||||
authoring platform
|
||||
@@ -1,20 +1,20 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020-2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# 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.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PYTHON:=python3.11
|
||||
PIP:=pip3.11
|
||||
@@ -49,16 +49,6 @@ LAST_COMMIT_HASH:=$(shell git rev-parse HEAD)
|
||||
PYVERSION:=py310
|
||||
PYPI_IMP:=cp
|
||||
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYLIBDIR:=python3.9
|
||||
PYNUMBER:=39
|
||||
PYPI_VERSION:=3.9
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
PYLIBDIR:=python3.10
|
||||
PYNUMBER:=310
|
||||
PYPI_VERSION:=3.10
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
PYLIBDIR:=python3.11
|
||||
PYNUMBER:=311
|
||||
@@ -105,7 +95,7 @@ endif
|
||||
rm -rf build
|
||||
mkdir -p build
|
||||
mkdir -p dist
|
||||
cp -r blenderbim build/
|
||||
cp -r bonsai build/
|
||||
|
||||
# To scope any build-time dependencies
|
||||
cd build && $(PYTHON) -m venv env && . env/$(VENV_ACTIVATE) && $(PIP) install build
|
||||
@@ -113,18 +103,18 @@ endif
|
||||
|
||||
mkdir -p build/wheels
|
||||
# Provides IfcOpenShell Python functionality
|
||||
cd ../ifcopenshell-python && make dist PLATFORM=$(PLATFORM)64 PYVERSION=$(PYVERSION) && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../bcf && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifcclash && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifctester && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifcfm && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../bsdd && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifcdiff && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifccsv && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifcpatch && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifc4d && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifc5d && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifccityjson && make dist && mv dist/*.whl ../blenderbim/build/wheels/
|
||||
cd ../ifcopenshell-python && make dist PLATFORM=$(PLATFORM)64 PYVERSION=$(PYVERSION) && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../bcf && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifcclash && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifctester && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifcfm && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../bsdd && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifcdiff && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifccsv && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifcpatch && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifc4d && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifc5d && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd ../ifccityjson && make dist && mv dist/*.whl ../bonsai/build/wheels/
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download GitPython --dest=./wheels
|
||||
# Provides audio playback for costing
|
||||
# This is a REALLY IMPORTANT feature
|
||||
@@ -191,28 +181,29 @@ else
|
||||
endif
|
||||
|
||||
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
||||
cd build/blenderbim/bim/data/gantt/ && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
cd build/blenderbim/bim/data/gantt/ && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
cd build/bonsai/bim/data/gantt/ && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
cd build/bonsai/bim/data/gantt/ && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
|
||||
# Provides IFCJSON functionality
|
||||
cd build && wget https://github.com/IFCJSON-Team/IFC2JSON_python/archive/master.zip
|
||||
cd build && unzip master.zip && rm master.zip
|
||||
# TODO: replace with main repo if https://github.com/IFCJSON-Team/IFC2JSON_python/pull/3 is merged.
|
||||
cd build && wget -O ifc2json.zip https://github.com/Moult/IFC2JSON_python/archive/refs/heads/feature-ios-v0.8.0.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-master/file_converters && \
|
||||
cd build && . env/$(VENV_ACTIVATE) && cd IFC2JSON_python-*/file_converters && \
|
||||
$(PYTHON) -c "from setuptools import setup; \
|
||||
setup( \
|
||||
name='ifcjson', \
|
||||
version='0.0.0', \
|
||||
version='0.0.1', \
|
||||
author='Jan Brouwer', \
|
||||
author_email='jan@brewsky.nl', \
|
||||
packages=['ifcjson'], \
|
||||
)" bdist_wheel
|
||||
cp -r build/IFC2JSON_python-master/file_converters/dist/*.whl build/wheels/
|
||||
cp -r build/IFC2JSON_python-*/file_converters/dist/*.whl build/wheels/
|
||||
|
||||
# Brickschema requires pkg_resources which is provided by Blender.
|
||||
# Provides Brickschema functionality
|
||||
# For now lets bundle the latest nightly schema
|
||||
cd build/blenderbim/bim/schema && wget https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl
|
||||
cd build/bonsai/bim/schema && 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
|
||||
@@ -227,11 +218,11 @@ endif
|
||||
cp -r build/bpypolyskel-master/dist/*.whl build/wheels/
|
||||
|
||||
# Required for Desktop icon and file association
|
||||
cp -r blenderbim/libs/desktop build/blenderbim/libs/
|
||||
cp -r bonsai/libs/desktop build/bonsai/libs/
|
||||
|
||||
# Generate translations module for BBIM build
|
||||
git clone https://github.com/IfcOpenShell/blenderbim-translations.git build/working
|
||||
$(PYTHON) scripts/bbim_translations.py -i "build/working" -o "build/blenderbim"
|
||||
# Generate translations module for Bonsai build
|
||||
git clone https://github.com/IfcOpenShell/bonsai-translations.git build/working
|
||||
$(PYTHON) scripts/bonsai_translations.py -i "build/working" -o "build/bonsai"
|
||||
rm -rf build/working
|
||||
|
||||
# Remove dependencies also bundled with Blender
|
||||
@@ -239,17 +230,17 @@ endif
|
||||
|
||||
cp pyproject.toml build/
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) "s/0.0.0/$(VERSION)/" build/blenderbim/blender_manifest.toml
|
||||
$(SED) "s/0.0.0/$(VERSION)/" build/bonsai/blender_manifest.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/pyproject.toml
|
||||
else
|
||||
$(SED) "s/0.0.0/$(VERSION)-alpha$(VERSION_DATE)/" build/blenderbim/blender_manifest.toml
|
||||
$(SED) "s/8888888/$(LAST_COMMIT_HASH)/" build/blenderbim/__init__.py
|
||||
$(SED) "s/0.0.0/$(VERSION)-alpha$(VERSION_DATE)/" build/bonsai/blender_manifest.toml
|
||||
$(SED) "s/8888888/$(LAST_COMMIT_HASH)/" build/bonsai/__init__.py
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)-alpha$(VERSION_DATE)"/' build/pyproject.toml
|
||||
endif
|
||||
|
||||
$(SED) "s/os-arch/$(BLENDER_PLATFORM)/" build/blenderbim/blender_manifest.toml
|
||||
$(SED) "s/os-arch/$(BLENDER_PLATFORM)/" build/bonsai/blender_manifest.toml
|
||||
|
||||
# Provides BlenderBIM Add-on functionality
|
||||
# Provides bonsai Add-on functionality
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/pyproject.toml
|
||||
else
|
||||
@@ -266,7 +257,7 @@ endif
|
||||
echo "Error: non-wheel dependencies are not supported by Blender!"; \
|
||||
exit 1; \
|
||||
fi
|
||||
mv build/wheels/*.whl build/blenderbim/wheels/
|
||||
mv build/wheels/*.whl build/bonsai/wheels/
|
||||
|
||||
# Ugly patch to accomodate MacOS universal builds not being recognized by Blender.
|
||||
# Blender doesn't look into the wheel contents, it just checks the name.
|
||||
@@ -275,41 +266,41 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
# Has universal and x86_64 builds.
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/MarkupSafe-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/MarkupSafe-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/_universal2/_arm64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
|
||||
# Has universal and x86_64 builds.
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/lxml-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/lxml-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/_universal2/_arm64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/tzfpy-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/tzfpy-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2/macosx_10_12_arm64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
|
||||
# Has only universal build.
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/greenlet-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/greenlet-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/_universal2/_arm64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
endif
|
||||
ifeq ($(PLATFORM), macos)
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/tzfpy-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/tzfpy-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2/macosx_10_9_x86_64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/greenlet-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/greenlet-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/_universal2/_x86_64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
|
||||
# has universal and amr64 builds.
|
||||
prev_whl_name=$$(find build/blenderbim/wheels/fonttools-*.whl); \
|
||||
prev_whl_name=$$(find build/bonsai/wheels/fonttools-*.whl); \
|
||||
whl_name=$$(echo $$prev_whl_name | sed "s/_universal2/_x86_64/"); \
|
||||
mv "$$prev_whl_name" "$$whl_name";
|
||||
endif
|
||||
|
||||
# Safeguard for unhandled universal files.
|
||||
wheels=$$(find build/blenderbim/wheels/*universal2*.whl); \
|
||||
wheels=$$(find build/bonsai/wheels/*universal2*.whl); \
|
||||
if [ -n "$$wheels" ]; then \
|
||||
echo "Found universal2 wheel files:"; \
|
||||
echo "$$wheels"; \
|
||||
@@ -320,7 +311,7 @@ endif
|
||||
ifneq ($(PLATFORM), linux)
|
||||
# Safeguard: in case one of `pip download` will break,
|
||||
# it will produce a linux wheel for non-linux build (our github action machine is using linux).
|
||||
wheels=$$(find build/blenderbim/wheels/*manylinux_*.whl); \
|
||||
wheels=$$(find build/bonsai/wheels/*manylinux_*.whl); \
|
||||
if [ -n "$$wheels" ]; then \
|
||||
echo "Found linux wheel files in non-linux build:"; \
|
||||
echo "$$wheels"; \
|
||||
@@ -329,26 +320,32 @@ ifneq ($(PLATFORM), linux)
|
||||
fi
|
||||
endif
|
||||
|
||||
$(PYTHON) scripts/get_wheels.py build/blenderbim/wheels build/blenderbim/blender_manifest.toml
|
||||
rm -rf build/blenderbim/bim/
|
||||
rm -rf build/blenderbim/core/
|
||||
rm -rf build/blenderbim/tool/
|
||||
$(PYTHON) scripts/get_wheels.py build/bonsai/wheels build/bonsai/blender_manifest.toml
|
||||
rm -rf build/bonsai/bim/
|
||||
rm -rf build/bonsai/core/
|
||||
rm -rf build/bonsai/tool/
|
||||
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
cd build && zip -r blenderbim_$(PYVERSION)-$(VERSION)-$(BLENDER_PLATFORM).zip ./blenderbim
|
||||
cd build && zip -r bonsai_$(PYVERSION)-$(VERSION)-$(BLENDER_PLATFORM).zip ./bonsai
|
||||
else
|
||||
cd build && zip -r blenderbim_$(PYVERSION)-$(VERSION)-alpha$(VERSION_DATE)-$(BLENDER_PLATFORM).zip ./blenderbim
|
||||
cd build && zip -r bonsai_$(PYVERSION)-$(VERSION)-alpha$(VERSION_DATE)-$(BLENDER_PLATFORM).zip ./bonsai
|
||||
endif
|
||||
|
||||
mv build/blenderbim*.zip dist/
|
||||
mv build/bonsai*.zip dist/
|
||||
|
||||
rm -rf build
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
make test-core
|
||||
make test-tool
|
||||
make test-bim
|
||||
@echo "Running all tests..."
|
||||
@ERROR=0; \
|
||||
make test-core || ERROR=1; \
|
||||
make test-tool || ERROR=1; \
|
||||
make test-bim || ERROR=1; \
|
||||
if [ $$ERROR -ne 0 ]; then \
|
||||
echo "One or more tests failed"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
.PHONY: test-core
|
||||
test-core:
|
||||
@@ -377,13 +374,13 @@ qa:
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
coverage run --source blenderbim.core -m pytest -p no:pytest-blender test/core
|
||||
coverage run --source bonsai.core -m pytest -p no:pytest-blender test/core
|
||||
coverage html
|
||||
xdg-open htmlcov/index.html
|
||||
|
||||
.PHONY: license
|
||||
license:
|
||||
copyright-header --license GPL3 --copyright-holder "Dion Moult <dion@thinkmoult.com>" --copyright-year "2022" --copyright-software "BlenderBIM Add-on" --copyright-software-description "OpenBIM Blender Add-on" -a ./ -o ./
|
||||
copyright-header --license GPL3 --copyright-holder "Dion Moult <dion@thinkmoult.com>" --copyright-year "2022" --copyright-software "Bonsai" --copyright-software-description "OpenBIM Blender Add-on" -a ./ -o ./
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@@ -0,0 +1,5 @@
|
||||
# Bonsai
|
||||
|
||||
An add-on to Blender to allow BIM functionality.
|
||||
|
||||
More information on the [Bonsai website](https://bonsaibim.org).
|
||||
@@ -1,25 +1,25 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# 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.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Ensure we don't try to import bpy or blenderbim.bim
|
||||
# Ensure we don't try to import bpy or bonsai.bim
|
||||
# to support running core tests.
|
||||
# We assume if bpy was never loaded in current python session
|
||||
# then we're not in Blender. It's still possible to use
|
||||
@@ -51,10 +51,10 @@ def get_last_commit_hash() -> Union[str, None]:
|
||||
return last_commit_hash[:7]
|
||||
|
||||
|
||||
# Accessed from blenderbim extension:
|
||||
# Accessed from bonsai extension:
|
||||
bbim_semver: dict[str, Any] = {}
|
||||
|
||||
# Accessed from blenderbim dependency:
|
||||
# Accessed from bonsai dependency:
|
||||
last_error = None
|
||||
last_actions: deque = deque(maxlen=10)
|
||||
FIRST_INSTALLED_BBIM_VERSION: Union[str, None] = None
|
||||
@@ -82,9 +82,6 @@ def initialize_bbim_semver():
|
||||
bbim_semver["version"] = version_str
|
||||
|
||||
|
||||
initialize_bbim_semver()
|
||||
|
||||
|
||||
def get_debug_info():
|
||||
bbim_version = bbim_semver["version"]
|
||||
|
||||
@@ -96,8 +93,8 @@ def get_debug_info():
|
||||
"machine": platform.machine(),
|
||||
"processor": platform.processor(),
|
||||
"blender_version": bpy.app.version_string,
|
||||
"blenderbim_version": bbim_version,
|
||||
"blenderbim_commit_hash": get_last_commit_hash(),
|
||||
"bonsai_version": bbim_version,
|
||||
"bonsai_commit_hash": get_last_commit_hash(),
|
||||
"last_actions": last_actions,
|
||||
"last_error": last_error,
|
||||
}
|
||||
@@ -129,7 +126,7 @@ def safe_link_dlls() -> None:
|
||||
# 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 BlenderBIM to never use it again, temporary directory won't be cleared.
|
||||
# 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
|
||||
@@ -177,6 +174,7 @@ def clean_up_dlls_safe_links() -> None:
|
||||
|
||||
|
||||
if IN_BLENDER:
|
||||
initialize_bbim_semver()
|
||||
|
||||
def get_binary_info() -> dict[str, Any]:
|
||||
info = {}
|
||||
@@ -214,7 +212,7 @@ if IN_BLENDER:
|
||||
try:
|
||||
import git
|
||||
|
||||
# We can't just use __file__ as blenderbim/__init__.py is typically not symlinked
|
||||
# We can't just use __file__ as bonsai/__init__.py is typically not symlinked
|
||||
# as Blender have errors symlinking main addon package file.
|
||||
path = Path(__file__).resolve().parent
|
||||
repo = git.Repo(str(path), search_parent_directories=True)
|
||||
@@ -240,23 +238,23 @@ if IN_BLENDER:
|
||||
if platform.system() == "Windows":
|
||||
clean_up_dlls_safe_links()
|
||||
|
||||
import blenderbim.bim
|
||||
import bonsai.bim
|
||||
|
||||
current_version = bbim_semver["version"]
|
||||
if blenderbim.FIRST_INSTALLED_BBIM_VERSION is None:
|
||||
blenderbim.FIRST_INSTALLED_BBIM_VERSION = current_version
|
||||
elif not blenderbim.REINSTALLED_BBIM_VERSION and blenderbim.FIRST_INSTALLED_BBIM_VERSION != current_version:
|
||||
blenderbim.REINSTALLED_BBIM_VERSION = current_version
|
||||
if bonsai.FIRST_INSTALLED_BBIM_VERSION is None:
|
||||
bonsai.FIRST_INSTALLED_BBIM_VERSION = current_version
|
||||
elif not bonsai.REINSTALLED_BBIM_VERSION and bonsai.FIRST_INSTALLED_BBIM_VERSION != current_version:
|
||||
bonsai.REINSTALLED_BBIM_VERSION = current_version
|
||||
|
||||
blenderbim.bim.register()
|
||||
bonsai.bim.register()
|
||||
|
||||
def unregister():
|
||||
if platform.system() == "Windows":
|
||||
safe_link_dlls()
|
||||
|
||||
import blenderbim.bim
|
||||
import bonsai.bim
|
||||
|
||||
blenderbim.bim.unregister()
|
||||
bonsai.bim.unregister()
|
||||
|
||||
except:
|
||||
|
||||
@@ -278,10 +276,10 @@ if IN_BLENDER:
|
||||
|
||||
print(last_error)
|
||||
print(format_debug_info(get_debug_info()))
|
||||
print("\nFATAL ERROR: Unable to load the BlenderBIM Add-on")
|
||||
print("\nFATAL ERROR: Unable to load Bonsai")
|
||||
|
||||
class BIM_PT_fatal_error(bpy.types.Panel):
|
||||
bl_label = "BlenderBIM Fatal Error"
|
||||
bl_label = "Bonsai Fatal Error"
|
||||
bl_idname = "SCENE_PT_error_message"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
@@ -292,7 +290,7 @@ if IN_BLENDER:
|
||||
|
||||
layout = self.layout
|
||||
layout.alert = True
|
||||
layout.label(text="BlenderBIM could not load.", icon="ERROR")
|
||||
layout.label(text="Bonsai could not load.", icon="ERROR")
|
||||
if info["os"] == "Windows":
|
||||
layout.operator("wm.console_toggle", text="View the console for full logs.", icon="CONSOLE")
|
||||
else:
|
||||
@@ -302,10 +300,10 @@ if IN_BLENDER:
|
||||
b3d = ".".join(info["blender_version"].split(".")[0:2])
|
||||
box.label(text="System Information:")
|
||||
box.label(text=f"Blender {b3d} {info['os']} {info['machine']}", icon="BLENDER")
|
||||
blenderbim_version = info["blenderbim_version"]
|
||||
if commit_hash := info.get("blenderbim_commit_hash"):
|
||||
blenderbim_version += f"-{commit_hash}"
|
||||
box.label(text=f"Python {py} BBIM {info['blenderbim_version']}", icon="SCRIPTPLUGINS")
|
||||
bonsai_version = info["bonsai_version"]
|
||||
if commit_hash := info.get("bonsai_commit_hash"):
|
||||
bonsai_version += f"-{commit_hash}"
|
||||
box.label(text=f"Python {py} BBIM {info['bonsai_version']}", icon="SCRIPTPLUGINS")
|
||||
|
||||
binary_py = get_binary_info().get("binary_python_version")
|
||||
if binary_py and py != binary_py:
|
||||
@@ -313,7 +311,7 @@ if IN_BLENDER:
|
||||
# From wrong-platform-build issues we're guarded by Blender extension installation.
|
||||
# But Blender currently doesn't support separate builds for different Python version,
|
||||
# so those issues might still slip in.
|
||||
box.label(text="BlenderBIM installed for wrong Python version.")
|
||||
box.label(text="Bonsai installed for wrong Python version.")
|
||||
box.label(text=f"Expected: {py}. Got: {binary_py}.")
|
||||
# On reinstallation, dependencies versions doesn't change, so Blender will just ignore new dependencies.
|
||||
# So, we need to make user will disable an extension (just uninstallation won't remove dependencies).
|
||||
@@ -321,16 +319,16 @@ if IN_BLENDER:
|
||||
# as dependencies failed to load due to Python version mismatch.
|
||||
box.label(text="Try reinstalling with the correct Python version.")
|
||||
box.label(text="Before reinstallation make sure to")
|
||||
box.label(text="DISABLE BlenderBIM (uninstallation won't help).")
|
||||
box.label(text="DISABLE Bonsai (uninstallation won't help).")
|
||||
box.label(text="You can download correct version below.")
|
||||
|
||||
layout.operator("bim.copy_debug_information", text="Copy Error Message To Clipboard")
|
||||
op = layout.operator("bim.open_uri", text="How Can I Fix This?")
|
||||
op.uri = "https://docs.blenderbim.org/users/troubleshooting.html#installation-issues"
|
||||
op.uri = "https://docs.bonsaibim.org/users/troubleshooting.html#installation-issues"
|
||||
|
||||
layout.label(text="Try Reinstalling:", icon="IMPORT")
|
||||
op = layout.operator("bim.open_uri", text="Re-download Add-on")
|
||||
bbim_version = info["blenderbim_version"]
|
||||
bbim_version = info["bonsai_version"]
|
||||
py_tag = py.replace(".", "")
|
||||
if "Linux" in info["os"]:
|
||||
os = "linux-x64"
|
||||
@@ -341,7 +339,7 @@ if IN_BLENDER:
|
||||
os = "macos-x64"
|
||||
else:
|
||||
os = "windows-x64"
|
||||
op.uri = f"https://github.com/IfcOpenShell/IfcOpenShell/releases/download/blenderbim-{bbim_version}/blenderbim_py{py_tag}-{bbim_version}-{os}.zip"
|
||||
op.uri = f"https://github.com/IfcOpenShell/IfcOpenShell/releases/download/bonsai-{bbim_version}/bonsai_py{py_tag}-{bbim_version}-{os}.zip"
|
||||
|
||||
class OpenUri(bpy.types.Operator):
|
||||
bl_idname = "bim.open_uri"
|
||||
@@ -1,20 +1,20 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Bonsai - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
# This file is part of Bonsai.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# 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.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import bpy
|
||||
@@ -25,7 +25,7 @@ from . import handler, ui, prop, operator, helper
|
||||
from typing import Callable, Union
|
||||
|
||||
try:
|
||||
from blenderbim.translations import translations_dict
|
||||
from bonsai.translations import translations_dict
|
||||
except ImportError:
|
||||
translations_dict = {}
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
@@ -91,18 +91,19 @@ modules = {
|
||||
|
||||
|
||||
for name in modules.keys():
|
||||
modules[name] = importlib.import_module(f"blenderbim.bim.module.{name}")
|
||||
modules[name] = importlib.import_module(f"bonsai.bim.module.{name}")
|
||||
|
||||
|
||||
classes = [
|
||||
operator.AddIfcFile,
|
||||
operator.BIM_OT_add_section_plane,
|
||||
operator.BIM_OT_delete_object,
|
||||
operator.BIM_OT_open_webbrowser,
|
||||
operator.BIM_OT_remove_section_plane,
|
||||
operator.BIM_OT_select_object,
|
||||
operator.BIM_OT_show_description,
|
||||
operator.BIM_OT_multiple_file_selector,
|
||||
operator.ClippingPlaneCutWithCappings,
|
||||
operator.CloseBlendWarning,
|
||||
operator.CloseError,
|
||||
operator.EditBlenderCollection,
|
||||
operator.FileAssociate,
|
||||
@@ -121,6 +122,7 @@ classes = [
|
||||
prop.StrProperty,
|
||||
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
|
||||
prop.ObjProperty,
|
||||
prop.MultipleFileSelect,
|
||||
prop.Attribute,
|
||||
prop.BIMAreaProperties,
|
||||
prop.BIMTabProperties,
|
||||
@@ -252,7 +254,7 @@ def register():
|
||||
icon_preview.load(icon_name, icon_path, "IMAGE")
|
||||
|
||||
icons = icon_preview
|
||||
bpy.app.translations.register("blenderbim", translations_dict)
|
||||
bpy.app.translations.register("bonsai", translations_dict)
|
||||
|
||||
|
||||
def unregister():
|
||||
@@ -289,10 +291,10 @@ def unregister():
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
import blenderbim.tool as tool
|
||||
import bonsai.tool as tool
|
||||
|
||||
# use tuple() as method will be removing keys from dict
|
||||
for panel in tuple(original_scene_panels_polls.keys()):
|
||||
tool.Blender.remove_scene_panel_override(panel)
|
||||
|
||||
bpy.app.translations.unregister("blenderbim")
|
||||
bpy.app.translations.unregister("bonsai")
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
* Bonsai - OpenBIM Blender Add-on
|
||||
* Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
*
|
||||
* This file is part of BlenderBIM Add-on.
|
||||
* This file is part of Bonsai.
|
||||
*
|
||||
* BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
* 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.
|
||||
*
|
||||
* BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
* 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
* long with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
* { stroke-linecap: round; stroke-linejoin: round; }
|
||||
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
* Bonsai - OpenBIM Blender Add-on
|
||||
* Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
*
|
||||
* This file is part of BlenderBIM Add-on.
|
||||
* This file is part of Bonsai.
|
||||
*
|
||||
* BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
* 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.
|
||||
*
|
||||
* BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
* 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
* long with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.cut { fill: white; stroke: black; stroke-linecap: 'round'; stroke-width: 0.35; }
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
* BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
* Bonsai - OpenBIM Blender Add-on
|
||||
* Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
*
|
||||
* This file is part of BlenderBIM Add-on.
|
||||
* This file is part of Bonsai.
|
||||
*
|
||||
* BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
* 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.
|
||||
*
|
||||
* BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
* 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 BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
* long with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -43,3 +43,9 @@
|
||||
}
|
||||
|
||||
text, tspan { /* 2.5mm */ fill: black; stroke: none; font-family: 'OpenGost Type B TT', 'DejaVu Sans Condensed', 'Liberation Sans', 'Arial Narrow', 'Arial'; }
|
||||
|
||||
.border {
|
||||
stroke: #000000;
|
||||
stroke-width:.125;
|
||||
fill: none; /* will be overriden if background color is set in .ods, or .xlsx */
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
@@ -5,8 +5,8 @@ FILE_NAME('/dev/null','2024-03-03T16:03:58+11:00',(),(),'IfcOpenShell v0.7.0-eaa
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROJECT('3NJUxHyTzEv96oezyDYEqf',$,'BlenderBIM Demo',$,$,$,$,(#12,#16),#7);
|
||||
#2=IFCPROJECTLIBRARY('0D39k7hbT5ce$jWaCd2niG',$,'BlenderBIM Demo Library',$,$,$,$,$,$);
|
||||
#1=IFCPROJECT('3NJUxHyTzEv96oezyDYEqf',$,'Bonsai Demo',$,$,$,$,(#12,#16),#7);
|
||||
#2=IFCPROJECTLIBRARY('0D39k7hbT5ce$jWaCd2niG',$,'Bonsai Demo Library',$,$,$,$,$,$);
|
||||
#3=IFCRELDECLARES('2RWVohyP57PBHT9zCs4H2O',$,$,$,#1,(#2));
|
||||
#4=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
|
||||
#5=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
|
||||