mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 09:21:46 +00:00
Compare commits
378 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd093303c4 | |||
| c5c7363a93 | |||
| 5014fef129 | |||
| d710a01df5 | |||
| 23c65742e1 | |||
| d8f52afa6c | |||
| 29ce8d5d80 | |||
| 5e5de0bbd8 | |||
| b9b58f5726 | |||
| 5c7271ddc8 | |||
| 2db35556e9 | |||
| 2449656311 | |||
| c66cf0a22b | |||
| e1a1ba62c5 | |||
| 6489f4dc1d | |||
| beab99bb0d | |||
| 8b50f1bcd6 | |||
| 4617834578 | |||
| 426dcbee43 | |||
| 2a12151c07 | |||
| c08958c1bd | |||
| e355a33d48 | |||
| ece9e2fdd1 | |||
| c0d84713bc | |||
| ca9f165b6a | |||
| 8f9c97a663 | |||
| 4ed8310b93 | |||
| 31be899dc9 | |||
| 6d7a6eeda7 | |||
| c520e0eeb5 | |||
| 73817acdff | |||
| 3d7e8d7c6c | |||
| a701840826 | |||
| 5de2ac9042 | |||
| 573e2626ad | |||
| 9de59afd49 | |||
| 74a9671075 | |||
| 799658ff41 | |||
| bd64f42a54 | |||
| 8eab7f155e | |||
| 5351966430 | |||
| 2663c079f4 | |||
| 6747bd9c8f | |||
| 6ece295be4 | |||
| 64a9f85f25 | |||
| d8fa853308 | |||
| ce37c49624 | |||
| 0da3270c7f | |||
| fda6fc6c48 | |||
| 3865f01df9 | |||
| 6bf61d7163 | |||
| b8ad73668f | |||
| b7a3dd4164 | |||
| 566fd443db | |||
| 51b5a507cf | |||
| a44357dad5 | |||
| 8e792ebb50 | |||
| 352321364c | |||
| 2ab32e41b2 | |||
| 3fbd9d7cdf | |||
| 7a7fde0a2a | |||
| 7992bd9902 | |||
| 3182fe9c15 | |||
| e8858aeeb3 | |||
| ec79d61095 | |||
| 266236ee49 | |||
| 192e4e43a4 | |||
| b22c92e951 | |||
| 7634e71434 | |||
| dda803df2e | |||
| c3ded31a6a | |||
| f2d19ab2c3 | |||
| ab80400e16 | |||
| c88496c6a6 | |||
| 0ee07fb8cc | |||
| 36cf458498 | |||
| e7c25bf99f | |||
| 50a3c8c2f3 | |||
| f18298d1fd | |||
| d4770bdee3 | |||
| 1fb107c361 | |||
| 0fa1e2d585 | |||
| dc13f4c5cc | |||
| d197c3f49a | |||
| c05200a5c6 | |||
| 235bb198da | |||
| 40f332d674 | |||
| e8a272dc97 | |||
| 0b308770a6 | |||
| 96c8323a06 | |||
| 25573cd0e0 | |||
| ff3c7786f6 | |||
| 5f4dfcf215 | |||
| 9a89555a53 | |||
| fc69a2acbe | |||
| 85a2a5ad12 | |||
| 49c3d28a0b | |||
| a8f20b2c6b | |||
| 66fa1cedd9 | |||
| eb971d3d73 | |||
| a30a796c07 | |||
| 9e46bacc12 | |||
| b33378e135 | |||
| d42e19f491 | |||
| 2597827ab3 | |||
| 3f71efea6d | |||
| 2d279b7a7f | |||
| e5fe039fd0 | |||
| 9e14829cc1 | |||
| e867602d9d | |||
| aecc3d56b8 | |||
| e3f5d3d2b7 | |||
| 65f8b1a532 | |||
| 96b4df10ba | |||
| 98b56aea42 | |||
| ba6ba29da8 | |||
| 1112b102f7 | |||
| 04b8172ea9 | |||
| f5f3edbc79 | |||
| 30029e3dc7 | |||
| ed836f5b4a | |||
| a88b708442 | |||
| 764c3bbb85 | |||
| 382d3f1f9f | |||
| c92f607a15 | |||
| b57b7080fd | |||
| 860ff4e513 | |||
| 3546f13593 | |||
| 663966e08d | |||
| f077ebdc81 | |||
| eb888fd116 | |||
| 40b6b3bf17 | |||
| 2ef2f923d0 | |||
| 75fab58831 | |||
| ce26c6e19b | |||
| 8728fa38b9 | |||
| 3037795199 | |||
| 39ee9cd8b1 | |||
| b375bbf558 | |||
| f2cae79dea | |||
| aadc77f6b6 | |||
| 35223d968c | |||
| e106dc4502 | |||
| 2995b73c2d | |||
| 770bc6ea61 | |||
| f5736a7144 | |||
| b4120b1cab | |||
| f44ca67ab9 | |||
| 77eae1c8e8 | |||
| 02d79f0687 | |||
| 83d364574a | |||
| 688d2b7bd1 | |||
| bf35239979 | |||
| ca8e014647 | |||
| b5f63ec4f3 | |||
| aec2141128 | |||
| 778344c804 | |||
| 3ede9b254f | |||
| 8df40dc4a6 | |||
| 75dd4f3132 | |||
| be11df3dc1 | |||
| 09ac212aa9 | |||
| e159151b44 | |||
| 27f6ac0575 | |||
| f840da3ffd | |||
| 034df852b2 | |||
| f242071ebb | |||
| b6663e9189 | |||
| 39d143668c | |||
| 6ea1e378c5 | |||
| a33f30e8ce | |||
| e79fb2ff0b | |||
| 054b4d0ee2 | |||
| 43bebf4eee | |||
| 532869a48a | |||
| 6569d0031f | |||
| bfaa61e592 | |||
| 1a09ce40e9 | |||
| 6f1b40fc86 | |||
| 734eec7715 | |||
| bfabc0db0f | |||
| e71aac84dc | |||
| c156100be2 | |||
| 48c2b43a58 | |||
| 2f8cfb5a95 | |||
| 1c4cc34c1b | |||
| b81e03d9c2 | |||
| eb96858460 | |||
| 5c7e70e987 | |||
| 9093c9d419 | |||
| 02a5b8d997 | |||
| f1b5f7d558 | |||
| 742a9ecd81 | |||
| 77a497cdf7 | |||
| 00576ef574 | |||
| c26caaa58d | |||
| b260bd3877 | |||
| cd6246c382 | |||
| a96d6dacc7 | |||
| 64c711a02a | |||
| 68a2480a66 | |||
| d5e2fd5d3c | |||
| bb445663f8 | |||
| 1f7db75572 | |||
| f478ec8d6b | |||
| cf3ba334b7 | |||
| c36af110c4 | |||
| 91eac7085b | |||
| 239d1d6fd2 | |||
| 831709d514 | |||
| 5925476ed9 | |||
| 3edb3c8df3 | |||
| 72badd8427 | |||
| ff251b7a6a | |||
| dbce57ffc5 | |||
| 8ff9bcef32 | |||
| 82b2006686 | |||
| ca4181c714 | |||
| 3928dd7c9c | |||
| 925964ee2a | |||
| 7201df8d22 | |||
| 7b65108a76 | |||
| 0fbe4d80c7 | |||
| 54c689d615 | |||
| ab828b1a8b | |||
| 8ddd349f8b | |||
| 3221219f4a | |||
| 36387f348e | |||
| c39c6d81e3 | |||
| e8042de1ed | |||
| 78fd999c53 | |||
| 91d1cb79c2 | |||
| 832618b84a | |||
| e4ce53d548 | |||
| 7b92b5c7e2 | |||
| c8c08439b2 | |||
| 3476ee8fd5 | |||
| d2f331c813 | |||
| 9e9b294f44 | |||
| f824ee8ca4 | |||
| 919f673108 | |||
| b034b40b09 | |||
| 34f038530f | |||
| 1c70990b06 | |||
| 07eecad433 | |||
| ef87f0fe74 | |||
| 23c2d73e8e | |||
| 0b47fb5987 | |||
| 8a1dee532b | |||
| f0c6c4ca59 | |||
| 92cf0d9265 | |||
| 7c438b6b9b | |||
| 46454c5c94 | |||
| 73aeafb063 | |||
| e06297940f | |||
| 1652629332 | |||
| 3d8de40407 | |||
| 308457300e | |||
| 6ef96841ac | |||
| 289b2d1e9d | |||
| 96db699ad2 | |||
| 6b7eec0db6 | |||
| 80f35d0bda | |||
| df390a655d | |||
| 593fca7c3d | |||
| 9335c8a0c8 | |||
| eccc21277d | |||
| 2ce7e16537 | |||
| 49835ee303 | |||
| f5500da0af | |||
| c9552fac29 | |||
| b11b3b7fa8 | |||
| 8aecee5836 | |||
| 2f3b3011ec | |||
| 491c9203b0 | |||
| 7f2b996d23 | |||
| d2ea6f6656 | |||
| 25128e8aa8 | |||
| 30fa917e69 | |||
| 40e494996d | |||
| cfdc54064e | |||
| 6daead6b61 | |||
| 241d52f0ad | |||
| 68dd93da1d | |||
| 82703670f0 | |||
| cb8462a0d0 | |||
| 000245c26c | |||
| d97ee8eed4 | |||
| f8af28f12a | |||
| f6fab30d0a | |||
| f1a4ed702b | |||
| c4080626df | |||
| a8078e38d2 | |||
| c52fe8abf9 | |||
| b310b5aaba | |||
| 7246e75085 | |||
| 48c0378bff | |||
| 91c90e7b86 | |||
| 72abdb0569 | |||
| 7947ba4aaf | |||
| 2520a93055 | |||
| fa480d99a2 | |||
| 72c057e7a0 | |||
| 61cfb361fa | |||
| 3786cfa666 | |||
| cabc06821f | |||
| f9fef4f5f6 | |||
| 7c89d072e2 | |||
| dbb9e8c907 | |||
| 2df5b4c70e | |||
| a5aa608240 | |||
| f7454366cc | |||
| f773480917 | |||
| 89f9cd0403 | |||
| b21159c6b3 | |||
| 227f556669 | |||
| 42bd69929c | |||
| a3532b24b3 | |||
| 5486c4c8e9 | |||
| 0259d4c0cd | |||
| 66c4c61dc2 | |||
| 0f32ffe232 | |||
| 72630de77a | |||
| 9395bed72b | |||
| 507a5cab83 | |||
| a46a60996d | |||
| 3106168889 | |||
| 7e0c0c5c83 | |||
| 19205c8774 | |||
| 62b5f1d728 | |||
| 299df62758 | |||
| e58bfde500 | |||
| b60306cdbd | |||
| 61e0549e65 | |||
| 52ae759218 | |||
| 9b41614eff | |||
| 58e01751c1 | |||
| 624134d033 | |||
| 22f83b68e4 | |||
| 1b35ea122e | |||
| f1deefbcb3 | |||
| d6c020b5ee | |||
| ff4eddf38a | |||
| 2b34dc4ce7 | |||
| 530260ebe7 | |||
| 594268c860 | |||
| e5fa8a01b4 | |||
| ad934cd9a6 | |||
| 92fe325816 | |||
| 818bb9c823 | |||
| d71fad988d | |||
| ff0d6c810f | |||
| 9aad249586 | |||
| d23e32c64a | |||
| b815719477 | |||
| 8e64b55290 | |||
| b45001a95a | |||
| fd65009f5a | |||
| 52036e9bd4 | |||
| 5399767898 | |||
| f96d477d2b | |||
| 67be2e8ce8 | |||
| f0e5304b8e | |||
| 61bd98e7db | |||
| 4bf0d9ccff | |||
| 1e36ac8740 | |||
| af864e8556 | |||
| ef72cd3250 | |||
| 4f1e59a613 | |||
| 5960e4153c | |||
| 66f735fde9 | |||
| 1a3aa7f031 | |||
| 37ab9c80e3 | |||
| 86a234d17e | |||
| f68baee5c3 | |||
| 0028fd3e9c | |||
| f5f9862b78 | |||
| 4e833e26ca |
@@ -39,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310]
|
||||
pyver: [py39, py310, py311]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
@@ -62,7 +62,7 @@ jobs:
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
python-version: '3.10'
|
||||
python-version: '3.11'
|
||||
- run: echo ${{ env.DATE }}
|
||||
- name: Get current date
|
||||
id: date
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
name: ci_py_only
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'src/**'
|
||||
- 'test/**'
|
||||
- 'conda/**'
|
||||
- 'cmake/**'
|
||||
- '.github/workflows/ci-py-only.yml'
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell' &&
|
||||
!contains(github.event.head_commit.message, 'skip ci')
|
||||
steps:
|
||||
- run: echo ok go
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install C++ dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --no-install-recommends \
|
||||
git cmake gcc g++ \
|
||||
libboost-date-time-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-iostreams-dev \
|
||||
libboost-program-options-dev \
|
||||
libboost-regex-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
python3-all-dev python3-pip \
|
||||
swig libpcre3-dev libxml2-dev \
|
||||
libtbb-dev nlohmann-json3-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
libhdf5-dev libcgal-dev
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: ${GITHUB_WORKFLOW}
|
||||
|
||||
- name: Build ifcopenshell
|
||||
run: |
|
||||
sudo /usr/sbin/update-ccache-symlinks
|
||||
mkdir build && cd build
|
||||
PATH="/usr/lib/ccache:$PATH" cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
|
||||
-DCOLLADA_SUPPORT=Off \
|
||||
"-DSCHEMA_VERSIONS=2x3;4;4x3_add1" \
|
||||
-DBUILD_CONVERT=Off \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include \
|
||||
-DCGAL_INCLUDE_DIR=/usr/include \
|
||||
-DGMP_INCLUDE_DIR=/usr/include \
|
||||
-DMPFR_INCLUDE_DIR=/usr/include \
|
||||
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
|
||||
../cmake
|
||||
sudo make -j $(nproc)
|
||||
sudo make install
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
sudo /usr/bin/python -m pip install -U pip
|
||||
sudo /usr/bin/python -m pip install xmlschema xsdata numpy lxml
|
||||
sudo /usr/bin/python -m pip install src/bcf --no-deps
|
||||
sudo /usr/bin/python -m pip install pytest
|
||||
sudo /usr/bin/python -m pip install isodate
|
||||
sudo /usr/bin/python -m pip install lark
|
||||
sudo /usr/bin/python -m pip install networkx
|
||||
sudo /usr/bin/python -m pip install tabulate
|
||||
sudo /usr/bin/python -m pip install python-dateutil
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
cd test
|
||||
sudo /usr/bin/python tests.py
|
||||
cd ../src/ifcopenshell-python
|
||||
mv ifcopenshell ifcopenshell-local # Force testing on installed module
|
||||
make test-safe
|
||||
+23
-20
@@ -31,12 +31,25 @@ jobs:
|
||||
- run: echo ok go
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.11
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil
|
||||
pip install src/bcf --no-deps
|
||||
pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
|
||||
- name: Install C++ dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -49,7 +62,6 @@ jobs:
|
||||
libboost-regex-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
python3-all-dev python3-pip \
|
||||
swig libpcre3-dev libxml2-dev \
|
||||
libtbb-dev nlohmann-json3-dev \
|
||||
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
|
||||
@@ -62,6 +74,9 @@ jobs:
|
||||
|
||||
- name: Build ifcopenshell
|
||||
run: |
|
||||
echo $Python3_ROOT_DIR
|
||||
echo ${{ env.pythonLocation }}
|
||||
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -71,9 +86,9 @@ jobs:
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.8 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.8.so \
|
||||
-DPYTHON_EXECUTABLE:FILEPATH=${{ env.pythonLocation }}/bin/python \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=${{ env.pythonLocation }}/include/python3.11 \
|
||||
-DPYTHON_LIBRARY:FILEPATH=${{ env.pythonLocation }}/lib/libpython3.11.so \
|
||||
-DCOLLADA_SUPPORT=Off \
|
||||
"-DSCHEMA_VERSIONS=2x3;4;4x3_add1" \
|
||||
-DGLTF_SUPPORT=On \
|
||||
@@ -102,23 +117,11 @@ jobs:
|
||||
grep 0$ statuses
|
||||
grep 0$ statuses | wc -l
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
sudo /usr/bin/python -m pip install -U pip
|
||||
sudo /usr/bin/python -m pip install xmlschema xsdata numpy lxml
|
||||
sudo /usr/bin/python -m pip install src/bcf --no-deps
|
||||
sudo /usr/bin/python -m pip install pytest
|
||||
sudo /usr/bin/python -m pip install isodate
|
||||
sudo /usr/bin/python -m pip install lark
|
||||
sudo /usr/bin/python -m pip install networkx
|
||||
sudo /usr/bin/python -m pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
sudo /usr/bin/python -m pip install tabulate
|
||||
sudo /usr/bin/python -m pip install python-dateutil
|
||||
|
||||
- name: Test
|
||||
- name: Test ifcopenshell-python
|
||||
run: |
|
||||
cd test
|
||||
sudo /usr/bin/python tests.py
|
||||
python tests.py
|
||||
cd ../src/ifcopenshell-python
|
||||
mv ifcopenshell ifcopenshell-local # Force testing on installed module
|
||||
make test-safe
|
||||
|
||||
+6
-12
@@ -7,34 +7,26 @@
|
||||
|
||||
# output directories
|
||||
/cmake/out/
|
||||
/docs/out/
|
||||
/src/examples/out/
|
||||
/src/ifcmax/out/
|
||||
/src/ifcwrap/out/
|
||||
/src/qtviewer/out/
|
||||
|
||||
|
||||
/win/BuildDepsCache*.txt
|
||||
# IfcExpressParser residue
|
||||
/src/ifcexpressparser/express_parser.py
|
||||
|
||||
# General Python residue
|
||||
__pycache__
|
||||
*.py.bak
|
||||
|
||||
# Visual Studio Code files
|
||||
.vscode
|
||||
.vs
|
||||
|
||||
# PyCharm files
|
||||
.idea
|
||||
|
||||
#Virtual Env Files
|
||||
Pipfile
|
||||
Pipfile.lock
|
||||
|
||||
# Docs
|
||||
/docs/output
|
||||
/docs/rst_files
|
||||
/docs/doxygen
|
||||
/src/ifcblenderexport/docs/_build
|
||||
/docs/cpp-api/output
|
||||
|
||||
# gettext binary translation files
|
||||
*.mo
|
||||
@@ -96,6 +88,8 @@ src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
|
||||
# apple
|
||||
.DS_Store
|
||||
|
||||
# clangd config
|
||||
.clangd
|
||||
# clangd cache
|
||||
.cache
|
||||
|
||||
|
||||
+4
-1
@@ -10,4 +10,7 @@
|
||||
url = https://github.com/IfcOpenShell/svgfill
|
||||
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
|
||||
path = src/ifcopenshell-python/test/Sample-BIM-Files
|
||||
url = https://github.com/IfcOpenShell/ids-test-files
|
||||
url = https://github.com/IfcOpenShell/ids-test-files
|
||||
[submodule "docs/cpp-api/assets/doxygen-awesome-css"]
|
||||
path = docs/cpp-api/assets/doxygen-awesome-css
|
||||
url = https://github.com/jothepro/doxygen-awesome-css.git
|
||||
|
||||
@@ -7,13 +7,13 @@ IfcOpenShell
|
||||
</p>
|
||||
|
||||
IfcOpenShell is an open source ([LGPL]) software library for working with Industry Foundation Classes ([IFC]). Complete
|
||||
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x2, and IFC4x3. Extensive geometric support
|
||||
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x2, and [IFC4x3 Add2]. Extensive geometric support
|
||||
is implemented for the IFC releases [IFC2x3 TC1] and [IFC4 Add2 TC1]. Extending with support for arbitrary IFC schemas
|
||||
is possible at compile-time when using C++ and at run-time when using Python.
|
||||
|
||||
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application to convert IFC models to
|
||||
other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform), and many
|
||||
other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
|
||||
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an application
|
||||
to convert IFC models to other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform),
|
||||
and many other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
|
||||
|
||||
For more information, see:
|
||||
|
||||
@@ -32,8 +32,8 @@ For more information, see:
|
||||
| Anaconda Daily Build | [](https://anaconda.org/ifcopenshell/ifcopenshell) |
|
||||
| Anaconda v0.7.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) |
|
||||
| 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) |
|
||||
@@ -44,7 +44,7 @@ Contents
|
||||
Those marked with an asterisk are part of IfcOpenShell.
|
||||
|
||||
| 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 |
|
||||
@@ -77,6 +77,7 @@ Those marked with an asterisk are part of IfcOpenShell.
|
||||
[IFC]: https://technical.buildingsmart.org/standards/ifc/ "IFC"
|
||||
[IFC2x3 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/ "IFC2x3 TC1"
|
||||
[IFC4 Add2 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/ "IFC4 Add2 TC1"
|
||||
[IFC4x3 Add2]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/ "IFC4x3 Add2"
|
||||
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
|
||||
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
|
||||
[MSYS2]: https://msys2.github.io/ "MSYS2"
|
||||
|
||||
@@ -29,7 +29,7 @@ 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"SET\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
|
||||
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"(?:set|SET)\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
|
||||
|
||||
|
||||
if sys.argv[1] == "--do_choco_release?":
|
||||
|
||||
+20
-13
@@ -17,7 +17,7 @@
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.1.3)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
||||
|
||||
@@ -27,6 +27,7 @@ cmake_policy(SET CMP0048 NEW)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
cmake_policy(SET CMP0078 OLD)
|
||||
cmake_policy(SET CMP0086 NEW)
|
||||
cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case <PACKAGENAME>_ROOT variables.
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
@@ -186,7 +187,7 @@ if(GLTF_SUPPORT AND BUILD_CONVERT)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_GLTF)
|
||||
endif()
|
||||
|
||||
# Add USD support to serializers
|
||||
# Add USD support to serializers
|
||||
if(USD_SUPPORT)
|
||||
UNIFY_ENVVARS_AND_CACHE(USD_INCLUDE_DIR)
|
||||
UNIFY_ENVVARS_AND_CACHE(USD_LIBRARY_DIR)
|
||||
@@ -209,13 +210,13 @@ if(USD_SUPPORT)
|
||||
endif()
|
||||
|
||||
set(USD_LIBRARIES
|
||||
usd_usd
|
||||
usd_usd
|
||||
usd_usdGeom
|
||||
usd_usdShade
|
||||
usd_usdLux
|
||||
usd_vt
|
||||
usd_sdf
|
||||
usd_tf
|
||||
usd_usdShade
|
||||
usd_usdLux
|
||||
usd_vt
|
||||
usd_sdf
|
||||
usd_tf
|
||||
usd_gf
|
||||
)
|
||||
|
||||
@@ -435,7 +436,7 @@ if(BUILD_IFCGEOM)
|
||||
|
||||
if(OCCT_STATIC)
|
||||
find_package(Threads)
|
||||
|
||||
|
||||
if(WASM_BUILD)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
else()
|
||||
@@ -447,7 +448,7 @@ if(BUILD_IFCGEOM)
|
||||
set(OPENCASCADE_LIBRARIES -Wl,--start-group ${OPENCASCADE_LIBRARIES} -Wl,--end-group ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT APPLE AND NOT WIN32)
|
||||
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
|
||||
endif()
|
||||
@@ -656,6 +657,10 @@ if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
endif()
|
||||
else()
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
@@ -755,6 +760,8 @@ if(NOT SCHEMA_VERSIONS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "IFC SCHEMA_VERSIONS that will be used for the build: ${SCHEMA_VERSIONS}.")
|
||||
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
add_definitions(-DHAS_SCHEMA_${schema})
|
||||
endforeach()
|
||||
@@ -837,7 +844,7 @@ if (BUILD_IFCGEOM)
|
||||
if (WASM_BUILD)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
|
||||
else()
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -900,7 +907,7 @@ if(BUILD_IFCGEOM)
|
||||
add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES})
|
||||
set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
|
||||
if (NOT WASM_BUILD)
|
||||
target_link_libraries(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES})
|
||||
target_link_libraries(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
@@ -936,7 +943,7 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
add_library(Serializers_ifc${schema} STATIC ${SERIALIZERS_S_FILES})
|
||||
set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
|
||||
|
||||
|
||||
if (WASM_BUILD)
|
||||
target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES})
|
||||
else()
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ requirements:
|
||||
- {{ compiler('cxx') }}
|
||||
- ninja >=1.10.2
|
||||
- cmake
|
||||
- swig >=4.0.2
|
||||
- swig 4.1.1
|
||||
|
||||
host:
|
||||
- python
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#Look for an executable called sphinx-build
|
||||
find_program(SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
DOC "Path to sphinx-build executable")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
#Handle standard arguments to find_package like REQUIRED and QUIET
|
||||
find_package_handle_standard_args(Sphinx
|
||||
"Failed to find sphinx-build executable"
|
||||
SPHINX_EXECUTABLE)
|
||||
@@ -1,11 +0,0 @@
|
||||
#Look for an executable called sphinx-build
|
||||
find_program(SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
DOC "Path to sphinx-build executable")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
#Handle standard arguments to find_package like REQUIRED and QUIET
|
||||
find_package_handle_standard_args(Sphinx
|
||||
"Failed to find sphinx-build executable"
|
||||
SPHINX_EXECUTABLE)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
# IfcOpenShell C++ API documentation
|
||||
|
||||
This folder contains the setup to build the IfcOpenShell C++ API documentation from the source code.
|
||||
|
||||
## Generating the documentation
|
||||
|
||||
> Prerequisites:
|
||||
>
|
||||
> Make sure to have [Doxygen](https://www.doxygen.nl) and [Graphviz](https://graphviz.org) installed into your `$PATH` variable.
|
||||
>
|
||||
> The documentation also use the [doxygen-awesome](https://jothepro.github.io/doxygen-awesome-css) theme as a git submodule.
|
||||
|
||||
Build with the command (from within the `/docs/cpp-api` folder):
|
||||
|
||||
```shell
|
||||
$ doxygen
|
||||
```
|
||||
|
||||
To include the current git commit hash into the build documentation, use the following command:
|
||||
|
||||
```shell
|
||||
$ PROJECT_NUMBER=$(git rev-parse --short HEAD) doxygen
|
||||
```
|
||||
|
||||
This will extract the current commit hash in short version and sets the propper ENV variable used by doxygen.
|
||||
|
||||
The generation of the documentation might take a while depending on your systems hardware, as it is configured to generate the Class graphs using .
|
||||
|
||||
The resulting documentation is located unter `/cpp-api/output/html` and can be directly accessed with your browser:
|
||||
|
||||
```shell
|
||||
$ open ./output/html/index.html
|
||||
```
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 120 KiB |
@@ -1,240 +0,0 @@
|
||||
APPLY_DEFAULT_MATERIALS
|
||||
-----------------------
|
||||
|
||||
Given the command invocation:
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d.dae -yv --include attribute GlobalId 3bXiCStxP6Fgxdej$yc50U
|
||||
|
||||
You will find log messages along the lines of
|
||||
|
||||
[Warning] {3bXiCStxP6Fgxdej$yc50U} No material and surface styles for:
|
||||
#333=IfcCovering('3bXiCStxP6Fgxdej$yc50U',#1,'Compound Ceiling:Gypsum Board:187483',$,'Compound Ceiling:Gypsum Board',#17840,#17052,'187483',.CEILING.)
|
||||
|
||||
This means that there is no IfcStyledItem associated to the representation items and that the element does not have an IfcMaterial association with IfcMaterialRepresentation from which we can derive a style (colour) for the element.
|
||||
|
||||
The interactive session below shows how with this setting enabled you will get a default generated material from the IFC element entity type and material indices of 0 pointing to that. With this setting disabled the material index would be -1 to indicate a missing style. Note that there is one material index for every triangle in the list of `shp.geometry.faces`.
|
||||
|
||||
>>> import ifcopenshell, ifcopenshell.geom
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>> s = ifcopenshell.geom.settings()
|
||||
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
|
||||
>>>
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.material_ids
|
||||
(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1)
|
||||
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
|
||||
[]
|
||||
>>>
|
||||
>>> s.set(s.APPLY_DEFAULT_MATERIALS, True)
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.material_ids
|
||||
(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
>>> [(m.name, m.diffuse) for m in shp.geometry.materials]
|
||||
[('IfcCovering', (0.7, 0.7, 0.7))]
|
||||
|
||||
This is enabled by default for the IfcConvert serializers as they will not gracefully handle -1 material indices and allows users to quickly assign colours based on entity types in their modelling applications.
|
||||
|
||||
APPLY_LAYERSETS
|
||||
---------------
|
||||
|
||||
This setting is available in IfcConvert as `--enable-layerset-slicing`.
|
||||
|
||||
For IfcWall and IfcSlab elements, takes the associated IfcMaterialLayerSet and builds a set of surfaces to segment the building element geometry.
|
||||
|
||||
Note that enabling this settings is computationally intensive as it involves 3D Boolean operations.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
Duplex_A_20110907_optimized.ifc d2.dae --enable-layerset-slicing -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
BUILDING_LOCAL_PLACEMENT
|
||||
------------------------
|
||||
|
||||
This setting is available in IfcConvert using `--building-local-placement`.
|
||||
|
||||
In the typical IfcSite > IfcBuilding > IfcBuildingStorey > ... hierarchy of elements, don't incorporate the ObjectPlacement of the IfcBuilding and above in the placement of elements in the output. This is useful when there is a large offset in this placement that reduces precision in further processing.
|
||||
|
||||
CONVERT_BACK_UNITS
|
||||
------------------
|
||||
|
||||
This setting is available in IfcConvert using `--convert-back-units`.
|
||||
|
||||
Internally IfcOpenShell uses meters as the global length unit to do calculations. This setting restores the coordinate positions after conversion by multiplying the factor of the IfcUnit with UnitType=LENGTHUNIT into the output geometry coordinate values.
|
||||
|
||||
DISABLE_OPENING_SUBTRACTIONS
|
||||
----------------------------
|
||||
|
||||
This setting is available in IfcConvert using `--disable-opening-subtraction`.
|
||||
|
||||
As in most viewer applications, IfcOpeningElement geometry is subtracted from their host elements. This setting disables this behavior.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d1.dae -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
Duplex_A_20110907_optimized.ifc d3.dae --disable-opening-subtraction -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
Note that disabling this settings will reduce processing time and improve robustness as it involves 3D Boolean operations.
|
||||
|
||||
DISABLE_TRIANGULATION
|
||||
---------------------
|
||||
|
||||
To be used in conjunction with `USE_BREP_DATA`. Do not apply the triangulation and - when `USE_BREP_DATA` is set - return a OpenCASCADE serialized TopoDS_Shape from `create_shape()` and `iterator`.
|
||||
|
||||
>>> import ifcopenshell, ifcopenshell.geom
|
||||
>>> s = ifcopenshell.geom.settings()
|
||||
>>> s.set(s.DISABLE_TRIANGULATION, True)
|
||||
>>> s.set(s.USE_BREP_DATA, True)
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> print(shp.geometry.brep_data)
|
||||
|
||||
CASCADE Topology V1, (c) Matra-Datavision
|
||||
Locations 0
|
||||
Curve2ds 0
|
||||
Curves 12
|
||||
1 4.6750000000000034 -8.0749999999999904 2.657 -2.0455514041918775e-15 -1 0
|
||||
1 4.6750000000000034 -8.0749999999999904 2.657 1 -3.435893306383461e-15 0
|
||||
1 6.2260000000000044 -8.0749999999999957 2.657 -2.0455514041918724e-15 -1 0
|
||||
1 6.226 -10.246000000000031 2.657 -1 6.8717866127669219e-15 0
|
||||
...
|
||||
|
||||
EDGE_ARROWS
|
||||
-----------
|
||||
|
||||
When `INCLUDE_CURVES` is true and geometric elements include curves (such as the wall axis), add arrow heads to the edges to indicate direction of the curve.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d4.dae --model --plan --edge-arrows -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
EXCLUDE_SOLIDS_AND_SURFACES
|
||||
---------------------------
|
||||
|
||||
Exclude faces, shells and solids from geometrical output. Implied when using `--plan` without `--model` in IfcConvert.
|
||||
|
||||
FASTER_BOOLEANS
|
||||
---------------
|
||||
|
||||
NOTE: Only applicable when using OCCT 6.9 and earlier.
|
||||
|
||||
This setting is available in IfcConvert using `--merge-boolean-operands`.
|
||||
|
||||
Fuse the collection of all boolean operands into a single union before applying the boolean subtraction, as opposed to doing individual subtractions. This likely improves performance. From OCCT 7.0 onwards the boolean operations with multiple arguments is used.
|
||||
|
||||
GENERATE_UVS
|
||||
------------
|
||||
|
||||
This setting is available in IfcConvert using `--generate-uvs`.
|
||||
|
||||
Applies a box projection on the generated geometry for the element to obtain UV coordinates. This is purely generated, it does not involve texture coordinates stored in the IFC model.
|
||||
|
||||
Duplex_A_20110907_optimized.ifc d5.dae --generate-uvs -yv --include attribute GlobalId 2O2Fr$t4X7Zf8NOew3FNr2
|
||||
|
||||

|
||||
|
||||
INCLUDE_CURVES
|
||||
--------------
|
||||
|
||||
This setting is available in IfcConvert using `--plan`.
|
||||
|
||||
Include edge and wire geometries in the geometric output.
|
||||
|
||||
LAYERSET_FIRST
|
||||
--------------
|
||||
|
||||
This setting is available in IfcConvert using `--layerset-first`.
|
||||
|
||||
When not using APPLY_LAYERSETS, take the first material layer from the set to use as the material for the overall element.
|
||||
|
||||
NO_NORMALS
|
||||
----------
|
||||
|
||||
This setting is available in IfcConvert using `--no-normals`.
|
||||
|
||||
Do not emit normals on geometric output
|
||||
|
||||
SEARCH_FLOOR
|
||||
------------
|
||||
|
||||
Note: Only applicable to Collada .DAE output when used from IfcConvert.
|
||||
|
||||
This setting is available in IfcConvert using `--use-element-hierarchy`.
|
||||
|
||||
Include the spatial hierarchy in the elements.
|
||||
|
||||
SEW_SHELLS
|
||||
----------
|
||||
|
||||
This setting is available in IfcConvert using `--orient-shells`.
|
||||
|
||||
Re-orient or sew connected face sets to have a consistent outwards orientation.
|
||||
|
||||
SITE_LOCAL_PLACEMENT
|
||||
--------------------
|
||||
|
||||
This setting is available in IfcConvert using `--site-local-placement`.
|
||||
|
||||
See `BUILDING_LOCAL_PLACEMENT`, but exclude also the ObjectPlacement of the IfcSite.
|
||||
|
||||
USE_BREP_DATA
|
||||
-------------
|
||||
|
||||
See `DISABLE_TRIANGULATION`.
|
||||
|
||||
USE_PYTHON_OPENCASCADE
|
||||
----------------------
|
||||
|
||||
Note: Only available when an import of `OCC.Core.BRepTools` or `OCC.BRepTools` succeeds.
|
||||
|
||||
This implies `USE_WORLD_COORDS` `USE_BREP_DATA` and `DISABLE_TRIANGULATION`. The serialized TopoDS_Shape of `USE_BREP_DATA` is deserialized by Python OpenCASCADE.
|
||||
|
||||
USE_WORLD_COORDS
|
||||
----------------
|
||||
|
||||
Apply the ObjectPlacement of the building elements to the geometric output. This is implied when using the Wavefront .OBJ output in IfcConvert. Note that this also eliminates the possibility for geometric elements to point to the same interpreted geometry result.
|
||||
|
||||
VALIDATE_QUANTITIES
|
||||
-------------------
|
||||
|
||||
This setting is available in IfcConvert using `--validate`.
|
||||
|
||||
Running IfcConvert with `--validate` will set a non-zero exit code when ever a log message with severity equal or greater than ERROR has been emitted.
|
||||
|
||||
Currently for internal use only. For every building element geometry converted, looks for an associated quantity set where the OwnerHistory's organization name is IfcOpenShell. And looks for the quantities "Total Surface Area", "Volume", "Shape Validation Properties.Surface Genus" and validates these according to the interpreted geometry definition. Emit Logger::Error when calculated values are outside of the tolerance range for the value stored in the model.
|
||||
|
||||
WELD_VERTICES
|
||||
-------------
|
||||
|
||||
Note: In Python, this setting is *on* by default.
|
||||
|
||||
Note: This setting only affects triangulated output.
|
||||
|
||||
This setting is available in IfcConvert using `--weld-vertices`.
|
||||
|
||||
Discards normals and joins vertices solely based on position. This is useful when output is to be modified in a modeling application.
|
||||
|
||||
>>> import ifcopenshell, ifcopenshell.geom
|
||||
>>> s = ifcopenshell.geom.settings()
|
||||
>>> s.set(s.WELD_VERTICES, False)
|
||||
>>> f = ifcopenshell.open("Duplex_A_20110907_optimized.ifc")
|
||||
>>> c = f["3bXiCStxP6Fgxdej$yc50U"]
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.verts
|
||||
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.657, 4.674999999999999, -10.24600000000002, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226, -10.24600000000003, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226, -10.24600000000003, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6, 4.675000000000003, -8.07499999999999, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 6.226000000000004, -8.074999999999996, 2.657, 6.226000000000004, -8.074999999999996, 2.6)
|
||||
>>> shp.geometry.normals
|
||||
(3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 3.059754518198021e-17, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, 2.110175529791737e-16, 0.0, -1.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, 6.8717866127669046e-15, 1.0, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, -1.0, 1.79434333701042e-15, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0, 3.4358933063834523e-15, 1.0, 0.0)
|
||||
>>>
|
||||
>>> s.set(s.WELD_VERTICES, True)
|
||||
>>> shp = ifcopenshell.geom.create_shape(s, c)
|
||||
>>> shp.geometry.verts
|
||||
(4.675000000000003, -8.07499999999999, 2.657, 4.674999999999999, -10.24600000000002, 2.657, 6.226000000000004, -8.074999999999996, 2.657, 6.226, -10.24600000000003, 2.657, 4.675000000000003, -8.07499999999999, 2.6, 4.674999999999999, -10.24600000000002, 2.6, 6.226000000000004, -8.074999999999996, 2.6, 6.226, -10.24600000000003, 2.6)
|
||||
>>> shp.geometry.normals
|
||||
()
|
||||
+4
-3
@@ -76,7 +76,7 @@ PROJECT_NAME = "IfcOpenShell"
|
||||
USE_CURRENT_PYTHON_VERSION = os.getenv("USE_CURRENT_PYTHON_VERSION")
|
||||
ADD_COMMIT_SHA = os.getenv("ADD_COMMIT_SHA")
|
||||
|
||||
PYTHON_VERSIONS = ["3.6.14", "3.7.13", "3.8.13", "3.9.11", "3.10.3", "3.11.0"]
|
||||
PYTHON_VERSIONS = ["3.6.14", "3.7.13", "3.8.13", "3.9.11", "3.10.3", "3.11.7", "3.12.1"]
|
||||
JSON_VERSION = "v3.6.1"
|
||||
OCE_VERSION = "0.18.3"
|
||||
OCCT_VERSION = "7.5.3"
|
||||
@@ -892,8 +892,9 @@ if "IfcOpenShell-Python" in targets:
|
||||
module_dir = os.path.dirname(run([python_executable, "-c", "import inspect, ifcopenshell; print(inspect.getfile(ifcopenshell))"]))
|
||||
|
||||
if platform.system() != "Darwin":
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
|
||||
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)
|
||||
|
||||
return module_dir
|
||||
|
||||
|
||||
+87
-47
@@ -50,24 +50,31 @@ PYLIBDIR:=python3.10
|
||||
PYNUMBER:=310
|
||||
PYPI_VERSION:=3.10
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
PYLIBDIR:=python3.11
|
||||
PYNUMBER:=311
|
||||
PYPI_VERSION:=3.11
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), linux)
|
||||
PYPI_PLATFORM:=--platform manylinux_2_17_x86_64
|
||||
LXML_ARCH:=manylinux_2_28_x86_64
|
||||
SHAPELY_ARCH:=manylinux_2_17_x86_64.manylinux2014_x86_64
|
||||
PILLOW_ARCH:=manylinux_2_28_x86_64
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py39h40a70d0_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py39hdfdd6bb_0.conda
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/linux-64/hpp-fcl-2.4.0-py39h359ec1e_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/linux-64/eigenpy-3.2.0-py39hb1babde_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py39h7c9e3ff_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/19/d9/a69c6aff5673554df48120565a14a50eaa41d29ae03b02faa0b023666318/lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/2d/f2/8ec281d357e8bb7d08dc8d727f0e4c8ef3dae7d3fa75c69c8e452bb82d50/shapely-2.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/01/61/3ff85fb4bb596ce3d223c8fcf93c8df5c12bc8899dfb4fb3cb1c5b20dd5f/Pillow-9.2.0-cp39-cp39-manylinux_2_28_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/linux-64/hpp-fcl-2.3.4-py310h995690b_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/linux-64/eigenpy-3.1.0-py310hf02b7e0_0.conda
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/linux-64/hpp-fcl-2.4.0-py310hd002f03_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/linux-64/eigenpy-3.2.0-py310hcfe0b05_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py310hc4a4660_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/25/1e/19b46d8e8881fe0df2e20945d51919eeb1817836d62a90efa8506530e45c/lxml-4.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/a8/a5/403728b5614b28083f6424dfdefec5fcf58068495fb03bb08532671c642f/shapely-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/f6/51/320986ebd6d46a0e95c2240468ced73153b691ce07617078bcdf30c609ec/Pillow-9.2.0-cp310-cp310-manylinux_2_28_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/linux-64/hpp-fcl-2.4.0-py311h04f086a_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/linux-64/eigenpy-3.2.0-py311h995a085_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/linux-64/boost-1.78.0-py311h59ea3da_3.tar.bz2
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/linux-64/assimp-5.0.1-hedfc422_6.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/linux-64/qhull-2020.2-h4bd325d_2.tar.bz2
|
||||
@@ -78,21 +85,25 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM), macos)
|
||||
PYPI_PLATFORM:=--platform macosx_10_9_x86_64
|
||||
SHAPELY_ARCH:=macosx_10_9_x86_64
|
||||
PILLOW_ARCH:=macosx_10_10_x86_64
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py39hd85b194_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py39hc4d6e28_0.conda
|
||||
LXML_ARCH:=macosx_11_0_x86_64
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-64/hpp-fcl-2.4.0-py39h26350b9_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-64/eigenpy-3.2.0-py39h3323527_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py39h953a6b8_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/b8/74/a71f7ad72e8db54ce899efab84507b801660750cbbfa6a39e6717557d36a/lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/36/a4/7e542a209f862f967d7cb8e939eff155f4294a27d17e16441fb8bdd51a2c/shapely-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/88/7a/ddfe28b485b623361457d4783007c1f9ba83a87f93e7fec32f64793efb6c/Pillow-9.2.0-cp39-cp39-macosx_10_10_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-64/hpp-fcl-2.3.4-py310h1db6f5f_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-64/eigenpy-3.1.0-py310h43da829_0.conda
|
||||
LXML_ARCH:=macosx_11_0_x86_64
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-64/hpp-fcl-2.4.0-py310ha216469_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-64/eigenpy-3.2.0-py310h33a8c9b_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py310h3e792ce_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/a1/44/17b7dac7a18807d30e2fe10c3328c152808f5464565e230bfd0e77f178c6/lxml-4.8.0-cp310-cp310-macosx_10_15_x86_64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/1f/2a/dc3353c2431cf53e8d04bb8fba27e584410ca3435c9c85f76d71bf0c0e80/shapely-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/d8/60/b13c00d403f34110e96c1b5c0afa73ce461efe3fe960c3a7e3e7fe190d82/Pillow-9.2.0-cp310-cp310-macosx_10_10_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
LXML_ARCH:=macosx_11_0_universal2
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-64/hpp-fcl-2.4.0-py311hebdd1a2_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-64/eigenpy-3.2.0-py311h62e90b6_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-64/boost-1.78.0-py311h349b758_4.tar.bz2
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-64/assimp-5.0.1-h1224e73_6.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-64/qhull-2020.2-h940c156_2.tar.bz2
|
||||
@@ -103,21 +114,23 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
PYPI_PLATFORM:=--platform macosx_11_0_arm64
|
||||
LXML_ARCH:=macosx_11_0_universal2
|
||||
SHAPELY_ARCH:=macosx_11_0_arm64
|
||||
PILLOW_ARCH:=macosx_11_0_arm64
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py39hc34188a_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py39h13cfc01_0.conda
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-arm64/hpp-fcl-2.4.0-py39h82b2ff2_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-arm64/eigenpy-3.2.0-py39h3a9e884_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py39h99de9ae_4.tar.bz2
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h9eb174b_0.tar.bz2
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/ea/aa/45fbd031edf3149cb767d8b9f9db45d5faf0324d743c6b8fb0298cc022d0/shapely-2.0.1-cp39-cp39-macosx_11_0_arm64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/aa/bc/21097cd891dd2fa02f2b3d767e02e883e026482e59d29975d1bc30024aa3/Pillow-9.2.0-cp39-cp39-macosx_11_0_arm64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/osx-arm64/hpp-fcl-2.3.4-py310h46fc4cd_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/osx-arm64/eigenpy-3.1.0-py310ha2643af_0.conda
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-arm64/hpp-fcl-2.4.0-py310hdb6c3eb_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-arm64/eigenpy-3.2.0-py310h96e9823_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py310h629746b_4.tar.bz2
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/ec/41/d59208743e737184e1b403e95a937aebb022b8459e99efbcd5208fc8be46/shapely-2.0.1-cp310-cp310-macosx_11_0_arm64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/0c/5f/117b653cad585f3aedfe0de996c292e67d4b020ed77f652e5a6c8c24f908/Pillow-9.2.0-cp310-cp310-macosx_11_0_arm64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/osx-arm64/hpp-fcl-2.4.0-py311hc0c29b9_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/osx-arm64/eigenpy-3.2.0-py311h24fa84d_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/osx-arm64/boost-1.78.0-py311h5c64717_4.tar.bz2
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-arm64/assimp-5.0.1-h0f81e16_7.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/osx-arm64/qhull-2020.2-hc021e02_2.tar.bz2
|
||||
@@ -128,21 +141,23 @@ endif
|
||||
|
||||
ifeq ($(PLATFORM), win)
|
||||
PYPI_PLATFORM:=--platform win_amd64
|
||||
LXML_ARCH:=win_amd64
|
||||
SHAPELY_ARCH:=win_amd64
|
||||
PILLOW_ARCH:=win_amd64
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/win-64/hpp-fcl-2.3.4-py39h39b25cb_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/win-64/eigenpy-3.1.0-py39hb6c915b_0.conda
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/win-64/hpp-fcl-2.4.0-py39hf3ebc58_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/win-64/eigenpy-3.2.0-py39ha1f6a47_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py39hea4d8d1_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/72/d4/426ecb8849c47c3e370c87aa0ac05d85768df917ffea27fcd6686a5e6495/lxml-4.6.3-cp39-cp39-win_amd64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/a7/ae/eab645c4075093584b7a65ab71cb8ff4563a015bd935c9b55dba14b2c1eb/shapely-2.0.1-cp39-cp39-win_amd64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/19/3f/b4d4bcf05dbcbe07f2e9613a8f4180c297395e73a91d8ad22c32c6624f8c/Pillow-9.2.0-cp39-cp39-win_amd64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.3.4/download/win-64/hpp-fcl-2.3.4-py310heb59267_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.1.0/download/win-64/eigenpy-3.1.0-py310hd146abe_0.conda
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/win-64/hpp-fcl-2.4.0-py310h1bf3f0a_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/win-64/eigenpy-3.2.0-py310h7fb871d_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py310h220cb41_4.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/f6/71/65c80a4caa1617a4c6e8fe1500cebb179db96232e2f623bfe6a1f4294e39/lxml-4.8.0-cp310-cp310-win_amd64.whl
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/81/8a/7ac076a86b2632f1872284c5e60ed5f2fc26094875a85b35d9fa17b52504/shapely-2.0.1-cp310-cp310-win_amd64.whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/02/55/67a3c17b9e7d972ed8c246f104da99ca4f3ea42fba566697e479011b84b6/Pillow-9.2.0-cp310-cp310-win_amd64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/2.4.0/download/win-64/hpp-fcl-2.4.0-py311hd263b2c_0.conda
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/3.2.0/download/win-64/eigenpy-3.2.0-py311hd354db1_0.conda
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.78.0/download/win-64/boost-1.78.0-py311h12feb9d_3.tar.bz2
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.2.5/download/win-64/assimp-5.2.5-h4dcb625_0.tar.bz2
|
||||
QHULL_URL:=https://anaconda.org/conda-forge/qhull/2020.2/download/win-64/qhull-2020.2-h70d2c02_2.tar.bz2
|
||||
@@ -151,6 +166,33 @@ BOOSTCPP_URL:=https://anaconda.org/conda-forge/boost-cpp/1.78.0/download/win-64/
|
||||
ZLIB_URL:=https://anaconda.org/conda-forge/zlib/1.2.11/download/win-64/zlib-1.2.11-h62dcd97_1010.tar.bz2
|
||||
endif
|
||||
|
||||
LXML_NAME:=lxml
|
||||
LXML_VER:=4.9.4
|
||||
SHAPELY_NAME:=shapely
|
||||
SHAPELY_VER:=2.0.2
|
||||
PILLOW_NAME:=pillow
|
||||
PILLOW_PKG_NAME:=Pillow
|
||||
PILLOW_VER:=9.5.0
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/s/$(SHAPELY_NAME)/$(SHAPELY_NAME)-$(SHAPELY_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(SHAPELY_ARCH).whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/p/$(PILLOW_NAME)/$(PILLOW_PKG_NAME)-$(PILLOW_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(PILLOW_ARCH).whl
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
ifeq ($(PYVERSION), py39)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h0520ce3_1.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py311h246f609_1.tar.bz2
|
||||
endif
|
||||
else
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/l/$(LXML_NAME)/$(LXML_NAME)-$(LXML_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(LXML_ARCH).whl
|
||||
endif
|
||||
$(info $$LXML_URL is [${LXML_URL}])
|
||||
$(info $$SHAPELY_URL is [${SHAPELY_URL}])
|
||||
$(info $$PILLOW_URL is [${PILLOW_URL}])
|
||||
|
||||
.PHONY: bump
|
||||
bump:
|
||||
cd . && $(SED) "s/$(OLD)/$(NEW)/" Makefile
|
||||
@@ -629,13 +671,6 @@ endif
|
||||
cp -r dist/working/IFC2JSON_python-master/file_converters/ifcjson dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides OpenLCA functionality
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/85/33/f91b96e9e8608ff65a003b692e8a9cdd60f2178f60617e5b1d21334c009c/olca-ipc-0.0.10.tar.gz
|
||||
cd dist/working && tar -xzvf olca-ipc*
|
||||
cd dist/working/olca-ipc-0.0.10/ && cp -r olca ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides Brickschema functionality
|
||||
mkdir dist/working
|
||||
# For now lets bundle the latest nightly schema
|
||||
@@ -661,6 +696,11 @@ endif
|
||||
# Required for Desktop icon and file association
|
||||
cp -r blenderbim/libs/desktop dist/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
|
||||
|
||||
# Remove dependencies also bundled with Blender
|
||||
rm -rf dist/blenderbim/libs/site/packages/numpy
|
||||
rm -rf dist/blenderbim/libs/site/packages/numpy.libs
|
||||
|
||||
@@ -24,6 +24,10 @@ import blenderbim
|
||||
import importlib
|
||||
from . import handler, ui, prop, operator, helper
|
||||
|
||||
try:
|
||||
from blenderbim.translations import translations_dict
|
||||
except ImportError:
|
||||
translations_dict = {}
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
modules = {
|
||||
@@ -44,6 +48,7 @@ modules = {
|
||||
"spatial": None,
|
||||
"void": None,
|
||||
"aggregate": None,
|
||||
"nest": None,
|
||||
"geometry": None,
|
||||
"fm": None,
|
||||
"resource": None,
|
||||
@@ -67,7 +72,6 @@ modules = {
|
||||
"document": None,
|
||||
"pset_template": None,
|
||||
"clash": None,
|
||||
"lca": None,
|
||||
"csv": None,
|
||||
"tester": None,
|
||||
"bimtester": None,
|
||||
@@ -92,28 +96,28 @@ for name in modules.keys():
|
||||
classes = [
|
||||
operator.AddIfcFile,
|
||||
operator.BIM_OT_add_section_plane,
|
||||
operator.BIM_OT_open_webbrowser,
|
||||
operator.BIM_OT_remove_section_plane,
|
||||
operator.BIM_OT_show_description,
|
||||
operator.EditBlenderCollection,
|
||||
operator.FileAssociate,
|
||||
operator.FileUnassociate,
|
||||
operator.OpenUpstream,
|
||||
operator.OpenUri,
|
||||
operator.SwitchTab,
|
||||
operator.SetTab,
|
||||
operator.ReloadIfcFile,
|
||||
operator.RemoveIfcFile,
|
||||
operator.SelectDataDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.ReloadSelectedIfcFile,
|
||||
operator.SelectSchemaDir,
|
||||
operator.FileAssociate,
|
||||
operator.FileUnassociate,
|
||||
operator.SelectURIAttribute,
|
||||
operator.EditBlenderCollection,
|
||||
operator.BIM_OT_open_webbrowser,
|
||||
operator.BIM_OT_show_description,
|
||||
operator.SetTab,
|
||||
operator.SwitchTab,
|
||||
prop.StrProperty,
|
||||
operator.BIM_OT_enum_property_search, # /!\ Register AFTER prop.StrProperty
|
||||
prop.ObjProperty,
|
||||
prop.Attribute,
|
||||
prop.BIMAreaProperties,
|
||||
prop.BIMTabProperties,
|
||||
prop.BIMProperties,
|
||||
prop.IfcParameter,
|
||||
prop.PsetQto,
|
||||
@@ -180,6 +184,7 @@ addon_keymaps = []
|
||||
icons = None
|
||||
is_registering = False
|
||||
last_commit_hash = "8888888"
|
||||
overridden_scene_panels = dict()
|
||||
|
||||
|
||||
def on_register(scene):
|
||||
@@ -204,6 +209,7 @@ def register():
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
bpy.types.Screen.BIMAreaProperties = bpy.props.CollectionProperty(type=prop.BIMAreaProperties)
|
||||
bpy.types.Screen.BIMTabProperties = bpy.props.PointerProperty(type=prop.BIMTabProperties)
|
||||
bpy.types.Collection.BIMCollectionProperties = bpy.props.PointerProperty(type=prop.BIMCollectionProperties)
|
||||
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
@@ -247,6 +253,8 @@ def register():
|
||||
except:
|
||||
pass
|
||||
|
||||
bpy.app.translations.register("blenderbim", translations_dict)
|
||||
|
||||
|
||||
def unregister():
|
||||
global icons
|
||||
@@ -284,17 +292,10 @@ def unregister():
|
||||
km.keymap_items.remove(kmi)
|
||||
addon_keymaps.clear()
|
||||
|
||||
for panel in [
|
||||
"SCENE_PT_scene",
|
||||
"SCENE_PT_unit",
|
||||
"SCENE_PT_physics",
|
||||
"SCENE_PT_rigid_body_world",
|
||||
"SCENE_PT_audio",
|
||||
"SCENE_PT_keying_sets",
|
||||
"SCENE_PT_simulation",
|
||||
"SCENE_PT_custom_props",
|
||||
]:
|
||||
try:
|
||||
bpy.utils.unregister_class(getattr(handler, f"Override_{panel}"))
|
||||
except:
|
||||
pass
|
||||
for panel in tuple(overridden_scene_panels.keys()):
|
||||
original_panel, override_panel = overridden_scene_panels[panel]
|
||||
bpy.utils.unregister_class(override_panel)
|
||||
bpy.utils.register_class(original_panel)
|
||||
del overridden_scene_panels[panel]
|
||||
|
||||
bpy.app.translations.unregister("blenderbim")
|
||||
|
||||
@@ -0,0 +1,993 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
|
||||
FILE_NAME('/dev/null','2024-01-24T15:32:17+05:00',(),(),'IfcOpenShell v0.7.0-6c9e130ca','IfcOpenShell v0.7.0-6c9e130ca','Nobody');
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROJECT('3GRx5GJtv7EvI86hmjeQD6',$,'Landscape Assets Library',$,$,$,$,(#10,#14),#5);
|
||||
#2=IFCPROJECTLIBRARY('1Go1D2HIr9AR4M6PdJb8DW',$,'Landscape Assets Library',$,$,$,$,$,$);
|
||||
#3=IFCRELDECLARES('2Nc$sSRrvCzOJbe4Q6ZcVa',$,$,$,#1,(#2));
|
||||
#4=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
|
||||
#5=IFCUNITASSIGNMENT((#4));
|
||||
#6=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#7=IFCDIRECTION((0.,0.,1.));
|
||||
#8=IFCDIRECTION((1.,0.,0.));
|
||||
#9=IFCAXIS2PLACEMENT3D(#6,#7,#8);
|
||||
#10=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,$);
|
||||
#11=IFCCARTESIANPOINT((0.,0.));
|
||||
#12=IFCDIRECTION((1.,0.));
|
||||
#13=IFCAXIS2PLACEMENT2D(#11,#12);
|
||||
#14=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#13,$);
|
||||
#15=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$);
|
||||
#16=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Plan',*,*,*,*,#14,$,.PLAN_VIEW.,$);
|
||||
#17=IFCCARTESIANPOINTLIST2D(((-331.408782958984,488.559936523438),(-428.486114501953,371.370391845703),(-408.744873046875,331.425659179688),(-492.345001220703,263.470184326172),(-519.991760253906,89.2266616821289),(-366.53076171875,65.1004943847656),(-523.9287109375,51.0255508422852),(-542.778625488281,-161.150390625),(-455.430816650391,-198.061676025391),(-467.317413330078,-264.261047363281),(-389.842987060547,-378.319213867188),(-351.178894042969,-382.372741699219),(-243.823715209961,-498.601684570312),(-171.287063598633,-509.852447509766),(-182.036499023438,-454.125518798828),(-123.127815246582,-538.493591308594),(208.583557128906,-495.693969726562),(174.199142456055,-387.101898193359),(269.968353271484,-457.362365722656),(517.720397949219,-208.39501953125),(467.592559814453,-165.981643676758),(535.54443359375,-138.483825683594),(546.240173339844,47.7887229919434),(425.388610839844,29.4520435333252),(514.287658691406,107.907821655273),(467.776489257812,312.002685546875),(374.896423339844,365.066589355469),(325.083190917969,461.613433837891),(224.657806396484,496.0244140625),(105.845329284668,424.517761230469),(191.164672851562,514.677307128906),(-7.41858577728271,553.592407226562),(-105.371849060059,531.902709960938),(-180.417175292969,499.200317382812)));
|
||||
#18=IFCINDEXEDPOLYCURVE(#17,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#19=IFCCARTESIANPOINTLIST3D(((80.,0.,0.),(40.,69.2820323027551,0.),(-40.,69.2820323027551,0.),(-80.,9.79717439317883E-15,0.),(-40.,-69.2820323027551,0.),(40.,-69.2820323027551,0.),(80.,0.,280.),(40.,69.2820323027551,280.),(-40.,69.2820323027551,280.),(-80.,9.79717439317883E-15,280.),(-40.,-69.2820323027551,280.),(40.,-69.2820323027551,280.),(570.140986817674,-5.11998806339175,502.765430824539),(261.339072714044,511.863483235935,520.441255965265),(-271.449977559115,464.840881207563,498.631051036932),(-577.400357563209,-18.0002392785791,529.745674601363),(-246.747896537159,-522.096293601777,523.07445182747),(289.929723989709,-497.828722152031,481.563368832141),(502.264135660384,-3.10815712380199,727.667741239885),(256.486268377103,397.638199139059,733.570036889682),(-210.099579404528,457.859720268934,722.445245365077),(-522.479901100414,-35.7080296205946,687.931736233252),(-213.081169792834,-438.257812253687,704.648197605265),(273.503462940155,-437.429578762916,717.812431534607),(409.72756228227,-31.3204193188668,937.51589967911),(231.939555298324,334.085354425246,911.578097173966),(-213.440011711198,325.481782873574,931.184023328963),(-391.4385670944,11.3681475906559,933.839400395571),(-181.597613330968,-384.045646583411,936.269525762716),(198.107253544529,-351.52926490917,903.558501964971),(358.836914477244,-29.0443800107266,1124.54961826854),(191.636382145782,325.816574427016,1143.76409675514),(-175.686180114122,275.257306965059,1132.35007279295),(-330.55780048986,-23.1508504281077,1121.17416888324),(-172.687090174965,-317.707089809191,1159.279616419),(192.616008554028,-273.601791847896,1147.14103266758),(252.691797114565,-4.70084047240072,1330.07490310776),(147.138603790187,216.221351494253,1352.71275883304),(-162.078730999078,224.60205813657,1371.67941135993),(-271.544406853979,26.607279268613,1378.19571732018),(-150.451939922955,-226.516554345382,1395.27272058484),(133.281231324475,-220.990480915293,1334.23398662872),(187.5691337229,-2.77622907865673,1575.7384942221),(88.4380124532162,169.216774598146,1585.64117034361),(-94.8941720337192,139.038794764388,1578.6341137138),(-154.588503036945,-6.10749408831602,1549.40002660187),(-129.962875945536,-160.551322551302,1550.49839466833),(64.8441918513045,-191.270989336927,1579.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
|
||||
#20=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#21=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#22=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#23=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#24=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#25=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#26=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#27=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#28=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#29=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#30=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#31=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#32=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#33=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#34=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#35=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#36=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#37=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#38=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#39=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#40=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#41=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#42=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#43=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#44=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#45=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#46=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#47=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#48=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#49=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#50=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#51=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#52=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#53=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#54=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#55=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#56=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#57=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#58=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#59=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#60=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#61=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#62=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#63=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#64=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#65=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#66=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#67=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#68=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#69=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#70=IFCPOLYGONALFACESET(#19,$,(#20,#21,#22,#23,#24,#25,#26,#27,#28,#29,#30,#31,#32,#33,#34,#35,#36,#37,#38,#39,#40,#41,#42,#43,#44,#45,#46,#47,#48,#49,#50,#51,#52,#53,#54,#55,#56,#57,#58,#59,#60,#61,#62,#63,#64,#65,#66,#67,#68,#69),$);
|
||||
#71=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#18));
|
||||
#72=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#70));
|
||||
#73=IFCGEOGRAPHICELEMENTTYPE('34zHVx8cX0dRoaynJ1QKTg',$,'Cone Tree (1.8m)',$,$,$,(#78,#83),$,$,.NOTDEFINED.);
|
||||
#74=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#75=IFCDIRECTION((1.,0.,0.));
|
||||
#76=IFCDIRECTION((0.,0.,1.));
|
||||
#77=IFCAXIS2PLACEMENT3D(#74,#76,#75);
|
||||
#78=IFCREPRESENTATIONMAP(#77,#72);
|
||||
#79=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#80=IFCDIRECTION((1.,0.,0.));
|
||||
#81=IFCDIRECTION((0.,0.,1.));
|
||||
#82=IFCAXIS2PLACEMENT3D(#79,#81,#80);
|
||||
#83=IFCREPRESENTATIONMAP(#82,#71);
|
||||
#84=IFCRELDECLARES('2hc5gFJQT6VP_pTBscCuS_',$,$,$,#2,(#840,#409,#680,#208,#613,#73,#342,#773,#275,#479,#742,#907,#711,#141,#546,#974,#444));
|
||||
#85=IFCCARTESIANPOINTLIST2D(((-1281.64282226562,1889.38659667969),(-1657.06579589844,1436.1845703125),(-1580.72131347656,1281.70812988281),(-1904.02453613281,1018.90686035156),(-2010.94165039062,345.062408447266),(-1417.46850585938,251.760314941406),(-2026.16674804688,197.328903198242),(-2099.06420898438,-623.209899902344),(-1761.26782226562,-765.955322265625),(-1807.236328125,-1021.96527099609),(-1507.62292480469,-1463.05749511719),(-1358.09887695312,-1478.73352050781),(-942.928833007812,-1928.220703125),(-662.411010742188,-1971.73022460938),(-703.981872558594,-1756.21984863281),(-476.166870117188,-2082.49291992188),(806.646179199219,-1916.97583007812),(673.672790527344,-1497.02233886719),(1044.03686523438,-1768.73767089844),(2002.15771484375,-805.917053222656),(1808.30041503906,-641.893615722656),(2071.087890625,-535.552490234375),(2112.45092773438,184.811248779297),(1645.0869140625,113.898612976074),(1988.88244628906,417.307220458984),(1809.01171875,1206.59436035156),(1449.82067871094,1411.80627441406),(1257.18005371094,1785.17761230469),(868.809387207031,1918.25366210938),(409.3310546875,1641.71911621094),(739.282836914062,1990.38916015625),(-28.6895751953125,2140.8837890625),(-407.5,2057.00415039062),(-697.719543457031,1930.53576660156)));
|
||||
#86=IFCINDEXEDPOLYCURVE(#85,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#87=IFCCARTESIANPOINTLIST3D(((220.,0.,0.),(110.,190.525588832576,0.),(-110.,190.525588832577,0.),(-220.,2.69422295812418E-14,0.),(-110.,-190.525588832576,0.),(110.,-190.525588832576,0.),(220.,0.,740.),(110.,190.525588832576,740.),(-110.,190.525588832577,740.),(-220.,2.69422295812418E-14,740.),(-110.,-190.525588832576,740.),(110.,-190.525588832576,740.),(2227.84155681395,-42.6665671949312,2823.99763782354),(916.158939283701,2080.25825808339,2971.29618066292),(-1000.41647965929,1688.40324118029,2789.54447292681),(-2288.33631302674,-150.00199398816,3048.8330026304),(-794.565804476328,-2165.53167779874,2993.23947951463),(1154.41436658091,-1963.30191571753,2647.31378788689),(1998.64557494764,-25.9013093650166,4925.80260557047),(1043.94112536474,1419.75032646046,4974.98840265211),(-657.385383926618,1921.59633587608,4882.28180661374),(-2167.11028694789,-297.566913504955,4594.66923051519),(-682.231970495834,-1758.24710241569,4733.97307528197),(1185.75108005685,-1751.34515665926,4843.67502469316),(1563.95190790781,-261.00349432389,6902.15630684973),(1007.60740526381,1181.51272302971,6686.0079526402),(-853.444542037762,1109.81629343244,6849.3906705985),(-1411.54361467555,94.7345632554656,6871.51881282023),(-588.091222202507,-1597.84849101442,6891.76985754645),(725.67155731552,-1326.87864372908,6619.17799256523),(1476.3076206437,-242.036500089388,8688.38967604738),(839.969851214854,1403.97565889549,8848.51033010232),(-707.051500951019,982.648430045852,8753.39346375077),(-1240.6483374155,-192.923753567565,8660.26093116989),(-682.059084791378,-1336.39662041362,8977.80632730116),(848.133404616898,-968.852470736159,8876.65146270604),(928.209420399157,-39.1736706033394,10628.7194306599),(637.377253807116,782.05157030683,10817.3682283706),(-761.878313881205,851.890792326142,10975.4236660946),(-1085.31450156094,221.727327238442,11029.7262157634),(-664.988388246851,-867.844927399578,11172.0345763022),(521.899149926181,-821.794315482163,10663.3784600012),(721.965003246392,-23.1352423221394,12903.5350708985),(316.42788155458,681.716198690303,12986.057371911),(-370.229211392105,430.233033408991,12927.6652333293),(-447.126414196768,-50.8957840693003,12684.0478407298),(-662.468410657245,-609.504098299938,12693.2009079504),(119.812709871982,-865.501321513485,12935.3041410664),(0.05,0.,15000.),(0.025,0.0433012701892219,15000.),(-0.025,0.0433012701892219,15000.),(-0.05,6.12323399573677E-18,15000.),(-0.025,-0.0433012701892219,15000.),(0.025,-0.0433012701892219,15000.)));
|
||||
#88=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#89=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#90=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#91=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#92=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#93=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#94=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#95=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#96=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#97=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#98=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#99=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#100=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#101=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#102=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#103=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#104=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#105=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#106=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#107=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#108=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#109=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#110=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#111=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#112=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#113=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#114=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#115=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#116=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#117=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#118=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#119=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#120=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#121=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#122=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#123=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#124=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#125=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#126=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#127=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#128=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#129=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#130=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#131=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#132=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#133=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#134=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#135=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#136=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#137=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#138=IFCPOLYGONALFACESET(#87,$,(#88,#89,#90,#91,#92,#93,#94,#95,#96,#97,#98,#99,#100,#101,#102,#103,#104,#105,#106,#107,#108,#109,#110,#111,#112,#113,#114,#115,#116,#117,#118,#119,#120,#121,#122,#123,#124,#125,#126,#127,#128,#129,#130,#131,#132,#133,#134,#135,#136,#137),$);
|
||||
#139=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#86));
|
||||
#140=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#138));
|
||||
#141=IFCGEOGRAPHICELEMENTTYPE('1up5YjiS1CSvOopNo9qhzA',$,'Cone Tree (15m)',$,$,$,(#146,#151),$,$,.NOTDEFINED.);
|
||||
#142=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#143=IFCDIRECTION((1.,0.,0.));
|
||||
#144=IFCDIRECTION((0.,0.,1.));
|
||||
#145=IFCAXIS2PLACEMENT3D(#142,#144,#143);
|
||||
#146=IFCREPRESENTATIONMAP(#145,#140);
|
||||
#147=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#148=IFCDIRECTION((1.,0.,0.));
|
||||
#149=IFCDIRECTION((0.,0.,1.));
|
||||
#150=IFCAXIS2PLACEMENT3D(#147,#149,#148);
|
||||
#151=IFCREPRESENTATIONMAP(#150,#139);
|
||||
#152=IFCCARTESIANPOINTLIST2D(((-498.579620361328,735.001647949219),(-644.625122070312,558.698791503906),(-614.925903320312,498.60498046875),(-740.696044921875,396.37109375),(-782.288513183594,134.234802246094),(-551.41796875,97.9387969970703),(-788.211303710938,76.7640991210938),(-816.569641113281,-242.43864440918),(-685.161376953125,-297.968902587891),(-703.043884277344,-397.560852050781),(-586.489440917969,-569.15283203125),(-528.322204589844,-575.251037597656),(-366.814422607422,-750.108703613281),(-257.688507080078,-767.03466796875),(-273.860229492188,-683.197692871094),(-185.236541748047,-810.123107910156),(313.798278808594,-745.734313964844),(262.069519042969,-582.365661621094),(406.147064208984,-688.067260742188),(778.871398925781,-313.5146484375),(703.457824707031,-249.706893920898),(805.686340332031,-208.338500976562),(821.777282714844,71.8945388793945),(639.965148925781,44.3083839416504),(773.707153320312,162.339202880859),(703.734558105469,469.384552001953),(564.003479003906,549.215209960938),(489.063201904297,694.462707519531),(337.980773925781,746.2314453125),(159.236328125,638.655029296875),(287.592864990234,774.293273925781),(-11.1607036590576,832.838073730469),(-158.524017333984,800.207580566406),(-271.424072265625,751.009338378906)));
|
||||
#153=IFCINDEXEDPOLYCURVE(#152,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#154=IFCCARTESIANPOINTLIST3D(((110.,0.,0.),(55.,95.2627944162882,0.),(-55.,95.2627944162883,0.),(-110.,1.34711147906209E-14,0.),(-55.,-95.2627944162882,0.),(55.,-95.2627944162882,0.),(110.,0.,320.),(55.,95.2627944162882,320.),(-55.,95.2627944162883,320.),(-110.,1.34711147906209E-14,320.),(-55.,-95.2627944162882,320.),(55.,-95.2627944162882,320.),(864.280518937983,-14.2221890649771,1004.18968879832),(366.2196464279,798.785843488237,1053.28920307812),(-394.305493219765,668.167504520537,992.705300499414),(-884.445437675581,-50.0006646627198,1079.13481040061),(-325.688601492109,-827.210316726686,1060.60363602869),(445.638122193637,-759.800396032949,945.295072152772),(771.659636093658,-8.63376978833887,1694.31515423778),(400.702597343804,564.567676396979,1710.71041993166),(-271.850683531095,731.84967953552,1679.8082212522),(-827.814540093743,-99.1889711683184,1583.93736255268),(-280.132879054167,-677.399935048722,1630.37197747494),(447.972582241171,-675.099286463246,1666.93929394534),(610.539524858158,-87.0011647746299,2342.62353085467),(380.480246199047,471.106285369781,2270.57407945149),(-329.092625123698,447.207475504026,2325.0349854376),(-559.736760447407,31.5781877518219,2332.41103284484),(-240.641518511947,-609.88487469802,2339.16138108691),(286.501630216284,-519.561592269572,2248.29742609317),(565.102540214566,-80.6788333631295,2927.55846344436),(316.489950404951,531.211740774762,2980.93201479601),(-272.18383365034,390.769331158215,2949.22639267883),(-486.549445805167,-64.3079178558549,2918.18221515187),(-263.853028263793,-508.685394614137,3024.03068052896),(319.211134872299,-386.170678054984,2990.31239233058),(366.18091791083,-13.0578902011131,3563.85885783901),(240.847973491261,309.854854694926,3626.74179040925),(-282.348326849291,333.134595368031,3679.42693631726),(-418.54927829809,73.9091090794806,3697.52778620685),(-250.051684971173,-338.452640392509,3744.96390638646),(202.355272197616,-323.102436420037,3575.41186761945),(281.210556637686,-7.71174744071313,4311.65454744235),(125.753738295971,262.36087427247,4339.1619811132),(-143.687514908479,178.533152512032,4319.69793491929),(-189.597693621145,-16.9652613564334,4238.49213738614),(-241.100581330193,-238.290174142348,4241.54315979299),(60.215347735105,-323.622581880197,4322.24423749834),(0.05,0.,5000.),(0.025,0.0433012701892219,5000.),(-0.025,0.0433012701892219,5000.),(-0.05,6.12323399573677E-18,5000.),(-0.025,-0.0433012701892219,5000.),(0.025,-0.0433012701892219,5000.)));
|
||||
#155=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#156=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#157=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#158=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#159=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#160=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#161=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#162=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#163=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#164=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#165=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#166=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#167=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#168=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#169=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#170=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#171=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#172=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#173=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#174=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#175=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#176=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#177=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#178=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#179=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#180=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#181=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#182=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#183=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#184=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#185=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#186=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#187=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#188=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#189=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#190=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#191=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#192=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#193=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#194=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#195=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#196=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#197=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#198=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#199=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#200=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#201=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#202=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#203=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#204=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#205=IFCPOLYGONALFACESET(#154,$,(#155,#156,#157,#158,#159,#160,#161,#162,#163,#164,#165,#166,#167,#168,#169,#170,#171,#172,#173,#174,#175,#176,#177,#178,#179,#180,#181,#182,#183,#184,#185,#186,#187,#188,#189,#190,#191,#192,#193,#194,#195,#196,#197,#198,#199,#200,#201,#202,#203,#204),$);
|
||||
#206=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#153));
|
||||
#207=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#205));
|
||||
#208=IFCGEOGRAPHICELEMENTTYPE('1cYi681Jz1UQcLu0VCPumj',$,'Cone Tree (5m)',$,$,$,(#213,#218),$,$,.NOTDEFINED.);
|
||||
#209=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#210=IFCDIRECTION((1.,0.,0.));
|
||||
#211=IFCDIRECTION((0.,0.,1.));
|
||||
#212=IFCAXIS2PLACEMENT3D(#209,#211,#210);
|
||||
#213=IFCREPRESENTATIONMAP(#212,#207);
|
||||
#214=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#215=IFCDIRECTION((1.,0.,0.));
|
||||
#216=IFCDIRECTION((0.,0.,1.));
|
||||
#217=IFCAXIS2PLACEMENT3D(#214,#216,#215);
|
||||
#218=IFCREPRESENTATIONMAP(#217,#206);
|
||||
#219=IFCCARTESIANPOINTLIST2D(((-117.312850952148,172.941558837891),(-151.676498413086,131.458541870117),(-144.688446044922,117.318817138672),(-174.28141784668,93.263786315918),(-184.067886352539,31.584659576416),(-129.745407104492,23.0444221496582),(-185.461486816406,18.062141418457),(-192.134033203125,-57.0443878173828),(-161.214447021484,-70.1103286743164),(-165.422088623047,-93.5437316894531),(-137.997512817383,-133.918304443359),(-124.311111450195,-135.353179931641),(-86.3092803955078,-176.496170043945),(-60.6325874328613,-180.478744506836),(-64.4376983642578,-160.752395629883),(-43.5850677490234,-190.617202758789),(73.8348922729492,-175.466888427734),(61.6634140014648,-137.027221679688),(95.5640106201172,-161.898178100586),(183.263854980469,-73.7681503295898),(165.519485473633,-58.7545623779297),(189.573257446289,-49.020824432373),(193.359359741211,16.9163608551025),(150.580032348633,10.4255018234253),(182.048736572266,38.1974563598633),(165.584594726562,110.443428039551),(132.706695556641,129.227111816406),(115.073692321777,163.402984619141),(79.5248870849609,175.583862304688),(37.4673728942871,150.271774291992),(67.6689071655273,182.186645507812),(-2.62604808807373,195.961898803711),(-37.2997703552246,188.284133911133),(-63.8644866943359,176.708084106445)));
|
||||
#220=IFCINDEXEDPOLYCURVE(#219,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#221=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(189.142441515039,-1.13777512519817,58.3923179610087),(89.297571714232,167.825915933192,62.3202791033923),(-91.5444394575811,157.376448815776,57.4735668970959),(-190.755635014047,-4.00005317301757,64.3879276891917),(-86.0550881193688,-170.099873792268,62.9054337394378),(95.651049775491,-164.707080136769,53.6807486293646),(196.799437554159,-0.69070158306711,117.259498053308),(99.5895411208377,162.136578649577,118.571119308818),(-89.2813880158209,175.51913890066,116.098943414462),(-201.291829874166,-7.93511769346546,108.4292747185),(-89.9439636576667,-171.163159341716,112.144043912281),(103.371139912627,-170.979107454878,115.069429229913),(198.976495321986,-6.96009318197039,172.781311039802),(105.50508636259,167.707783451086,167.017354927548),(-101.394076676563,165.795878661826,171.374227406436),(-194.912274169126,2.52625502014577,171.964311199016),(-94.3179881476225,-178.810070597345,172.504339058381),(97.9867970839694,-171.58420800307,165.235222658882),(198.408203217165,-6.45430666905036,223.233248504121),(101.919196032396,175.172031121757,227.503132612252),(-98.3747066920271,163.936638352433,224.966682842878),(-192.123955664413,-5.14463342846837,222.483148640721),(-97.7082422611035,-173.369923428907,230.951025870888),(102.136890789784,-163.568746104175,228.253562815018),(185.561140099533,-1.04463121608905,277.794422912835),(97.4011712126342,160.119291473642,282.825057518454),(-100.721199481277,161.981670727491,287.039869191095),(-189.750608930514,5.91272872635847,288.487937182262),(-98.1374681310272,-162.407114329449,292.282826796631),(94.3217551091426,-161.179098011651,278.71866369527),(181.830177864348,-0.61693979525705,341.275220938245),(89.7269657303444,158.975584278118,343.475815631913),(-91.161667859345,152.269366537283,341.9186919364),(-174.501148823025,-1.35722090851465,335.422228133748),(-98.9547131730822,-157.049928267708,335.666309926296),(84.4838944854751,-163.876520886736,342.122396142724),(0.05,0.,400.),(0.025,0.0433012701892219,400.),(-0.025,0.0433012701892219,400.),(-0.05,6.12323399573677E-18,400.),(-0.025,-0.0433012701892219,400.),(0.025,-0.0433012701892219,400.)));
|
||||
#222=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#223=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#224=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#225=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#226=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#227=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#228=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#229=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#230=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#231=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#232=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#233=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#234=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#235=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#236=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#237=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#238=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#239=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#240=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#241=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#242=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#243=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#244=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#245=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#246=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#247=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#248=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#249=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#250=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#251=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#252=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#253=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#254=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#255=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#256=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#257=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#258=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#259=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#260=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#261=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#262=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#263=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#264=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#265=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#266=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#267=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#268=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#269=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#270=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#271=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#272=IFCPOLYGONALFACESET(#221,$,(#222,#223,#224,#225,#226,#227,#228,#229,#230,#231,#232,#233,#234,#235,#236,#237,#238,#239,#240,#241,#242,#243,#244,#245,#246,#247,#248,#249,#250,#251,#252,#253,#254,#255,#256,#257,#258,#259,#260,#261,#262,#263,#264,#265,#266,#267,#268,#269,#270,#271),$);
|
||||
#273=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#220));
|
||||
#274=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#272));
|
||||
#275=IFCGEOGRAPHICELEMENTTYPE('1mO0fZa2b4sflxAiM3QTIb',$,'Hedge Small (0.4m)',$,$,$,(#280,#285),$,$,.NOTDEFINED.);
|
||||
#276=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#277=IFCDIRECTION((1.,0.,0.));
|
||||
#278=IFCDIRECTION((0.,0.,1.));
|
||||
#279=IFCAXIS2PLACEMENT3D(#276,#278,#277);
|
||||
#280=IFCREPRESENTATIONMAP(#279,#274);
|
||||
#281=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#282=IFCDIRECTION((1.,0.,0.));
|
||||
#283=IFCDIRECTION((0.,0.,1.));
|
||||
#284=IFCAXIS2PLACEMENT3D(#281,#283,#282);
|
||||
#285=IFCREPRESENTATIONMAP(#284,#273);
|
||||
#286=IFCCARTESIANPOINTLIST2D(((-234.625701904297,345.883117675781),(-303.352996826172,262.917083740234),(-289.376892089844,234.637634277344),(-348.562835693359,186.527572631836),(-368.135772705078,63.169319152832),(-259.490814208984,46.0888442993164),(-370.922973632812,36.1242828369141),(-384.26806640625,-114.088775634766),(-322.428894042969,-140.220657348633),(-330.844177246094,-187.087463378906),(-275.995025634766,-267.836608886719),(-248.622222900391,-270.706359863281),(-172.618560791016,-352.992340087891),(-121.265174865723,-360.957489013672),(-128.875396728516,-321.504791259766),(-87.1701354980469,-381.234405517578),(147.669784545898,-350.933776855469),(123.32682800293,-274.054443359375),(191.128021240234,-323.796356201172),(366.527709960938,-147.53630065918),(331.038970947266,-117.509124755859),(379.146514892578,-98.0416488647461),(386.718719482422,33.8327217102051),(301.160064697266,20.8510036468506),(364.097473144531,76.3949127197266),(331.169189453125,220.886856079102),(265.413391113281,258.454223632812),(230.147384643555,326.805969238281),(159.049774169922,351.167724609375),(74.9347457885742,300.543548583984),(135.337814331055,364.373291015625),(-5.25209617614746,391.923797607422),(-74.5995407104492,376.568267822266),(-127.728973388672,353.416168212891)));
|
||||
#287=IFCINDEXEDPOLYCURVE(#286,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#288=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(378.284883030077,-2.27555025039633,116.784635922017),(178.595143428464,335.651831866383,124.640558206785),(-183.088878915162,314.752897631551,114.947133794192),(-381.511270028093,-8.00010634603514,128.775855378383),(-172.110176238738,-340.199747584535,125.810867478876),(191.302099550982,-329.414160273537,107.361497258729),(393.598875108319,-1.38140316613422,234.518996106616),(199.179082241675,324.273157299153,237.142238617636),(-178.562776031642,351.03827780132,232.197886828923),(-402.583659748332,-15.8702353869309,216.858549437001),(-179.887927315333,-342.326318683432,224.288087824562),(206.742279825254,-341.958214909756,230.138858459826),(397.952990643972,-13.9201863639408,345.562622079605),(211.010172725181,335.415566902172,334.034709855096),(-202.788153353125,331.591757323652,342.748454812872),(-389.824548338252,5.05251004029154,343.928622398032),(-188.635976295245,-357.620141194691,345.008678116763),(195.973594167939,-343.168416006139,330.470445317765),(396.81640643433,-12.9086133381007,446.466497008241),(203.838392064792,350.344062243514,455.006265224505),(-196.749413384054,327.873276704866,449.933365685756),(-384.247911328827,-10.2892668569367,444.966297281442),(-195.416484522207,-346.739846857814,461.902051741776),(204.273781579568,-327.137492208349,456.507125630036),(371.122280199066,-2.0892624321781,555.588845825671),(194.802342425268,320.238582947285,565.650115036909),(-201.442398962553,323.963341454982,574.07973838219),(-379.501217861028,11.8254574527169,576.975874364524),(-196.274936262054,-324.814228658898,584.565653593263),(188.643510218285,-322.358196023303,557.43732739054),(363.660355728696,-1.2338795905141,682.550441876491),(179.453931460689,317.951168556236,686.951631263826),(-182.32333571869,304.538733074566,683.837383872801),(-349.00229764605,-2.71444181702931,670.844456267496),(-197.909426346164,-314.099856535417,671.332619852593),(168.96778897095,-327.753041773473,684.244792285448),(0.05,0.,800.),(0.025,0.0433012701892219,800.),(-0.025,0.0433012701892219,800.),(-0.05,6.12323399573677E-18,800.),(-0.025,-0.0433012701892219,800.),(0.025,-0.0433012701892219,800.)));
|
||||
#289=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#290=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#291=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#292=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#293=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#294=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#295=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#296=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#297=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#298=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#299=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#300=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#301=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#302=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#303=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#304=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#305=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#306=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#307=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#308=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#309=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#310=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#311=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#312=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#313=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#314=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#315=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#316=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#317=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#318=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#319=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#320=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#321=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#322=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#323=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#324=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#325=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#326=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#327=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#328=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#329=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#330=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#331=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#332=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#333=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#334=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#335=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#336=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#337=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#338=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#339=IFCPOLYGONALFACESET(#288,$,(#289,#290,#291,#292,#293,#294,#295,#296,#297,#298,#299,#300,#301,#302,#303,#304,#305,#306,#307,#308,#309,#310,#311,#312,#313,#314,#315,#316,#317,#318,#319,#320,#321,#322,#323,#324,#325,#326,#327,#328,#329,#330,#331,#332,#333,#334,#335,#336,#337,#338),$);
|
||||
#340=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#287));
|
||||
#341=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#339));
|
||||
#342=IFCGEOGRAPHICELEMENTTYPE('1esPZTKFXE3Af39$mWJyUW',$,'Hedge Medium (0.8m)',$,$,$,(#347,#352),$,$,.NOTDEFINED.);
|
||||
#343=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#344=IFCDIRECTION((1.,0.,0.));
|
||||
#345=IFCDIRECTION((0.,0.,1.));
|
||||
#346=IFCAXIS2PLACEMENT3D(#343,#345,#344);
|
||||
#347=IFCREPRESENTATIONMAP(#346,#341);
|
||||
#348=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#349=IFCDIRECTION((1.,0.,0.));
|
||||
#350=IFCDIRECTION((0.,0.,1.));
|
||||
#351=IFCAXIS2PLACEMENT3D(#348,#350,#349);
|
||||
#352=IFCREPRESENTATIONMAP(#351,#340);
|
||||
#353=IFCCARTESIANPOINTLIST2D(((-527.907836914062,778.237060546875),(-682.544250488281,591.5634765625),(-651.098022460938,527.934692382812),(-784.266357421875,419.687042236328),(-828.305480957031,142.130966186523),(-583.854309082031,103.699897766113),(-834.57666015625,81.2796401977539),(-864.603149414062,-256.699737548828),(-725.465026855469,-315.496459960938),(-744.3994140625,-420.946807861328),(-620.988830566406,-602.632385253906),(-559.400024414062,-609.08935546875),(-388.391754150391,-794.232788085938),(-272.846649169922,-812.154357910156),(-289.969635009766,-723.3857421875),(-196.1328125,-857.777404785156),(332.257019042969,-789.601013183594),(277.4853515625,-616.622497558594),(430.038055419922,-728.541809082031),(824.687377929688,-331.956665039062),(744.837707519531,-264.395538330078),(853.079650878906,-220.593704223633),(870.117126464844,76.1236267089844),(677.610168457031,46.9147605895996),(819.219299316406,171.888565063477),(745.130676269531,496.995422363281),(597.18017578125,581.522033691406),(517.831604003906,735.313415527344),(357.861999511719,790.127380371094),(168.603179931641,676.222961425781),(304.510101318359,819.839904785156),(-11.8172159194946,881.828552246094),(-167.848968505859,847.278625488281),(-287.390197753906,795.186340332031)));
|
||||
#354=IFCINDEXEDPOLYCURVE(#353,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#355=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(851.140986817674,-5.11998806339175,262.765430824539),(401.839072714044,755.216621699362,280.441255965265),(-411.949977559115,708.19401967099,258.631051036932),(-858.400357563209,-18.0002392785791,289.745674601363),(-387.24789653716,-765.449432065204,283.07445182747),(430.429723989709,-741.181860615459,241.563368832141),(885.597468993717,-3.10815712380199,527.667741239885),(448.152935043769,729.614603923094,533.570036889682),(-401.766246071194,789.836125052969,522.445245365077),(-905.813234433747,-35.7080296205946,487.931736233252),(-404.7478364595,-770.234217037722,504.648197605265),(465.170129606822,-769.40598354695,517.812431534608),(895.394228948937,-31.3204193188668,777.515899679111),(474.772888631657,754.685025529888,751.578097173967),(-456.273345044531,746.081453978216,771.184023328963),(-877.105233761067,11.368147590656,773.839400395571),(-424.430946664301,-804.645317688054,776.269525762717),(440.940586877863,-772.128936013813,743.558501964971),(892.836914477244,-29.0443800107266,1004.54961826854),(458.636382145783,788.274140047906,1023.76409675514),(-442.686180114122,737.714872585949,1012.35007279295),(-864.55780048986,-23.1508504281077,1001.17416888324),(-439.687090174966,-780.164655430081,1039.279616419),(459.616008554028,-736.059357468786,1027.14103266758),(835.025130447899,-4.70084047240072,1250.07490310776),(438.305270456854,720.536811631391,1272.71275883304),(-453.245397665745,728.917518273708,1291.67941135993),(-853.877740187312,26.6072792686131,1298.19571732018),(-441.618606589622,-730.832014482521,1315.27272058484),(424.447897991142,-725.305941052431,1254.23398662872),(818.235800389567,-2.77622907865673,1535.7384942221),(403.77134578655,715.390129251532,1545.64117034361),(-410.227505367052,685.212149417774,1538.6341137138),(-785.255169703612,-6.10749408831594,1509.40002660187),(-445.29620927887,-706.724677204688,1510.49839466833),(380.177525184638,-737.444343990313,1539.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
|
||||
#356=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#357=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#358=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#359=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#360=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#361=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#362=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#363=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#364=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#365=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#366=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#367=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#368=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#369=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#370=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#371=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#372=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#373=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#374=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#375=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#376=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#377=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#378=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#379=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#380=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#381=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#382=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#383=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#384=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#385=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#386=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#387=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#388=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#389=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#390=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#391=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#392=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#393=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#394=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#395=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#396=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#397=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#398=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#399=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#400=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#401=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#402=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#403=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#404=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#405=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#406=IFCPOLYGONALFACESET(#355,$,(#356,#357,#358,#359,#360,#361,#362,#363,#364,#365,#366,#367,#368,#369,#370,#371,#372,#373,#374,#375,#376,#377,#378,#379,#380,#381,#382,#383,#384,#385,#386,#387,#388,#389,#390,#391,#392,#393,#394,#395,#396,#397,#398,#399,#400,#401,#402,#403,#404,#405),$);
|
||||
#407=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#354));
|
||||
#408=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#406));
|
||||
#409=IFCGEOGRAPHICELEMENTTYPE('2ITyucrb9DnxtmPeA_FCBG',$,'Hedge Big (1.8m)',$,$,$,(#414,#419),$,$,.NOTDEFINED.);
|
||||
#410=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#411=IFCDIRECTION((1.,0.,0.));
|
||||
#412=IFCDIRECTION((0.,0.,1.));
|
||||
#413=IFCAXIS2PLACEMENT3D(#410,#412,#411);
|
||||
#414=IFCREPRESENTATIONMAP(#413,#408);
|
||||
#415=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#416=IFCDIRECTION((1.,0.,0.));
|
||||
#417=IFCDIRECTION((0.,0.,1.));
|
||||
#418=IFCAXIS2PLACEMENT3D(#415,#417,#416);
|
||||
#419=IFCREPRESENTATIONMAP(#418,#407);
|
||||
#420=IFCCARTESIANPOINTLIST3D(((-2517.70166015625,-2646.30053710938,3901.58129882812),(-255.675521850586,-1248.60815429688,5000.),(-1133.70935058594,-349.566070556641,4688.61865234375),(0.,0.,4658.5205078125),(3472.91040039062,-1142.93579101562,3901.58129882812),(1250.74682617188,317.302124023438,5000.),(806.568603515625,-858.251220703125,4688.61865234375),(1171.36364746094,3483.57202148438,3901.58129882812),(-298.783111572266,1267.951171875,5000.),(874.774963378906,818.52783203125,4688.61865234375),(-3164.8310546875,1859.35131835938,3901.58129882812),(-1289.18603515625,-25.3927478790283,5000.),(-613.466796875,1034.14660644531,4688.61865234375)));
|
||||
#421=IFCINDEXEDPOLYGONALFACE((3,2,1));
|
||||
#422=IFCINDEXEDPOLYGONALFACE((3,4,2));
|
||||
#423=IFCINDEXEDPOLYGONALFACE((7,6,5));
|
||||
#424=IFCINDEXEDPOLYGONALFACE((7,4,6));
|
||||
#425=IFCINDEXEDPOLYGONALFACE((10,9,8));
|
||||
#426=IFCINDEXEDPOLYGONALFACE((10,4,9));
|
||||
#427=IFCINDEXEDPOLYGONALFACE((13,12,11));
|
||||
#428=IFCINDEXEDPOLYGONALFACE((13,4,12));
|
||||
#429=IFCPOLYGONALFACESET(#420,$,(#421,#422,#423,#424,#425,#426,#427,#428),$);
|
||||
#430=IFCCARTESIANPOINT((0.,0.));
|
||||
#431=IFCAXIS2PLACEMENT2D(#430,$);
|
||||
#432=IFCCIRCLE(#431,100.);
|
||||
#433=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#432);
|
||||
#434=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#435=IFCDIRECTION((0.,0.,1.));
|
||||
#436=IFCDIRECTION((1.,0.,0.));
|
||||
#437=IFCAXIS2PLACEMENT3D(#434,#435,#436);
|
||||
#438=IFCDIRECTION((0.,0.,1.));
|
||||
#439=IFCEXTRUDEDAREASOLID(#433,#437,#438,4658.5204646405);
|
||||
#440=IFCCARTESIANPOINTLIST2D(((-2517.70166015625,-2646.30053710938,0.),(-255.675521850586,-1248.60815429688,0.),(-1133.70935058594,-349.566070556641,0.),(0.,0.,0.),(3472.91040039062,-1142.93579101562,0.),(1250.74682617188,317.302124023438,0.),(806.568603515625,-858.251220703125,0.),(1171.36364746094,3483.57202148438,0.),(-298.783111572266,1267.951171875,0.),(874.774963378906,818.52783203125,0.),(-3164.8310546875,1859.35131835938,0.),(-1289.18603515625,-25.3927478790283,0.),(-613.466796875,1034.14660644531,0.)));
|
||||
#441=IFCINDEXEDPOLYCURVE(#440,(IFCLINEINDEX((4,12,11,13,4)),IFCLINEINDEX((4,2,1,3,4)),IFCLINEINDEX((4,6,5,7,4)),IFCLINEINDEX((4,9,8,10,4))),$);
|
||||
#442=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#441));
|
||||
#443=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#429,#439));
|
||||
#444=IFCGEOGRAPHICELEMENTTYPE('0If5oJIRTAxw5EHjhL6zX$',$,'Palm Tree (5m)',$,$,$,(#449,#454),$,$,.NOTDEFINED.);
|
||||
#445=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#446=IFCDIRECTION((1.,0.,0.));
|
||||
#447=IFCDIRECTION((0.,0.,1.));
|
||||
#448=IFCAXIS2PLACEMENT3D(#445,#447,#446);
|
||||
#449=IFCREPRESENTATIONMAP(#448,#443);
|
||||
#450=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#451=IFCDIRECTION((1.,0.,0.));
|
||||
#452=IFCDIRECTION((0.,0.,1.));
|
||||
#453=IFCAXIS2PLACEMENT3D(#450,#452,#451);
|
||||
#454=IFCREPRESENTATIONMAP(#453,#442);
|
||||
#455=IFCCARTESIANPOINTLIST3D(((-5223.76025390625,-5490.57861328125,12720.986328125),(-530.478881835938,-2590.62841796875,15000.),(-2352.23486328125,-725.284240722656,14353.9423828125),(0.,0.,14291.4931640625),(7205.64013671875,-2371.37817382812,12720.986328125),(2595.06591796875,658.342590332031,15000.),(1673.47912597656,-1780.7109375,14353.9423828125),(2430.36059570312,7227.76025390625,12720.986328125),(-619.919128417969,2630.76171875,15000.),(1814.99462890625,1698.29223632812,14353.9423828125),(-6566.43310546875,3857.80639648438,12720.986328125),(-2674.81982421875,-52.6852073669434,15000.),(-1272.82897949219,2145.66088867188,14353.9423828125)));
|
||||
#456=IFCINDEXEDPOLYGONALFACE((3,2,1));
|
||||
#457=IFCINDEXEDPOLYGONALFACE((3,4,2));
|
||||
#458=IFCINDEXEDPOLYGONALFACE((7,6,5));
|
||||
#459=IFCINDEXEDPOLYGONALFACE((7,4,6));
|
||||
#460=IFCINDEXEDPOLYGONALFACE((10,9,8));
|
||||
#461=IFCINDEXEDPOLYGONALFACE((10,4,9));
|
||||
#462=IFCINDEXEDPOLYGONALFACE((13,12,11));
|
||||
#463=IFCINDEXEDPOLYGONALFACE((13,4,12));
|
||||
#464=IFCPOLYGONALFACESET(#455,$,(#456,#457,#458,#459,#460,#461,#462,#463),$);
|
||||
#465=IFCCARTESIANPOINT((0.,0.));
|
||||
#466=IFCAXIS2PLACEMENT2D(#465,$);
|
||||
#467=IFCCIRCLE(#466,200.);
|
||||
#468=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#467);
|
||||
#469=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#470=IFCDIRECTION((0.,0.,1.));
|
||||
#471=IFCDIRECTION((1.,0.,0.));
|
||||
#472=IFCAXIS2PLACEMENT3D(#469,#470,#471);
|
||||
#473=IFCDIRECTION((0.,0.,1.));
|
||||
#474=IFCEXTRUDEDAREASOLID(#468,#472,#473,14291.4938033876);
|
||||
#475=IFCCARTESIANPOINTLIST2D(((-5223.76025390625,-5490.57861328125,0.),(-530.478881835938,-2590.62841796875,0.),(-2352.23486328125,-725.284240722656,0.),(0.,0.,0.),(7205.64013671875,-2371.37817382812,0.),(2595.06591796875,658.342590332031,0.),(1673.47912597656,-1780.7109375,0.),(2430.36059570312,7227.76025390625,0.),(-619.919128417969,2630.76171875,0.),(1814.99462890625,1698.29223632812,0.),(-6566.43310546875,3857.80639648438,0.),(-2674.81982421875,-52.6852073669434,0.),(-1272.82897949219,2145.66088867188,0.)));
|
||||
#476=IFCINDEXEDPOLYCURVE(#475,(IFCLINEINDEX((4,12,11,13,4)),IFCLINEINDEX((4,2,1,3,4)),IFCLINEINDEX((4,6,5,7,4)),IFCLINEINDEX((4,9,8,10,4))),$);
|
||||
#477=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#476));
|
||||
#478=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#464,#474));
|
||||
#479=IFCGEOGRAPHICELEMENTTYPE('11RlAtH99EAwxYuNeuU3sf',$,'Palm Tree (15m)',$,$,$,(#484,#489),$,$,.NOTDEFINED.);
|
||||
#480=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#481=IFCDIRECTION((1.,0.,0.));
|
||||
#482=IFCDIRECTION((0.,0.,1.));
|
||||
#483=IFCAXIS2PLACEMENT3D(#480,#482,#481);
|
||||
#484=IFCREPRESENTATIONMAP(#483,#478);
|
||||
#485=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#486=IFCDIRECTION((1.,0.,0.));
|
||||
#487=IFCDIRECTION((0.,0.,1.));
|
||||
#488=IFCAXIS2PLACEMENT3D(#485,#487,#486);
|
||||
#489=IFCREPRESENTATIONMAP(#488,#477);
|
||||
#490=IFCCARTESIANPOINTLIST2D(((-117.312850952148,172.941558837891),(-151.676498413086,131.458541870117),(-144.688446044922,117.318817138672),(-174.28141784668,93.263786315918),(-184.067886352539,31.584659576416),(-129.745407104492,23.0444221496582),(-185.461486816406,18.062141418457),(-192.134033203125,-57.0443878173828),(-161.214447021484,-70.1103286743164),(-165.422088623047,-93.5437316894531),(-137.997512817383,-133.918304443359),(-124.311111450195,-135.353179931641),(-86.3092803955078,-176.496170043945),(-60.6325874328613,-180.478744506836),(-64.4376983642578,-160.752395629883),(-43.5850677490234,-190.617202758789),(73.8348922729492,-175.466888427734),(61.6634140014648,-137.027221679688),(95.5640106201172,-161.898178100586),(183.263854980469,-73.7681503295898),(165.519485473633,-58.7545623779297),(189.573257446289,-49.020824432373),(193.359359741211,16.9163608551025),(150.580032348633,10.4255018234253),(182.048736572266,38.1974563598633),(165.584594726562,110.443428039551),(132.706695556641,129.227111816406),(115.073692321777,163.402984619141),(79.5248870849609,175.583862304688),(37.4673728942871,150.271774291992),(67.6689071655273,182.186645507812),(-2.62604808807373,195.961898803711),(-37.2997703552246,188.284133911133),(-63.8644866943359,176.708084106445)));
|
||||
#491=IFCINDEXEDPOLYCURVE(#490,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#492=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(117.302441515039,-1.13777512519817,58.3923179610087),(53.377571714232,105.610650925318,62.3202791033923),(-55.6244394575812,95.1611838079015,57.4735668970959),(-118.915635014047,-4.00005317301758,64.3879276891917),(-50.1350881193688,-107.884608784393,62.9054337394378),(59.731049775491,-102.491815128895,53.6807486293646),(146.906104220826,-0.69070158306711,117.259498053308),(74.642874454171,118.927684503425,118.571119308818),(-64.3347213491543,132.310244754508,116.098943414462),(-151.398496540833,-7.93511769346546,108.4292747185),(-64.9972969910001,-127.954265195564,112.144043912281),(78.4244732459604,-127.770213308726,115.069429229913),(171.029828655319,-6.96009318197039,172.781311039802),(91.5317530292571,143.505260166657,167.017354927548),(-87.4207433432292,141.593355377397,171.374227406436),(-166.965607502459,2.52625502014577,171.964311199016),(-80.3446548142891,-154.607547312916,172.504339058381),(84.0134637506361,-147.38168471864,165.235222658882),(204.408203217165,-6.45430666905036,223.233248504121),(104.919196032396,180.368183544464,227.503132612252),(-101.374706692027,169.13279077514,224.966682842878),(-198.123955664413,-5.14463342846837,222.483148640721),(-100.708242261103,-178.566075851614,230.951025870888),(105.136890789784,-168.764898526881,228.253562815018),(169.614473432866,-1.04463121608905,277.794422912835),(89.4278378793009,146.309073034627,282.825057518454),(-92.7478661479432,148.171452288475,287.039869191095),(-173.803942263847,5.91272872635847,288.487937182262),(-90.1641347976938,-148.596895890433,292.282826796631),(86.3484217758093,-147.368879572635,278.71866369527),(143.936844531015,-0.61693979525705,341.275220938245),(70.7802990636777,126.15899497738,343.475815631913),(-72.2150011926783,119.452777236545,341.9186919364),(-136.607815489692,-1.35722090851466,335.422228133748),(-80.0080465064155,-124.23333896697,335.666309926296),(65.5372278188084,-131.059931585998,342.122396142724),(0.05,0.,400.),(0.025,0.0433012701892219,400.),(-0.025,0.0433012701892219,400.),(-0.05,6.12323399573677E-18,400.),(-0.025,-0.0433012701892219,400.),(0.025,-0.0433012701892219,400.)));
|
||||
#493=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#494=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#495=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#496=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#497=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#498=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#499=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#500=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#501=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#502=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#503=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#504=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#505=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#506=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#507=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#508=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#509=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#510=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#511=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#512=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#513=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#514=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#515=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#516=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#517=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#518=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#519=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#520=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#521=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#522=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#523=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#524=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#525=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#526=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#527=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#528=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#529=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#530=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#531=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#532=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#533=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#534=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#535=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#536=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#537=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#538=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#539=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#540=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#541=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#542=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#543=IFCPOLYGONALFACESET(#492,$,(#493,#494,#495,#496,#497,#498,#499,#500,#501,#502,#503,#504,#505,#506,#507,#508,#509,#510,#511,#512,#513,#514,#515,#516,#517,#518,#519,#520,#521,#522,#523,#524,#525,#526,#527,#528,#529,#530,#531,#532,#533,#534,#535,#536,#537,#538,#539,#540,#541,#542),$);
|
||||
#544=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#491));
|
||||
#545=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#543));
|
||||
#546=IFCGEOGRAPHICELEMENTTYPE('224k6o88949Ak$WjDPqiY0',$,'Shrub Small (0.4m)',$,$,$,(#551,#556),$,$,.NOTDEFINED.);
|
||||
#547=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#548=IFCDIRECTION((1.,0.,0.));
|
||||
#549=IFCDIRECTION((0.,0.,1.));
|
||||
#550=IFCAXIS2PLACEMENT3D(#547,#549,#548);
|
||||
#551=IFCREPRESENTATIONMAP(#550,#545);
|
||||
#552=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#553=IFCDIRECTION((1.,0.,0.));
|
||||
#554=IFCDIRECTION((0.,0.,1.));
|
||||
#555=IFCAXIS2PLACEMENT3D(#552,#554,#553);
|
||||
#556=IFCREPRESENTATIONMAP(#555,#544);
|
||||
#557=IFCCARTESIANPOINTLIST2D(((-234.625701904297,345.883117675781),(-303.352996826172,262.917083740234),(-289.376892089844,234.637634277344),(-348.562835693359,186.527572631836),(-368.135772705078,63.169319152832),(-259.490814208984,46.0888442993164),(-370.922973632812,36.1242828369141),(-384.26806640625,-114.088775634766),(-322.428894042969,-140.220657348633),(-330.844177246094,-187.087463378906),(-275.995025634766,-267.836608886719),(-248.622222900391,-270.706359863281),(-172.618560791016,-352.992340087891),(-121.265174865723,-360.957489013672),(-128.875396728516,-321.504791259766),(-87.1701354980469,-381.234405517578),(147.669784545898,-350.933776855469),(123.32682800293,-274.054443359375),(191.128021240234,-323.796356201172),(366.527709960938,-147.53630065918),(331.038970947266,-117.509124755859),(379.146514892578,-98.0416488647461),(386.718719482422,33.8327217102051),(301.160064697266,20.8510036468506),(364.097473144531,76.3949127197266),(331.169189453125,220.886856079102),(265.413391113281,258.454223632812),(230.147384643555,326.805969238281),(159.049774169922,351.167724609375),(74.9347457885742,300.543548583984),(135.337814331055,364.373291015625),(-5.25209617614746,391.923797607422),(-74.5995407104492,376.568267822266),(-127.728973388672,353.416168212891)));
|
||||
#558=IFCINDEXEDPOLYCURVE(#557,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#559=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(234.604883030077,-2.27555025039633,116.784635922017),(106.755143428464,211.221301850635,124.640558206785),(-111.248878915162,190.322367615803,114.947133794192),(-237.831270028093,-8.00010634603516,128.775855378383),(-100.270176238738,-215.769217568787,125.810867478876),(119.462099550982,-204.983630257789,107.361497258729),(293.812208441652,-1.38140316613422,234.518996106616),(149.285748908342,237.85536900685,237.142238617636),(-128.669442698309,264.620489509016,232.197886828923),(-302.796993081665,-15.8702353869309,216.858549437001),(-129.994593982,-255.908530391129,224.288087824562),(156.848946491921,-255.540426617453,230.138858459826),(342.059657310639,-13.9201863639408,345.562622079605),(183.063506058514,287.010520333314,334.034709855096),(-174.841486686458,283.186710754793,342.748454812872),(-333.931215004918,5.05251004029153,343.928622398032),(-160.689309628578,-309.215094625832,345.008678116763),(168.026927501272,-294.763369437281,330.470445317765),(408.81640643433,-12.9086133381007,446.466497008241),(209.838392064792,360.736367088927,455.006265224505),(-202.749413384054,338.26558155028,449.933365685756),(-396.247911328827,-10.2892668569367,444.966297281442),(-201.416484522207,-357.132151703227,461.902051741776),(210.273781579568,-337.529797053763,456.507125630036),(339.228946865733,-2.0892624321781,555.588845825671),(178.855675758602,292.618146069253,565.650115036909),(-185.495732295886,296.34290457695,574.07973838219),(-347.607884527694,11.8254574527169,576.975874364524),(-180.328269595388,-297.193791780866,584.565653593263),(172.696843551619,-294.737759145271,557.43732739054),(287.87368906203,-1.2338795905141,682.550441876491),(141.560598127355,252.31798995476,686.951631263826),(-144.430002385357,238.90555447309,683.837383872801),(-273.215630979383,-2.71444181702932,670.844456267496),(-160.016093012831,-248.46667793394,671.332619852593),(131.074455637617,-262.119863171996,684.244792285448),(0.05,0.,800.),(0.025,0.0433012701892219,800.),(-0.025,0.0433012701892219,800.),(-0.05,6.12323399573677E-18,800.),(-0.025,-0.0433012701892219,800.),(0.025,-0.0433012701892219,800.)));
|
||||
#560=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#561=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#562=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#563=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#564=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#565=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#566=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#567=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#568=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#569=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#570=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#571=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#572=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#573=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#574=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#575=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#576=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#577=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#578=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#579=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#580=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#581=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#582=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#583=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#584=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#585=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#586=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#587=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#588=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#589=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#590=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#591=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#592=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#593=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#594=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#595=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#596=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#597=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#598=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#599=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#600=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#601=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#602=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#603=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#604=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#605=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#606=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#607=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#608=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#609=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#610=IFCPOLYGONALFACESET(#559,$,(#560,#561,#562,#563,#564,#565,#566,#567,#568,#569,#570,#571,#572,#573,#574,#575,#576,#577,#578,#579,#580,#581,#582,#583,#584,#585,#586,#587,#588,#589,#590,#591,#592,#593,#594,#595,#596,#597,#598,#599,#600,#601,#602,#603,#604,#605,#606,#607,#608,#609),$);
|
||||
#611=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#558));
|
||||
#612=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#610));
|
||||
#613=IFCGEOGRAPHICELEMENTTYPE('0sCZ5iWS904ODo2Mqo8nHu',$,'Shrum Medium (0.8m)',$,$,$,(#618,#623),$,$,.NOTDEFINED.);
|
||||
#614=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#615=IFCDIRECTION((1.,0.,0.));
|
||||
#616=IFCDIRECTION((0.,0.,1.));
|
||||
#617=IFCAXIS2PLACEMENT3D(#614,#616,#615);
|
||||
#618=IFCREPRESENTATIONMAP(#617,#612);
|
||||
#619=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#620=IFCDIRECTION((1.,0.,0.));
|
||||
#621=IFCDIRECTION((0.,0.,1.));
|
||||
#622=IFCAXIS2PLACEMENT3D(#619,#621,#620);
|
||||
#623=IFCREPRESENTATIONMAP(#622,#611);
|
||||
#624=IFCCARTESIANPOINTLIST2D(((-527.907836914062,778.237060546875),(-682.544250488281,591.5634765625),(-651.098022460938,527.934692382812),(-784.266357421875,419.687042236328),(-828.305480957031,142.130966186523),(-583.854309082031,103.699897766113),(-834.57666015625,81.2796401977539),(-864.603149414062,-256.699737548828),(-725.465026855469,-315.496459960938),(-744.3994140625,-420.946807861328),(-620.988830566406,-602.632385253906),(-559.400024414062,-609.08935546875),(-388.391754150391,-794.232788085938),(-272.846649169922,-812.154357910156),(-289.969635009766,-723.3857421875),(-196.1328125,-857.777404785156),(332.257019042969,-789.601013183594),(277.4853515625,-616.622497558594),(430.038055419922,-728.541809082031),(824.687377929688,-331.956665039062),(744.837707519531,-264.395538330078),(853.079650878906,-220.593704223633),(870.117126464844,76.1236267089844),(677.610168457031,46.9147605895996),(819.219299316406,171.888565063477),(745.130676269531,496.995422363281),(597.18017578125,581.522033691406),(517.831604003906,735.313415527344),(357.861999511719,790.127380371094),(168.603179931641,676.222961425781),(304.510101318359,819.839904785156),(-11.8172159194946,881.828552246094),(-167.848968505859,847.278625488281),(-287.390197753906,795.186340332031)));
|
||||
#625=IFCINDEXEDPOLYCURVE(#624,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#626=IFCCARTESIANPOINTLIST3D(((0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(0.,0.,0.),(527.860986817674,-5.11998806339175,262.765430824539),(240.199072714044,475.247929163929,280.441255965265),(-250.309977559115,428.225327135557,258.631051036932),(-535.120357563209,-18.0002392785791,289.745674601363),(-225.607896537159,-485.480739529771,283.07445182747),(268.789723989709,-461.213168080025,241.563368832141),(661.077468993717,-3.10815712380199,527.667741239885),(335.892935043769,535.174580265412,533.570036889682),(-289.506246071194,595.396101395287,522.445245365077),(-681.293234433747,-35.7080296205946,487.931736233252),(-292.4878364595,-575.794193380039,504.648197605265),(352.910129606822,-574.965959889268,517.812431534608),(769.634228948937,-31.3204193188668,777.515899679111),(411.892888631657,645.773670749957,751.578097173967),(-393.393345044531,637.170099198285,771.184023328963),(-751.345233761067,11.3681475906559,773.839400395571),(-361.550946664301,-695.733962908123,776.269525762717),(378.060586877863,-663.217581233882,743.558501964971),(919.836914477244,-29.0443800107266,1004.54961826854),(472.136382145783,811.656825950086,1023.76409675514),(-456.186180114122,761.097558488129,1012.35007279295),(-891.55780048986,-23.1508504281077,1001.17416888324),(-453.187090174966,-803.547341332261,1039.279616419),(473.116008554028,-759.442043370966,1027.14103266758),(763.265130447899,-4.70084047240072,1250.07490310776),(402.425270456854,658.39082865582,1272.71275883304),(-417.365397665745,666.771535298137,1291.67941135993),(-782.117740187312,26.6072792686131,1298.19571732018),(-405.738606589622,-668.686031506949,1315.27272058484),(388.567897991142,-663.159958076859,1254.23398662872),(647.715800389567,-2.77622907865673,1535.7384942221),(318.51134578655,567.715477398209,1545.64117034361),(-324.967505367052,537.537497564452,1538.6341137138),(-614.735169703612,-6.10749408831597,1509.40002660187),(-360.03620927887,-559.050025351365,1510.49839466833),(294.917525184638,-589.769692136991,1539.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
|
||||
#627=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#628=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#629=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#630=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#631=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#632=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#633=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#634=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#635=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#636=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#637=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#638=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#639=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#640=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#641=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#642=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#643=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#644=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#645=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#646=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#647=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#648=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#649=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#650=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#651=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#652=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#653=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#654=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#655=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#656=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#657=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#658=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#659=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#660=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#661=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#662=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#663=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#664=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#665=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#666=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#667=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#668=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#669=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#670=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#671=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#672=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#673=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#674=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#675=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#676=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#677=IFCPOLYGONALFACESET(#626,$,(#627,#628,#629,#630,#631,#632,#633,#634,#635,#636,#637,#638,#639,#640,#641,#642,#643,#644,#645,#646,#647,#648,#649,#650,#651,#652,#653,#654,#655,#656,#657,#658,#659,#660,#661,#662,#663,#664,#665,#666,#667,#668,#669,#670,#671,#672,#673,#674,#675,#676),$);
|
||||
#678=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#625));
|
||||
#679=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#677));
|
||||
#680=IFCGEOGRAPHICELEMENTTYPE('3mKZtHjt12Rh_uInKdrcGZ',$,'Shrub Big (1.8m)',$,$,$,(#685,#690),$,$,.NOTDEFINED.);
|
||||
#681=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#682=IFCDIRECTION((1.,0.,0.));
|
||||
#683=IFCDIRECTION((0.,0.,1.));
|
||||
#684=IFCAXIS2PLACEMENT3D(#681,#683,#682);
|
||||
#685=IFCREPRESENTATIONMAP(#684,#679);
|
||||
#686=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#687=IFCDIRECTION((1.,0.,0.));
|
||||
#688=IFCDIRECTION((0.,0.,1.));
|
||||
#689=IFCAXIS2PLACEMENT3D(#686,#688,#687);
|
||||
#690=IFCREPRESENTATIONMAP(#689,#678);
|
||||
#691=IFCCARTESIANPOINT((0.,0.));
|
||||
#692=IFCAXIS2PLACEMENT2D(#691,$);
|
||||
#693=IFCCIRCLE(#692,100.);
|
||||
#694=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#693);
|
||||
#695=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#696=IFCDIRECTION((0.,0.,1.));
|
||||
#697=IFCDIRECTION((1.,0.,0.));
|
||||
#698=IFCAXIS2PLACEMENT3D(#695,#696,#697);
|
||||
#699=IFCDIRECTION((0.,0.,1.));
|
||||
#700=IFCEXTRUDEDAREASOLID(#694,#698,#699,460.);
|
||||
#701=IFCCARTESIANPOINT((0.,0.,1130.));
|
||||
#702=IFCDIRECTION((0.,0.,1.));
|
||||
#703=IFCDIRECTION((1.,0.,0.));
|
||||
#704=IFCAXIS2PLACEMENT3D(#701,#702,#703);
|
||||
#705=IFCSPHERE(#704,670.);
|
||||
#706=IFCCARTESIANPOINT((0.,0.));
|
||||
#707=IFCAXIS2PLACEMENT2D(#706,$);
|
||||
#708=IFCCIRCLE(#707,670.);
|
||||
#709=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#708));
|
||||
#710=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#700,#705));
|
||||
#711=IFCGEOGRAPHICELEMENTTYPE('24b7xpbZb38f1BXogqUXhD',$,'Simple Tree (1.8m)',$,$,$,(#716,#721),$,$,.NOTDEFINED.);
|
||||
#712=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#713=IFCDIRECTION((1.,0.,0.));
|
||||
#714=IFCDIRECTION((0.,0.,1.));
|
||||
#715=IFCAXIS2PLACEMENT3D(#712,#714,#713);
|
||||
#716=IFCREPRESENTATIONMAP(#715,#710);
|
||||
#717=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#718=IFCDIRECTION((1.,0.,0.));
|
||||
#719=IFCDIRECTION((0.,0.,1.));
|
||||
#720=IFCAXIS2PLACEMENT3D(#717,#719,#718);
|
||||
#721=IFCREPRESENTATIONMAP(#720,#709);
|
||||
#722=IFCCARTESIANPOINT((0.,0.));
|
||||
#723=IFCAXIS2PLACEMENT2D(#722,$);
|
||||
#724=IFCCIRCLE(#723,100.);
|
||||
#725=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#724);
|
||||
#726=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#727=IFCDIRECTION((0.,0.,1.));
|
||||
#728=IFCDIRECTION((1.,0.,0.));
|
||||
#729=IFCAXIS2PLACEMENT3D(#726,#727,#728);
|
||||
#730=IFCDIRECTION((0.,0.,1.));
|
||||
#731=IFCEXTRUDEDAREASOLID(#725,#729,#730,1710.);
|
||||
#732=IFCCARTESIANPOINT((0.,0.,3355.));
|
||||
#733=IFCDIRECTION((0.,0.,1.));
|
||||
#734=IFCDIRECTION((1.,0.,0.));
|
||||
#735=IFCAXIS2PLACEMENT3D(#732,#733,#734);
|
||||
#736=IFCSPHERE(#735,1645.);
|
||||
#737=IFCCARTESIANPOINT((0.,0.));
|
||||
#738=IFCAXIS2PLACEMENT2D(#737,$);
|
||||
#739=IFCCIRCLE(#738,1645.);
|
||||
#740=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#739));
|
||||
#741=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#731,#736));
|
||||
#742=IFCGEOGRAPHICELEMENTTYPE('3VL8Zl9Xb2AwPSDD7jujfl',$,'Simple Tree (5m)',$,$,$,(#747,#752),$,$,.NOTDEFINED.);
|
||||
#743=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#744=IFCDIRECTION((1.,0.,0.));
|
||||
#745=IFCDIRECTION((0.,0.,1.));
|
||||
#746=IFCAXIS2PLACEMENT3D(#743,#745,#744);
|
||||
#747=IFCREPRESENTATIONMAP(#746,#741);
|
||||
#748=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#749=IFCDIRECTION((1.,0.,0.));
|
||||
#750=IFCDIRECTION((0.,0.,1.));
|
||||
#751=IFCAXIS2PLACEMENT3D(#748,#750,#749);
|
||||
#752=IFCREPRESENTATIONMAP(#751,#740);
|
||||
#753=IFCCARTESIANPOINT((0.,0.));
|
||||
#754=IFCAXIS2PLACEMENT2D(#753,$);
|
||||
#755=IFCCIRCLE(#754,220.);
|
||||
#756=IFCARBITRARYCLOSEDPROFILEDEF(.AREA.,$,#755);
|
||||
#757=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#758=IFCDIRECTION((0.,0.,1.));
|
||||
#759=IFCDIRECTION((1.,0.,0.));
|
||||
#760=IFCAXIS2PLACEMENT3D(#757,#758,#759);
|
||||
#761=IFCDIRECTION((0.,0.,1.));
|
||||
#762=IFCEXTRUDEDAREASOLID(#756,#760,#761,5790.);
|
||||
#763=IFCCARTESIANPOINT((0.,0.,10395.));
|
||||
#764=IFCDIRECTION((0.,0.,1.));
|
||||
#765=IFCDIRECTION((1.,0.,0.));
|
||||
#766=IFCAXIS2PLACEMENT3D(#763,#764,#765);
|
||||
#767=IFCSPHERE(#766,4605.);
|
||||
#768=IFCCARTESIANPOINT((0.,0.));
|
||||
#769=IFCAXIS2PLACEMENT2D(#768,$);
|
||||
#770=IFCCIRCLE(#769,4605.);
|
||||
#771=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#770));
|
||||
#772=IFCSHAPEREPRESENTATION(#15,'Body','SweptSolid',(#762,#767));
|
||||
#773=IFCGEOGRAPHICELEMENTTYPE('3jGYIuJcL0phM2h4r9r95Q',$,'Simple Tree (15m)',$,$,$,(#778,#783),$,$,.NOTDEFINED.);
|
||||
#774=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#775=IFCDIRECTION((1.,0.,0.));
|
||||
#776=IFCDIRECTION((0.,0.,1.));
|
||||
#777=IFCAXIS2PLACEMENT3D(#774,#776,#775);
|
||||
#778=IFCREPRESENTATIONMAP(#777,#772);
|
||||
#779=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#780=IFCDIRECTION((1.,0.,0.));
|
||||
#781=IFCDIRECTION((0.,0.,1.));
|
||||
#782=IFCAXIS2PLACEMENT3D(#779,#781,#780);
|
||||
#783=IFCREPRESENTATIONMAP(#782,#771);
|
||||
#784=IFCCARTESIANPOINTLIST2D(((-498.579620361328,735.001647949219),(-644.625122070312,558.698791503906),(-614.925903320312,498.60498046875),(-740.696044921875,396.37109375),(-782.288513183594,134.234802246094),(-551.41796875,97.9387969970703),(-788.211303710938,76.7640991210938),(-816.569641113281,-242.43864440918),(-685.161376953125,-297.968902587891),(-703.043884277344,-397.560852050781),(-586.489440917969,-569.15283203125),(-528.322204589844,-575.251037597656),(-366.814422607422,-750.108703613281),(-257.688507080078,-767.03466796875),(-273.860229492188,-683.197692871094),(-185.236541748047,-810.123107910156),(313.798278808594,-745.734313964844),(262.069519042969,-582.365661621094),(406.147064208984,-688.067260742188),(778.871398925781,-313.5146484375),(703.457824707031,-249.706893920898),(805.686340332031,-208.338500976562),(821.777282714844,71.8945388793945),(639.965148925781,44.3083839416504),(773.707153320312,162.339202880859),(703.734558105469,469.384552001953),(564.003479003906,549.215209960938),(489.063201904297,694.462707519531),(337.980773925781,746.2314453125),(159.236328125,638.655029296875),(287.592864990234,774.293273925781),(-11.1607036590576,832.838073730469),(-158.524017333984,800.207580566406),(-271.424072265625,751.009338378906)));
|
||||
#785=IFCINDEXEDPOLYCURVE(#784,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#786=IFCCARTESIANPOINTLIST3D(((80.,0.,0.),(40.,69.2820323027551,0.),(-40.,69.2820323027551,0.),(-80.,9.79717439317883E-15,0.),(-40.,-69.2820323027551,0.),(40.,-69.2820323027551,0.),(80.,0.,280.),(40.,69.2820323027551,280.),(-40.,69.2820323027551,280.),(-80.,9.79717439317883E-15,280.),(-40.,-69.2820323027551,280.),(40.,-69.2820323027551,280.),(610.340986817674,-5.11998806339175,502.765430824539),(281.439072714044,546.677704468069,520.441255965265),(-291.549977559115,499.655102439697,498.631051036932),(-617.600357563209,-18.0002392785791,529.745674601363),(-266.847896537159,-556.910514833911,523.07445182747),(310.029723989709,-532.642943384166,481.563368832141),(699.397468993717,-3.10815712380199,727.667741239885),(355.052935043769,568.360673738432,733.570036889682),(-308.666246071194,628.582194868307,722.445245365077),(-719.613234433747,-35.7080296205946,687.931736233252),(-311.6478364595,-608.980286853059,704.648197605265),(372.070129606822,-608.152053362288,717.812431534607),(763.794228948937,-31.3204193188668,937.51589967911),(408.972888631657,640.716082391856,911.578097173966),(-390.473345044531,632.112510840184,931.184023328963),(-745.505233761067,11.3681475906559,933.839400395571),(-358.630946664301,-690.676374550022,936.269525762716),(375.140586877863,-658.159992875781,903.558501964971),(869.836914477244,-29.0443800107266,1124.54961826854),(447.136382145783,768.355555760864,1143.76409675514),(-431.186180114122,717.796288298907,1132.35007279295),(-841.55780048986,-23.1508504281077,1121.17416888324),(-428.187090174966,-760.246071143039,1159.279616419),(448.116008554028,-716.140773181744,1147.14103266758),(757.425130447899,-4.70084047240072,1330.07490310776),(399.505270456854,653.333240297718,1352.71275883304),(-414.445397665745,661.713946940036,1371.67941135993),(-776.277740187312,26.6072792686131,1378.19571732018),(-402.818606589622,-663.628443148848,1395.27272058484),(385.647897991142,-658.102369718758,1334.23398662872),(686.035800389567,-2.77622907865673,1575.7384942221),(337.67134578655,600.901570871229,1585.64117034361),(-344.127505367052,570.723591037471,1578.6341137138),(-653.055169703612,-6.10749408831596,1549.40002660187),(-379.19620927887,-592.236118824385,1550.49839466833),(314.077525184638,-622.955785610011,1579.55078264226),(0.05,0.,1800.),(0.025,0.0433012701892219,1800.),(-0.025,0.0433012701892219,1800.),(-0.05,6.12323399573677E-18,1800.),(-0.025,-0.0433012701892219,1800.),(0.025,-0.0433012701892219,1800.)));
|
||||
#787=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#788=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#789=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#790=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#791=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#792=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#793=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#794=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#795=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#796=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#797=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#798=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#799=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#800=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#801=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#802=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#803=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#804=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#805=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#806=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#807=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#808=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#809=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#810=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#811=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#812=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#813=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#814=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#815=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#816=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#817=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#818=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#819=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#820=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#821=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#822=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#823=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#824=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#825=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#826=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#827=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#828=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#829=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#830=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#831=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#832=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#833=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#834=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#835=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#836=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#837=IFCPOLYGONALFACESET(#786,$,(#787,#788,#789,#790,#791,#792,#793,#794,#795,#796,#797,#798,#799,#800,#801,#802,#803,#804,#805,#806,#807,#808,#809,#810,#811,#812,#813,#814,#815,#816,#817,#818,#819,#820,#821,#822,#823,#824,#825,#826,#827,#828,#829,#830,#831,#832,#833,#834,#835,#836),$);
|
||||
#838=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#785));
|
||||
#839=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#837));
|
||||
#840=IFCGEOGRAPHICELEMENTTYPE('1CLHhCfcnFaBY1EM4kLSOR',$,'Tree Small (1.8m)',$,$,$,(#845,#850),$,$,.NOTDEFINED.);
|
||||
#841=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#842=IFCDIRECTION((1.,0.,0.));
|
||||
#843=IFCDIRECTION((0.,0.,1.));
|
||||
#844=IFCAXIS2PLACEMENT3D(#841,#843,#842);
|
||||
#845=IFCREPRESENTATIONMAP(#844,#839);
|
||||
#846=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#847=IFCDIRECTION((1.,0.,0.));
|
||||
#848=IFCDIRECTION((0.,0.,1.));
|
||||
#849=IFCAXIS2PLACEMENT3D(#846,#848,#847);
|
||||
#850=IFCREPRESENTATIONMAP(#849,#838);
|
||||
#851=IFCCARTESIANPOINTLIST2D(((-2932.8212890625,4323.5390625),(-3791.91259765625,3286.46362304688),(-3617.21118164062,2932.97045898438),(-4357.03564453125,2331.5947265625),(-4601.697265625,789.616455078125),(-3243.63500976562,576.110534667969),(-4636.537109375,451.553527832031),(-4803.35107421875,-1426.10961914062),(-4030.36108398438,-1752.75817871094),(-4135.55224609375,-2338.59326171875),(-3449.93798828125,-3347.95776367188),(-3107.77783203125,-3383.82958984375),(-2157.73193359375,-4412.404296875),(-1515.81469726562,-4511.96826171875),(-1610.94250488281,-4018.80981445312),(-1089.62670898438,-4765.43017578125),(1845.87219238281,-4386.67236328125),(1541.58532714844,-3425.68041992188),(2389.10034179688,-4047.45458984375),(4581.5966796875,-1844.20373535156),(4137.9873046875,-1468.86413574219),(4739.33154296875,-1225.52062988281),(4833.98388671875,422.909027099609),(3764.5009765625,260.637542724609),(4551.21826171875,954.936462402344),(4139.615234375,2761.08569335938),(3317.66748046875,3230.677734375),(2876.84228515625,4085.07470703125),(1988.12219238281,4389.5966796875),(936.684326171875,3756.79443359375),(1691.72277832031,4554.66650390625),(-65.6511993408203,4899.0478515625),(-932.494262695312,4707.103515625),(-1596.61218261719,4417.7021484375)));
|
||||
#852=IFCINDEXEDPOLYCURVE(#851,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#853=IFCCARTESIANPOINTLIST3D(((220.,0.,0.),(110.,190.525588832576,0.),(-110.,190.525588832577,0.),(-220.,2.69422295812418E-14,0.),(-110.,-190.525588832576,0.),(110.,-190.525588832576,0.),(220.,0.,1830.),(110.,190.525588832576,1830.),(-110.,190.525588832577,1830.),(-220.,2.69422295812418E-14,1830.),(-110.,-190.525588832576,1830.),(110.,-190.525588832576,1830.),(3602.84155681395,-42.6665671949312,3758.28335210925),(1603.6589392837,3271.04318828699,3905.58189494864),(-1687.91647965929,2879.18817138389,3723.83018721253),(-3663.33631302674,-150.001993988159,3983.11871691612),(-1482.06580447633,-3356.31660800234,3927.52519380035),(1841.91436658091,-3154.08684592113,3581.5995021726),(4144.97890828097,-25.9013093650166,5704.3740341419),(2117.10779203141,3278.52951811646,5753.55983122354),(-1730.55205059328,3780.37552753208,5660.85323518517),(-4313.44362028123,-297.566913504955,5373.24065908662),(-1755.3986371625,-3617.02629407169,5512.5445038534),(2258.91774672351,-3610.12434831526,5622.24645326459),(4481.61857457447,-261.00349432389,7525.01344970687),(2466.44073859714,3708.28617613811,7308.86509549734),(-2312.27787537109,3636.58974654084,7472.24781345564),(-4329.21028134222,94.734563255466,7494.37595567738),(-2046.92455553584,-4124.62194412282,7514.62700040359),(2184.50489064885,-3853.65209683748,7242.03513542238),(5165.3076206437,-242.036500089388,9155.53253319023),(2684.46985121485,4598.74337345629,9315.65318724518),(-2551.55150095102,4177.41614460665,9220.53632089363),(-4929.6483374155,-192.923753567564,9127.40378831275),(-2526.55908479138,-4531.16433497441,9444.94918444402),(2692.6334046169,-4163.62018529695,9343.7943198489),(4428.54275373249,-39.1736706033394,10940.1480020885),(2387.54392047378,3813.42915868696,11128.7967997992),(-2512.04498054787,3883.26838070627,11286.8522375232),(-4585.64783489427,221.727327238442,11341.154787192),(-2415.15505491352,-3899.22251577971,11483.4631477308),(2272.06581659285,-3853.17190386229,10974.8070314298),(4033.63166991306,-23.1352423221394,13059.2493566128),(1972.26121488791,3549.70366088977,13141.7716576253),(-2026.06254472544,3298.22049560846,13083.3795190436),(-3758.79308086343,-50.8957840692999,12839.7621264441),(-2318.30174399058,-3477.4915604994,12848.9151936647),(1775.64604320532,-3733.48878371295,13091.0184267807),(0.05,0.,15000.),(0.025,0.0433012701892219,15000.),(-0.025,0.0433012701892219,15000.),(-0.05,6.12323399573677E-18,15000.),(-0.025,-0.0433012701892219,15000.),(0.025,-0.0433012701892219,15000.)));
|
||||
#854=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#855=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#856=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#857=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#858=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#859=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#860=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#861=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#862=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#863=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#864=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#865=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#866=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#867=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#868=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#869=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#870=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#871=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#872=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#873=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#874=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#875=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#876=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#877=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#878=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#879=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#880=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#881=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#882=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#883=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#884=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#885=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#886=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#887=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#888=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#889=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#890=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#891=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#892=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#893=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#894=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#895=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#896=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#897=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#898=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#899=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#900=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#901=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#902=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#903=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#904=IFCPOLYGONALFACESET(#853,$,(#854,#855,#856,#857,#858,#859,#860,#861,#862,#863,#864,#865,#866,#867,#868,#869,#870,#871,#872,#873,#874,#875,#876,#877,#878,#879,#880,#881,#882,#883,#884,#885,#886,#887,#888,#889,#890,#891,#892,#893,#894,#895,#896,#897,#898,#899,#900,#901,#902,#903),$);
|
||||
#905=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#852));
|
||||
#906=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#904));
|
||||
#907=IFCGEOGRAPHICELEMENTTYPE('1$Hd6qXnz8ff4y_T2Agko8',$,'Tree Big (15m)',$,$,$,(#912,#917),$,$,.NOTDEFINED.);
|
||||
#908=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#909=IFCDIRECTION((1.,0.,0.));
|
||||
#910=IFCDIRECTION((0.,0.,1.));
|
||||
#911=IFCAXIS2PLACEMENT3D(#908,#910,#909);
|
||||
#912=IFCREPRESENTATIONMAP(#911,#906);
|
||||
#913=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#914=IFCDIRECTION((1.,0.,0.));
|
||||
#915=IFCDIRECTION((0.,0.,1.));
|
||||
#916=IFCAXIS2PLACEMENT3D(#913,#915,#914);
|
||||
#917=IFCREPRESENTATIONMAP(#916,#905);
|
||||
#918=IFCCARTESIANPOINTLIST2D(((-1466.41064453125,2161.76953125),(-1895.95629882812,1643.23181152344),(-1808.60559082031,1466.48522949219),(-2178.51782226562,1165.79736328125),(-2300.8486328125,394.808227539062),(-1621.81750488281,288.055267333984),(-2318.2685546875,225.776763916016),(-2401.67553710938,-713.054809570312),(-2015.18054199219,-876.379089355469),(-2067.77612304688,-1169.29663085938),(-1724.96899414062,-1673.97888183594),(-1553.88891601562,-1691.91479492188),(-1078.86596679688,-2206.2021484375),(-757.907348632812,-2255.98413085938),(-805.471252441406,-2009.40490722656),(-544.813354492188,-2382.71508789062),(922.936096191406,-2193.33618164062),(770.792663574219,-1712.84020996094),(1194.55017089844,-2023.72729492188),(2290.79833984375,-922.101867675781),(2068.99365234375,-734.432067871094),(2369.66577148438,-612.760314941406),(2416.99194335938,211.454513549805),(1882.25048828125,130.318771362305),(2275.60913085938,477.468231201172),(2069.8076171875,1380.54284667969),(1658.83374023438,1615.3388671875),(1438.42114257812,2042.53735351562),(994.061096191406,2194.79833984375),(468.342163085938,1878.39721679688),(845.861389160156,2277.33325195312),(-32.8255996704102,2449.52392578125),(-466.247131347656,2353.5517578125),(-798.306091308594,2208.85107421875)));
|
||||
#919=IFCINDEXEDPOLYCURVE(#918,(IFCLINEINDEX((1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,1))),$);
|
||||
#920=IFCCARTESIANPOINTLIST3D(((110.,0.,0.),(55.,95.2627944162882,0.),(-55.,95.2627944162883,0.),(-110.,1.34711147906209E-14,0.),(-55.,-95.2627944162882,0.),(55.,-95.2627944162882,0.),(110.,0.,840.),(55.,95.2627944162882,840.),(-55.,95.2627944162883,840.),(-110.,1.34711147906209E-14,840.),(-55.,-95.2627944162882,840.),(55.,-95.2627944162882,840.),(1794.28051893798,-14.2221890649771,1449.90397451261),(831.219646427901,1604.18946900776,1499.0034887924),(-859.305493219764,1473.57113004006,1438.4195862137),(-1814.44543767558,-50.0006646627197,1524.8490961149),(-790.68860149211,-1632.61394224621,1506.31792174297),(910.638122193637,-1565.20402155248,1391.00935786706),(2054.99296942699,-8.63376978833887,2065.74372566635),(1042.36926401047,1675.96694458701,2082.13899136023),(-913.517350197761,1843.24894772555,2051.23679268077),(-2111.14787342708,-99.1889711683183,1955.36593398126),(-921.799545720834,-1788.79920323875,2001.80054890351),(1089.63924890784,-1786.49855465328,2038.36786537391),(2247.20619152482,-87.0011647746299,2639.76638799753),(1198.81357953238,1888.50119623031,2567.71693659435),(-1147.42595845703,1864.60238636456,2622.17784258045),(-2196.40342711407,31.5781877518221,2629.5538899877),(-1058.97485184528,-2027.27978555855,2636.30423822977),(1104.83496354962,-1936.9565031301,2545.44028323603),(2555.10254021457,-80.6788333631295,3150.41560630151),(1311.48995040495,2254.60229430579,3203.78915765315),(-1267.18383365034,2114.15988468925,3172.08353553597),(-2476.54944580517,-64.3079178558546,3141.03935800901),(-1258.85302826379,-2232.07594814517,3246.8878233861),(1314.2111348723,-2109.56123158602,3213.16953518773),(2229.51425124416,-13.0578902011131,3712.43028641044),(1172.51464015793,1923.54885707993,3775.31321898068),(-1214.01499351596,1946.82859775303,3827.99836488869),(-2281.88261163142,73.9091090794808,3846.09921477827),(-1181.71835163784,-1952.14664277751,3893.53533495789),(1134.02193886428,-1936.79643880504,3723.98329619088),(2017.87722330435,-7.71174744071313,4385.94026172807),(994.087071629305,1766.35832551144,4413.44769539892),(-1012.02084824181,1682.53060375101,4393.983649205),(-1926.26436028781,-16.9652613564332,4312.77785167185),(-1109.43391466353,-1742.28762538132,4315.82887407871),(928.548681068438,-1827.62003311917,4396.52995178405),(0.05,0.,5000.),(0.025,0.0433012701892219,5000.),(-0.025,0.0433012701892219,5000.),(-0.05,6.12323399573677E-18,5000.),(-0.025,-0.0433012701892219,5000.),(0.025,-0.0433012701892219,5000.)));
|
||||
#921=IFCINDEXEDPOLYGONALFACE((1,2,3,4,5,6));
|
||||
#922=IFCINDEXEDPOLYGONALFACE((6,1,7,12));
|
||||
#923=IFCINDEXEDPOLYGONALFACE((1,2,8,7));
|
||||
#924=IFCINDEXEDPOLYGONALFACE((2,3,9,8));
|
||||
#925=IFCINDEXEDPOLYGONALFACE((3,4,10,9));
|
||||
#926=IFCINDEXEDPOLYGONALFACE((4,5,11,10));
|
||||
#927=IFCINDEXEDPOLYGONALFACE((5,6,12,11));
|
||||
#928=IFCINDEXEDPOLYGONALFACE((12,7,13,18));
|
||||
#929=IFCINDEXEDPOLYGONALFACE((7,8,14,13));
|
||||
#930=IFCINDEXEDPOLYGONALFACE((8,9,15,14));
|
||||
#931=IFCINDEXEDPOLYGONALFACE((9,10,16,15));
|
||||
#932=IFCINDEXEDPOLYGONALFACE((10,11,17,16));
|
||||
#933=IFCINDEXEDPOLYGONALFACE((11,12,18,17));
|
||||
#934=IFCINDEXEDPOLYGONALFACE((18,13,19,24));
|
||||
#935=IFCINDEXEDPOLYGONALFACE((13,14,20,19));
|
||||
#936=IFCINDEXEDPOLYGONALFACE((14,15,21,20));
|
||||
#937=IFCINDEXEDPOLYGONALFACE((15,16,22,21));
|
||||
#938=IFCINDEXEDPOLYGONALFACE((16,17,23,22));
|
||||
#939=IFCINDEXEDPOLYGONALFACE((17,18,24,23));
|
||||
#940=IFCINDEXEDPOLYGONALFACE((24,19,25,30));
|
||||
#941=IFCINDEXEDPOLYGONALFACE((19,20,26,25));
|
||||
#942=IFCINDEXEDPOLYGONALFACE((20,21,27,26));
|
||||
#943=IFCINDEXEDPOLYGONALFACE((21,22,28,27));
|
||||
#944=IFCINDEXEDPOLYGONALFACE((22,23,29,28));
|
||||
#945=IFCINDEXEDPOLYGONALFACE((23,24,30,29));
|
||||
#946=IFCINDEXEDPOLYGONALFACE((30,25,31,36));
|
||||
#947=IFCINDEXEDPOLYGONALFACE((25,26,32,31));
|
||||
#948=IFCINDEXEDPOLYGONALFACE((26,27,33,32));
|
||||
#949=IFCINDEXEDPOLYGONALFACE((27,28,34,33));
|
||||
#950=IFCINDEXEDPOLYGONALFACE((28,29,35,34));
|
||||
#951=IFCINDEXEDPOLYGONALFACE((29,30,36,35));
|
||||
#952=IFCINDEXEDPOLYGONALFACE((36,31,37,42));
|
||||
#953=IFCINDEXEDPOLYGONALFACE((31,32,38,37));
|
||||
#954=IFCINDEXEDPOLYGONALFACE((32,33,39,38));
|
||||
#955=IFCINDEXEDPOLYGONALFACE((33,34,40,39));
|
||||
#956=IFCINDEXEDPOLYGONALFACE((34,35,41,40));
|
||||
#957=IFCINDEXEDPOLYGONALFACE((35,36,42,41));
|
||||
#958=IFCINDEXEDPOLYGONALFACE((42,37,43,48));
|
||||
#959=IFCINDEXEDPOLYGONALFACE((37,38,44,43));
|
||||
#960=IFCINDEXEDPOLYGONALFACE((38,39,45,44));
|
||||
#961=IFCINDEXEDPOLYGONALFACE((39,40,46,45));
|
||||
#962=IFCINDEXEDPOLYGONALFACE((40,41,47,46));
|
||||
#963=IFCINDEXEDPOLYGONALFACE((41,42,48,47));
|
||||
#964=IFCINDEXEDPOLYGONALFACE((48,43,49,54));
|
||||
#965=IFCINDEXEDPOLYGONALFACE((43,44,50,49));
|
||||
#966=IFCINDEXEDPOLYGONALFACE((44,45,51,50));
|
||||
#967=IFCINDEXEDPOLYGONALFACE((45,46,52,51));
|
||||
#968=IFCINDEXEDPOLYGONALFACE((46,47,53,52));
|
||||
#969=IFCINDEXEDPOLYGONALFACE((47,48,54,53));
|
||||
#970=IFCINDEXEDPOLYGONALFACE((49,50,51,52,53,54));
|
||||
#971=IFCPOLYGONALFACESET(#920,$,(#921,#922,#923,#924,#925,#926,#927,#928,#929,#930,#931,#932,#933,#934,#935,#936,#937,#938,#939,#940,#941,#942,#943,#944,#945,#946,#947,#948,#949,#950,#951,#952,#953,#954,#955,#956,#957,#958,#959,#960,#961,#962,#963,#964,#965,#966,#967,#968,#969,#970),$);
|
||||
#972=IFCSHAPEREPRESENTATION(#16,'Body','Curve2D',(#919));
|
||||
#973=IFCSHAPEREPRESENTATION(#15,'Body','Tessellation',(#971));
|
||||
#974=IFCGEOGRAPHICELEMENTTYPE('1t393Epk10ahdDnhnFR8sr',$,'Tree Medium (5m)',$,$,$,(#979,#984),$,$,.NOTDEFINED.);
|
||||
#975=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#976=IFCDIRECTION((1.,0.,0.));
|
||||
#977=IFCDIRECTION((0.,0.,1.));
|
||||
#978=IFCAXIS2PLACEMENT3D(#975,#977,#976);
|
||||
#979=IFCREPRESENTATIONMAP(#978,#973);
|
||||
#980=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#981=IFCDIRECTION((1.,0.,0.));
|
||||
#982=IFCDIRECTION((0.,0.,1.));
|
||||
#983=IFCAXIS2PLACEMENT3D(#980,#982,#981);
|
||||
#984=IFCREPRESENTATIONMAP(#983,#972);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -21,6 +21,7 @@ import bpy
|
||||
import json
|
||||
import addon_utils
|
||||
import ifcopenshell.api.owner.settings
|
||||
import blenderbim.bim
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.owner as core_owner
|
||||
from bpy.app.handlers import persistent
|
||||
@@ -253,85 +254,58 @@ def viewport_shading_changed_callback(area):
|
||||
bpy.context.scene.BIMStylesProperties.active_style_type = "External"
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_scene"):
|
||||
@classmethod
|
||||
def poll_check_blender_tab(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
class Override_SCENE_PT_scene(bpy.types.SCENE_PT_scene):
|
||||
bl_idname = "SCENE_PT_scene_override"
|
||||
|
||||
def get_override_scene_panel(panel_name):
|
||||
original_panel = getattr(bpy.types, panel_name)
|
||||
|
||||
override_panel = type(f"Override_{panel_name}", (original_panel,), {})
|
||||
override_panel.bl_idname = f"{panel_name}_override"
|
||||
|
||||
# some blender panel depend on other and register_class will throw an error
|
||||
# if we won't override their `bl_parent_id`
|
||||
bl_parent_id = getattr(override_panel, "bl_parent_id", None)
|
||||
if bl_parent_id is not None:
|
||||
override_panel.bl_parent_id = f"{bl_parent_id}_override"
|
||||
|
||||
# override poll method
|
||||
poll = getattr(override_panel, "poll", None)
|
||||
if poll is None:
|
||||
override_panel.poll = poll_check_blender_tab
|
||||
else:
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
def wrapped_poll(cls, context):
|
||||
return super(override_panel, cls).poll(context) and poll_check_blender_tab.__func__(cls, context)
|
||||
|
||||
override_panel.poll = wrapped_poll
|
||||
|
||||
return override_panel
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_unit"):
|
||||
|
||||
class Override_SCENE_PT_unit(bpy.types.SCENE_PT_unit):
|
||||
bl_idname = "SCENE_PT_unit_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_physics"):
|
||||
|
||||
class Override_SCENE_PT_physics(bpy.types.SCENE_PT_physics):
|
||||
bl_idname = "SCENE_PT_physics_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_rigid_body_world"):
|
||||
|
||||
class Override_SCENE_PT_rigid_body_world(bpy.types.SCENE_PT_rigid_body_world):
|
||||
bl_idname = "SCENE_PT_rigid_body_world_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_audio"):
|
||||
|
||||
class Override_SCENE_PT_audio(bpy.types.SCENE_PT_audio):
|
||||
bl_idname = "SCENE_PT_audio_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_keying_sets"):
|
||||
|
||||
class Override_SCENE_PT_keying_sets(bpy.types.SCENE_PT_keying_sets):
|
||||
bl_idname = "SCENE_PT_keying_sets_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
if getattr(bpy.types, "SCENE_PT_custom_props"):
|
||||
|
||||
class Override_SCENE_PT_custom_props(bpy.types.SCENE_PT_custom_props):
|
||||
bl_idname = "SCENE_PT_custom_props_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
|
||||
|
||||
# available on Blender 4.0+
|
||||
if getattr(bpy.types, "SCENE_PT_simulation", None):
|
||||
|
||||
class Override_SCENE_PT_simulation(bpy.types.SCENE_PT_simulation):
|
||||
bl_idname = "SCENE_PT_simulation_override"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return tool.Blender.is_tab(context, "BLENDER")
|
||||
# TODO: possibly override scene panels from other addons too?
|
||||
# list can be updated from
|
||||
# https://projects.blender.org/blender/blender/src/branch/main/scripts/startup/bl_ui/properties_scene.py#L421
|
||||
OVERRIDE_SCENE_PANELS = (
|
||||
"SCENE_PT_scene",
|
||||
"SCENE_PT_unit",
|
||||
"SCENE_PT_physics",
|
||||
"SCENE_PT_rigid_body_world",
|
||||
"SCENE_PT_rigid_body_world_settings",
|
||||
"SCENE_PT_rigid_body_cache",
|
||||
"SCENE_PT_rigid_body_field_weights",
|
||||
"SCENE_PT_audio",
|
||||
"SCENE_PT_keying_sets",
|
||||
"SCENE_PT_custom_props",
|
||||
# after SCENE_PT_keying_sets
|
||||
"SCENE_PT_keying_set_paths",
|
||||
"SCENE_PT_keyframing_settings",
|
||||
)
|
||||
if bpy.app.version >= (4, 0):
|
||||
OVERRIDE_SCENE_PANELS += ("SCENE_PT_simulation",)
|
||||
|
||||
|
||||
@persistent
|
||||
@@ -372,27 +346,12 @@ def load_post(scene):
|
||||
# To improve usability for new users, we hijack the scene properties
|
||||
# tab. We override default scene properties panels with our own poll
|
||||
# to hide them unless the user has chosen to view Blender properties.
|
||||
for panel in [
|
||||
"SCENE_PT_scene",
|
||||
"SCENE_PT_unit",
|
||||
"SCENE_PT_physics",
|
||||
"SCENE_PT_rigid_body_world",
|
||||
"SCENE_PT_audio",
|
||||
"SCENE_PT_keying_sets",
|
||||
"SCENE_PT_simulation",
|
||||
"SCENE_PT_custom_props",
|
||||
]:
|
||||
if getattr(bpy.types, panel, None):
|
||||
try:
|
||||
bpy.utils.register_class(globals()[f"Override_{panel}"])
|
||||
bpy.utils.unregister_class(getattr(bpy.types, panel))
|
||||
except:
|
||||
pass
|
||||
|
||||
# https://blender.stackexchange.com/questions/140644/how-can-make-the-state-of-a-boolean-property-relative-to-the-3d-view-area
|
||||
for screen in bpy.data.screens:
|
||||
if len(screen.BIMAreaProperties) == 20:
|
||||
continue
|
||||
screen.BIMAreaProperties.clear()
|
||||
for i in range(20): # 20 is an arbitrary value of split areas
|
||||
screen.BIMAreaProperties.add()
|
||||
for panel in OVERRIDE_SCENE_PANELS:
|
||||
if panel in blenderbim.bim.overridden_scene_panels:
|
||||
continue
|
||||
override_panel = get_override_scene_panel(panel)
|
||||
original_panel = getattr(bpy.types, panel)
|
||||
bpy.utils.register_class(override_panel)
|
||||
bpy.utils.unregister_class(original_panel)
|
||||
blenderbim.bim.overridden_scene_panels[panel] = (original_panel, override_panel)
|
||||
tool.Blender.setup_tabs()
|
||||
|
||||
@@ -245,7 +245,9 @@ def get_obj_ifc_definition_id(context, obj, obj_type):
|
||||
].ifc_definition_id
|
||||
elif obj_type == "WorkSchedule":
|
||||
return context.scene.BIMWorkScheduleProperties.active_work_schedule_id
|
||||
|
||||
elif obj_type == "Group":
|
||||
prop = context.scene.BIMGroupProperties
|
||||
return prop.groups[prop.active_group_index].ifc_definition_id
|
||||
|
||||
# hack to close popup
|
||||
# https://blender.stackexchange.com/a/202576/130742
|
||||
@@ -321,6 +323,7 @@ def draw_filter(layout, filter_groups, data, module):
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "pset", text="", icon="PROPERTIES")
|
||||
row.prop(ifc_filter, "name", text="")
|
||||
row.prop(ifc_filter, "comparison", text="")
|
||||
row.prop(ifc_filter, "value", text="")
|
||||
elif ifc_filter.type == "classification":
|
||||
row = box.row(align=True)
|
||||
@@ -328,6 +331,9 @@ def draw_filter(layout, filter_groups, data, module):
|
||||
elif ifc_filter.type == "location":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="PACKAGE")
|
||||
elif ifc_filter.type == "group":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="OUTLINER_COLLECTION")
|
||||
elif ifc_filter.type == "query":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "name", text="", icon="POINTCLOUD_DATA")
|
||||
|
||||
@@ -80,8 +80,8 @@ class IfcStore:
|
||||
if IfcStore.path:
|
||||
try:
|
||||
IfcStore.load_file(IfcStore.path)
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"Failed to load file {IfcStore.path}. Error details: {e}")
|
||||
return IfcStore.file
|
||||
|
||||
@staticmethod
|
||||
@@ -163,8 +163,12 @@ class IfcStore:
|
||||
if not IfcStore.get_file():
|
||||
return
|
||||
for obj in bpy.data.objects:
|
||||
if obj.library:
|
||||
continue
|
||||
IfcStore.relink_object(obj)
|
||||
for obj in bpy.data.materials:
|
||||
if obj.library:
|
||||
continue
|
||||
IfcStore.relink_object(obj)
|
||||
|
||||
@staticmethod
|
||||
@@ -317,6 +321,7 @@ class IfcStore:
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_operator(operator, context, is_invoke=False):
|
||||
bpy.context.scene.BIMProperties.is_dirty = True
|
||||
is_top_level_operator = not bool(IfcStore.current_transaction)
|
||||
|
||||
if is_top_level_operator:
|
||||
|
||||
@@ -188,6 +188,7 @@ class IfcImporter:
|
||||
self.diff = None
|
||||
self.file = None
|
||||
self.context_settings = []
|
||||
self.gross_context_settings = []
|
||||
self.contexts = []
|
||||
self.project = None
|
||||
self.has_existing_project = False
|
||||
@@ -375,6 +376,15 @@ class IfcImporter:
|
||||
settings.set_context_ids([context.id()])
|
||||
self.context_settings.append(settings)
|
||||
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set_deflection_tolerance(self.ifc_import_settings.deflection_tolerance)
|
||||
settings.set_angular_tolerance(self.ifc_import_settings.angular_tolerance)
|
||||
settings.set(settings.STRICT_TOLERANCE, True)
|
||||
settings.set(settings.INCLUDE_CURVES, True)
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, True)
|
||||
settings.set_context_ids([context.id()])
|
||||
self.gross_context_settings.append(settings)
|
||||
|
||||
def process_element_filter(self):
|
||||
offset = self.ifc_import_settings.element_offset
|
||||
offset_limit = offset + self.ifc_import_settings.element_limit
|
||||
@@ -418,6 +428,17 @@ class IfcImporter:
|
||||
else:
|
||||
self.spatial_elements = set(self.file.by_type("IfcSpatialElement"))
|
||||
|
||||
# Detect excessive voids
|
||||
self.gross_elements = set(
|
||||
filter(lambda e: len(getattr(e, "HasOpenings", [])) > self.ifc_import_settings.void_limit, self.elements)
|
||||
)
|
||||
self.elements = self.elements.difference(self.gross_elements)
|
||||
|
||||
if self.gross_elements:
|
||||
print("Warning! Excessive voids were found and skipped for the following elements:")
|
||||
for element in self.gross_elements:
|
||||
print(element)
|
||||
|
||||
def get_spatial_elements_filtered_by_elements(self, elements):
|
||||
leaf_spatial_elements = set([ifcopenshell.util.element.get_container(e) for e in elements])
|
||||
results = set()
|
||||
@@ -640,7 +661,7 @@ class IfcImporter:
|
||||
if elements_checked > element_checking_threshold:
|
||||
return
|
||||
if element.ObjectPlacement and element.ObjectPlacement.is_a("IfcLocalPlacement"):
|
||||
placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)[:,3][0:3]
|
||||
placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)[:, 3][0:3]
|
||||
if self.is_point_far_away(placement, is_meters=False):
|
||||
return placement
|
||||
if not self.does_element_likely_have_geometry_far_away(element):
|
||||
@@ -816,6 +837,10 @@ class IfcImporter:
|
||||
|
||||
def create_elements(self):
|
||||
self.create_generic_elements(self.elements)
|
||||
tmp = self.context_settings
|
||||
self.context_settings = self.gross_context_settings
|
||||
self.create_generic_elements(self.gross_elements)
|
||||
self.context_settings = tmp
|
||||
|
||||
def create_generic_shape(self, element):
|
||||
for settings in self.context_settings:
|
||||
@@ -1343,7 +1368,7 @@ class IfcImporter:
|
||||
element_type = ifcopenshell.util.element.get_type(element)
|
||||
if not element_type:
|
||||
continue
|
||||
merge_key = str(element_type.id()) + "-" + element_type.Name or "Unnamed"
|
||||
merge_key = str(element_type.id()) + "-" + (element_type.Name or "Unnamed")
|
||||
merge_set.setdefault(merge_key, []).append(obj)
|
||||
id_set.setdefault(merge_key, []).append(ifc_definition_id)
|
||||
self.merge_objects(merge_set, id_set)
|
||||
@@ -1550,20 +1575,27 @@ class IfcImporter:
|
||||
|
||||
def create_aggregate_and_nest_collections(self):
|
||||
if self.ifc_import_settings.has_filter:
|
||||
rel_aggregates = [e.IsDecomposedBy[0] for e in self.elements if e.IsDecomposedBy]
|
||||
rel_aggregates += [e.Decomposes[0] for e in self.elements if e.Decomposes]
|
||||
rel_aggregates += [e.IsNestedBy[0] for e in self.elements if e.IsNestedBy]
|
||||
rel_aggregates += [e.Nests[0] for e in self.elements if e.Nests]
|
||||
rel_aggregates = set(rel_aggregates)
|
||||
rel_aggregates = set()
|
||||
for element in self.elements:
|
||||
if element.IsDecomposedBy:
|
||||
rel_aggregates.add(element.IsDecomposedBy[0])
|
||||
elif element.Decomposes:
|
||||
rel_aggregates.add(element.Decomposes[0])
|
||||
elif getattr(element, "IsNestedBy", []): # IFC2X3 does not have IsNestedBy
|
||||
if [e for e in element.IsNestedBy[0].RelatedObjects if not e.is_a("IfcPort")]:
|
||||
rel_aggregates.add(element.IsNestedBy[0])
|
||||
elif getattr(element, "Nests", []):
|
||||
rel_aggregates.add(element.Nests[0])
|
||||
else:
|
||||
rel_aggregates = [
|
||||
a
|
||||
for a in self.file.by_type("IfcRelAggregates")
|
||||
if a.RelatingObject.is_a("IfcElement") or a.RelatingObject.is_a("IfcElementType")
|
||||
r
|
||||
for r in self.file.by_type("IfcRelAggregates")
|
||||
if r.RelatingObject.is_a("IfcElement") or r.RelatingObject.is_a("IfcElementType")
|
||||
] + [
|
||||
a
|
||||
for a in self.file.by_type("IfcRelNests")
|
||||
if a.RelatingObject.is_a("IfcElement") or a.RelatingObject.is_a("IfcElementType")
|
||||
r
|
||||
for r in self.file.by_type("IfcRelNests")
|
||||
if (r.RelatingObject.is_a("IfcElement") or r.RelatingObject.is_a("IfcElementType"))
|
||||
and [e for e in r.RelatedObjects if not e.is_a("IfcPort")]
|
||||
]
|
||||
|
||||
if len(rel_aggregates) > 10000:
|
||||
@@ -1668,7 +1700,7 @@ class IfcImporter:
|
||||
elif getattr(element, "Decomposes", None):
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
return self.collections[aggregate.GlobalId].objects.link(obj)
|
||||
elif getattr(element, "Nests", None):
|
||||
elif getattr(element, "Nests", None) and not element.is_a("IfcPort"):
|
||||
nest = ifcopenshell.util.element.get_nest(element)
|
||||
return self.collections[nest.GlobalId].objects.link(obj)
|
||||
else:
|
||||
@@ -1948,6 +1980,7 @@ class IfcImportSettings:
|
||||
self.is_coordinating = True
|
||||
self.deflection_tolerance = 0.001
|
||||
self.angular_tolerance = 0.5
|
||||
self.void_limit = 30
|
||||
self.distance_limit = 1000
|
||||
self.false_origin = None
|
||||
self.element_offset = 0
|
||||
@@ -1979,6 +2012,7 @@ class IfcImportSettings:
|
||||
settings.is_coordinating = props.is_coordinating
|
||||
settings.deflection_tolerance = props.deflection_tolerance
|
||||
settings.angular_tolerance = props.angular_tolerance
|
||||
settings.void_limit = props.void_limit
|
||||
settings.distance_limit = props.distance_limit
|
||||
settings.false_origin = [float(o) for o in props.false_origin.split(",")] if props.false_origin else None
|
||||
if settings.false_origin == [0, 0, 0]:
|
||||
|
||||
@@ -20,14 +20,14 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.BIM_OT_assign_object,
|
||||
operator.BIM_OT_unassign_object,
|
||||
operator.BIM_OT_enable_editing_aggregate,
|
||||
operator.BIM_OT_disable_editing_aggregate,
|
||||
operator.BIM_OT_add_aggregate,
|
||||
operator.BIM_OT_select_parts,
|
||||
operator.BIM_OT_select_aggregate,
|
||||
operator.BIM_OT_add_part_to_object,
|
||||
operator.BIM_OT_aggregate_assign_object,
|
||||
operator.BIM_OT_disable_editing_aggregate,
|
||||
operator.BIM_OT_enable_editing_aggregate,
|
||||
operator.BIM_OT_select_aggregate,
|
||||
operator.BIM_OT_select_parts,
|
||||
operator.BIM_OT_aggregate_unassign_object,
|
||||
prop.BIMObjectAggregateProperties,
|
||||
ui.BIM_PT_aggregate,
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ class AggregateData:
|
||||
"has_relating_object": cls.has_relating_object(),
|
||||
"relating_object_label": cls.get_relating_object_label(),
|
||||
"has_related_objects": cls.has_related_objects(),
|
||||
"related_objects_amount": cls.get_related_objects_amount(),
|
||||
"total_parts": cls.total_parts(),
|
||||
"ifc_class": cls.ifc_class(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
@@ -59,7 +59,7 @@ class AggregateData:
|
||||
return ifcopenshell.util.element.get_parts(tool.Ifc.get_entity(bpy.context.active_object))
|
||||
|
||||
@classmethod
|
||||
def get_related_objects_amount(cls):
|
||||
def total_parts(cls):
|
||||
parts = cls.get_related_objects()
|
||||
return len(parts) if parts else 0
|
||||
|
||||
|
||||
@@ -33,11 +33,11 @@ class Operator:
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_assign_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
|
||||
"""Create aggregation relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.assign_object"
|
||||
bl_label = "Assign Object"
|
||||
bl_idname = "bim.aggregate_assign_object"
|
||||
bl_label = "Assign Object To Aggregation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
relating_object: bpy.props.IntProperty()
|
||||
|
||||
@@ -67,11 +67,11 @@ class BIM_OT_assign_object(bpy.types.Operator, Operator):
|
||||
self.report({"ERROR"}, f" Cannot aggregate {obj.name} to {relating_obj.name}")
|
||||
|
||||
|
||||
class BIM_OT_unassign_object(bpy.types.Operator, Operator):
|
||||
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
|
||||
"""Remove aggregation relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.unassign_object"
|
||||
bl_label = "Unassign Object"
|
||||
bl_idname = "bim.aggregate_unassign_object"
|
||||
bl_label = "Unassign Object From Aggregation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
@@ -164,6 +164,7 @@ class BIM_OT_add_aggregate(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def create_aggregate(self, context, ifc_class):
|
||||
aggregate = bpy.data.objects.new("Assembly", None)
|
||||
aggregate.location = context.scene.cursor.location
|
||||
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class=ifc_class)
|
||||
return aggregate
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class BIM_PT_aggregate(Panel):
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "relating_object", text="")
|
||||
if props.relating_object:
|
||||
op = row.operator("bim.assign_object", icon="CHECKMARK", text="")
|
||||
op = row.operator("bim.aggregate_assign_object", icon="CHECKMARK", text="")
|
||||
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
|
||||
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
|
||||
else:
|
||||
@@ -65,15 +65,21 @@ class BIM_PT_aggregate(Panel):
|
||||
op.obj = context.active_object.name
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
op = row.operator("bim.unassign_object", icon="X", text="")
|
||||
op = row.operator("bim.aggregate_unassign_object", icon="X", text="")
|
||||
else:
|
||||
row.label(text="No Aggregate", icon="TRIA_UP")
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
parts = AggregateData.data["related_objects_amount"]
|
||||
row.label(text=f"{parts or 'No'} Part{'s' if parts > 1 else ''}", icon="TRIA_DOWN")
|
||||
total_parts = AggregateData.data["total_parts"]
|
||||
if total_parts == 0:
|
||||
row.label(text="No Parts", icon="TRIA_DOWN")
|
||||
elif total_parts == 1:
|
||||
row.label(text="1 Part", icon="TRIA_DOWN")
|
||||
else:
|
||||
row.label(text=f"{total_parts} Parts", icon="TRIA_DOWN")
|
||||
|
||||
if AggregateData.data["has_related_objects"]:
|
||||
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
|
||||
@@ -22,6 +22,7 @@ import logging
|
||||
import shapely
|
||||
import mathutils
|
||||
import numpy as np
|
||||
import multiprocessing
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.shape
|
||||
@@ -30,7 +31,7 @@ import ifcopenshell.util.placement
|
||||
import ifcopenshell.util.representation
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.import_ifc as import_ifc
|
||||
from math import pi, inf
|
||||
from math import pi, inf, degrees, acos, radians
|
||||
from mathutils import Vector, Matrix
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.model.decorator import ProfileDecorator
|
||||
@@ -63,7 +64,8 @@ def disable_editing_boundary_geometry(context):
|
||||
|
||||
|
||||
class Loader:
|
||||
def __init__(self):
|
||||
def __init__(self, operator=None):
|
||||
self.operator = operator
|
||||
self.ifc_file = None
|
||||
self.logger = None
|
||||
self.ifc_importer = None
|
||||
@@ -85,14 +87,33 @@ class Loader:
|
||||
tool.Loader.link_mesh(shape, mesh)
|
||||
except RuntimeError:
|
||||
# Fallback solution for invalid geometry provided by Revit. (InnerBoundaries cuting OuterBoundary)
|
||||
print(f"Failed to create mesh from IfcRelSpaceBoundary with ID {boundary.id()}. Geometry might be invalid")
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, surface.OuterBoundary)
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
(
|
||||
f"IfcRelSpaceBoundary {boundary.id()} mesh creation failed. Geometry might be invalid. Using fallback solution"
|
||||
),
|
||||
)
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, surface.OuterBoundary)
|
||||
except RuntimeError:
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
f"Skipping IfcRelSpaceBoundary {boundary.id()}. Fallback solution failed. Geometry might be invalid",
|
||||
)
|
||||
return None
|
||||
mesh = bpy.data.meshes.new(str(surface.id()))
|
||||
bm = bmesh.new()
|
||||
verts = [bm.verts.new(shape.verts[i : i + 3]) for i in range(0, len(shape.verts), 3)]
|
||||
bm.faces.new(verts)
|
||||
for inner_boundary in surface.InnerBoundaries:
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, inner_boundary)
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(self.fallback_settings, inner_boundary)
|
||||
except RuntimeError:
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
f"Skipping an inner boundary for IfcRelSpaceBoundary with ID {boundary.id()}. Geometry might be invalid",
|
||||
)
|
||||
return None
|
||||
verts = [bm.verts.new(shape.verts[i : i + 3]) for i in range(0, len(shape.verts), 3)]
|
||||
for i in range(len(verts) - 1):
|
||||
bm.edges.new(verts[i : i + 2])
|
||||
@@ -103,7 +124,7 @@ class Loader:
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
matrix = mathutils.Matrix(
|
||||
ifcopenshell.util.placement.get_axis2placement(surface.BasisSurface.Position).tolist()
|
||||
)
|
||||
)
|
||||
matrix.translation *= unit_scale
|
||||
mesh.transform(matrix)
|
||||
return mesh
|
||||
@@ -126,7 +147,15 @@ class Loader:
|
||||
self.ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
||||
self.ifc_importer.file = self.ifc_file
|
||||
|
||||
def load_boundary(self, boundary, blender_space):
|
||||
def load_boundary(self, boundary, blender_space=None):
|
||||
if not blender_space:
|
||||
if not boundary.RelatingSpace:
|
||||
self.operator.report(
|
||||
{"WARNING"},
|
||||
f"Skipping IfcRelSpaceBoundary {boundary.id()} which have no relating space. Invalid boundary.",
|
||||
)
|
||||
return
|
||||
blender_space = tool.Ifc.get_object(boundary.RelatingSpace)
|
||||
obj = tool.Ifc.get_object(boundary)
|
||||
if obj:
|
||||
return obj
|
||||
@@ -145,9 +174,9 @@ class LoadProjectSpaceBoundaries(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
for rel in tool.Ifc.get().by_type("IfcRelSpaceBoundary"):
|
||||
loader.load_boundary(rel, tool.Ifc.get_object(rel.RelatingSpace))
|
||||
loader.load_boundary(rel)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -158,7 +187,7 @@ class LoadBoundary(bpy.types.Operator):
|
||||
boundary_id: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
for obj in context.visible_objects:
|
||||
obj.select_set(False)
|
||||
obj = loader.load_boundary(tool.Ifc.get().by_id(self.boundary_id), context.active_object)
|
||||
@@ -173,7 +202,7 @@ class LoadSpaceBoundaries(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
element = tool.Ifc.get_entity(context.active_object)
|
||||
for rel in element.BoundedBy or []:
|
||||
loader.load_boundary(rel, context.active_object)
|
||||
@@ -459,7 +488,7 @@ class EditBoundaryGeometry(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), old_surface)
|
||||
|
||||
old_mesh = obj.data
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
obj.data = loader.create_mesh(element)
|
||||
tool.Geometry.delete_data(old_mesh)
|
||||
|
||||
@@ -484,7 +513,7 @@ class ShowBoundaries(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
props = bpy.context.scene.BIMBoundaryProperties
|
||||
loader = Loader()
|
||||
loader = Loader(self)
|
||||
for obj in context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element or not getattr(element, "BoundedBy", None):
|
||||
@@ -538,6 +567,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
related_building_element = None
|
||||
relating_space_obj = None
|
||||
related_building_element_obj = None
|
||||
parent_boundaries = []
|
||||
|
||||
objs = context.selected_objects
|
||||
if len(objs) == 2:
|
||||
@@ -552,8 +582,19 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
related_building_element = element
|
||||
related_building_element_obj = obj
|
||||
parent_boundary = self.create_element_boundary(
|
||||
context, relating_space, relating_space_obj, related_building_element, related_building_element_obj
|
||||
)
|
||||
if parent_boundary:
|
||||
parent_boundaries.append(parent_boundary)
|
||||
elif len(objs) == 1:
|
||||
# New prototype, old code not yet removed. Still testing.
|
||||
space = tool.Ifc.get_entity(objs[0])
|
||||
if space.is_a("IfcSpace"):
|
||||
self.auto_generate_boundaries(space, objs[0])
|
||||
elif len(objs) == 1:
|
||||
# Optionally the user may select just the space, and the building element shall be auto-detected
|
||||
# TODO : refactor to be able to generate all boundaries for selected space automatically or with an option
|
||||
|
||||
def msg(self, context):
|
||||
self.layout.label(text="NO ACTIVE STOREY")
|
||||
@@ -563,8 +604,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
relating_space = element
|
||||
relating_space_obj = objs[0]
|
||||
|
||||
target = bpy.context.scene.cursor.location
|
||||
|
||||
collection = context.view_layer.active_layer_collection.collection
|
||||
collection_obj = bpy.data.objects.get(collection.name)
|
||||
if not collection_obj:
|
||||
@@ -576,19 +615,258 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return
|
||||
|
||||
for subelement in ifcopenshell.util.element.get_decomposition(spatial_element):
|
||||
if not (subelement.is_a("IfcWall") or subelement.is_a("IfcSlab")):
|
||||
if not (
|
||||
subelement.is_a("IfcWall") or subelement.is_a("IfcSlab") or subelement.is_a("IfcVirtualElement")
|
||||
):
|
||||
continue
|
||||
obj = tool.Ifc.get_object(subelement)
|
||||
if obj:
|
||||
raycast = obj.closest_point_on_mesh(obj.matrix_world.inverted() @ target, distance=0.1)
|
||||
if raycast[0]:
|
||||
related_building_element = subelement
|
||||
related_building_element_obj = obj
|
||||
break
|
||||
related_building_element = subelement
|
||||
related_building_element_obj = obj
|
||||
parent_boundary = self.create_element_boundary(
|
||||
context,
|
||||
relating_space,
|
||||
relating_space_obj,
|
||||
related_building_element,
|
||||
related_building_element_obj,
|
||||
)
|
||||
if parent_boundary:
|
||||
parent_boundaries.append(parent_boundary)
|
||||
|
||||
bpy.ops.bim.show_boundaries()
|
||||
for parent_boundary in parent_boundaries:
|
||||
obj = tool.Ifc.get_object(parent_boundary)
|
||||
obj.select_set(True)
|
||||
|
||||
def auto_generate_boundaries(self, space, space_obj):
|
||||
# Identify all potential building elements
|
||||
# TODO: don't select everything, use AABB culling in Blender
|
||||
building_elements = (
|
||||
tool.Ifc.get().by_type("IfcWall")
|
||||
+ tool.Ifc.get().by_type("IfcSlab")
|
||||
+ tool.Ifc.get().by_type("IfcVirtualElement")
|
||||
)
|
||||
|
||||
# Don't generate boundaries of building elements that we've already got bounaries for.
|
||||
for boundary in space.BoundedBy:
|
||||
if boundary.RelatedBuildingElement in building_elements:
|
||||
building_elements.remove(boundary.RelatedBuildingElement)
|
||||
|
||||
# Create tree of gross shapes of all potential related building elements
|
||||
include = building_elements + [space]
|
||||
tree = ifcopenshell.geom.tree()
|
||||
shapes = {}
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set(settings.STRICT_TOLERANCE, True)
|
||||
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, True)
|
||||
iterator = ifcopenshell.geom.iterator(settings, tool.Ifc.get(), multiprocessing.cpu_count(), include=include)
|
||||
if iterator.initialize():
|
||||
while True:
|
||||
tree.add_element(iterator.get_native())
|
||||
shape = iterator.get()
|
||||
shapes[shape.id] = shape
|
||||
if not iterator.next():
|
||||
break
|
||||
|
||||
# Spatially query all potential boundary elements via a 100mm extension of the space
|
||||
building_elements = [e for e in tree.select(space, extend=0.1) if e != space]
|
||||
|
||||
if not building_elements:
|
||||
return
|
||||
|
||||
# Create a dissolved bmesh for the space
|
||||
space_bm = bmesh.new()
|
||||
space_bm.from_mesh(space_obj.data)
|
||||
bmesh.ops.dissolve_limit(space_bm, angle_limit=pi * 2 / 360, verts=space_bm.verts, edges=space_bm.edges)
|
||||
|
||||
# Create dissolved bmeshes for all boundary elements
|
||||
building_element_bms = {}
|
||||
for building_element in building_elements:
|
||||
bm = bmesh.new()
|
||||
shape = shapes[building_element.id()]
|
||||
|
||||
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
|
||||
for vert in verts:
|
||||
bm.verts.new(Vector(vert))
|
||||
bm.verts.ensure_lookup_table()
|
||||
|
||||
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
|
||||
for face in faces:
|
||||
bm.faces.new([bm.verts[i] for i in face])
|
||||
bm.verts.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
bm.normal_update() # Needed so that dissolve_limit will work.
|
||||
bmesh.ops.dissolve_limit(bm, angle_limit=radians(1), verts=bm.verts[:], edges=bm.edges[:])
|
||||
bm.verts.ensure_lookup_table()
|
||||
bm.faces.ensure_lookup_table()
|
||||
building_element_bms[building_element.id()] = bm
|
||||
|
||||
# Compare space faces and building element faces to see if they relate to one another
|
||||
for space_face in space_bm.faces:
|
||||
space_face_normal = space_obj.matrix_world.to_3x3() @ space_face.normal
|
||||
space_face_vert = space_obj.matrix_world @ space_face.verts[0].co
|
||||
for building_element in building_elements:
|
||||
for face in building_element_bms[building_element.id()].faces:
|
||||
building_obj = tool.Ifc.get_object(building_element)
|
||||
face_normal = building_obj.matrix_world.to_3x3() @ face.normal
|
||||
angle = degrees(acos(max(min(space_face_normal.dot(face_normal), 1), -1)))
|
||||
if tool.Cad.is_x(angle, 180, tolerance=2):
|
||||
pass # Faces need to be parallel and have opposite normals to be related.
|
||||
elif building_element.is_a("IfcVirtualElement") and tool.Cad.is_x(angle, 0, tolerance=2):
|
||||
pass # Virtual elements only need to be parallel to be related, since they are planes.
|
||||
else:
|
||||
continue
|
||||
|
||||
# Both faces should be close to one another. Say within 50mm.
|
||||
space_vert = building_obj.matrix_world.inverted() @ space_face_vert
|
||||
dist = mathutils.geometry.distance_point_to_plane(space_vert, face.verts[0].co, face.normal)
|
||||
if abs(dist) > 0.05:
|
||||
continue
|
||||
|
||||
# Project the building element face onto the space face
|
||||
space_face_verts = [v.co.copy() for v in space_face.verts]
|
||||
space_face_matrix = self.get_face_matrix(*[v.copy() for v in space_face_verts[0:3]])
|
||||
space_face_matrix_i = space_face_matrix.inverted()
|
||||
|
||||
space_face_polygon = shapely.Polygon(
|
||||
[tuple((space_face_matrix_i @ v).xy) for v in space_face_verts]
|
||||
)
|
||||
|
||||
space_matrix_world_i = space_obj.matrix_world.inverted()
|
||||
face_verts = [space_matrix_world_i @ building_obj.matrix_world @ v.co.copy() for v in face.verts]
|
||||
face_polygon = shapely.Polygon([tuple((space_face_matrix_i @ v).xy) for v in face_verts])
|
||||
|
||||
gross_boundary_polygon = space_face_polygon.intersection(face_polygon)
|
||||
|
||||
if type(gross_boundary_polygon) == shapely.GeometryCollection:
|
||||
for geom in gross_boundary_polygon.geoms:
|
||||
if type(geom) == shapely.Polygon:
|
||||
gross_boundary_polygon = geom
|
||||
break
|
||||
|
||||
if (
|
||||
not (isinstance(gross_boundary_polygon, shapely.Polygon) and gross_boundary_polygon.is_valid)
|
||||
or gross_boundary_polygon.is_empty
|
||||
):
|
||||
continue
|
||||
|
||||
# The gross boundary polygon may not be a true gross boundary since it
|
||||
# may have openings already removed, such as in IFC4 Reference View. So
|
||||
# we cheat by using the exterior boundary to mean "gross".
|
||||
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
|
||||
|
||||
parent_boundary = tool.Ifc.run(
|
||||
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
|
||||
)
|
||||
if building_element.is_a("IfcVirtualElement"):
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
|
||||
else:
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
parent_boundary.InternalOrExternalBoundary = "NOTDEFINED"
|
||||
if building_element.is_a("IfcWall"):
|
||||
is_external = ifcopenshell.util.element.get_pset(
|
||||
building_element, "Pset_WallCommon", "IsExternal"
|
||||
)
|
||||
if is_external is True:
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
|
||||
elif is_external is False:
|
||||
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
elif building_element.is_a("IfcSlab"):
|
||||
predefined_type = ifcopenshell.util.element.get_predefined_type(building_element)
|
||||
if predefined_type == "BASESLAB":
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL_EARTH"
|
||||
else:
|
||||
is_external = ifcopenshell.util.element.get_pset(
|
||||
building_element, "Pset_SlabCommon", "IsExternal"
|
||||
)
|
||||
if is_external is True:
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
|
||||
elif is_external is False:
|
||||
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
parent_boundary.RelatingSpace = space
|
||||
parent_boundary.RelatedBuildingElement = building_element
|
||||
parent_boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
|
||||
exterior_boundary_polygon, space_face_matrix
|
||||
)
|
||||
self.set_boundary_name(parent_boundary)
|
||||
|
||||
for rel in getattr(building_element, "HasOpenings", []):
|
||||
opening = rel.RelatedOpeningElement
|
||||
filling = opening.HasFillings[0].RelatedBuildingElement if opening.HasFillings else None
|
||||
|
||||
# Create shape of opening as a dissolved BMesh
|
||||
settings = ifcopenshell.geom.settings()
|
||||
settings.set(settings.STRICT_TOLERANCE, True)
|
||||
shape = ifcopenshell.geom.create_shape(settings, opening)
|
||||
m = shape.transformation.matrix.data
|
||||
mat = Matrix(
|
||||
(
|
||||
[m[0], m[3], m[6], m[9]],
|
||||
[m[1], m[4], m[7], m[10]],
|
||||
[m[2], m[5], m[8], m[11]],
|
||||
[0, 0, 0, 1],
|
||||
)
|
||||
)
|
||||
opening_bm = bmesh.new()
|
||||
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
|
||||
for vert in verts:
|
||||
opening_bm.verts.new(Vector(vert))
|
||||
opening_bm.verts.ensure_lookup_table()
|
||||
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
|
||||
for face in faces:
|
||||
opening_bm.faces.new([opening_bm.verts[i] for i in face])
|
||||
opening_bm.verts.ensure_lookup_table()
|
||||
opening_bm.faces.ensure_lookup_table()
|
||||
opening_bm.normal_update() # Needed so that dissolve_limit will work.
|
||||
bmesh.ops.dissolve_limit(
|
||||
opening_bm, angle_limit=radians(1), verts=opening_bm.verts[:], edges=opening_bm.edges[:]
|
||||
)
|
||||
opening_bm.verts.ensure_lookup_table()
|
||||
opening_bm.faces.ensure_lookup_table()
|
||||
|
||||
# Get relevant faces of BMesh that can turn into boundaries
|
||||
opening_polygons = []
|
||||
for opening_face in opening_bm.faces:
|
||||
opening_face_normal = mat.to_3x3() @ opening_face.normal
|
||||
angle = degrees(acos(max(min(opening_face_normal.dot(face_normal), 1), -1)))
|
||||
if not tool.Cad.is_x(angle, 180, tolerance=2):
|
||||
continue # Any non-parallel faces are not relevant
|
||||
opening_face_verts = [space_matrix_world_i @ mat @ v.co.copy() for v in opening_face.verts]
|
||||
polygon = shapely.Polygon([tuple((space_face_matrix_i @ v).xy) for v in opening_face_verts])
|
||||
opening_polygons.append(polygon)
|
||||
|
||||
# Merge them all into a single opening polygon for our boundary
|
||||
opening_polygon = shapely.ops.unary_union(opening_polygons)
|
||||
|
||||
# Only openings that are projected onto our exterior boundary are relevant.
|
||||
if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
|
||||
continue
|
||||
|
||||
boundary = tool.Ifc.run(
|
||||
"root.create_entity", ifc_class=bpy.context.scene.BIMModelProperties.boundary_class
|
||||
)
|
||||
boundary.RelatingSpace = space
|
||||
boundary.RelatedBuildingElement = filling or opening
|
||||
boundary.ConnectionGeometry = self.create_connection_geometry_from_polygon(
|
||||
opening_polygon, space_face_matrix
|
||||
)
|
||||
if filling:
|
||||
boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
else:
|
||||
boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
|
||||
boundary.InternalOrExternalBoundary = parent_boundary.InternalOrExternalBoundary
|
||||
if boundary.is_a() != "IfcRelSpaceBoundary":
|
||||
boundary.ParentBoundary = parent_boundary
|
||||
self.set_boundary_name(boundary)
|
||||
|
||||
def create_element_boundary(
|
||||
self, context, relating_space, relating_space_obj, related_building_element, related_building_element_obj
|
||||
):
|
||||
if not relating_space or not related_building_element:
|
||||
return
|
||||
|
||||
# Find which face on space should be bounded to related building element
|
||||
# TODO: Handle round wall where multiple faces need to be bound to the same related building element
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(relating_space_obj.data)
|
||||
bmesh.ops.dissolve_limit(bm, angle_limit=pi * 2 / 360, verts=bm.verts, edges=bm.edges)
|
||||
@@ -609,8 +887,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
if not target_face:
|
||||
return
|
||||
|
||||
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
|
||||
|
||||
# Is this right? Or should I use loop?
|
||||
target_face_verts = [v.co.copy() for v in target_face.verts]
|
||||
target_face_matrix = self.get_face_matrix(*[v.copy() for v in target_face_verts[0:3]])
|
||||
@@ -630,6 +906,18 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
gross_boundary_polygon = geom
|
||||
break
|
||||
|
||||
if (
|
||||
not (isinstance(gross_boundary_polygon, shapely.Polygon) and gross_boundary_polygon.is_valid)
|
||||
or gross_boundary_polygon.is_empty
|
||||
):
|
||||
return
|
||||
|
||||
parent_boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
# Set to EXTERNAL by default and turn later to internal if there is a corresponding boundary relating to an
|
||||
# internal space
|
||||
parent_boundary.InternalOrExternalBoundary = "EXTERNAL"
|
||||
|
||||
# The gross boundary polygon may not be a true gross boundary since it
|
||||
# may have openings already removed, such as in IFC4 Reference View. So
|
||||
# we cheat by using the exterior boundary to mean "gross". Later, we
|
||||
@@ -637,19 +925,25 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
# space.
|
||||
exterior_boundary_polygon = shapely.Polygon(gross_boundary_polygon.exterior.coords)
|
||||
|
||||
net_boundary_polygon = shapely.Polygon(gross_boundary_polygon)
|
||||
|
||||
inner_boundaries = []
|
||||
|
||||
for rel in getattr(related_building_element, "HasOpenings", []):
|
||||
opening = rel.RelatedOpeningElement
|
||||
filling = None
|
||||
if opening.HasFillings:
|
||||
filling = opening.HasFillings[0].RelatedBuildingElement
|
||||
if not opening.HasFillings:
|
||||
continue
|
||||
# TODO: HasFilling is a zero to many relationship. How to handle many ?
|
||||
filling = opening.HasFillings[0].RelatedBuildingElement
|
||||
|
||||
opening_polygon = self.get_flattened_polygon(opening, relating_space_obj, target_face_matrix_i)
|
||||
|
||||
net_boundary_polygon = net_boundary_polygon.difference(opening_polygon)
|
||||
# An inner boundary is supposed to overlap its parent boundary according to IFC4 documentation
|
||||
# so we extend our exterior boundary with all opening which has a filling
|
||||
# Also see Implementation aggreement SB 1.1 for IFC 2x3 TC1 Space Boundary Addon View
|
||||
# https://standards.buildingsmart.org/MVD/RELEASE/IFC2x3/TC1/SB1_1/IFC%20Space%20Boundary%20Implementation%20Agreement%20Addendum%202010-03-22.pdf
|
||||
unionised_object = exterior_boundary_polygon.union(opening_polygon)
|
||||
if isinstance(unionised_object, shapely.Polygon):
|
||||
exterior_boundary_polygon = unionised_object
|
||||
|
||||
# Only openings that are projected onto our exterior boundary are relevant.
|
||||
if opening_polygon.intersection(exterior_boundary_polygon).area == 0:
|
||||
continue
|
||||
@@ -657,24 +951,25 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
connection_geometry = self.create_connection_geometry_from_polygon(opening_polygon, target_face_matrix)
|
||||
boundary = tool.Ifc.run("root.create_entity", ifc_class=context.scene.BIMModelProperties.boundary_class)
|
||||
boundary.RelatingSpace = relating_space
|
||||
boundary.RelatedBuildingElement = filling or related_building_element
|
||||
boundary.RelatedBuildingElement = filling
|
||||
boundary.ConnectionGeometry = connection_geometry
|
||||
boundary.PhysicalOrVirtualBoundary = "PHYSICAL" if filling else "VIRTUAL"
|
||||
boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
|
||||
if related_building_element.is_a("IfcVirtualElement"):
|
||||
boundary.PhysicalOrVirtualBoundary = "VIRTUAL"
|
||||
else:
|
||||
boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
boundary.InternalOrExternalBoundary = parent_boundary.InternalOrExternalBoundary
|
||||
self.set_boundary_name(boundary)
|
||||
if boundary.is_a("IfcRelSpaceBoundary2ndLevel"):
|
||||
boundary.ParentBoundary = parent_boundary
|
||||
|
||||
connection_geometry = self.create_connection_geometry_from_polygon(net_boundary_polygon, target_face_matrix)
|
||||
connection_geometry = self.create_connection_geometry_from_polygon(
|
||||
exterior_boundary_polygon, target_face_matrix
|
||||
)
|
||||
parent_boundary.RelatingSpace = relating_space
|
||||
parent_boundary.RelatedBuildingElement = related_building_element
|
||||
parent_boundary.ConnectionGeometry = connection_geometry
|
||||
parent_boundary.PhysicalOrVirtualBoundary = "PHYSICAL"
|
||||
parent_boundary.InternalOrExternalBoundary = "INTERNAL"
|
||||
|
||||
bpy.ops.bim.show_boundaries()
|
||||
obj = tool.Ifc.get_object(parent_boundary)
|
||||
obj.select_set(True)
|
||||
self.set_boundary_name(parent_boundary)
|
||||
return parent_boundary
|
||||
|
||||
def get_face_matrix(self, p1, p2, p3):
|
||||
edge1 = p2 - p1
|
||||
@@ -729,11 +1024,13 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Model.unit_scale = self.unit_scale
|
||||
|
||||
surface = tool.Ifc.get().createIfcCurveBoundedPlane()
|
||||
surface.BasisSurface = tool.Ifc.get().createIfcPlane(tool.Ifc.get().createIfcAxis2Placement3D(
|
||||
tool.Ifc.get().createIfcCartesianPoint([o / self.unit_scale for o in p1]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in z_axis]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in x_axis]),
|
||||
))
|
||||
surface.BasisSurface = tool.Ifc.get().createIfcPlane(
|
||||
tool.Ifc.get().createIfcAxis2Placement3D(
|
||||
tool.Ifc.get().createIfcCartesianPoint([o / self.unit_scale for o in p1]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in z_axis]),
|
||||
tool.Ifc.get().createIfcDirection([float(o) for o in x_axis]),
|
||||
)
|
||||
)
|
||||
|
||||
if tool.Ifc.get().schema != "IFC2X3":
|
||||
points = [tool.Model.convert_si_to_unit(list(co)) for co in polygon.exterior.coords]
|
||||
@@ -746,9 +1043,24 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
point_list = tool.Ifc.get().createIfcCartesianPointList2D(points)
|
||||
inner_boundaries.append(tool.Ifc.get().createIfcIndexedPolyCurve(point_list, None, False))
|
||||
else:
|
||||
pass # TODO
|
||||
pass # TODO
|
||||
|
||||
surface.OuterBoundary = outer_boundary
|
||||
surface.InnerBoundaries = inner_boundaries
|
||||
|
||||
return surface
|
||||
|
||||
def set_boundary_name(self, boundary):
|
||||
"""
|
||||
By convention 1stLevel and 2ndLevel boundary have specific name and description
|
||||
See https://ifc43-docs.standards.buildingsmart.org/IFC/RELEASE/IFC4x3/HTML/lexical/IfcRelSpaceBoundary.htm
|
||||
Warning: IfcRelSpaceBoundary2ndLevel is a subclass of IfcRelSpaceBoundary1stLevel test order matter
|
||||
"""
|
||||
if boundary.is_a("IfcRelSpaceBoundary2ndLevel"):
|
||||
boundary.Name = "2ndLevel"
|
||||
if boundary.CorrespondingBoundary:
|
||||
boundary.Description = "2a"
|
||||
else:
|
||||
boundary.Description = "2b"
|
||||
elif boundary.is_a("IfcRelSpaceBoundary1stLevel"):
|
||||
boundary.Name = "1stLevel"
|
||||
|
||||
@@ -22,8 +22,8 @@ from . import ui, prop, operator
|
||||
classes = (
|
||||
operator.GetBSDDClassificationProperties,
|
||||
operator.LoadBSDDDomains,
|
||||
operator.SearchBSDDClassifications,
|
||||
operator.SetActiveBSDDDomain,
|
||||
operator.SearchBSDDClass,
|
||||
operator.SetActiveBSDDDictionary,
|
||||
prop.BSDDDomain,
|
||||
prop.BSDDClassification,
|
||||
prop.BSDDPset,
|
||||
|
||||
@@ -16,73 +16,42 @@
|
||||
# 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 bsdd
|
||||
import json
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.core import bsdd as core
|
||||
|
||||
|
||||
class LoadBSDDDomains(bpy.types.Operator):
|
||||
bl_idname = "bim.load_bsdd_domains"
|
||||
bl_label = "Load bSDD Domains"
|
||||
bl_label = "Load bSDD Dictionaries"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
props.domains.clear()
|
||||
client = bsdd.Client()
|
||||
for domain in sorted(client.Domain(), key=lambda x: x["name"]):
|
||||
new = props.domains.add()
|
||||
new.name = domain["name"]
|
||||
new.namespace_uri = domain["namespaceUri"]
|
||||
new.default_language_code = domain["defaultLanguageCode"]
|
||||
new.organization_name_owner = domain["organizationNameOwner"]
|
||||
new.status = domain["status"]
|
||||
new.version = domain["version"]
|
||||
core.load_bsdd(bsdd.Client(), tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SetActiveBSDDDomain(bpy.types.Operator):
|
||||
class SetActiveBSDDDictionary(bpy.types.Operator):
|
||||
bl_idname = "bim.set_active_bsdd_domain"
|
||||
bl_label = "Load bSDD Domains"
|
||||
bl_label = "Load bSDD Dictionary"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
name: bpy.props.StringProperty()
|
||||
uri: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
props.active_domain = self.name
|
||||
props.active_uri = self.uri
|
||||
core.set_active_bsdd_dictionary(self.name, self.uri, tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SearchBSDDClassifications(bpy.types.Operator):
|
||||
class SearchBSDDClass(bpy.types.Operator):
|
||||
bl_idname = "bim.search_bsdd_classifications"
|
||||
bl_label = "Search bSDD Classifications"
|
||||
bl_label = "Search bSDD Class"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
props.classifications.clear()
|
||||
client = bsdd.Client()
|
||||
related_ifc_entities = []
|
||||
if len(props.keyword) < 3:
|
||||
return {"FINISHED"}
|
||||
if props.should_filter_ifc_class and context.active_object:
|
||||
element = tool.Ifc.get_entity(context.active_object)
|
||||
if element:
|
||||
related_ifc_entities = [element.is_a()]
|
||||
results = client.ClassificationSearchOpen(props.keyword, DomainNamespaceUris=[props.active_uri], RelatedIfcEntities=related_ifc_entities)
|
||||
for result in sorted(results["classifications"], key=lambda x: x["referenceCode"]):
|
||||
new = props.classifications.add()
|
||||
new.name = result["name"]
|
||||
new.reference_code = result["referenceCode"]
|
||||
new.description = result.get("description", "")
|
||||
new.namespace_uri = result["namespaceUri"]
|
||||
new.domain_name = result["domainName"]
|
||||
new.domain_namespace_uri = result["domainNamespaceUri"]
|
||||
keyword = context.scene.BIMBSDDProperties.keyword
|
||||
core.search_class(keyword, bsdd.Client(), tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -92,41 +61,5 @@ class GetBSDDClassificationProperties(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
bprops = context.scene.BIMBSDDProperties
|
||||
bprops.classification_psets.clear()
|
||||
bsdd_classification = bprops.classifications[bprops.active_classification_index]
|
||||
client = bsdd.Client()
|
||||
data = client.Classification(bsdd_classification.namespace_uri)
|
||||
|
||||
properties = data.get("classificationProperties", None)
|
||||
if not properties:
|
||||
return {"FINISHED"}
|
||||
|
||||
psets = {}
|
||||
|
||||
for prop in properties:
|
||||
if prop.get("propertyDomainName") != "IFC":
|
||||
continue
|
||||
pset = prop.get("propertySet", None)
|
||||
if not pset:
|
||||
continue
|
||||
psets.setdefault(pset, {})
|
||||
|
||||
predefined_value = prop.get("predefinedValue")
|
||||
if predefined_value:
|
||||
possible_values = [predefined_value]
|
||||
else:
|
||||
possible_values = prop.get("possibleValues", []) or []
|
||||
possible_values = [v["value"] for v in possible_values]
|
||||
|
||||
psets[pset][prop["name"]] = possible_values
|
||||
|
||||
for pset_name, pset in psets.items():
|
||||
new = bprops.classification_psets.add()
|
||||
new.name = pset_name
|
||||
for name, values in pset.items():
|
||||
new2 = new.properties.add()
|
||||
new2.name = name
|
||||
new2.enum_items = json.dumps(values)
|
||||
new2.data_type = "enum"
|
||||
core.get_class_properties(bsdd.Client(), tool.Bsdd)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -33,7 +33,7 @@ from bpy.props import (
|
||||
|
||||
class BSDDDomain(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
namespace_uri: StringProperty(name="URI")
|
||||
uri: StringProperty(name="URI")
|
||||
default_language_code: StringProperty(name="Language")
|
||||
organization_name_owner: StringProperty(name="Organization")
|
||||
status: StringProperty(name="Status")
|
||||
@@ -44,7 +44,7 @@ class BSDDClassification(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
reference_code: StringProperty(name="Reference Code")
|
||||
description: StringProperty(name="Description")
|
||||
namespace_uri: StringProperty(name="Namespace URI")
|
||||
uri: StringProperty(name="Namespace URI")
|
||||
domain_name: StringProperty(name="Domain Name")
|
||||
domain_namespace_uri: StringProperty(name="Domain Namespace URI")
|
||||
|
||||
@@ -63,4 +63,5 @@ class BIMBSDDProperties(PropertyGroup):
|
||||
active_classification_index: IntProperty(name="Active Classification Index")
|
||||
keyword: StringProperty(name="Keyword")
|
||||
should_filter_ifc_class: BoolProperty(name="Filter Active IFC Class", default=True)
|
||||
load_preview_domains: BoolProperty(name="Load Preview Domains", default=False)
|
||||
classification_psets: CollectionProperty(name="Classification Psets", type=BSDDPset)
|
||||
|
||||
@@ -32,6 +32,11 @@ class BIM_PT_bsdd(Panel):
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "load_preview_domains")
|
||||
if len(props.domains):
|
||||
row.operator("bim.load_bsdd_domains", text="", icon="FILE_REFRESH")
|
||||
|
||||
if props.active_domain:
|
||||
row = self.layout.row()
|
||||
row.label(text="Active: " + props.active_domain, icon="URL")
|
||||
@@ -57,10 +62,13 @@ class BIM_UL_bsdd_domains(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=f"{item.name} ({item.organization_name_owner})")
|
||||
if item.status != "Active":
|
||||
row.label(text=f"{item.name} ({item.organization_name_owner}) - {item.status}", icon="ERROR")
|
||||
else:
|
||||
row.label(text=f"{item.name} ({item.organization_name_owner})")
|
||||
op = row.operator("bim.set_active_bsdd_domain", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.name = item.name
|
||||
op.uri = item.namespace_uri
|
||||
op.uri = item.uri
|
||||
|
||||
|
||||
class BIM_UL_bsdd_classifications(UIList):
|
||||
|
||||
@@ -20,26 +20,33 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddClashSet,
|
||||
operator.AddClashSource,
|
||||
operator.ExecuteIfcClash,
|
||||
operator.ExportClashSets,
|
||||
operator.ImportClashSets,
|
||||
operator.AddClashSet,
|
||||
operator.LoadIfcClashes,
|
||||
operator.SaveIfcClashes,
|
||||
operator.LoadSmartGroupsForActiveClashSet,
|
||||
operator.RemoveClashSet,
|
||||
operator.AddClashSource,
|
||||
operator.RemoveClashSource,
|
||||
operator.SelectClashSource,
|
||||
operator.ExecuteIfcClash,
|
||||
operator.SelectIfcClashResults,
|
||||
operator.SelectClash,
|
||||
operator.SelectClashResults,
|
||||
operator.SelectClashSource,
|
||||
operator.SelectIfcClashResults,
|
||||
operator.SelectSmartGroup,
|
||||
operator.SelectSmartGroupedClashesPath,
|
||||
operator.SmartClashGroup,
|
||||
operator.SelectSmartGroup,
|
||||
operator.LoadSmartGroupsForActiveClashSet,
|
||||
prop.Clash,
|
||||
prop.ClashSource,
|
||||
prop.ClashSet,
|
||||
prop.SmartClashGroup,
|
||||
prop.BIMClashProperties,
|
||||
ui.BIM_PT_ifcclash,
|
||||
ui.BIM_PT_clash_manager,
|
||||
ui.BIM_PT_dumb_clash_manager,
|
||||
ui.BIM_PT_smart_clash_manager,
|
||||
ui.BIM_UL_clashes,
|
||||
ui.BIM_UL_clash_sets,
|
||||
ui.BIM_UL_smart_groups,
|
||||
)
|
||||
|
||||
@@ -26,6 +26,7 @@ import ifcopenshell
|
||||
from mathutils import Matrix, Vector
|
||||
from math import radians
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
class ExportClashSets(bpy.types.Operator):
|
||||
@@ -245,12 +246,14 @@ class ExecuteIfcClash(bpy.types.Operator):
|
||||
y = Vector([y.x, y.y, y.z])
|
||||
x = y.cross(z)
|
||||
|
||||
mat = Matrix([
|
||||
[x[0], y[0], z[0], p.x],
|
||||
[x[1], y[1], z[1], p.y],
|
||||
[x[2], y[2], z[2], p.z],
|
||||
[0, 0, 0, 0],
|
||||
])
|
||||
mat = Matrix(
|
||||
[
|
||||
[x[0], y[0], z[0], p.x],
|
||||
[x[1], y[1], z[1], p.y],
|
||||
[x[2], y[2], z[2], p.z],
|
||||
[0, 0, 0, 0],
|
||||
]
|
||||
)
|
||||
|
||||
camera.matrix_world = mat
|
||||
context.scene.camera = camera
|
||||
@@ -349,6 +352,119 @@ class SelectIfcClashResults(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LoadIfcClashes(bpy.types.Operator):
|
||||
bl_idname = "bim.load_ifc_clashes"
|
||||
bl_label = "Load IFC Clashes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Load the clashing IFC geometry stored in a file"
|
||||
filename_ext = ".json"
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
|
||||
WindowManager = context.window_manager
|
||||
WindowManager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
|
||||
with open(self.filepath) as f:
|
||||
clash_sets_json = json.load(f)
|
||||
active_clash_set = context.scene.BIMClashProperties.active_clash_set
|
||||
|
||||
for clash_set in clash_sets_json:
|
||||
if not "clashes" in clash_set.keys():
|
||||
self.report({"WARNING"}, "No clashes found for the selected Clash Set.")
|
||||
return {"CANCELLED"}
|
||||
active_clash_set.clashes.clear()
|
||||
for clash in clash_set["clashes"].values():
|
||||
blender_clash = active_clash_set.clashes.add()
|
||||
blender_clash.a_global_id = clash["a_global_id"]
|
||||
blender_clash.b_global_id = clash["b_global_id"]
|
||||
blender_clash.a_name = "{}/{}".format(clash["a_ifc_class"], clash["a_name"])
|
||||
blender_clash.b_name = "{}/{}".format(clash["b_ifc_class"], clash["b_name"])
|
||||
blender_clash.status = False if not "status" in clash.keys() else clash["status"]
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SaveIfcClashes(bpy.types.Operator):
|
||||
bl_idname = "bim.save_ifc_clashes"
|
||||
bl_label = "Save IFC Clashes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Save the clashing IFC geometry stored in a file"
|
||||
filename_ext = ".json"
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".json")
|
||||
WindowManager = context.window_manager
|
||||
WindowManager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
self.filepath = bpy.path.ensure_ext(self.filepath, ".json")
|
||||
clash_sets_json = self.load_json()
|
||||
active_clash_set = context.scene.BIMClashProperties.active_clash_set
|
||||
self.update_clash_sets(clash_sets_json, active_clash_set)
|
||||
self.save_json(clash_sets_json)
|
||||
return {"FINISHED"}
|
||||
|
||||
def load_json(self):
|
||||
with open(self.filepath) as f:
|
||||
return json.load(f)
|
||||
|
||||
def update_clash_sets(self, clash_sets_json, active_clash_set):
|
||||
for clash_set in clash_sets_json:
|
||||
if clash_set["name"] != active_clash_set.name or "clashes" not in clash_set.keys():
|
||||
continue
|
||||
for clash in active_clash_set.clashes:
|
||||
clash_key = clash.a_global_id + "-" + clash.b_global_id
|
||||
if clash_set.get("clashes", {}).get(clash_key, None) is not None:
|
||||
clash_set["clashes"][clash_key]["status"] = clash.status
|
||||
|
||||
def save_json(self, clash_sets_json):
|
||||
with open(self.filepath, "w") as destination:
|
||||
json.dump(clash_sets_json, destination, indent=4)
|
||||
|
||||
|
||||
class SelectClash(bpy.types.Operator):
|
||||
bl_idname = "bim.select_clash"
|
||||
bl_label = "Select Clash"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Select the clashing IFC geometry stored in a file"
|
||||
index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
clash = context.scene.BIMClashProperties.active_clash
|
||||
|
||||
products = []
|
||||
linked_objects = []
|
||||
try:
|
||||
products.append(tool.Ifc.get().by_guid(clash.a_global_id))
|
||||
except:
|
||||
linked_objects.append(clash.a_name)
|
||||
try:
|
||||
products.append(tool.Ifc.get().by_guid(clash.b_global_id))
|
||||
except:
|
||||
linked_objects.append(clash.b_name)
|
||||
|
||||
tool.Spatial.select_products(products, unhide=True)
|
||||
print(linked_objects)
|
||||
for obj_name in linked_objects:
|
||||
obj = bpy.data.objects.get(obj_name)
|
||||
if obj:
|
||||
obj.select_set(True)
|
||||
else:
|
||||
print("Object not found:", obj_name)
|
||||
if context.scene.BIMClashProperties.sould_focus_on_clash:
|
||||
context_override = tool.Blender.get_viewport_context()
|
||||
with bpy.context.temp_override(**context_override):
|
||||
bpy.ops.view3d.view_selected()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SmartClashGroup(bpy.types.Operator):
|
||||
bl_idname = "bim.smart_clash_group"
|
||||
bl_label = "Smart Group Clashes"
|
||||
@@ -433,9 +549,9 @@ class LoadSmartGroupsForActiveClashSet(bpy.types.Operator):
|
||||
new_group = context.scene.BIMClashProperties.smart_clash_groups.add()
|
||||
new_group.number = f"{smart_group}"
|
||||
for pair in global_id_pairs:
|
||||
for id in pair:
|
||||
for guid in pair:
|
||||
new_global_id = new_group.global_ids.add()
|
||||
new_global_id.name = id
|
||||
new_global_id.guid = guid
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -450,20 +566,16 @@ class SelectSmartGroup(bpy.types.Operator):
|
||||
return IfcStore.get_file() and context.visible_objects and context.scene.BIMClashProperties.active_smart_group
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
# Select smart group in view
|
||||
selected_smart_group = context.scene.BIMClashProperties.active_smart_group
|
||||
# print(selected_smart_group.number)
|
||||
|
||||
for obj in context.visible_objects:
|
||||
if not obj.BIMObjectProperties.ifc_definition_id:
|
||||
products = []
|
||||
for global_id in selected_smart_group.global_ids:
|
||||
try:
|
||||
products.append(tool.Ifc.get().by_guid(global_id.guid))
|
||||
except:
|
||||
continue
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
for id in selected_smart_group.global_ids:
|
||||
# print("Id: ", id)
|
||||
# print("Global id: ", element.GlobalId)
|
||||
if element.GlobalId in id.name:
|
||||
# print("object match: ", global_id)
|
||||
obj.select_set(True)
|
||||
|
||||
tool.Spatial.select_products(products, unhide=True)
|
||||
context_override = tool.Blender.get_viewport_context()
|
||||
with bpy.context.temp_override(**context_override):
|
||||
bpy.ops.view3d.view_selected()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -43,11 +43,20 @@ class ClashSource(PropertyGroup):
|
||||
)
|
||||
|
||||
|
||||
class Clash(PropertyGroup):
|
||||
a_global_id: StringProperty(name="A")
|
||||
b_global_id: StringProperty(name="B")
|
||||
a_name: StringProperty(name="A Name")
|
||||
b_name: StringProperty(name="B Name")
|
||||
status: BoolProperty(name="Status", default=False)
|
||||
|
||||
|
||||
class ClashSet(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
tolerance: FloatProperty(name="Tolerance")
|
||||
a: CollectionProperty(name="Group A", type=ClashSource)
|
||||
b: CollectionProperty(name="Group B", type=ClashSource)
|
||||
clashes: CollectionProperty(name="Clashes", type=Clash)
|
||||
|
||||
|
||||
class SmartClashGroup(PropertyGroup):
|
||||
@@ -63,11 +72,13 @@ class BIMClashProperties(PropertyGroup):
|
||||
clash_results_path: StringProperty(name="Clash Results Path")
|
||||
smart_grouped_clashes_path: StringProperty(name="Smart Grouped Clashes Path")
|
||||
active_clash_set_index: IntProperty(name="Active Clash Set Index")
|
||||
active_clash_index: IntProperty(name="Active Clash Index")
|
||||
smart_clash_groups: CollectionProperty(name="Smart Clash Groups", type=SmartClashGroup)
|
||||
active_smart_group_index: IntProperty(name="Active Smart Group Index")
|
||||
smart_clash_grouping_max_distance: IntProperty(
|
||||
name="Smart Clash Grouping Max Distance", default=3, soft_min=1, soft_max=10
|
||||
)
|
||||
sould_focus_on_clash: BoolProperty(name="Show Focus Clash", default=False)
|
||||
|
||||
@property
|
||||
def active_clash_set(self):
|
||||
@@ -80,3 +91,9 @@ class BIMClashProperties(PropertyGroup):
|
||||
if not self.smart_clash_groups:
|
||||
return None
|
||||
return self.smart_clash_groups[self.active_smart_group_index]
|
||||
|
||||
@property
|
||||
def active_clash(self):
|
||||
if not self.active_clash_set:
|
||||
return None
|
||||
return self.active_clash_set.clashes[self.active_clash_index]
|
||||
|
||||
@@ -107,6 +107,42 @@ class BIM_PT_clash_manager(Panel):
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_clash_detection"
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
|
||||
|
||||
class BIM_PT_dumb_clash_manager(Panel):
|
||||
bl_idname = "BIM_PT_dumb_clash_manager"
|
||||
bl_label = "Dumb Manager"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_clash_manager"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = context.scene.BIMClashProperties
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.load_ifc_clashes", text="LOAD IFC CLASHES", icon="IMPORT")
|
||||
row.operator("bim.save_ifc_clashes", text="SAVE CLASH RESULTS", icon="EXPORT")
|
||||
layout.template_list("BIM_UL_clashes", "", props.active_clash_set, "clashes", props, "active_clash_index")
|
||||
# bim.select_clash
|
||||
row = layout.row(align=True)
|
||||
row.operator("bim.select_clash", text="SELECT CLASH", icon="IMPORT")
|
||||
row.prop(props, "sould_focus_on_clash", icon="RESTRICT_VIEW_OFF")
|
||||
|
||||
|
||||
class BIM_PT_smart_clash_manager(Panel):
|
||||
bl_idname = "BIM_PT_smart_clash_manager"
|
||||
bl_label = "Smart Clash Manager"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_clash_manager"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
props = context.scene.BIMClashProperties
|
||||
@@ -156,3 +192,14 @@ class BIM_UL_smart_groups(bpy.types.UIList):
|
||||
layout.label(text=str(item.number), translate=False, icon="NONE", icon_value=0)
|
||||
else:
|
||||
layout.label(text="", translate=False)
|
||||
|
||||
|
||||
class BIM_UL_clashes(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=str(item.a_name), translate=False, icon="NONE", icon_value=0)
|
||||
row.label(text=str(item.b_name), translate=False, icon="NONE", icon_value=0)
|
||||
row.prop(item, "status", text="")
|
||||
else:
|
||||
layout.label(text="", translate=False)
|
||||
|
||||
@@ -24,12 +24,18 @@ classes = (
|
||||
operator.AddClassificationFromBSDD,
|
||||
operator.AddClassificationReference,
|
||||
operator.AddClassificationReferenceFromBSDD,
|
||||
operator.AddManualClassification,
|
||||
operator.AddManualClassificationReference,
|
||||
operator.ChangeClassificationLevel,
|
||||
operator.DisableAddingManualClassification,
|
||||
operator.DisableAddingManualClassificationReference,
|
||||
operator.DisableEditingClassification,
|
||||
operator.DisableEditingClassificationReference,
|
||||
operator.DisableEditingClassificationReferences,
|
||||
operator.EditClassification,
|
||||
operator.EditClassificationReference,
|
||||
operator.EnableAddingManualClassification,
|
||||
operator.EnableAddingManualClassificationReference,
|
||||
operator.EnableEditingClassification,
|
||||
operator.EnableEditingClassificationReference,
|
||||
operator.LoadClassificationLibrary,
|
||||
|
||||
@@ -73,6 +73,10 @@ class ReferencesData:
|
||||
if name in [e.Name for e in tool.Ifc.get().by_type("IfcClassification")]:
|
||||
return name
|
||||
|
||||
@classmethod
|
||||
def classifications(cls):
|
||||
return [(str(e.id()), e.Name, "") for e in tool.Ifc.get().by_type("IfcClassification")]
|
||||
|
||||
|
||||
class ClassificationReferencesData(ReferencesData):
|
||||
data = {}
|
||||
@@ -83,6 +87,8 @@ class ClassificationReferencesData(ReferencesData):
|
||||
cls.is_loaded = True
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "OBJECT"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
@@ -105,6 +111,8 @@ class MaterialClassificationsData(ReferencesData):
|
||||
cls.is_loaded = True
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "MATERIAL"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
@@ -127,6 +135,8 @@ class CostClassificationsData(ReferencesData):
|
||||
cls.is_loaded = True
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "COST"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
|
||||
@@ -54,6 +54,50 @@ class AddClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
|
||||
|
||||
class AddManualClassification(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_manual_classification"
|
||||
bl_label = "Add Manual Classification"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.classification_attributes)
|
||||
classification = ifcopenshell.api.run(
|
||||
"classification.add_classification", tool.Ifc.get(), classification="Unnamed"
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_classification", tool.Ifc.get(), classification=classification, attributes=attributes
|
||||
)
|
||||
props.is_adding = False
|
||||
|
||||
|
||||
class AddManualClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_manual_classification_reference"
|
||||
bl_label = "Add Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.reference_attributes)
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
# TODO: refactor and support material and cost item classifications
|
||||
classification = tool.Ifc.get().by_id(int(props.classifications))
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
tool.Ifc.get(),
|
||||
product=product,
|
||||
classification=classification,
|
||||
identification="X",
|
||||
name="Unnamed",
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_reference", tool.Ifc.get(), reference=reference, attributes=attributes
|
||||
)
|
||||
props.is_adding = False
|
||||
|
||||
|
||||
class AddClassificationFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_classification_from_bsdd"
|
||||
bl_label = "Add Classification From bSDD"
|
||||
@@ -63,16 +107,67 @@ class AddClassificationFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
|
||||
props = context.scene.BIMBSDDProperties
|
||||
domain = [d for d in props.domains if d.name == props.active_domain][0]
|
||||
for element in tool.Ifc.get().by_type("IfcClassification"):
|
||||
if element.Name == props.active_domain or element.Location == domain.namespace_uri:
|
||||
if element.Name == props.active_domain or element.Location == domain.uri:
|
||||
return
|
||||
classification = ifcopenshell.api.run(
|
||||
"classification.add_classification", tool.Ifc.get(), classification=props.active_domain
|
||||
)
|
||||
classification.Source = domain.organization_name_owner
|
||||
classification.Location = domain.namespace_uri
|
||||
classification.Location = domain.uri
|
||||
classification.Edition = domain.version
|
||||
|
||||
|
||||
class EnableAddingManualClassification(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_adding_manual_classification"
|
||||
bl_label = "Enable Adding Manual Classification"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
props.is_adding = True
|
||||
props.active_classification_id = 0
|
||||
props.classification_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2("IfcClassification", props.classification_attributes)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableAddingManualClassification(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_adding_manual_classification"
|
||||
bl_label = "Disable Adding Manual Classification"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
props.is_adding = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableAddingManualClassificationReference(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_adding_manual_classification_reference"
|
||||
bl_label = "Enable Adding Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.is_adding = True
|
||||
props.reference_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2("IfcClassificationReference", props.reference_attributes)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableAddingManualClassificationReference(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_adding_manual_classification_reference"
|
||||
bl_label = "Disable Adding Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.is_adding = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingClassification(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_classification"
|
||||
bl_label = "Enable Editing Classification"
|
||||
@@ -194,21 +289,23 @@ class RemoveClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
objects = [self.obj]
|
||||
|
||||
identification = tool.Ifc.get().by_id(self.reference)[0]
|
||||
active_reference = tool.Ifc.get().by_id(self.reference)
|
||||
identification = active_reference[1]
|
||||
|
||||
for obj in objects:
|
||||
ifc_definition_id = blenderbim.bim.helper.get_obj_ifc_definition_id(context, obj, self.obj_type)
|
||||
element = tool.Ifc.get().by_id(ifc_definition_id)
|
||||
references = ifcopenshell.util.classification.get_references(element, should_inherit=False)
|
||||
for reference in references:
|
||||
if reference[0] == identification:
|
||||
if (identification and reference[1] == identification) or (
|
||||
not identification and reference == active_reference
|
||||
):
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_reference",
|
||||
tool.Ifc.get(),
|
||||
reference=reference,
|
||||
product=element,
|
||||
)
|
||||
break
|
||||
|
||||
|
||||
class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
@@ -321,20 +418,35 @@ class AddClassificationReferenceFromBSDD(bpy.types.Operator, tool.Ifc.Operator):
|
||||
identification=bsdd_classification.reference_code,
|
||||
name=bsdd_classification.name,
|
||||
)
|
||||
reference.Location = bsdd_classification.namespace_uri
|
||||
reference.Location = bsdd_classification.uri
|
||||
|
||||
for classification_pset in bprops.classification_psets:
|
||||
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name)
|
||||
is_pset = not classification_pset.name.startswith("Qto_")
|
||||
|
||||
if is_pset:
|
||||
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name, psets_only=True)
|
||||
else:
|
||||
pset = ifcopenshell.util.element.get_pset(element, classification_pset.name, qtos_only=True)
|
||||
|
||||
if pset:
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
else:
|
||||
elif is_pset:
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_pset", tool.Ifc.get(), product=element, name=classification_pset.name
|
||||
)
|
||||
else:
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_qto", tool.Ifc.get(), product=element, name=classification_pset.name
|
||||
)
|
||||
|
||||
properties = {}
|
||||
for prop in classification_pset.properties:
|
||||
properties[prop.name] = prop.get_value()
|
||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties=properties)
|
||||
|
||||
if is_pset:
|
||||
ifcopenshell.api.run("pset.edit_pset", tool.Ifc.get(), pset=pset, properties=properties)
|
||||
else:
|
||||
ifcopenshell.api.run("pset.edit_qto", tool.Ifc.get(), qto=pset, properties=properties)
|
||||
|
||||
|
||||
class ChangeClassificationLevel(bpy.types.Operator):
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.bim.helper
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.classification.data import ClassificationsData
|
||||
from blenderbim.bim.module.classification.data import ClassificationsData, ClassificationReferencesData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -39,6 +40,12 @@ def get_available_classifications(self, context):
|
||||
return ClassificationsData.data["available_classifications"]
|
||||
|
||||
|
||||
def get_classifications(self, context):
|
||||
if not ClassificationReferencesData.is_loaded:
|
||||
ClassificationReferencesData.load()
|
||||
return ClassificationReferencesData.data["classifications"]
|
||||
|
||||
|
||||
class ClassificationReference(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
identification: StringProperty(name="Identification")
|
||||
@@ -48,6 +55,7 @@ class ClassificationReference(PropertyGroup):
|
||||
|
||||
|
||||
class BIMClassificationProperties(PropertyGroup):
|
||||
is_adding: BoolProperty(name="Is Adding", default=False)
|
||||
classification_source: EnumProperty(
|
||||
items=[
|
||||
("FILE", "IFC File", ""),
|
||||
@@ -66,5 +74,7 @@ class BIMClassificationProperties(PropertyGroup):
|
||||
|
||||
|
||||
class BIMClassificationReferenceProperties(PropertyGroup):
|
||||
is_adding: BoolProperty(name="Is Adding", default=False)
|
||||
classifications: EnumProperty(items=get_classifications, name="Classifications")
|
||||
reference_attributes: CollectionProperty(name="Reference Attributes", type=Attribute)
|
||||
active_reference_id: IntProperty(name="Active Reference Id")
|
||||
|
||||
@@ -66,8 +66,14 @@ class BIM_PT_classifications(Panel):
|
||||
self.draw_ui(classification)
|
||||
|
||||
def draw_add_manual_ui(self, context):
|
||||
row = self.layout.row()
|
||||
row.label(text="TODO", icon="ERROR")
|
||||
if self.props.is_adding:
|
||||
blenderbim.bim.helper.draw_attributes(self.props.classification_attributes, self.layout)
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.add_manual_classification", text="Save", icon="CHECKMARK")
|
||||
row.operator("bim.disable_adding_manual_classification", text="", icon="CANCEL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.enable_adding_manual_classification", text="Add Classification", icon="ADD")
|
||||
|
||||
def draw_add_bsdd_ui(self, context):
|
||||
self.bprops = context.scene.BIMBSDDProperties
|
||||
@@ -144,7 +150,16 @@ class ReferenceUI:
|
||||
|
||||
def draw_add_manual_ui(self, context):
|
||||
row = self.layout.row()
|
||||
row.label(text="TODO", icon="ERROR")
|
||||
row.prop(self.props, "classifications", text="")
|
||||
if self.props.is_adding:
|
||||
blenderbim.bim.helper.draw_attributes(self.props.reference_attributes, self.layout)
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.add_manual_classification_reference", text="Save", icon="CHECKMARK")
|
||||
op.type = self.data.data["object_type"]
|
||||
row.operator("bim.disable_adding_manual_classification_reference", text="", icon="CANCEL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.enable_adding_manual_classification_reference", text="Add Reference", icon="ADD")
|
||||
|
||||
def draw_add_bsdd_ui(self, context):
|
||||
if not self.bprops.active_domain:
|
||||
@@ -239,6 +254,8 @@ class ReferenceUI:
|
||||
name = reference["Identification"] or "No Identification"
|
||||
row.label(text=name, icon="ASSET_MANAGER")
|
||||
row.label(text=reference["Name"] or "")
|
||||
if reference["Location"]:
|
||||
row.operator("bim.open_uri", icon="URL", text="").uri = reference["Location"]
|
||||
if not self.props.active_reference_id:
|
||||
op = row.operator("bim.enable_editing_classification_reference", text="", icon="GREASEPENCIL")
|
||||
op.reference = reference["id"]
|
||||
|
||||
@@ -256,7 +256,7 @@ class CostSchedulesData:
|
||||
for cost_value in cost_item.CostValues or []:
|
||||
label = "{0:.2f}".format(ifcopenshell.util.cost.calculate_applied_value(cost_item, cost_value))
|
||||
label += " = {}".format(ifcopenshell.util.cost.serialise_cost_value(cost_value))
|
||||
results.append({"id": cost_value.id(), "label": label})
|
||||
results.append({"id": cost_value.id(), "label": label, "name": cost_value.Name})
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -37,12 +37,10 @@ class AddCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
|
||||
object_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.add_cost_schedule(
|
||||
tool.Ifc,
|
||||
name=self.name,
|
||||
predefined_type=context.scene.BIMCostProperties.cost_schedule_predefined_types,
|
||||
object_type=self.object_type,
|
||||
)
|
||||
predefined_type = context.scene.BIMCostProperties.cost_schedule_predefined_types
|
||||
if predefined_type == "USERDEFINED":
|
||||
predefined_type = self.object_type
|
||||
core.add_cost_schedule(tool.Ifc, name=self.name, predefined_type=predefined_type)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
@@ -42,19 +42,21 @@ class BIM_PT_cost_schedules(Panel):
|
||||
CostSchedulesData.load()
|
||||
|
||||
self.props = context.scene.BIMCostProperties
|
||||
row = self.layout.row(align=True)
|
||||
if not self.props.active_cost_schedule_id:
|
||||
row = self.layout.row(align=True)
|
||||
if CostSchedulesData.data["total_cost_schedules"]:
|
||||
row.alignment = "RIGHT"
|
||||
row.operator("bim.export_cost_schedules",icon="EXPORT",text="Export All Schedules")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"{CostSchedulesData.data['total_cost_schedules']} Cost Schedules Found", icon="TEXT")
|
||||
else:
|
||||
row.label(text="No Cost Schedules found.", icon="TEXT")
|
||||
|
||||
row.operator("bim.add_cost_schedule", icon="ADD", text="")
|
||||
row.operator("import_cost_schedule_csv.bim",icon="IMPORT",text="")
|
||||
|
||||
for schedule in CostSchedulesData.data["schedules"]:
|
||||
self.draw_cost_schedule_ui(schedule)
|
||||
row2 = self.layout.row()
|
||||
row2.alignment = "RIGHT"
|
||||
row2.operator("bim.export_cost_schedules", text="Export all", icon="EXPORT")
|
||||
|
||||
def draw_cost_schedule_ui(self, cost_schedule):
|
||||
row = self.layout.row(align=True)
|
||||
@@ -236,6 +238,8 @@ class BIM_PT_cost_schedules(Panel):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, self.layout.box())
|
||||
|
||||
def draw_readonly_cost_value_ui(self, layout, cost_value):
|
||||
if cost_value["name"]:
|
||||
layout.label(text=f"{cost_value['name']}: ")
|
||||
if self.props.active_cost_value_id == cost_value["id"] and self.props.cost_value_editing_type == "FORMULA":
|
||||
layout.prop(self.props, "cost_value_formula", text="")
|
||||
else:
|
||||
|
||||
@@ -24,6 +24,7 @@ import logging
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.drawing.scheduler as scheduler
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.handler import refresh_ui_data
|
||||
|
||||
@@ -92,15 +93,26 @@ class ImportCsvAttributes(bpy.types.Operator):
|
||||
data = json.load(open(self.filepath))
|
||||
tool.Search.import_filter_query(data["query"], props.filter_groups)
|
||||
|
||||
for prop in [
|
||||
"should_generate_svg",
|
||||
"should_preserve_existing",
|
||||
"include_global_id",
|
||||
"null_value",
|
||||
"empty_value",
|
||||
"true_value",
|
||||
"false_value",
|
||||
"concat_value",
|
||||
"csv_delimiter",
|
||||
"format",
|
||||
"csv_custom_delimiter",
|
||||
]:
|
||||
setattr(props, prop, data["settings"][prop])
|
||||
|
||||
props.csv_attributes.clear()
|
||||
for attribute in data["attributes"]:
|
||||
new = props.csv_attributes.add()
|
||||
new.name = attribute["name"]
|
||||
new.header = attribute["header"]
|
||||
new.sort = attribute["sort"]
|
||||
new.group = attribute["group"]
|
||||
new.summary = attribute["summary"]
|
||||
new.formatting = attribute["formatting"]
|
||||
for prop in ["name", "header", "sort", "group", "summary", "formatting"]:
|
||||
setattr(new, prop, attribute[prop])
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
@@ -120,6 +132,22 @@ class ExportCsvAttributes(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
props = context.scene.CsvProperties
|
||||
|
||||
settings = {}
|
||||
for prop in [
|
||||
"should_generate_svg",
|
||||
"should_preserve_existing",
|
||||
"include_global_id",
|
||||
"null_value",
|
||||
"empty_value",
|
||||
"true_value",
|
||||
"false_value",
|
||||
"concat_value",
|
||||
"csv_delimiter",
|
||||
"format",
|
||||
"csv_custom_delimiter",
|
||||
]:
|
||||
settings[prop] = getattr(props, prop)
|
||||
|
||||
data = {
|
||||
"query": tool.Search.export_filter_query(props.filter_groups),
|
||||
"attributes": [
|
||||
@@ -133,6 +161,7 @@ class ExportCsvAttributes(bpy.types.Operator):
|
||||
}
|
||||
for a in props.csv_attributes
|
||||
],
|
||||
"settings": settings,
|
||||
}
|
||||
|
||||
with open(self.filepath, "w") as outfile:
|
||||
@@ -213,6 +242,10 @@ class ExportIfcCsv(bpy.types.Operator):
|
||||
summaries=summaries,
|
||||
formatting=formatting,
|
||||
)
|
||||
|
||||
if props.format != "csv" and props.should_generate_svg:
|
||||
schedule_creator = scheduler.Scheduler()
|
||||
schedule_creator.schedule(self.filepath, tool.Drawing.get_path_with_ext(self.filepath, "svg"))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ class CsvProperties(PropertyGroup):
|
||||
ifc_selector: StringProperty(default="", name="IFC Selector")
|
||||
filter_groups: CollectionProperty(type=BIMFilterGroup, name="Filter Groups")
|
||||
csv_attributes: CollectionProperty(name="CSV Attributes", type=CsvAttribute)
|
||||
should_generate_svg: BoolProperty(default=False, name="Generate SVG")
|
||||
should_preserve_existing: BoolProperty(default=False, name="Preserve Existing")
|
||||
include_global_id: BoolProperty(default=True, name="Include GlobalId")
|
||||
null_value: StringProperty(default="N/A", name="Null Value")
|
||||
|
||||
@@ -67,6 +67,8 @@ class BIM_PT_ifccsv(Panel):
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "csv_custom_delimiter")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, "should_generate_svg")
|
||||
row = layout.row()
|
||||
row.prop(props, "should_preserve_existing")
|
||||
row = layout.row()
|
||||
|
||||
@@ -213,7 +213,7 @@ class CreateAllShapes(bpy.types.Operator):
|
||||
settings_2d.set(settings_2d.INCLUDE_CURVES, True)
|
||||
failures = []
|
||||
excludes = () # For the developer to debug with
|
||||
for i, element in enumerate(elements):
|
||||
for i, element in enumerate(elements, 1):
|
||||
if element.GlobalId in excludes:
|
||||
continue
|
||||
print(f"{i}/{total}:", element)
|
||||
@@ -475,7 +475,7 @@ class OverrideDisplayType(bpy.types.Operator):
|
||||
|
||||
class PrintUnusedElementStats(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.print_unused_elements_stats"
|
||||
bl_label = "Purge Unused Elements Stats"
|
||||
bl_label = "Print Unused Elements Stats"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = (
|
||||
"Print all unused elements in current IFC project in system console, not limited to the selected class"
|
||||
@@ -484,6 +484,7 @@ class PrintUnusedElementStats(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ignore_contexts: bpy.props.BoolProperty(name="Ignore Contexts", default=True)
|
||||
ignore_relationships: bpy.props.BoolProperty(name="Ignore Relationships", default=True)
|
||||
ignore_types: bpy.props.BoolProperty(name="Ignore Types", default=True)
|
||||
ignore_styled_items: bpy.props.BoolProperty(name="Ignoer Styled Items", default=True)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMDebugProperties
|
||||
@@ -495,6 +496,8 @@ class PrintUnusedElementStats(bpy.types.Operator, tool.Ifc.Operator):
|
||||
ignore_classes += ["IfcRelationship"]
|
||||
if self.ignore_types:
|
||||
ignore_classes += ["IfcTypeProduct"]
|
||||
if self.ignore_styled_items:
|
||||
ignore_classes += ["IfcStyledItem"]
|
||||
|
||||
unused_elements = tool.Debug.print_unused_elements_stats(props.ifc_class_purge, ignore_classes)
|
||||
self.report({"INFO"}, f"{unused_elements} unused elements found, check the system console for the details.")
|
||||
@@ -504,11 +507,119 @@ class PurgeUnusedElementsByClass(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.purge_unused_elements_by_class"
|
||||
bl_label = "Purge Unused Elements By Class"
|
||||
bl_description = (
|
||||
"Will find all elements of class that have no inverse refernces and will remove them, use very carefully."
|
||||
"Will find all elements of class that have no inverse refernces and will remove them, use very carefully"
|
||||
)
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
filter_glob: bpy.props.StringProperty(default="*.ifc", options={"HIDDEN"})
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMDebugProperties
|
||||
purged_elements = core.purge_unused_elements(tool.Ifc, tool.Debug, props.ifc_class_purge)
|
||||
self.report({"INFO"}, f"{purged_elements} unused elements found and removed.")
|
||||
if props.ifc_class_purge:
|
||||
purged_elements = core.purge_unused_elements(tool.Ifc, tool.Debug, props.ifc_class_purge)
|
||||
self.report({"INFO"}, f"{purged_elements} unused elements found and removed.")
|
||||
tool.Ifc.get().write(self.filepath)
|
||||
return
|
||||
|
||||
# A whitelisted class is a class that only contains simple data that
|
||||
# has no meaning by itself (only has meaning when combined with other
|
||||
# data). E.g. a colour by itself has no meaning so is whitelisted, but
|
||||
# a material by itself may be part of your materials library.
|
||||
|
||||
# There are classes I don't know enough about to decide. Not whitelisting in case.
|
||||
# IfcAlignmentParameterSegment
|
||||
# IfcBoundaryCondition
|
||||
# IfcStructuralConnectionCondition
|
||||
# IfcStructuralLoad
|
||||
|
||||
whitelisted_classes = [
|
||||
"IfcActorRole",
|
||||
"IfcAddress",
|
||||
"IfcApplication",
|
||||
"IfcAppliedValue",
|
||||
"IfcConnectionGeometry",
|
||||
"IfcCoordinateReferenceSystem",
|
||||
"IfcDerivedUnit",
|
||||
"IfcDerivedUnitElement",
|
||||
"IfcDimensionalExponents",
|
||||
"IfcExternalReference",
|
||||
"IfcGridAxis",
|
||||
"IfcIrregularTimeSeriesValue",
|
||||
"IfcLightDistributionData",
|
||||
"IfcLightIntensityDistribution",
|
||||
"IfcMeasureWithUnit",
|
||||
"IfcMonetaryUnit",
|
||||
"IfcNamedUnit",
|
||||
"IfcObjectPlacement",
|
||||
"IfcOrganization", # Should be referenced as part of an actor
|
||||
"IfcOwnerHistory",
|
||||
"IfcPerson", # Should be referenced as part of an actor
|
||||
"IfcPersonAndOrganization", # Should be referenced as part of an actor
|
||||
"IfcPhysicalQuantity",
|
||||
"IfcPresentationItem",
|
||||
"IfcProductDefinitionShape",
|
||||
"IfcPropertyAbstraction",
|
||||
"IfcRecurrencePattern",
|
||||
"IfcReference",
|
||||
"IfcRepresentation",
|
||||
"IfcRepresentationContext",
|
||||
"IfcRepresentationItem",
|
||||
"IfcRepresentationMap",
|
||||
"IfcPropertyDefinition", # A bit of a questionable one, and the odd one out from IfcRoot.
|
||||
"IfcSchedulingTime",
|
||||
"IfcShapeAspect",
|
||||
"IfcTable",
|
||||
"IfcTableColumn",
|
||||
"IfcTableRow",
|
||||
"IfcTextureCoordinateIndices",
|
||||
"IfcTimePeriod",
|
||||
"IfcTimeSeries",
|
||||
"IfcTimeSeriesValue",
|
||||
"IfcUnitAssignment",
|
||||
"IfcVirtualGridIntersection",
|
||||
]
|
||||
|
||||
total_purged = 0
|
||||
while True:
|
||||
total_batches = 0
|
||||
print("*" * 100)
|
||||
total_batch_purged = 0
|
||||
for ifc_class in whitelisted_classes:
|
||||
total_class_purged = 0
|
||||
try:
|
||||
elements = tool.Ifc.get().by_type(ifc_class)
|
||||
except:
|
||||
continue # Probably not in this schema?
|
||||
to_purge = set()
|
||||
for element in elements:
|
||||
try:
|
||||
if ifc_class == "IfcRepresentationItem" and element.is_a("IfcStyledItem") and element.Item:
|
||||
continue
|
||||
except:
|
||||
to_purge.add(element.id()) # It's invalid, definitely purge it.
|
||||
if tool.Ifc.get().get_total_inverses(element) == 0:
|
||||
to_purge.add(element.id())
|
||||
for element_id in to_purge:
|
||||
try:
|
||||
element = tool.Ifc.get().by_id(element_id)
|
||||
ifcopenshell.util.element.remove_deep2(tool.Ifc.get(), element)
|
||||
total_class_purged += 1
|
||||
except:
|
||||
continue
|
||||
if total_class_purged > 0:
|
||||
total_batch_purged += total_class_purged
|
||||
print(f"Auto purged {total_class_purged} {ifc_class}")
|
||||
if total_batch_purged > 0:
|
||||
total_purged += total_batch_purged
|
||||
print(f"Auto purged in batch: {total_batch_purged}")
|
||||
total_batches += 1
|
||||
if total_batch_purged == 0:
|
||||
break
|
||||
elif total_batches > 20:
|
||||
print("Finished 20 batches. Manually stopping in case of infinite loop.")
|
||||
self.report({"INFO"}, f"Auto purged {total_purged} orphaned elements")
|
||||
tool.Ifc.get().write(self.filepath)
|
||||
|
||||
@@ -37,7 +37,6 @@ class BIM_PT_debug(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.BIMProperties, "ifc_file", text="")
|
||||
row.operator("bim.validate_ifc_file", icon="CHECKMARK", text="")
|
||||
row.operator("bim.reload_selected_ifc_file", icon="FILE_REFRESH", text="")
|
||||
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
@@ -45,6 +44,9 @@ class BIM_PT_debug(Panel):
|
||||
row.operator("bim.parse_express", icon="IMPORT", text="")
|
||||
row.operator("bim.select_express_file", icon="FILE_FOLDER", text="")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.reload_ifc_file", text="Incrementally Reload Changes")
|
||||
|
||||
row = layout.row()
|
||||
row.operator("bim.print_ifc_file")
|
||||
|
||||
@@ -87,6 +89,13 @@ class BIM_PT_debug(Panel):
|
||||
row.prop(props, "display_type", text="")
|
||||
row.operator("bim.override_display_type").display = context.scene.BIMDebugProperties.display_type
|
||||
|
||||
layout.operator("bim.purge_unused_representations")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(context.scene.BIMDebugProperties, "ifc_class_purge", text="")
|
||||
row.operator("bim.purge_unused_elements_by_class", text="Purge Orphaned", icon="TRASH")
|
||||
row.operator("bim.print_unused_elements_stats", text="", icon="INFO")
|
||||
|
||||
if context.active_object and context.active_object.data:
|
||||
mprops = context.active_object.data.BIMMeshProperties
|
||||
row = layout.row()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
import os
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import blenderbim.tool as tool
|
||||
|
||||
@@ -801,7 +801,7 @@ class AngleDecorator(BaseDecorator):
|
||||
angle_rad = acos(cos_a)
|
||||
angle = angle_rad / pi * 180
|
||||
except ZeroDivisionError:
|
||||
angle = 0
|
||||
angle_rad, angle = 0, 0
|
||||
|
||||
# calculate angle position
|
||||
p0, p1, p2 = [location_3d_to_region_2d(region, region3d, p) for p in vertices[i0 : i1 + 2]]
|
||||
@@ -1949,9 +1949,10 @@ class DecorationsHandler:
|
||||
def get_objects_and_decorators(self, collection):
|
||||
# TODO: do it in data instead of the handler for performance?
|
||||
results = []
|
||||
viewport = bpy.context.space_data
|
||||
|
||||
for obj in collection.all_objects:
|
||||
if obj.hide_get():
|
||||
if not obj.visible_get(viewport=viewport):
|
||||
continue
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
@@ -44,6 +44,7 @@ import blenderbim.bim.module.drawing.helper as helper
|
||||
import blenderbim.bim.export_ifc
|
||||
from blenderbim.bim.module.drawing.decoration import CutDecorator
|
||||
from blenderbim.bim.module.drawing.data import DecoratorData, DrawingsData
|
||||
from typing import NamedTuple, List
|
||||
from lxml import etree
|
||||
from mathutils import Vector, Color, Matrix
|
||||
from timeit import default_timer as timer
|
||||
@@ -77,6 +78,11 @@ class Operator:
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class LineworkContexts(NamedTuple):
|
||||
body: List[List[int]]
|
||||
annotation: List[List[int]]
|
||||
|
||||
|
||||
class AddAnnotationType(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.add_annotation_type"
|
||||
bl_label = "Add Annotation Type"
|
||||
@@ -367,6 +373,105 @@ class CreateDrawing(bpy.types.Operator):
|
||||
self.svg_writer.create_blank_svg(svg_path).draw_underlay(context.scene.render.filepath).save()
|
||||
return svg_path
|
||||
|
||||
def get_linework_contexts(self, ifc, target_view) -> LineworkContexts:
|
||||
plan_body_target_contexts = []
|
||||
plan_body_model_contexts = []
|
||||
model_body_target_contexts = []
|
||||
model_body_model_contexts = []
|
||||
|
||||
plan_annotation_target_contexts = []
|
||||
plan_annotation_model_contexts = []
|
||||
model_annotation_target_contexts = []
|
||||
model_annotation_model_contexts = []
|
||||
|
||||
for rep_context in ifc.by_type("IfcGeometricRepresentationContext"):
|
||||
if rep_context.is_a("IfcGeometricRepresentationSubContext"):
|
||||
if rep_context.ContextType == "Plan":
|
||||
if rep_context.ContextIdentifier in ["Body", "Facetation"]:
|
||||
if rep_context.TargetView == target_view:
|
||||
plan_body_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
plan_body_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextIdentifier == "Annotation":
|
||||
if rep_context.TargetView == target_view:
|
||||
plan_annotation_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
plan_annotation_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextType == "Model":
|
||||
if rep_context.ContextIdentifier in ["Body", "Facetation"]:
|
||||
if rep_context.TargetView == target_view:
|
||||
model_body_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
model_body_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextIdentifier == "Annotation":
|
||||
if rep_context.TargetView == target_view:
|
||||
model_annotation_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
model_annotation_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextType == "Model":
|
||||
# You should never purely assign to a "Model" context, but
|
||||
# if you do, this is what we assume your intention is.
|
||||
model_body_model_contexts.append(rep_context.id())
|
||||
continue
|
||||
|
||||
body_contexts = (
|
||||
[
|
||||
plan_body_target_contexts,
|
||||
plan_body_model_contexts,
|
||||
model_body_target_contexts,
|
||||
model_body_model_contexts,
|
||||
]
|
||||
if target_view in ["PLAN_VIEW", "REFLECTED_PLAN_VIEW"]
|
||||
else [
|
||||
model_body_target_contexts,
|
||||
model_body_model_contexts,
|
||||
]
|
||||
)
|
||||
|
||||
annotation_contexts = (
|
||||
[
|
||||
plan_annotation_target_contexts,
|
||||
plan_annotation_model_contexts,
|
||||
model_annotation_target_contexts,
|
||||
model_annotation_model_contexts,
|
||||
]
|
||||
if target_view in ["PLAN_VIEW", "REFLECTED_PLAN_VIEW"]
|
||||
else [
|
||||
model_annotation_target_contexts,
|
||||
model_annotation_model_contexts,
|
||||
]
|
||||
)
|
||||
|
||||
return LineworkContexts(body_contexts, annotation_contexts)
|
||||
|
||||
def serialize_contexts_elements(
|
||||
self, ifc, tree: ifcopenshell.geom.tree, contexts: LineworkContexts, context_type, drawing_elements, target_view
|
||||
):
|
||||
drawing_elements = drawing_elements.copy()
|
||||
contexts = getattr(contexts, context_type)
|
||||
for context in contexts:
|
||||
with profile(f"Processing {context_type} context"):
|
||||
if not context or not drawing_elements:
|
||||
continue
|
||||
geom_settings = ifcopenshell.geom.settings(
|
||||
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
|
||||
)
|
||||
if ifc.by_id(context[0]).ContextType == "Plan" and "PLAN_VIEW" in target_view:
|
||||
offset = ifcopenshell.ifcopenshell_wrapper.float_array_3()
|
||||
# A 2mm Z offset to combat Z-fighting in plan or RCPs
|
||||
offset[2] = 0.002 if target_view == "PLAN_VIEW" else -0.002
|
||||
geom_settings.offset = offset
|
||||
geom_settings.set_context_ids(context)
|
||||
it = ifcopenshell.geom.iterator(
|
||||
geom_settings, ifc, multiprocessing.cpu_count(), include=drawing_elements
|
||||
)
|
||||
processed = set()
|
||||
for elem in it:
|
||||
processed.add(ifc.by_id(elem.id))
|
||||
self.serialiser.write(elem)
|
||||
tree.add_element(elem)
|
||||
drawing_elements -= processed
|
||||
|
||||
def generate_linework(self, context):
|
||||
if not ifcopenshell.util.element.get_pset(self.drawing, "EPset_Drawing", "HasLinework"):
|
||||
return
|
||||
@@ -408,77 +513,8 @@ class CreateDrawing(bpy.types.Operator):
|
||||
# Drawings only draw bodies and annotations (and facetation, due to a Revit bug).
|
||||
# A drawing prioritises a target view context first, followed by a model view context as a fallback.
|
||||
# Specifically for PLAN_VIEW and REFLECTED_PLAN_VIEW, any Plan context is also prioritised.
|
||||
|
||||
plan_body_target_contexts = []
|
||||
plan_body_model_contexts = []
|
||||
model_body_target_contexts = []
|
||||
model_body_model_contexts = []
|
||||
|
||||
plan_annotation_target_contexts = []
|
||||
plan_annotation_model_contexts = []
|
||||
model_annotation_target_contexts = []
|
||||
model_annotation_model_contexts = []
|
||||
|
||||
target_view = ifcopenshell.util.element.get_psets(self.camera_element)["EPset_Drawing"]["TargetView"]
|
||||
|
||||
for rep_context in ifc.by_type("IfcGeometricRepresentationContext"):
|
||||
if rep_context.is_a("IfcGeometricRepresentationSubContext"):
|
||||
if rep_context.ContextType == "Plan":
|
||||
if rep_context.ContextIdentifier in ["Body", "Facetation"]:
|
||||
if rep_context.TargetView == target_view:
|
||||
plan_body_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
plan_body_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextIdentifier == "Annotation":
|
||||
if rep_context.TargetView == target_view:
|
||||
plan_annotation_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
plan_annotation_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextType == "Model":
|
||||
if rep_context.ContextIdentifier in ["Body", "Facetation"]:
|
||||
if rep_context.TargetView == target_view:
|
||||
model_body_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
model_body_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextIdentifier == "Annotation":
|
||||
if rep_context.TargetView == target_view:
|
||||
model_annotation_target_contexts.append(rep_context.id())
|
||||
elif rep_context.TargetView == "MODEL_VIEW":
|
||||
model_annotation_model_contexts.append(rep_context.id())
|
||||
elif rep_context.ContextType == "Model":
|
||||
# You should never purely assign to a "Model" context, but
|
||||
# if you do, this is what we assume your intention is.
|
||||
model_body_model_contexts.append(rep_context.id())
|
||||
continue
|
||||
|
||||
body_contexts = (
|
||||
[
|
||||
plan_body_target_contexts,
|
||||
plan_body_model_contexts,
|
||||
model_body_target_contexts,
|
||||
model_body_model_contexts,
|
||||
]
|
||||
if target_view in ["PLAN_VIEW", "REFLECTED_PLAN_VIEW"]
|
||||
else [
|
||||
model_body_target_contexts,
|
||||
model_body_model_contexts,
|
||||
]
|
||||
)
|
||||
|
||||
annotation_contexts = (
|
||||
[
|
||||
plan_annotation_target_contexts,
|
||||
plan_annotation_model_contexts,
|
||||
model_annotation_target_contexts,
|
||||
model_annotation_model_contexts,
|
||||
]
|
||||
if target_view in ["PLAN_VIEW", "REFLECTED_PLAN_VIEW"]
|
||||
else [
|
||||
model_annotation_target_contexts,
|
||||
model_annotation_model_contexts,
|
||||
]
|
||||
)
|
||||
|
||||
contexts = self.get_linework_contexts(ifc, target_view)
|
||||
drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element)
|
||||
|
||||
self.setup_serialiser(ifc, target_view)
|
||||
@@ -487,50 +523,15 @@ class CreateDrawing(bpy.types.Operator):
|
||||
tree = ifcopenshell.geom.tree()
|
||||
tree.enable_face_styles(True)
|
||||
|
||||
elements = drawing_elements.copy()
|
||||
for body_context in body_contexts:
|
||||
with profile("Processing body context"):
|
||||
if body_context and elements:
|
||||
geom_settings = ifcopenshell.geom.settings(
|
||||
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
|
||||
)
|
||||
geom_settings.set_context_ids(body_context)
|
||||
it = ifcopenshell.geom.iterator(
|
||||
geom_settings, ifc, multiprocessing.cpu_count(), include=elements
|
||||
)
|
||||
it.set_cache(cache)
|
||||
processed = set()
|
||||
for elem in self.yield_from_iterator(it):
|
||||
processed.add(ifc.by_id(elem.id))
|
||||
self.serialiser.write(elem)
|
||||
tree.add_element(elem)
|
||||
elements -= processed
|
||||
|
||||
elements = drawing_elements.copy()
|
||||
for annotation_context in annotation_contexts:
|
||||
with profile("Processing annotation context"):
|
||||
if annotation_context and elements:
|
||||
geom_settings = ifcopenshell.geom.settings(
|
||||
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
|
||||
)
|
||||
geom_settings.set_context_ids(annotation_context)
|
||||
it = ifcopenshell.geom.iterator(
|
||||
geom_settings, ifc, multiprocessing.cpu_count(), include=elements
|
||||
)
|
||||
it.set_cache(cache)
|
||||
processed = set()
|
||||
for elem in self.yield_from_iterator(it):
|
||||
processed.add(ifc.by_id(elem.id))
|
||||
self.serialiser.write(elem)
|
||||
tree.add_element(elem)
|
||||
elements -= processed
|
||||
self.serialize_contexts_elements(ifc, tree, contexts, "body", drawing_elements, target_view)
|
||||
self.serialize_contexts_elements(ifc, tree, contexts, "annotation", drawing_elements, target_view)
|
||||
|
||||
if self.camera_element not in drawing_elements:
|
||||
with profile("Camera element"):
|
||||
# The camera must always be included, regardless of any include/exclude filters.
|
||||
geom_settings = ifcopenshell.geom.settings(DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True)
|
||||
it = ifcopenshell.geom.iterator(geom_settings, ifc, include=[self.camera_element])
|
||||
for elem in self.yield_from_iterator(it):
|
||||
for elem in it:
|
||||
self.serialiser.write(elem)
|
||||
|
||||
with profile("Finalizing"):
|
||||
@@ -874,13 +875,6 @@ class CreateDrawing(bpy.types.Operator):
|
||||
# the style of the face when running tree.select_ray()
|
||||
# tree.enable_face_styles(True)
|
||||
|
||||
def yield_from_iterator(self, it):
|
||||
if it.initialize():
|
||||
while True:
|
||||
yield it.get()
|
||||
if not it.next():
|
||||
break
|
||||
|
||||
def get_svg_classes(self, element):
|
||||
classes = [element.is_a()]
|
||||
material = ifcopenshell.util.element.get_material(element, should_skip_usage=True)
|
||||
@@ -956,17 +950,21 @@ class CreateDrawing(bpy.types.Operator):
|
||||
# alone (e.g. dangles, cuts, invalids). See #3421.
|
||||
line_strings = []
|
||||
old_paths = []
|
||||
has_open_paths = False
|
||||
for path in el.findall("{http://www.w3.org/2000/svg}path"):
|
||||
for subpath in path.attrib["d"].split("M")[1:]:
|
||||
subpath = "M" + subpath.strip()
|
||||
coords = [[round(float(o), 1) for o in co[1:].split(",")] for co in subpath.split()]
|
||||
if coords[0] != coords[-1]:
|
||||
has_open_paths = True
|
||||
line_strings.append(shapely.LineString(coords))
|
||||
old_paths.append(path)
|
||||
unioned_line_strings = shapely.union_all(shapely.GeometryCollection(line_strings))
|
||||
if hasattr(unioned_line_strings, "geoms"):
|
||||
results = shapely.polygonize_full(unioned_line_strings.geoms)
|
||||
else:
|
||||
results = []
|
||||
|
||||
results = []
|
||||
if has_open_paths:
|
||||
unioned_line_strings = shapely.union_all(shapely.GeometryCollection(line_strings))
|
||||
if hasattr(unioned_line_strings, "geoms"):
|
||||
results = shapely.polygonize_full(unioned_line_strings.geoms)
|
||||
|
||||
# If we succeeded in generating new path geometry, remove all the
|
||||
# old paths and add new ones.
|
||||
@@ -1996,11 +1994,11 @@ class AddReferenceToSheet(bpy.types.Operator, Operator):
|
||||
props = context.scene.DocProperties
|
||||
active_reference = props.references[props.active_reference_index]
|
||||
active_sheet = tool.Drawing.get_active_sheet(context)
|
||||
reference = tool.Ifc.get().by_id(active_reference.ifc_definition_id)
|
||||
extref = tool.Ifc.get().by_id(active_reference.ifc_definition_id)
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
reference_location = tool.Drawing.get_path_with_ext(reference.DocumentReferences[0].Location, "svg")
|
||||
extref_location = tool.Drawing.get_path_with_ext(extref.DocumentReferences[0].Location, "svg")
|
||||
else:
|
||||
reference_location = tool.Drawing.get_path_with_ext(reference.HasDocumentReferences[0].Location, "svg")
|
||||
extref_location = tool.Drawing.get_path_with_ext(extref.HasDocumentReferences[0].Location, "svg")
|
||||
|
||||
sheet = tool.Ifc.get().by_id(active_sheet.ifc_definition_id)
|
||||
if not sheet.is_a("IfcDocumentInformation"):
|
||||
@@ -2008,30 +2006,30 @@ class AddReferenceToSheet(bpy.types.Operator, Operator):
|
||||
|
||||
references = tool.Drawing.get_document_references(sheet)
|
||||
|
||||
has_reference = False
|
||||
has_extref = False
|
||||
for reference in references:
|
||||
if reference.Location == reference_location:
|
||||
has_reference = True
|
||||
if reference.Location == extref_location:
|
||||
has_extref = True
|
||||
break
|
||||
if has_reference:
|
||||
if has_extref:
|
||||
return
|
||||
|
||||
if not tool.Drawing.does_file_exist(tool.Ifc.resolve_uri(reference_location)):
|
||||
self.report({"ERROR"}, f"Cannot find reference svg by path {reference_location}.")
|
||||
if not tool.Drawing.does_file_exist(tool.Ifc.resolve_uri(extref_location)):
|
||||
self.report({"ERROR"}, f"Cannot find reference svg by path {extref_location}.")
|
||||
return
|
||||
|
||||
reference = tool.Ifc.run("document.add_reference", information=sheet)
|
||||
id_attr = "ItemReference" if tool.Ifc.get_schema() == "IFC2X3" else "Identification"
|
||||
attributes = {
|
||||
id_attr: str(len([r for r in references if r.Description in ("DRAWING", "REFERENCE")]) + 1),
|
||||
"Location": reference_location,
|
||||
"Location": extref_location,
|
||||
"Description": "REFERENCE",
|
||||
}
|
||||
tool.Ifc.run("document.edit_reference", reference=reference, attributes=attributes)
|
||||
|
||||
sheet_builder = sheeter.SheetBuilder()
|
||||
sheet_builder.data_dir = context.scene.BIMProperties.data_dir
|
||||
sheet_builder.add_document(reference, reference, sheet)
|
||||
sheet_builder.add_document(reference, extref, sheet)
|
||||
|
||||
tool.Drawing.import_sheets()
|
||||
|
||||
@@ -2571,6 +2569,7 @@ class AddReferenceImage(bpy.types.Operator, Operator):
|
||||
bl_label = "Add Reference Image"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
use_relative_path: bpy.props.BoolProperty(name="Use Relative Path", default=True)
|
||||
filepath: bpy.props.StringProperty(
|
||||
name="File Path", description="Filepath used to import from", maxlen=1024, default="", subtype="FILE_PATH"
|
||||
)
|
||||
@@ -2590,19 +2589,34 @@ class AddReferenceImage(bpy.types.Operator, Operator):
|
||||
options={"SKIP_SAVE"},
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
if Path(tool.Ifc.get_path()).is_file():
|
||||
layout.prop(self, "use_relative_path")
|
||||
else:
|
||||
self.use_relative_path = False
|
||||
layout.label(text="Save the .ifc file first ")
|
||||
layout.label(text="to use relative paths.")
|
||||
layout.prop(self, "override_existing_image")
|
||||
layout.prop(self, "use_existing_object_by_name")
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def _execute(self, context):
|
||||
abs_path = Path(self.filepath)
|
||||
if self.use_relative_path:
|
||||
image_filepath = abs_path.relative_to(Path(tool.Ifc.get_path()).parent)
|
||||
else:
|
||||
image_filepath = abs_path
|
||||
ifc_file = tool.Ifc.get()
|
||||
image_filepath = Path(self.filepath)
|
||||
|
||||
if self.override_existing_image:
|
||||
params = {"check_existing": True, "force_reload": True}
|
||||
else:
|
||||
params = {"check_existing": False}
|
||||
image = load_image(image_filepath.name, image_filepath.parent, **params)
|
||||
image = load_image(abs_path.name, abs_path.parent, **params)
|
||||
|
||||
def bm_add_image_plane(mesh):
|
||||
bm = tool.Blender.get_bmesh_for_mesh(mesh, clean=True)
|
||||
@@ -2638,8 +2652,33 @@ class AddReferenceImage(bpy.types.Operator, Operator):
|
||||
|
||||
style = ifc_file.by_id(material.BIMMaterialProperties.ifc_style_id)
|
||||
tool.Style.assign_style_to_object(style, obj)
|
||||
tool.Geometry.record_object_materials(obj)
|
||||
|
||||
material.BIMStyleProperties.diffuse_path = self.filepath
|
||||
material.BIMStyleProperties.uv_mode = "Generated"
|
||||
bpy.ops.bim.update_style_colours()
|
||||
# TODO: IfcSurfaceStyleRendering is unnecessary here, added it only because
|
||||
# we don't support IfcSurfaceStyleWithTextures without Rendering yet
|
||||
shading_attributes = {
|
||||
"SurfaceColour": {
|
||||
"Red": 1.0,
|
||||
"Green": 1.0,
|
||||
"Blue": 1.0,
|
||||
},
|
||||
"Transparency": 0.0,
|
||||
"ReflectanceMethod": "NOTDEFINED",
|
||||
}
|
||||
ifcopenshell.api.run(
|
||||
"style.add_surface_style",
|
||||
tool.Ifc.get(),
|
||||
style=style,
|
||||
ifc_class="IfcSurfaceStyleRendering",
|
||||
attributes=shading_attributes,
|
||||
)
|
||||
texture = ifc_file.create_entity("IfcImageTexture", Mode="DIFFUSE", URLReference=image_filepath.as_posix())
|
||||
textures = [texture]
|
||||
ifc_file.create_entity("IfcTextureCoordinateGenerator", Maps=textures, Mode="COORD") # UV map
|
||||
tool.Ifc.run(
|
||||
"style.add_surface_style",
|
||||
style=style,
|
||||
ifc_class="IfcSurfaceStyleWithTextures",
|
||||
attributes={"Textures": textures},
|
||||
)
|
||||
tool.Style.reload_material_from_ifc(material)
|
||||
tool.Geometry.record_object_materials(obj)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
|
||||
import svgwrite
|
||||
import openpyxl
|
||||
|
||||
from odf.opendocument import load as load_ods
|
||||
from odf.table import Table, TableRow, TableColumn, TableCell
|
||||
@@ -62,6 +63,156 @@ class Scheduler:
|
||||
)
|
||||
self.padding = 1
|
||||
self.margin = 1
|
||||
if infile.endswith("ods"):
|
||||
self.schedule_ods(infile, outfile)
|
||||
elif infile.endswith("xlsx"):
|
||||
self.schedule_xlsx(infile, outfile)
|
||||
|
||||
def schedule_xlsx(self, infile, outfile):
|
||||
workbook = openpyxl.open(infile, data_only=True)
|
||||
sheet = workbook.active
|
||||
|
||||
column_dimensions = {k: v.width for k, v in sheet.column_dimensions.items()}
|
||||
row_dimensions = {k: v.height for k, v in sheet.row_dimensions.items()}
|
||||
default_width = 8.43 # 8.43 characters wide
|
||||
default_height = 15 # 15pt seems to be the default height
|
||||
|
||||
merged_cells = []
|
||||
for cell_range in sheet.merged_cells.ranges:
|
||||
pass
|
||||
|
||||
y = self.margin
|
||||
rows = list(sheet.iter_rows())
|
||||
total_rows = len(rows)
|
||||
for i, row in enumerate(rows):
|
||||
# The last row may contain only null values
|
||||
if i == (total_rows - 1) and not [c for c in row if c.value is not None]:
|
||||
continue
|
||||
|
||||
x = self.margin
|
||||
for cell in row:
|
||||
if isinstance(cell, openpyxl.cell.cell.MergedCell):
|
||||
column_letter = openpyxl.utils.get_column_letter(cell.column)
|
||||
width = column_dimensions.get(column_letter, default_width)
|
||||
else:
|
||||
width = column_dimensions.get(cell.column_letter, default_width)
|
||||
width = self.convert_character_width_to_mm(width)
|
||||
height = row_dimensions.get(cell.row, default_height)
|
||||
height = self.convert_to_mm(f"{height}pt")
|
||||
|
||||
if isinstance(cell, openpyxl.cell.cell.MergedCell):
|
||||
x += width
|
||||
continue
|
||||
|
||||
unmerged_width = width
|
||||
unmerged_height = height
|
||||
|
||||
for cell_range in sheet.merged_cells.ranges:
|
||||
if cell.coordinate not in cell_range:
|
||||
continue
|
||||
merged_width = 0
|
||||
merged_height = 0
|
||||
for merged_column in cell_range.cols:
|
||||
merged_cell = sheet.cell(*merged_column[0])
|
||||
column_letter = openpyxl.utils.get_column_letter(merged_cell.column)
|
||||
width = column_dimensions.get(cell.column_letter, default_width)
|
||||
width = self.convert_character_width_to_mm(width)
|
||||
merged_width += width
|
||||
for merged_row in cell_range.rows:
|
||||
merged_cell = sheet.cell(*merged_row[0])
|
||||
height = row_dimensions.get(merged_cell.row, default_height)
|
||||
height = self.convert_to_mm(f"{height}pt")
|
||||
merged_height += height
|
||||
width = merged_width
|
||||
height = merged_height
|
||||
break
|
||||
|
||||
if cell.fill.patternType:
|
||||
background_color = "#" + str(cell.fill.bgColor.rgb).lower()[2:]
|
||||
else:
|
||||
background_color = "#ffffff"
|
||||
|
||||
self.svg.add(
|
||||
self.svg.rect(
|
||||
insert=(x, y),
|
||||
size=(width, height),
|
||||
style=f"fill: {background_color}; stroke-width:.125; stroke: #000000;",
|
||||
)
|
||||
)
|
||||
|
||||
if not cell.value:
|
||||
x += unmerged_width
|
||||
continue
|
||||
|
||||
font_size = cell.font.size or 11 # 11pt default
|
||||
font_size = font_size / FONT_SIZE_PT * FONT_SIZE # Magic?
|
||||
|
||||
text_position = [0.0, 0.0]
|
||||
if cell.alignment.horizontal == "left":
|
||||
text_position[0] = x + self.padding
|
||||
horizontal_align = "left"
|
||||
elif cell.alignment.horizontal == "general" and isinstance(cell.value, str):
|
||||
text_position[0] = x + self.padding
|
||||
horizontal_align = "left"
|
||||
elif cell.alignment.horizontal in ("center", "justify", "centerContinuous", "distributed"):
|
||||
text_position[0] = x + width / 2
|
||||
horizontal_align = "middle"
|
||||
elif cell.alignment.horizontal == "right":
|
||||
text_position[0] = x + width - self.padding
|
||||
horizontal_align = "right"
|
||||
elif cell.alignment.horizontal == "general" and not isinstance(cell.value, str):
|
||||
text_position[0] = x + width - self.padding
|
||||
horizontal_align = "right"
|
||||
else:
|
||||
text_position[0] = x + self.padding
|
||||
horizontal_align = "left"
|
||||
|
||||
if cell.alignment.vertical == "top":
|
||||
text_position[1] = y + self.padding
|
||||
vertical_align = "top"
|
||||
elif cell.alignment.vertical in ("center", "justify", "distributed"):
|
||||
text_position[1] = y + height / 2
|
||||
vertical_align = "middle"
|
||||
elif cell.alignment.vertical == "bottom":
|
||||
text_position[1] = y + height - self.padding
|
||||
vertical_align = "bottom"
|
||||
else:
|
||||
text_position[1] = y + height - self.padding
|
||||
vertical_align = "bottom"
|
||||
|
||||
if vertical_align == "middle" and horizontal_align == "middle":
|
||||
box_alignment = "center"
|
||||
else:
|
||||
box_alignment = f"{vertical_align}-{horizontal_align}"
|
||||
|
||||
if cell.font.color:
|
||||
text_color = "#" + str(cell.font.color.rgb).lower()[2:]
|
||||
else:
|
||||
text_color = "#000000"
|
||||
|
||||
self.add_text(
|
||||
[cell.value],
|
||||
*text_position,
|
||||
font_size=font_size,
|
||||
box_alignment=box_alignment,
|
||||
wrap_text=cell.alignment.wrapText or False,
|
||||
cell_width=width,
|
||||
bold=cell.font.b,
|
||||
italic=cell.font.i,
|
||||
text_color=text_color,
|
||||
)
|
||||
|
||||
x += unmerged_width
|
||||
y += unmerged_height
|
||||
|
||||
total_width = x + self.margin
|
||||
total_height = y + self.margin
|
||||
self.svg["width"] = "{}mm".format(total_width)
|
||||
self.svg["height"] = "{}mm".format(total_height)
|
||||
self.svg["viewBox"] = "0 0 {} {}".format(total_width, total_height)
|
||||
self.svg.save(pretty=True)
|
||||
|
||||
def schedule_ods(self, infile, outfile):
|
||||
doc = load_ods(infile)
|
||||
|
||||
# useful for debugging ods
|
||||
@@ -386,6 +537,10 @@ class Scheduler:
|
||||
if len(text_lines) == 1 and not wrap_text:
|
||||
text_params.update(box_alignment_params)
|
||||
text_tag = self.svg.text(text_lines[0], insert=(x, y), **(text_params))
|
||||
if self.is_url(text_lines[0]):
|
||||
anchor = self.svg.a(text_lines[0].strip())
|
||||
anchor.add(text_tag)
|
||||
text_tag = anchor
|
||||
self.svg.add(text_tag)
|
||||
return
|
||||
|
||||
@@ -420,11 +575,26 @@ class Scheduler:
|
||||
tspan = self.svg.tspan(text_line, insert=(x, y), **text_params)
|
||||
# doing it here and not in tspan constructor because constructor adds unnecessary spaces
|
||||
tspan.update({"dy": f"{line_number}em"})
|
||||
if self.is_url(text_line):
|
||||
anchor = self.svg.a(text_line.strip())
|
||||
anchor.add(tspan)
|
||||
tspan = anchor
|
||||
text_tag.add(tspan)
|
||||
line_number += dy_dir
|
||||
|
||||
self.svg.add(text_tag)
|
||||
|
||||
def is_url(self, value):
|
||||
return value.strip().startswith("http") and " " not in value.strip() and "://" in value # Wrong but fast
|
||||
|
||||
def convert_character_width_to_mm(self, value):
|
||||
# Excel measures widths in terms of "number of characters of the
|
||||
# default font", which is most commonly 11pt Calibri. The width of the
|
||||
# "0" character in Calibri is approximately 7px at 100% zoom.
|
||||
px_per_character = 7
|
||||
px_to_pt = 0.75
|
||||
return self.convert_to_mm(f"{value * px_per_character * px_to_pt}pt")
|
||||
|
||||
def convert_to_mm(self, value):
|
||||
# XSL is what defines the units of measurements in ODF
|
||||
# https://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#datatype-positiveLength
|
||||
|
||||
@@ -187,11 +187,11 @@ class SheetBuilder:
|
||||
|
||||
layout_tree.write(layout_path)
|
||||
|
||||
def add_document(self, reference, schedule, sheet):
|
||||
view_path = tool.Drawing.get_path_with_ext(tool.Drawing.get_document_uri(schedule), "svg")
|
||||
def add_document(self, reference, document, sheet):
|
||||
view_path = tool.Drawing.get_path_with_ext(tool.Drawing.get_document_uri(document), "svg")
|
||||
if not os.path.exists(view_path):
|
||||
tool.Drawing.create_svg_schedule(schedule)
|
||||
schedule_name = os.path.splitext(os.path.basename(view_path))[0]
|
||||
tool.Drawing.create_svg_document(document)
|
||||
document_name = os.path.splitext(os.path.basename(view_path))[0]
|
||||
layout_path = tool.Drawing.get_document_uri(sheet, "LAYOUT")
|
||||
layout_dir = os.path.dirname(layout_path)
|
||||
|
||||
@@ -207,12 +207,12 @@ class SheetBuilder:
|
||||
view_height = self.convert_to_mm(view_root.attrib.get("height"))
|
||||
|
||||
view = ET.SubElement(layout_root, "g")
|
||||
view.attrib["data-type"] = "schedule"
|
||||
view.attrib["data-id"] = str(reference.id())
|
||||
view.attrib["data-schedule"] = str(schedule.id())
|
||||
view.attrib["data-type"] = document.Scope.lower()
|
||||
view.attrib["data-document"] = str(document.id())
|
||||
|
||||
foreground = ET.SubElement(view, "image")
|
||||
foreground.attrib["data-type"] = "table"
|
||||
foreground.attrib["data-type"] = "content"
|
||||
foreground.attrib["xlink:href"] = os.path.relpath(view_path, layout_dir)
|
||||
foreground.attrib["x"] = str(DEFAULT_POSITION.x)
|
||||
foreground.attrib["y"] = str(DEFAULT_POSITION.y)
|
||||
@@ -263,7 +263,7 @@ class SheetBuilder:
|
||||
|
||||
self.build_titleblock(root, sheet)
|
||||
self.build_drawings(root, sheet)
|
||||
self.build_schedules(root, sheet)
|
||||
self.build_documents(root, sheet)
|
||||
|
||||
with open(sheet_path, "wb") as output:
|
||||
tree.write(output)
|
||||
@@ -390,11 +390,14 @@ class SheetBuilder:
|
||||
for image in images:
|
||||
view.remove(image)
|
||||
|
||||
def build_schedules(self, root, sheet):
|
||||
for view in root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]'):
|
||||
def build_documents(self, root, sheet):
|
||||
schedules = root.findall('{http://www.w3.org/2000/svg}g[@data-type="schedule"]')
|
||||
references = root.findall('{http://www.w3.org/2000/svg}g[@data-type="reference"]')
|
||||
documents = schedules + references
|
||||
for view in documents:
|
||||
try:
|
||||
reference = tool.Ifc.get().by_id(int(view.attrib["data-id"]))
|
||||
schedule = tool.Ifc.get().by_id(int(view.attrib["data-schedule"]))
|
||||
document = tool.Ifc.get().by_id(int(view.attrib["data-document"]))
|
||||
except:
|
||||
# Perhaps the SVG has outdated content or is edited externally which we cannot control.
|
||||
continue
|
||||
@@ -405,7 +408,7 @@ class SheetBuilder:
|
||||
view_title = None
|
||||
|
||||
for image in images:
|
||||
if image.attrib["data-type"] == "table":
|
||||
if image.attrib["data-type"] == "content":
|
||||
table = image
|
||||
elif image.attrib["data-type"] == "view-title":
|
||||
view_title = image
|
||||
@@ -418,7 +421,7 @@ class SheetBuilder:
|
||||
data = reference.get_info()
|
||||
data.update({"Sheet" + k: v for k, v in sheet.get_info().items()})
|
||||
if not data["Name"]:
|
||||
data["Name"] = schedule.Name or "Unnamed"
|
||||
data["Name"] = document.Name or "Unnamed"
|
||||
view.append(self.parse_embedded_svg(view_title, data))
|
||||
|
||||
for image in images:
|
||||
|
||||
@@ -27,10 +27,10 @@ classes = (
|
||||
operator.EnableEditingRepresentationItems,
|
||||
operator.FlipObject,
|
||||
operator.GetRepresentationIfcParameters,
|
||||
operator.DuplicateMoveLinkedAggregate,
|
||||
operator.DuplicateMoveLinkedAggregateMacro,
|
||||
operator.OverrideDelete,
|
||||
operator.OverrideDuplicateMove,
|
||||
operator.OverrideDuplicateMoveAggregate,
|
||||
operator.OverrideDuplicateMoveAggregateMacro,
|
||||
operator.OverrideDuplicateMoveLinked,
|
||||
operator.OverrideDuplicateMoveLinkedMacro,
|
||||
operator.OverrideDuplicateMoveMacro,
|
||||
@@ -42,14 +42,24 @@ classes = (
|
||||
operator.OverrideOutlinerDelete,
|
||||
operator.OverridePasteBuffer,
|
||||
operator.PurgeUnusedRepresentations,
|
||||
operator.RefreshAggregate,
|
||||
operator.RefreshLinkedAggregate,
|
||||
operator.RemoveConnection,
|
||||
operator.RemoveRepresentation,
|
||||
operator.SelectConnection,
|
||||
operator.SwitchRepresentation,
|
||||
operator.UpdateParametricRepresentation,
|
||||
operator.UpdateRepresentation,
|
||||
operator.RemoveRepresentationItem,
|
||||
operator.EnableEditingRepresentationItemStyle,
|
||||
operator.EditRepresentationItemStyle,
|
||||
operator.DisableEditingRepresentationItemStyle,
|
||||
operator.UnassignRepresentationItemStyle,
|
||||
operator.EnableEditingRepresentationItemShapeAspect,
|
||||
operator.EditRepresentationItemShapeAspect,
|
||||
operator.DisableEditingRepresentationItemShapeAspect,
|
||||
operator.RemoveRepresentationItemFromShapeAspect,
|
||||
prop.RepresentationItem,
|
||||
prop.ShapeAspect,
|
||||
prop.BIMObjectGeometryProperties,
|
||||
prop.BIMGeometryProperties,
|
||||
ui.BIM_PT_placement,
|
||||
@@ -74,8 +84,8 @@ def register():
|
||||
operator.OverrideDuplicateMoveMacro.define("TRANSFORM_OT_translate")
|
||||
operator.OverrideDuplicateMoveLinkedMacro.define("BIM_OT_override_object_duplicate_move_linked")
|
||||
operator.OverrideDuplicateMoveLinkedMacro.define("TRANSFORM_OT_translate")
|
||||
operator.OverrideDuplicateMoveAggregateMacro.define("BIM_OT_override_object_duplicate_move_aggregate")
|
||||
operator.OverrideDuplicateMoveAggregateMacro.define("TRANSFORM_OT_translate")
|
||||
operator.DuplicateMoveLinkedAggregateMacro.define("BIM_OT_object_duplicate_move_linked_aggregate")
|
||||
operator.DuplicateMoveLinkedAggregateMacro.define("TRANSFORM_OT_translate")
|
||||
|
||||
bpy.types.Object.BIMGeometryProperties = bpy.props.PointerProperty(type=prop.BIMObjectGeometryProperties)
|
||||
bpy.types.Scene.BIMGeometryProperties = bpy.props.PointerProperty(type=prop.BIMGeometryProperties)
|
||||
@@ -83,6 +93,7 @@ def register():
|
||||
bpy.types.OUTLINER_MT_object.append(ui.outliner_menu)
|
||||
bpy.types.VIEW3D_MT_object_context_menu.append(ui.object_menu)
|
||||
bpy.types.VIEW3D_MT_edit_mesh.append(ui.edit_mesh_menu)
|
||||
bpy.types.VIEW3D_HT_header.append(ui.mode_menu)
|
||||
wm = bpy.context.window_manager
|
||||
if wm.keyconfigs.addon:
|
||||
km = wm.keyconfigs.addon.keymaps.new(name="Object Mode", space_type="EMPTY")
|
||||
@@ -93,7 +104,7 @@ def register():
|
||||
kmi = km.keymap_items.new("bim.override_object_duplicate_move_linked_macro", "D", "PRESS", alt=True)
|
||||
addon_keymaps.append((km, kmi))
|
||||
kmi = km.keymap_items.new(
|
||||
"bim.override_object_duplicate_move_aggregate_macro", "D", "PRESS", ctrl=True, shift=True
|
||||
"bim.object_duplicate_move_linked_aggregate_macro", "D", "PRESS", ctrl=True, shift=True
|
||||
)
|
||||
addon_keymaps.append((km, kmi))
|
||||
kmi = km.keymap_items.new("bim.override_paste_buffer", "V", "PRESS", ctrl=True)
|
||||
@@ -131,6 +142,7 @@ def unregister():
|
||||
bpy.types.OUTLINER_MT_object.remove(ui.outliner_menu)
|
||||
bpy.types.VIEW3D_MT_object_context_menu.remove(ui.outliner_menu)
|
||||
bpy.types.VIEW3D_MT_edit_mesh.remove(ui.edit_mesh_menu)
|
||||
bpy.types.VIEW3D_HT_header.remove(ui.mode_menu)
|
||||
del bpy.types.Scene.BIMGeometryProperties
|
||||
del bpy.types.Object.BIMGeometryProperties
|
||||
wm = bpy.context.window_manager
|
||||
|
||||
@@ -38,6 +38,7 @@ class RepresentationsData:
|
||||
def load(cls):
|
||||
cls.data = {"representations": cls.representations()}
|
||||
cls.data["contexts"] = cls.contexts()
|
||||
cls.data["shape_aspects"] = cls.shape_aspects()
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
@@ -92,6 +93,24 @@ class RepresentationsData:
|
||||
)
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def shape_aspects(cls):
|
||||
obj = bpy.context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
active_representation_id = obj.data.BIMMeshProperties.ifc_definition_id
|
||||
base_representation = tool.Ifc.get().by_id(active_representation_id)
|
||||
|
||||
# shape aspects matching context of the active representation
|
||||
matching_shape_aspects = []
|
||||
for shape_aspect in tool.Geometry.get_shape_aspects(element):
|
||||
matching_representation = tool.Geometry.get_shape_aspect_representation(shape_aspect, base_representation)
|
||||
if matching_representation:
|
||||
matching_shape_aspects.append(shape_aspect)
|
||||
|
||||
# blender enum items
|
||||
new_shape_aspect = [("NEW", "Create A New Shape Aspect", "")]
|
||||
return new_shape_aspect + [(str(s.id()), s.Name or "Unnamed", "") for s in matching_shape_aspects]
|
||||
|
||||
|
||||
class RepresentationItemsData:
|
||||
data = {}
|
||||
|
||||
@@ -759,13 +759,23 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
|
||||
self.new_active_obj = None
|
||||
# Track decompositions so they can be recreated after the operation
|
||||
relationships = tool.Root.get_decomposition_relationships(objects_to_duplicate)
|
||||
decomposition_relationships = tool.Root.get_decomposition_relationships(objects_to_duplicate)
|
||||
connection_relationships = tool.Root.get_connection_relationships(objects_to_duplicate)
|
||||
old_to_new = {}
|
||||
|
||||
for obj in objects_to_duplicate:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if element and element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
continue # For now, don't copy drawings until we stabilise a bit more. It's tricky.
|
||||
if element:
|
||||
if element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
self.report(
|
||||
{"INFO"}, "Did not duplicate. Duplicate drawings through the Drawings and Documents UI."
|
||||
)
|
||||
obj.select_set(False)
|
||||
continue # For now, don't copy drawings until we stabilise a bit more. It's tricky.
|
||||
elif element.is_a("IfcProject"):
|
||||
self.report({"INFO"}, "Did not duplicate. IFC can only have one project.")
|
||||
obj.select_set(False)
|
||||
continue # Only one IfcProject is allowed.
|
||||
|
||||
linked_non_ifc_object = linked and not element
|
||||
|
||||
@@ -819,9 +829,19 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
if new.is_a("IfcRelSpaceBoundary"):
|
||||
tool.Boundary.decorate_boundary(new_obj)
|
||||
|
||||
# Recreate aggregate relationship
|
||||
for old in old_to_new.keys():
|
||||
if old.is_a("IfcElementAssembly"):
|
||||
tool.Root.recreate_aggregate(old_to_new)
|
||||
|
||||
# Remove connections with old objects and recreates paths
|
||||
OverrideDuplicateMove.remove_old_connections(old_to_new)
|
||||
tool.Root.recreate_connections(connection_relationships, old_to_new)
|
||||
|
||||
# Recreate decompositions
|
||||
tool.Root.recreate_decompositions(relationships, old_to_new)
|
||||
tool.Root.recreate_decompositions(decomposition_relationships, old_to_new)
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return old_to_new
|
||||
|
||||
@staticmethod
|
||||
def process_arrays(self, context):
|
||||
@@ -859,6 +879,19 @@ class OverrideDuplicateMove(bpy.types.Operator):
|
||||
|
||||
return arrays_to_create, array_children
|
||||
|
||||
def remove_old_connections(old_to_new):
|
||||
for new in old_to_new.values():
|
||||
if not hasattr(new[0], "ConnectedTo"):
|
||||
continue
|
||||
for connection in new[0].ConnectedTo:
|
||||
entity = connection.RelatedElement
|
||||
if entity in old_to_new.keys():
|
||||
core.remove_connection(tool.Geometry, connection=connection)
|
||||
for connection in new[0].ConnectedFrom:
|
||||
entity = connection.RelatingElement
|
||||
if entity in old_to_new.keys():
|
||||
core.remove_connection(tool.Geometry, connection=connection)
|
||||
|
||||
|
||||
class OverrideDuplicateMoveLinkedMacro(bpy.types.Macro):
|
||||
bl_idname = "bim.override_object_duplicate_move_linked_macro"
|
||||
@@ -882,15 +915,15 @@ class OverrideDuplicateMoveLinked(bpy.types.Operator):
|
||||
return OverrideDuplicateMove.execute_ifc_duplicate_operator(self, context, linked=True)
|
||||
|
||||
|
||||
class OverrideDuplicateMoveAggregateMacro(bpy.types.Macro):
|
||||
bl_idname = "bim.override_object_duplicate_move_aggregate_macro"
|
||||
bl_label = "IFC Duplicate Objects Aggregate"
|
||||
class DuplicateMoveLinkedAggregateMacro(bpy.types.Macro):
|
||||
bl_idname = "bim.object_duplicate_move_linked_aggregate_macro"
|
||||
bl_label = "IFC Duplicate Linked Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
|
||||
class OverrideDuplicateMoveAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.override_object_duplicate_move_aggregate"
|
||||
bl_label = "IFC Duplicate Objects Aggregate"
|
||||
class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.object_duplicate_move_linked_aggregate"
|
||||
bl_label = "IFC Duplicate Linked Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
is_interactive: bpy.props.BoolProperty(name="Is Interactive", default=True)
|
||||
|
||||
@@ -902,263 +935,95 @@ class OverrideDuplicateMoveAggregate(bpy.types.Operator):
|
||||
return OverrideDuplicateMove.execute_duplicate_operator(self, context, linked=False)
|
||||
|
||||
def _execute(self, context):
|
||||
return DuplicateMoveLinkedAggregate.execute_ifc_duplicate_linked_aggregate_operator(self, context)
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_duplicate_linked_aggregate_operator(self, context):
|
||||
self.new_active_obj = None
|
||||
self.group_name = "BBIM_Linked_Aggregate"
|
||||
self.pset_name = "BBIM_Linked_Aggregate"
|
||||
old_to_new = {}
|
||||
|
||||
### Adding the assembly data
|
||||
def add_assembly_data(element, parent, data_to_add):
|
||||
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Aggregate_Data")
|
||||
data = [data_to_add]
|
||||
def select_objects_and_add_data(element):
|
||||
add_linked_aggregate_group(element)
|
||||
obj = tool.Ifc.get_object(element)
|
||||
obj.select_set(True)
|
||||
parts = ifcopenshell.util.element.get_parts(element)
|
||||
if parts:
|
||||
index = 0
|
||||
for part in parts:
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
select_objects_and_add_data(part)
|
||||
|
||||
if pset:
|
||||
if parent == None:
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
tool.Ifc.get(),
|
||||
pset=tool.Ifc.get().by_id(pset["id"]),
|
||||
properties={"Data": tool.Ifc.get().createIfcText(json.dumps(data))},
|
||||
)
|
||||
else:
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
tool.Ifc.get(),
|
||||
pset=tool.Ifc.get().by_id(pset["id"]),
|
||||
properties={"Parent": parent.GlobalId, "Data": tool.Ifc.get().createIfcText(json.dumps(data))},
|
||||
)
|
||||
add_linked_aggregate_pset(part, index)
|
||||
index += 1
|
||||
|
||||
obj = tool.Ifc.get_object(part)
|
||||
obj.select_set(True)
|
||||
|
||||
def add_linked_aggregate_group(element):
|
||||
linked_aggregate_group = None
|
||||
product_groups_name = [
|
||||
r.RelatingGroup.Name
|
||||
for r in getattr(element, "HasAssignments", []) or []
|
||||
if r.is_a("IfcRelAssignsToGroup")
|
||||
]
|
||||
if self.group_name in product_groups_name:
|
||||
return
|
||||
|
||||
linked_aggregate_group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.group_name)
|
||||
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), products=[element], group=linked_aggregate_group)
|
||||
|
||||
def add_linked_aggregate_pset(part, index):
|
||||
pset = ifcopenshell.util.element.get_pset(part, self.pset_name)
|
||||
|
||||
if not pset:
|
||||
pset = ifcopenshell.api.run("pset.add_pset", tool.Ifc.get(), product=part, name=self.pset_name)
|
||||
else:
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_pset", tool.Ifc.get(), product=element, name="BBIM_Aggregate_Data"
|
||||
)
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
tool.Ifc.get(),
|
||||
pset=pset,
|
||||
properties={"Parent": parent.GlobalId, "Data": tool.Ifc.get().createIfcText(json.dumps(data))},
|
||||
)
|
||||
|
||||
def add_child_to_assembly_data(new_entity):
|
||||
pset = ifcopenshell.util.element.get_pset(new_entity, "BBIM_Aggregate_Data")
|
||||
parent_element = tool.Ifc.get().by_guid(pset["Parent"])
|
||||
parent_pset = ifcopenshell.util.element.get_pset(parent_element, "BBIM_Aggregate_Data")
|
||||
data = json.loads(parent_pset["Data"])
|
||||
data[0]["children"].append(new_entity.GlobalId)
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
tool.Ifc.get(),
|
||||
pset=tool.Ifc.get().by_id(parent_pset["id"]),
|
||||
properties={"Data": tool.Ifc.get().createIfcText(json.dumps(data))},
|
||||
pset=pset,
|
||||
properties={"Index": index},
|
||||
)
|
||||
|
||||
def create_data_structure(entity, level=-1):
|
||||
level += 1
|
||||
return index
|
||||
|
||||
data_children = {
|
||||
"children": [],
|
||||
"instance_of": [],
|
||||
}
|
||||
|
||||
data_parent = {
|
||||
"children": [],
|
||||
"instance_of": [entity.GlobalId],
|
||||
}
|
||||
|
||||
if not entity.is_a("IfcElementAssembly"):
|
||||
return
|
||||
else:
|
||||
if level == 0:
|
||||
add_assembly_data(entity, entity, data_parent)
|
||||
else:
|
||||
add_assembly_data(entity, None, data_parent)
|
||||
parts = ifcopenshell.util.element.get_parts(entity)
|
||||
for part in parts:
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
add_assembly_data(part, entity, data_children)
|
||||
add_child_to_assembly_data(part)
|
||||
create_data_structure(part, level)
|
||||
continue
|
||||
add_assembly_data(part, entity, data_children)
|
||||
add_child_to_assembly_data(part)
|
||||
|
||||
return
|
||||
|
||||
def recreate_data_structure(entity, level=-1):
|
||||
level += 1
|
||||
|
||||
pset = ifcopenshell.util.element.get_pset(entity, "BBIM_Aggregate_Data")
|
||||
pset_data = json.loads(pset["Data"])[0]
|
||||
instance_of = pset_data["instance_of"]
|
||||
|
||||
data_children = {
|
||||
"children": [],
|
||||
"instance_of": [],
|
||||
}
|
||||
|
||||
# Keeps instance ID through all copies
|
||||
data_parent = {
|
||||
"children": [],
|
||||
"instance_of": instance_of,
|
||||
}
|
||||
|
||||
if not entity.is_a("IfcElementAssembly"):
|
||||
return
|
||||
else:
|
||||
if level == 0:
|
||||
add_assembly_data(entity, entity, data_parent)
|
||||
else:
|
||||
add_assembly_data(entity, None, data_parent)
|
||||
parts = ifcopenshell.util.element.get_parts(entity)
|
||||
for part in parts:
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
add_child_to_assembly_data(part)
|
||||
recreate_data_structure(part, level)
|
||||
continue
|
||||
add_assembly_data(part, entity, data_children)
|
||||
add_child_to_assembly_data(part)
|
||||
|
||||
return
|
||||
|
||||
def duplicate_all(obj, level=-1, new_parent=None, parents=[]):
|
||||
level += 1
|
||||
|
||||
entity = tool.Ifc.get_entity(obj)
|
||||
|
||||
if level == 0:
|
||||
new_parent = duplicate_objects(obj)
|
||||
parents.append(new_parent)
|
||||
else:
|
||||
pair = []
|
||||
pair.append(new_parent)
|
||||
new_parent = duplicate_objects(obj)
|
||||
pair.append(new_parent)
|
||||
parents.append(pair)
|
||||
|
||||
if not entity.is_a("IfcElementAssembly"):
|
||||
return
|
||||
else:
|
||||
parts = ifcopenshell.util.element.get_parts(entity)
|
||||
|
||||
# Ensures that we are duplication all the IfcElementAssembly
|
||||
# before duplicating the nested objects
|
||||
for part in parts:
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
pass
|
||||
else:
|
||||
part_obj = tool.Ifc.get_object(part)
|
||||
new_part = duplicate_objects(part_obj)
|
||||
blenderbim.core.aggregate.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(new_parent),
|
||||
related_obj=tool.Ifc.get_object(new_part),
|
||||
)
|
||||
|
||||
for part in parts:
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
part_obj = tool.Ifc.get_object(part)
|
||||
|
||||
# Recursion Call
|
||||
duplicate_all(part_obj, level, new_parent, parents)
|
||||
|
||||
if level == 0:
|
||||
for p in parents[1:]:
|
||||
blenderbim.core.aggregate.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(p[0]),
|
||||
related_obj=tool.Ifc.get_object(p[1]),
|
||||
)
|
||||
|
||||
return new_parent
|
||||
return
|
||||
|
||||
def duplicate_objects(obj, is_root=False):
|
||||
new_obj = obj.copy()
|
||||
if obj.data:
|
||||
new_obj.data = obj.data.copy()
|
||||
if obj == context.active_object:
|
||||
self.new_active_obj = new_obj
|
||||
for collection in obj.users_collection:
|
||||
collection.objects.link(new_obj)
|
||||
obj.select_set(False)
|
||||
new_obj.select_set(True)
|
||||
|
||||
# This is needed to make sure the new object gets unlink from
|
||||
# the old object assembly collection
|
||||
new_obj.BIMObjectProperties.collection = None
|
||||
|
||||
# Copy the actual class
|
||||
new_entity = blenderbim.core.root.copy_class(
|
||||
tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new_obj
|
||||
)
|
||||
|
||||
if new_entity:
|
||||
tool.Model.handle_array_on_copied_element(new_entity)
|
||||
blenderbim.core.aggregate.unassign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(selected_root_entity),
|
||||
related_obj=tool.Ifc.get_object(new_entity),
|
||||
)
|
||||
|
||||
old_to_new[tool.Ifc.get_entity(obj)] = [new_entity]
|
||||
|
||||
return new_entity
|
||||
|
||||
### Check if only one element and it's assembly
|
||||
if len(context.selected_objects) != 1:
|
||||
return {"FINISHED"}
|
||||
|
||||
selected_obj = context.selected_objects[0]
|
||||
selected_root_entity = tool.Ifc.get_entity(selected_obj)
|
||||
selected_element = tool.Ifc.get_entity(selected_obj)
|
||||
|
||||
if not selected_root_entity.is_a("IfcElementAssembly"):
|
||||
if selected_element.is_a("IfcElementAssembly"):
|
||||
pass
|
||||
elif selected_element.Decomposes:
|
||||
if selected_element.Decomposes[0].RelatingObject.is_a("IfcElementAssembly"):
|
||||
selected_element = selected_element.Decomposes[0].RelatingObject
|
||||
selected_obj = tool.Ifc.get_object(selected_element)
|
||||
else:
|
||||
self.report({"INFO"}, "Object is not part of a IfcElementAssembly.")
|
||||
return {"FINISHED"}
|
||||
|
||||
pset = ifcopenshell.util.element.get_pset(selected_root_entity, "BBIM_Aggregate_Data")
|
||||
if not pset:
|
||||
create_data_structure(selected_root_entity)
|
||||
select_objects_and_add_data(selected_element)
|
||||
|
||||
pset = ifcopenshell.util.element.get_pset(selected_root_entity, "BBIM_Aggregate_Data")
|
||||
old_to_new = OverrideDuplicateMove.execute_ifc_duplicate_operator(self, context, linked=True)
|
||||
|
||||
selected_root_parent = selected_root_entity
|
||||
|
||||
new_root_entity = duplicate_all(selected_obj)
|
||||
|
||||
recreate_data_structure(new_root_entity)
|
||||
|
||||
# Remove connections with old objects
|
||||
for new in old_to_new.values():
|
||||
for connection in new[0].ConnectedTo:
|
||||
entity = connection.RelatedElement
|
||||
if entity in old_to_new.keys():
|
||||
core.remove_connection(tool.Geometry, connection=connection)
|
||||
for connection in new[0].ConnectedFrom:
|
||||
entity = connection.RelatingElement
|
||||
if entity in old_to_new.keys():
|
||||
core.remove_connection(tool.Geometry, connection=connection)
|
||||
|
||||
old_objs = []
|
||||
for old, new in old_to_new.items():
|
||||
old_objs.append(tool.Ifc.get_object(old))
|
||||
|
||||
relationships = tool.Root.get_decomposition_relationships(old_objs)
|
||||
|
||||
tool.Root.recreate_decompositions(relationships, old_to_new)
|
||||
# Recreate aggregate relationship
|
||||
for old in old_to_new.keys():
|
||||
if old.is_a("IfcElementAssembly"):
|
||||
tool.Root.recreate_aggregate(old_to_new)
|
||||
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
|
||||
return {"FINISHED"}
|
||||
return old_to_new
|
||||
|
||||
|
||||
class RefreshAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.refresh_aggregate"
|
||||
bl_label = "IFC Refresh Aggregate"
|
||||
class RefreshLinkedAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.refresh_linked_aggregate"
|
||||
bl_label = "IFC Refresh Linked Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
@@ -1174,213 +1039,134 @@ class RefreshAggregate(bpy.types.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
def _execute(self, context):
|
||||
refresh_start_time = time()
|
||||
self.new_active_obj = None
|
||||
self.group_name = "BBIM_Linked_Aggregate"
|
||||
self.pset_name = "BBIM_Linked_Aggregate"
|
||||
refresh_start_time = time()
|
||||
old_to_new = {}
|
||||
|
||||
def remove_objects(entity, level=-1, parents=[]):
|
||||
level += 1
|
||||
if level == 0:
|
||||
parents = [entity]
|
||||
parts = ifcopenshell.util.element.get_parts(entity)
|
||||
for part in parts:
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
parents.append(part)
|
||||
remove_objects(part, level, parents)
|
||||
continue
|
||||
else:
|
||||
part_obj = tool.Ifc.get_object(part)
|
||||
if part_obj:
|
||||
tool.Geometry.delete_ifc_object(part_obj)
|
||||
|
||||
return parents
|
||||
|
||||
def duplicate_children(entity):
|
||||
pset = ifcopenshell.util.element.get_pset(entity, "BBIM_Aggregate_Data")
|
||||
pset_data = json.loads(pset["Data"])[0]
|
||||
instance_of = pset_data["instance_of"][0]
|
||||
|
||||
instance_entity = tool.Ifc.get().by_guid(instance_of)
|
||||
|
||||
if not instance_entity.is_a("IfcElementAssembly"):
|
||||
return
|
||||
else:
|
||||
parts = ifcopenshell.util.element.get_parts(instance_entity)
|
||||
def delete_objects(element):
|
||||
parts = ifcopenshell.util.element.get_parts(element)
|
||||
if parts:
|
||||
for part in parts:
|
||||
pset = ifcopenshell.util.element.get_pset(part, "BBIM_Aggregate_Data")
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
if not pset:
|
||||
data_children = {
|
||||
"children": [],
|
||||
"instance_of": [part.GlobalId],
|
||||
}
|
||||
data = [data_children]
|
||||
delete_objects(part)
|
||||
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_pset", tool.Ifc.get(), product=part, name="BBIM_Aggregate_Data"
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
tool.Ifc.get(),
|
||||
pset=pset,
|
||||
properties={
|
||||
"Parent": instance_entity.GlobalId,
|
||||
"Data": tool.Ifc.get().createIfcText(json.dumps(data)),
|
||||
},
|
||||
)
|
||||
tool.Geometry.delete_ifc_object(tool.Ifc.get_object(part))
|
||||
|
||||
part_obj = tool.Ifc.get_object(part)
|
||||
new_part = duplicate_objects(part_obj)
|
||||
tool.Geometry.delete_ifc_object(tool.Ifc.get_object(element))
|
||||
|
||||
def get_element_assembly(element):
|
||||
if element.is_a("IfcElementAssembly"):
|
||||
return element
|
||||
elif element.Decomposes:
|
||||
if element.Decomposes[0].RelatingObject.is_a("IfcElementAssembly"):
|
||||
element = element.Decomposes[0].RelatingObject
|
||||
return element
|
||||
else:
|
||||
return None
|
||||
|
||||
def handle_selection(selected_objs):
|
||||
selected_elements = [tool.Ifc.get_entity(selected_obj) for selected_obj in selected_objs]
|
||||
if None in selected_elements:
|
||||
self.report({"INFO"}, "Object has no Ifc Metadata.")
|
||||
return None, None
|
||||
|
||||
selected_parents = []
|
||||
for selected_element in selected_elements:
|
||||
selected_element = get_element_assembly(selected_element)
|
||||
if not selected_element:
|
||||
self.report({"INFO"}, "Object is not part of a IfcElementAssembly.")
|
||||
return None, None
|
||||
selected_parents.append(selected_element)
|
||||
|
||||
selected_parents = list(set(selected_parents))
|
||||
linked_aggregate_groups = []
|
||||
for selected_element in selected_parents:
|
||||
product_linked_agg_group = [
|
||||
r.RelatingGroup
|
||||
for r in getattr(selected_element, "HasAssignments", []) or []
|
||||
if r.is_a("IfcRelAssignsToGroup")
|
||||
if self.group_name in r.RelatingGroup.Name
|
||||
]
|
||||
try:
|
||||
linked_aggregate_groups.append(product_linked_agg_group[0].id())
|
||||
except:
|
||||
self.report({"INFO"}, "Object is not part of a Linked Aggregate.")
|
||||
return None, None
|
||||
|
||||
return list(set(linked_aggregate_groups)), selected_parents
|
||||
|
||||
active_element = tool.Ifc.get_entity(context.active_object)
|
||||
if not active_element:
|
||||
self.report({"INFO"}, "Object has no Ifc metadata.")
|
||||
return {"FINISHED"}
|
||||
|
||||
active_element = get_element_assembly(active_element)
|
||||
selected_objs = context.selected_objects
|
||||
linked_aggregate_groups, selected_parents = handle_selection(selected_objs)
|
||||
if not linked_aggregate_groups or not selected_parents:
|
||||
return {"FINISHED"}
|
||||
|
||||
if len(linked_aggregate_groups) > 1:
|
||||
if len(selected_parents) != len(linked_aggregate_groups):
|
||||
self.report(
|
||||
{"INFO"},
|
||||
"Select only one object from each Linked Aggregate or multiple objects from the same Linked Aggregate.",
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
for group in linked_aggregate_groups:
|
||||
elements = tool.Drawing.get_group_elements(tool.Ifc.get().by_id(group))
|
||||
if len(linked_aggregate_groups) > 1:
|
||||
base_instance = [e for e in elements if e in selected_parents][0]
|
||||
instances_to_refresh = elements
|
||||
|
||||
elif (len(linked_aggregate_groups) == 1) and (len(selected_parents) > 1):
|
||||
base_instance = active_element
|
||||
instances_to_refresh = [element for element in elements if element in selected_parents]
|
||||
|
||||
else:
|
||||
base_instance = active_element
|
||||
instances_to_refresh = elements
|
||||
|
||||
for element in instances_to_refresh:
|
||||
if element.GlobalId == base_instance.GlobalId:
|
||||
continue
|
||||
|
||||
element_aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
|
||||
selected_obj = tool.Ifc.get_object(base_instance)
|
||||
selected_matrix = selected_obj.matrix_world
|
||||
object_duplicate = tool.Ifc.get_object(element)
|
||||
duplicate_matrix = object_duplicate.matrix_world.decompose()
|
||||
|
||||
delete_objects(element)
|
||||
|
||||
for obj in context.selected_objects:
|
||||
obj.select_set(False)
|
||||
|
||||
tool.Ifc.get_object(base_instance).select_set(True)
|
||||
|
||||
old_to_new = DuplicateMoveLinkedAggregate.execute_ifc_duplicate_linked_aggregate_operator(self, context)
|
||||
for old, new in old_to_new.items():
|
||||
new_obj = tool.Ifc.get_object(new[0])
|
||||
new_base_matrix = Matrix.LocRotScale(*duplicate_matrix)
|
||||
matrix_diff = Matrix.inverted(selected_matrix) @ new_obj.matrix_world
|
||||
new_obj_matrix = new_base_matrix @ matrix_diff
|
||||
new_obj.matrix_world = new_obj_matrix
|
||||
|
||||
if element_aggregate and new[0].is_a("IfcElementAssembly"):
|
||||
new_aggregate = ifcopenshell.util.element.get_aggregate(new[0])
|
||||
|
||||
if not new_aggregate:
|
||||
blenderbim.core.aggregate.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(entity),
|
||||
related_obj=tool.Ifc.get_object(new_part),
|
||||
relating_obj=tool.Ifc.get_object(element_aggregate),
|
||||
related_obj=tool.Ifc.get_object(new[0]),
|
||||
)
|
||||
duplicate_children(new_part)
|
||||
|
||||
for part in parts:
|
||||
pset = ifcopenshell.util.element.get_pset(part, "BBIM_Aggregate_Data")
|
||||
if part.is_a("IfcElementAssembly"):
|
||||
pass
|
||||
|
||||
else:
|
||||
if not pset:
|
||||
pset = ifcopenshell.api.run(
|
||||
"pset.add_pset", tool.Ifc.get(), product=part, name="BBIM_Aggregate_Data"
|
||||
)
|
||||
else:
|
||||
pset = ifcopenshell.util.element.get_pset(part, "BBIM_Aggregate_Data")
|
||||
pset = tool.Ifc.get().by_id(pset["id"])
|
||||
|
||||
data_children = {
|
||||
"children": [],
|
||||
"instance_of": [],
|
||||
}
|
||||
data = [data_children]
|
||||
|
||||
ifcopenshell.api.run(
|
||||
"pset.edit_pset",
|
||||
tool.Ifc.get(),
|
||||
pset=pset,
|
||||
properties={
|
||||
"Parent": instance_entity.GlobalId,
|
||||
"Data": tool.Ifc.get().createIfcText(json.dumps(data)),
|
||||
},
|
||||
)
|
||||
|
||||
part_obj = tool.Ifc.get_object(part)
|
||||
new_part = duplicate_objects(part_obj)
|
||||
blenderbim.core.aggregate.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(entity),
|
||||
related_obj=tool.Ifc.get_object(new_part),
|
||||
)
|
||||
|
||||
def duplicate_objects(obj, is_root=False):
|
||||
new_obj = obj.copy()
|
||||
if obj.data:
|
||||
new_obj.data = obj.data.copy()
|
||||
if obj == context.active_object:
|
||||
self.new_active_obj = new_obj
|
||||
for collection in obj.users_collection:
|
||||
collection.objects.link(new_obj)
|
||||
obj.select_set(False)
|
||||
new_obj.select_set(True)
|
||||
|
||||
# This is needed to make sure the new object gets unlink from
|
||||
# the old object assembly collection
|
||||
new_obj.BIMObjectProperties.collection = None
|
||||
|
||||
# Copy the actual class
|
||||
new_entity = blenderbim.core.root.copy_class(
|
||||
tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new_obj
|
||||
)
|
||||
|
||||
if new_entity:
|
||||
tool.Model.handle_array_on_copied_element(new_entity)
|
||||
|
||||
if not new_entity.is_a("IfcElementAssembly"):
|
||||
blenderbim.core.aggregate.unassign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=obj,
|
||||
related_obj=tool.Ifc.get_object(new_entity),
|
||||
)
|
||||
|
||||
old_to_new[tool.Ifc.get_entity(obj)] = [new_entity]
|
||||
|
||||
return new_entity
|
||||
|
||||
if len(context.selected_objects) != 1:
|
||||
self.report({"INFO"}, "Only 1 object need to be selected.")
|
||||
return {"FINISHED"}
|
||||
|
||||
selected_root_obj = context.selected_objects[0]
|
||||
selected_root_entity = tool.Ifc.get_entity(selected_root_obj)
|
||||
|
||||
if selected_root_entity.is_a("IfcElementAssembly"):
|
||||
pass
|
||||
elif selected_root_entity.Decomposes:
|
||||
if selected_root_entity.Decomposes[0].RelatingObject.is_a("IfcElementAssembly"):
|
||||
selected_root_entity = selected_root_entity.Decomposes[0].RelatingObject
|
||||
selected_root_obj = tool.Ifc.get_object(selected_root_entity)
|
||||
else:
|
||||
self.report({"INFO"}, "Object is not part of a IfcElementAssembly.")
|
||||
return {"FINISHED"}
|
||||
|
||||
pset = ifcopenshell.util.element.get_pset(selected_root_entity, "BBIM_Aggregate_Data")
|
||||
if not pset:
|
||||
self.report({"INFO"}, "Object is not part of an assembly aggregate.")
|
||||
return {"FINISHED"}
|
||||
|
||||
pset_data = json.loads(pset["Data"])[0]
|
||||
instance_of = pset_data["instance_of"][0]
|
||||
original_root_entity = tool.Ifc.get().by_guid(instance_of)
|
||||
if original_root_entity == selected_root_entity:
|
||||
self.report({"INFO"}, "Cannot refresh original assembly. Select an assembly instance.")
|
||||
return {"FINISHED"}
|
||||
|
||||
parents = remove_objects(selected_root_entity)
|
||||
|
||||
original_root_object = tool.Ifc.get_object(original_root_entity)
|
||||
|
||||
selected_matrix = selected_root_obj.matrix_world
|
||||
original_matrix = original_root_object.matrix_world
|
||||
|
||||
for parent in parents:
|
||||
duplicate_children(parent)
|
||||
|
||||
# Remove connections with old objects
|
||||
for new in old_to_new.values():
|
||||
for connection in new[0].ConnectedTo:
|
||||
entity = connection.RelatedElement
|
||||
if entity in old_to_new.keys():
|
||||
core.remove_connection(tool.Geometry, connection=connection)
|
||||
for connection in new[0].ConnectedFrom:
|
||||
entity = connection.RelatingElement
|
||||
if entity in old_to_new.keys():
|
||||
core.remove_connection(tool.Geometry, connection=connection)
|
||||
|
||||
old_objs = []
|
||||
for old, new in old_to_new.items():
|
||||
old_objs.append(tool.Ifc.get_object(old))
|
||||
|
||||
new_obj = tool.Ifc.get_object(new[0])
|
||||
|
||||
matrix_diff = Matrix.inverted(original_matrix) @ new_obj.matrix_world
|
||||
new_matrix = selected_matrix @ matrix_diff
|
||||
|
||||
new_obj.matrix_world = new_matrix
|
||||
|
||||
relationships = tool.Root.get_decomposition_relationships(old_objs)
|
||||
|
||||
tool.Root.recreate_decompositions(relationships, old_to_new)
|
||||
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
|
||||
@@ -1495,7 +1281,12 @@ class OverridePasteBuffer(bpy.types.Operator):
|
||||
bpy.ops.view3d.pastebuffer()
|
||||
if IfcStore.get_file():
|
||||
for obj in context.selected_objects:
|
||||
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
|
||||
# Pasted objects may come from another Blender session, or even
|
||||
# from the same session where the original object has since
|
||||
# been deleted. As the source element may not exist, paste will
|
||||
# always unlink the element. If you want to duplicate an
|
||||
# element, use the duplicate commands.
|
||||
tool.Root.unlink_object(obj)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -1607,7 +1398,12 @@ class OverrideModeSetEdit(bpy.types.Operator):
|
||||
# The active object is non-mesh-like. Set a valid object (or None) as active
|
||||
context.view_layer.objects.active = context.selected_objects[0] if context.selected_objects else None
|
||||
if context.active_object:
|
||||
return tool.Blender.toggle_edit_mode(context)
|
||||
tool.Blender.toggle_edit_mode(context)
|
||||
context.scene.BIMGeometryProperties.is_changing_mode = True
|
||||
if context.scene.BIMGeometryProperties.mode != "EDIT":
|
||||
context.scene.BIMGeometryProperties.mode = "EDIT"
|
||||
context.scene.BIMGeometryProperties.is_changing_mode = False
|
||||
return {"FINISHED"}
|
||||
|
||||
# Restore the selection if nothing worked
|
||||
for obj in selected_objs:
|
||||
@@ -1678,6 +1474,11 @@ class OverrideModeSetObject(bpy.types.Operator):
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT", toggle=True)
|
||||
|
||||
context.scene.BIMGeometryProperties.is_changing_mode = True
|
||||
if context.scene.BIMGeometryProperties.mode != "OBJECT":
|
||||
context.scene.BIMGeometryProperties.mode = "OBJECT"
|
||||
context.scene.BIMGeometryProperties.is_changing_mode = False
|
||||
|
||||
if not tool.Ifc.get():
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1791,6 +1592,11 @@ class EnableEditingRepresentationItems(bpy.types.Operator, Operator):
|
||||
new.surface_style = style.Name or "Unnamed"
|
||||
elif inverse.is_a("IfcPresentationLayerAssignment"):
|
||||
new.layer = inverse.Name or "Unnamed"
|
||||
elif inverse.is_a("IfcShapeRepresentation"):
|
||||
if inverse.OfShapeAspect:
|
||||
shape_aspect = inverse.OfShapeAspect[0]
|
||||
new.shape_aspect = shape_aspect.Name
|
||||
new.shape_aspect_id = shape_aspect.id()
|
||||
|
||||
|
||||
class DisableEditingRepresentationItems(bpy.types.Operator, Operator):
|
||||
@@ -1801,3 +1607,196 @@ class DisableEditingRepresentationItems(bpy.types.Operator, Operator):
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
obj.BIMGeometryProperties.is_editing = False
|
||||
|
||||
|
||||
class RemoveRepresentationItem(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_representation_item"
|
||||
bl_label = "Remove Representation Item"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
representation_item_id: bpy.props.IntProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if context.active_object is None or len(context.active_object.BIMGeometryProperties.items) <= 1:
|
||||
cls.poll_message_set(
|
||||
"Active object need to have more than 1 representation items to keep representation valid"
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMGeometryProperties
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
representation_item = ifc_file.by_id(self.representation_item_id)
|
||||
tool.Geometry.remove_representation_item(representation_item)
|
||||
tool.Geometry.reload_representation(obj)
|
||||
|
||||
# reload style ui
|
||||
bpy.ops.bim.disable_editing_representation_items()
|
||||
bpy.ops.bim.enable_editing_representation_items()
|
||||
|
||||
|
||||
class EnableEditingRepresentationItemStyle(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.enable_editing_representation_item_style"
|
||||
bl_label = "Enable Editing Representation Item Style"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.active_object.BIMGeometryProperties
|
||||
props.is_editing_item_style = True
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
# set dropdown to currently active style
|
||||
representation_item_id = props.items[props.active_item_index].ifc_definition_id
|
||||
representation_item = ifc_file.by_id(representation_item_id)
|
||||
style = tool.Style.get_representation_item_style(representation_item)
|
||||
if style:
|
||||
props.representation_item_style = str(style.id())
|
||||
|
||||
|
||||
class EditRepresentationItemStyle(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.edit_representation_item_style"
|
||||
bl_label = "Edit Representation Item Style"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMGeometryProperties
|
||||
props.is_editing_item_style = False
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
surface_style = ifc_file.by_id(int(props.representation_item_style))
|
||||
representation_item_id = props.items[props.active_item_index].ifc_definition_id
|
||||
representation_item = ifc_file.by_id(representation_item_id)
|
||||
|
||||
tool.Style.assign_style_to_representation_item(representation_item, surface_style)
|
||||
tool.Geometry.reload_representation(obj)
|
||||
# reload style ui
|
||||
bpy.ops.bim.disable_editing_representation_items()
|
||||
bpy.ops.bim.enable_editing_representation_items()
|
||||
|
||||
|
||||
class DisableEditingRepresentationItemStyle(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_representation_item_style"
|
||||
bl_label = "Disable Editing Representation Item Style"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.active_object.BIMGeometryProperties
|
||||
props.is_editing_item_style = False
|
||||
|
||||
|
||||
class UnassignRepresentationItemStyle(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.unassign_representation_item_style"
|
||||
bl_label = "Unassign Representation Item Style"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMGeometryProperties
|
||||
props.is_editing_item_style = False
|
||||
|
||||
# get active representation item
|
||||
representation_item_id = props.items[props.active_item_index].ifc_definition_id
|
||||
representation_item = tool.Ifc.get_entity_by_id(representation_item_id)
|
||||
if not representation_item:
|
||||
self.report({"ERROR"}, f"Couldn't find representation item by id {representation_item_id}.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
tool.Style.assign_style_to_representation_item(representation_item, None)
|
||||
tool.Geometry.reload_representation(obj)
|
||||
# reload style ui
|
||||
bpy.ops.bim.disable_editing_representation_items()
|
||||
bpy.ops.bim.enable_editing_representation_items()
|
||||
|
||||
|
||||
class EnableEditingRepresentationItemShapeAspect(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.enable_editing_representation_item_shape_aspect"
|
||||
bl_label = "Enable Editing Representation Item Shape Aspect"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.active_object.BIMGeometryProperties
|
||||
props.is_editing_item_shape_aspect = True
|
||||
|
||||
# set dropdown to currently active shape aspect
|
||||
shape_aspect_id = props.items[props.active_item_index].shape_aspect_id
|
||||
if shape_aspect_id != 0:
|
||||
props.representation_item_shape_aspect = str(shape_aspect_id)
|
||||
|
||||
|
||||
class EditRepresentationItemShapeAspect(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.edit_representation_item_shape_aspect"
|
||||
bl_label = "Edit Representation Item Shape Aspect"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
props = obj.BIMGeometryProperties
|
||||
props.is_editing_item_shape_aspect = False
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
representation_item_id = props.items[props.active_item_index].ifc_definition_id
|
||||
representation_item = ifc_file.by_id(representation_item_id)
|
||||
|
||||
if props.representation_item_shape_aspect == "NEW":
|
||||
active_representation = tool.Geometry.get_active_representation(obj)
|
||||
# find IfcProductRepresentationSelect based on current representation
|
||||
if hasattr(element, "Representation"): # IfcProduct
|
||||
product_shape = element.Representation
|
||||
else: # IfcTypeProduct
|
||||
for representation_map in element.RepresentationMaps:
|
||||
if representation_map.MappedRepresentation == active_representation:
|
||||
product_shape = representation_map
|
||||
previous_shape_aspect_id = props.items[props.active_item_index].shape_aspect_id
|
||||
# will be None if item didn't had a shape aspect
|
||||
previous_shape_aspect = tool.Ifc.get_entity_by_id(previous_shape_aspect_id)
|
||||
shape_aspect = tool.Geometry.create_shape_aspect(
|
||||
product_shape, active_representation, [representation_item], previous_shape_aspect
|
||||
)
|
||||
else:
|
||||
shape_aspect = ifc_file.by_id(int(props.representation_item_shape_aspect))
|
||||
tool.Geometry.add_representation_item_to_shape_aspect([representation_item], shape_aspect)
|
||||
|
||||
# set attributes from UI
|
||||
shape_aspect_attrs = props.shape_aspect_attrs
|
||||
shape_aspect.Name = shape_aspect_attrs.name
|
||||
shape_aspect.Description = shape_aspect_attrs.description
|
||||
|
||||
# reload style ui
|
||||
bpy.ops.bim.disable_editing_representation_items()
|
||||
bpy.ops.bim.enable_editing_representation_items()
|
||||
|
||||
|
||||
class DisableEditingRepresentationItemShapeAspect(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.disable_editing_representation_item_shape_aspect"
|
||||
bl_label = "Disable Editing Representation Item Shape Aspect"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.active_object.BIMGeometryProperties
|
||||
props.is_editing_item_shape_aspect = False
|
||||
|
||||
|
||||
class RemoveRepresentationItemFromShapeAspect(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.remove_representation_item_from_shape_aspect"
|
||||
bl_label = "Remove Representation Item From Shape Aspect"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
obj = context.active_object
|
||||
props = obj.BIMGeometryProperties
|
||||
ifc_file = tool.Ifc.get()
|
||||
|
||||
representation_item_id = props.items[props.active_item_index].ifc_definition_id
|
||||
representation_item = ifc_file.by_id(representation_item_id)
|
||||
shape_aspect = ifc_file.by_id(props.items[props.active_item_index].shape_aspect_id)
|
||||
|
||||
tool.Geometry.remove_representation_items_from_shape_aspect([representation_item], shape_aspect)
|
||||
# reload style ui
|
||||
bpy.ops.bim.disable_editing_representation_items()
|
||||
bpy.ops.bim.enable_editing_representation_items()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.geometry.data import RepresentationsData
|
||||
from bpy.types import PropertyGroup
|
||||
@@ -38,11 +39,69 @@ def get_contexts(self, context):
|
||||
return RepresentationsData.data["contexts"]
|
||||
|
||||
|
||||
def update_mode(self, context):
|
||||
if self.is_changing_mode:
|
||||
return
|
||||
if self.mode == "OBJECT":
|
||||
bpy.ops.bim.override_mode_set_object("INVOKE_DEFAULT")
|
||||
elif self.mode == "EDIT":
|
||||
bpy.ops.bim.override_mode_set_edit("INVOKE_DEFAULT")
|
||||
|
||||
|
||||
def get_styles(self, context):
|
||||
# postponed import to avoid circular import
|
||||
from blenderbim.bim.module.material.data import MaterialsData
|
||||
|
||||
if not MaterialsData.is_loaded:
|
||||
MaterialsData.load()
|
||||
return MaterialsData.data["styles"]
|
||||
|
||||
|
||||
def get_shape_aspects(self, context):
|
||||
if not RepresentationsData.is_loaded:
|
||||
RepresentationsData.load()
|
||||
return RepresentationsData.data["shape_aspects"]
|
||||
|
||||
|
||||
def get_material_constituents(self, context, edit_text):
|
||||
# TODO: cache in data.py
|
||||
return [m.Name for m in tool.Ifc.get().by_type("IfcMaterialConstituent") if m.Name]
|
||||
|
||||
|
||||
def update_shape_aspect(self, context):
|
||||
shape_aspect_id = self.representation_item_shape_aspect
|
||||
attrs = self.shape_aspect_attrs
|
||||
|
||||
if shape_aspect_id == "NEW": # new shape aspect
|
||||
attrs.name = tool.Blender.get_blender_prop_default_value(attrs, "name")
|
||||
attrs.description = tool.Blender.get_blender_prop_default_value(attrs, "description")
|
||||
else:
|
||||
shape_aspect = tool.Ifc.get().by_id(int(shape_aspect_id))
|
||||
attrs.name = shape_aspect.Name or ""
|
||||
attrs.description = shape_aspect.Description or ""
|
||||
|
||||
|
||||
class RepresentationItem(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
surface_style: StringProperty(name="Surface Style")
|
||||
layer: StringProperty(name="Layer")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
shape_aspect: StringProperty(name="Shape Aspect")
|
||||
shape_aspect_id: IntProperty(name="Shape Aspect IFC ID")
|
||||
|
||||
|
||||
class ShapeAspect(PropertyGroup):
|
||||
name: StringProperty(
|
||||
name="Name",
|
||||
description=(
|
||||
"Note that IfcMaterialConstituent is applied based on shape aspects using the same name as material constituent.\n"
|
||||
"In dropdown suggestions you can see names of existing material constituents."
|
||||
),
|
||||
search=get_material_constituents,
|
||||
)
|
||||
description: StringProperty(
|
||||
name="Description",
|
||||
)
|
||||
|
||||
|
||||
class BIMObjectGeometryProperties(PropertyGroup):
|
||||
@@ -50,6 +109,13 @@ class BIMObjectGeometryProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
items: CollectionProperty(name="Representation Items", type=RepresentationItem)
|
||||
active_item_index: IntProperty(name="Active Representation Item Index")
|
||||
is_editing_item_style: BoolProperty(name="Is Editing Item's Style", default=False)
|
||||
representation_item_style: EnumProperty(items=get_styles, name="Representation Item Style")
|
||||
is_editing_item_shape_aspect: BoolProperty(name="Is Editing Item's Shape Aspect", default=False)
|
||||
representation_item_shape_aspect: EnumProperty(
|
||||
items=get_shape_aspects, name="Representation Item Shape Aspect", update=update_shape_aspect
|
||||
)
|
||||
shape_aspect_attrs: PointerProperty(type=ShapeAspect)
|
||||
|
||||
|
||||
class BIMGeometryProperties(PropertyGroup):
|
||||
@@ -59,3 +125,13 @@ class BIMGeometryProperties(PropertyGroup):
|
||||
should_force_faceted_brep: BoolProperty(name="Force Faceted Breps", default=False)
|
||||
# Navisworks workaround
|
||||
should_force_triangulation: BoolProperty(name="Force Triangulation", default=False)
|
||||
is_changing_mode: BoolProperty(name="Is Changing Mode", default=False)
|
||||
mode: EnumProperty(
|
||||
default="OBJECT",
|
||||
items=[
|
||||
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
|
||||
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
|
||||
],
|
||||
name="IFC Interaction Mode",
|
||||
update=update_mode,
|
||||
)
|
||||
|
||||
@@ -29,6 +29,12 @@ from blenderbim.bim.module.geometry.data import (
|
||||
PlacementData,
|
||||
DerivedCoordinatesData,
|
||||
)
|
||||
from blenderbim.bim.module.layer.data import LayersData
|
||||
|
||||
|
||||
def mode_menu(self, context):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(context.scene.BIMGeometryProperties, "mode", text="", icon_value=blenderbim.bim.icons["IFC"].icon_id)
|
||||
|
||||
|
||||
def object_menu(self, context):
|
||||
@@ -128,6 +134,7 @@ class BIM_PT_representations(Panel):
|
||||
|
||||
if not RepresentationsData.data["representations"]:
|
||||
layout.label(text="No Representations Found")
|
||||
return
|
||||
|
||||
for representation in RepresentationsData.data["representations"]:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -145,6 +152,18 @@ class BIM_PT_representations(Panel):
|
||||
op.ifc_definition_id = representation["id"]
|
||||
op.disable_opening_subtractions = False
|
||||
row.operator("bim.remove_representation", icon="X", text="").representation_id = representation["id"]
|
||||
if representation["is_active"]:
|
||||
active_representation = representation
|
||||
|
||||
layout.separator()
|
||||
if not LayersData.is_loaded:
|
||||
LayersData.load()
|
||||
if LayersData.data["active_layers"]:
|
||||
layout.label(text="Representation Presentation Layers:")
|
||||
for layer_name in LayersData.data["active_layers"].values():
|
||||
layout.label(text=layer_name, icon="STICKY_UVS_LOC")
|
||||
else:
|
||||
layout.label(text="Representation Has No Presentation Layers", icon="STICKY_UVS_LOC")
|
||||
|
||||
|
||||
class BIM_PT_representation_items(Panel):
|
||||
@@ -182,20 +201,47 @@ class BIM_PT_representation_items(Panel):
|
||||
self.layout.template_list("BIM_UL_representation_items", "", props, "items", props, "active_item_index")
|
||||
|
||||
item_is_active = props.active_item_index < len(props.items)
|
||||
if item_is_active:
|
||||
surface_style = props.items[props.active_item_index].surface_style
|
||||
presentation_layer = props.items[props.active_item_index].layer
|
||||
if not item_is_active:
|
||||
return
|
||||
|
||||
active_item = props.items[props.active_item_index]
|
||||
surface_style = active_item.surface_style
|
||||
shape_aspect = active_item.shape_aspect
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
if props.is_editing_item_style:
|
||||
# NOTE: we currently support 1 item having just 1 style
|
||||
# when IfcStyledItem can actually have multiple styles
|
||||
row.prop(props, "representation_item_style", icon="SHADING_RENDERED", text="")
|
||||
row.operator("bim.edit_representation_item_style", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_representation_item_style", icon="CANCEL", text="")
|
||||
else:
|
||||
surface_style, presentation_layer = None, None
|
||||
if surface_style:
|
||||
row.label(text=surface_style, icon="SHADING_RENDERED")
|
||||
else:
|
||||
row.label(text="No Surface Style", icon="MESH_UVSPHERE")
|
||||
row.operator("bim.enable_editing_representation_item_style", icon="GREASEPENCIL", text="")
|
||||
if surface_style:
|
||||
row.operator("bim.unassign_representation_item_style", icon="X", text="")
|
||||
|
||||
row = self.layout.row()
|
||||
if surface_style:
|
||||
row.label(text=surface_style, icon="MATERIAL")
|
||||
else:
|
||||
row.label(text="No Surface Style", icon="MESH_UVSPHERE")
|
||||
row.label(text=active_item.layer or "No Presentation Layer", icon="STICKY_UVS_LOC")
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text=presentation_layer or "No Presentation Layer", icon="STICKY_UVS_LOC")
|
||||
row = self.layout.row(align=True)
|
||||
if props.is_editing_item_shape_aspect:
|
||||
row.prop(props, "representation_item_shape_aspect", icon="SHAPEKEY_DATA", text="")
|
||||
row.operator("bim.edit_representation_item_shape_aspect", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_representation_item_shape_aspect", icon="CANCEL", text="")
|
||||
|
||||
shape_aspect_attrs = props.shape_aspect_attrs
|
||||
self.layout.label(text="Shape Aspect Attributes:")
|
||||
self.layout.prop(shape_aspect_attrs, "name")
|
||||
self.layout.prop(shape_aspect_attrs, "description")
|
||||
else:
|
||||
row.label(text=shape_aspect or "No Shape Aspect", icon="SHAPEKEY_DATA")
|
||||
row.operator("bim.enable_editing_representation_item_shape_aspect", icon="GREASEPENCIL", text="")
|
||||
if shape_aspect:
|
||||
row.operator("bim.remove_representation_item_from_shape_aspect", icon="X", text="")
|
||||
|
||||
|
||||
class BIM_PT_connections(Panel):
|
||||
@@ -464,3 +510,5 @@ class BIM_UL_representation_items(UIList):
|
||||
row.label(text=item.name, icon=icon)
|
||||
if item.layer:
|
||||
row.label(text="", icon="STICKY_UVS_LOC")
|
||||
op = row.operator("bim.remove_representation_item", icon="X", text="")
|
||||
op.representation_item_id = item.ifc_definition_id
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.helper import import_attributes
|
||||
from blenderbim.bim.module.pset.data import refresh as refresh_pset
|
||||
from bpy.types import PropertyGroup
|
||||
import json
|
||||
from bpy.props import (
|
||||
@@ -33,6 +33,10 @@ from bpy.props import (
|
||||
)
|
||||
|
||||
|
||||
def update_active_group_index(self, context):
|
||||
refresh_pset()
|
||||
|
||||
|
||||
class ExpandedGroups(StrProperty):
|
||||
json_string: StringProperty(name="JSON String", default="[]")
|
||||
|
||||
@@ -50,5 +54,5 @@ class BIMGroupProperties(PropertyGroup):
|
||||
group_attributes: CollectionProperty(name="Group Attributes", type=Attribute)
|
||||
is_editing: BoolProperty(name="Is Editing", default=False)
|
||||
groups: CollectionProperty(name="Groups", type=Group)
|
||||
active_group_index: IntProperty(name="Active Group Index")
|
||||
active_group_index: IntProperty(name="Active Group Index", update=update_active_group_index)
|
||||
active_group_id: IntProperty(name="Active Group Id")
|
||||
|
||||
@@ -88,7 +88,7 @@ class IfcGitData:
|
||||
try:
|
||||
if tool.IfcGitRepo.repo.branches:
|
||||
return tool.IfcGit.branches_by_hexsha(tool.IfcGitRepo.repo)
|
||||
except:
|
||||
except AttributeError:
|
||||
return {}
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -40,14 +40,15 @@ class LayersData:
|
||||
|
||||
@classmethod
|
||||
def active_layers(cls):
|
||||
if not bpy.context.active_object:
|
||||
return []
|
||||
data = bpy.context.active_object.data
|
||||
if not data:
|
||||
return []
|
||||
if not isinstance(data, bpy.types.Mesh) or not data.BIMMeshProperties.ifc_definition_id:
|
||||
return []
|
||||
results = []
|
||||
results = dict()
|
||||
shape = tool.Ifc.get().by_id(data.BIMMeshProperties.ifc_definition_id)
|
||||
for inverse in tool.Ifc.get().get_inverse(shape):
|
||||
if inverse.is_a("IfcPresentationLayerAssignment"):
|
||||
results.append(inverse.id())
|
||||
for inverse in shape.LayerAssignments:
|
||||
results[inverse.id()] = inverse.Name or "Unnamed"
|
||||
return results
|
||||
|
||||
@@ -137,6 +137,7 @@ class RemovePresentationLayer(bpy.types.Operator):
|
||||
class AssignPresentationLayer(bpy.types.Operator):
|
||||
bl_idname = "bim.assign_presentation_layer"
|
||||
bl_label = "Assign Presentation Layer"
|
||||
bl_description = "Assign presentation layer to the active representation of the active object"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
item: bpy.props.StringProperty()
|
||||
layer: bpy.props.IntProperty()
|
||||
@@ -158,6 +159,7 @@ class AssignPresentationLayer(bpy.types.Operator):
|
||||
class UnassignPresentationLayer(bpy.types.Operator):
|
||||
bl_idname = "bim.unassign_presentation_layer"
|
||||
bl_label = "Unassign Presentation Layer"
|
||||
bl_description = "Unassign presentation layer from the active representation of the active object"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
item: bpy.props.StringProperty()
|
||||
layer: bpy.props.IntProperty()
|
||||
|
||||
@@ -84,6 +84,7 @@ class BIM_UL_layers(UIList):
|
||||
op = row.operator("bim.assign_presentation_layer", text="", icon="KEYFRAME", emboss=False)
|
||||
op.layer = item.ifc_definition_id
|
||||
|
||||
# TODO: replace placeholder UI for hiding presentation layers
|
||||
row.operator("bim.disable_editing_layer", text="", icon="HIDE_OFF", emboss=False)
|
||||
row.operator("bim.disable_editing_layer", text="", icon="FREEZE", emboss=False)
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import olca
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
def refresh():
|
||||
LcaData.is_loaded = False
|
||||
|
||||
|
||||
class LcaData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"product_systems": cls.product_systems(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def product_systems(cls):
|
||||
if not bpy.context.scene.BIMLCAProperties.is_connected:
|
||||
return []
|
||||
results = []
|
||||
client = olca.Client(context.preferences.addons["blenderbim"].preferences.openlca_port)
|
||||
try:
|
||||
results = [(ps.name, ps.name, "") for ps in client.get_all(olca.ProductSystem)]
|
||||
except:
|
||||
pass
|
||||
return results
|
||||
@@ -1,55 +0,0 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import olca
|
||||
import ifcopenshell
|
||||
|
||||
|
||||
class CalculateLCA(bpy.types.Operator):
|
||||
bl_idname = "bim.calculate_lca"
|
||||
bl_label = "Calculate LCA"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
filter_glob: bpy.props.StringProperty(default="*.xlsx", options={"HIDDEN"})
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMLCAProperties
|
||||
client = olca.Client(context.preferences.addons["blenderbim"].preferences.openlca_port)
|
||||
setup = olca.CalculationSetup()
|
||||
setup.calculation_type = olca.CalculationType.SIMPLE_CALCULATION
|
||||
setup.impact_method = client.find(olca.ImpactMethod, "CML-IA baseline")
|
||||
setup.product_system = client.find(olca.ProductSystem, props.product_systems)
|
||||
setup.amount = props.amount
|
||||
result = client.calculate(setup)
|
||||
client.excel_export(result, self.filepath)
|
||||
return {"FINISHED"}
|
||||
|
||||
def invoke(self, context, event):
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class ConnectOpenLCA(bpy.types.Operator):
|
||||
bl_idname = "bim.connect_openlca"
|
||||
bl_label = "Connect OpenLCA"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMLCAProperties.is_connected = True
|
||||
return {"FINISHED"}
|
||||
@@ -1,43 +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 bpy
|
||||
from bpy.types import Panel
|
||||
|
||||
|
||||
class BIM_PT_lca(Panel):
|
||||
bl_label = "BIM Life Cycle Assessment"
|
||||
bl_idname = "BIM_PT_lca"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_sandbox"
|
||||
|
||||
def draw(self, context):
|
||||
props = context.scene.BIMLCAProperties
|
||||
if props.is_connected:
|
||||
row = self.layout.row()
|
||||
row.prop(props, "product_systems", text="")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "amount", text="")
|
||||
row = self.layout.row()
|
||||
row.operator("bim.calculate_lca")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.operator("bim.connect_openlca")
|
||||
@@ -181,7 +181,7 @@ class FilledOpeningGenerator:
|
||||
return
|
||||
|
||||
opening = filling.FillsVoids[0].RelatingOpeningElement
|
||||
voided_obj = tool.Ifc.get_object(opening.VoidsElements[0].RelatingBuildingElement)
|
||||
voided_element = opening.VoidsElements[0].RelatingBuildingElement
|
||||
|
||||
opening_rep = ifcopenshell.util.representation.get_representation(opening, "Model", "Body", "MODEL_VIEW")
|
||||
ifcopenshell.api.run(
|
||||
@@ -217,16 +217,22 @@ class FilledOpeningGenerator:
|
||||
"geometry.assign_representation", tool.Ifc.get(), product=opening, representation=mapped_representation
|
||||
)
|
||||
|
||||
representation = tool.Ifc.get().by_id(voided_obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=voided_obj,
|
||||
representation=representation,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
# update voided object representation or all it's parts if it's an aggregate
|
||||
voided_elements = ifcopenshell.util.element.get_parts(voided_element) or [voided_element]
|
||||
for voided_element in voided_elements:
|
||||
voided_obj = tool.Ifc.get_object(voided_element)
|
||||
if not voided_obj.data:
|
||||
continue
|
||||
representation = tool.Ifc.get().by_id(voided_obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
tool.Geometry,
|
||||
obj=voided_obj,
|
||||
representation=representation,
|
||||
should_reload=True,
|
||||
is_global=True,
|
||||
should_sync_changes_first=False,
|
||||
)
|
||||
|
||||
def generate_opening_from_filling(self, filling, filling_obj):
|
||||
# Since openings are reused later, we give a default thickness of 1.2m
|
||||
@@ -515,6 +521,7 @@ class AddBoolean(Operator, tool.Ifc.Operator):
|
||||
return {"FINISHED"}
|
||||
if element2 and not element1:
|
||||
obj1, obj2 = obj2, obj1
|
||||
element1, element2 = element2, element1
|
||||
if not obj1.data or not hasattr(obj1.data, "BIMMeshProperties"):
|
||||
return {"FINISHED"}
|
||||
representation = tool.Ifc.get().by_id(obj1.data.BIMMeshProperties.ifc_definition_id)
|
||||
@@ -662,17 +669,17 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
||||
except:
|
||||
continue
|
||||
|
||||
boolean = None
|
||||
boolean_id = None
|
||||
for inverse in tool.Ifc.get().get_inverse(item):
|
||||
if inverse.is_a("IfcBooleanResult"):
|
||||
boolean = inverse
|
||||
boolean_id = inverse.id()
|
||||
break
|
||||
ifcopenshell.api.run("geometry.remove_boolean", tool.Ifc.get(), item=item)
|
||||
|
||||
if obj.data.BIMMeshProperties.obj:
|
||||
upstream_obj = obj.data.BIMMeshProperties.obj
|
||||
element = tool.Ifc.get_entity(upstream_obj)
|
||||
bbim_boolean_updates.setdefault(element, []).append(boolean)
|
||||
bbim_boolean_updates.setdefault(element, []).append(boolean_id)
|
||||
body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
if body:
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
@@ -686,8 +693,8 @@ class RemoveBooleans(Operator, tool.Ifc.Operator, AddObjectHelper):
|
||||
)
|
||||
bpy.data.objects.remove(obj)
|
||||
|
||||
for element, booleans in bbim_boolean_updates.items():
|
||||
tool.Model.unmark_manual_booleans(element, booleans)
|
||||
for element, boolean_ids in bbim_boolean_updates.items():
|
||||
tool.Model.unmark_manual_booleans(element, boolean_ids)
|
||||
|
||||
tool.Blender.set_active_object(upstream_obj)
|
||||
return {"FINISHED"}
|
||||
@@ -755,8 +762,6 @@ class EditOpenings(Operator, tool.Ifc.Operator):
|
||||
def _execute(self, context):
|
||||
props = bpy.context.scene.BIMModelProperties
|
||||
building_objs = set()
|
||||
model = tool.Ifc.get()
|
||||
all_openings = model.by_type("IfcOpeningElement")
|
||||
|
||||
for obj in context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
@@ -767,23 +772,24 @@ class EditOpenings(Operator, tool.Ifc.Operator):
|
||||
obj = tool.Ifc.get_object(element)
|
||||
openings = [r.RelatedOpeningElement for r in element.HasOpenings]
|
||||
for opening in openings:
|
||||
similar_openings = [o for o in all_openings if o.ObjectPlacement == opening.ObjectPlacement]
|
||||
opening_obj = tool.Ifc.get_object(opening)
|
||||
building_objs.add(obj)
|
||||
|
||||
similar_openings = blenderbim.core.geometry.get_similar_openings(tool.Ifc, opening)
|
||||
similar_openings_building_objs = blenderbim.core.geometry.get_similar_openings_building_objs(tool.Ifc, similar_openings)
|
||||
building_objs.update(similar_openings_building_objs)
|
||||
|
||||
if opening_obj:
|
||||
if tool.Ifc.is_edited(opening_obj):
|
||||
tool.Geometry.run_geometry_update_representation(obj=opening_obj)
|
||||
blenderbim.core.geometry.edit_similar_opening_placement(tool.Geometry, opening, similar_openings)
|
||||
elif tool.Ifc.is_moved(opening_obj):
|
||||
blenderbim.core.geometry.edit_object_placement(
|
||||
tool.Ifc, tool.Geometry, tool.Surveyor, obj=opening_obj
|
||||
)
|
||||
for similar_opening in similar_openings:
|
||||
similar_opening.ObjectPlacement = opening.ObjectPlacement
|
||||
element = similar_opening.VoidsElements[0].RelatingBuildingElement
|
||||
obj = tool.Ifc.get_object(element)
|
||||
building_objs.add(obj)
|
||||
|
||||
building_objs.update(self.get_all_building_objects_of_similar_openings(opening))
|
||||
blenderbim.core.geometry.edit_similar_opening_placement(tool.Geometry, opening, similar_openings)
|
||||
|
||||
building_objs.update(self.get_all_building_objects_of_similar_openings(opening)) #NB this has nothing to do with clone similar_opening
|
||||
tool.Ifc.unlink(element=opening, obj=opening_obj)
|
||||
bpy.data.objects.remove(opening_obj)
|
||||
|
||||
@@ -826,13 +832,10 @@ class CloneOpening(Operator, tool.Ifc.Operator):
|
||||
continue
|
||||
|
||||
opening_placement = opening.ObjectPlacement
|
||||
opening_representations = opening.Representation.Representations
|
||||
opening_representation = opening.Representation
|
||||
|
||||
new_opening = ifcopenshell.api.run("root.create_entity", tool.Ifc.get(), ifc_class="IfcOpeningElement")
|
||||
for representation in opening_representations:
|
||||
ifcopenshell.api.run(
|
||||
"geometry.assign_representation", tool.Ifc.get(), product=new_opening, representation=representation
|
||||
)
|
||||
new_opening.Representation = opening_representation
|
||||
|
||||
ifcopenshell.api.run("void.add_opening", tool.Ifc.get(), opening=new_opening, element=wall)
|
||||
new_opening.ObjectPlacement = opening_placement
|
||||
|
||||
@@ -87,8 +87,8 @@ class VIEW3D_MT_PIE_bim(bpy.types.Menu):
|
||||
pie.operator("bim.pie_add_opening")
|
||||
pie.operator("bim.pie_update_container")
|
||||
pie.operator("bim.open_pie_class", text="Assign IFC Class")
|
||||
pie.operator("bim.assign_object", text ="Assign Aggregation")
|
||||
pie.operator("bim.unassign_object", text ="Unassign Aggregation")
|
||||
pie.operator("bim.aggregate_assign_object", text="Assign Aggregation")
|
||||
pie.operator("bim.aggregate_unassign_object", text="Unassign Aggregation")
|
||||
|
||||
|
||||
class VIEW3D_MT_PIE_bim_class(bpy.types.Menu):
|
||||
|
||||
@@ -189,12 +189,12 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
||||
collection_obj = collection.BIMCollectionProperties.obj
|
||||
|
||||
bpy.ops.bim.assign_class(obj=obj.name, ifc_class=instance_class)
|
||||
tool.Blender.remove_data_block(mesh) # Remove "Instance" mesh
|
||||
tool.Blender.remove_data_block(mesh) # Remove "Instance" mesh
|
||||
|
||||
mesh_data = obj.data
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
blenderbim.core.type.assign_type(tool.Ifc, tool.Type, element=element, type=relating_type)
|
||||
if obj.data != mesh_data: # remove orphaned mesh from "bim.assign_class"
|
||||
if obj.data != mesh_data: # remove orphaned mesh from "bim.assign_class"
|
||||
tool.Blender.remove_data_block(mesh_data)
|
||||
|
||||
# Update required as core.type.assign_type may change obj.data
|
||||
@@ -204,7 +204,7 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
||||
if (
|
||||
building_obj
|
||||
and building_element
|
||||
and building_element.is_a() in ["IfcWall", "IfcWallStandardCase", "IfcCovering"]
|
||||
and building_element.is_a() in ["IfcWall", "IfcWallStandardCase", "IfcCovering", "IfcElementAssembly"]
|
||||
and instance_class in ["IfcWindow", "IfcDoor"]
|
||||
):
|
||||
# Fills should be a sibling to the building element
|
||||
@@ -234,14 +234,19 @@ class AddConstrTypeInstance(bpy.types.Operator):
|
||||
if (
|
||||
building_obj
|
||||
and building_element
|
||||
and building_element.is_a() in ["IfcWall", "IfcWallStandardCase", "IfcCovering"]
|
||||
and building_element.is_a() in ["IfcWall", "IfcWallStandardCase", "IfcCovering", "IfcElementAssembly"]
|
||||
):
|
||||
if instance_class in ["IfcWindow", "IfcDoor"]:
|
||||
# TODO For now we are hardcoding windows and doors as a prototype
|
||||
bpy.ops.bim.add_filled_opening(voided_obj=building_obj.name, filling_obj=obj.name)
|
||||
else:
|
||||
if collection_obj and tool.Ifc.get_entity(collection_obj):
|
||||
obj.location.z = collection_obj.location.z - tool.Blender.get_object_bounding_box(obj)["min_z"]
|
||||
if props.rl_mode == "BOTTOM":
|
||||
obj.location.z = collection_obj.location.z - tool.Blender.get_object_bounding_box(obj)["min_z"]
|
||||
elif props.rl_mode == "CONTAINER":
|
||||
obj.location.z = collection_obj.location.z
|
||||
elif props.rl_mode == "CURSOR":
|
||||
pass
|
||||
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
|
||||
for port in ifcopenshell.util.system.get_ports(relating_type):
|
||||
|
||||
@@ -456,7 +456,9 @@ class DumbProfileJoiner:
|
||||
if not extrusion:
|
||||
return None, None
|
||||
position = extrusion.Position
|
||||
return (position.Axis.DirectionRatios, position.RefDirection.DirectionRatios)
|
||||
if position.Axis:
|
||||
return (position.Axis.DirectionRatios, position.RefDirection.DirectionRatios)
|
||||
return ((0.0, 0.0, 1.0), (1.0, 0.0, 0.0))
|
||||
|
||||
old_body = ifcopenshell.util.representation.get_representation(element, "Model", "Body", "MODEL_VIEW")
|
||||
new_body = ifcopenshell.api.run(
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import blenderbim.tool as tool
|
||||
import math
|
||||
from blenderbim.bim.prop import ObjProperty
|
||||
from blenderbim.bim.module.model.data import AuthoringData
|
||||
from bpy.types import PropertyGroup, NodeTree
|
||||
@@ -132,6 +133,15 @@ class BIMModelProperties(PropertyGroup):
|
||||
x: bpy.props.FloatProperty(name="X", default=0.5, subtype="DISTANCE", description="Size by X axis for the opening")
|
||||
y: bpy.props.FloatProperty(name="Y", default=0.5, subtype="DISTANCE", description="Size by Y axis for the opening")
|
||||
z: bpy.props.FloatProperty(name="Z", default=0.5, subtype="DISTANCE", description="Size by Z axis for the opening")
|
||||
rl_mode: bpy.props.EnumProperty(
|
||||
items=(
|
||||
("BOTTOM", "Bottom", "Snaps the element's lowest geometry to the container's Z value."),
|
||||
("CONTAINER", "Container", "Positions the element's placement origin at the container's Z value."),
|
||||
("CURSOR", "Cursor", "Places the object placement at the 3D cursor's Z value."),
|
||||
),
|
||||
name="RL Mode",
|
||||
default="BOTTOM",
|
||||
)
|
||||
# Used for things like walls, doors, flooring, skirting, etc
|
||||
rl1: bpy.props.FloatProperty(name="RL", default=1, subtype="DISTANCE", description="Z offset for walls")
|
||||
# Used for things like windows, other hosted furniture, and MEP
|
||||
@@ -683,6 +693,7 @@ class BIMRoofProperties(PropertyGroup):
|
||||
"roof_type",
|
||||
"generation_method",
|
||||
"angle",
|
||||
"percentage",
|
||||
"rafter_edge_angle",
|
||||
)
|
||||
roof_types = (("HIP/GABLE ROOF", "HIP/GABLE ROOF", ""),)
|
||||
@@ -701,7 +712,8 @@ class BIMRoofProperties(PropertyGroup):
|
||||
height: bpy.props.FloatProperty(
|
||||
name="Height", default=1.0, description="Maximum height of the roof to be generated.", subtype="DISTANCE"
|
||||
)
|
||||
angle: bpy.props.FloatProperty(name="Slope Angle", default=pi / 18, subtype="ANGLE")
|
||||
angle: bpy.props.FloatProperty(name="Slope Angle", default=pi / 18, subtype="ANGLE", update=lambda self, context: self.update_percentage())
|
||||
percentage: bpy.props.FloatProperty(name="Slope %", default=17.63269754733197, subtype="PERCENTAGE", update=lambda self, context: self.update_angle())
|
||||
roof_thickness: bpy.props.FloatProperty(name="Roof Thickness", default=0.1, subtype="DISTANCE")
|
||||
rafter_edge_angle: bpy.props.FloatProperty(name="Rafter Edge Angle", min=0, max=pi, default=pi / 2, subtype="ANGLE")
|
||||
|
||||
@@ -718,6 +730,7 @@ class BIMRoofProperties(PropertyGroup):
|
||||
kwargs["height"] = self.height
|
||||
else:
|
||||
kwargs["angle"] = self.angle
|
||||
kwargs["percentage"] = self.percentage
|
||||
|
||||
if not convert_to_project_units:
|
||||
return kwargs
|
||||
@@ -727,3 +740,9 @@ class BIMRoofProperties(PropertyGroup):
|
||||
kwargs = tool.Model.convert_data_to_si_units(kwargs, self.non_si_units_props)
|
||||
for prop_name in kwargs:
|
||||
setattr(self, prop_name, kwargs[prop_name])
|
||||
|
||||
def update_angle(self):
|
||||
self.angle = math.atan(self.percentage / 100)
|
||||
|
||||
def update_percentage(self):
|
||||
self.percentage = math.tan(self.angle)*100
|
||||
@@ -1120,11 +1120,11 @@ class DumbWallJoiner:
|
||||
other = tool.Ifc.get_object(rel.RelatedElement)
|
||||
if connection not in ["ATPATH", "NOTDEFINED"]:
|
||||
self.join(
|
||||
obj,
|
||||
other,
|
||||
connection,
|
||||
rel.RelatedConnectionType,
|
||||
is_relating=True,
|
||||
obj,
|
||||
other,
|
||||
connection,
|
||||
rel.RelatedConnectionType,
|
||||
is_relating=True,
|
||||
description=rel.Description
|
||||
)
|
||||
for rel in element.ConnectedFrom:
|
||||
@@ -1226,6 +1226,7 @@ class DumbWallJoiner:
|
||||
# If opening has filling then stick to the filling's position
|
||||
# We're applying new openings position only after wall position is applied
|
||||
for opening in [r.RelatedOpeningElement for r in element.HasOpenings if r.RelatedOpeningElement.HasFillings]:
|
||||
similar_openings = blenderbim.core.geometry.get_similar_openings(tool.Ifc, opening)
|
||||
filling_obj = tool.Ifc.get_object(opening.HasFillings[0].RelatedBuildingElement)
|
||||
filling_moved = tool.Ifc.is_moved(filling_obj)
|
||||
if filling_moved:
|
||||
@@ -1234,6 +1235,7 @@ class DumbWallJoiner:
|
||||
ifcopenshell.api.run(
|
||||
"geometry.edit_object_placement", tool.Ifc.get(), product=opening, matrix=filling_obj.matrix_world
|
||||
)
|
||||
blenderbim.core.geometry.edit_similar_opening_placement(tool.Geometry, opening, similar_openings)
|
||||
|
||||
blenderbim.core.geometry.switch_representation(
|
||||
tool.Ifc,
|
||||
|
||||
@@ -194,6 +194,7 @@ class PipeTool(BimTool):
|
||||
def add_layout_hotkey_operator(layout, text, hotkey, description):
|
||||
modifiers = {
|
||||
"A": "EVENT_ALT",
|
||||
"C": "EVENT_CTRL",
|
||||
"S": "EVENT_SHIFT",
|
||||
}
|
||||
modifier, key = hotkey.split("_")
|
||||
@@ -283,6 +284,9 @@ class BimToolUI:
|
||||
row.prop(data=cls.props, property="rl2", text="RL")
|
||||
elif cls.props.ifc_class in ("IfcSpaceType"):
|
||||
add_layout_hotkey_operator(cls.layout, "Generate", "S_G", bpy.ops.bim.generate_space.__doc__)
|
||||
else:
|
||||
row = cls.layout.row(align=True)
|
||||
row.prop(data=cls.props, property="rl_mode", text="RL")
|
||||
|
||||
@classmethod
|
||||
def draw_edit_object_interface(cls, context):
|
||||
@@ -414,7 +418,7 @@ class BimToolUI:
|
||||
row.label(text="", icon="EVENT_SHIFT")
|
||||
row.label(text="", icon="EVENT_O")
|
||||
|
||||
if len(context.selected_objects) == 2:
|
||||
if len(context.selected_objects) > 1:
|
||||
row.operator("bim.add_opening", text="Apply Void")
|
||||
else:
|
||||
row.operator("bim.add_potential_opening", text="Add Void")
|
||||
@@ -445,6 +449,10 @@ class BimToolUI:
|
||||
add_layout_hotkey_operator(cls.layout, "Void", "A_O", "Toggle openings")
|
||||
add_layout_hotkey_operator(cls.layout, "Decomposition", "A_D", "Select decomposition")
|
||||
|
||||
cls.layout.row(align=True).label(text="Aggregation")
|
||||
add_layout_hotkey_operator(cls.layout, "Assign", "C_P", bpy.ops.bim.aggregate_assign_object.__doc__)
|
||||
add_layout_hotkey_operator(cls.layout, "Unassign", "A_P", bpy.ops.bim.aggregate_unassign_object.__doc__)
|
||||
|
||||
cls.layout.separator()
|
||||
add_layout_hotkey_operator(
|
||||
cls.layout, "Calculate All Quantities", "S_Q", bpy.ops.bim.calculate_all_quantities.__doc__
|
||||
@@ -580,12 +588,12 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
|
||||
def hotkey_C_P(self):
|
||||
if not bpy.context.selected_objects:
|
||||
return
|
||||
bpy.ops.bim.assign_object()
|
||||
bpy.ops.bim.aggregate_assign_object()
|
||||
|
||||
def hotkey_A_P(self):
|
||||
if not bpy.context.selected_objects:
|
||||
return
|
||||
bpy.ops.bim.unassign_object()
|
||||
bpy.ops.bim.aggregate_unassign_object()
|
||||
|
||||
def hotkey_S_C(self):
|
||||
if not bpy.context.selected_objects:
|
||||
|
||||
+11
-7
@@ -1,5 +1,5 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
@@ -20,16 +20,20 @@ import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.CalculateLCA,
|
||||
operator.ConnectOpenLCA,
|
||||
prop.BIMLCAProperties,
|
||||
ui.BIM_PT_lca,
|
||||
operator.BIM_OT_nest_assign_object,
|
||||
operator.BIM_OT_disable_editing_nest,
|
||||
operator.BIM_OT_enable_editing_nest,
|
||||
operator.BIM_OT_select_components,
|
||||
operator.BIM_OT_select_nest,
|
||||
operator.BIM_OT_nest_unassign_object,
|
||||
prop.BIMObjectNestProperties,
|
||||
ui.BIM_PT_nest,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMLCAProperties = bpy.props.PointerProperty(type=prop.BIMLCAProperties)
|
||||
bpy.types.Object.BIMObjectNestProperties = bpy.props.PointerProperty(type=prop.BIMObjectNestProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMLCAProperties
|
||||
del bpy.types.Object.BIMObjectNestProperties
|
||||
@@ -0,0 +1,67 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.element
|
||||
|
||||
|
||||
def refresh():
|
||||
NestData.is_loaded = False
|
||||
|
||||
|
||||
class NestData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"has_relating_object": cls.has_relating_object(),
|
||||
"relating_object_label": cls.get_relating_object_label(),
|
||||
"has_related_objects": cls.has_related_objects(),
|
||||
"total_components": cls.total_components(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def get_relating_object(cls):
|
||||
return ifcopenshell.util.element.get_nest(tool.Ifc.get_entity(bpy.context.active_object))
|
||||
|
||||
@classmethod
|
||||
def has_relating_object(cls) -> bool:
|
||||
return cls.get_relating_object() is not None
|
||||
|
||||
@classmethod
|
||||
def get_relating_object_label(cls) -> str:
|
||||
nest = cls.get_relating_object()
|
||||
if nest:
|
||||
return f"{nest.is_a()}/{nest.Name or ''}"
|
||||
|
||||
@classmethod
|
||||
def get_related_objects(cls):
|
||||
return ifcopenshell.util.element.get_components(tool.Ifc.get_entity(bpy.context.active_object))
|
||||
|
||||
@classmethod
|
||||
def total_components(cls):
|
||||
components = cls.get_related_objects()
|
||||
return len(components) if components else 0
|
||||
|
||||
@classmethod
|
||||
def has_related_objects(cls) -> bool:
|
||||
return bool(cls.get_related_objects())
|
||||
@@ -0,0 +1,151 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.core.nest as core
|
||||
import blenderbim.core.spatial
|
||||
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_nest_assign_object(bpy.types.Operator, Operator):
|
||||
"""Create nest relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.nest_assign_object"
|
||||
bl_label = "Assign Object To Nesting"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
relating_object: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
relating_obj = None
|
||||
if self.relating_object:
|
||||
relating_obj = tool.Ifc.get_object(tool.Ifc.get().by_id(self.relating_object))
|
||||
elif context.active_object:
|
||||
relating_obj = context.active_object
|
||||
if not relating_obj:
|
||||
return
|
||||
|
||||
for obj in bpy.context.selected_objects:
|
||||
if obj == relating_obj:
|
||||
continue
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
result = core.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Nest,
|
||||
tool.Collector,
|
||||
relating_obj=relating_obj,
|
||||
related_obj=obj,
|
||||
)
|
||||
if not result:
|
||||
self.report({"ERROR"}, f" Cannot nest {obj.name} to {relating_obj.name}")
|
||||
|
||||
|
||||
class BIM_OT_nest_unassign_object(bpy.types.Operator, Operator):
|
||||
"""Remove nest relationship between two ifc elements"""
|
||||
|
||||
bl_idname = "bim.nest_unassign_object"
|
||||
bl_label = "Unassign Object From Nesting"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
for obj in bpy.context.selected_objects:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
nest = ifcopenshell.util.element.get_nest(element)
|
||||
if not nest:
|
||||
continue
|
||||
core.unassign_object(
|
||||
tool.Ifc,
|
||||
tool.Nest,
|
||||
tool.Collector,
|
||||
relating_obj=tool.Ifc.get_object(nest),
|
||||
related_obj=tool.Ifc.get_object(element),
|
||||
)
|
||||
|
||||
|
||||
class BIM_OT_enable_editing_nest(bpy.types.Operator, Operator):
|
||||
"""Enable editing nest relationship"""
|
||||
|
||||
bl_idname = "bim.enable_editing_nest"
|
||||
bl_label = "Enable Editing Nest"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
core.enable_editing_nest(tool.Nest, obj=context.active_object)
|
||||
|
||||
|
||||
class BIM_OT_disable_editing_nest(bpy.types.Operator, Operator):
|
||||
"""Disable editing nest relationship"""
|
||||
|
||||
bl_idname = "bim.disable_editing_nest"
|
||||
bl_label = "Disable Editing Nest"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def _execute(self, context):
|
||||
core.disable_editing_nest(tool.Nest, obj=context.active_object)
|
||||
|
||||
|
||||
class BIM_OT_select_components(bpy.types.Operator):
|
||||
"""Select Components"""
|
||||
|
||||
bl_idname = "bim.select_components"
|
||||
bl_label = "Select Components"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
obj = bpy.data.objects.get(self.obj) or context.active_object
|
||||
components = ifcopenshell.util.element.get_components(tool.Ifc.get_entity(obj))
|
||||
component_objs = set(tool.Ifc.get_object(c) for c in components)
|
||||
selectable_component_objs = set(context.selectable_objects).intersection(component_objs)
|
||||
for selectable_component_obj in selectable_component_objs:
|
||||
selectable_component_obj.select_set(True)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class BIM_OT_select_nest(bpy.types.Operator):
|
||||
"""Select Nest"""
|
||||
|
||||
bl_idname = "bim.select_nest"
|
||||
bl_label = "Select Nest"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
obj = bpy.data.objects.get(self.obj) or context.active_object
|
||||
nest = ifcopenshell.util.element.get_nest(tool.Ifc.get_entity(obj))
|
||||
nest_obj = tool.Ifc.get_object(nest)
|
||||
if nest_obj in context.selectable_objects:
|
||||
nest_obj.select_set(True)
|
||||
bpy.context.view_layer.objects.active = nest_obj
|
||||
return {"FINISHED"}
|
||||
+14
-10
@@ -1,5 +1,5 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
# This file is part of BlenderBIM Add-on.
|
||||
#
|
||||
@@ -17,8 +17,8 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
from blenderbim.bim.module.lca.data import LcaData
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.spatial.data import SpatialData
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -32,13 +32,17 @@ from bpy.props import (
|
||||
)
|
||||
|
||||
|
||||
def get_product_systems(self, context):
|
||||
if not LcaData.is_loaded:
|
||||
LcaData.load()
|
||||
return LcaData.data["product_systems"]
|
||||
def update_relating_object(self, context):
|
||||
def message(self, context):
|
||||
self.layout.label(text="Please select a valid Ifc Element")
|
||||
|
||||
if self.relating_object is None:
|
||||
return
|
||||
if not self.relating_object.BIMObjectProperties.ifc_definition_id:
|
||||
context.window_manager.popup_menu(message, title="Invalid Element Selected", icon="INFO")
|
||||
self.relating_object = None
|
||||
|
||||
|
||||
class BIMLCAProperties(PropertyGroup):
|
||||
is_connected: BoolProperty(name="Is Connected")
|
||||
amount: FloatProperty(name="Amount")
|
||||
product_systems: EnumProperty(items=get_product_systems, name="Product Systems")
|
||||
class BIMObjectNestProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing")
|
||||
relating_object: PointerProperty(name="Nest Host", type=bpy.types.Object, update=update_relating_object)
|
||||
@@ -0,0 +1,83 @@
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2023 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.module.nest.data import NestData
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
class BIM_PT_nest(Panel):
|
||||
bl_label = "Nest"
|
||||
bl_idname = "BIM_PT_nest"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "object"
|
||||
bl_parent_id = "BIM_PT_tab_object_metadata"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.active_object:
|
||||
return False
|
||||
props = context.active_object.BIMObjectProperties
|
||||
if not props.ifc_definition_id:
|
||||
return False
|
||||
if not IfcStore.get_element(props.ifc_definition_id):
|
||||
return False
|
||||
if not IfcStore.get_file().by_id(props.ifc_definition_id).is_a("IfcObjectDefinition"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
if not NestData.is_loaded:
|
||||
NestData.load()
|
||||
|
||||
props = context.active_object.BIMObjectNestProperties
|
||||
|
||||
if props.is_editing:
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "relating_object", text="")
|
||||
if props.relating_object:
|
||||
op = row.operator("bim.nest_assign_object", icon="CHECKMARK", text="")
|
||||
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
|
||||
row.operator("bim.disable_editing_nest", icon="CANCEL", text="")
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
if NestData.data["has_relating_object"]:
|
||||
row.label(text=NestData.data["relating_object_label"], icon="TRIA_UP")
|
||||
op = row.operator("bim.select_nest", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
row.operator("bim.enable_editing_nest", icon="GREASEPENCIL", text="")
|
||||
op = row.operator("bim.nest_unassign_object", icon="X", text="")
|
||||
else:
|
||||
row.label(text="No Host", icon="TRIA_UP")
|
||||
row.operator("bim.enable_editing_nest", icon="GREASEPENCIL", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
total_components = NestData.data["total_components"]
|
||||
if total_components == 0:
|
||||
row.label(text="No Components", icon="TRIA_DOWN")
|
||||
elif total_components == 1:
|
||||
row.label(text="1 Component", icon="TRIA_DOWN")
|
||||
else:
|
||||
row.label(text=f"{total_components} Components", icon="TRIA_DOWN")
|
||||
|
||||
if NestData.data["has_related_objects"]:
|
||||
op = row.operator("bim.select_components", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
@@ -88,7 +88,7 @@ class ExecuteIfcPatch(bpy.types.Operator):
|
||||
file = ifcopenshell.open(props.ifc_patch_input)
|
||||
|
||||
# Store this in case the patch recipe resets the Blender session, such as by loading a new project.
|
||||
ifc_patch_output = props.ifc_patch_output
|
||||
ifc_patch_output = props.ifc_patch_output or props.ifc_patch_input
|
||||
|
||||
output = ifcpatch.execute(
|
||||
{
|
||||
@@ -100,6 +100,7 @@ class ExecuteIfcPatch(bpy.types.Operator):
|
||||
}
|
||||
)
|
||||
ifcpatch.write(output, ifc_patch_output)
|
||||
self.report({"INFO"}, f"{props.ifc_patch_recipes} patch executed successfully")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ def get_ifcpatch_recipes(self, context):
|
||||
continue
|
||||
docs = ifcpatch.extract_docs(f, "Patcher", "__init__", ("src", "file", "logger", "args"))
|
||||
ifcpatchrecipes_enum.append((f, f, docs.get("description", "") if docs else ""))
|
||||
return ifcpatchrecipes_enum
|
||||
return sorted(ifcpatchrecipes_enum, key=lambda x: x[0])
|
||||
|
||||
|
||||
def update_ifc_patch_recipe(self, context):
|
||||
|
||||
@@ -683,7 +683,7 @@ class RevertProject(bpy.types.Operator, IFCFileSelector):
|
||||
bl_idname = "bim.revert_project"
|
||||
bl_label = "Revert IFC Project"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Reload currently opened IFC project discarding all unsaved changes"
|
||||
bl_description = "Revert to a fresh session discarding all unsaved changes"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@@ -1105,6 +1105,7 @@ class ExportIFC(bpy.types.Operator):
|
||||
save_blend_file = bool(bpy.data.is_saved and bpy.data.is_dirty and bpy.data.filepath)
|
||||
if save_blend_file:
|
||||
bpy.ops.wm.save_mainfile(filepath=bpy.data.filepath)
|
||||
bpy.context.scene.BIMProperties.is_dirty = False
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
self.report(
|
||||
{"INFO"},
|
||||
|
||||
@@ -157,6 +157,7 @@ class BIMProjectProperties(PropertyGroup):
|
||||
is_coordinating: BoolProperty(name="For Coordination Only", default=False)
|
||||
deflection_tolerance: FloatProperty(name="Deflection Tolerance", default=0.001)
|
||||
angular_tolerance: FloatProperty(name="Angular Tolerance", default=0.5)
|
||||
void_limit: IntProperty(name="Void Limit", default=30)
|
||||
distance_limit: FloatProperty(name="Distance Limit", default=1000)
|
||||
false_origin: StringProperty(name="False Origin", default="0,0,0")
|
||||
element_offset: IntProperty(name="Element Offset", default=0)
|
||||
|
||||
@@ -146,6 +146,8 @@ class BIM_PT_project(Panel):
|
||||
row = self.layout.row()
|
||||
row.prop(pprops, "angular_tolerance")
|
||||
row = self.layout.row()
|
||||
row.prop(pprops, "void_limit")
|
||||
row = self.layout.row()
|
||||
row.prop(pprops, "distance_limit")
|
||||
row = self.layout.row()
|
||||
row.prop(pprops, "false_origin")
|
||||
@@ -206,12 +208,14 @@ class BIM_PT_project(Panel):
|
||||
|
||||
if props.ifc_file:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Saved", icon="EXPORT")
|
||||
if context.scene.BIMProperties.is_dirty:
|
||||
row.label(text="Saved*", icon="EXPORT")
|
||||
else:
|
||||
row.label(text="Saved", icon="EXPORT")
|
||||
row.label(text=ProjectData.data["last_saved"])
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "ifc_file", text="")
|
||||
row.operator("bim.reload_ifc_file", icon="FILE_REFRESH", text="")
|
||||
row.operator("bim.select_ifc_file", icon="FILE_FOLDER", text="")
|
||||
row.operator("bim.unload_project", text="", icon="CANCEL")
|
||||
else:
|
||||
@@ -399,11 +403,3 @@ class BIM_PT_purge(Panel):
|
||||
layout = self.layout
|
||||
layout.operator("bim.purge_unused_profiles")
|
||||
layout.operator("bim.purge_unused_types")
|
||||
layout.operator("bim.purge_unused_representations")
|
||||
layout.separator()
|
||||
|
||||
layout.label(text="Purge unused elements by class:")
|
||||
row = layout.row(align=True)
|
||||
row.prop(context.scene.BIMDebugProperties, "ifc_class_purge", text="")
|
||||
row.operator("bim.purge_unused_elements_by_class", text="", icon="TRASH")
|
||||
row.operator("bim.print_unused_elements_stats", text="", icon="INFO")
|
||||
|
||||
@@ -44,6 +44,7 @@ classes = (
|
||||
prop.MaterialSetItemPsetProperties,
|
||||
prop.TaskPsetProperties,
|
||||
prop.ResourcePsetProperties,
|
||||
prop.GroupPsetProperties,
|
||||
prop.ProfilePsetProperties,
|
||||
prop.WorkSchedulePsetProperties,
|
||||
prop.RenameProperties,
|
||||
@@ -57,6 +58,8 @@ classes = (
|
||||
ui.BIM_PT_task_qtos,
|
||||
ui.BIM_PT_resource_qtos,
|
||||
ui.BIM_PT_resource_psets,
|
||||
ui.BIM_PT_group_psets,
|
||||
ui.BIM_PT_group_qtos,
|
||||
ui.BIM_PT_profile_psets,
|
||||
ui.BIM_PT_work_schedule_psets,
|
||||
ui.BIM_PT_bulk_property_editor,
|
||||
@@ -73,6 +76,7 @@ def register():
|
||||
bpy.types.Material.PsetProperties = bpy.props.PointerProperty(type=prop.MaterialPsetProperties)
|
||||
bpy.types.Scene.TaskPsetProperties = bpy.props.PointerProperty(type=prop.TaskPsetProperties)
|
||||
bpy.types.Scene.ResourcePsetProperties = bpy.props.PointerProperty(type=prop.ResourcePsetProperties)
|
||||
bpy.types.Scene.GroupPsetProperties = bpy.props.PointerProperty(type=prop.GroupPsetProperties)
|
||||
bpy.types.Scene.ProfilePsetProperties = bpy.props.PointerProperty(type=prop.ProfilePsetProperties)
|
||||
bpy.types.Scene.WorkSchedulePsetProperties = bpy.props.PointerProperty(type=prop.WorkSchedulePsetProperties)
|
||||
bpy.types.Scene.RenameProperties = bpy.props.CollectionProperty(type=prop.RenameProperties)
|
||||
@@ -85,6 +89,7 @@ def unregister():
|
||||
del bpy.types.Material.PsetProperties
|
||||
del bpy.types.Scene.TaskPsetProperties
|
||||
del bpy.types.Scene.ResourcePsetProperties
|
||||
del bpy.types.Scene.GroupPsetProperties
|
||||
del bpy.types.Scene.ProfilePsetProperties
|
||||
del bpy.types.Scene.WorkSchedulePsetProperties
|
||||
del bpy.types.Scene.RenameProperties
|
||||
|
||||
@@ -36,6 +36,8 @@ def refresh():
|
||||
TaskQtosData.is_loaded = False
|
||||
ResourceQtosData.is_loaded = False
|
||||
ResourcePsetsData.is_loaded = False
|
||||
GroupQtosData.is_loaded = False
|
||||
GroupPsetData.is_loaded = False
|
||||
ProfilePsetsData.is_loaded = False
|
||||
WorkSchedulePsetsData.is_loaded = False
|
||||
AddEditCustomPropertiesData.is_loaded = False
|
||||
@@ -89,7 +91,9 @@ class ObjectPsetsData(Data):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return []
|
||||
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(element.is_a(), pset_only=True)
|
||||
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(
|
||||
element.is_a(), ifcopenshell.util.element.get_predefined_type(element), pset_only=True
|
||||
)
|
||||
psetnames = cls.format_pset_enum(psets)
|
||||
assigned_names = ifcopenshell.util.element.get_psets(element, psets_only=True, should_inherit=False).keys()
|
||||
return [p for p in psetnames if p[0] not in assigned_names]
|
||||
@@ -100,7 +104,9 @@ class ObjectPsetsData(Data):
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return []
|
||||
qtos = blenderbim.bim.schema.ifc.psetqto.get_applicable(element.is_a(), qto_only=True)
|
||||
qtos = blenderbim.bim.schema.ifc.psetqto.get_applicable(
|
||||
element.is_a(), ifcopenshell.util.element.get_predefined_type(element), qto_only=True
|
||||
)
|
||||
return cls.format_pset_enum(qtos)
|
||||
|
||||
@classmethod
|
||||
@@ -205,6 +211,30 @@ class ResourcePsetsData(Data):
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class GroupQtosData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
props = bpy.context.scene.BIMGroupProperties
|
||||
ifc_definition_id = props.groups[props.active_group_index].ifc_definition_id
|
||||
cls.data = {"qtos": cls.psetqtos(tool.Ifc.get_entity_by_id(ifc_definition_id), qtos_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class GroupPsetData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
props = bpy.context.scene.BIMGroupProperties
|
||||
ifc_definition_id = props.groups[props.active_group_index].ifc_definition_id
|
||||
cls.data = {"psets": cls.psetqtos(tool.Ifc.get_entity_by_id(ifc_definition_id), psets_only=True)}
|
||||
cls.is_loaded = True
|
||||
|
||||
|
||||
class ProfilePsetsData(Data):
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@@ -58,7 +58,8 @@ def get_pset_props(context, obj, obj_type):
|
||||
return context.scene.ProfilePsetProperties
|
||||
elif obj_type == "WorkSchedule":
|
||||
return context.scene.WorkSchedulePsetProperties
|
||||
|
||||
elif obj_type == "Group":
|
||||
return context.scene.GroupPsetProperties
|
||||
|
||||
class TogglePsetExpansion(bpy.types.Operator, Operator):
|
||||
bl_idname = "bim.toggle_pset_expansion"
|
||||
@@ -196,6 +197,7 @@ class EnablePsetEditing(bpy.types.Operator):
|
||||
new.is_selected = enum in selected_enum_items
|
||||
|
||||
def load_from_pset_data(self, pset):
|
||||
props = []
|
||||
if pset.is_a("IfcElementQuantity"):
|
||||
props = pset.Quantities
|
||||
elif pset.is_a("IfcPropertySet"):
|
||||
|
||||
@@ -130,6 +130,23 @@ def get_resource_qto_names(self, context):
|
||||
return qtonames[ifc_class]
|
||||
|
||||
|
||||
def get_group_pset_names(self, context):
|
||||
global psetnames
|
||||
ifc_class = "IfcGroup"
|
||||
if ifc_class not in psetnames:
|
||||
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, pset_only=True)
|
||||
psetnames[ifc_class] = blender_formatted_enum_from_psets(psets)
|
||||
return psetnames[ifc_class]
|
||||
|
||||
|
||||
def get_group_qto_names(self, context):
|
||||
global qtonames
|
||||
ifc_class = "IfcGroup"
|
||||
if ifc_class not in qtonames:
|
||||
psets = blenderbim.bim.schema.ifc.psetqto.get_applicable(ifc_class, qto_only=True)
|
||||
qtonames[ifc_class] = blender_formatted_enum_from_psets(psets)
|
||||
return qtonames[ifc_class]
|
||||
|
||||
def get_profile_pset_names(self, context):
|
||||
global psetnames
|
||||
pprops = context.scene.BIMProfileProperties
|
||||
@@ -229,6 +246,14 @@ class ResourcePsetProperties(PropertyGroup):
|
||||
qto_name: EnumProperty(items=get_resource_qto_names, name="Qto Name")
|
||||
|
||||
|
||||
class GroupPsetProperties(PropertyGroup):
|
||||
active_pset_id: IntProperty(name="Active Pset ID")
|
||||
active_pset_name: StringProperty(name="Pset Name")
|
||||
active_pset_type: StringProperty(name="Active Pset Type")
|
||||
properties: CollectionProperty(name="Properties", type=IfcProperty)
|
||||
pset_name: EnumProperty(items=get_group_pset_names, name="Pset Name")
|
||||
qto_name: EnumProperty(items=get_group_qto_names, name="Qto Name")
|
||||
|
||||
class ProfilePsetProperties(PropertyGroup):
|
||||
active_pset_id: IntProperty(name="Active Pset ID")
|
||||
active_pset_name: StringProperty(name="Pset Name")
|
||||
|
||||
@@ -29,8 +29,11 @@ from blenderbim.bim.module.pset.data import (
|
||||
TaskQtosData,
|
||||
ResourceQtosData,
|
||||
ResourcePsetsData,
|
||||
GroupQtosData,
|
||||
GroupPsetData,
|
||||
ProfilePsetsData,
|
||||
WorkSchedulePsetsData,
|
||||
|
||||
)
|
||||
|
||||
|
||||
@@ -470,6 +473,76 @@ class BIM_PT_resource_psets(Panel):
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Resource")
|
||||
|
||||
|
||||
class BIM_PT_group_qtos(Panel):
|
||||
bl_label = "Group Quantity Sets"
|
||||
bl_idname = "BIM_PT_group_qtos"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_groups"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BIMGroupProperties
|
||||
total_resources = len(props.groups)
|
||||
if total_resources > 0 and props.active_group_index < total_resources:
|
||||
return True
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not GroupQtosData.is_loaded:
|
||||
GroupQtosData.load()
|
||||
|
||||
props = context.scene.GroupPsetProperties
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "qto_name", text="")
|
||||
op = row.operator("bim.add_qto", icon="ADD", text="")
|
||||
op.obj_type = "Group"
|
||||
|
||||
if not props.active_pset_id and props.active_pset_name and props.active_pset_type == "QTO":
|
||||
draw_psetqto_ui(context, 0, {}, props, self.layout, "Group")
|
||||
|
||||
for qto in GroupQtosData.data["qtos"]:
|
||||
draw_psetqto_ui(context, qto["id"], qto, props, self.layout, "Group")
|
||||
|
||||
|
||||
class BIM_PT_group_psets(Panel):
|
||||
bl_label = "Group Property Sets"
|
||||
bl_idname = "BIM_PT_group_psets"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_groups"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BIMGroupProperties
|
||||
total_resources = len(props.groups)
|
||||
if total_resources > 0 and props.active_group_index < total_resources:
|
||||
return True
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not GroupPsetData.is_loaded:
|
||||
GroupPsetData.load()
|
||||
|
||||
props = context.scene.GroupPsetProperties
|
||||
row = self.layout.row(align=True)
|
||||
prop_with_search(row, props, "pset_name", text="")
|
||||
op = row.operator("bim.add_pset", icon="ADD", text="")
|
||||
op.obj_type = "Group"
|
||||
|
||||
if not props.active_pset_id and props.active_pset_name and props.active_pset_type == "PSET":
|
||||
draw_psetqto_ui(context, 0, {}, props, self.layout, "Group")
|
||||
|
||||
for pset in GroupPsetData.data["psets"]:
|
||||
draw_psetqto_ui(context, pset["id"], pset, props, self.layout, "Group")
|
||||
|
||||
|
||||
|
||||
|
||||
class BIM_PT_profile_psets(Panel):
|
||||
bl_label = "Profile Property Sets"
|
||||
bl_idname = "BIM_PT_profile_psets"
|
||||
|
||||
@@ -20,6 +20,7 @@ import os
|
||||
import bpy
|
||||
import pathlib
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.attribute
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
@@ -36,6 +37,7 @@ class PsetTemplatesData:
|
||||
def load(cls):
|
||||
cls.is_loaded = True
|
||||
cls.data["primary_measure_type"] = cls.primary_measure_type()
|
||||
cls.data["property_template_type"] = cls.property_template_type()
|
||||
cls.data["pset_template_files"] = cls.pset_template_files()
|
||||
cls.data["pset_templates"] = cls.pset_templates()
|
||||
cls.data["pset_template"] = cls.pset_template()
|
||||
@@ -43,13 +45,25 @@ class PsetTemplatesData:
|
||||
|
||||
@classmethod
|
||||
def primary_measure_type(cls):
|
||||
schema = tool.Ifc.schema()
|
||||
version = tool.Ifc.get_schema()
|
||||
ifc_file = IfcStore.pset_template_file
|
||||
if not ifc_file:
|
||||
return []
|
||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
||||
version = ifc_file.schema
|
||||
return [
|
||||
(t, t, ifcopenshell.util.doc.get_type_doc(version, t).get("description", ""))
|
||||
for t in sorted([d.name() for d in schema.declarations() if hasattr(d, "declared_type")])
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def property_template_type(cls):
|
||||
ifc_file = IfcStore.pset_template_file
|
||||
if not ifc_file:
|
||||
return []
|
||||
schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(ifc_file.schema)
|
||||
attribute = schema.declaration_by_name("IfcSimplePropertyTemplate").attributes()[0]
|
||||
return [(i, i, "") for i in ifcopenshell.util.attribute.get_enum_items(attribute)]
|
||||
|
||||
@classmethod
|
||||
def pset_template_files(cls):
|
||||
results = []
|
||||
|
||||
@@ -307,7 +307,8 @@ class EditPropTemplate(bpy.types.Operator, Operator):
|
||||
bpy.ops.bim.disable_editing_prop_template()
|
||||
IfcStore.pset_template_file.write(IfcStore.pset_template_path)
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
blenderbim.bim.schema.reload(tool.Ifc.get().schema)
|
||||
if tool.Ifc.get():
|
||||
blenderbim.bim.schema.reload(tool.Ifc.get().schema)
|
||||
|
||||
# TODO -This will need to go into the
|
||||
# api code at some point - vulevukusej
|
||||
|
||||
@@ -42,6 +42,8 @@ def updatePsetTemplateFiles(self, context):
|
||||
PsetTemplatesData.data["pset_template_files"] = PsetTemplatesData.pset_template_files()
|
||||
PsetTemplatesData.data["pset_templates"] = PsetTemplatesData.pset_templates()
|
||||
PsetTemplatesData.data["prop_templates"] = PsetTemplatesData.prop_templates()
|
||||
PsetTemplatesData.data["primary_measure_type"] = PsetTemplatesData.primary_measure_type()
|
||||
PsetTemplatesData.data["property_template_type"] = PsetTemplatesData.property_template_type()
|
||||
|
||||
|
||||
def getPsetTemplateFiles(self, context):
|
||||
@@ -67,6 +69,12 @@ def get_primary_measure_type(self, context):
|
||||
return PsetTemplatesData.data["primary_measure_type"]
|
||||
|
||||
|
||||
def get_property_template_type(self, context):
|
||||
if not PsetTemplatesData.is_loaded:
|
||||
PsetTemplatesData.load()
|
||||
return PsetTemplatesData.data["property_template_type"]
|
||||
|
||||
|
||||
def get_template_type(self, context):
|
||||
return [
|
||||
(
|
||||
@@ -157,10 +165,7 @@ class PropTemplate(PropertyGroup):
|
||||
description=get_attribute_doc("IFC4", "IfcPropertyTemplate", "Description"),
|
||||
)
|
||||
primary_measure_type: EnumProperty(items=get_primary_measure_type, name="Primary Measure Type")
|
||||
template_type: EnumProperty(
|
||||
items=[("P_SINGLEVALUE", "P_SINGLEVALUE", ""), ("P_ENUMERATEDVALUE", "P_ENUMERATEDVALUE", "")],
|
||||
name="Template Type",
|
||||
)
|
||||
template_type: EnumProperty(items=get_property_template_type, name="Template Type")
|
||||
enum_values: CollectionProperty(type=EnumerationValues)
|
||||
|
||||
def get_value_name(self):
|
||||
|
||||
@@ -158,6 +158,9 @@ class AssignClass(bpy.types.Operator, Operator):
|
||||
ifc_context = tool.Ifc.get().by_id(ifc_context)
|
||||
active_object = context.active_object
|
||||
for obj in objects:
|
||||
if obj.mode != "OBJECT":
|
||||
self.report({"ERROR"}, "Object must be in OBJECT mode to assign class")
|
||||
continue
|
||||
core.assign_class(
|
||||
tool.Ifc,
|
||||
tool.Collector,
|
||||
@@ -177,48 +180,45 @@ class UnlinkObject(bpy.types.Operator):
|
||||
bl_label = "Unlink Object"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
should_delete: bpy.props.BoolProperty(name="Should Delete", default=True)
|
||||
should_delete: bpy.props.BoolProperty(name="Delete IFC Element", default=True)
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
if self.obj:
|
||||
objects = [bpy.data.objects.get(self.obj)]
|
||||
else:
|
||||
objects = context.selected_objects
|
||||
|
||||
for obj in objects:
|
||||
was_active_object = obj == context.active_object
|
||||
object_name = obj.name
|
||||
|
||||
if obj in IfcStore.edited_objs:
|
||||
IfcStore.edited_objs.remove(obj)
|
||||
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if element:
|
||||
if self.should_delete:
|
||||
obj_copy = obj.copy()
|
||||
if element and self.should_delete:
|
||||
object_name = obj.name
|
||||
|
||||
# copy object data, so it won't be removed by `delete_ifc_object`
|
||||
if obj.data:
|
||||
obj_copy.data = obj.data.copy()
|
||||
if obj.type == "MESH":
|
||||
obj_copy.data.BIMMeshProperties.ifc_definition_id = 0
|
||||
# Copy object, so it won't be removed by `delete_ifc_object`
|
||||
obj_copy = obj.copy()
|
||||
if obj.data:
|
||||
obj_copy.data = obj.data.copy()
|
||||
|
||||
for collection in obj.users_collection:
|
||||
collection.objects.link(obj_copy)
|
||||
tool.Geometry.delete_ifc_object(obj)
|
||||
obj = obj_copy
|
||||
if obj in IfcStore.edited_objs:
|
||||
IfcStore.edited_objs.remove(obj)
|
||||
tool.Ifc.unlink(obj=obj)
|
||||
tool.Geometry.delete_ifc_object(obj)
|
||||
|
||||
for material_slot in obj.material_slots:
|
||||
if material_slot.material:
|
||||
material_slot.material = material_slot.material.copy()
|
||||
blenderbim.core.style.unlink_style(tool.Ifc, tool.Style, obj=material_slot.material)
|
||||
blenderbim.core.material.unlink_material(tool.Ifc, obj=material_slot.material)
|
||||
if "Ifc" in object_name and "/" in object_name:
|
||||
obj.name = object_name.split("/", 1)[1]
|
||||
if was_active_object:
|
||||
tool.Blender.set_active_object(obj)
|
||||
obj = obj_copy
|
||||
obj.name = object_name
|
||||
|
||||
tool.Root.unlink_object(obj)
|
||||
for collection in obj.users_collection:
|
||||
# Reset collection because its original collection may be removed too.
|
||||
collection.objects.unlink(obj)
|
||||
bpy.context.scene.collection.objects.link(obj)
|
||||
|
||||
if was_active_object:
|
||||
tool.Blender.set_active_object(obj)
|
||||
return {"FINISHED"}
|
||||
|
||||
def draw(self, context):
|
||||
|
||||
@@ -116,8 +116,9 @@ class BIMSearchProperties(PropertyGroup):
|
||||
("classification", "Classification", "", "OUTLINER", 4),
|
||||
("location", "Location", "", "PACKAGE", 5),
|
||||
("type", "Type", "", "FILE_VOLUME", 6),
|
||||
("query", "Query", "", "POINTCLOUD_DATA", 7),
|
||||
("instance", "GlobalId", "", "GRIP", 8),
|
||||
("group", "Group", "", "OUTLINER_COLLECTION", 7),
|
||||
("query", "Query", "", "POINTCLOUD_DATA", 8),
|
||||
("instance", "GlobalId", "", "GRIP", 9),
|
||||
],
|
||||
)
|
||||
saved_searches: EnumProperty(items=get_saved_searches, name="Saved Searches")
|
||||
|
||||
@@ -32,7 +32,7 @@ class SpatialData:
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"parent_container_id": cls.get_parent_container_id(),
|
||||
"parent_container_id": cls.parent_container_id(),
|
||||
"is_directly_contained": cls.is_directly_contained(),
|
||||
"label": cls.label(),
|
||||
"references": cls.references(),
|
||||
@@ -55,12 +55,12 @@ class SpatialData:
|
||||
return results
|
||||
|
||||
@classmethod
|
||||
def get_parent_container_id(cls):
|
||||
def parent_container_id(cls):
|
||||
container_id = bpy.context.scene.BIMSpatialProperties.active_container_id
|
||||
if not container_id:
|
||||
return
|
||||
container = tool.Ifc.get().by_id(container_id)
|
||||
if container.is_a("IfcProject"):
|
||||
container = tool.Ifc.get_entity_by_id(container_id)
|
||||
if not container or container.is_a("IfcProject"):
|
||||
return
|
||||
return container.Decomposes[0].RelatingObject.id()
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user