mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-28 07:49:59 +00:00
Compare commits
392 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| ec29e3d60b | |||
| 70bc32b3df | |||
| ca781655b0 | |||
| 03e2cb70bb | |||
| 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 | |||
| 153a71f91e | |||
| ae7b1bb9b4 | |||
| 6f70196a6c | |||
| 228bbc30ad | |||
| f83a7ac730 | |||
| fad4ea82a7 | |||
| a252b459a2 | |||
| 9ac159e0af | |||
| 74fbf29d5f | |||
| 1fef4c5857 | |||
| e7b791f4a2 | |||
| a6286293d8 | |||
| bddb8d1e56 | |||
| d51fa2c5f7 | |||
| e4afcc96d1 | |||
| 5f94a84616 | |||
| a883e9f490 | |||
| 74db3fcbbe | |||
| d7b85d1264 | |||
| 455fe740c7 | |||
| eac4e80ee9 | |||
| 33e188b321 | |||
| 59a3c019a4 | |||
| 30ab2f1e48 | |||
| aae160b568 | |||
| c4d3dad639 | |||
| adbf9093d3 | |||
| c8defbb77f | |||
| a14fc0a7f5 | |||
| 91f4427bb5 | |||
| 8d2717d25b | |||
| 8b29e50f11 | |||
| 7edd1225c0 | |||
| 075a0c79e2 | |||
| a1c4221cd7 | |||
| dc197a2ae2 | |||
| 5fab630a8b | |||
| b021dbf55e | |||
| d3bcd2f73e | |||
| 3d4c85c7dc | |||
| adde772014 | |||
| 59579fd4c4 | |||
| 0dde4102bc | |||
| b988df9e1f | |||
| 390b280442 | |||
| 9776adee86 | |||
| 06c8a9ef14 | |||
| 9713cc0c2e | |||
| dda010b130 | |||
| 4122f22ee1 | |||
| e833b0aa81 | |||
| 975b215bd0 | |||
| 276c4b871e | |||
| 8e6d13242e | |||
| c852e624e9 | |||
| ad17a610eb | |||
| 6b4c695942 | |||
| 61dfb42cee | |||
| 386caab840 | |||
| f50bbf9704 | |||
| 4912e86e6e | |||
| b0fe30c597 | |||
| 84d4bf16c3 | |||
| 7851efd0c8 | |||
| 500587f267 | |||
| 6defdc63b5 | |||
| 216b3a4e37 | |||
| 4e79384c8e | |||
| f7a3b0706b | |||
| 5d4a3d504c | |||
| 96b4ad8cd3 | |||
| 54131b3fe5 | |||
| 93fe2e9b0f | |||
| a7e856c311 | |||
| 1fbdb4811d | |||
| 797e3e8d8c | |||
| 4c53881242 | |||
| 44fc5768af | |||
| ffbade0f7a | |||
| 1ca6c489b1 | |||
| 845b3e0f6b | |||
| 51e9626809 | |||
| 1d12f54c36 | |||
| 1281eb4aea | |||
| c0f2ac592e | |||
| 41f1d66fee | |||
| aa31436c67 | |||
| e95e92356f | |||
| e27980f746 | |||
| 3f3f3b6aff | |||
| 2b3035ec02 | |||
| cc0760d505 | |||
| f683fd220f | |||
| 889d3c5451 | |||
| c16cfc8afd | |||
| 4d698deb21 | |||
| 3bbe598dff | |||
| e88bd3af80 | |||
| a428ae5c86 | |||
| 05e202059e | |||
| ab97f23b47 | |||
| 4f0a65baea | |||
| e88abd881d | |||
| d6d5dbfaa3 | |||
| 3ea1f95fcf | |||
| 48026c7a50 | |||
| 8f2e8ec64d | |||
| 15945d854a | |||
| f69c42aaae | |||
| b88e35e3e7 | |||
| 6befa2dc12 | |||
| c25bb03a9c | |||
| 4fdf8145f0 | |||
| bb910e42ab | |||
| 13dce9d663 | |||
| bda69555f6 | |||
| e50f88a91c | |||
| fc7288b9e7 | |||
| 1355f3ab6b | |||
| d60c03b632 | |||
| b39020ce74 | |||
| cb23b00913 | |||
| 268ab107e2 | |||
| 734b4901fd | |||
| 0ecc3d3e2a | |||
| 237cd99e3b | |||
| 31acd0a39b | |||
| 7fb04c7d8f | |||
| ad05434777 | |||
| 99cb50d365 | |||
| d29a201814 | |||
| fb702afee6 | |||
| 657906a2dd | |||
| 5b96b4a414 | |||
| 30623ba333 | |||
| 34652aa2b7 | |||
| e7fd06a6d6 | |||
| f0077b9e22 | |||
| 71aa30a25f | |||
| d96f960313 | |||
| 5a2a809061 | |||
| 2710148276 | |||
| 7ff1c535e5 | |||
| 71575905cb | |||
| 56573160d1 | |||
| 49555eb81e | |||
| 9ed286660e | |||
| 3d2dfdf9cb | |||
| c3d4847b29 | |||
| 9bf68db080 | |||
| 798cc6069f | |||
| 0efa36940c | |||
| 6fbb1a286c | |||
| 7c606fea9b | |||
| ae97350e64 | |||
| 3e7dbcaeb6 | |||
| 4ad426a5c5 | |||
| eeb200a19d | |||
| 766eb75e3a | |||
| 607f79f2f5 | |||
| 70f252988a | |||
| f956545743 | |||
| 6f8aac96f0 | |||
| a2018a22a6 | |||
| 7a10edbd73 | |||
| 669b0b8c83 | |||
| 70336f179d | |||
| 7fc7a73db8 | |||
| 41065f77d1 | |||
| 010f854a07 | |||
| c0635afb64 | |||
| dedbf7014a | |||
| d8cf6ca4fc | |||
| f1ab63dda9 | |||
| 3a5c3d856a | |||
| 54fe0f8ff9 | |||
| 483516a902 | |||
| 83085ba3c1 | |||
| 215866cf30 | |||
| 09d5fafdf8 | |||
| 54cc4192bd | |||
| eff778d5be | |||
| 66877c227b | |||
| 7e117bca90 | |||
| 9f084558f6 | |||
| c715d9a81b | |||
| 8923d02f68 | |||
| 447a13b6e7 | |||
| 2531a58083 | |||
| 70ae0fd850 | |||
| 174749caf7 | |||
| dd8ec95fad | |||
| 0a791a3b85 | |||
| 1c91b966b5 | |||
| db6cda2816 | |||
| d6dab75653 | |||
| 0dc084d785 | |||
| 3bafea62f4 | |||
| 69b7658196 | |||
| 9e93f22e53 | |||
| 94bcb8d266 | |||
| bbd4e00972 | |||
| 16e8c504f3 | |||
| 95c457f53d | |||
| 38f5b77f92 | |||
| 4f1a36753c | |||
| 565a0edb73 | |||
| 54a65abd76 | |||
| 5b16699eb4 | |||
| b4482780cf | |||
| 589b9d4a79 | |||
| 04365053a8 | |||
| c79e490d6d | |||
| b674b8ca58 | |||
| f56bae141b | |||
| 8579c61ab6 | |||
| 5440445cbc | |||
| e28b4d40ab | |||
| a6940d2cba | |||
| 9f14769cba | |||
| 585eeb283a | |||
| 3a6c3a8312 | |||
| 86fa24aba3 | |||
| 474d8381ab | |||
| feea42f988 | |||
| 88d3152f04 | |||
| 515bfd1beb | |||
| 472e2f8e59 | |||
| 83a0d7a63c | |||
| 4e78de6ce9 | |||
| 670bf9d4a6 | |||
| ad1183dab8 | |||
| a1568641b0 | |||
| 76a6ad6596 | |||
| 355cca3679 | |||
| 7e1eadf54c | |||
| a2dead2dd7 | |||
| 220fb13eec | |||
| 7c1c139074 | |||
| 3a3421897c | |||
| b34d10bd35 | |||
| 8e86b3d1d8 | |||
| acf135a6ed | |||
| 7c1459b83e | |||
| dd561d3703 | |||
| 24c4858570 | |||
| 9690bfb1ed | |||
| fd48f70ef1 | |||
| c33c19c483 | |||
| c9989c5f8f | |||
| d996811306 | |||
| 10b5910654 | |||
| ee5b3d1775 | |||
| b45a995bb3 | |||
| fc45e587c0 | |||
| c18e4ea6ce | |||
| ff662fdfcf | |||
| f075b0ca52 | |||
| a3844fe098 | |||
| d00e60369b | |||
| 22b7027746 | |||
| 410fff6ee9 | |||
| 9d11f8a25b | |||
| 95f71a2e2f | |||
| accb1890dc | |||
| 2a808318bf | |||
| 24d1a2ee64 | |||
| 1d59edcbe8 | |||
| 8a9ca9ac60 | |||
| 7a89d8f5ed | |||
| a6951d1a6d | |||
| 1cdd4c27fc | |||
| 7acea25fdf | |||
| 2510e4e6c4 | |||
| d0f4c25c9f | |||
| 0557ff810a | |||
| fdaf059c60 | |||
| 79f96d22a5 | |||
| 31e7cd7a8c | |||
| 6b274535c6 | |||
| 410767921d | |||
| 78dd4856eb | |||
| 166e75db3f | |||
| 01c7be2b48 | |||
| d05e30b4c5 | |||
| 4f44bde9e9 | |||
| bd50276e7d | |||
| 58b132136d | |||
| bd8988a474 | |||
| c0216efffe | |||
| 25e964788c | |||
| 52d9cbff28 | |||
| 1eb9537d58 | |||
| 24c753a09d | |||
| b5a130263a | |||
| 13a1252c77 | |||
| f338f66b4b | |||
| a782812911 | |||
| 10f96d873a | |||
| 09a2494967 | |||
| 84d58cc572 |
@@ -32,7 +32,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/bcf &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
name: ci-black-formatting
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
lint-formatting:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: psf/black@stable
|
||||
@@ -28,28 +28,17 @@ jobs:
|
||||
|
||||
build:
|
||||
needs: activate
|
||||
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
|
||||
name: "choco_release"
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py312]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
short_name: win,
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-tags: true
|
||||
- uses: actions/setup-python@v5 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.12.4' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
fetch-depth: 0
|
||||
- run: echo ${{ env.DATE }}
|
||||
|
||||
- name: Check in release tags if we should do a choco release and perform release if needed
|
||||
- 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/ &&
|
||||
|
||||
@@ -3,10 +3,10 @@ name: ci-blenderbim-daily
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.github/workflows/ci-blenderbim-matrix.yml'
|
||||
- '.github/workflows/ci-blenderbim-daily.yml'
|
||||
- 'src/blenderbim/**'
|
||||
- 'src/ifcopenshell-python/ifcopenshell/**'
|
||||
- 'src/bcf/src/bcf/**'
|
||||
- 'src/bcf/bcf/**'
|
||||
- 'src/ifcclash/ifcclash/**'
|
||||
- 'src/ifccobie/**'
|
||||
- 'src/ifcdiff/**'
|
||||
@@ -43,15 +43,15 @@ jobs:
|
||||
}
|
||||
- {
|
||||
name: "Linux Build",
|
||||
short_name: linux
|
||||
short_name: linux,
|
||||
}
|
||||
- {
|
||||
name: "MacOS Build",
|
||||
short_name: macos
|
||||
short_name: macos,
|
||||
}
|
||||
- {
|
||||
name: "MacOS ARM Build",
|
||||
short_name: macosm1
|
||||
short_name: macosm1,
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -67,15 +67,19 @@ jobs:
|
||||
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cp -r src/blenderbim src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
cd src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
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: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
asset_name: blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
release_name: "blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}} (unstable)"
|
||||
tag: "blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}"
|
||||
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,5 +1,10 @@
|
||||
name: ci-blenderbim
|
||||
|
||||
# Differences from ci-blenderbim-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
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -48,15 +53,20 @@ jobs:
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cp -r src/blenderbim src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
cd src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
cd src/blenderbim &&
|
||||
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)
|
||||
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: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blenderbim-${{steps.version.outputs.version}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
asset_name: blenderbim-${{steps.version.outputs.version}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
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}}"
|
||||
overwrite: true
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/bsdd &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifc4d &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifc5d &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifccityjson &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifcclash &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
name: ci-ifcconvert
|
||||
|
||||
on:
|
||||
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:
|
||||
config:
|
||||
- {
|
||||
name: "Windows 64bit",
|
||||
short_name: win64,
|
||||
}
|
||||
- {
|
||||
name: "Windows 32bit",
|
||||
short_name: win32,
|
||||
}
|
||||
- {
|
||||
name: "Linux 64bit",
|
||||
short_name: linux64
|
||||
}
|
||||
- {
|
||||
name: "MacOS Intel 64bit",
|
||||
short_name: macos64
|
||||
}
|
||||
- {
|
||||
name: "MacOS Silicon 64bit",
|
||||
short_name: macosm164
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
- run: echo ${{ env.DATE }}
|
||||
- name: Get current version
|
||||
id: version
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cd src/ifcopenshell-python &&
|
||||
make zip-ifcconvert PLATFORM=${{ matrix.config.short_name }}
|
||||
- name: Upload zip file to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: src/ifcopenshell-python/dist/ifcconvert-${{ steps.version.outputs.version }}-${{ matrix.config.short_name }}.zip
|
||||
asset_name: ifcconvert-${{ steps.version.outputs.version }}-${{ matrix.config.short_name }}.zip
|
||||
release_name: "ifcconvert-${{steps.version.outputs.version}}"
|
||||
tag: "ifcconvert-${{steps.version.outputs.version}}"
|
||||
overwrite: true
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifccsv &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifcdiff &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifcfm &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -90,7 +90,10 @@ jobs:
|
||||
return
|
||||
|
||||
# sort the versions in descending order
|
||||
versions = sorted(versions, reverse=True)
|
||||
print(f"Before reversal: {versions=}")
|
||||
versions.reverse()
|
||||
print(f"After reversal: {versions=}")
|
||||
|
||||
releases = versions[number_of_supported_versions:]
|
||||
|
||||
for release in releases:
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
- name: Version + date str
|
||||
id: verdate
|
||||
run: echo "verdate='${{ steps.version.outputs.version }}.${{ steps.date.outputs.date }}'" >> $GITHUB_OUTPUT
|
||||
run: echo "verdate='${{ steps.version.outputs.version }}alpha${{ steps.date.outputs.date }}'" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
test:
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
pip install build
|
||||
cp -r src/ifcopenshell-python src/ifcopenshell_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
cd src/ifcopenshell_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }} IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifcpatch &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: |
|
||||
pip install build
|
||||
cd src/ifctester &&
|
||||
make dist
|
||||
make dist IS_STABLE=TRUE
|
||||
- name: Publish a Python distribution to PyPI
|
||||
uses: ortega2247/pypi-upload-action@master
|
||||
with:
|
||||
|
||||
@@ -26,49 +26,45 @@ For more information, see:
|
||||
* [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)
|
||||
|
||||
Development is sponsored through your generous donations!
|
||||
|
||||
| Service | Status |
|
||||
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Anaconda Daily Build | [](https://anaconda.org/ifcopenshell/ifcopenshell) |
|
||||
| Anaconda v0.8.0 Stable | [](https://anaconda.org/conda-forge/ifcopenshell) |
|
||||
| PyPi Daily Build | [](https://pypi.org/project/ifcopenshell/) |
|
||||
| ArchLinux AUR Package Stable | [](https://aur.archlinux.org/packages/ifcopenshell) |
|
||||
| ArchLinux AUR Package git | [](https://aur.archlinux.org/packages/ifcopenshell-git) |
|
||||
| BlenderBIM Add-on Chocolatey (under moderation) | [](https://community.chocolatey.org/packages/blenderbim-nightly/) |
|
||||
| Sponsor development on OpenCollective | [](https://opencollective.com/opensourcebim/) |
|
||||
| Docker hub | [](https://hub.docker.com/r/aecgeeks/ifcopenshell) |
|
||||
[](https://opencollective.com/opensourcebim/)
|
||||
|
||||
Contents
|
||||
--------
|
||||
|
||||
Those marked with an asterisk are part of IfcOpenShell.
|
||||
| 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/) |
|
||||
| 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/) |
|
||||
| ifc5d | Report and optimise cost information from IFC | LGPL-3.0-or-later | [](https://pypi.org/project/ifc5d/) |
|
||||
| ifcbimtester | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later |
|
||||
| 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) [](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://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/) |
|
||||
|
||||
The IfcOpenShell C++ codebase is split into multiple interal libraries:
|
||||
|
||||
| Name | Description | License |
|
||||
| ------------------------- | --------------------------------------------------------------------- | ------------------- |
|
||||
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later |
|
||||
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later |
|
||||
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later |
|
||||
| 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 |
|
||||
| ifc5d | Report and optimise cost information from IFC | LGPL-3.0-or-later |
|
||||
| ifcbimtester | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later |
|
||||
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later\* |
|
||||
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later |
|
||||
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later |
|
||||
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* |
|
||||
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later |
|
||||
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later |
|
||||
| ifcfm | Extract IFC data for FM handover requirements | LGPL-3.0-or-later |
|
||||
| ifcgeom | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| ifcgeom\_schema\_agnostic | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| ifcgeomserver | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| ifcjni | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| ifcmax | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later\* |
|
||||
| ifcopenshell-python | Python library for IFC manipulation | LGPL-3.0-or-later\* |
|
||||
| ifcparse | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| ifcpatch | Utility to run pre-packaged scripts to manipulate IFCs | LGPL-3.0-or-later |
|
||||
| ifcsverchok | Blender Add-on for visual node programming with IFC | GPL-3.0-or-later |
|
||||
| ifctester | Library, CLI and webapp for IDS model auditing | LGPL-3.0-or-later |
|
||||
| ifcwrap | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| qtviewer | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
| serializers | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import datetime
|
||||
import os
|
||||
|
||||
|
||||
def get_repo_tag_names():
|
||||
git_return = os.popen("git tag -l").read()
|
||||
return [tag_name for tag_name in git_return.split("\n") if tag_name]
|
||||
|
||||
|
||||
def set_github_env_var(key: str, value: str):
|
||||
env_file_path = os.getenv('GITHUB_ENV')
|
||||
with open(env_file_path, "a") as env_file:
|
||||
_ = env_file.write(f"{key}={value}" + "\n")
|
||||
|
||||
|
||||
blenderbim_date_yesterday = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%y%m%d")
|
||||
|
||||
for tag_name in get_repo_tag_names():
|
||||
if blenderbim_date_yesterday in tag_name:
|
||||
set_github_env_var(key="choco_release", value="do_choco_release")
|
||||
set_github_env_var(key="target_release_tag", value=tag_name)
|
||||
print("do_choco_release", end="")
|
||||
break
|
||||
@@ -1,78 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from urllib import request
|
||||
|
||||
|
||||
def request_repo_info(url: str):
|
||||
req = request.Request(url)
|
||||
resp = request.urlopen(req)
|
||||
if not resp.status == 200:
|
||||
print(f"[ERROR] could not contact server: {url}")
|
||||
quit(1)
|
||||
return resp
|
||||
|
||||
|
||||
def get_choco_package_info() -> str:
|
||||
resp = request_repo_info(URL_CHOCO_PACKAGE)
|
||||
html_txt = str(resp.read())
|
||||
return html_txt
|
||||
|
||||
|
||||
def get_latest_blender_version() -> list:
|
||||
html_txt = get_choco_package_info()
|
||||
return re.findall(RE_BLENDER_VERSION_MIN_MAJ_PAT, html_txt)
|
||||
|
||||
|
||||
URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
|
||||
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
|
||||
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+)\)"
|
||||
|
||||
|
||||
if sys.argv[1] == "--latest_blender_release_maj_min_pat?":
|
||||
latest_blender_version = get_latest_blender_version()
|
||||
if latest_blender_version:
|
||||
print(latest_blender_version[0], end="")
|
||||
else:
|
||||
print("[ERROR] could not determine blender_version_min_maj_pat")
|
||||
quit(1)
|
||||
|
||||
|
||||
elif sys.argv[1] == "--latest_blender_release_maj_min?":
|
||||
html_txt = get_choco_package_info()
|
||||
blender_version_min_maj = re.findall(RE_BLENDER_VERSION_MIN_MAJ, html_txt)
|
||||
if blender_version_min_maj:
|
||||
print(blender_version_min_maj[0], end="")
|
||||
else:
|
||||
print("[ERROR] could not determine blender_version_min_maj")
|
||||
quit(1)
|
||||
|
||||
|
||||
elif sys.argv[1] == "--latest_blender_python_version_maj_min?":
|
||||
latest_blender_version = get_latest_blender_version()
|
||||
if latest_blender_version:
|
||||
latest_blender_version_tag = f"v{latest_blender_version[0]}"
|
||||
resp = request_repo_info(URL_BLENDER_CMAKE.format(latest_blender_version_tag))
|
||||
html_txt = str(resp.read())
|
||||
found = re.findall(RE_BLENDER_PYTHON_VERSION_MAJ_MIN, html_txt)
|
||||
if found:
|
||||
print(found[0], end="")
|
||||
else:
|
||||
print("[ERROR] could not determine blender_python_version_maj_min")
|
||||
quit(1)
|
||||
|
||||
|
||||
elif sys.argv[1] == "--pyver?":
|
||||
latest_blender_version = get_latest_blender_version()
|
||||
if latest_blender_version:
|
||||
latest_blender_version_tag = f"v{latest_blender_version[0]}"
|
||||
resp = request_repo_info(URL_BLENDER_CMAKE.format(latest_blender_version_tag))
|
||||
html_txt = str(resp.read())
|
||||
found = re.findall(RE_BLENDER_PYTHON_VERSION_MAJ_MIN, html_txt)
|
||||
if found:
|
||||
print(f"py{found[0].replace('.', '')}", end="")
|
||||
else:
|
||||
print("[ERROR] could not determine pyver")
|
||||
quit(1)
|
||||
@@ -127,7 +127,7 @@ print(f"{blender_python_version_maj_min=}")
|
||||
python_version = f"py{found[0].replace('.', '')}"
|
||||
print(f"{python_version=}")
|
||||
|
||||
blenderbim_build_version = f"0.0.{blenderbim_date_yesterday}"
|
||||
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"
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
print("[INFO] inserting dynamic chocolatey package parameters")
|
||||
HERE_DIR = Path(__file__).parent.absolute()
|
||||
# print(f"[INFO] HERE_DIR: {HERE_DIR}")
|
||||
|
||||
topics = {
|
||||
"spec": {
|
||||
"path": HERE_DIR / "blenderbim.nuspec",
|
||||
"env_vars": {
|
||||
"latest_blender_version_maj_min_pat",
|
||||
"blenderbim_build_version",
|
||||
},
|
||||
},
|
||||
"install": {
|
||||
"path": HERE_DIR / "tools" / "chocolateyinstall.ps1",
|
||||
"env_vars": {
|
||||
"url_blenderbim_py3x_win_zip",
|
||||
"sha256sum_blenderbim_py3x_win_zip",
|
||||
"latest_blender_version_maj_min",
|
||||
},
|
||||
},
|
||||
"uninstall": {
|
||||
"path": HERE_DIR / "tools" / "chocolateyuninstall.ps1",
|
||||
"env_vars": {
|
||||
"latest_blender_version_maj_min",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for topic, info in topics.items():
|
||||
print(f"[INFO] {topic}:")
|
||||
for env_var_name in info["env_vars"]:
|
||||
print(f"[INFO] {env_var_name} exists?: {os.environ[env_var_name]}")
|
||||
|
||||
with open(info["path"], encoding="utf-8") as txt:
|
||||
content = txt.read()
|
||||
|
||||
for env_var_name in info["env_vars"]:
|
||||
# print(f"[INFO] replace: {env_var_name}")
|
||||
content = content.replace(env_var_name, os.environ[env_var_name])
|
||||
|
||||
with open(info["path"], "w", encoding="utf-8") as txt:
|
||||
txt.write(content)
|
||||
print(f"[INFO] written: {info['path']}")
|
||||
|
||||
print("[INFO] inserting dynamic chocolatey package parameters successful")
|
||||
+2
-1
@@ -53,6 +53,7 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import glob
|
||||
import subprocess as sp
|
||||
import shutil
|
||||
import tarfile
|
||||
@@ -971,7 +972,7 @@ if "IfcOpenShell-Python" in targets:
|
||||
if platform.system() != "Darwin":
|
||||
if BUILD_CFG == "Release":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", glob.glob(os.path.join(module_dir, "_ifcopenshell_wrapper*.so"))[0]], cwd=module_dir)
|
||||
|
||||
return module_dir
|
||||
|
||||
|
||||
@@ -1,5 +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/ifcopenshell-python/ifcopenshell/mvd/*
|
||||
|src/ifc2ca/templates/*
|
||||
'''
|
||||
|
||||
[tool.pyright]
|
||||
reportInvalidTypeForm = false
|
||||
|
||||
+2
-16
@@ -16,11 +16,8 @@
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
VERSION:=$(shell cat ../../VERSION)
|
||||
SED:=sed -i
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
SED:=sed -i '' -e
|
||||
endif
|
||||
PACKAGE_NAME:=bcf
|
||||
include ../common.mk
|
||||
|
||||
.PHONY: ci
|
||||
ci:
|
||||
@@ -36,17 +33,6 @@ 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
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
rm -rf dist
|
||||
cp pyproject.toml pyproject.toml.bak
|
||||
cp src/bcf/__init__.py __init__.py.bak
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' pyproject.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' src/bcf/__init__.py
|
||||
python -m build
|
||||
mv pyproject.toml.bak pyproject.toml
|
||||
mv __init__.py.bak src/bcf/__init__.py
|
||||
|
||||
# .PHONY
|
||||
# api:
|
||||
# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0
|
||||
|
||||
@@ -18,6 +18,7 @@ GNU Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with BCF. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union
|
||||
@@ -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.
|
||||
|
||||
@@ -5,6 +5,7 @@ Copyright (c) 2017-2020 Anthon van der Neut, Ruamel bvba
|
||||
|
||||
original idea from https://stackoverflow.com/a/19722365/1307905
|
||||
"""
|
||||
|
||||
import zipfile
|
||||
from io import BytesIO
|
||||
from os import PathLike
|
||||
@@ -13,8 +14,7 @@ from typing import Any, Optional, Protocol
|
||||
|
||||
|
||||
class ZipFileInterface(Protocol):
|
||||
def writestr(self, filename_in_zip: str | zipfile.ZipInfo, file_contents: bytes | str) -> None:
|
||||
...
|
||||
def writestr(self, filename_in_zip: str | zipfile.ZipInfo, file_contents: bytes | str) -> None: ...
|
||||
|
||||
|
||||
class InMemoryZipFile:
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML V2 handler."""
|
||||
|
||||
import uuid
|
||||
import warnings
|
||||
import zipfile
|
||||
@@ -34,7 +34,7 @@ class BimSnippet:
|
||||
metadata={
|
||||
"name": "isExternal",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class HeaderFile:
|
||||
"name": "Filename",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
date: Optional[XmlDateTime] = field(
|
||||
default=None,
|
||||
@@ -72,7 +72,7 @@ class HeaderFile:
|
||||
"name": "Date",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
reference: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -80,7 +80,7 @@ class HeaderFile:
|
||||
"name": "Reference",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
ifc_project: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -89,7 +89,7 @@ class HeaderFile:
|
||||
"type": "Attribute",
|
||||
"length": 22,
|
||||
"pattern": r"[0-9,A-Z,a-z,_$]*",
|
||||
}
|
||||
},
|
||||
)
|
||||
ifc_spatial_structure_element: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -98,14 +98,14 @@ class HeaderFile:
|
||||
"type": "Attribute",
|
||||
"length": 22,
|
||||
"pattern": r"[0-9,A-Z,a-z,_$]*",
|
||||
}
|
||||
},
|
||||
)
|
||||
is_external: bool = field(
|
||||
default=True,
|
||||
metadata={
|
||||
"name": "isExternal",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ class TopicDocumentReference:
|
||||
"name": "ReferencedDocument",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
description: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -128,7 +128,7 @@ class TopicDocumentReference:
|
||||
"name": "Description",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -136,14 +136,14 @@ class TopicDocumentReference:
|
||||
"name": "Guid",
|
||||
"type": "Attribute",
|
||||
"pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}",
|
||||
}
|
||||
},
|
||||
)
|
||||
is_external: bool = field(
|
||||
default=False,
|
||||
metadata={
|
||||
"name": "isExternal",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class ViewPoint:
|
||||
"name": "Viewpoint",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
snapshot: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -178,7 +178,7 @@ class ViewPoint:
|
||||
"name": "Snapshot",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
index: Optional[int] = field(
|
||||
default=None,
|
||||
@@ -186,7 +186,7 @@ class ViewPoint:
|
||||
"name": "Index",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -230,7 +230,7 @@ class Comment:
|
||||
"name": "Viewpoint",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
modified_date: Optional[XmlDateTime] = field(
|
||||
default=None,
|
||||
@@ -238,7 +238,7 @@ class Comment:
|
||||
"name": "ModifiedDate",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
modified_author: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -246,7 +246,7 @@ class Comment:
|
||||
"name": "ModifiedAuthor",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -267,7 +267,7 @@ class Header:
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ class Topic:
|
||||
"name": "ReferenceLink",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
title: str = field(
|
||||
metadata={
|
||||
@@ -295,7 +295,7 @@ class Topic:
|
||||
"name": "Priority",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
index: Optional[int] = field(
|
||||
default=None,
|
||||
@@ -303,7 +303,7 @@ class Topic:
|
||||
"name": "Index",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
labels: List[str] = field(
|
||||
default_factory=list,
|
||||
@@ -311,7 +311,7 @@ class Topic:
|
||||
"name": "Labels",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
creation_date: XmlDateTime = field(
|
||||
metadata={
|
||||
@@ -335,7 +335,7 @@ class Topic:
|
||||
"name": "ModifiedDate",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
modified_author: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -343,7 +343,7 @@ class Topic:
|
||||
"name": "ModifiedAuthor",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
due_date: Optional[XmlDateTime] = field(
|
||||
default=None,
|
||||
@@ -351,7 +351,7 @@ class Topic:
|
||||
"name": "DueDate",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
assigned_to: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -359,7 +359,7 @@ class Topic:
|
||||
"name": "AssignedTo",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
stage: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -367,7 +367,7 @@ class Topic:
|
||||
"name": "Stage",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
description: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -375,7 +375,7 @@ class Topic:
|
||||
"name": "Description",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
bim_snippet: Optional[BimSnippet] = field(
|
||||
default=None,
|
||||
@@ -383,7 +383,7 @@ class Topic:
|
||||
"name": "BimSnippet",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
document_reference: List[TopicDocumentReference] = field(
|
||||
default_factory=list,
|
||||
@@ -391,7 +391,7 @@ class Topic:
|
||||
"name": "DocumentReference",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
related_topic: List[TopicRelatedTopic] = field(
|
||||
default_factory=list,
|
||||
@@ -399,7 +399,7 @@ class Topic:
|
||||
"name": "RelatedTopic",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -414,14 +414,14 @@ class Topic:
|
||||
metadata={
|
||||
"name": "TopicType",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
topic_status: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "TopicStatus",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ class Markup:
|
||||
"name": "Header",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
topic: Topic = field(
|
||||
metadata={
|
||||
@@ -449,7 +449,7 @@ class Markup:
|
||||
"name": "Comment",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
viewpoints: List[ViewPoint] = field(
|
||||
default_factory=list,
|
||||
@@ -457,5 +457,5 @@ class Markup:
|
||||
"name": "Viewpoints",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -10,7 +10,7 @@ class Project:
|
||||
"name": "Name",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
project_id: str = field(
|
||||
metadata={
|
||||
@@ -29,7 +29,7 @@ class ProjectExtension:
|
||||
"name": "Project",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
extension_schema: str = field(
|
||||
metadata={
|
||||
@@ -10,12 +10,12 @@ class Version:
|
||||
"name": "DetailedVersion",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
version_id: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "VersionId",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -15,14 +15,14 @@ class Component:
|
||||
metadata={
|
||||
"name": "OriginatingSystem",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
authoring_tool_id: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "AuthoringToolId",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
ifc_guid: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -31,7 +31,7 @@ class Component:
|
||||
"type": "Attribute",
|
||||
"length": 22,
|
||||
"pattern": r"[0-9,A-Z,a-z,_$]*",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -92,21 +92,21 @@ class ViewSetupHints:
|
||||
metadata={
|
||||
"name": "SpacesVisible",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
space_boundaries_visible: Optional[bool] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "SpaceBoundariesVisible",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
openings_visible: Optional[bool] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "OpeningsVisible",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ class ComponentColoringColor:
|
||||
"name": "Component",
|
||||
"type": "Element",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
color: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -147,7 +147,7 @@ class ComponentColoringColor:
|
||||
"name": "Color",
|
||||
"type": "Attribute",
|
||||
"pattern": r"[0-9,a-f,A-F]{6}([0-9,a-f,A-F]{2})?",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ class ComponentSelection:
|
||||
"name": "Component",
|
||||
"type": "Element",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ class ComponentVisibilityExceptions:
|
||||
"name": "Component",
|
||||
"type": "Element",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -205,6 +205,7 @@ class OrthogonalCamera:
|
||||
camera_up_vector:
|
||||
view_to_world_scale: view's visible size in meters
|
||||
"""
|
||||
|
||||
camera_view_point: Point = field(
|
||||
metadata={
|
||||
"name": "CameraViewPoint",
|
||||
@@ -247,6 +248,7 @@ class PerspectiveCamera:
|
||||
release and viewers should be expect values outside this
|
||||
range in current implementations.
|
||||
"""
|
||||
|
||||
camera_view_point: Point = field(
|
||||
metadata={
|
||||
"name": "CameraViewPoint",
|
||||
@@ -336,7 +338,7 @@ class ComponentColoring:
|
||||
"name": "Color",
|
||||
"type": "Element",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -347,14 +349,14 @@ class ComponentVisibility:
|
||||
metadata={
|
||||
"name": "Exceptions",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
default_visibility: Optional[bool] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "DefaultVisibility",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -368,7 +370,7 @@ class VisualizationInfoClippingPlanes:
|
||||
metadata={
|
||||
"name": "ClippingPlane",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -383,7 +385,7 @@ class VisualizationInfoLines:
|
||||
"name": "Line",
|
||||
"type": "Element",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -394,14 +396,14 @@ class Components:
|
||||
metadata={
|
||||
"name": "ViewSetupHints",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
selection: Optional[ComponentSelection] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Selection",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
visibility: ComponentVisibility = field(
|
||||
metadata={
|
||||
@@ -415,7 +417,7 @@ class Components:
|
||||
metadata={
|
||||
"name": "Coloring",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -424,47 +426,48 @@ class VisualizationInfo:
|
||||
"""
|
||||
VisualizationInfo documentation.
|
||||
"""
|
||||
|
||||
components: Optional[Components] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Components",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
orthogonal_camera: Optional[OrthogonalCamera] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "OrthogonalCamera",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
perspective_camera: Optional[PerspectiveCamera] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "PerspectiveCamera",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
lines: Optional[VisualizationInfoLines] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Lines",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
clipping_planes: Optional[VisualizationInfoClippingPlanes] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "ClippingPlanes",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
bitmap: List[VisualizationInfoBitmap] = field(
|
||||
default_factory=list,
|
||||
metadata={
|
||||
"name": "Bitmap",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML V2 Topic handler."""
|
||||
|
||||
import datetime
|
||||
import tempfile
|
||||
import uuid
|
||||
@@ -277,7 +278,7 @@ 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) -> None:
|
||||
"""Add a viewpoint pointing at an XYZ point in space
|
||||
|
||||
Args:
|
||||
@@ -176,7 +176,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":
|
||||
@@ -224,7 +224,7 @@ 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.
|
||||
|
||||
@@ -261,7 +261,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 +275,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.
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML V3 handlers."""
|
||||
|
||||
import uuid
|
||||
import warnings
|
||||
import zipfile
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML V3 Documents handler."""
|
||||
|
||||
import zipfile
|
||||
from typing import Any, Optional
|
||||
|
||||
@@ -22,7 +22,7 @@ class Document:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -45,7 +45,7 @@ class DocumentInfoDocuments:
|
||||
"name": "Document",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -57,5 +57,5 @@ class DocumentInfo:
|
||||
"name": "Documents",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -15,7 +15,7 @@ class ExtensionsPriorities:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class ExtensionsSnippetTypes:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ class ExtensionsStages:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ class ExtensionsTopicLabels:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class ExtensionsTopicStatuses:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ class ExtensionsTopicTypes:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ class ExtensionsUsers:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ class Extensions:
|
||||
"name": "TopicTypes",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
topic_statuses: Optional[ExtensionsTopicStatuses] = field(
|
||||
default=None,
|
||||
@@ -137,7 +137,7 @@ class Extensions:
|
||||
"name": "TopicStatuses",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
priorities: Optional[ExtensionsPriorities] = field(
|
||||
default=None,
|
||||
@@ -145,7 +145,7 @@ class Extensions:
|
||||
"name": "Priorities",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
topic_labels: Optional[ExtensionsTopicLabels] = field(
|
||||
default=None,
|
||||
@@ -153,7 +153,7 @@ class Extensions:
|
||||
"name": "TopicLabels",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
users: Optional[ExtensionsUsers] = field(
|
||||
default=None,
|
||||
@@ -161,7 +161,7 @@ class Extensions:
|
||||
"name": "Users",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
snippet_types: Optional[ExtensionsSnippetTypes] = field(
|
||||
default=None,
|
||||
@@ -169,7 +169,7 @@ class Extensions:
|
||||
"name": "SnippetTypes",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
stages: Optional[ExtensionsStages] = field(
|
||||
default=None,
|
||||
@@ -177,5 +177,5 @@ class Extensions:
|
||||
"name": "Stages",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -40,7 +40,7 @@ class BimSnippet:
|
||||
metadata={
|
||||
"name": "IsExternal",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class DocumentReference:
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
"pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}",
|
||||
}
|
||||
},
|
||||
)
|
||||
url: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -78,7 +78,7 @@ class DocumentReference:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
description: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -88,7 +88,7 @@ class DocumentReference:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -110,7 +110,7 @@ class File:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
date: Optional[XmlDateTime] = field(
|
||||
default=None,
|
||||
@@ -118,7 +118,7 @@ class File:
|
||||
"name": "Date",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
reference: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -128,7 +128,7 @@ class File:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
ifc_project: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -137,7 +137,7 @@ class File:
|
||||
"type": "Attribute",
|
||||
"length": 22,
|
||||
"pattern": r"[0-9A-Za-z_$]*",
|
||||
}
|
||||
},
|
||||
)
|
||||
ifc_spatial_structure_element: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -146,14 +146,14 @@ class File:
|
||||
"type": "Attribute",
|
||||
"length": 22,
|
||||
"pattern": r"[0-9A-Za-z_$]*",
|
||||
}
|
||||
},
|
||||
)
|
||||
is_external: bool = field(
|
||||
default=True,
|
||||
metadata={
|
||||
"name": "IsExternal",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ class TopicLabels:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ class TopicReferenceLinks:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ class ViewPoint:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
snapshot: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -226,7 +226,7 @@ class ViewPoint:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
index: Optional[int] = field(
|
||||
default=None,
|
||||
@@ -234,7 +234,7 @@ class ViewPoint:
|
||||
"name": "Index",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -274,7 +274,7 @@ class Comment:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
viewpoint: Optional[CommentViewpoint] = field(
|
||||
default=None,
|
||||
@@ -282,7 +282,7 @@ class Comment:
|
||||
"name": "Viewpoint",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
modified_date: Optional[XmlDateTime] = field(
|
||||
default=None,
|
||||
@@ -290,7 +290,7 @@ class Comment:
|
||||
"name": "ModifiedDate",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
modified_author: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -300,7 +300,7 @@ class Comment:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -323,7 +323,7 @@ class HeaderFiles:
|
||||
"name": "File",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ class TopicDocumentReferences:
|
||||
"name": "DocumentReference",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ class TopicRelatedTopics:
|
||||
"name": "RelatedTopic",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -368,7 +368,7 @@ class TopicViewpoints:
|
||||
"name": "ViewPoint",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -380,7 +380,7 @@ class Header:
|
||||
"name": "Files",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -395,7 +395,7 @@ class TopicComments:
|
||||
"name": "Comment",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -407,7 +407,7 @@ class Topic:
|
||||
"name": "ReferenceLinks",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
title: str = field(
|
||||
metadata={
|
||||
@@ -427,7 +427,7 @@ class Topic:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
index: Optional[int] = field(
|
||||
default=None,
|
||||
@@ -435,7 +435,7 @@ class Topic:
|
||||
"name": "Index",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
labels: Optional[TopicLabels] = field(
|
||||
default=None,
|
||||
@@ -443,7 +443,7 @@ class Topic:
|
||||
"name": "Labels",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
creation_date: XmlDateTime = field(
|
||||
metadata={
|
||||
@@ -469,7 +469,7 @@ class Topic:
|
||||
"name": "ModifiedDate",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
modified_author: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -479,7 +479,7 @@ class Topic:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
due_date: Optional[XmlDateTime] = field(
|
||||
default=None,
|
||||
@@ -487,7 +487,7 @@ class Topic:
|
||||
"name": "DueDate",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
assigned_to: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -497,7 +497,7 @@ class Topic:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
stage: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -507,7 +507,7 @@ class Topic:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
description: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -517,7 +517,7 @@ class Topic:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
bim_snippet: Optional[BimSnippet] = field(
|
||||
default=None,
|
||||
@@ -525,7 +525,7 @@ class Topic:
|
||||
"name": "BimSnippet",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
document_references: Optional[TopicDocumentReferences] = field(
|
||||
default=None,
|
||||
@@ -533,7 +533,7 @@ class Topic:
|
||||
"name": "DocumentReferences",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
related_topics: Optional[TopicRelatedTopics] = field(
|
||||
default=None,
|
||||
@@ -541,7 +541,7 @@ class Topic:
|
||||
"name": "RelatedTopics",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
comments: Optional[TopicComments] = field(
|
||||
default=None,
|
||||
@@ -549,7 +549,7 @@ class Topic:
|
||||
"name": "Comments",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
viewpoints: Optional[TopicViewpoints] = field(
|
||||
default=None,
|
||||
@@ -557,7 +557,7 @@ class Topic:
|
||||
"name": "Viewpoints",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -574,7 +574,7 @@ class Topic:
|
||||
"type": "Attribute",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
topic_type: str = field(
|
||||
metadata={
|
||||
@@ -604,7 +604,7 @@ class Markup:
|
||||
"name": "Header",
|
||||
"type": "Element",
|
||||
"namespace": "",
|
||||
}
|
||||
},
|
||||
)
|
||||
topic: Topic = field(
|
||||
metadata={
|
||||
@@ -12,7 +12,7 @@ class Project:
|
||||
"namespace": "",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
project_id: str = field(
|
||||
metadata={
|
||||
@@ -17,7 +17,7 @@ class Component:
|
||||
"type": "Element",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
authoring_tool_id: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -26,7 +26,7 @@ class Component:
|
||||
"type": "Element",
|
||||
"min_length": 1,
|
||||
"white_space": "collapse",
|
||||
}
|
||||
},
|
||||
)
|
||||
ifc_guid: Optional[str] = field(
|
||||
default=None,
|
||||
@@ -35,7 +35,7 @@ class Component:
|
||||
"type": "Attribute",
|
||||
"length": 22,
|
||||
"pattern": r"[0-9A-Za-z_$]*",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -96,21 +96,21 @@ class ViewSetupHints:
|
||||
metadata={
|
||||
"name": "SpacesVisible",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
space_boundaries_visible: bool = field(
|
||||
default=False,
|
||||
metadata={
|
||||
"name": "SpaceBoundariesVisible",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
openings_visible: bool = field(
|
||||
default=False,
|
||||
metadata={
|
||||
"name": "OpeningsVisible",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ class ComponentColoringColorComponents:
|
||||
"name": "Component",
|
||||
"type": "Element",
|
||||
"min_occurs": 1,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ class ComponentSelection:
|
||||
metadata={
|
||||
"name": "Component",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ class ComponentVisibilityExceptions:
|
||||
metadata={
|
||||
"name": "Component",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -249,6 +249,7 @@ class OrthogonalCamera:
|
||||
aspect_ratio: Proportional relationship between the width and
|
||||
the height of the view (w/h).
|
||||
"""
|
||||
|
||||
camera_view_point: Point = field(
|
||||
metadata={
|
||||
"name": "CameraViewPoint",
|
||||
@@ -302,6 +303,7 @@ class PerspectiveCamera:
|
||||
aspect_ratio: Proportional relationship between the width and
|
||||
the height of the view (w/h).
|
||||
"""
|
||||
|
||||
camera_view_point: Point = field(
|
||||
metadata={
|
||||
"name": "CameraViewPoint",
|
||||
@@ -371,21 +373,21 @@ class ComponentVisibility:
|
||||
metadata={
|
||||
"name": "ViewSetupHints",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
exceptions: Optional[ComponentVisibilityExceptions] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Exceptions",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
default_visibility: bool = field(
|
||||
default=False,
|
||||
metadata={
|
||||
"name": "DefaultVisibility",
|
||||
"type": "Attribute",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -399,7 +401,7 @@ class VisualizationInfoBitmaps:
|
||||
metadata={
|
||||
"name": "Bitmap",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -413,7 +415,7 @@ class VisualizationInfoClippingPlanes:
|
||||
metadata={
|
||||
"name": "ClippingPlane",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -427,7 +429,7 @@ class VisualizationInfoLines:
|
||||
metadata={
|
||||
"name": "Line",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -438,7 +440,7 @@ class ComponentColoring:
|
||||
metadata={
|
||||
"name": "Color",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -449,21 +451,21 @@ class Components:
|
||||
metadata={
|
||||
"name": "Selection",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
visibility: Optional[ComponentVisibility] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Visibility",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
coloring: Optional[ComponentColoring] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Coloring",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -472,47 +474,48 @@ class VisualizationInfo:
|
||||
"""
|
||||
VisualizationInfo documentation.
|
||||
"""
|
||||
|
||||
components: Optional[Components] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Components",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
orthogonal_camera: Optional[OrthogonalCamera] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "OrthogonalCamera",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
perspective_camera: Optional[PerspectiveCamera] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "PerspectiveCamera",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
lines: Optional[VisualizationInfoLines] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Lines",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
clipping_planes: Optional[VisualizationInfoClippingPlanes] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "ClippingPlanes",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
bitmaps: Optional[VisualizationInfoBitmaps] = field(
|
||||
default=None,
|
||||
metadata={
|
||||
"name": "Bitmaps",
|
||||
"type": "Element",
|
||||
}
|
||||
},
|
||||
)
|
||||
guid: str = field(
|
||||
metadata={
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML V3 Topic handler."""
|
||||
|
||||
import datetime
|
||||
import uuid
|
||||
import zipfile
|
||||
@@ -174,7 +175,7 @@ class TopicHandler:
|
||||
new_viewpoint = VisualizationInfoHandler.create_new(element, self._xml_handler)
|
||||
self.add_visinfo_handler(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) -> None:
|
||||
"""
|
||||
Add a viewpoint tergeting an IFC element to the topic.
|
||||
|
||||
@@ -175,7 +175,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":
|
||||
@@ -218,7 +218,7 @@ 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.
|
||||
|
||||
@@ -255,7 +255,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 +269,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.
|
||||
@@ -1,4 +1,5 @@
|
||||
"""XML Parser and Serializer factories."""
|
||||
|
||||
from typing import Optional, Protocol, Type, TypeVar
|
||||
|
||||
from xsdata.formats.dataclass.context import XmlContext
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML tests."""
|
||||
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""BCF XML tests."""
|
||||
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
+229
-185
@@ -20,8 +20,12 @@ PYTHON:=python3.11
|
||||
PIP:=pip3.11
|
||||
PATCH:=patch
|
||||
SED:=sed -i
|
||||
VENV_ACTIVATE:=bin/activate
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
HOSTOS:=win
|
||||
PYTHON:=python
|
||||
VENV_ACTIVATE:=Scripts/activate
|
||||
else
|
||||
UNAME_S:=$(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
@@ -68,238 +72,278 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM), linux)
|
||||
PYPI_PLATFORM:=--platform manylinux_2_17_x86_64
|
||||
BLENDER_PLATFORM:=linux-x64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macos)
|
||||
PYPI_PLATFORM:=--platform macosx_10_10_x86_64
|
||||
BLENDER_PLATFORM:=macos-x64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
PYPI_PLATFORM:=--platform macosx_11_0_arm64
|
||||
BLENDER_PLATFORM:=macos-arm64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), win)
|
||||
PYPI_PLATFORM:=--platform win_amd64
|
||||
BLENDER_PLATFORM:=windows-x64
|
||||
endif
|
||||
|
||||
# Current build commit hash.
|
||||
OLD:=dda4dd3
|
||||
OLD:=d51fa2c
|
||||
.PHONY: bump
|
||||
bump:
|
||||
cd . && $(SED) -b "s/$(OLD)/$(NEW)/" Makefile
|
||||
cd ../ifcopenshell-python/ && $(SED) -b "s/$(OLD)/$(NEW)/" Makefile
|
||||
cd ../ifcopenshell-python/docs/ifcconvert/ && $(SED) -b "s/$(OLD)/$(NEW)/" installation.rst
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
ifndef PLATFORM
|
||||
$(error PLATFORM is not set)
|
||||
endif
|
||||
rm -rf dist
|
||||
mkdir -p dist/working
|
||||
mkdir -p dist/blenderbim
|
||||
cp -r blenderbim/* dist/blenderbim/
|
||||
rm -rf build
|
||||
mkdir -p build
|
||||
mkdir -p dist
|
||||
cp -r blenderbim build/
|
||||
|
||||
# To scope any build-time dependencies
|
||||
cd build && $(PYTHON) -m venv env && . env/$(VENV_ACTIVATE) && $(PIP) install build
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) install wheel
|
||||
|
||||
mkdir -p build/wheels
|
||||
# Provides IfcOpenShell Python functionality
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v$(VERSION)-${OLD}-$(PLATFORM)64.zip
|
||||
cd dist/working && unzip ifcopenshell-python*
|
||||
cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
|
||||
# See bug #812
|
||||
cd dist/working && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/blenderbim/occ_utils.py
|
||||
cd dist/working && mv occ_utils.py ../blenderbim/libs/site/packages/ifcopenshell/geom/occ_utils.py
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides dependencies that are part of IfcOpenShell
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/archive/refs/heads/v0.8.0.zip
|
||||
cd dist/working && unzip v0.8.0.zip
|
||||
# IfcOpenBot sometimes lags behind, so we only use its binaries
|
||||
mv dist/blenderbim/libs/site/packages/ifcopenshell/*ifcopenshell_wrapper* dist/working/
|
||||
rm -rf dist/blenderbim/libs/site/packages/ifcopenshell
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcopenshell-python/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
mv dist/working/*ifcopenshell_wrapper* dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
# Provides bcf functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/bcf/src/bcf dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCClash functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcclash/ifcclash dist/blenderbim/libs/site/packages/
|
||||
# Provides BIMTester functionality
|
||||
cd dist/working && $(PYTHON) -m venv env
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pybabel
|
||||
cd dist/working && . env/bin/activate && $(PIP) install babel
|
||||
cd dist/working && . env/bin/activate && ./env/bin/pybabel compile -d ./IfcOpenShell-0.8.0/src/ifcbimtester/bimtester/locale/
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCTester functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifctester/ifctester dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCFM functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcfm/ifcfm dist/blenderbim/libs/site/packages/
|
||||
# Provides bSDD functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/bsdd/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCDiff functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcdiff/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCSV functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifccsv/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCPatch functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcpatch/ifcpatch dist/blenderbim/libs/site/packages/
|
||||
# Provides IFC4D functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifc4d/ifc4d dist/blenderbim/libs/site/packages/
|
||||
# Provides IFC5D functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCityJSON functionality
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifccityjson dist/blenderbim/libs/site/packages/
|
||||
# Provides IfcGit functionality
|
||||
cd dist/working && . env/bin/activate && $(PIP) install GitPython --target=./site-packages
|
||||
cp -r dist/working/site-packages/smmap dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/site-packages/gitdb dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/site-packages/git dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
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 build && . env/$(VENV_ACTIVATE) && $(PIP) download GitPython --dest=./wheels
|
||||
# Provides audio playback for costing
|
||||
mkdir -p dist/working
|
||||
git clone https://github.com/Andrej730/aud.git --branch master-reduced-size --depth 1 dist/working/aud
|
||||
cd dist/working/aud && git checkout 529af208fbcb707c387bfb681d2605c0b6112de7
|
||||
cp -r dist/working/aud/aud dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
# This is a REALLY IMPORTANT feature
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) wheel git+https://github.com/Andrej730/aud.git --wheel-dir=./wheels
|
||||
# IfcOpenShell dependency - support for new typing features
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download typing_extensions --dest=./wheels
|
||||
# Required by IfcCSV
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pandas $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Pandas ships with very heavy tests
|
||||
# cd build/site-packages/pandas && rm -rf tests
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download openpyxl --dest=./wheels
|
||||
# odfpy doesn't come with its own wheel, so whee'l (get it?) create it ourselves!
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) wheel odfpy --wheel-dir=./wheels
|
||||
# Required by IFCCityJSON
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download cjio --dest=./wheels
|
||||
# Provides express rule validation for ifcopenshell.validate
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pytest --dest=./wheels
|
||||
# Provides Brickschema functionality
|
||||
# Is not platform specific but has platform specific dependencies.
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download "brickschema[persistence]==0.7.6a2" $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Required for SVG to DXF conversion
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download ezdxf $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Required by bcf
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download xsdata --dest=./wheels
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download xmlschema --dest=./wheels
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download elementpath --dest=./wheels
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download six --dest=./wheels
|
||||
# Required by drawing module
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download lxml $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Required by qto and drawing module
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download shapely $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Required by the BIM type manager thumbnail generator
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pillow $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Provides mustache templating in construction docs and web UI data
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pystache --dest=./wheels
|
||||
# Provides SVG export in construction documentation
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download svgwrite --dest=./wheels
|
||||
# Provides fuzzy date parsing for construction sequencing
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download python-dateutil --dest=./wheels
|
||||
# Provides duration parsing for construction sequencing
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download isodate --dest=./wheels
|
||||
# Provides networkx graph analysis for project dependency calculations
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download networkx --dest=./wheels
|
||||
# Required by IFCDiff
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download deepdiff --dest=./wheels
|
||||
# Required by IFCCSV and ifcopenshell.util.selector
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download lark --dest=./wheels
|
||||
# Required by IFC4D
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download PyP6Xer --dest=./wheels
|
||||
# Required by web module
|
||||
# Is not platform specific but has platform specific dependencies.
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download python-socketio[asyncio_client] $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download aiohttp $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# Required by light module
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pytz --dest=./wheels
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download tzfpy $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
# pyradiance is using different platform versions than defaults in our makefile.
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance --platform manylinux_2_35_x86_64 --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
else ifeq ($(PLATFORM), macos)
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance --platform macosx_10_13_x86_64 --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
else
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PIP) download pyradiance $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --dest=./wheels
|
||||
endif
|
||||
|
||||
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
cp dist/working/jsgantt* dist/blenderbim/bim/data/gantt/
|
||||
rm -rf dist/working
|
||||
|
||||
mkdir dist/working
|
||||
cd dist/working && $(PYTHON) -m venv env
|
||||
cd dist/working && mkdir site-packages
|
||||
# Required by IfcCSV
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pandas $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Pandas ships with very heavy tests
|
||||
cd dist/working/site-packages/pandas && rm -rf tests
|
||||
cd dist/working && . env/bin/activate && $(PIP) install openpyxl --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install odfpy --target=./site-packages
|
||||
# Required by IFCCityJSON
|
||||
cd dist/working && . env/bin/activate && $(PIP) install cjio --target=./site-packages
|
||||
# Provides express rule validation for ifcopenshell.validate
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pytest --target=./site-packages
|
||||
# Provides Brickschema functionality
|
||||
cd dist/working && . env/bin/activate && $(PIP) install "brickschema[persistence]==0.7.6a2" --target=./site-packages
|
||||
# Required for SVG to DXF conversion
|
||||
cd dist/working && . env/bin/activate && $(PIP) install ezdxf --target=./site-packages
|
||||
# Required by bcf
|
||||
cd dist/working && . env/bin/activate && $(PIP) install xsdata --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install xmlschema --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install elementpath --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install six --target=./site-packages
|
||||
# Required by drawing module
|
||||
cd dist/working && . env/bin/activate && $(PIP) install lxml $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Required by qto and drawing module
|
||||
cd dist/working && . env/bin/activate && $(PIP) install shapely $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Required by the BIM type manager thumbnail generator
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pillow $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Provides mustache templating in construction docs and web UI data
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pystache --target=./site-packages
|
||||
# Provides SVG export in construction documentation
|
||||
cd dist/working && . env/bin/activate && $(PIP) install svgwrite --target=./site-packages
|
||||
# Provides fuzzy date parsing for construction sequencing
|
||||
cd dist/working && . env/bin/activate && $(PIP) install python-dateutil --target=./site-packages
|
||||
# Provides duration parsing for construction sequencing
|
||||
cd dist/working && . env/bin/activate && $(PIP) install isodate --target=./site-packages
|
||||
# Provides networkx graph analysis for project dependency calculations
|
||||
cd dist/working && . env/bin/activate && $(PIP) install networkx --target=./site-packages
|
||||
# Required by IFCDiff
|
||||
cd dist/working && . env/bin/activate && $(PIP) install deepdiff --target=./site-packages
|
||||
# Required by IFCCSV and ifcopenshell.util.selector
|
||||
cd dist/working && . env/bin/activate && $(PIP) install lark --target=./site-packages
|
||||
# Required by IFC4D
|
||||
cd dist/working && . env/bin/activate && $(PIP) install PyP6Xer --target=./site-packages
|
||||
# Required by Web module
|
||||
cd dist/working && . env/bin/activate && $(PIP) install python-socketio[asyncio_client] --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install aiohttp --target=./site-packages
|
||||
|
||||
cp -r dist/working/site-packages/* dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by BIMTester
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/c8/4b/d0a8c23b6c8985e5544ea96d27105a273ea22051317f850c2cdbf2029fe4/behave-1.2.6.tar.gz
|
||||
cd dist/working && tar -xzvf behave*
|
||||
cd dist/working/behave-1.2.6/ && cp -r behave ../../blenderbim/libs/site/packages/
|
||||
# See bug #1294
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/ifcbimtester/patch/model_core.patch
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/ifcbimtester/patch/runner_util.patch
|
||||
cd dist/working/ && $(PATCH) ../blenderbim/libs/site/packages/behave/model_core.py < model_core.patch
|
||||
cd dist/working/ && $(PATCH) ../blenderbim/libs/site/packages/behave/runner_util.py < runner_util.patch
|
||||
# See bug #2159
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/ifcbimtester/patch/junit.patch
|
||||
cd dist/working/ && $(PATCH) ../blenderbim/libs/site/packages/behave/reporter/junit.py < junit.patch
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by behave
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/f4/65/220bb4075fddb09d5b3ea2c1c1fa66c1c72be9361ec187aab50fa161e576/parse-1.15.0.tar.gz
|
||||
cd dist/working && tar -xzvf parse*
|
||||
cd dist/working/parse-1.15.0/ && cp parse.py ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by behave
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/2e/79/81bebd1b0446d46733db99d74543b4bb80646ef4c988584bae0862e706bc/parse_type-0.5.2.tar.gz
|
||||
cd dist/working && tar -xzvf parse_type*
|
||||
cd dist/working/parse_type-0.5.2/ && cp -r parse_type ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
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
|
||||
|
||||
# Provides IFCJSON functionality
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/IFCJSON-Team/IFC2JSON_python/archive/master.zip
|
||||
cd dist/working && unzip master.zip
|
||||
cp -r dist/working/IFC2JSON_python-master/file_converters/ifcjson dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
# 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-*/file_converters && \
|
||||
$(PYTHON) -c "from setuptools import setup; \
|
||||
setup( \
|
||||
name='ifcjson', \
|
||||
version='0.0.1', \
|
||||
author='Jan Brouwer', \
|
||||
author_email='jan@brewsky.nl', \
|
||||
packages=['ifcjson'], \
|
||||
)" bdist_wheel
|
||||
cp -r build/IFC2JSON_python-*/file_converters/dist/*.whl build/wheels/
|
||||
|
||||
# Brickschema requires pkg_resources which is provided by Blender.
|
||||
# Provides Brickschema functionality
|
||||
mkdir dist/working
|
||||
# For now lets bundle the latest nightly schema
|
||||
cd dist/working && wget https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl
|
||||
cd dist/working && cp Brick.ttl ../blenderbim/bim/schema/Brick.ttl
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by brickschema
|
||||
# This is a bit of a dodgy one, it should be provided by setuptools which Blender doesn't ship.
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/raw/v0.8.0/src/blenderbim/scripts/pkg_resources.tar.gz
|
||||
cd dist/working && tar -xzvf pkg_resources*
|
||||
cd dist/working/ && cp -r pkg_resources ../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
cd build/blenderbim/bim/schema && wget https://github.com/BrickSchema/Brick/releases/download/nightly/Brick.ttl
|
||||
|
||||
# Required for hipped roof generation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/prochitecture/bpypolyskel/archive/refs/heads/master.zip
|
||||
cd dist/working && unzip master.zip
|
||||
cp -r dist/working/bpypolyskel-master/bpypolyskel dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
cd build && wget https://github.com/prochitecture/bpypolyskel/archive/refs/heads/master.zip
|
||||
cd build && unzip master.zip && rm master.zip
|
||||
cd build && . env/$(VENV_ACTIVATE) && cd bpypolyskel-master && \
|
||||
$(PYTHON) -c "from setuptools import setup; \
|
||||
setup( \
|
||||
name='bpypolyskel', \
|
||||
version='0.0.0', \
|
||||
packages=['bpypolyskel'], \
|
||||
)" bdist_wheel
|
||||
cp -r build/bpypolyskel-master/dist/*.whl build/wheels/
|
||||
|
||||
# Required for Desktop icon and file association
|
||||
cp -r blenderbim/libs/desktop dist/blenderbim/libs/
|
||||
cp -r blenderbim/libs/desktop build/blenderbim/libs/
|
||||
|
||||
# Generate translations module for BBIM build
|
||||
git clone https://github.com/IfcOpenShell/blenderbim-translations.git dist/working
|
||||
$(PYTHON) scripts/bbim_translations.py -i "dist/working" -o "dist/blenderbim"
|
||||
rm -rf dist/working
|
||||
git clone https://github.com/IfcOpenShell/blenderbim-translations.git build/working
|
||||
$(PYTHON) scripts/bbim_translations.py -i "build/working" -o "build/blenderbim"
|
||||
rm -rf build/working
|
||||
|
||||
# Remove dependencies also bundled with Blender
|
||||
rm -rf dist/blenderbim/libs/site/packages/numpy
|
||||
rm -rf dist/blenderbim/libs/site/packages/numpy.libs
|
||||
rm -rf build/wheels/numpy*
|
||||
|
||||
cp pyproject.toml build/
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) "s/0.0.0/$(VERSION)/" build/blenderbim/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/version = "0.0.0"/version = "$(VERSION)-alpha$(VERSION_DATE)"/' build/pyproject.toml
|
||||
endif
|
||||
|
||||
$(SED) "s/os-arch/$(BLENDER_PLATFORM)/" build/blenderbim/blender_manifest.toml
|
||||
|
||||
# Provides BlenderBIM Add-on functionality
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/pyproject.toml
|
||||
else
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)a$(VERSION_DATE)"/' build/pyproject.toml
|
||||
endif
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PYTHON) -m build
|
||||
cp build/dist/*.whl build/wheels/
|
||||
|
||||
# Safeguard for non-wheel dependencies slipping in.
|
||||
wheels=$$(find build/wheels/* ! -name "*.whl"); \
|
||||
if [ -n "$$wheels" ]; then \
|
||||
echo "Found non-wheel dependencies:"; \
|
||||
echo "$$wheels"; \
|
||||
echo "Error: non-wheel dependencies are not supported by Blender!"; \
|
||||
exit 1; \
|
||||
fi
|
||||
mv build/wheels/*.whl build/blenderbim/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.
|
||||
# So this hack works without working out some way to repack those wheels.
|
||||
# See: https://projects.blender.org/blender/blender/issues/125091
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
# Has universal and x86_64 builds.
|
||||
prev_whl_name=$$(find build/blenderbim/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); \
|
||||
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); \
|
||||
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); \
|
||||
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); \
|
||||
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); \
|
||||
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); \
|
||||
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); \
|
||||
if [ -n "$$wheels" ]; then \
|
||||
echo "Found universal2 wheel files:"; \
|
||||
echo "$$wheels"; \
|
||||
echo "Error: universal2 wheel files are not supported by Blender!"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
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); \
|
||||
if [ -n "$$wheels" ]; then \
|
||||
echo "Found linux wheel files in non-linux build:"; \
|
||||
echo "$$wheels"; \
|
||||
echo "Error: linux wheels are incompatible with build $(PLATFORM)!"; \
|
||||
exit 1; \
|
||||
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/
|
||||
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
cd dist/blenderbim && $(SED) "s/0, 0, 0/$(VERSION_MAJOR), $(VERSION_MINOR), $(VERSION_PATCH)/" __init__.py
|
||||
cd dist/blenderbim && $(SED) "s/0.0.0/$(VERSION)/" blender_manifest.toml
|
||||
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||
cd build && zip -r blenderbim_$(PYVERSION)-$(VERSION)-$(BLENDER_PLATFORM).zip ./blenderbim
|
||||
else
|
||||
cd dist/blenderbim && $(SED) "s/0, 0, 0/$(VERSION_MAJOR), $(VERSION_MINOR), $(VERSION_PATCH), $(VERSION_DATE)/" __init__.py
|
||||
cd dist/blenderbim && $(SED) "s/0.0.0/$(VERSION).$(VERSION_DATE)/" blender_manifest.toml
|
||||
cd dist/blenderbim/bim && $(SED) "s/8888888/$(LAST_COMMIT_HASH)/" __init__.py
|
||||
cd dist && zip -r blenderbim-$(VERSION).$(VERSION_DATE)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||
cd build && zip -r blenderbim_$(PYVERSION)-$(VERSION)-alpha$(VERSION_DATE)-$(BLENDER_PLATFORM).zip ./blenderbim
|
||||
endif
|
||||
rm -rf dist/blenderbim
|
||||
|
||||
mv build/blenderbim*.zip dist/
|
||||
|
||||
rm -rf build
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
|
||||
@@ -27,41 +27,67 @@ import sys
|
||||
IN_BLENDER = sys.modules.get("bpy", None)
|
||||
if IN_BLENDER:
|
||||
import bpy
|
||||
import addon_utils
|
||||
|
||||
import re
|
||||
import platform
|
||||
import traceback
|
||||
import webbrowser
|
||||
import uuid
|
||||
import shutil
|
||||
from collections import deque
|
||||
from pathlib import Path
|
||||
from typing import Union, Any, Generator
|
||||
|
||||
# NOTE: bl_info is superseded by blender_manifest.toml
|
||||
# if addon is installed as an extension (Blender 4.2+)
|
||||
bl_info = {
|
||||
"name": "BlenderBIM",
|
||||
"description": "Transforms Blender into a native Building Information Model authoring platform using IFC.",
|
||||
"author": "IfcOpenShell Contributors",
|
||||
"blender": (3, 1, 0),
|
||||
"version": (0, 0, 0),
|
||||
"location": "File Menu, Scene Properties Tab. See documentation for more.",
|
||||
"doc_url": "https://docs.blenderbim.org/",
|
||||
"tracker_url": "https://github.com/IfcOpenShell/IfcOpenShell/issues",
|
||||
"category": "System",
|
||||
}
|
||||
|
||||
last_commit_hash = "8888888"
|
||||
|
||||
|
||||
def get_last_commit_hash() -> Union[str, None]:
|
||||
# Using this weird way to write 8888888,
|
||||
# so makefile won't accidentally replace it here
|
||||
# we'll be able to distinguish commit hash from placeholder value.
|
||||
if last_commit_hash == str(8_888888):
|
||||
return None
|
||||
return last_commit_hash[:7]
|
||||
|
||||
|
||||
# Accessed from blenderbim extension:
|
||||
bbim_semver: dict[str, Any] = {}
|
||||
|
||||
# Accessed from blenderbim dependency:
|
||||
last_error = None
|
||||
last_actions: deque = deque(maxlen=10)
|
||||
FIRST_INSTALLED_BBIM_VERSION: Union[str, None] = None
|
||||
REINSTALLED_BBIM_VERSION: Union[str, None] = None
|
||||
|
||||
|
||||
def initialize_bbim_semver():
|
||||
"""Initialize `bbim_semver` dictionary.
|
||||
|
||||
Blender doesn't seem to store a full extension version (only major-minor-patch)
|
||||
in `addon_utils.modules()->bl_info['version']`,
|
||||
therefore we just parse it from .toml.
|
||||
"""
|
||||
import tomllib
|
||||
|
||||
toml_path = Path(__file__).parent / "blender_manifest.toml"
|
||||
with open(toml_path, "rb") as f:
|
||||
manifest = tomllib.load(f)
|
||||
semver_pattern = r"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
|
||||
version_str = manifest["version"]
|
||||
re_version = re.match(semver_pattern, version_str)
|
||||
assert re_version
|
||||
global bbim_semver
|
||||
bbim_semver = re_version.groupdict()
|
||||
bbim_semver["version"] = version_str
|
||||
|
||||
|
||||
initialize_bbim_semver()
|
||||
|
||||
|
||||
def get_debug_info():
|
||||
version = ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
bbim_version = bbim_semver["version"]
|
||||
|
||||
return {
|
||||
"os": platform.system(),
|
||||
"os_version": platform.version(),
|
||||
@@ -70,7 +96,8 @@ def get_debug_info():
|
||||
"machine": platform.machine(),
|
||||
"processor": platform.processor(),
|
||||
"blender_version": bpy.app.version_string,
|
||||
"blenderbim_version": version,
|
||||
"blenderbim_version": bbim_version,
|
||||
"blenderbim_commit_hash": get_last_commit_hash(),
|
||||
"last_actions": last_actions,
|
||||
"last_error": last_error,
|
||||
}
|
||||
@@ -87,11 +114,113 @@ def format_debug_info(info: dict):
|
||||
return text.strip()
|
||||
|
||||
|
||||
def get_binaries(path: Path) -> Generator[Path, None, None]:
|
||||
yield from path.glob("**/*.pyd")
|
||||
yield from path.glob("**/*.dll")
|
||||
# pyradiance is using .so files on windows for some reason.
|
||||
yield from path.glob("**/*.so")
|
||||
|
||||
|
||||
def safe_link_dlls() -> None:
|
||||
# Blender 4.2+ has a problem on Windows for disabling/enabling/reinstalling extensions
|
||||
# with loaded binary dependencies (on Windows you can't remove a binary if it's loaded by some program).
|
||||
# To avoid this issue we temporary hard link dlls to our temp directory on unregister()
|
||||
# (unregister is executed before Blender will try to uninstall dependencies and the issue will arise).
|
||||
# Then, Blender won't have a problem unlinking unloaded dlls as they are still linked somewhere.
|
||||
# On register() we clean up our temp directory with binaries.
|
||||
#
|
||||
# TODO: If user uninstalls BlenderBIM to never use it again, temporary directory won't be cleared.
|
||||
#
|
||||
# See: https://projects.blender.org/blender/blender/issues/125049
|
||||
import bpy
|
||||
|
||||
ext_path = Path(bpy.utils.user_resource("EXTENSIONS"))
|
||||
local_path = ext_path / ".local"
|
||||
|
||||
# We use random hash subfolder as user may try to enable/disable addon multiple times.
|
||||
random_hash = uuid.uuid4().hex[:8]
|
||||
temp_local = ext_path / ".local_temp" / random_hash
|
||||
temp_local.mkdir(parents=True)
|
||||
|
||||
for filepath in get_binaries(local_path):
|
||||
dest_path = temp_local / filepath.relative_to(local_path)
|
||||
dest_path.parent.mkdir(exist_ok=True, parents=True)
|
||||
os.link(filepath, dest_path)
|
||||
|
||||
|
||||
def clean_up_dlls_safe_links() -> None:
|
||||
import bpy
|
||||
|
||||
ext_path = Path(bpy.utils.user_resource("EXTENSIONS"))
|
||||
temp_path = ext_path / ".local_temp"
|
||||
if not temp_path.exists():
|
||||
return
|
||||
|
||||
for filepath in get_binaries(temp_path):
|
||||
try:
|
||||
os.unlink(filepath)
|
||||
except PermissionError:
|
||||
pass
|
||||
|
||||
def is_empty_directory(directory: Path) -> bool:
|
||||
return not any(directory.iterdir())
|
||||
|
||||
def remove_empty_folders(folder: Path) -> None:
|
||||
for subfolder in folder.iterdir():
|
||||
if subfolder.is_dir():
|
||||
remove_empty_folders(subfolder)
|
||||
|
||||
if is_empty_directory(folder):
|
||||
folder.rmdir()
|
||||
|
||||
remove_empty_folders(temp_path)
|
||||
|
||||
|
||||
if IN_BLENDER:
|
||||
# Process *.pth in /libs/site/packages to setup globally importable modules
|
||||
# This is 3 levels deep as required by the static RPATH of ../../ from dependencies taken from Anaconda
|
||||
# site.addsitedir(os.path.join(os.path.dirname(os.path.realpath(__file__)), "libs", "site", "packages"))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "libs", "site", "packages"))
|
||||
|
||||
def get_binary_info() -> dict[str, Any]:
|
||||
info = {}
|
||||
py_version = sys.version_info
|
||||
site_path = (
|
||||
Path(bpy.utils.user_resource("EXTENSIONS"))
|
||||
/ ".local"
|
||||
/ "lib"
|
||||
/ f"python{py_version.major}.{py_version.minor}"
|
||||
/ "site-packages"
|
||||
)
|
||||
lib = site_path / "ifcopenshell"
|
||||
binary = next((i for i in lib.glob("_ifcopenshell_wrapper.*")), None)
|
||||
if binary is None:
|
||||
info["binary_error"] = "Couldn't find ifcopenshell wrapper binary."
|
||||
return info
|
||||
|
||||
# Examples:
|
||||
# _ifcopenshell_wrapper.cp311-win_amd64.pyd
|
||||
# _ifcopenshell_wrapper.cpython-311-darwin.so
|
||||
# _ifcopenshell_wrapper.cpython-311-x86_64-linux-gnu.so
|
||||
binary = binary.name
|
||||
info["binary_file_name"] = binary
|
||||
pattern = re.compile(r"cp(\d+)|cpython-(\d+)")
|
||||
match = pattern.search(binary)
|
||||
if not match:
|
||||
info["binary_error"] = f"Couldn't parse binary version from '{binary}'."
|
||||
return info
|
||||
|
||||
version = match.group(1) or match.group(2)
|
||||
version = f"{version[0]}.{version[1:]}"
|
||||
info["binary_python_version"] = version
|
||||
return info
|
||||
|
||||
try:
|
||||
import git
|
||||
|
||||
# We can't just use __file__ as blenderbim/__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)
|
||||
last_commit_hash = repo.head.object.hexsha
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
import ifcopenshell.api
|
||||
@@ -108,24 +237,43 @@ if IN_BLENDER:
|
||||
ifcopenshell.api.add_pre_listener("*", "action_logger", log_api)
|
||||
|
||||
def register():
|
||||
global BLENDER_PACKAGE_NAME, __name__, __package__
|
||||
BLENDER_PACKAGE_NAME = __name__
|
||||
if bpy.app.version >= (4, 2, 0):
|
||||
sys.modules["blenderbim"] = sys.modules[__name__]
|
||||
__name__ = "blenderbim"
|
||||
# Only renaming __name__ is actually required to make imports work.
|
||||
# We renaming __package__ just for consistency.
|
||||
__package__ = "blenderbim"
|
||||
if platform.system() == "Windows":
|
||||
clean_up_dlls_safe_links()
|
||||
|
||||
import blenderbim.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
|
||||
|
||||
blenderbim.bim.register()
|
||||
|
||||
def unregister():
|
||||
if platform.system() == "Windows":
|
||||
safe_link_dlls()
|
||||
|
||||
import blenderbim.bim
|
||||
|
||||
blenderbim.bim.unregister()
|
||||
|
||||
except:
|
||||
|
||||
def show_scene_properties() -> None:
|
||||
# By default in Blender object properties are selected.
|
||||
# Or user may have some other properties selected in their startup file.
|
||||
# Select scene properties to ensure user will see our error handler.
|
||||
for area in bpy.context.screen.areas:
|
||||
if area.type != "PROPERTIES":
|
||||
continue
|
||||
space = area.spaces.active
|
||||
assert isinstance(space, bpy.types.SpaceProperties)
|
||||
space.context = "SCENE"
|
||||
|
||||
# Use a timer as we're not allowed to make changes to data during register().
|
||||
bpy.app.timers.register(show_scene_properties, first_interval=0.1)
|
||||
|
||||
last_error = traceback.format_exc()
|
||||
|
||||
print(last_error)
|
||||
@@ -152,26 +300,48 @@ if IN_BLENDER:
|
||||
box = layout.box()
|
||||
py = ".".join(info["python_version"].split(".")[0:2])
|
||||
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")
|
||||
|
||||
binary_py = get_binary_info().get("binary_python_version")
|
||||
if binary_py and py != binary_py:
|
||||
box.separator()
|
||||
# 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=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).
|
||||
# Blender restart doesn't seem to be required in that case
|
||||
# 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="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"
|
||||
|
||||
layout.label(text="Try Reinstalling:", icon="IMPORT")
|
||||
op = layout.operator("bim.open_uri", text="Re-download Add-on")
|
||||
bbim_date = info["blenderbim_version"].split(".")[-1]
|
||||
bbim_version = info["blenderbim_version"]
|
||||
py_tag = py.replace(".", "")
|
||||
if "Linux" in info["os"]:
|
||||
os = "linux"
|
||||
os = "linux-x64"
|
||||
elif "Darwin" in info["os"]:
|
||||
if "arm64" in info["machine"]:
|
||||
os = "macosm1"
|
||||
os = "macos-arm64"
|
||||
else:
|
||||
os = "macos"
|
||||
os = "macos-x64"
|
||||
else:
|
||||
os = "win"
|
||||
op.uri = f"https://github.com/IfcOpenShell/IfcOpenShell/releases/download/blenderbim-{bbim_date}/blenderbim-{bbim_date}-py{py_tag}-{os}.zip"
|
||||
os = "windows-x64"
|
||||
op.uri = f"https://github.com/IfcOpenShell/IfcOpenShell/releases/download/blenderbim-{bbim_version}/blenderbim_py{py_tag}-{bbim_version}-{os}.zip"
|
||||
|
||||
class OpenUri(bpy.types.Operator):
|
||||
bl_idname = "bim.open_uri"
|
||||
@@ -188,7 +358,9 @@ if IN_BLENDER:
|
||||
bl_description = "Copies debugging information to your clipboard for use in bugreports"
|
||||
|
||||
def execute(self, context):
|
||||
info = format_debug_info(get_debug_info())
|
||||
info = get_debug_info()
|
||||
info.update(get_binary_info())
|
||||
info = format_debug_info(info)
|
||||
context.window_manager.clipboard = info
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
import os
|
||||
import bpy
|
||||
import bpy.utils.previews
|
||||
import blenderbim
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from . import handler, ui, prop, operator, helper
|
||||
@@ -75,7 +74,6 @@ modules = {
|
||||
"clash": None,
|
||||
"csv": None,
|
||||
"tester": None,
|
||||
"bimtester": None,
|
||||
"diff": None,
|
||||
"patch": None,
|
||||
"gis": None,
|
||||
@@ -85,6 +83,7 @@ modules = {
|
||||
"ifcgit": None,
|
||||
"covering": None,
|
||||
"web": None,
|
||||
"light": None,
|
||||
# Uncomment this line to enable loading of the demo module. Happy hacking!
|
||||
# The name "demo" must correlate to a folder name in `bim/module/`.
|
||||
# "demo": None,
|
||||
@@ -99,10 +98,10 @@ 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.CloseError,
|
||||
operator.EditBlenderCollection,
|
||||
@@ -122,6 +121,7 @@ classes = [
|
||||
prop.StrProperty,
|
||||
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
|
||||
prop.ObjProperty,
|
||||
prop.MultipleFileSelect,
|
||||
prop.Attribute,
|
||||
prop.BIMAreaProperties,
|
||||
prop.BIMTabProperties,
|
||||
@@ -168,6 +168,8 @@ classes = [
|
||||
# Services and systems
|
||||
ui.BIM_PT_tab_services,
|
||||
ui.BIM_PT_tab_zones,
|
||||
ui.BIM_PT_tab_solar_analysis,
|
||||
ui.BIM_PT_tab_lighting,
|
||||
# Structural analysis
|
||||
ui.BIM_PT_tab_structural,
|
||||
# Construction scheduling
|
||||
@@ -195,7 +197,6 @@ for mod in modules.values():
|
||||
addon_keymaps = []
|
||||
icons = None
|
||||
is_registering = False
|
||||
last_commit_hash = "8888888"
|
||||
original_scene_panels_polls: dict[bpy.types.Panel, Union[Callable, None]] = dict()
|
||||
|
||||
|
||||
@@ -252,17 +253,6 @@ def register():
|
||||
icon_preview.load(icon_name, icon_path, "IMAGE")
|
||||
|
||||
icons = icon_preview
|
||||
|
||||
global last_commit_hash
|
||||
try:
|
||||
import git
|
||||
|
||||
path = Path(__file__).resolve().parent
|
||||
repo = git.Repo(str(path), search_parent_directories=True)
|
||||
last_commit_hash = repo.head.object.hexsha
|
||||
except:
|
||||
pass
|
||||
|
||||
bpy.app.translations.register("blenderbim", translations_dict)
|
||||
|
||||
|
||||
|
||||
@@ -67,11 +67,11 @@ DATA;
|
||||
#60=IFCMATERIALPROFILESET($,$,(#62),$);
|
||||
#61=IFCRELASSOCIATESMATERIAL('09FXUZCnrFEffxBrtg16gx',$,$,$,(#59),#60);
|
||||
#62=IFCMATERIALPROFILE($,$,#20,#58,$,$);
|
||||
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR200',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#64=IFCMATERIALLAYERSET((#66),$,$);
|
||||
#65=IFCRELASSOCIATESMATERIAL('0jzkXlkBL4HhmQ_FTWW6Cj',$,$,$,(#63),#64);
|
||||
#66=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
|
||||
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR300',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#68=IFCMATERIALLAYERSET((#70),$,$);
|
||||
#69=IFCRELASSOCIATESMATERIAL('3a6kjEM29DleYTlSkA8_DK',$,$,$,(#67),#68);
|
||||
#70=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$);
|
||||
|
||||
@@ -67,11 +67,11 @@ DATA;
|
||||
#60=IFCMATERIALPROFILESET($,$,(#62),$);
|
||||
#61=IFCRELASSOCIATESMATERIAL('09FXUZCnrFEffxBrtg16gx',$,$,$,(#59),#60);
|
||||
#62=IFCMATERIALPROFILE($,$,#20,#58,$,$);
|
||||
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR200',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#64=IFCMATERIALLAYERSET((#66),$,$);
|
||||
#65=IFCRELASSOCIATESMATERIAL('0jzkXlkBL4HhmQ_FTWW6Cj',$,$,$,(#63),#64);
|
||||
#66=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
|
||||
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR300',$,$,$,$,$,$,.NOTDEFINED.);
|
||||
#68=IFCMATERIALLAYERSET((#70),$,$);
|
||||
#69=IFCRELASSOCIATESMATERIAL('3a6kjEM29DleYTlSkA8_DK',$,$,$,(#67),#68);
|
||||
#70=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$);
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
import sys
|
||||
import os
|
||||
import webbrowser
|
||||
|
||||
blenderbim_lib_path = os.environ.get("BLENDERBIM_LIB_PATH")
|
||||
blenderbim_version = os.environ.get("BLENDERBIM_VERSION")
|
||||
|
||||
if blenderbim_lib_path:
|
||||
sys.path.insert(0, blenderbim_lib_path)
|
||||
|
||||
import argparse
|
||||
from aiohttp import web
|
||||
import socketio
|
||||
@@ -21,6 +31,8 @@ sio = socketio.AsyncServer(
|
||||
app = web.Application()
|
||||
sio.attach(app)
|
||||
|
||||
|
||||
# represents a caching for blender messages
|
||||
blender_messages = {}
|
||||
|
||||
|
||||
@@ -31,12 +43,34 @@ class WebNamespace(socketio.AsyncNamespace):
|
||||
|
||||
async def on_connect(self, sid, environ):
|
||||
print(f"Web client connected: {sid}")
|
||||
if blender_messages:
|
||||
await self.send_cached_messages(sid)
|
||||
|
||||
async def on_disconnect(self, sid):
|
||||
print(f"Web client disconnected: {sid}")
|
||||
|
||||
async def on_web_operator(self, sid, data):
|
||||
await sio.emit("web_operator", data["operator"], namespace="/blender", room=data["blenderId"])
|
||||
await sio.emit(
|
||||
"web_operator",
|
||||
data,
|
||||
namespace="/blender",
|
||||
room=data.get("blenderId", None),
|
||||
)
|
||||
|
||||
async def on_get_svg(self, sid, data):
|
||||
print("hello world!")
|
||||
file_path = data["path"]
|
||||
with open(file_path, "r") as file:
|
||||
svg_data = file.read()
|
||||
await sio.emit("svg_data", svg_data, room=sid, namespace="/web")
|
||||
|
||||
async def send_cached_messages(self, sid):
|
||||
# Send cached messages to the connected web client
|
||||
for blenderId, messages in blender_messages.items():
|
||||
if "csv_data" in messages:
|
||||
await self.emit("csv_data", {"blenderId": blenderId, "data": messages["csv_data"]}, room=sid)
|
||||
if "gantt_data" in messages:
|
||||
await self.emit("gantt_data", {"blenderId": blenderId, "data": messages["gantt_data"]}, room=sid)
|
||||
|
||||
|
||||
# Blender namespace
|
||||
@@ -60,7 +94,7 @@ class BlenderNamespace(socketio.AsyncNamespace):
|
||||
async def on_data(self, sid, data):
|
||||
print(f"Data from Blender client {sid}")
|
||||
# blender_messages[sid]["default_data"] = data
|
||||
# await sio.emit("default_data", {"blenderId": sid, "data": data}, namespace="/web")
|
||||
await sio.emit("default_data", {"blenderId": sid, "data": data}, namespace="/web")
|
||||
|
||||
async def on_csv_data(self, sid, data):
|
||||
print(f"CSV data from Blender client {sid}")
|
||||
@@ -68,6 +102,17 @@ class BlenderNamespace(socketio.AsyncNamespace):
|
||||
blender_messages[sid]["csv_data"] = data
|
||||
await sio.emit("csv_data", {"blenderId": sid, "data": data}, namespace="/web")
|
||||
|
||||
async def on_gantt_data(self, sid, data):
|
||||
print(f"Gant Chart data from Blender client {sid}")
|
||||
blender_messages[sid]["gantt_data"] = data
|
||||
await sio.emit("gantt_data", {"blenderId": sid, "data": data}, namespace="/web")
|
||||
|
||||
async def on_drawings_data(self, sid, data):
|
||||
print(f"Drawings directory from Blender client {sid}")
|
||||
print(data)
|
||||
blender_messages[sid]["drwings_data"] = data
|
||||
await sio.emit("drawings_data", {"blenderId": sid, "data": data}, namespace="/web")
|
||||
|
||||
|
||||
# Attach namespaces
|
||||
sio.register_namespace(WebNamespace("/web"))
|
||||
@@ -78,12 +123,45 @@ sio.register_namespace(BlenderNamespace("/blender"))
|
||||
async def index(request):
|
||||
with open("templates/index.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": blenderbim_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
async def gantt(request):
|
||||
with open("templates/gantt.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port, "version": blenderbim_version})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
async def drawings(request):
|
||||
with open("templates/drawings.html", "r") as f:
|
||||
template = f.read()
|
||||
html_content = pystache.render(template, {"port": sio_port})
|
||||
return web.Response(text=html_content, content_type="text/html")
|
||||
|
||||
|
||||
async def on_startup(app):
|
||||
pid_file = "running_pid.json"
|
||||
|
||||
if os.path.exists(pid_file):
|
||||
with open(pid_file, "r") as f:
|
||||
pids = json.load(f)
|
||||
else:
|
||||
pids = {}
|
||||
|
||||
pids[str(os.getpid())] = sio_port
|
||||
|
||||
with open(pid_file, "w") as f:
|
||||
json.dump(pids, f, indent=4)
|
||||
|
||||
|
||||
app.router.add_get("/", index)
|
||||
app.router.add_get("/drawings", drawings)
|
||||
app.router.add_get("/gantt", gantt)
|
||||
app.router.add_static("/jsgantt/", path="../gantt", name="jsgantt")
|
||||
app.router.add_static("/static/", path="./static", name="static")
|
||||
app.on_startup.append(on_startup)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
:root {
|
||||
--font-family: Arial, sans-serif;
|
||||
--base-font-size: 16px;
|
||||
--margin-tiny: 0.125rem;
|
||||
--margin-small: 0.625rem;
|
||||
--margin-medium: 1.25rem;
|
||||
--margin-large: 2.5rem;
|
||||
--padding-tiny: 0.125rem;
|
||||
--padding-small: 0.625rem;
|
||||
--padding-medium: 1rem;
|
||||
--font-size-large: 1.2rem;
|
||||
--logo-height: 2.5rem;
|
||||
--nav-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;
|
||||
--border-color: #464444;
|
||||
}
|
||||
|
||||
: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;
|
||||
--border-color: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--base-font-size);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
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);
|
||||
height: calc(100vh - var(--nav-height));
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: var(--nav-bg-color);
|
||||
height: var(--nav-height);
|
||||
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-tiny);
|
||||
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;
|
||||
}
|
||||
|
||||
#client-list {
|
||||
position: absolute;
|
||||
top: calc(0 + var(--nav-height));
|
||||
overflow-y: auto;
|
||||
overflow: hidden;
|
||||
transition: opacity 0.3s ease-out, visibility 0.3s ease-out;
|
||||
border: 1px solid var(--table-border-color);
|
||||
background-color: var(--nav-bg-color);
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#client-list.show {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#connected-list-div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.client {
|
||||
padding: var(--margin-small);
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.client-details {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
padding-left: var(--padding-small);
|
||||
transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out;
|
||||
background-color: var(--nav-bg-color);
|
||||
margin-top: var(--margin-tiny);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.client-details.show {
|
||||
max-height: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.client-detail {
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
padding: var(--padding-small);
|
||||
}
|
||||
|
||||
#show-connected-button {
|
||||
width: auto;
|
||||
background-color: var(--bg-color);
|
||||
border: none;
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
#show-connected-button:hover,
|
||||
.scroll-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scroll-button {
|
||||
font-size: var(--base-font-size);
|
||||
margin-left: var(--margin-tiny);
|
||||
margin-top: var(--margin-small);
|
||||
}
|
||||
|
||||
|
||||
.left {
|
||||
flex: 1;
|
||||
background-color: var(--bg-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.right {
|
||||
flex: 4;
|
||||
background-color: var(--bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
#svg-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background-color: var(--nav-bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
padding: 10px;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card-header,
|
||||
.card-body {
|
||||
background-color: var(--bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--nav-bg-color);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
li.svg-name {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#dropdown-menu:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* remove bootstrap css confilcts */
|
||||
*,
|
||||
::after,
|
||||
::before {
|
||||
box-sizing: unset;
|
||||
}
|
||||
|
||||
.btn,
|
||||
.btn:hover {
|
||||
color: var(--nav-link-hover-color);
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
:root {
|
||||
--font-family: Arial, sans-serif;
|
||||
--base-font-size: 16px;
|
||||
--margin-tiny: 0.125rem;
|
||||
--margin-small: 0.625rem;
|
||||
--margin-medium: 1.25rem;
|
||||
--margin-large: 2.5rem;
|
||||
--padding-tiny: 0.125rem;
|
||||
--padding-small: 0.625rem;
|
||||
--padding-medium: 1rem;
|
||||
--font-size-small: 1rem;
|
||||
--font-size-large: 1.2rem;
|
||||
--logo-height: 2.5rem;
|
||||
--nav-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;
|
||||
--details-border-color: #464444;
|
||||
}
|
||||
|
||||
: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;
|
||||
--details-border-color: #222;
|
||||
}
|
||||
|
||||
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);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#container {
|
||||
flex: 1;
|
||||
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-tiny);
|
||||
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;
|
||||
}
|
||||
|
||||
#client-list {
|
||||
position: absolute;
|
||||
top: calc(0 + var(--nav-height));
|
||||
overflow-y: auto;
|
||||
overflow: hidden;
|
||||
transition: opacity 0.3s ease-out, visibility 0.3s ease-out;
|
||||
border: 1px solid var(--table-border-color);
|
||||
background-color: var(--nav-bg-color);
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#client-list.show {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#connected-list-div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.client {
|
||||
padding: var(--margin-small);
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.client-details {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
padding-left: var(--padding-small);
|
||||
transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out;
|
||||
background-color: var(--nav-bg-color);
|
||||
margin-top: var(--margin-tiny);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.client-details.show {
|
||||
max-height: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.client-detail {
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
padding: var(--padding-small);
|
||||
}
|
||||
|
||||
#show-connected-button {
|
||||
width: auto;
|
||||
background-color: var(--bg-color);
|
||||
border: none;
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
#show-connected-button:hover,
|
||||
.scroll-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scroll-button {
|
||||
font-size: var(--base-font-size);
|
||||
margin-left: var(--margin-tiny);
|
||||
margin-top: var(--margin-small);
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: var(--nav-bg-color);
|
||||
text-align: right;
|
||||
padding: var(--padding-tiny);
|
||||
border-top: 1px solid var(--nav-border-color);
|
||||
}
|
||||
|
||||
footer p {
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
margin-right: var(--margin-small);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
:root {
|
||||
--font-family: Arial, sans-serif;
|
||||
--base-font-size: 16px;
|
||||
--margin-tiny: 0.125rem;
|
||||
--margin-small: 0.625rem;
|
||||
--margin-medium: 1.25rem;
|
||||
--margin-large: 2.5rem;
|
||||
--padding-tiny: 0.125rem;
|
||||
--padding-small: 0.625rem;
|
||||
--padding-medium: 1rem;
|
||||
--font-size-large: 1.2rem;
|
||||
--logo-height: 2.5rem;
|
||||
--nav-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;
|
||||
--table-border-color: #464444;
|
||||
}
|
||||
|
||||
: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;
|
||||
--table-border-color: #222;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
margin: 0;
|
||||
font-family: var(--font-family);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#container {
|
||||
flex: 1;
|
||||
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);
|
||||
height: var(--nav-height);
|
||||
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-tiny);
|
||||
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;
|
||||
}
|
||||
|
||||
#client-list {
|
||||
position: absolute;
|
||||
top: calc(0 + var(--nav-height));
|
||||
overflow-y: auto;
|
||||
overflow: hidden;
|
||||
transition: opacity 0.3s ease-out, visibility 0.3s ease-out;
|
||||
border: 1px solid var(--table-border-color);
|
||||
background-color: var(--nav-bg-color);
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#client-list.show {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#connected-list-div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.client {
|
||||
padding: var(--margin-small);
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.client-details {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
padding-left: var(--padding-small);
|
||||
transition: max-height 0.2s ease-out, padding 0.2s ease-out, opacity 0.1s ease-out;
|
||||
background-color: var(--nav-bg-color);
|
||||
margin-top: var(--margin-tiny);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.client-details.show {
|
||||
max-height: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.client-detail {
|
||||
border-bottom: 1px solid var(--table-border-color);
|
||||
padding: var(--padding-small);
|
||||
}
|
||||
|
||||
#show-connected-button {
|
||||
width: auto;
|
||||
background-color: var(--bg-color);
|
||||
border: none;
|
||||
font-size: var(--base-font-size);
|
||||
}
|
||||
|
||||
#show-connected-button:hover,
|
||||
.scroll-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.scroll-button {
|
||||
font-size: var(--base-font-size);
|
||||
margin-left: var(--margin-tiny);
|
||||
margin-top: var(--margin-small);
|
||||
}
|
||||
|
||||
footer {
|
||||
background-color: var(--nav-bg-color);
|
||||
text-align: right;
|
||||
padding: var(--padding-tiny);
|
||||
border-top: 1px solid var(--nav-border-color);
|
||||
}
|
||||
|
||||
footer p {
|
||||
margin: 0;
|
||||
color: var(--text-color);
|
||||
margin-right: var(--margin-small);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-bottom: var(--margin-large);
|
||||
}
|
||||
|
||||
.csv-table {
|
||||
margin-top: var(--margin-small);
|
||||
}
|
||||
|
||||
/* ------------ 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 var(--table-border-color);
|
||||
border-bottom: 2px solid var(--table-border-color);
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
body {
|
||||
background-color: #252525;
|
||||
color: #e0e0e0;
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
#container {
|
||||
margin-top: 20px;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 20px
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.csv-table {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
nav {
|
||||
background-color: #121212;
|
||||
padding: 1em 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
nav .logo {
|
||||
margin-left: 40px;
|
||||
height: 40px;
|
||||
/* Adjust height as needed */
|
||||
}
|
||||
|
||||
nav ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
margin-left: 1px;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
nav ul li {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
nav ul li a {
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
nav ul li a:hover,
|
||||
nav ul li a.active {
|
||||
color: #3fb449;
|
||||
}
|
||||
|
||||
nav .bottom-bar {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background-color: #25682a;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
// keeps track of blenders connected
|
||||
const connectedClients = {};
|
||||
const allDrawings = {};
|
||||
let socket;
|
||||
|
||||
// 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);
|
||||
|
||||
$("#dropdown-menu").change(function () {
|
||||
const blenderId = $(this).attr("id");
|
||||
const ifcFile = $(this).val();
|
||||
displayDrawingsNames(blenderId, ifcFile);
|
||||
});
|
||||
|
||||
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("connect", handleWebConnect);
|
||||
socket.on("drawings_data", handleDrawingsData);
|
||||
socket.on("svg_data", handleSvgData);
|
||||
// socket.on("default_data", handleDefaultData);
|
||||
}
|
||||
|
||||
// function used to get drawings data from blenderbim
|
||||
function handleWebConnect() {
|
||||
const msg = {
|
||||
sourcePage: "drawings",
|
||||
operator: {
|
||||
type: "getDrawings",
|
||||
},
|
||||
};
|
||||
socket.emit("web_operator", msg);
|
||||
}
|
||||
|
||||
// Function to handle 'blender_connect' event
|
||||
function handleBlenderConnect(blenderId) {
|
||||
console.log("blender_connect: ", blenderId);
|
||||
if (!connectedClients.hasOwnProperty(blenderId)) {
|
||||
connectedClients[blenderId] = {
|
||||
shown: false,
|
||||
ifc_file: "",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Function to handle 'blender_disconnect' event
|
||||
function handleBlenderDisconnect(blenderId) {
|
||||
console.log("blender_disconnect: ", blenderId);
|
||||
if (connectedClients.hasOwnProperty(blenderId)) {
|
||||
delete connectedClients[blenderId];
|
||||
// remove(blenderId);
|
||||
}
|
||||
|
||||
$("#blender-count").text(function (i, text) {
|
||||
return parseInt(text, 10) - 1;
|
||||
});
|
||||
}
|
||||
|
||||
function handleDrawingsData(data) {
|
||||
const blenderId = data["blenderId"];
|
||||
|
||||
console.log(data);
|
||||
|
||||
const filename = data["data"]["ifc_file"];
|
||||
const drawings = data["data"]["drawings_data"]["drawings"];
|
||||
const sheets = data["data"]["drawings_data"]["sheets"];
|
||||
|
||||
allDrawings[filename] = { drawings: drawings, sheets: sheets };
|
||||
|
||||
console.log(connectedClients);
|
||||
|
||||
if (connectedClients.hasOwnProperty(blenderId)) {
|
||||
if (!connectedClients[blenderId].shown) {
|
||||
connectedClients[blenderId] = {
|
||||
shown: true,
|
||||
ifc_file: filename,
|
||||
};
|
||||
addSelectOption(blenderId, filename);
|
||||
} else {
|
||||
// update(blenderId, data, filename);
|
||||
}
|
||||
} else {
|
||||
connectedClients[blenderId] = {
|
||||
shown: true,
|
||||
ifc_file: filename,
|
||||
};
|
||||
addSelectOption(blenderId, filename);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSvgData(data) {
|
||||
const svgContainer = document.getElementById("svg-container");
|
||||
svgContainer.innerHTML = "";
|
||||
svgContainer.style.backgroundColor = "white";
|
||||
|
||||
const dom = SVG(svgContainer).svg(data);
|
||||
const svgElement = dom.node.children[0];
|
||||
|
||||
// to make the svg not grow outside the svg container
|
||||
svgElement.setAttribute("width", "100%");
|
||||
svgElement.setAttribute("height", "100%");
|
||||
svgElement.style.maxWidth = "100%";
|
||||
svgElement.style.maxHeight = "100%";
|
||||
svgElement.style.width = "100%";
|
||||
svgElement.style.height = "100%";
|
||||
svgElement.style.boxSizing = "border-box"; // Ensure padding and borders are included in the element's total width and height
|
||||
|
||||
const panZoomControls = svgPanZoom(svgElement, {
|
||||
zoomEnabled: true,
|
||||
controlIconsEnabled: true,
|
||||
fit: true,
|
||||
center: true,
|
||||
});
|
||||
}
|
||||
|
||||
function addSelectOption(blenderId, filename) {
|
||||
const filenameOption = $("<option></option>")
|
||||
.attr("id", "blender-" + blenderId)
|
||||
.val(filename)
|
||||
.text(filename);
|
||||
$("#dropdown-menu").append(filenameOption);
|
||||
}
|
||||
|
||||
function displayDrawingsNames(blenderId, ifcFile) {
|
||||
drawings = allDrawings[ifcFile].drawings;
|
||||
sheets = allDrawings[ifcFile].sheets;
|
||||
|
||||
function createSvgNames(text, index, type) {
|
||||
var label = $("<li></lio>")
|
||||
.text(text)
|
||||
.attr("id", type + "-" + index)
|
||||
.addClass("svg-name")
|
||||
.click(function () {
|
||||
const id = $(this).attr("id").split("-");
|
||||
const index = parseInt(id[1]);
|
||||
const type = id[0];
|
||||
const ifcFile = $("#dropdown-menu").val();
|
||||
|
||||
var path = "";
|
||||
|
||||
if (type === "drawing") {
|
||||
path = allDrawings[ifcFile].drawings[index].path;
|
||||
} else if (type === "sheet") {
|
||||
path = allDrawings[ifcFile].sheets[index].path;
|
||||
}
|
||||
|
||||
const msg = {
|
||||
path: path,
|
||||
};
|
||||
console.log(msg);
|
||||
socket.emit("get_svg", msg);
|
||||
});
|
||||
|
||||
if (type === "drawing") $("#drawings-sub-panel").append(label);
|
||||
else if (type === "sheet") $("#sheets-sub-panel").append(label);
|
||||
}
|
||||
|
||||
$("#drawings-sub-panel").empty();
|
||||
drawings.forEach(function (drawing, index) {
|
||||
createSvgNames(drawing.name, index, "drawing");
|
||||
});
|
||||
|
||||
$("#sheets-sub-panel").empty();
|
||||
sheets.forEach(function (sheet, index) {
|
||||
createSvgNames(sheet.name, index, "sheet");
|
||||
});
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleClientList() {
|
||||
var clientList = $("#client-list");
|
||||
|
||||
if (clientList.hasClass("show")) {
|
||||
clientList.removeClass("show");
|
||||
return;
|
||||
}
|
||||
|
||||
clientList.empty();
|
||||
|
||||
$.each(connectedClients, function (id, client) {
|
||||
if (!client.shown) return;
|
||||
|
||||
const dropdownIcon = $("<i>")
|
||||
.addClass("fas fa-chevron-down")
|
||||
.css("margin-left", "0.5rem");
|
||||
|
||||
const clientDiv = $("<div>").addClass("client").text(client.ifc_file);
|
||||
|
||||
clientDiv.append(dropdownIcon);
|
||||
|
||||
const clientDetailsDiv = $("<div>").addClass("client-details");
|
||||
|
||||
if (id) {
|
||||
const clientId = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(`Blender ID: ${id}`);
|
||||
clientDetailsDiv.append(clientId);
|
||||
}
|
||||
|
||||
if (client.headers && client.headers.length) {
|
||||
const clientHeaders = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(`Table Headers: ${client.headers.join(", ")}`);
|
||||
|
||||
const scrollButton = $("<button>")
|
||||
.addClass("scroll-button")
|
||||
.text("Scroll to Table")
|
||||
.on("click", function () {
|
||||
$("html, body").animate(
|
||||
{
|
||||
scrollTop: $("#table-" + id).offset().top,
|
||||
},
|
||||
600
|
||||
);
|
||||
clientList.removeClass("show");
|
||||
});
|
||||
|
||||
clientDetailsDiv.append(clientHeaders);
|
||||
clientDetailsDiv.append(scrollButton);
|
||||
}
|
||||
|
||||
clientDiv.append(clientDetailsDiv);
|
||||
|
||||
clientDiv.on("click", function () {
|
||||
clientDetailsDiv.toggleClass("show");
|
||||
});
|
||||
|
||||
clientList.append(clientDiv);
|
||||
});
|
||||
clientList.addClass("show");
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
// 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);
|
||||
}
|
||||
|
||||
$("#blender-count").text(function (i, text) {
|
||||
return parseInt(text, 10) - 1;
|
||||
});
|
||||
}
|
||||
|
||||
// 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,
|
||||
ifc_file: filename,
|
||||
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,
|
||||
ifc_file: filename,
|
||||
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) {
|
||||
$("#blender-count").text(function (i, text) {
|
||||
return parseInt(text, 10) + 1;
|
||||
});
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleClientList() {
|
||||
var clientList = $("#client-list");
|
||||
|
||||
if (clientList.hasClass("show")) {
|
||||
clientList.removeClass("show");
|
||||
return;
|
||||
}
|
||||
|
||||
clientList.empty();
|
||||
|
||||
$.each(connectedClients, function (id, client) {
|
||||
if (!client.shown) return;
|
||||
|
||||
const dropdownIcon = $("<i>")
|
||||
.addClass("fas fa-chevron-down")
|
||||
.css("margin-left", "0.5rem");
|
||||
|
||||
const clientDiv = $("<div>").addClass("client").text(client.ifc_file);
|
||||
|
||||
clientDiv.append(dropdownIcon);
|
||||
|
||||
const clientDetailsDiv = $("<div>").addClass("client-details");
|
||||
|
||||
if (id) {
|
||||
const clientId = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(`Blender ID: ${id}`);
|
||||
clientDetailsDiv.append(clientId);
|
||||
}
|
||||
|
||||
if (client.workSchedule && client.gantt) {
|
||||
const clientScheduleName = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(`Schedule Name: ${client.workSchedule.Name}`);
|
||||
|
||||
const clientScheduleDate = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(
|
||||
`Schedule Date: ${new Date(
|
||||
client.workSchedule.CreationDate
|
||||
).toLocaleDateString()}`
|
||||
);
|
||||
|
||||
const scrollButton = $("<button>")
|
||||
.addClass("scroll-button")
|
||||
.text("Scroll to Gantt Chart")
|
||||
.on("click", function () {
|
||||
$("html, body").animate(
|
||||
{
|
||||
scrollTop: $("#gantt-" + id).offset().top,
|
||||
},
|
||||
600
|
||||
);
|
||||
clientList.removeClass("show");
|
||||
});
|
||||
|
||||
clientDetailsDiv.append(clientScheduleName);
|
||||
clientDetailsDiv.append(clientScheduleDate);
|
||||
clientDetailsDiv.append(scrollButton);
|
||||
}
|
||||
|
||||
clientDiv.append(clientDetailsDiv);
|
||||
|
||||
clientDiv.on("click", function () {
|
||||
clientDetailsDiv.toggleClass("show");
|
||||
});
|
||||
|
||||
clientList.append(clientDiv);
|
||||
});
|
||||
clientList.addClass("show");
|
||||
}
|
||||
@@ -5,6 +5,12 @@ let socket;
|
||||
|
||||
// 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();
|
||||
});
|
||||
|
||||
@@ -18,6 +24,7 @@ function connectSocket() {
|
||||
socket.on("blender_connect", handleBlenderConnect);
|
||||
socket.on("blender_disconnect", handleBlenderDisconnect);
|
||||
socket.on("csv_data", handleCsvData);
|
||||
socket.on("default_data", handleDefaultData);
|
||||
}
|
||||
|
||||
// Function to handle 'blender_connect' event
|
||||
@@ -35,13 +42,17 @@ function handleBlenderDisconnect(blenderId) {
|
||||
delete connectedClients[blenderId];
|
||||
removeTableElement(blenderId);
|
||||
}
|
||||
|
||||
$("#blender-count").text(function (i, text) {
|
||||
return parseInt(text, 10) - 1;
|
||||
});
|
||||
}
|
||||
|
||||
// Function to handle 'csv_data' event
|
||||
function handleCsvData(data) {
|
||||
const blenderId = data["blenderId"];
|
||||
const csvData = data["data"]["data"];
|
||||
const filename = data["data"]["IFC_File"];
|
||||
const csvData = data["data"]["csv_data"];
|
||||
const filename = data["data"]["ifc_file"];
|
||||
console.log(data);
|
||||
|
||||
if (connectedClients.hasOwnProperty(blenderId)) {
|
||||
@@ -65,8 +76,19 @@ function handleCsvData(data) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleDefaultData(data) {
|
||||
const blenderId = data["blenderId"];
|
||||
const isDirty = data["data"]["is_dirty"];
|
||||
showWarning(blenderId, isDirty);
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
// Function to add a new table with data and filename
|
||||
function addTableElement(blenderId, csvData, filename) {
|
||||
$("#blender-count").text(function (i, text) {
|
||||
return parseInt(text, 10) + 1;
|
||||
});
|
||||
|
||||
// store headers of the csv data
|
||||
const firstLine = csvData.indexOf("\n");
|
||||
const csvHeaders = csvData.substring(0, firstLine).split(",");
|
||||
@@ -82,11 +104,19 @@ function addTableElement(blenderId, csvData, filename) {
|
||||
.text(filename)
|
||||
.css("margin-bottom", "10px");
|
||||
|
||||
const warning = $("<div></div>")
|
||||
.attr("id", "warning-" + blenderId)
|
||||
.html(
|
||||
"⚠ Warning: This table may contain outdated data due to recent changes in Blender."
|
||||
)
|
||||
.addClass("warning");
|
||||
|
||||
const tableDiv = $("<div></div>")
|
||||
.addClass("csv-table")
|
||||
.attr("id", "table-" + blenderId);
|
||||
|
||||
tableContainer.append(tableTitle);
|
||||
tableContainer.append(warning);
|
||||
tableContainer.append(tableDiv);
|
||||
$("#container").append(tableContainer);
|
||||
|
||||
@@ -167,10 +197,11 @@ function addTableElement(blenderId, csvData, filename) {
|
||||
var tableId = row.getTable().element.id.substr(6);
|
||||
|
||||
const msg = {
|
||||
sourcePage: "csv",
|
||||
blenderId: tableId,
|
||||
operator: {
|
||||
type: "selection",
|
||||
GlobalId: index,
|
||||
globalId: index,
|
||||
},
|
||||
};
|
||||
socket.emit("web_operator", msg);
|
||||
@@ -198,6 +229,7 @@ function updateTableElement(blenderId, csvData, filename) {
|
||||
connectedClients[blenderId].headers = newHeaders;
|
||||
}
|
||||
$("#title-" + blenderId).text(filename);
|
||||
$("#warning-" + blenderId).css("display", "none");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,6 +238,10 @@ function removeTableElement(blenderId) {
|
||||
$("#container-" + blenderId).remove();
|
||||
}
|
||||
|
||||
function showWarning(blenderId, isDirty) {
|
||||
$("#warning-" + blenderId).css("display", "block");
|
||||
}
|
||||
|
||||
// Utility function to compare two csv header
|
||||
function compareHeaders(headers1, headers2) {
|
||||
if (headers1.length !== headers2.length) {
|
||||
@@ -218,3 +254,94 @@ function compareHeaders(headers1, headers2) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function setTheme(theme) {
|
||||
var stylesheet = $("#tabulator-stylesheet");
|
||||
if (theme === "light") {
|
||||
stylesheet.attr(
|
||||
"href",
|
||||
"https://unpkg.com/tabulator-tables/dist/css/tabulator_site.min.css"
|
||||
);
|
||||
$("html").removeClass("dark").addClass("light");
|
||||
$("#toggle-theme").html('<i class="fas fa-sun"></i>');
|
||||
} else {
|
||||
stylesheet.attr(
|
||||
"href",
|
||||
"https://unpkg.com/tabulator-tables/dist/css/tabulator_site_dark.min.css"
|
||||
);
|
||||
$("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");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleClientList() {
|
||||
var clientList = $("#client-list");
|
||||
|
||||
if (clientList.hasClass("show")) {
|
||||
clientList.removeClass("show");
|
||||
return;
|
||||
}
|
||||
|
||||
clientList.empty();
|
||||
|
||||
$.each(connectedClients, function (id, client) {
|
||||
if (!client.shown) return;
|
||||
|
||||
const dropdownIcon = $("<i>")
|
||||
.addClass("fas fa-chevron-down")
|
||||
.css("margin-left", "0.5rem");
|
||||
|
||||
const clientDiv = $("<div>").addClass("client").text(client.ifc_file);
|
||||
|
||||
clientDiv.append(dropdownIcon);
|
||||
|
||||
const clientDetailsDiv = $("<div>").addClass("client-details");
|
||||
|
||||
if (id) {
|
||||
const clientId = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(`Blender ID: ${id}`);
|
||||
clientDetailsDiv.append(clientId);
|
||||
}
|
||||
|
||||
if (client.headers && client.headers.length) {
|
||||
const clientHeaders = $("<div>")
|
||||
.addClass("client-detail")
|
||||
.text(`Table Headers: ${client.headers.join(", ")}`);
|
||||
|
||||
const scrollButton = $("<button>")
|
||||
.addClass("scroll-button")
|
||||
.text("Scroll to Table")
|
||||
.on("click", function () {
|
||||
$("html, body").animate(
|
||||
{
|
||||
scrollTop: $("#table-" + id).offset().top,
|
||||
},
|
||||
600
|
||||
);
|
||||
clientList.removeClass("show");
|
||||
});
|
||||
|
||||
clientDetailsDiv.append(clientHeaders);
|
||||
clientDetailsDiv.append(scrollButton);
|
||||
}
|
||||
|
||||
clientDiv.append(clientDetailsDiv);
|
||||
|
||||
clientDiv.on("click", function () {
|
||||
clientDetailsDiv.toggleClass("show");
|
||||
});
|
||||
|
||||
clientList.append(clientDiv);
|
||||
});
|
||||
clientList.addClass("show");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
<!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="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="/static/css/drawings.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://cdnjs.cloudflare.com/ajax/libs/svg.js/3.1.1/svg.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/svg-pan-zoom@3.6.1/dist/svg-pan-zoom.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.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/drawings.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<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">Gantt Chart</a></li>
|
||||
<li><a href="/drawings" class="active">Drawings</a></li>
|
||||
</ul>
|
||||
<button id="toggle-theme" onclick="toggleTheme()">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<div id="connected-list-div">
|
||||
<button id="show-connected-button" onclick="toggleClientList()">
|
||||
Connected Blenders:
|
||||
<span id="blender-count">0</span>
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
<div id="client-list"></div>
|
||||
</div>
|
||||
<div class="container-fluid d-flex" id="container">
|
||||
<div class="col-2 left">
|
||||
<!-- Dropdown menu -->
|
||||
<div class="dropdown mb-3">
|
||||
<label for="dropdown-menu">IFC File:</label>
|
||||
<select class="p-0 pl-2" id="dropdown-menu">
|
||||
<!-- IFC files will be dynamically populated here -->
|
||||
<option value="" selected disabled hidden>IFC File</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Panel with sub-panels -->
|
||||
<div class="panel">
|
||||
<div id="accordion">
|
||||
<div class="card pb-2">
|
||||
<div class="card-header overflow-hidden" id="headingOne">
|
||||
<button
|
||||
class="btn p-0 w-100 text-left"
|
||||
data-toggle="collapse"
|
||||
data-target="#collapseOne"
|
||||
>
|
||||
Drawings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="collapseOne" class="collapse show">
|
||||
<div class="card-body">
|
||||
<ul class="sub-panel pl-2" id="drawings-sub-panel">
|
||||
<!-- Drawings will be dynamically populated here -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card pb-2">
|
||||
<div class="card-header overflow-hidden" id="headingTwo">
|
||||
<button
|
||||
class="btn p-0 w-100 text-left"
|
||||
data-toggle="collapse"
|
||||
data-target="#collapseTwo"
|
||||
>
|
||||
Sheets
|
||||
</button>
|
||||
</div>
|
||||
<div id="collapseTwo" class="collapse show">
|
||||
<div class="card-body">
|
||||
<ul class="sub-panel pl-2" id="sheets-sub-panel">
|
||||
<!-- Sheets will be dynamically populated here -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-10 right pl-3">
|
||||
<div id="svg-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,56 @@
|
||||
<!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>
|
||||
<li><a href="/drawings">Drawings</a></li>
|
||||
</ul>
|
||||
<button id="toggle-theme" onclick="toggleTheme()">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<div id="connected-list-div">
|
||||
<button id="show-connected-button" onclick="toggleClientList()">
|
||||
Connected Blenders:
|
||||
<span id="blender-count">0</span>
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
<div id="client-list"></div>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
<footer>
|
||||
<p>BlenderBIM Version: {{version}}</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,14 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<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/styles.css" />
|
||||
<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"
|
||||
@@ -28,11 +33,31 @@
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<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="/" class="active">IFC Data</a></li>
|
||||
<li><a href="/gantt">Gantt Chart</a></li>
|
||||
<li><a href="/drawings">Drawings</a></li>
|
||||
</ul>
|
||||
<div class="bottom-bar"></div>
|
||||
<button id="toggle-theme" onclick="toggleTheme()">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
</nav>
|
||||
<div id="connected-list-div">
|
||||
<button id="show-connected-button" onclick="toggleClientList()">
|
||||
Connected Blenders:
|
||||
<span id="blender-count">0</span>
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
<div id="client-list"></div>
|
||||
</div>
|
||||
<div id="container"></div>
|
||||
<footer>
|
||||
<p>BlenderBIM Version: {{version}}</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -167,21 +167,6 @@ class IfcExporter:
|
||||
def get_application_name(self) -> str:
|
||||
return "BlenderBIM"
|
||||
|
||||
def get_application_version(self) -> str:
|
||||
version = ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
if blenderbim.bim.last_commit_hash != "8888888":
|
||||
version += f"-{blenderbim.bim.last_commit_hash[:7]}"
|
||||
return version
|
||||
|
||||
|
||||
class IfcExportSettings:
|
||||
def __init__(self):
|
||||
|
||||
@@ -20,6 +20,8 @@ import os
|
||||
import bpy
|
||||
import json
|
||||
import addon_utils
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.api.owner.settings
|
||||
import blenderbim.bim
|
||||
import blenderbim.tool as tool
|
||||
@@ -220,7 +222,7 @@ def redo_post(scene):
|
||||
|
||||
def get_application(ifc: ifcopenshell.file) -> ifcopenshell.entity_instance:
|
||||
# TODO: cache this for even faster application retrieval. It honestly makes a difference on long scripts.
|
||||
version = get_application_version()
|
||||
version = tool.Blender.get_blenderbim_version()
|
||||
for element in ifc.by_type("IfcApplication"):
|
||||
if element.ApplicationIdentifier == "BlenderBIM" and element.Version == version:
|
||||
return element
|
||||
@@ -246,19 +248,6 @@ def get_user(ifc: ifcopenshell.file) -> Union[ifcopenshell.entity_instance, None
|
||||
return pao
|
||||
|
||||
|
||||
def get_application_version() -> str:
|
||||
return ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def viewport_shading_changed_callback(area):
|
||||
shading = area.spaces.active.shading.type
|
||||
if shading == "RENDERED":
|
||||
|
||||
@@ -50,6 +50,8 @@ def draw_attribute(attribute, layout, copy_operator=None):
|
||||
return
|
||||
if value_name == "enum_value":
|
||||
prop_with_search(layout, attribute, "enum_value", text=attribute.name)
|
||||
elif value_name == "filepath_value":
|
||||
attribute.filepath_value.layout_file_select(layout, filter_glob=attribute.filter_glob, text=attribute.name)
|
||||
elif attribute.name in ["ScheduleDuration", "ActualDuration", "FreeFloat", "TotalFloat"]:
|
||||
propis = bpy.context.scene.BIMWorkScheduleProperties
|
||||
for item in propis.durations_attributes:
|
||||
|
||||
@@ -36,7 +36,6 @@ import blenderbim.tool as tool
|
||||
from itertools import chain, accumulate
|
||||
from blenderbim.bim.ifc import IfcStore, IFC_CONNECTED_TYPE
|
||||
from blenderbim.tool.loader import OBJECT_DATA_TYPE
|
||||
from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA
|
||||
from typing import Dict, Union, Optional, Any
|
||||
|
||||
|
||||
@@ -78,6 +77,7 @@ class MaterialCreator:
|
||||
self.load_texture_maps()
|
||||
self.assign_material_slots_to_faces()
|
||||
tool.Geometry.record_object_materials(obj)
|
||||
del self.mesh["ios_materials"]
|
||||
|
||||
def load_existing_materials(self) -> None:
|
||||
for material in bpy.data.materials:
|
||||
@@ -110,7 +110,7 @@ class MaterialCreator:
|
||||
tool.Loader.load_indexed_texture_map(coords, self.mesh)
|
||||
|
||||
def assign_material_slots_to_faces(self) -> None:
|
||||
if "ios_materials" not in self.mesh or not self.mesh["ios_materials"]:
|
||||
if not self.mesh["ios_materials"]:
|
||||
return
|
||||
|
||||
ios_materials = self.mesh["ios_materials"]
|
||||
@@ -509,6 +509,7 @@ class IfcImporter:
|
||||
elif self.ifc_import_settings.false_origin_mode == "AUTOMATIC":
|
||||
if not props.has_blender_offset:
|
||||
tool.Loader.guess_false_origin(self.file)
|
||||
tool.Georeference.set_model_origin()
|
||||
|
||||
def create_positioning_elements(self):
|
||||
self.create_grids()
|
||||
@@ -1262,9 +1263,12 @@ class IfcImporter:
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
tool.Collector.assign(obj)
|
||||
|
||||
def is_curve_annotation(self, element):
|
||||
def is_curve_annotation(self, element: ifcopenshell.entity_instance) -> bool:
|
||||
object_type = element.ObjectType
|
||||
return object_type in ANNOTATION_TYPES_DATA and ANNOTATION_TYPES_DATA[object_type][3] == "curve"
|
||||
return (
|
||||
object_type in tool.Drawing.ANNOTATION_TYPES_DATA
|
||||
and tool.Drawing.ANNOTATION_TYPES_DATA[object_type][3] == "curve"
|
||||
)
|
||||
|
||||
def get_drawing_group(self, element):
|
||||
for rel in element.HasAssignments or []:
|
||||
@@ -1384,6 +1388,7 @@ class IfcImporter:
|
||||
#
|
||||
# we do `.tolist()` because Blender can't assign `np.int32` to it's custom attributes
|
||||
mesh["ios_edges"] = list(set(tuple(e) for e in ifcopenshell.util.shape.get_edges(geometry).tolist()))
|
||||
mesh["ios_item_ids"] = ifcopenshell.util.shape.get_representation_item_ids(geometry).tolist()
|
||||
|
||||
mesh.vertices.add(num_vertices)
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
@@ -1496,6 +1501,7 @@ class IfcImportSettings:
|
||||
self.distance_limit = 1000
|
||||
self.false_origin_mode = "AUTOMATIC"
|
||||
self.false_origin = None
|
||||
self.project_north = None
|
||||
self.element_offset = 0
|
||||
self.element_limit = 30000
|
||||
self.has_filter = None
|
||||
@@ -1531,6 +1537,10 @@ class IfcImportSettings:
|
||||
settings.false_origin = [float(o) for o in props.false_origin.split(",")[:3]]
|
||||
except:
|
||||
settings.false_origin = [0, 0, 0]
|
||||
try:
|
||||
settings.project_north = float(props.project_north)
|
||||
except:
|
||||
settings.project_north = 0
|
||||
settings.element_offset = props.element_offset
|
||||
settings.element_limit = props.element_limit
|
||||
return settings
|
||||
|
||||
@@ -75,7 +75,7 @@ class AggregateData:
|
||||
return []
|
||||
if not element:
|
||||
return []
|
||||
|
||||
|
||||
product_linked_agg_group = [
|
||||
r
|
||||
for r in getattr(aggregate, "HasAssignments", []) or []
|
||||
@@ -85,7 +85,6 @@ class AggregateData:
|
||||
|
||||
if not product_linked_agg_group:
|
||||
return []
|
||||
|
||||
|
||||
total = len(product_linked_agg_group[0].RelatedObjects)
|
||||
return total
|
||||
|
||||
|
||||
@@ -26,14 +26,7 @@ import blenderbim.bim.handler
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class Operator:
|
||||
def execute(self, context):
|
||||
IfcStore.execute_ifc_operator(self, context)
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator):
|
||||
"""Create aggregation relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.aggregate_assign_object"
|
||||
@@ -75,7 +68,7 @@ class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
|
||||
self.report({"ERROR"}, f"Cannot aggregate to {relating_obj.name} with a body representation")
|
||||
|
||||
|
||||
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, tool.Ifc.Operator):
|
||||
"""Remove aggregation relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.aggregate_unassign_object"
|
||||
@@ -99,14 +92,14 @@ class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
|
||||
)
|
||||
|
||||
# Removes Pset related to Linked Aggregates
|
||||
if not element.is_a('IfcElementAssembly'):
|
||||
pset = ifcopenshell.util.element.get_pset(element, 'BBIM_Linked_Aggregate')
|
||||
if not element.is_a("IfcElementAssembly"):
|
||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Linked_Aggregate")
|
||||
if pset:
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
|
||||
|
||||
|
||||
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator):
|
||||
|
||||
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, tool.Ifc.Operator):
|
||||
"""Enable editing aggregation relationship"""
|
||||
|
||||
bl_idname = "bim.enable_editing_aggregate"
|
||||
@@ -117,7 +110,7 @@ class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator):
|
||||
core.enable_editing_aggregate(tool.Aggregate, obj=context.active_object)
|
||||
|
||||
|
||||
class BIM_OT_disable_editing_aggregate(bpy.types.Operator, Operator):
|
||||
class BIM_OT_disable_editing_aggregate(bpy.types.Operator, tool.Ifc.Operator):
|
||||
"""Disable editing aggregation relationship"""
|
||||
|
||||
bl_idname = "bim.disable_editing_aggregate"
|
||||
@@ -174,7 +167,7 @@ class BIM_OT_add_aggregate(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Ifc,
|
||||
tool.Collector,
|
||||
tool.Spatial,
|
||||
structure_obj=tool.Ifc.get_object(current_container),
|
||||
container=current_container,
|
||||
element_obj=aggregate,
|
||||
)
|
||||
core.assign_object(tool.Ifc, tool.Aggregate, tool.Collector, relating_obj=aggregate, related_obj=obj)
|
||||
@@ -232,7 +225,7 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
|
||||
# obj = bpy.data.objects.get(self.obj) or context.active_object
|
||||
# aggregate = ifcopenshell.util.element.get_aggregate(tool.Ifc.get_entity(obj))
|
||||
# aggregate_obj = tool.Ifc.get_object(aggregate)
|
||||
|
||||
|
||||
all_parts = []
|
||||
for obj in context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -245,7 +238,7 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
|
||||
pass
|
||||
if not element:
|
||||
obj.select_set(False)
|
||||
|
||||
|
||||
if self.select_parts:
|
||||
all_objs = []
|
||||
for part in all_parts:
|
||||
@@ -263,12 +256,12 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
|
||||
for aggregate_element in all_parts:
|
||||
aggregate_obj = tool.Ifc.get_object(aggregate_element)
|
||||
aggregate_obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = aggregate_obj
|
||||
bpy.context.view_layer.objects.active = aggregate_obj
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_add_part_to_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_add_part_to_object(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_part_to_object"
|
||||
bl_label = "Add Part to Object"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
@@ -293,7 +286,7 @@ class BIM_OT_add_part_to_object(bpy.types.Operator, Operator):
|
||||
blenderbim.core.spatial.import_spatial_decomposition(tool.Spatial)
|
||||
|
||||
|
||||
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
|
||||
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.break_link_to_other_aggregates"
|
||||
bl_label = "Break link to other aggregates"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
@@ -311,7 +304,7 @@ class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
|
||||
for part in parts:
|
||||
pset = ifcopenshell.util.element.get_pset(part, "BBIM_Linked_Aggregate")
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=part, pset=pset)
|
||||
|
||||
linked_aggregate_group = [
|
||||
r.RelatingGroup
|
||||
@@ -324,7 +317,7 @@ class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_select_linked_aggregates(bpy.types.Operator, Operator):
|
||||
class BIM_OT_select_linked_aggregates(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.select_linked_aggregates"
|
||||
bl_label = "Select linked aggregates"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
@@ -338,7 +331,7 @@ class BIM_OT_select_linked_aggregates(bpy.types.Operator, Operator):
|
||||
return "Select all aggregates"
|
||||
|
||||
def _execute(self, context):
|
||||
|
||||
|
||||
for obj in context.selected_objects:
|
||||
obj.select_set(False)
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
@@ -99,7 +99,7 @@ class BIM_PT_aggregate(Panel):
|
||||
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
|
||||
|
||||
|
||||
class BIM_PT_linked_aggregate(Panel):
|
||||
bl_label = "Linked Aggregates"
|
||||
bl_idname = "BIM_PT_linked_aggregate"
|
||||
@@ -133,9 +133,8 @@ class BIM_PT_linked_aggregate(Panel):
|
||||
props = obj.BIMObjectAggregateProperties
|
||||
row = layout.row(align=True)
|
||||
|
||||
|
||||
if element.Decomposes:
|
||||
Number_Linked_Aggregates = AggregateData.data['total_linked_aggregate']
|
||||
Number_Linked_Aggregates = AggregateData.data["total_linked_aggregate"]
|
||||
if not Number_Linked_Aggregates:
|
||||
row.label(text="Not a Linked Aggregate")
|
||||
else:
|
||||
@@ -151,6 +150,3 @@ class BIM_PT_linked_aggregate(Panel):
|
||||
op = row.operator("bim.break_link_to_other_aggregates", text="", icon="X")
|
||||
else:
|
||||
row.label(text="Not an Aggregate")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import json
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.guid
|
||||
import ifcopenshell.util.element
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.bim.handler
|
||||
import blenderbim.tool as tool
|
||||
@@ -28,13 +29,6 @@ import blenderbim.core.attribute as core
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class Operator:
|
||||
def execute(self, context):
|
||||
IfcStore.execute_ifc_operator(self, context)
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingAttributes(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_attributes"
|
||||
bl_label = "Enable Editing Attributes"
|
||||
@@ -43,7 +37,7 @@ class EnableEditingAttributes(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
obj = bpy.data.objects[self.obj]
|
||||
props = obj.BIMAttributeProperties
|
||||
props.attributes.clear()
|
||||
|
||||
@@ -89,7 +83,7 @@ class DisableEditingAttributes(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditAttributes(bpy.types.Operator, Operator):
|
||||
class EditAttributes(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_attributes"
|
||||
bl_label = "Edit Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
@@ -118,7 +112,7 @@ class EditAttributes(bpy.types.Operator, Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class GenerateGlobalId(bpy.types.Operator, Operator):
|
||||
class GenerateGlobalId(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.generate_global_id"
|
||||
bl_label = "Regenerate GlobalId"
|
||||
bl_description = "Regenerate GlobalId\n\nSHIFT+CLICK to regenerate GlobalIds for all selected objects"
|
||||
@@ -161,7 +155,7 @@ class GenerateGlobalId(bpy.types.Operator, Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CopyAttributeToSelection(bpy.types.Operator, Operator):
|
||||
class CopyAttributeToSelection(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.copy_attribute_to_selection"
|
||||
bl_label = "Copy Attribute To Selection"
|
||||
name: bpy.props.StringProperty()
|
||||
|
||||
@@ -45,8 +45,7 @@ def draw_ui(context, layout, attributes):
|
||||
row.label(text=attribute["name"])
|
||||
# row.label(text=attribute["value"])
|
||||
op = row.operator("bim.select_similar", text=attribute["value"], icon="NONE", emboss=False)
|
||||
op.key = attribute['name']
|
||||
|
||||
op.key = attribute["name"]
|
||||
|
||||
# TODO: reimplement, see #1222
|
||||
# if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name:
|
||||
|
||||
@@ -26,6 +26,7 @@ import requests
|
||||
import tempfile
|
||||
import datetime
|
||||
import addon_utils
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
class AuginLogin(bpy.types.Operator):
|
||||
@@ -77,16 +78,7 @@ class AuginCreateNewModel(bpy.types.Operator):
|
||||
props.project_filename = "BBM{}{}".format(
|
||||
datetime.datetime.now().strftime("%Y%m%d%H%M%S"), "".join(random.choice(chars) for _ in range(6))
|
||||
)
|
||||
addon_version = ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
addon_version = tool.Blender.get_blenderbim_version()
|
||||
|
||||
payload = {
|
||||
"user_token": props.token,
|
||||
|
||||
@@ -66,10 +66,7 @@ class LoadBcfProject(bpy.types.Operator):
|
||||
if bcfxml.version.version_id.startswith("2"):
|
||||
print("No project, we will create one for BBIM.")
|
||||
bcfxml.project_info = bcf.v2.model.ProjectExtension(
|
||||
project=bcf.v2.model.Project(
|
||||
name=nameless,
|
||||
project_id=str(uuid.uuid4())
|
||||
), extension_schema=""
|
||||
project=bcf.v2.model.Project(name=nameless, project_id=str(uuid.uuid4())), extension_schema=""
|
||||
)
|
||||
if bcfxml.project.name is None:
|
||||
bcfxml.project.name = nameless
|
||||
@@ -949,9 +946,9 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
matrix = ifcopenshell.util.geolocation.global2local(
|
||||
matrix,
|
||||
float(props.blender_eastings) * unit_scale,
|
||||
float(props.blender_northings) * unit_scale,
|
||||
float(props.blender_orthogonal_height) * unit_scale,
|
||||
float(props.blender_offset_x) * unit_scale,
|
||||
float(props.blender_offset_y) * unit_scale,
|
||||
float(props.blender_offset_z) * unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
@@ -971,13 +968,14 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
self.set_colours(viewpoint)
|
||||
|
||||
def set_exceptions(self, viewpoint, context):
|
||||
if (
|
||||
not hasattr(viewpoint.visualization_info.components, "visibility")
|
||||
or not hasattr(viewpoint.visualization_info.components.visibility.exceptions, "component")
|
||||
if not hasattr(viewpoint.visualization_info.components, "visibility") or not hasattr(
|
||||
viewpoint.visualization_info.components.visibility.exceptions, "component"
|
||||
):
|
||||
return
|
||||
|
||||
exception_global_ids = {v.ifc_guid for v in viewpoint.visualization_info.components.visibility.exceptions.component or []}
|
||||
exception_global_ids = {
|
||||
v.ifc_guid for v in viewpoint.visualization_info.components.visibility.exceptions.component or []
|
||||
}
|
||||
|
||||
# print("default_visibility: {}".format(viewpoint.visualization_info.components.visibility.default_visibility))
|
||||
if viewpoint.visualization_info.components.visibility.default_visibility:
|
||||
@@ -1034,7 +1032,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
context.area.type = old
|
||||
|
||||
def set_openings_visibility(self, is_visible, context):
|
||||
pass # We no longer have an openings collection
|
||||
pass # We no longer have an openings collection
|
||||
|
||||
def set_selection(self, viewpoint):
|
||||
if not viewpoint.visualization_info.components or not viewpoint.visualization_info.components.selection:
|
||||
@@ -1147,7 +1145,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
# https://github.com/buildingSMART/BCF-XML/tree/release_3_0/Documentation#coloring
|
||||
if lv == 8:
|
||||
t = tuple(int(value[i : i + lv // 4], 16) for i in range(0, lv, lv // 4))
|
||||
col = [t[1] / 255.0, t[2] / 255.0, t[3] / 255.0, t[0] / 255.0]
|
||||
col = [t[1] / 255.0, t[2] / 255.0, t[3] / 255.0, t[0] / 255.0]
|
||||
else:
|
||||
t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3))
|
||||
col = [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1]
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 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 os
|
||||
import bpy
|
||||
import tempfile
|
||||
import webbrowser
|
||||
|
||||
try:
|
||||
import bimtester
|
||||
import bimtester.run
|
||||
import bimtester.reports
|
||||
except:
|
||||
print("Failed to load BIMTester. Try disabling other add-ons, in particular Blender-OSM. See bug #1318.")
|
||||
|
||||
from pathlib import Path
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class ExecuteBIMTester(bpy.types.Operator):
|
||||
bl_idname = "bim.execute_bim_tester"
|
||||
bl_label = "Execute BIMTester"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
return (props.ifc_file or props.should_load_from_memory) and props.feature
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
|
||||
with tempfile.TemporaryDirectory() as dirpath:
|
||||
report = os.path.join(dirpath, "{}.html".format(props.feature))
|
||||
args = {
|
||||
"action": "run",
|
||||
"advanced_arguments": "",
|
||||
"console": False,
|
||||
"feature": props.feature,
|
||||
"ifc": props.ifc_file,
|
||||
"path": "",
|
||||
"report": report,
|
||||
"schema_file": "",
|
||||
"schema_name": "",
|
||||
"lang": "en",
|
||||
"steps": props.steps,
|
||||
}
|
||||
use_stored_ifc = props.should_load_from_memory and IfcStore.get_file()
|
||||
runner = bimtester.run.TestRunner(args["ifc"], ifc=IfcStore.get_file() if use_stored_ifc else None)
|
||||
report_json = runner.run(args)
|
||||
bimtester.reports.ReportGenerator().generate(report_json, args["report"])
|
||||
webbrowser.open("file://" + report)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIMTesterPurge(bpy.types.Operator):
|
||||
bl_idname = "bim.bim_tester_purge"
|
||||
bl_label = "Purge Tests"
|
||||
|
||||
def execute(self, context):
|
||||
cwd = os.getcwd()
|
||||
os.chdir(context.scene.BimTesterProperties.features_dir)
|
||||
bimtester.clean.TestPurger().purge()
|
||||
os.chdir(cwd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectFeature(bpy.types.Operator):
|
||||
bl_idname = "bim.select_feature"
|
||||
bl_label = "Select Feature / IDS"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".feature"
|
||||
filter_glob: bpy.props.StringProperty(default="*.feature;*.xml", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BimTesterProperties.feature = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class SelectSteps(bpy.types.Operator):
|
||||
bl_idname = "bim.select_steps"
|
||||
bl_label = "Select Steps"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".py"
|
||||
filter_glob: bpy.props.StringProperty(default="*.py", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BimTesterProperties.steps = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class SelectBIMTesterIfcFile(bpy.types.Operator):
|
||||
bl_idname = "bim.select_bimtester_ifc_file"
|
||||
bl_label = "Select BIMTester IFC File"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".ifc"
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BimTesterProperties.ifc_file = self.filepath
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class RejectElement(bpy.types.Operator):
|
||||
bl_idname = "bim.reject_element"
|
||||
bl_label = "Reject Element"
|
||||
|
||||
def execute(self, context):
|
||||
lines = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in context.selected_objects:
|
||||
lines.append(
|
||||
" * The element {} should not exist because {}".format(
|
||||
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId,
|
||||
context.scene.BimTesterProperties.qa_reject_element_reason,
|
||||
)
|
||||
)
|
||||
QAHelper.append_to_scenario(lines, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ApproveClass(bpy.types.Operator):
|
||||
bl_idname = "bim.approve_class"
|
||||
bl_label = "Approve Class"
|
||||
|
||||
def execute(self, context):
|
||||
lines = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
lines.append(" * The element {} is an {}".format(element.GlobalId, element.is_a()))
|
||||
QAHelper.append_to_scenario(lines, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RejectClass(bpy.types.Operator):
|
||||
bl_idname = "bim.reject_class"
|
||||
bl_label = "Reject Class"
|
||||
|
||||
def execute(self, context):
|
||||
lines = []
|
||||
self.file = IfcStore.get_file()
|
||||
for obj in context.selected_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
lines.append(
|
||||
" * The element {} is an {}".format(
|
||||
self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId,
|
||||
context.scene.BimTesterProperties.audit_ifc_class,
|
||||
)
|
||||
)
|
||||
QAHelper.append_to_scenario(lines, context)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectAudited(bpy.types.Operator):
|
||||
bl_idname = "bim.select_audited"
|
||||
bl_label = "Select Audited"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
audited_global_ids = []
|
||||
self.file = IfcStore.get_file()
|
||||
for filename in Path(context.scene.BimTesterProperties.features_dir).glob("*.feature"):
|
||||
with open(filename, "r") as feature_file:
|
||||
lines = feature_file.readlines()
|
||||
for line in lines:
|
||||
words = line.strip().split()
|
||||
for word in words:
|
||||
if self.is_a_global_id(word):
|
||||
audited_global_ids.append(word)
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
continue
|
||||
if self.file.by_id(obj.BIMObjectProperties.ifc_definition_id).GlobalId in audited_global_ids:
|
||||
obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
|
||||
def is_a_global_id(self, word):
|
||||
return word[0] in ["0", "1", "2", "3"] and len(word) == 22
|
||||
|
||||
|
||||
class QAHelper:
|
||||
@classmethod
|
||||
def append_to_scenario(cls, lines, context):
|
||||
filename = os.path.join(
|
||||
context.scene.BimTesterProperties.features_dir,
|
||||
context.scene.BimTesterProperties.features_file + ".feature",
|
||||
)
|
||||
if os.path.exists(filename + "~"):
|
||||
os.remove(filename + "~")
|
||||
os.rename(filename, filename + "~")
|
||||
with open(filename, "w") as destination:
|
||||
with open(filename + "~", "r") as source:
|
||||
is_in_scenario = False
|
||||
for source_line in source:
|
||||
if (
|
||||
"Scenario: " in source_line
|
||||
and context.scene.BimTesterProperties.scenario == source_line.strip()[len("Scenario: ") :]
|
||||
):
|
||||
is_in_scenario = True
|
||||
elif is_in_scenario:
|
||||
for line in lines:
|
||||
destination.write(line + "\n")
|
||||
is_in_scenario = False
|
||||
destination.write(source_line)
|
||||
os.remove(filename + "~")
|
||||
@@ -1,71 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 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 os
|
||||
from pathlib import Path
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
from blenderbim.bim.module.root.prop import get_ifc_classes
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
|
||||
scenarios_enum = []
|
||||
|
||||
|
||||
def purge():
|
||||
global scenarios_enum
|
||||
scenarios_enum = []
|
||||
|
||||
|
||||
def getScenarios(self, context):
|
||||
global scenarios_enum
|
||||
if len(scenarios_enum) < 1:
|
||||
scenarios_enum.clear()
|
||||
|
||||
if context.scene.BimTesterProperties.feature != "":
|
||||
with open(context.scene.BimTesterProperties.feature, "r") as feature_file:
|
||||
lines = feature_file.readlines()
|
||||
for line in lines:
|
||||
if "Scenario:" in line:
|
||||
s = line.strip()[len("Scenario: ") :]
|
||||
scenarios_enum.append((s, s, ""))
|
||||
return scenarios_enum
|
||||
|
||||
|
||||
def refreshScenarios(self, context):
|
||||
global scenarios_enum
|
||||
scenarios_enum.clear()
|
||||
getScenarios(self, context)
|
||||
|
||||
|
||||
class BimTesterProperties(PropertyGroup):
|
||||
feature: StringProperty(default="", name="Feature", update=refreshScenarios)
|
||||
steps: StringProperty(default="", name="Custom Steps")
|
||||
ifc_file: StringProperty(default="", name="IFC File")
|
||||
audit_ifc_class: EnumProperty(items=get_ifc_classes, name="Audit Class")
|
||||
qa_reject_element_reason: StringProperty(name="Element Rejection Reason")
|
||||
scenario: EnumProperty(items=getScenarios, name="Scenario")
|
||||
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
|
||||
@@ -1,81 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 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 bpy.types import Panel
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class BIM_PT_qa(Panel):
|
||||
bl_label = "BIMTester"
|
||||
bl_idname = "BIM_PT_qa"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_quality_control"
|
||||
|
||||
def draw(self, context):
|
||||
self.layout.use_property_split = True
|
||||
|
||||
props = context.scene.BimTesterProperties
|
||||
|
||||
if IfcStore.get_file():
|
||||
row = self.layout.row()
|
||||
row.prop(props, "should_load_from_memory")
|
||||
|
||||
if not IfcStore.get_file() or not props.should_load_from_memory:
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "ifc_file")
|
||||
row.operator("bim.select_bimtester_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "feature")
|
||||
row.operator("bim.select_feature", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "steps")
|
||||
row.operator("bim.select_steps", icon="FILE_FOLDER", text="")
|
||||
|
||||
has_ifc_file = (IfcStore.get_file() and props.should_load_from_memory) or (
|
||||
props.ifc_file and not props.should_load_from_memory
|
||||
)
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.execute_bim_tester")
|
||||
row.operator("bim.bim_tester_purge")
|
||||
|
||||
if props.feature and has_ifc_file:
|
||||
self.layout.label(text="Scenario Authoring:")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "scenario")
|
||||
|
||||
row = self.layout.row()
|
||||
row.prop(props, "qa_reject_element_reason")
|
||||
row = self.layout.row()
|
||||
row.operator("bim.reject_element")
|
||||
|
||||
row = self.layout.row()
|
||||
row.prop(props, "audit_ifc_class")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.approve_class")
|
||||
row.operator("bim.reject_class")
|
||||
|
||||
row = self.layout.row()
|
||||
row.operator("bim.select_audited")
|
||||
@@ -603,7 +603,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
objs = context.selected_objects
|
||||
|
||||
if not any((element:=tool.Ifc.get_entity(obj)) and element.is_a("IfcSpace") for obj in objs):
|
||||
if not any((element := tool.Ifc.get_entity(obj)) and element.is_a("IfcSpace") for obj in objs):
|
||||
self.report({"INFO"}, "No IfcSpace elements selected.")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user