Compare commits
423 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a8bdeeaa3 | |||
| 6b46ff71a6 | |||
| d73a5c46ea | |||
| 037261afb9 | |||
| be87b17909 | |||
| 932a21309f | |||
| 7a1b35f7e2 | |||
| 79dcf809ed | |||
| 2f53e43b90 | |||
| cdc9180111 | |||
| a936a5317d | |||
| f5e5ede0fa | |||
| 2d1ddea3d0 | |||
| df932b90d6 | |||
| 2514e93a8d | |||
| 64e6561828 | |||
| 76685d236c | |||
| fd83564af0 | |||
| 37e3a65ffb | |||
| e5cf0cde2d | |||
| 78e4478242 | |||
| 3497022c78 | |||
| 810d36781c | |||
| f8eb1c178a | |||
| b726ba7816 | |||
| 4ab23d231d | |||
| 00694854af | |||
| fa52ed6dbc | |||
| 319b59a266 | |||
| 357fcded71 | |||
| c3cc5881df | |||
| 56046dd6f9 | |||
| 9164a7bcc3 | |||
| e0a5c9c8f3 | |||
| 22e087c82a | |||
| 57396e1bb9 | |||
| 389076bff4 | |||
| bfcc067257 | |||
| f88ac5de62 | |||
| cdd456bede | |||
| 7041d17c16 | |||
| de842f7aba | |||
| 6107c39c1c | |||
| 9584687fcf | |||
| b231e9051b | |||
| 40f9875930 | |||
| 328773550d | |||
| 303544dc5c | |||
| 1c66f986cc | |||
| e801629f86 | |||
| 74bbd6d116 | |||
| e06794ef3d | |||
| cd7062c905 | |||
| 42d476cbb0 | |||
| cd0d3908d3 | |||
| cb70f97789 | |||
| 572ed0db0f | |||
| 43d78af767 | |||
| c7aa42bfd5 | |||
| 18d7193efc | |||
| 8da92557cc | |||
| 761b4c035f | |||
| ee0f7f1677 | |||
| dca2e58586 | |||
| 3810255f04 | |||
| d3ca647cd5 | |||
| 8b35a3aadd | |||
| 78314b1ec7 | |||
| ef88b30639 | |||
| 5e815e7832 | |||
| e7b153cbf6 | |||
| 9b855bed2d | |||
| 3143f8c9a5 | |||
| 8dd781aea2 | |||
| 0506475f26 | |||
| ac092fb6f8 | |||
| 9beddca2f7 | |||
| 6d9770542f | |||
| 544d6ee695 | |||
| b8963b3d6e | |||
| f2bd46d699 | |||
| 8ac8ad33b3 | |||
| 44bbd17d97 | |||
| 8f0e67a35b | |||
| d2d4112724 | |||
| 209eea6a18 | |||
| 85426b3fef | |||
| c602f0f233 | |||
| bb6312e174 | |||
| d6d70af5a0 | |||
| 8187c75183 | |||
| 01cfcebb09 | |||
| 75040b6ffb | |||
| 6c8858e51d | |||
| 6bb63817af | |||
| 1e299a0ddd | |||
| 3201c234fa | |||
| f5d27621e7 | |||
| 3e1eb9648f | |||
| 5f9474acb7 | |||
| f4e6e924b1 | |||
| bcfc97037c | |||
| 65d0abd072 | |||
| 776c68e2b0 | |||
| dab2d5ce04 | |||
| 29b33661d7 | |||
| 5dec636584 | |||
| d11b91f152 | |||
| b0fc98e384 | |||
| 56f09d2541 | |||
| 4484b77232 | |||
| f6c054066b | |||
| d5c70e51f2 | |||
| cab9e4d892 | |||
| 14cd8289ea | |||
| 4202c08487 | |||
| a70fb41652 | |||
| df437fd3e3 | |||
| 3102dbcd44 | |||
| 9d838db096 | |||
| 0c9d555693 | |||
| 4b637c7049 | |||
| fd3a873bbd | |||
| 5cea988911 | |||
| 70fcbfa990 | |||
| c541aa78e5 | |||
| b821e62391 | |||
| 41141b8fc9 | |||
| ae0789e4ec | |||
| 13d4a99358 | |||
| becb375ec2 | |||
| a777a558bd | |||
| de37aeb515 | |||
| 23be1a6939 | |||
| 8edced5a0c | |||
| 21937e88e8 | |||
| f7da83737a | |||
| 27663d80ba | |||
| 4ec5d4fc65 | |||
| 2b34ca9eb7 | |||
| 2bb9810072 | |||
| c7e87324de | |||
| ec62d8fbb9 | |||
| 7b5aae9487 | |||
| 12c94fafab | |||
| 09be170820 | |||
| 966af5a757 | |||
| 89557460c8 | |||
| 2bad6b2722 | |||
| e5cd30c6d0 | |||
| 6f2da2896e | |||
| 0387c778f4 | |||
| 76568ea67c | |||
| 8e2a1a1649 | |||
| cb5f57d68a | |||
| e7c6f28312 | |||
| 1820f72bc4 | |||
| 1631dc39f5 | |||
| d2f19e7c28 | |||
| 736703336c | |||
| 44df1f676d | |||
| f1ffb81c86 | |||
| 08ec3fc73f | |||
| f1d7cf1dfb | |||
| 1ee488b148 | |||
| ecb9827e7f | |||
| 88f26eaead | |||
| ce03742aab | |||
| 62540f0b00 | |||
| 406b8b4540 | |||
| ca24838a3f | |||
| ff7219b557 | |||
| 711acfe120 | |||
| f1acda85c9 | |||
| 228f62d218 | |||
| 6186a88568 | |||
| 074a8c287f | |||
| d4736710a5 | |||
| 0bc86631a5 | |||
| 9751b6af05 | |||
| 6d641aaac1 | |||
| 489a248e9a | |||
| 9c00872a57 | |||
| d77bc6bdaa | |||
| 911d703f57 | |||
| 09bf5b85aa | |||
| 41a694d0dc | |||
| 6232ee36f9 | |||
| 5b1cc2cab5 | |||
| f706adfb81 | |||
| b0358a5a7b | |||
| eb09cc8af8 | |||
| 7c61c7d200 | |||
| 92d28901ac | |||
| 32769184b0 | |||
| de7f1d9d46 | |||
| cbd0c8a410 | |||
| f4f40c4b16 | |||
| f9d70fd51d | |||
| bb43405299 | |||
| 00cb3cd0db | |||
| 823f988536 | |||
| d95977a784 | |||
| 4f9991fb13 | |||
| d8b2cc77cc | |||
| 077f9b701d | |||
| 36ade628cf | |||
| 0f59f3e35a | |||
| 31e7bad056 | |||
| eee693dfcb | |||
| 4a8e03862b | |||
| 04f7fc0bdb | |||
| fbe9bb1ee2 | |||
| ca59b3220b | |||
| 39c8c8db37 | |||
| f49de02ab7 | |||
| 8b0a7821b1 | |||
| 0f365cadbd | |||
| 0bc76b1af7 | |||
| efce28c053 | |||
| 071505038d | |||
| 98938acb26 | |||
| 4817360ecd | |||
| b8e3fbba8c | |||
| 49ea774851 | |||
| f4f2a3d24e | |||
| a25ca91ba6 | |||
| fded9b3523 | |||
| 9257f275af | |||
| 40039e65df | |||
| dbce9ec049 | |||
| b9c5c28c54 | |||
| 184a189f2a | |||
| 37f549927d | |||
| a5fe3e77e7 | |||
| 708da97bbd | |||
| f80792091f | |||
| a1e34b0acb | |||
| e618232e70 | |||
| 922fc2beda | |||
| 4564ee3476 | |||
| 510dca1aca | |||
| 5604db8072 | |||
| 5961253c29 | |||
| 624e296d24 | |||
| 6ad605fbeb | |||
| 797a5ec1a0 | |||
| d56869d341 | |||
| 405e8bc5aa | |||
| b607242339 | |||
| f57aa77ac2 | |||
| 01cc1887e0 | |||
| 003441a451 | |||
| 4b64f09aaa | |||
| 4afcca8550 | |||
| 1a7ea1ea05 | |||
| 5616a6ede5 | |||
| 28fa774a9a | |||
| 52d4fa4781 | |||
| 9258dc3104 | |||
| 469fb9c204 | |||
| f7175a67c8 | |||
| ebfaeafeee | |||
| 1f68c3f612 | |||
| aceb2140ad | |||
| 310d13ac75 | |||
| bc2ac6b31a | |||
| 059c405652 | |||
| 28d168b96c | |||
| e4640df6f0 | |||
| 5c3642e1d1 | |||
| 615f567ebf | |||
| a56ca661e8 | |||
| 8ee9835e27 | |||
| b26147c1c7 | |||
| c3847ff38a | |||
| 8299505672 | |||
| 0db743d3f7 | |||
| e7558d0008 | |||
| c9f40126c3 | |||
| b0554e71d5 | |||
| 1bed25408f | |||
| 603a034ac6 | |||
| 6f802ed770 | |||
| c1b9062fa4 | |||
| e4f591babf | |||
| e9c84d1c11 | |||
| e62b7e94a4 | |||
| e89d540236 | |||
| fa23f64e9f | |||
| cfaa90b1fb | |||
| dc909f1fc6 | |||
| 30fc2ad580 | |||
| c542fb2480 | |||
| 25717d002f | |||
| 0181bd7e56 | |||
| 71c6bba36d | |||
| eb539666d9 | |||
| e43eec6203 | |||
| 4ca64ac42e | |||
| f51e0db7fe | |||
| b1e8e0a968 | |||
| be66a98cfa | |||
| 76487ea3bf | |||
| 13fe011c75 | |||
| 266a341c6b | |||
| a5bcbe046f | |||
| ab057e3eff | |||
| 6aa0651190 | |||
| 0f296c486f | |||
| 29f64f7c11 | |||
| d2d4a1b976 | |||
| 249ff95920 | |||
| 4c8d12d978 | |||
| 04d02feb86 | |||
| e6700ea29b | |||
| 9c7c3d7078 | |||
| 0d3175c6ef | |||
| 04abadac22 | |||
| 0b39226869 | |||
| 9e31991e75 | |||
| b40bd681b1 | |||
| 63384a730b | |||
| b9f81b8014 | |||
| c34f357301 | |||
| beb58b89fe | |||
| 97df037c93 | |||
| a7d8bffca5 | |||
| b5f58dc113 | |||
| 4e889b75d7 | |||
| 36cfb0d3f5 | |||
| 5921bcb63d | |||
| 23ad1a8005 | |||
| f257aef8f4 | |||
| 3eacd809b0 | |||
| e1b90ed3b2 | |||
| 28c2d7248e | |||
| 3bee746f49 | |||
| eeb27bb1c7 | |||
| d50c89abee | |||
| 15cf3f5afd | |||
| 1e22dbca1e | |||
| 28fbf0ea99 | |||
| d874a0089d | |||
| 441d842f67 | |||
| 667ac307c3 | |||
| c81031819c | |||
| 7cbb87284c | |||
| d0a9edd186 | |||
| 425379aaad | |||
| 25d86a50c5 | |||
| 0286cd370d | |||
| 0178804feb | |||
| 1892e9cc86 | |||
| 1b46f5c83a | |||
| 3a0edab8c1 | |||
| 7032ee9f11 | |||
| fd19b2d730 | |||
| a65b9f2ba7 | |||
| 2db4a6f89f | |||
| 517b819504 | |||
| a0f79cc0db | |||
| 67666ed70e | |||
| 6bcfa5946f | |||
| 52691b7ee5 | |||
| 780ea707b0 | |||
| 7e7cfbdd5f | |||
| ab102176cc | |||
| d7f289bc8a | |||
| 95a34cb8d0 | |||
| 8369818b88 | |||
| 5251bdabc6 | |||
| 83c33dd5b0 | |||
| bfc695c756 | |||
| 459faec01a | |||
| 4fb65199b8 | |||
| 08576e28d6 | |||
| b3f581d78d | |||
| 89d6b3d21a | |||
| d2bf2cf46e | |||
| 43b2982dbb | |||
| e750a134d0 | |||
| 6bbbc528fe | |||
| 7f4a436708 | |||
| e6592ca706 | |||
| cc2138463e | |||
| 6de3e55d19 | |||
| 595131e6e8 | |||
| 6966da3bdf | |||
| 4e897a0c21 | |||
| 73a9015801 | |||
| 1b2bebecb0 | |||
| e4dee2258d | |||
| 7de3eec1b1 | |||
| 20fe48bd6a | |||
| 1d6b2dcb37 | |||
| 45f3e677df | |||
| 65160f9bb4 | |||
| 333ba08841 | |||
| 2cb3b0817f | |||
| 4ea95960a2 | |||
| 10f4bca5d2 | |||
| d4a01618cd | |||
| c9c6529978 | |||
| 2829a0764b | |||
| 76d61cb4d4 | |||
| e9d2a39166 | |||
| d08f4171e3 | |||
| 23483eafb3 | |||
| 686ba2536b | |||
| 7d5ac99f34 | |||
| 9b8d224aca | |||
| 8939d93333 | |||
| 04aad216ba | |||
| 27eb9d340a | |||
| fbb53f93d8 | |||
| af6aed80da | |||
| 92ba412c95 | |||
| 110c382973 | |||
| 977df60f05 | |||
| 539d77b5ad | |||
| ea34c3de85 | |||
| 9374594920 |
@@ -0,0 +1,66 @@
|
||||
name: Publish-blenderbim-multiplatform
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'src/blenderbim/**'
|
||||
- '.github/workflows/ci-blenderbim-matrix.yml'
|
||||
|
||||
env:
|
||||
major: 0
|
||||
minor: 0
|
||||
name: blenderbim
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
steps:
|
||||
- name: Set env
|
||||
run: echo ok go
|
||||
|
||||
build:
|
||||
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py37, py39]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
short_name: win,
|
||||
}
|
||||
- {
|
||||
name: "Linux Build",
|
||||
short_name: linux
|
||||
}
|
||||
- {
|
||||
name: "MacOS Build",
|
||||
short_name: macos
|
||||
}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.7.7' # Version range or exact version of a Python version to use, using SemVer's version range syntax
|
||||
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
|
||||
- run: echo ${{ env.DATE }}
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "::set-output name=date::$(date +'%y%m%d')"
|
||||
- name: Compile
|
||||
run: |
|
||||
cp -r src/blenderbim src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
cd src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
|
||||
make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
- name: Upload Zip file to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blender28-bim-${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
asset_name: blender28-bim-${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
|
||||
tag: "blenderbim-${{steps.date.outputs.date}}"
|
||||
overwrite: true
|
||||
body: "Daily developer testing build blenderbim-${{steps.date.outputs.date}}"
|
||||
@@ -0,0 +1,107 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
activate:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.repository == 'IfcOpenShell/IfcOpenShell' &&
|
||||
!startsWith(github.event.head_commit.message, 'Release ') &&
|
||||
!contains(github.event.head_commit.message, 'ci skip')
|
||||
steps:
|
||||
- run: echo ok go
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: activate
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install --no-install-recommends \
|
||||
git cmake gcc g++ libboost1.67-all-dev python3-all-dev swig libpcre3-dev libxml2-dev \
|
||||
liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
|
||||
-
|
||||
name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
|
||||
-
|
||||
name: Build ifcopenshell
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_INSTALL_PREFIX=$PWD/install/ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DBUILD_PACKAGE=On \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/oce \
|
||||
-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 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES=/usr/lib/x86_64-linux-gnu/libxml2.so \
|
||||
../cmake
|
||||
make -j $(nproc)
|
||||
make install
|
||||
-
|
||||
name: Package
|
||||
run: |
|
||||
make package
|
||||
working-directory: build
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
# Artifact name
|
||||
name: ifcos-artifacts
|
||||
# Directory containing files to upload
|
||||
path: build/assets/Ifc*
|
||||
|
||||
deliver:
|
||||
runs-on: ubuntu-20.04
|
||||
needs: build
|
||||
name: Docker Build, Tag, Push
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: true
|
||||
|
||||
- name: Download
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
# Artifact name
|
||||
name: ifcos-artifacts
|
||||
path: artifacts/
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Login to Dockerhub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: aecgeeks
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
-
|
||||
name: Build container image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: artifacts
|
||||
repository: aecgeeks/ifcopenshell
|
||||
tags: aecgeeks/ifcopenshell:latest
|
||||
file: ./Dockerfile
|
||||
push: true
|
||||
@@ -0,0 +1,96 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v[0-9].[0-9].[0-9]*'
|
||||
|
||||
jobs:
|
||||
activate:
|
||||
if: github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo ok go
|
||||
build:
|
||||
needs: activate
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
lfs: true
|
||||
-
|
||||
name: Update ubuntu
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get install git cmake gcc g++ libboost1.67-all-dev python3-all-dev swig libpcre3-dev libxml2-dev
|
||||
sudo apt-get install liboce-foundation-dev liboce-modeling-dev liboce-ocaf-dev liboce-visualization-dev liboce-ocaf-lite-dev
|
||||
- name: Build
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake \
|
||||
-DCMAKE_INSTALL_PREFIX=$PWD/install/ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH=/usr \
|
||||
-DCMAKE_SYSTEM_PREFIX_PATH=/usr \
|
||||
-DBUILD_PACKAGE=On \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/oce \
|
||||
-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 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES=/usr/lib/x86_64-linux-gnu/libxml2.so \
|
||||
../cmake
|
||||
make -j $(nproc)
|
||||
make install
|
||||
- name: Package
|
||||
id: package
|
||||
run: |
|
||||
make package
|
||||
echo ::set-output name=tgz::$( ls assets/*.tar.gz | head -n 1 | xargs basename )
|
||||
echo ::set-output name=deb::$( ls assets/*.deb | head -n 1 | xargs basename )
|
||||
working-directory: build
|
||||
env:
|
||||
CHANGELOG_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Release
|
||||
id: release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
body: |
|
||||
Changes to this release
|
||||
- add github actions support #1306
|
||||
- add boost depends to ifcopenshell deb packaging
|
||||
- <add more changes here>
|
||||
See more details in the documentation
|
||||
# body_path: build/CHANGELOG.md
|
||||
- name: Upload TGZ
|
||||
id: upload-tgz
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||
asset_path: build/assets/${{ steps.package.outputs.tgz }}
|
||||
asset_name: ${{ steps.package.outputs.tgz }}
|
||||
asset_content_type: application/x-gzip
|
||||
- name: Upload DEB
|
||||
id: upload-deb
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
|
||||
asset_path: build/assets/${{ steps.package.outputs.deb }}
|
||||
asset_name: ${{ steps.package.outputs.deb }}
|
||||
asset_content_type: application/vnd.debian.binary-package
|
||||
@@ -1,4 +1,7 @@
|
||||
# Dependency and build folders created by the build scripts
|
||||
/_build-vs2017-x64/
|
||||
/_deps-vs2017-x64-installed/
|
||||
/_deps/
|
||||
/deps*/
|
||||
/build*/
|
||||
/install*/
|
||||
@@ -23,3 +26,5 @@ __pycache__
|
||||
*.mo
|
||||
# Vim
|
||||
*.swp
|
||||
|
||||
|
||||
|
||||
@@ -1,56 +1,60 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
cache: ccache
|
||||
os: linux
|
||||
dist: bionic
|
||||
sudo: required
|
||||
dist: focal
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- libboost-date-time-dev
|
||||
- libboost-filesystem-dev
|
||||
- libboost-iostreams-dev
|
||||
- libboost-program-options-dev
|
||||
- libboost-regex-dev
|
||||
- libboost-system-dev
|
||||
- libboost-thread-dev
|
||||
- libocct-data-exchange-dev
|
||||
- libocct-foundation-dev
|
||||
- libocct-modeling-algorithms-dev
|
||||
- libocct-modeling-data-dev
|
||||
- libxml2-dev
|
||||
- nlohmann-json3-dev
|
||||
- opencollada-dev
|
||||
- python3-all-dev
|
||||
- swig
|
||||
|
||||
before_install:
|
||||
- "sudo add-apt-repository -y ppa:freecad-community/ppa"
|
||||
- sudo apt-get update -qq
|
||||
|
||||
|
||||
install:
|
||||
- |
|
||||
sudo apt-get install -y \
|
||||
libocct-data-exchange-dev libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev \
|
||||
libboost-system-dev libboost-program-options-dev libboost-regex-dev libboost-thread-dev libboost-date-time-dev libboost-iostreams-dev libboost-filesystem-dev \
|
||||
build-essential cmake python2.7 libpython2.7-dev swig zlib1g liblzma5 opencollada-dev wget apt-transport-https
|
||||
- sudo mkdir -p /usr/include/json/nlohmann/
|
||||
- sudo wget https://github.com/nlohmann/json/releases/download/v3.6.1/json.hpp -O /usr/include/json/nlohmann/json.hpp
|
||||
# - sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
|
||||
# - sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
|
||||
# - sudo apt-get update -qq && sudo apt-get install -y dart
|
||||
# - export PATH=$PATH:/usr/lib/dart/bin:$HOME/.pub-cache/bin
|
||||
# - git clone https://github.com/KhronosGroup/glTF-Validator && pushd glTF-Validator && pub get && pub global activate --source path ./ && popd
|
||||
before_script:
|
||||
- if [ $TRAVIS_OS_NAME == "linux" ]; then ccache -z; fi
|
||||
|
||||
script:
|
||||
- pwd
|
||||
- cd cmake
|
||||
- mkdir build
|
||||
- cd build
|
||||
- mkdir build && cd build
|
||||
- |
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
|
||||
-DPYTHON_LIBRARY=/usr/lib/python2.7/config-x86_64-linux-gnu/libpython2.7.so \
|
||||
-DPYTHON_INCLUDE_DIR=/usr/include/python2.7 \
|
||||
-DPYTHON_EXECUTABLE=/usr/bin/python2.7 \
|
||||
-DLIBXML2_INCLUDE_DIR=/usr/include/libxml2 \
|
||||
-DLIBXML2_LIBRARIES="/usr/lib/x86_64-linux-gnu/libxml2.so;/lib/x86_64-linux-gnu/libz.so.1;/lib/x86_64-linux-gnu/liblzma.so.5;/usr/lib/x86_64-linux-gnu/libicuuc.so.60;/usr/lib/x86_64-linux-gnu/libicudata.so.60" \
|
||||
-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 \
|
||||
-DGLTF_SUPPORT=On \
|
||||
-DJSON_INCLUDE_DIR=/usr/include/json \
|
||||
..
|
||||
- sudo make -j2 install
|
||||
-DJSON_INCLUDE_DIR=/usr/include \
|
||||
../cmake
|
||||
|
||||
# TODO: Drop sudo
|
||||
- sudo make -j $(nproc) install
|
||||
|
||||
- cd ../../test
|
||||
- /usr/bin/python2.7 tests.py
|
||||
- cd ../test
|
||||
- /usr/bin/python tests.py
|
||||
|
||||
- cd input
|
||||
|
||||
- /usr/local/bin/IfcConvert -yv acad2010_walls.ifc acad2010_walls.glb
|
||||
# - gltf_validator acad2010_walls.glb
|
||||
|
||||
- /usr/bin/python2.7 -c "from __future__ import print_function; from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); assert list(map(ord, f[1][0])) == [39, 97, 39, 32, 49, 109, 179, 32, 8804, 32, 53, 109, 179, 32, 8805, 32, 49, 48, 109, 179]"
|
||||
- /usr/bin/python -c "from io import open; import ifcopenshell; f = ifcopenshell.open('encoding.ifc'); assert list(map(ord, f[1][0])) == [39, 97, 39, 32, 49, 109, 179, 32, 8804, 32, 53, 109, 179, 32, 8805, 32, 49, 48, 109, 179]"
|
||||
|
||||
- |
|
||||
(for i in *.ifc; do \
|
||||
@@ -64,3 +68,6 @@ script:
|
||||
- echo Succeeded
|
||||
- grep 0$ statuses
|
||||
- grep 0$ statuses | wc -l
|
||||
|
||||
after_script:
|
||||
- if [ $TRAVIS_OS_NAME == "linux" ]; then ccache -s; fi
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- mode: Dockerfile -*-
|
||||
|
||||
FROM ubuntu:focal
|
||||
|
||||
ARG CHANNEL
|
||||
ENV CHANNEL=${CHANNEL:-latest}
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
vim \
|
||||
ssh \
|
||||
sudo \
|
||||
wget \
|
||||
software-properties-common ;\
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN useradd --user-group --create-home --shell /bin/bash IfcOpenShell ;\
|
||||
echo "IfcOpenShell ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN echo "deb http://archive.ubuntu.com/ubuntu focal-proposed main restricted" | tee -a /etc/apt/sources.list; \
|
||||
echo "deb http://archive.ubuntu.com/ubuntu focal-proposed universe" | tee -a /etc/apt/sources.list; \
|
||||
echo "deb http://archive.ubuntu.com/ubuntu focal-proposed multiverse" | tee -a /etc/apt/sources.list; \
|
||||
apt-get -qq update; \
|
||||
apt-get -y install tzdata dos2unix rsync; \
|
||||
apt-get -y install python3 libxml2 liboce-foundation11 liboce-modeling11 liboce-ocaf11 liboce-visualization11 \
|
||||
liboce-ocaf-lite11 libpython3.8 libboost-system1.67.0 libboost-program-options1.67.0 \
|
||||
libboost-regex1.67.0 libboost-thread1.67.0 libboost-date-time1.67.0; \
|
||||
rm -rf /var/lib/apt/lists/* ;
|
||||
|
||||
COPY . /home/IfcOpenShell/
|
||||
RUN ls -lrtR /home/IfcOpenShell
|
||||
|
||||
RUN dpkg -i /home/IfcOpenShell/*.deb
|
||||
|
||||
USER IfcOpenShell
|
||||
|
||||
@@ -19,8 +19,8 @@ Prerequisites
|
||||
Dependencies
|
||||
-------------
|
||||
* [Boost](http://www.boost.org/)
|
||||
* [Open Cascade](http://opencascade.org) - *optional*, but required for building IfcGeom
|
||||
([official](http://www.opencascade.org/getocc/download/loadocc/), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
|
||||
* [Open Cascade](https://dev.opencascade.org/) - *optional*, but required for building IfcGeom
|
||||
([official](https://dev.opencascade.org/release), "OCCT", or [community edition](https://github.com/tpaviot/oce), "OCE")
|
||||
For converting IFC representation items into BRep solids and tesselated meshes
|
||||
* [OpenCOLLADA](https://github.com/khronosGroup/OpenCOLLADA/) - *optional*
|
||||
For IfcConvert to be able to write tessellated Collada (.dae) files
|
||||
@@ -101,7 +101,7 @@ Note: where `make -j` is written, add a number roughly equal to the amount of CP
|
||||
$ make -j
|
||||
$ sudo make install
|
||||
|
||||
**2c)** or obtain and compile OCCT from http://www.opencascade.org/getocc/download/loadocc/
|
||||
**2c)** or obtain and compile OCCT from https://dev.opencascade.org/release
|
||||
|
||||
**3)** For building IfcConvert with COLLADA (.dae) support (on by default), OpenCOLLADA is needed:
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ cmake_minimum_required(VERSION 3.1.3)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
||||
|
||||
project (IfcOpenShell)
|
||||
project (IfcOpenShell VERSION 0.6.0)
|
||||
|
||||
# use extra version to make pre-release using eg semver
|
||||
set( EXTRA_VERSION "-alpha.3")
|
||||
|
||||
foreach(max_year RANGE 2014 2030)
|
||||
set(max_sdk "$ENV{ADSK_3DSMAX_SDK_${max_year}}")
|
||||
@@ -35,6 +38,7 @@ OPTION(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLL
|
||||
OPTION(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
|
||||
OPTION(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
OPTION(IFCCONVERT_DOUBLE_PRECISION "IfcConvert: Use double precision floating-point numbers." ON)
|
||||
OPTION(BUILD_PACKAGE "" OFF)
|
||||
OPTION(BUILD_IFCGEOM "Build IfcGeom." ON)
|
||||
OPTION(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF)
|
||||
OPTION(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
@@ -54,7 +58,7 @@ OPTION(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only ins
|
||||
|
||||
# TODO QtViewer is deprecated ATM as it uses the 0.4 API
|
||||
# OPTION(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer (requires Qt 4 framework)." OFF)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM))
|
||||
message(STATUS "'IfcGeom' is required with current outputs")
|
||||
set(BUILD_IFCGEOM ON)
|
||||
@@ -65,7 +69,7 @@ IF(NOT BINDIR)
|
||||
set(BINDIR bin)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${BINDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_PREFIX}/${BINDIR})
|
||||
set(BINDIR ${CMAKE_INSTALL_BINDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "BINDIR: ${BINDIR}")
|
||||
|
||||
@@ -73,7 +77,7 @@ IF(NOT INCLUDEDIR)
|
||||
set(INCLUDEDIR include)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
||||
|
||||
@@ -81,11 +85,11 @@ IF(NOT LIBDIR)
|
||||
set(LIBDIR lib)
|
||||
ENDIF()
|
||||
IF(NOT IS_ABSOLUTE ${LIBDIR})
|
||||
set(LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIBDIR})
|
||||
set(LIBDIR ${CMAKE_INSTALL_LIBDIR})
|
||||
ENDIF()
|
||||
MESSAGE(STATUS "LIBDIR: ${LIBDIR}")
|
||||
|
||||
set(IFCOPENSHELL_LIBARY_DIR "") # for *nix rpaths
|
||||
set(IFCOPENSHELL_LIBRARY_DIR "") # for *nix rpaths
|
||||
|
||||
if (BUILD_SHARED_LIBS)
|
||||
add_definitions(-DIFC_SHARED_BUILD)
|
||||
@@ -95,7 +99,7 @@ if (BUILD_SHARED_LIBS)
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
set(IFCOPENSHELL_LIBARY_DIR "${LIBDIR}")
|
||||
set(IFCOPENSHELL_LIBRARY_DIR "${LIBDIR}")
|
||||
endif()
|
||||
|
||||
# Create cache entries if absent for environment variables
|
||||
@@ -175,6 +179,7 @@ if(USE_MMAP)
|
||||
endif()
|
||||
|
||||
if (IFCXML_SUPPORT)
|
||||
find_package(LibXml2 REQUIRED)
|
||||
add_definitions(-DWITH_IFCXML)
|
||||
endif()
|
||||
|
||||
@@ -219,45 +224,57 @@ endfunction()
|
||||
if(BUILD_IFCGEOM)
|
||||
|
||||
IF(MSVC)
|
||||
add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d)
|
||||
add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d)
|
||||
ENDIF()
|
||||
|
||||
# Find Open CASCADE
|
||||
# Open CASCADE
|
||||
IF("${OCC_INCLUDE_DIR}" STREQUAL "")
|
||||
SET(OCC_INCLUDE_DIR "/usr/include/oce/" CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_INCLUDE_DIR to specify another directory")
|
||||
FIND_PATH(OCC_INCLUDE_DIR Standard_Version.hxx
|
||||
[PATHS
|
||||
/usr/include/occt
|
||||
/usr/include/oce
|
||||
/usr/include/opencascade
|
||||
]
|
||||
REQUIRED
|
||||
)
|
||||
IF(OCC_INCLUDE_DIR)
|
||||
MESSAGE(STATUS "Found Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find Open CASCADE include directory, specify OCC_INCLUDE_DIR manually.")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_FILE(gp_Pnt_hxx "gp_Pnt.hxx" ${OCC_INCLUDE_DIR})
|
||||
IF(gp_Pnt_hxx)
|
||||
MESSAGE(STATUS "Header files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find header files, aborting")
|
||||
SET(OCC_INCLUDE_DIR ${OCC_INCLUDE_DIR} CACHE FILEPATH "Open CASCADE header files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE include files in: ${OCC_INCLUDE_DIR}")
|
||||
ENDIF()
|
||||
|
||||
SET(OPENCASCADE_LIBRARY_NAMES
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR
|
||||
TKernel TKMath TKBRep TKGeomBase TKGeomAlgo TKG3d TKG2d TKShHealing TKTopAlgo TKMesh TKPrim TKBool TKBO
|
||||
TKFillet TKSTEP TKSTEPBase TKSTEPAttr TKXSBase TKSTEP209 TKIGES TKOffset TKHLR
|
||||
)
|
||||
|
||||
IF("${OCC_LIBRARY_DIR}" STREQUAL "")
|
||||
SET(OCC_LIBRARY_DIR "/usr/lib/" CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
MESSAGE(STATUS "Use OCC_LIBRARY_DIR to specify another directory")
|
||||
find_library(OCC_LIBRARY TKernel
|
||||
[PATHS
|
||||
/usr/lib
|
||||
]
|
||||
REQUIRED
|
||||
)
|
||||
IF(OCC_LIBRARY)
|
||||
GET_FILENAME_COMPONENT(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
|
||||
MESSAGE(STATUS "Found Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable find Open CASCADE library directory, specify OCC_LIBRARY_DIR manually.")
|
||||
ENDIF()
|
||||
ELSE()
|
||||
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
SET(OCC_LIBRARY_DIR ${OCC_LIBRARY_DIR} CACHE FILEPATH "Open CASCADE library files")
|
||||
MESSAGE(STATUS "Looking for Open CASCADE library files in: ${OCC_LIBRARY_DIR}")
|
||||
ENDIF()
|
||||
|
||||
FIND_LIBRARY(libTKernel NAMES TKernel TKerneld PATHS ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
IF(libTKernel)
|
||||
MESSAGE(STATUS "Library files found")
|
||||
MESSAGE(STATUS "Required Open Cascade Library files found")
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "Unable to find library files, aborting")
|
||||
MESSAGE(FATAL_ERROR "Unable to find Open Cascade library files, aborting")
|
||||
ENDIF()
|
||||
|
||||
# Use the found libTKernel as a template for all other OCC libraries
|
||||
@@ -449,6 +466,10 @@ ElSE()
|
||||
else()
|
||||
add_definitions(-Wno-maybe-uninitialized)
|
||||
endif()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0))
|
||||
# OpenCascade spews a lot of deprecated-copy warnings
|
||||
add_definitions(-Wno-deprecated-copy)
|
||||
endif()
|
||||
# -fPIC is not relevant on Windows and creates pointless warnings
|
||||
if (UNIX)
|
||||
add_definitions(-fPIC)
|
||||
@@ -473,7 +494,7 @@ function(files_for_ifc_version IFC_VERSION RESULT_NAME)
|
||||
)
|
||||
endfunction()
|
||||
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1")
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1" "4x3_rc2")
|
||||
|
||||
if(COMPILE_SCHEMA)
|
||||
# @todo, this appears to be untested at the moment
|
||||
@@ -624,7 +645,7 @@ if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
# Only set RPATHs when building shared libraries (i.e. IfcParse and
|
||||
# IfcGeom are dynamically linked). Not necessarily a perfect solution
|
||||
# but probably a good indication of whether RPATHs are necessary.
|
||||
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}")
|
||||
SET_INSTALL_RPATHS(IfcConvert "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS};${OPENCOLLADA_LIBRARY_DIR}")
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS IfcConvert
|
||||
@@ -645,7 +666,7 @@ ADD_EXECUTABLE(IfcGeomServer ${SOURCE_FILES})
|
||||
TARGET_LINK_LIBRARIES(IfcGeomServer ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES})
|
||||
|
||||
if ((NOT WIN32) AND BUILD_SHARED_LIBS)
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
|
||||
SET_INSTALL_RPATHS(IfcGeomServer "${IFCOPENSHELL_LIBRARY_DIR};${OCC_LIBRARY_DIR};${Boost_LIBRARY_DIRS}")
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS IfcGeomServer
|
||||
@@ -716,3 +737,43 @@ INSTALL(FILES ${SERIALIZERS_S_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
||||
.git
|
||||
.gitignore
|
||||
)
|
||||
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}")
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/assets")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IfcOpenShell")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "IfcOpenShell.")
|
||||
set(CPACK_PACKAGE_VENDOR "Cemosis")
|
||||
set(CPACK_PACKAGE_CONTACT "Christophe Prud'homme <christophe.prudhomme@cemosis.fr>")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
|
||||
|
||||
|
||||
set(CPACK_GENERATOR "TGZ;DEB")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
|
||||
FOREACH(COMPONENT IN ITEMS ${BOOST_COMPONENTS})
|
||||
string(REPLACE "_" "-" COMP ${COMPONENT})
|
||||
set(BOOST_DEPS "${BOOST_DEPS}, libboost-${COMP}1.67.0")
|
||||
endforeach(COMPONENT)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_CONTACT}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3, libxml2, liboce-foundation11, liboce-modeling11, liboce-ocaf11, liboce-visualization11, liboce-ocaf-lite11, libpython3.8 ${BOOST_DEPS}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "science")
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
#set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst")
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||
# title of most generated pages and in a few other places.
|
||||
# The default value is: My Project.
|
||||
|
||||
PROJECT_NAME = "My Project"
|
||||
PROJECT_NAME = "IfcOpenShell"
|
||||
|
||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
@@ -829,7 +829,7 @@ WARN_LOGFILE =
|
||||
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ../src/ifcgeom ../src/serializers
|
||||
INPUT = ../src/ifcgeom ../src/serializers ../src/ifcgeom_schema_agnostic ../src/ifcparse
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
||||
@@ -22,7 +22,7 @@ exhale_args = {
|
||||
# These arguments are required
|
||||
"containmentFolder": "./rst_files",
|
||||
"rootFileName": "library_root.rst",
|
||||
"rootFileTitle": "IfcOpenShell",
|
||||
"rootFileTitle": "IfcOpenShell C++",
|
||||
"doxygenStripFromPath": "..",
|
||||
# Suggested optional arguments
|
||||
"createTreeView": True,
|
||||
@@ -34,15 +34,4 @@ exhale_args = {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# # Tell sphinx what the primary language being documented is.
|
||||
# primary_domain = 'cpp'
|
||||
|
||||
# # Tell sphinx what the pygments highlight language should be.
|
||||
# highlight_language = 'cpp'
|
||||
|
||||
|
||||
|
||||
cpp_id_attributes = ['IFC_PARSE_API', 'IFC_GEOM_API']
|
||||
|
||||
@@ -7,4 +7,4 @@ IfcOpenShell
|
||||
rst_files/library_root
|
||||
|
||||
|
||||
`ifcopenshell-python documentation <_build/html/index.html>`_
|
||||
* `ifcopenshell-python documentation <python/html/index.html>`_
|
||||
@@ -1,52 +1,39 @@
|
||||
# This program requires doxygen, sphinx, breathe and exhale.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
|
||||
from sys import platform
|
||||
|
||||
|
||||
def copy_content(content, container):
|
||||
with open(content) as f:
|
||||
with open(container, "w") as f1:
|
||||
for line in f:
|
||||
f1.write(line)
|
||||
|
||||
|
||||
conf_path = "./conf.py"
|
||||
index_path = "./index.rst"
|
||||
# some extra check to see if we can find sphinx in pypy bin dir
|
||||
sphinx_build = os.path.join(os.path.dirname(sys.executable), 'sphinx-build')
|
||||
if not os.path.exists(sphinx_build):
|
||||
sphinx_build = "sphinx-build"
|
||||
# else:
|
||||
# os.environ['PATH'] = os.pathsep + os.path.dirname(sys.executable)
|
||||
|
||||
# not used, -j caused issues in my sphinx install
|
||||
j = str(multiprocessing.cpu_count())
|
||||
|
||||
if not os.path.isdir("./output/doxygen/xml"):
|
||||
os.makedirs("output/doxygen/xml")
|
||||
|
||||
if os.path.isfile(conf_path) and not os.path.isfile(index_path):
|
||||
os.remove(conf_path)
|
||||
if os.path.isfile(index_path) and not os.path.isfile(conf_path):
|
||||
os.remove(index_path)
|
||||
subprocess.check_call([sphinx_build, "-b", "html", ".", "output"])
|
||||
|
||||
if not (os.path.isfile(conf_path) and os.path.isfile(index_path)):
|
||||
subprocess.run(["sphinx-quickstart", "-q", "-p", "IfcOpenShell"])
|
||||
|
||||
conf_copy = ["./conf_to_copy.py", "./conf.py"]
|
||||
index_copy = ["./index_to_copy.rst", "./index.rst"]
|
||||
|
||||
copy_content(conf_copy[0], conf_copy[1])
|
||||
copy_content(index_copy[0], index_copy[1])
|
||||
|
||||
if platform == "linux" or platform == "linux2":
|
||||
subprocess.run(["make", "html"])
|
||||
if not os.path.isdir("/output/_build"):
|
||||
subprocess.run(["cd","../src/ifcblenderexport/docs"])
|
||||
subprocess.run(["make", "html"])
|
||||
subprocess.run(["cd", "../../../docs"])
|
||||
|
||||
subprocess.run(["mv" "../src/ifcblenderexport/docs/_build", "./output"])
|
||||
if sys.platform == "linux" or sys.platform == "linux2":
|
||||
if os.path.isdir("output/python"):
|
||||
shutil.rmtree("output/python")
|
||||
|
||||
if not os.path.exists(os.path.join("../src/ifcblenderexport/docs", "contents.rst")):
|
||||
subprocess.check_call(["ln", "index.rst", "contents.rst"], cwd="../src/ifcblenderexport/docs")
|
||||
|
||||
subprocess.check_call(["sed", "-i", "s/html_theme/# html_theme/g", "conf.py"], cwd="../src/ifcblenderexport/docs")
|
||||
subprocess.check_call(["make", "html"], cwd="../src/ifcblenderexport/docs")
|
||||
subprocess.check_call(["git", "checkout", "conf.py"], cwd="../src/ifcblenderexport/docs")
|
||||
|
||||
shutil.move("../src/ifcblenderexport/docs/_build", "./output")
|
||||
os.rename("./output/_build", "./output/python")
|
||||
|
||||
elif platform == "win32" or platform == "win64":
|
||||
subprocess.run(["make.bat", "html"])
|
||||
|
||||
|
||||
|
||||
elif sys.platform == "win32" or sys.platform == "win64":
|
||||
subprocess.check_call(["make.bat", "html"])
|
||||
|
||||
@@ -7,4 +7,4 @@ IfcOpenShell
|
||||
rst_files/library_root
|
||||
|
||||
|
||||
`ifcopenshell-python documentation <_build/html/index.html>`_
|
||||
* `ifcopenshell-python documentation <python/html/index.html>`_
|
||||
@@ -336,7 +336,7 @@ def git_clone_or_pull_repository(clone_url, target_dir, revision=None):
|
||||
`None`."""
|
||||
if not os.path.exists(target_dir):
|
||||
logger.info("cloning '%s' into '%s'" % (clone_url, target_dir))
|
||||
run([git, "clone", clone_url, target_dir])
|
||||
run([git, "clone", "--recursive", clone_url, target_dir])
|
||||
else:
|
||||
logger.info("directory '%s' already cloned. Pulling latest changes." % (target_dir,))
|
||||
|
||||
|
||||
@@ -50,9 +50,12 @@ class BcfXml:
|
||||
zip_file = zipfile.ZipFile(filepath)
|
||||
self.filepath = tempfile.mkdtemp()
|
||||
zip_file.extractall(self.filepath)
|
||||
data = self._read_xml("project.bcfp", "project.xsd")
|
||||
self.project.project_id = data["Project"]["@ProjectId"]
|
||||
self.project.name = data["Project"]["Name"]
|
||||
if os.path.isfile(os.path.join(self.filepath, "project.bcfp")):
|
||||
data = self._read_xml("project.bcfp", "project.xsd")
|
||||
self.project.extension_schema = data["ExtensionSchema"]
|
||||
if "Project" in data:
|
||||
self.project.project_id = data["Project"]["@ProjectId"]
|
||||
self.project.name = data["Project"].get("Name")
|
||||
return self.project
|
||||
|
||||
def edit_project(self):
|
||||
|
||||
@@ -2,6 +2,7 @@ class Project:
|
||||
def __init__(self):
|
||||
self.project_id = ""
|
||||
self.name = ""
|
||||
self.extension_schema = ""
|
||||
|
||||
|
||||
class BimSnippet:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
xmlschema
|
||||
@@ -1,19 +1,44 @@
|
||||
VERSION:=`date '+%y%m%d'`
|
||||
PYVERSION:=py37
|
||||
|
||||
ifeq ($(PLATFORM), win)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
PYTHONOCC_URL:=https://anaconda.org/DLR-SC/pythonocc-core/0.17.3/download/win-64/pythonocc-core-0.17.3-py37he980bc4_10.tar.bz2
|
||||
OCE_URL:=https://anaconda.org/DLR-SC/oce/0.17.2/download/win-64/oce-0.17.2-he980bc4_14.tar.bz2
|
||||
TBB_URL:=https://anaconda.org/DLR-SC/tbb/2019.5/download/win-64/tbb-2019.5-he980bc4_0.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYTHONOCC_URL:=https://anaconda.org/conda-forge/pythonocc-core/7.4.1/download/win-64/pythonocc-core-7.4.1-py39h3d1c7c5_0.tar.bz2
|
||||
OCE_URL:=https://anaconda.org/conda-forge/occt/7.4.0/download/win-64/occt-7.4.0-h823b557_3.tar.bz2
|
||||
TBB_URL:=https://anaconda.org/conda-forge/tbb/2020.2/download/win-64/tbb-2020.2-h2d74725_4.tar.bz2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macos)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
PYTHONOCC_URL:=https://anaconda.org/DLR-SC/pythonocc-core/0.17.3/download/osx-64/pythonocc-core-0.17.3-py37h04f5b5a_10.tar.bz2
|
||||
OCE_URL:=https://anaconda.org/DLR-SC/oce/0.17.2/download/osx-64/oce-0.17.2-h04f5b5a_12.tar.bz2
|
||||
TBB_URL:=https://anaconda.org/DLR-SC/tbb/4.3.6/download/osx-64/tbb-4.3.6-0.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYTHONOCC_URL:=https://anaconda.org/conda-forge/pythonocc-core/7.4.1/download/osx-64/pythonocc-core-7.4.1-py39h4d29fe3_0.tar.bz2
|
||||
OCE_URL:=https://anaconda.org/conda-forge/occt/7.4.0/download/osx-64/occt-7.4.0-hb9b6dc7_3.tar.bz2
|
||||
TBB_URL:=https://anaconda.org/conda-forge/tbb/2020.2/download/osx-64/tbb-2020.2-h940c156_4.tar.bz2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), linux)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
PYTHONOCC_URL:=https://anaconda.org/DLR-SC/pythonocc-core/0.17.3/download/linux-64/pythonocc-core-0.17.3-py37h6bb024c_10.tar.bz2
|
||||
OCE_URL:=https://anaconda.org/DLR-SC/oce/0.17.2/download/linux-64/oce-0.17.2-h6bb024c_14.tar.bz2
|
||||
TBB_URL:=https://anaconda.org/DLR-SC/tbb/4.3.6/download/linux-64/tbb-4.3.6-0.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
PYTHONOCC_URL:=https://anaconda.org/conda-forge/pythonocc-core/7.4.1/download/linux-64/pythonocc-core-7.4.1-py39h465cb30_0.tar.bz2
|
||||
OCE_URL:=https://anaconda.org/conda-forge/occt/7.4.0/download/linux-64/occt-7.4.0-h9121d39_3.tar.bz2
|
||||
TBB_URL:=https://anaconda.org/conda-forge/tbb/2020.2/download/linux-64/tbb-2020.2-h4bd325d_4.tar.bz2
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: dist
|
||||
dist:
|
||||
@@ -26,14 +51,31 @@ endif
|
||||
cp -r blenderbim/* dist/blenderbim/
|
||||
|
||||
# Provides IfcOpenShell Python functionality
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-37-v0.6.0-3bbdc3f-$(PLATFORM)64.zip
|
||||
ifeq ($(PYVERSION), py37)
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-37-v0.6.0-ff7219b-$(PLATFORM)64.zip
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-39-v0.6.0-ff7219b-$(PLATFORM)64.zip
|
||||
endif
|
||||
cd dist/working && unzip ifcblender*
|
||||
cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
|
||||
# See bug #812
|
||||
cd dist/working && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcblenderexport/occ_utils.py
|
||||
cd dist/working && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/blenderbim/occ_utils.py
|
||||
cd dist/working && mv occ_utils.py ../blenderbim/libs/site/packages/ifcopenshell/geom/occ_utils.py
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides IfcConvert for construction documentation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/IfcConvert-v0.6.0-517b819-$(PLATFORM)64.zip
|
||||
cd dist/working && unzip IfcConvert*
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/IfcConvert.exe dist/blenderbim/libs/
|
||||
else
|
||||
cp -r dist/working/IfcConvert dist/blenderbim/libs/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides Python OCC functionality for cutting IFC geometry for construction documentation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(PYTHONOCC_URL)
|
||||
@@ -41,16 +83,26 @@ endif
|
||||
ifeq ($(PLATFORM), win)
|
||||
cd dist/working && cp -r Lib/site-packages/OCC ../blenderbim/libs/site/packages/
|
||||
else
|
||||
ifeq ($(PYVERSION), py37)
|
||||
cd dist/working && cp -r lib/python3.7/site-packages/OCC ../blenderbim/libs/site/packages/
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
cd dist/working && cp -r lib/python3.9/site-packages/OCC ../blenderbim/libs/site/packages/
|
||||
endif
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by Python OCC
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(OCE_URL)
|
||||
cd dist/working && tar -xjvf oce*
|
||||
cd dist/working && tar -xjvf oc*
|
||||
ifeq ($(PLATFORM), win)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
cd dist/working && cp -r Library/bin/* ../blenderbim/libs/site/packages/OCC/
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
cd dist/working && cp -r Library/bin/* ../blenderbim/libs/site/packages/OCC/Core/
|
||||
endif
|
||||
else
|
||||
# Unix Conda builds of PythonOCC expect OCE libs to have a RPATH of ../../../
|
||||
cd dist/working && cp -r lib/* ../blenderbim/libs/
|
||||
@@ -65,7 +117,12 @@ endif
|
||||
cd dist/working && wget $(TBB_URL)
|
||||
cd dist/working && tar -xjvf tbb*
|
||||
ifeq ($(PLATFORM), win)
|
||||
ifeq ($(PYVERSION), py37)
|
||||
cd dist/working && cp -r Library/bin/* ../blenderbim/libs/site/packages/OCC/
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
cd dist/working && cp -r Library/bin/* ../blenderbim/libs/site/packages/OCC/Core/
|
||||
endif
|
||||
else
|
||||
cd dist/working && cp -r lib/* ../blenderbim/libs/
|
||||
endif
|
||||
@@ -85,11 +142,16 @@ endif
|
||||
cd dist/working && unzip v0.6.0.zip
|
||||
# IfcOpenBot sometimes lags behind, so we hotfix the Python utilities
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/util/* dist/blenderbim/libs/site/packages/ifcopenshell/util/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/api/* dist/blenderbim/libs/site/packages/ifcopenshell/api/
|
||||
# Provides bcf functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/bcf/bcf dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCClash functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcclash/* dist/blenderbim/libs/site/packages/
|
||||
# Provides BIMTester functionality
|
||||
cd dist/working && python -m venv env
|
||||
cd dist/working && . env/bin/activate && pip install pybabel
|
||||
cd dist/working && . env/bin/activate && pip install babel
|
||||
cd dist/working && . env/bin/activate && ./env/bin/pybabel compile -d ./IfcOpenShell-0.6.0/src/ifcbimtester/bimtester/locale/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCCOBie functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifccobie/* dist/blenderbim/libs/site/packages/
|
||||
@@ -98,7 +160,7 @@ endif
|
||||
# Provides IFCCSV functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifccsv/* dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCPatch functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcpatch dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcpatch/ifcpatch dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides Mustache templating in construction documentation
|
||||
@@ -115,6 +177,20 @@ endif
|
||||
cp -r dist/working/svgwrite-1.3.1/svgwrite dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides fuzzy date parsing for construction sequencing
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/be/ed/5bbc91f03fa4c839c4c7360375da77f9659af5f7086b7a7bdda65771c8e0/python-dateutil-2.8.1.tar.gz
|
||||
cd dist/working && tar -xzvf python-dateutil*
|
||||
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.css
|
||||
cp dist/working/jsgantt* dist/blenderbim/bim/data/gantt/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCDiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/Moult/deepdiff/archive/master.zip
|
||||
@@ -179,8 +255,6 @@ ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/fcl dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
endif
|
||||
|
||||
# Required by IFCClash
|
||||
ifeq ($(PLATFORM), win)
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/19/e6/6e9f33fb59e8f27c0e1592bd26e644bc92b85c942b072b2d3854105d5887/python_fcl_win32-0.0.12.post3-py3-none-win_amd64.whl
|
||||
@@ -194,6 +268,11 @@ endif
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/c8/4b/d0a8c23b6c8985e5544ea96d27105a273ea22051317f850c2cdbf2029fe4/behave-1.2.6.tar.gz
|
||||
cd dist/working && tar -xzvf behave*
|
||||
cd dist/working/behave-1.2.6/ && cp -r behave ../../blenderbim/libs/site/packages/
|
||||
# See bug #1294
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcbimtester/patch/model_core.patch
|
||||
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.6.0/src/ifcbimtester/patch/runner_util.patch
|
||||
cd dist/working/ && patch ../blenderbim/libs/site/packages/behave/model_core.py < model_core.patch
|
||||
cd dist/working/ && patch ../blenderbim/libs/site/packages/behave/runner_util.py < runner_util.patch
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by behave
|
||||
@@ -231,6 +310,34 @@ endif
|
||||
cd dist/working/defusedxml-0.6.0/ && cp -r defusedxml ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by augin
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/76/b4/b7baffbda025efd5dc8fcd8d2e953e3aa939c236a484084fa8f4c3588ee9/boto3-1.17.17.tar.gz
|
||||
cd dist/working && tar -xzvf boto3*
|
||||
cd dist/working/boto3-1.17.17/ && cp -r boto3 ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by boto3
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/7f/2e/e02fdfd0f0377c4e44e61de27b05d5cfe93575770661ef9ded80ed90fa88/botocore-1.20.17.tar.gz
|
||||
cd dist/working && tar -xzvf botocore*
|
||||
cd dist/working/botocore-1.20.17/ && cp -r botocore ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by boto3
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/3c/56/3f325b1eef9791759784aa5046a8f6a1aff8f7c898a2e34506771d3b99d8/jmespath-0.10.0.tar.gz
|
||||
cd dist/working && tar -xzvf jmespath*
|
||||
cd dist/working/jmespath-0.10.0/ && cp -r jmespath ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by boto3
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/08/e1/3ee2096ebaeeb8c186d20ed16c8faf4a503913e5c9a0e14cd6b8ffc405a3/s3transfer-0.3.4.tar.gz
|
||||
cd dist/working && tar -xzvf s3transfer*
|
||||
cd dist/working/s3transfer-0.3.4/ && cp -r s3transfer ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides IFCJSON functionality
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://github.com/IFCJSON-Team/IFC2JSON_python/archive/master.zip
|
||||
@@ -239,7 +346,7 @@ endif
|
||||
rm -rf dist/working
|
||||
|
||||
cd dist/blenderbim && sed -i "s/999999/$(VERSION)/" __init__.py
|
||||
cd dist && zip -r blender28-bim-$(VERSION)-$(PLATFORM).zip ./*
|
||||
cd dist && zip -r blender28-bim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||
rm -rf dist/blenderbim
|
||||
|
||||
.PHONY: clean
|
||||
|
Before Width: | Height: | Size: 399 KiB After Width: | Height: | Size: 399 KiB |
@@ -6,7 +6,7 @@ bpy = sys.modules.get("bpy")
|
||||
if bpy is not None:
|
||||
import bpy
|
||||
import importlib
|
||||
from . import handler, ui, prop, operator
|
||||
from . import handler, ui, prop, operator, gizmos
|
||||
|
||||
modules = {
|
||||
"project": None,
|
||||
@@ -16,6 +16,7 @@ if bpy is not None:
|
||||
"unit": None,
|
||||
"georeference": None,
|
||||
"context": None,
|
||||
"drawing": None,
|
||||
"attribute": None,
|
||||
"type": None,
|
||||
"spatial": None,
|
||||
@@ -23,6 +24,11 @@ if bpy is not None:
|
||||
"aggregate": None,
|
||||
"geometry": None,
|
||||
"cobie": None,
|
||||
"resource": None,
|
||||
"cost": None,
|
||||
"sequence": None,
|
||||
"group": None,
|
||||
"structural": None,
|
||||
"material": None,
|
||||
"style": None,
|
||||
"layer": None,
|
||||
@@ -40,6 +46,7 @@ if bpy is not None:
|
||||
"diff": None,
|
||||
"patch": None,
|
||||
"covetool": None,
|
||||
"augin": None,
|
||||
"debug": None,
|
||||
}
|
||||
|
||||
@@ -86,7 +93,6 @@ if bpy is not None:
|
||||
operator.RemoveVariable,
|
||||
operator.PropagateTextData,
|
||||
operator.SetOverrideColour,
|
||||
operator.AddDrawing,
|
||||
operator.RemoveDrawing,
|
||||
operator.AddDrawingStyle,
|
||||
operator.RemoveDrawingStyle,
|
||||
@@ -120,7 +126,6 @@ if bpy is not None:
|
||||
prop.BIMProperties,
|
||||
prop.DocProperties,
|
||||
prop.IfcParameter,
|
||||
prop.BoundaryCondition,
|
||||
prop.PsetQto,
|
||||
prop.GlobalId,
|
||||
prop.RepresentationItem,
|
||||
@@ -135,7 +140,6 @@ if bpy is not None:
|
||||
ui.BIM_PT_drawings,
|
||||
ui.BIM_PT_schedules,
|
||||
ui.BIM_PT_sheets,
|
||||
ui.BIM_PT_camera,
|
||||
ui.BIM_PT_text,
|
||||
ui.BIM_PT_annotation_utilities,
|
||||
ui.BIM_PT_misc_utilities,
|
||||
@@ -143,6 +147,11 @@ if bpy is not None:
|
||||
ui.BIM_UL_drawinglist,
|
||||
ui.BIM_UL_topics,
|
||||
ui.BIM_ADDON_preferences,
|
||||
gizmos.UglyDotGizmo,
|
||||
gizmos.DotGizmo,
|
||||
gizmos.DimensionLabelGizmo,
|
||||
gizmos.ExtrusionGuidesGizmo,
|
||||
gizmos.ExtrusionWidget
|
||||
]
|
||||
|
||||
for module in modules.values():
|
||||
@@ -164,7 +173,7 @@ if bpy is not None:
|
||||
bpy.app.handlers.depsgraph_update_post.append(on_register)
|
||||
bpy.app.handlers.load_post.append(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.append(handler.storeIdMap)
|
||||
bpy.app.handlers.save_pre.append(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
@@ -174,6 +183,8 @@ if bpy is not None:
|
||||
bpy.types.Collection.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties) # Check if we need this
|
||||
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
|
||||
bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Curve.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Camera.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Camera.BIMCameraProperties = bpy.props.PointerProperty(type=prop.BIMCameraProperties)
|
||||
bpy.types.TextCurve.BIMTextProperties = bpy.props.PointerProperty(type=prop.BIMTextProperties)
|
||||
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
||||
@@ -189,7 +200,7 @@ if bpy is not None:
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.remove(handler.storeIdMap)
|
||||
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
del bpy.types.Scene.BIMProperties
|
||||
@@ -199,6 +210,8 @@ if bpy is not None:
|
||||
del bpy.types.Collection.BIMObjectProperties # Check if we need this
|
||||
del bpy.types.Material.BIMMaterialProperties
|
||||
del bpy.types.Mesh.BIMMeshProperties
|
||||
del bpy.types.Curve.BIMMeshProperties
|
||||
del bpy.types.Camera.BIMMeshProperties
|
||||
del bpy.types.Camera.BIMCameraProperties
|
||||
del bpy.types.TextCurve.BIMTextProperties
|
||||
bpy.types.SCENE_PT_unit.remove(ui.ifc_units)
|
||||
@@ -6,68 +6,71 @@ import numpy
|
||||
import pickle
|
||||
import multiprocessing
|
||||
|
||||
try:
|
||||
from OCC.Core import (
|
||||
gp,
|
||||
Geom,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRep,
|
||||
BRepPrimAPI,
|
||||
BRepAlgoAPI,
|
||||
BRepBuilderAPI,
|
||||
TopOpeBRepTool,
|
||||
TopOpeBRepBuild,
|
||||
ShapeExtend,
|
||||
GProp,
|
||||
BRepGProp,
|
||||
GC,
|
||||
ShapeAnalysis,
|
||||
TopTools,
|
||||
TopExp,
|
||||
TopAbs,
|
||||
HLRAlgo,
|
||||
HLRBRep,
|
||||
TopLoc,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRepTools,
|
||||
TopoDS,
|
||||
GeomLProp,
|
||||
IntCurvesFace,
|
||||
)
|
||||
from OCC.Core.TopoDS import topods
|
||||
except ImportError:
|
||||
from OCC import (
|
||||
gp,
|
||||
Geom,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRep,
|
||||
BRepPrimAPI,
|
||||
BRepAlgoAPI,
|
||||
BRepBuilderAPI,
|
||||
TopOpeBRepTool,
|
||||
TopOpeBRepBuild,
|
||||
ShapeExtend,
|
||||
GProp,
|
||||
BRepGProp,
|
||||
GC,
|
||||
ShapeAnalysis,
|
||||
TopTools,
|
||||
TopExp,
|
||||
TopAbs,
|
||||
HLRAlgo,
|
||||
HLRBRep,
|
||||
TopLoc,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRepTools,
|
||||
TopoDS,
|
||||
GeomLProp,
|
||||
IntCurvesFace,
|
||||
)
|
||||
from OCC.TopoDS import topods
|
||||
|
||||
def load_occ():
|
||||
# Don't import until we really need to, as a temporary step before we can purge OCC
|
||||
try:
|
||||
from OCC.Core import (
|
||||
gp,
|
||||
Geom,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRep,
|
||||
BRepPrimAPI,
|
||||
BRepAlgoAPI,
|
||||
BRepBuilderAPI,
|
||||
TopOpeBRepTool,
|
||||
TopOpeBRepBuild,
|
||||
ShapeExtend,
|
||||
GProp,
|
||||
BRepGProp,
|
||||
GC,
|
||||
ShapeAnalysis,
|
||||
TopTools,
|
||||
TopExp,
|
||||
TopAbs,
|
||||
HLRAlgo,
|
||||
HLRBRep,
|
||||
TopLoc,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRepTools,
|
||||
TopoDS,
|
||||
GeomLProp,
|
||||
IntCurvesFace,
|
||||
)
|
||||
from OCC.Core.TopoDS import topods
|
||||
except ImportError:
|
||||
from OCC import (
|
||||
gp,
|
||||
Geom,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRep,
|
||||
BRepPrimAPI,
|
||||
BRepAlgoAPI,
|
||||
BRepBuilderAPI,
|
||||
TopOpeBRepTool,
|
||||
TopOpeBRepBuild,
|
||||
ShapeExtend,
|
||||
GProp,
|
||||
BRepGProp,
|
||||
GC,
|
||||
ShapeAnalysis,
|
||||
TopTools,
|
||||
TopExp,
|
||||
TopAbs,
|
||||
HLRAlgo,
|
||||
HLRBRep,
|
||||
TopLoc,
|
||||
Bnd,
|
||||
BRepBndLib,
|
||||
BRepTools,
|
||||
TopoDS,
|
||||
GeomLProp,
|
||||
IntCurvesFace,
|
||||
)
|
||||
from OCC.TopoDS import topods
|
||||
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
@@ -79,6 +82,7 @@ this_file = os.path.join(cwd, "cut_ifc.py")
|
||||
|
||||
|
||||
def get_booleaned_edges(shape):
|
||||
load_occ()
|
||||
edges = []
|
||||
exp = TopExp.TopExp_Explorer(shape, TopAbs.TopAbs_EDGE)
|
||||
while exp.More():
|
||||
@@ -88,6 +92,7 @@ def get_booleaned_edges(shape):
|
||||
|
||||
|
||||
def connect_edges_into_wires(unconnected_edges):
|
||||
load_occ()
|
||||
edges = TopTools.TopTools_HSequenceOfShape()
|
||||
edges_handle = TopTools.Handle_TopTools_HSequenceOfShape(edges)
|
||||
wires = TopTools.TopTools_HSequenceOfShape()
|
||||
@@ -101,6 +106,7 @@ def connect_edges_into_wires(unconnected_edges):
|
||||
|
||||
|
||||
def do_cut(process_data):
|
||||
load_occ()
|
||||
global_id, shape, section, trsf_data = process_data
|
||||
|
||||
axis = gp.gp_Ax2(
|
||||
@@ -320,6 +326,7 @@ class IfcCutter:
|
||||
return False
|
||||
|
||||
def create_section_box(self):
|
||||
load_occ()
|
||||
top_left_corner = gp.gp_Pnt(
|
||||
self.section_box["top_left_corner"][0],
|
||||
self.section_box["top_left_corner"][1],
|
||||
@@ -350,6 +357,7 @@ class IfcCutter:
|
||||
self.transformation.SetDisplacement(source, destination)
|
||||
|
||||
def get_bbox(self, shape):
|
||||
load_occ()
|
||||
bbox = Bnd.Bnd_Box()
|
||||
BRepBndLib.brepbndlib_Add(shape, bbox)
|
||||
return bbox
|
||||
@@ -361,6 +369,7 @@ class IfcCutter:
|
||||
return zpos, zmax
|
||||
|
||||
def get_booleaned_edges(self, shape):
|
||||
load_occ()
|
||||
edges = []
|
||||
exp = TopExp.TopExp_Explorer(shape, TopAbs.TopAbs_EDGE)
|
||||
while exp.More():
|
||||
@@ -377,6 +386,7 @@ class IfcCutter:
|
||||
|
||||
def get_annotation(self):
|
||||
import mathutils
|
||||
load_occ()
|
||||
|
||||
self.annotation_objs = []
|
||||
settings_2d = ifcopenshell.geom.settings()
|
||||
@@ -0,0 +1,11 @@
|
||||
<link href="jsgantt.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="jsgantt.js" type="text/javascript"></script>
|
||||
<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
|
||||
<script type="text/javascript">
|
||||
var g = new JSGantt.GanttChart(document.getElementById('GanttChartDIV'), 'day');
|
||||
var json_data = `
|
||||
{{{json_data}}}
|
||||
`;
|
||||
JSGantt.parseJSONString(json_data, g);
|
||||
g.Draw();
|
||||
</script>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 572 B |
@@ -25,7 +25,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<desc
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/ifcblenderexport/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/blenderbim/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.07874;stroke-linecap:round;stroke-linejoin:round;stop-color:#000000"
|
||||
id="rect1036"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -25,7 +25,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<desc
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/ifcblenderexport/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/blenderbim/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
<rect
|
||||
y="3.1753578e-05"
|
||||
x="-4.3300333e-05"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -25,7 +25,7 @@
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<desc
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/ifcblenderexport/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
id="desc89610">/home/dion/Projects/IfcOpenShell/src/blenderbim/titleblock.dxf - scale = 1.000000, origin = (0.000000, 0.000000), method = manual</desc>
|
||||
<rect
|
||||
y="3.1753578e-05"
|
||||
x="-4.3300333e-05"
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -0,0 +1,193 @@
|
||||
import os
|
||||
import bpy
|
||||
import json
|
||||
import numpy as np
|
||||
import datetime
|
||||
import zipfile
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.api
|
||||
from ifcopenshell.api.spatial.data import Data as SpatialData
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
import addon_utils
|
||||
|
||||
|
||||
class IfcExporter:
|
||||
def __init__(self, ifc_export_settings):
|
||||
self.ifc_export_settings = ifc_export_settings
|
||||
|
||||
def export(self):
|
||||
self.file = IfcStore.get_file()
|
||||
self.set_header()
|
||||
if bpy.context.scene.BIMProjectProperties.is_authoring:
|
||||
self.sync_object_placements_and_deletions()
|
||||
self.sync_edited_objects()
|
||||
extension = self.ifc_export_settings.output_file.split(".")[-1]
|
||||
if extension == "ifczip":
|
||||
with tempfile.TemporaryDirectory() as unzipped_path:
|
||||
filename, ext = os.path.splitext(os.path.basename(self.ifc_export_settings.output_file))
|
||||
tmp_name = "{}.ifc".format(filename)
|
||||
tmp_file = os.path.join(unzipped_path, tmp_name)
|
||||
self.file.write(tmp_file)
|
||||
with zipfile.ZipFile(
|
||||
self.ifc_export_settings.output_file, mode="w", compression=zipfile.ZIP_DEFLATED, compresslevel=9
|
||||
) as zf:
|
||||
zf.write(tmp_file)
|
||||
elif extension == "ifc":
|
||||
self.file.write(self.ifc_export_settings.output_file)
|
||||
elif extension == "ifcjson":
|
||||
import ifcjson
|
||||
|
||||
if self.ifc_export_settings.json_version == "4":
|
||||
jsonData = ifcjson.IFC2JSON4(self.file, self.ifc_export_settings.json_compact).spf2Json()
|
||||
with open(self.ifc_export_settings.output_file, "w") as outfile:
|
||||
json.dump(jsonData, outfile, indent=None if self.ifc_export_settings.json_compact else 4)
|
||||
elif self.ifc_export_settings.json_version == "5a":
|
||||
jsonData = ifcjson.IFC2JSON5a(self.file, self.ifc_export_settings.json_compact).spf2Json()
|
||||
with open(self.ifc_export_settings.output_file, "w") as outfile:
|
||||
json.dump(jsonData, outfile, indent=None if self.ifc_export_settings.json_compact else 4)
|
||||
|
||||
def set_header(self):
|
||||
# TODO: add all metadata, pending bug #747
|
||||
self.file.wrapped_data.header.file_name.name = os.path.basename(self.ifc_export_settings.output_file)
|
||||
self.file.wrapped_data.header.file_name.time_stamp = (
|
||||
datetime.datetime.utcnow()
|
||||
.replace(tzinfo=datetime.timezone.utc)
|
||||
.astimezone()
|
||||
.replace(microsecond=0)
|
||||
.isoformat()
|
||||
)
|
||||
self.file.wrapped_data.header.file_name.preprocessor_version = "IfcOpenShell {}".format(ifcopenshell.version)
|
||||
self.file.wrapped_data.header.file_name.originating_system = "{} {}".format(
|
||||
self.get_application_name(), self.get_application_version()
|
||||
)
|
||||
# TODO: reimplement. See #1222.
|
||||
# if self.owner_history:
|
||||
# if self.schema_version == "IFC2X3":
|
||||
# self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Id
|
||||
# else:
|
||||
# self.file.wrapped_data.header.file_name.authorization = (
|
||||
# self.owner_history.OwningUser.ThePerson.Identification
|
||||
# )
|
||||
# else:
|
||||
# self.file.wrapped_data.header.file_name.authorization = "Nobody"
|
||||
|
||||
def sync_object_placements_and_deletions(self):
|
||||
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
to_delete = []
|
||||
|
||||
for ifc_definition_id, obj in IfcStore.id_map.items():
|
||||
try:
|
||||
self.sync_object_placement(obj)
|
||||
self.sync_object_container(ifc_definition_id, obj)
|
||||
except ReferenceError:
|
||||
pass # The object is likely deleted
|
||||
if self.should_delete(obj):
|
||||
to_delete.append(ifc_definition_id)
|
||||
|
||||
SpatialData.purge()
|
||||
|
||||
for ifc_definition_id in to_delete:
|
||||
product = self.file.by_id(ifc_definition_id)
|
||||
IfcStore.unlink_element(product)
|
||||
ifcopenshell.api.run("root.remove_product", self.file, **{"product": product})
|
||||
|
||||
def sync_edited_objects(self):
|
||||
for obj_name in IfcStore.edited_objs.copy():
|
||||
obj = bpy.data.objects.get(obj_name)
|
||||
if not obj:
|
||||
continue
|
||||
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep":
|
||||
bpy.ops.bim.update_mesh_representation(obj=obj.name)
|
||||
IfcStore.edited_objs.clear()
|
||||
|
||||
def sync_object_placement(self, obj):
|
||||
blender_matrix = np.matrix(obj.matrix_world)
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if not hasattr(element, "ObjectPlacement"):
|
||||
return
|
||||
ifc_matrix = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
ifc_matrix[0][3] *= self.unit_scale
|
||||
ifc_matrix[1][3] *= self.unit_scale
|
||||
ifc_matrix[2][3] *= self.unit_scale
|
||||
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset and props.blender_offset_type == "OBJECT_PLACEMENT":
|
||||
ifc_matrix = ifcopenshell.util.geolocation.global2local(
|
||||
ifc_matrix,
|
||||
float(props.blender_eastings) * self.unit_scale,
|
||||
float(props.blender_northings) * self.unit_scale,
|
||||
float(props.blender_orthogonal_height) * self.unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
if not np.allclose(ifc_matrix, blender_matrix, atol=0.0001):
|
||||
bpy.ops.bim.edit_object_placement(obj=obj.name)
|
||||
|
||||
def sync_object_container(self, guid, obj):
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
element_collection = bpy.data.collections.get(obj.name)
|
||||
|
||||
if self.file.schema == "IFC2X3":
|
||||
if element.is_a("IfcProject"):
|
||||
return
|
||||
elif element.is_a("IfcContext"):
|
||||
return
|
||||
|
||||
if (element.is_a("IfcElement") and element_collection) or element.is_a("IfcSpatialStructureElement"):
|
||||
try:
|
||||
parent_collection = [c for c in bpy.data.collections if c.children.get(element_collection.name)][0]
|
||||
except:
|
||||
return # Out of the spatial tree
|
||||
else:
|
||||
parent_collection = obj.users_collection[0]
|
||||
|
||||
parent_obj = bpy.data.objects.get(parent_collection.name)
|
||||
if not parent_obj or not parent_obj.BIMObjectProperties.ifc_definition_id:
|
||||
return
|
||||
parent = self.file.by_id(parent_obj.BIMObjectProperties.ifc_definition_id)
|
||||
|
||||
if parent.is_a("IfcSpatialStructureElement") and not element.is_a("IfcSpatialStructureElement"):
|
||||
if parent != ifcopenshell.util.element.get_container(element):
|
||||
bpy.ops.bim.assign_container(relating_structure=parent.id(), related_element=obj.name)
|
||||
elif parent != ifcopenshell.util.element.get_aggregate(element):
|
||||
bpy.ops.bim.assign_object(relating_object=parent_obj.name, related_object=obj.name)
|
||||
|
||||
def should_delete(self, obj):
|
||||
try:
|
||||
# This will throw an exception if the Blender object no longer exists
|
||||
foo = obj.name
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
|
||||
def get_application_name(self):
|
||||
return "BlenderBIM"
|
||||
|
||||
def get_application_version(self):
|
||||
return ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class IfcExportSettings:
|
||||
def __init__(self):
|
||||
self.logger = None
|
||||
self.output_file = None
|
||||
|
||||
@staticmethod
|
||||
def factory(context, output_file, logger):
|
||||
scene_bim = context.scene.BIMProperties
|
||||
settings = IfcExportSettings()
|
||||
settings.output_file = output_file
|
||||
settings.logger = logger
|
||||
return settings
|
||||
@@ -0,0 +1,400 @@
|
||||
import bpy
|
||||
import blf
|
||||
from bpy import types
|
||||
import math
|
||||
from mathutils import Vector, Matrix
|
||||
from mathutils import geometry
|
||||
import gpu, bgl
|
||||
from bpy_extras import view3d_utils
|
||||
|
||||
|
||||
from .shaders import DotsGizmoShader, ExtrusionGuidesShader, BaseLinesShader
|
||||
|
||||
|
||||
"""Gizmos under the hood
|
||||
|
||||
## Transforms:
|
||||
|
||||
source/blender/windowmanager/gizmo/WM_gizmo_types.h
|
||||
matrix_basis -- "Transformation of this gizmo." = placement in scene
|
||||
matrix_offset -- "Custom offset from origin." = local transforms according to state/value
|
||||
matrix_space -- "The space this gizmo is being modified in." used by some gizmos for undefined purposes
|
||||
matrix_world -- final matrix, scaled according to viewport zoom and custom scale_basis
|
||||
|
||||
source/blender/windowmanager/gizmo/intern/wm_gizmo.c:WM_gizmo_calc_matrix_final_params
|
||||
final = space @ (autoscale * (basis @ offset))
|
||||
final = space @ (basis @ offset) -- if gizmo.use_draw_scale == False
|
||||
final = space @ ((autoscale * basis) @ offset) -- if gizmo.use_draw_offset_scale
|
||||
|
||||
source/blender/windowmanager/gizmo/intern/wm_gizmo.c:wm_gizmo_calculate_scale
|
||||
autoscale = gizmo.scale_basis * magic(preferences, matrix_space, matrix_basis, context.region_data)
|
||||
magic -- making 1.0 to match preferences.view.gizmo_size pixels (75 by default)
|
||||
|
||||
|
||||
## Selection
|
||||
|
||||
select_id -- apparently, id of a selectable part
|
||||
test_select -- expected to return id of selection, doesn't seem to work
|
||||
draw_select -- fake-draw of selection geometry for gpu-side cursor tracking
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# some geometries for Gizmo.custom_shape shaders
|
||||
|
||||
CUBE = (
|
||||
(+1, +1, +1), (-1, +1, +1), (+1, -1, +1), # top
|
||||
(+1, -1, +1), (-1, +1, +1), (-1, -1, +1),
|
||||
(+1, +1, +1), (+1, -1, +1), (+1, +1, -1), # right
|
||||
(+1, +1, -1), (+1, -1, +1), (+1, -1, -1),
|
||||
(+1, +1, +1), (+1, +1, -1), (-1, +1, +1), # back
|
||||
(-1, +1, +1), (+1, +1, -1), (-1, +1, -1),
|
||||
(-1, -1, -1), (-1, +1, -1), (+1, -1, -1), # bot
|
||||
(+1, -1, -1), (-1, +1, -1), (+1, +1, -1),
|
||||
(-1, -1, -1), (-1, -1, +1), (-1, +1, -1), # left
|
||||
(-1, +1, -1), (-1, -1, +1), (-1, +1, +1),
|
||||
(-1, -1, -1), (+1, -1, -1), (-1, -1, +1), # front
|
||||
(-1, -1, +1), (+1, -1, -1), (+1, -1, +1)
|
||||
)
|
||||
|
||||
DISC = (
|
||||
(0.0, 0.0, 0.0), (1.0, 0.0, 0), (0.8660254037844387, 0.49999999999999994, 0),
|
||||
(0.0, 0.0, 0.0), (0.8660254037844387, 0.49999999999999994, 0), (0.5000000000000001, 0.8660254037844386, 0),
|
||||
(0.0, 0.0, 0.0), (0.5000000000000001, 0.8660254037844386, 0), (6.123233995736766e-17, 1.0, 0),
|
||||
(0.0, 0.0, 0.0), (6.123233995736766e-17, 1.0, 0), (-0.4999999999999998, 0.8660254037844387, 0),
|
||||
(0.0, 0.0, 0.0), (-0.4999999999999998, 0.8660254037844387, 0), (-0.8660254037844385, 0.5000000000000003, 0),
|
||||
(0.0, 0.0, 0.0), (-0.8660254037844385, 0.5000000000000003, 0), (-1.0, 1.2246467991473532e-16, 0),
|
||||
(0.0, 0.0, 0.0), (-1.0, 1.2246467991473532e-16, 0), (-0.8660254037844388, -0.4999999999999997, 0),
|
||||
(0.0, 0.0, 0.0), (-0.8660254037844388, -0.4999999999999997, 0), (-0.5000000000000004, -0.8660254037844384, 0),
|
||||
(0.0, 0.0, 0.0), (-0.5000000000000004, -0.8660254037844384, 0), (-1.8369701987210297e-16, -1.0, 0),
|
||||
(0.0, 0.0, 0.0), (-1.8369701987210297e-16, -1.0, 0), (0.49999999999999933, -0.866025403784439, 0),
|
||||
(0.0, 0.0, 0.0), (0.49999999999999933, -0.866025403784439, 0), (0.8660254037844384, -0.5000000000000004, 0),
|
||||
(0.0, 0.0, 0.0), (0.8660254037844384, -0.5000000000000004, 0), (1.0, 0.0, 0),
|
||||
)
|
||||
|
||||
X3DISC = (
|
||||
(0.0, 0.0, 0.0), (1.0, 0.0, 0), (0.8660254037844387, 0.49999999999999994, 0),
|
||||
(0.0, 0.0, 0.0), (0.8660254037844387, 0.49999999999999994, 0), (0.5000000000000001, 0.8660254037844386, 0),
|
||||
(0.0, 0.0, 0.0), (0.5000000000000001, 0.8660254037844386, 0), (6.123233995736766e-17, 1.0, 0),
|
||||
(0.0, 0.0, 0.0), (6.123233995736766e-17, 1.0, 0), (-0.4999999999999998, 0.8660254037844387, 0),
|
||||
(0.0, 0.0, 0.0), (-0.4999999999999998, 0.8660254037844387, 0), (-0.8660254037844385, 0.5000000000000003, 0),
|
||||
(0.0, 0.0, 0.0), (-0.8660254037844385, 0.5000000000000003, 0), (-1.0, 1.2246467991473532e-16, 0),
|
||||
(0.0, 0.0, 0.0), (-1.0, 1.2246467991473532e-16, 0), (-0.8660254037844388, -0.4999999999999997, 0),
|
||||
(0.0, 0.0, 0.0), (-0.8660254037844388, -0.4999999999999997, 0), (-0.5000000000000004, -0.8660254037844384, 0),
|
||||
(0.0, 0.0, 0.0), (-0.5000000000000004, -0.8660254037844384, 0), (-1.8369701987210297e-16, -1.0, 0),
|
||||
(0.0, 0.0, 0.0), (-1.8369701987210297e-16, -1.0, 0), (0.49999999999999933, -0.866025403784439, 0),
|
||||
(0.0, 0.0, 0.0), (0.49999999999999933, -0.866025403784439, 0), (0.8660254037844384, -0.5000000000000004, 0),
|
||||
(0.0, 0.0, 0.0), (0.8660254037844384, -0.5000000000000004, 0), (1.0, 0.0, 0),
|
||||
(0.0, 0.0, 0.0), (0, 1.0, 0.0), (0, 0.8660254037844387, 0.49999999999999994),
|
||||
(0.0, 0.0, 0.0), (0, 0.8660254037844387, 0.49999999999999994), (0, 0.5000000000000001, 0.8660254037844386),
|
||||
(0.0, 0.0, 0.0), (0, 0.5000000000000001, 0.8660254037844386), (0, 6.123233995736766e-17, 1.0),
|
||||
(0.0, 0.0, 0.0), (0, 6.123233995736766e-17, 1.0), (0, -0.4999999999999998, 0.8660254037844387),
|
||||
(0.0, 0.0, 0.0), (0, -0.4999999999999998, 0.8660254037844387), (0, -0.8660254037844385, 0.5000000000000003),
|
||||
(0.0, 0.0, 0.0), (0, -0.8660254037844385, 0.5000000000000003), (0, -1.0, 1.2246467991473532e-16),
|
||||
(0.0, 0.0, 0.0), (0, -1.0, 1.2246467991473532e-16), (0, -0.8660254037844388, -0.4999999999999997),
|
||||
(0.0, 0.0, 0.0), (0, -0.8660254037844388, -0.4999999999999997), (0, -0.5000000000000004, -0.8660254037844384),
|
||||
(0.0, 0.0, 0.0), (0, -0.5000000000000004, -0.8660254037844384), (0, -1.8369701987210297e-16, -1.0),
|
||||
(0.0, 0.0, 0.0), (0, -1.8369701987210297e-16, -1.0), (0, 0.49999999999999933, -0.866025403784439),
|
||||
(0.0, 0.0, 0.0), (0, 0.49999999999999933, -0.866025403784439), (0, 0.8660254037844384, -0.5000000000000004),
|
||||
(0.0, 0.0, 0.0), (0, 0.8660254037844384, -0.5000000000000004), (0, 1.0, 0.0),
|
||||
(0.0, 0.0, 0.0), (0.0, 0, 1.0), (0.49999999999999994, 0, 0.8660254037844387),
|
||||
(0.0, 0.0, 0.0), (0.49999999999999994, 0, 0.8660254037844387), (0.8660254037844386, 0, 0.5000000000000001),
|
||||
(0.0, 0.0, 0.0), (0.8660254037844386, 0, 0.5000000000000001), (1.0, 0, 6.123233995736766e-17),
|
||||
(0.0, 0.0, 0.0), (1.0, 0, 6.123233995736766e-17), (0.8660254037844387, 0, -0.4999999999999998),
|
||||
(0.0, 0.0, 0.0), (0.8660254037844387, 0, -0.4999999999999998), (0.5000000000000003, 0, -0.8660254037844385),
|
||||
(0.0, 0.0, 0.0), (0.5000000000000003, 0, -0.8660254037844385), (1.2246467991473532e-16, 0, -1.0),
|
||||
(0.0, 0.0, 0.0), (1.2246467991473532e-16, 0, -1.0), (-0.4999999999999997, 0, -0.8660254037844388),
|
||||
(0.0, 0.0, 0.0), (-0.4999999999999997, 0, -0.8660254037844388), (-0.8660254037844384, 0, -0.5000000000000004),
|
||||
(0.0, 0.0, 0.0), (-0.8660254037844384, 0, -0.5000000000000004), (-1.0, 0, -1.8369701987210297e-16),
|
||||
(0.0, 0.0, 0.0), (-1.0, 0, -1.8369701987210297e-16), (-0.866025403784439, 0, 0.49999999999999933),
|
||||
(0.0, 0.0, 0.0), (-0.866025403784439, 0, 0.49999999999999933), (-0.5000000000000004, 0, 0.8660254037844384),
|
||||
(0.0, 0.0, 0.0), (-0.5000000000000004, 0, 0.8660254037844384), (0.0, 0, 1.0),
|
||||
)
|
||||
|
||||
|
||||
class CustomGizmo():
|
||||
# FIXME: highliting/selection doesnt work
|
||||
def draw_very_custom_shape(self, ctx, custom_shape, select_id=None):
|
||||
# similar to draw_custom_shape
|
||||
shape, batch, shader = custom_shape
|
||||
|
||||
shader.bind()
|
||||
|
||||
if select_id is not None:
|
||||
gpu.select.load_id(select_id)
|
||||
else:
|
||||
if self.is_highlight:
|
||||
color = (*self.color_highlight, self.alpha_highlight)
|
||||
else:
|
||||
color = (*self.color, self.alpha)
|
||||
shader.uniform_float('color', color)
|
||||
shape.glenable()
|
||||
|
||||
shape.uniform_region(ctx)
|
||||
# shader.uniform_float('modelMatrix', self.matrix_world)
|
||||
with gpu.matrix.push_pop():
|
||||
gpu.matrix.multiply_matrix(self.matrix_world)
|
||||
batch.draw()
|
||||
|
||||
bgl.glDisable(bgl.GL_BLEND)
|
||||
|
||||
|
||||
class OffsetHandle():
|
||||
"""Handling mouse to offset gizmo from base along Z axis"""
|
||||
# FIXME: works a bit weird for rotated objects
|
||||
|
||||
def invoke(self, ctx, event):
|
||||
self.init_value = self.target_get_value('offset') / self.scale_value
|
||||
coordz = self.project_mouse(ctx, event)
|
||||
if coordz is None:
|
||||
return {'CANCELLED'}
|
||||
self.init_coordz = coordz
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def modal(self, ctx, event, tweak):
|
||||
coordz = self.project_mouse(ctx, event)
|
||||
if coordz is None:
|
||||
return {'CANCELLED'}
|
||||
delta = coordz - self.init_coordz
|
||||
if 'PRECISE' in tweak:
|
||||
delta /= 10.0
|
||||
value = max(0, self.init_value + delta)
|
||||
value *= self.scale_value
|
||||
# ctx.area.header_text_set(f"coords: {self.init_coordz} - {coordz}, delta: {delta}, value: {value}")
|
||||
ctx.area.header_text_set(f"Depth: {value}")
|
||||
self.target_set_value('offset', value)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
def project_mouse(self, ctx, event):
|
||||
"""Projecting mouse coords to local axis Z"""
|
||||
# logic from source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c:gizmo_arrow_modal
|
||||
|
||||
mouse = Vector((event.mouse_region_x, event.mouse_region_y))
|
||||
region = ctx.region
|
||||
region3d = ctx.region_data
|
||||
ray_orig = view3d_utils.region_2d_to_origin_3d(region, region3d, mouse)
|
||||
ray_norm = view3d_utils.region_2d_to_vector_3d(region, region3d, mouse)
|
||||
|
||||
# 'arrow' origin and direction
|
||||
base = Vector((0, 0, 0))
|
||||
axis = Vector((0, 0, 1))
|
||||
|
||||
# projecttion of the arrow to a plane, perpendicular to view ray
|
||||
axis_proj = axis - ray_norm * axis.dot(ray_norm)
|
||||
|
||||
# intersection of the axis with the plane through view origin perpendicular to the arrow projection
|
||||
coords = geometry.intersect_line_plane(base, axis, ray_orig, axis_proj)
|
||||
|
||||
return coords.z
|
||||
|
||||
def exit(self, ctx, cancel):
|
||||
if cancel:
|
||||
self.target_set_value('offset', self.init_value)
|
||||
else:
|
||||
self.group.update(ctx)
|
||||
|
||||
|
||||
class UglyDotGizmo(OffsetHandle, types.Gizmo):
|
||||
"""three orthogonal circles"""
|
||||
bl_idname = "BIM_GT_uglydot_3d"
|
||||
bl_target_properties = (
|
||||
{'id': 'offset', 'type': 'FLOAT', 'array_length': 1},
|
||||
)
|
||||
|
||||
__slots__ = (
|
||||
'scale_value',
|
||||
'custom_shape',
|
||||
'init_value',
|
||||
'init_coordz',
|
||||
)
|
||||
|
||||
def setup(self):
|
||||
self.custom_shape = self.new_custom_shape(type='TRIS', verts=X3DISC)
|
||||
|
||||
def refresh(self):
|
||||
offset = self.target_get_value('offset') / self.scale_value
|
||||
self.matrix_offset.col[3][2] = offset # z-shift
|
||||
|
||||
def draw(self, ctx):
|
||||
self.refresh()
|
||||
self.draw_custom_shape(self.custom_shape)
|
||||
|
||||
def draw_select(self, ctx, select_id):
|
||||
self.refresh()
|
||||
self.draw_custom_shape(self.custom_shape, select_id=select_id)
|
||||
|
||||
|
||||
class DotGizmo(CustomGizmo, OffsetHandle, types.Gizmo):
|
||||
"""Single dot viewport-aligned"""
|
||||
# FIXME: make it selectable
|
||||
bl_idname = "BIM_GT_dot_2d"
|
||||
bl_target_properties = (
|
||||
{'id': 'offset', 'type': 'FLOAT', 'array_length': 1},
|
||||
)
|
||||
|
||||
__slots__ = (
|
||||
'scale_value',
|
||||
'custom_shape',
|
||||
)
|
||||
|
||||
def setup(self):
|
||||
shader = DotsGizmoShader()
|
||||
self.custom_shape = shader, shader.batch(pos=((0, 0, 0),)), shader.prog
|
||||
self.use_draw_scale = False
|
||||
|
||||
def refresh(self):
|
||||
offset = self.target_get_value('offset') / self.scale_value
|
||||
self.matrix_offset.col[3][2] = offset # z-shifted
|
||||
|
||||
def draw(self, ctx):
|
||||
self.refresh()
|
||||
self.draw_very_custom_shape(ctx, self.custom_shape)
|
||||
|
||||
def draw_select(self, ctx, select_id):
|
||||
self.refresh()
|
||||
self.draw_very_custom_shape(ctx, self.custom_shape, select_id=select_id)
|
||||
|
||||
# doesn't get called
|
||||
# def test_select(self, ctx, location):
|
||||
# pass
|
||||
|
||||
|
||||
class ExtrusionGuidesGizmo(CustomGizmo, types.Gizmo):
|
||||
"""Extrusion guides
|
||||
|
||||
Noninteractive gizmo to indicate extrusion depth and planes.
|
||||
Draws main segment and orthogonal cross at endpoints.
|
||||
"""
|
||||
bl_idname = "BIM_GT_extrusion_guides"
|
||||
bl_target_properties = (
|
||||
{'id': 'depth', 'type': 'FLOAT', 'array_length': 1},
|
||||
)
|
||||
|
||||
__slots__ = (
|
||||
'scale_value',
|
||||
'custom_shape'
|
||||
)
|
||||
|
||||
def setup(self):
|
||||
shader = ExtrusionGuidesShader()
|
||||
self.custom_shape = shader, shader.batch(pos=((0, 0, 0), (0, 0, 1))), shader.prog
|
||||
self.use_draw_scale = False
|
||||
|
||||
def refresh(self):
|
||||
depth = self.target_get_value('depth') / self.scale_value
|
||||
self.matrix_offset.col[2][2] = depth # z-scaled
|
||||
|
||||
def draw(self, ctx):
|
||||
self.refresh()
|
||||
self.draw_very_custom_shape(ctx, self.custom_shape)
|
||||
|
||||
|
||||
class DimensionLabelGizmo(types.Gizmo):
|
||||
"""Text label for a dimension"""
|
||||
# does not work properly, fonts are totally screwed up
|
||||
|
||||
bl_idname = "BIM_GT_dimension_label"
|
||||
bl_target_properties = (
|
||||
{'id': 'value', 'type': 'FLOAT', 'array_length': 1},
|
||||
)
|
||||
|
||||
__slots__ = (
|
||||
'text_label'
|
||||
)
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def refresh(self, ctx):
|
||||
value = self.target_get_value('value')
|
||||
self.matrix_offset.col[3][2] = value * .5
|
||||
unit_system = ctx.scene.unit_settings.system
|
||||
self.text_label = bpy.utils.units.to_string(unit_system, 'LENGTH', value, 3, split_unit=False)
|
||||
|
||||
def draw(self, ctx):
|
||||
self.refresh(ctx)
|
||||
self.draw_text(ctx)
|
||||
|
||||
def draw_text(self, ctx):
|
||||
font_id = 0
|
||||
font_size = 16
|
||||
dpi = ctx.preferences.system.dpi
|
||||
|
||||
# pos = self.matrix_world @ Vector((0, 0, 0, 1))
|
||||
# pos = Vector((0, 0, 0.5))
|
||||
# region = ctx.region
|
||||
# region3d = ctx.region_data
|
||||
# pos = view3d_utils.location_3d_to_region_2d(region, region3d, pos)
|
||||
|
||||
# text = self.text_label
|
||||
|
||||
blf.size(font_id, font_size, dpi)
|
||||
blf.position(font_id, 0, 0, 0)
|
||||
blf.color(font_id, *self.color, self.alpha)
|
||||
blf.draw(font_id, "ABC")
|
||||
|
||||
|
||||
class ExtrusionWidget(types.GizmoGroup):
|
||||
bl_idname = "bim.extrusion_widget"
|
||||
bl_label = "Extrusion Gizmos"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_options = {'3D', 'PERSISTENT', 'SHOW_MODAL_ALL'}
|
||||
|
||||
# FIXME: use proper scale from ifc value to blender units
|
||||
|
||||
@classmethod
|
||||
def poll(cls, ctx):
|
||||
obj = ctx.object
|
||||
return (obj and obj.type == 'MESH'
|
||||
and obj.data.BIMMeshProperties.ifc_parameters.get('IfcExtrudedAreaSolid/Depth') is not None)
|
||||
|
||||
def setup(self, ctx):
|
||||
target = ctx.object
|
||||
prop = target.data.BIMMeshProperties.ifc_parameters.get('IfcExtrudedAreaSolid/Depth')
|
||||
|
||||
basis = target.matrix_world.normalized()
|
||||
theme = ctx.preferences.themes[0].user_interface
|
||||
|
||||
gz = self.handle = self.gizmos.new('BIM_GT_uglydot_3d')
|
||||
gz.matrix_basis = basis
|
||||
gz.scale_basis = 0.1
|
||||
gz.color = gz.color_highlight = tuple(theme.gizmo_primary)
|
||||
gz.alpha = 0.5
|
||||
gz.alpha_highlight = 1.0
|
||||
gz.use_draw_modal = True
|
||||
gz.target_set_prop('offset', prop, 'value')
|
||||
gz.scale_value = 1000
|
||||
|
||||
gz = self.guides = self.gizmos.new('BIM_GT_extrusion_guides')
|
||||
gz.matrix_basis = basis
|
||||
gz.color = gz.color_highlight = tuple(theme.gizmo_secondary)
|
||||
gz.alpha = gz.alpha_highlight = 0.5
|
||||
gz.use_draw_modal = True
|
||||
gz.target_set_prop('depth', prop, 'value')
|
||||
gz.scale_value = 1000
|
||||
|
||||
# gz = self.label = self.gizmos.new('GIZMO_GT_dimension_label')
|
||||
# gz.matrix_basis = basis
|
||||
# gz.color = tuple(theme.gizmo_secondary)
|
||||
# gz.alpha = 0.5
|
||||
# gz.use_draw_modal = True
|
||||
# gz.target_set_prop('value', target.demo, 'depth')
|
||||
|
||||
def refresh(self, ctx):
|
||||
"""updating gizmos"""
|
||||
target = ctx.object
|
||||
basis = target.matrix_world.normalized()
|
||||
self.handle.matrix_basis = basis
|
||||
self.guides.matrix_basis = basis
|
||||
|
||||
def update(self, ctx):
|
||||
"""updating object"""
|
||||
bpy.ops.bim.update_parametric_representation()
|
||||
# parameters disappear after update
|
||||
# need to retrieve and rebind them again
|
||||
bpy.ops.bim.get_representation_ifc_parameters()
|
||||
target = ctx.object
|
||||
prop = target.data.BIMMeshProperties.ifc_parameters.get('IfcExtrudedAreaSolid/Depth')
|
||||
self.handle.target_set_prop('offset', prop, 'value')
|
||||
self.guides.target_set_prop('depth', prop, 'value')
|
||||
@@ -0,0 +1,250 @@
|
||||
import bpy
|
||||
import json
|
||||
import addon_utils
|
||||
import blenderbim.bim.decoration as decoration
|
||||
import ifcopenshell.api.owner.settings
|
||||
from bpy.app.handlers import persistent
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.attribute.data import Data as AttributeData
|
||||
from ifcopenshell.api.type.data import Data as TypeData
|
||||
|
||||
|
||||
def mode_callback(obj, data):
|
||||
for obj in bpy.context.selected_objects:
|
||||
if (
|
||||
obj.mode != "EDIT"
|
||||
or not obj.data
|
||||
or not isinstance(obj.data, bpy.types.Mesh)
|
||||
or not obj.data.BIMMeshProperties.ifc_definition_id
|
||||
or not bpy.context.scene.BIMProjectProperties.is_authoring
|
||||
):
|
||||
return
|
||||
representation = IfcStore.get_file().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
|
||||
if representation.RepresentationType == "Tessellation" or representation.RepresentationType == "Brep":
|
||||
IfcStore.edited_objs.add(obj.name)
|
||||
|
||||
|
||||
def name_callback(obj, data):
|
||||
# Blender material names are up to 63 UTF-8 bytes
|
||||
if not obj.BIMObjectProperties.ifc_definition_id or "/" not in obj.name or len(bytes(obj.name, "utf-8")) >= 63:
|
||||
return
|
||||
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if not element.is_a("IfcRoot"):
|
||||
return
|
||||
if element.is_a("IfcSpatialStructureElement") or (hasattr(element, "IsDecomposedBy") and element.IsDecomposedBy):
|
||||
collection = obj.users_collection[0]
|
||||
collection.name = obj.name
|
||||
if element.is_a("IfcTypeProduct"):
|
||||
TypeData.purge()
|
||||
element.Name = "/".join(obj.name.split("/")[1:])
|
||||
AttributeData.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
|
||||
|
||||
def subscribe_to(object, data_path, callback):
|
||||
subscribe_to = object.path_resolve(data_path, False)
|
||||
bpy.msgbus.subscribe_rna(
|
||||
key=subscribe_to,
|
||||
owner=object,
|
||||
args=(
|
||||
object,
|
||||
data_path,
|
||||
),
|
||||
notify=callback,
|
||||
options={
|
||||
"PERSISTENT",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def purge_module_data():
|
||||
from blenderbim.bim import modules
|
||||
|
||||
for name, value in modules.items():
|
||||
try:
|
||||
getattr(getattr(getattr(ifcopenshell.api, name), "data"), "Data").purge()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
getattr(value, "prop").purge()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
@persistent
|
||||
def loadIfcStore(scene):
|
||||
IfcStore.purge()
|
||||
ifc_file = IfcStore.get_file()
|
||||
IfcStore.get_schema()
|
||||
[
|
||||
IfcStore.link_element(ifc_file.by_id(o.BIMObjectProperties.ifc_definition_id), o)
|
||||
for o in bpy.data.objects
|
||||
if o.BIMObjectProperties.ifc_definition_id
|
||||
]
|
||||
purge_module_data()
|
||||
|
||||
|
||||
@persistent
|
||||
def ensureIfcExported(scene):
|
||||
if IfcStore.get_file() and not bpy.context.scene.BIMProperties.ifc_file:
|
||||
bpy.ops.export_ifc.bim("INVOKE_DEFAULT")
|
||||
|
||||
|
||||
def get_application(ifc):
|
||||
version = get_application_version()
|
||||
for element in ifc.by_type("IfcApplication"):
|
||||
if element.ApplicationIdentifier == "BlenderBIM" and element.Version == version:
|
||||
return element
|
||||
return ifc.create_entity(
|
||||
"IfcApplication",
|
||||
**{
|
||||
"ApplicationDeveloper": create_application_organisation(ifc),
|
||||
"Version": get_application_version(),
|
||||
"ApplicationFullName": "BlenderBIM Add-on",
|
||||
"ApplicationIdentifier": "BlenderBIM",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def get_application_version():
|
||||
return ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def create_application_organisation(ifc):
|
||||
return ifc.create_entity(
|
||||
"IfcOrganization",
|
||||
**{
|
||||
"Name": "IfcOpenShell",
|
||||
"Description": "IfcOpenShell is an open source (LGPL) software library that helps users and software developers to work with the IFC file format.",
|
||||
"Roles": [ifc.create_entity("IfcActorRole", **{"Role": "USERDEFINED", "UserDefinedRole": "CONTRIBUTOR"})],
|
||||
"Addresses": [
|
||||
ifc.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The main webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://ifcopenshell.org",
|
||||
},
|
||||
),
|
||||
ifc.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The BlenderBIM Add-on webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://blenderbim.org",
|
||||
},
|
||||
),
|
||||
ifc.create_entity(
|
||||
"IfcTelecomAddress",
|
||||
**{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "REPOSITORY",
|
||||
"Description": "The source code repository of the software collection.",
|
||||
"WWWHomePageURL": "https://github.com/IfcOpenShell/IfcOpenShell.git",
|
||||
},
|
||||
),
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@persistent
|
||||
def setDefaultProperties(scene):
|
||||
ifcopenshell.api.owner.settings.get_person = (
|
||||
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_person))
|
||||
if bpy.context.scene.BIMOwnerProperties.user_person
|
||||
else None
|
||||
)
|
||||
ifcopenshell.api.owner.settings.get_organisation = (
|
||||
lambda ifc: ifc.by_id(int(bpy.context.scene.BIMOwnerProperties.user_organisation))
|
||||
if bpy.context.scene.BIMOwnerProperties.user_organisation
|
||||
else None
|
||||
)
|
||||
ifcopenshell.api.owner.settings.get_application = get_application
|
||||
if len(bpy.context.scene.DocProperties.drawing_styles) == 0:
|
||||
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
||||
drawing_style.name = "Technical"
|
||||
drawing_style.render_type = "VIEWPORT"
|
||||
drawing_style.raster_style = json.dumps(
|
||||
{
|
||||
"bpy.data.worlds[0].color": (1, 1, 1),
|
||||
"bpy.context.scene.render.engine": "BLENDER_WORKBENCH",
|
||||
"bpy.context.scene.render.film_transparent": False,
|
||||
"bpy.context.scene.display.shading.show_object_outline": True,
|
||||
"bpy.context.scene.display.shading.show_cavity": False,
|
||||
"bpy.context.scene.display.shading.cavity_type": "BOTH",
|
||||
"bpy.context.scene.display.shading.curvature_ridge_factor": 1,
|
||||
"bpy.context.scene.display.shading.curvature_valley_factor": 1,
|
||||
"bpy.context.scene.view_settings.view_transform": "Standard",
|
||||
"bpy.context.scene.display.shading.light": "FLAT",
|
||||
"bpy.context.scene.display.shading.color_type": "SINGLE",
|
||||
"bpy.context.scene.display.shading.single_color": (1, 1, 1),
|
||||
"bpy.context.scene.display.shading.show_shadows": False,
|
||||
"bpy.context.scene.display.shading.shadow_intensity": 0.5,
|
||||
"bpy.context.scene.display.light_direction": (0.5, 0.5, 0.5),
|
||||
"bpy.context.scene.view_settings.use_curve_mapping": False,
|
||||
"space.overlay.show_wireframes": True,
|
||||
"space.overlay.wireframe_threshold": 0,
|
||||
"space.overlay.show_floor": False,
|
||||
"space.overlay.show_axis_x": False,
|
||||
"space.overlay.show_axis_y": False,
|
||||
"space.overlay.show_axis_z": False,
|
||||
"space.overlay.show_object_origins": False,
|
||||
"space.overlay.show_relationship_lines": False,
|
||||
}
|
||||
)
|
||||
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
||||
drawing_style.name = "Shaded"
|
||||
drawing_style.render_type = "VIEWPORT"
|
||||
drawing_style.raster_style = json.dumps(
|
||||
{
|
||||
"bpy.data.worlds[0].color": (1, 1, 1),
|
||||
"bpy.context.scene.render.engine": "BLENDER_WORKBENCH",
|
||||
"bpy.context.scene.render.film_transparent": False,
|
||||
"bpy.context.scene.display.shading.show_object_outline": True,
|
||||
"bpy.context.scene.display.shading.show_cavity": True,
|
||||
"bpy.context.scene.display.shading.cavity_type": "BOTH",
|
||||
"bpy.context.scene.display.shading.curvature_ridge_factor": 1,
|
||||
"bpy.context.scene.display.shading.curvature_valley_factor": 1,
|
||||
"bpy.context.scene.view_settings.view_transform": "Standard",
|
||||
"bpy.context.scene.display.shading.light": "STUDIO",
|
||||
"bpy.context.scene.display.shading.color_type": "MATERIAL",
|
||||
"bpy.context.scene.display.shading.single_color": (1, 1, 1),
|
||||
"bpy.context.scene.display.shading.show_shadows": True,
|
||||
"bpy.context.scene.display.shading.shadow_intensity": 0.5,
|
||||
"bpy.context.scene.display.light_direction": (0.5, 0.5, 0.5),
|
||||
"bpy.context.scene.view_settings.use_curve_mapping": False,
|
||||
"space.overlay.show_wireframes": True,
|
||||
"space.overlay.wireframe_threshold": 0,
|
||||
"space.overlay.show_floor": False,
|
||||
"space.overlay.show_axis_x": False,
|
||||
"space.overlay.show_axis_y": False,
|
||||
"space.overlay.show_axis_z": False,
|
||||
"space.overlay.show_object_origins": False,
|
||||
"space.overlay.show_relationship_lines": False,
|
||||
}
|
||||
)
|
||||
drawing_style = bpy.context.scene.DocProperties.drawing_styles.add()
|
||||
drawing_style.name = "Blender Default"
|
||||
drawing_style.render_type = "DEFAULT"
|
||||
bpy.ops.bim.save_drawing_style(index="2")
|
||||
|
||||
|
||||
@persistent
|
||||
def toggleDecorationsOnLoad(*args):
|
||||
toggle = bpy.context.scene.DocProperties.should_draw_decorations
|
||||
if toggle:
|
||||
decoration.DecorationsHandler.install(bpy.context)
|
||||
else:
|
||||
decoration.DecorationsHandler.uninstall()
|
||||
@@ -1,5 +1,6 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.handler
|
||||
|
||||
|
||||
class IfcStore:
|
||||
@@ -8,8 +9,24 @@ class IfcStore:
|
||||
schema = None
|
||||
id_map = {}
|
||||
guid_map = {}
|
||||
edited_objs = set()
|
||||
pset_template_path = ""
|
||||
pset_template_file = None
|
||||
library_path = ""
|
||||
library_file = None
|
||||
|
||||
@staticmethod
|
||||
def purge():
|
||||
IfcStore.path = ""
|
||||
IfcStore.file = None
|
||||
IfcStore.schema = None
|
||||
IfcStore.id_map = {}
|
||||
IfcStore.guid_map = {}
|
||||
IfcStore.edited_objs = set()
|
||||
IfcStore.pset_template_path = ""
|
||||
IfcStore.pset_template_file = None
|
||||
IfcStore.library_path = ""
|
||||
IfcStore.library_file = None
|
||||
|
||||
@staticmethod
|
||||
def get_file():
|
||||
@@ -33,12 +50,16 @@ class IfcStore:
|
||||
@staticmethod
|
||||
def link_element(element, obj):
|
||||
IfcStore.id_map[element.id()] = obj
|
||||
IfcStore.guid_map[element.GlobalId] = obj
|
||||
if hasattr(element, "GlobalId"):
|
||||
IfcStore.guid_map[element.GlobalId] = obj
|
||||
obj.BIMObjectProperties.ifc_definition_id = element.id()
|
||||
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
||||
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
|
||||
|
||||
@staticmethod
|
||||
def unlink_element(element, obj=None):
|
||||
del IfcStore.id_map[element.id()]
|
||||
del IfcStore.guid_map[element.GlobalId]
|
||||
if hasattr(element, "GlobalId"):
|
||||
del IfcStore.guid_map[element.GlobalId]
|
||||
if obj:
|
||||
obj.BIMObjectProperties.ifc_definition_id = 0
|
||||
@@ -1,7 +1,7 @@
|
||||
import bpy
|
||||
import blenderbim.bim.module.aggregate.assign_object as assign_object
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.aggregate.data import Data
|
||||
from ifcopenshell.api.aggregate.data import Data
|
||||
|
||||
|
||||
class AssignObject(bpy.types.Operator):
|
||||
@@ -12,36 +12,41 @@ class AssignObject(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
related_object = bpy.data.objects.get(self.related_object) if self.related_object else bpy.context.active_object
|
||||
props = related_object.BIMObjectProperties
|
||||
relating_object = bpy.data.objects.get(self.relating_object) if self.relating_object else props.relating_object
|
||||
related_objects = (
|
||||
[bpy.data.objects.get(self.related_object)] if self.related_object else bpy.context.selected_objects
|
||||
)
|
||||
relating_object = bpy.data.objects.get(self.relating_object)
|
||||
if not relating_object or not relating_object.BIMObjectProperties.ifc_definition_id:
|
||||
return {"FINISHED"}
|
||||
product = self.file.by_id(props.ifc_definition_id)
|
||||
assign_object.Usecase(
|
||||
self.file,
|
||||
{
|
||||
"product": product,
|
||||
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
|
||||
},
|
||||
).execute()
|
||||
bpy.ops.bim.edit_object_placement(obj=related_object.name)
|
||||
Data.load(props.ifc_definition_id)
|
||||
bpy.ops.bim.disable_editing_aggregate(obj=related_object.name)
|
||||
for related_object in related_objects:
|
||||
oprops = related_object.BIMObjectProperties
|
||||
product = self.file.by_id(oprops.ifc_definition_id)
|
||||
ifcopenshell.api.run(
|
||||
"aggregate.assign_object",
|
||||
self.file,
|
||||
**{
|
||||
"product": product,
|
||||
"relating_object": self.file.by_id(relating_object.BIMObjectProperties.ifc_definition_id),
|
||||
},
|
||||
)
|
||||
bpy.ops.bim.edit_object_placement(obj=related_object.name)
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
bpy.ops.bim.disable_editing_aggregate(obj=related_object.name)
|
||||
|
||||
spatial_collection = bpy.data.collections.get(related_object.name)
|
||||
relating_collection = bpy.data.collections.get(relating_object.name)
|
||||
if spatial_collection:
|
||||
self.remove_collection(bpy.context.scene.collection, spatial_collection)
|
||||
for collection in bpy.data.collections:
|
||||
if collection == relating_collection:
|
||||
collection.children.link(spatial_collection)
|
||||
continue
|
||||
self.remove_collection(collection, spatial_collection)
|
||||
else:
|
||||
for collection in related_object.users_collection:
|
||||
collection.objects.unlink(related_object)
|
||||
relating_collection.objects.link(related_object)
|
||||
spatial_collection = bpy.data.collections.get(related_object.name)
|
||||
relating_collection = bpy.data.collections.get(relating_object.name)
|
||||
if spatial_collection:
|
||||
self.remove_collection(bpy.context.scene.collection, spatial_collection)
|
||||
for collection in bpy.data.collections:
|
||||
if collection == relating_collection:
|
||||
if not collection.children.get(spatial_collection.name):
|
||||
collection.children.link(spatial_collection)
|
||||
continue
|
||||
self.remove_collection(collection, spatial_collection)
|
||||
else:
|
||||
for collection in related_object.users_collection:
|
||||
collection.objects.unlink(related_object)
|
||||
relating_collection.objects.link(related_object)
|
||||
return {"FINISHED"}
|
||||
|
||||
def remove_collection(self, parent, child):
|
||||
@@ -1,5 +1,5 @@
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.module.aggregate.data import Data
|
||||
from ifcopenshell.api.aggregate.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class BIM_PT_aggregate(Panel):
|
||||
if not IfcStore.get_file().by_id(props.ifc_definition_id).is_a("IfcObjectDefinition"):
|
||||
return False
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(props.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
if not Data.products[props.ifc_definition_id]:
|
||||
return False
|
||||
return True
|
||||
@@ -29,12 +29,13 @@ class BIM_PT_aggregate(Panel):
|
||||
if not props.ifc_definition_id:
|
||||
return
|
||||
if props.ifc_definition_id not in Data.products:
|
||||
Data.load(props.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), props.ifc_definition_id)
|
||||
|
||||
if props.is_editing_aggregate:
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "relating_object", text="")
|
||||
row.operator("bim.assign_object", icon="CHECKMARK", text="")
|
||||
if props.relating_object:
|
||||
row.operator("bim.assign_object", icon="CHECKMARK", text="").relating_object = props.relating_object.name
|
||||
row.operator("bim.disable_editing_aggregate", icon="X", text="")
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
@@ -1,9 +1,9 @@
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.module.attribute.edit_attributes as edit_attributes
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.attribute.data import Data
|
||||
from ifcopenshell.api.attribute.data import Data
|
||||
|
||||
|
||||
class EnableEditingAttributes(bpy.types.Operator):
|
||||
@@ -33,7 +33,7 @@ class EnableEditingAttributes(bpy.types.Operator):
|
||||
elif attribute["type"] == "integer":
|
||||
new.int_value = attribute["value"] or 0
|
||||
elif attribute["type"] == "float":
|
||||
new.float_value = attribute["value"] or 0.
|
||||
new.float_value = attribute["value"] or 0.0
|
||||
elif attribute["type"] == "enum":
|
||||
new.enum_items = json.dumps(attribute["enum_items"])
|
||||
if attribute["value"]:
|
||||
@@ -95,17 +95,16 @@ class EditAttributes(bpy.types.Operator):
|
||||
elif attribute["type"] == "enum":
|
||||
attributes[attribute["name"]] = blender_attribute.enum_value
|
||||
product = self.file.by_id(oprops.ifc_definition_id)
|
||||
edit_attributes.Usecase(self.file, {
|
||||
"product": product,
|
||||
"attributes": attributes
|
||||
}).execute()
|
||||
ifcopenshell.api.run(
|
||||
"attribute.edit_attributes", self.file, **{"product": product, "attributes": attributes}
|
||||
)
|
||||
if "Name" in attributes:
|
||||
new_name = "{}/{}".format(product.is_a(), product.Name or "Unnamed")
|
||||
collection = bpy.data.collections.get(obj.name)
|
||||
if collection:
|
||||
collection.name = new_name
|
||||
obj.name = new_name
|
||||
Data.load(oprops.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
bpy.ops.bim.disable_editing_attributes(obj=obj.name, obj_type=self.obj_type)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import bpy
|
||||
import blenderbim.bim.schema # refactor
|
||||
from blenderbim.bim.module.material.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from bpy.types import PropertyGroup
|
||||
@@ -1,5 +1,6 @@
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.module.attribute.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.attribute.data import Data
|
||||
|
||||
|
||||
def draw_ui(context, layout, obj_type):
|
||||
@@ -7,7 +8,7 @@ def draw_ui(context, layout, obj_type):
|
||||
oprops = obj.BIMObjectProperties
|
||||
props = obj.BIMAttributeProperties
|
||||
if oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(oprops.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
|
||||
if props.is_editing_attributes:
|
||||
row = layout.row(align=True)
|
||||
@@ -50,6 +51,12 @@ def draw_ui(context, layout, obj_type):
|
||||
op = row.operator("bim.enable_editing_attributes", icon="GREASEPENCIL", text="Edit")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
|
||||
if "GlobalId" not in [a["name"] for a in Data.products[oprops.ifc_definition_id]]:
|
||||
row = layout.row(align=True)
|
||||
row.label(text="STEP ID")
|
||||
row.label(text=str(oprops.ifc_definition_id))
|
||||
|
||||
for attribute in Data.products[oprops.ifc_definition_id]:
|
||||
if attribute["value"] is None or attribute["type"] == "entity":
|
||||
continue
|
||||
@@ -0,0 +1,18 @@
|
||||
import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
prop.AuginProperties,
|
||||
ui.BIM_PT_augin,
|
||||
operator.AuginLogin,
|
||||
operator.AuginCreateNewModel,
|
||||
operator.AuginReset,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.AuginProperties = bpy.props.PointerProperty(type=prop.AuginProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.AuginProperties
|
||||
@@ -0,0 +1,133 @@
|
||||
import os
|
||||
import bpy
|
||||
import json
|
||||
import string
|
||||
import random
|
||||
import shutil
|
||||
import requests
|
||||
import tempfile
|
||||
import datetime
|
||||
import addon_utils
|
||||
|
||||
|
||||
class AuginLogin(bpy.types.Operator):
|
||||
bl_idname = "bim.augin_login"
|
||||
bl_label = "Login to Augin"
|
||||
|
||||
def execute(self, context):
|
||||
props = bpy.context.scene.AuginProperties
|
||||
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/user_login"
|
||||
payload = {"email": props.username, "password": props.password}
|
||||
response = requests.request("POST", url, data=payload)
|
||||
result = response.json()
|
||||
|
||||
if result["success_feedback"]["success"]:
|
||||
props.token = result["token"]
|
||||
else:
|
||||
self.report({"ERROR"}, "Login failed :(")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AuginReset(bpy.types.Operator):
|
||||
bl_idname = "bim.augin_reset"
|
||||
bl_label = "Upload Another Project"
|
||||
|
||||
def execute(self, context):
|
||||
props = bpy.context.scene.AuginProperties
|
||||
props.is_success = False
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AuginCreateNewModel(bpy.types.Operator):
|
||||
bl_idname = "bim.augin_create_new_model"
|
||||
bl_label = "Create New Augin Model"
|
||||
|
||||
def execute(self, context):
|
||||
import boto3
|
||||
from botocore.config import Config
|
||||
props = bpy.context.scene.AuginProperties
|
||||
|
||||
# Create project
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/new_model"
|
||||
|
||||
chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
|
||||
props.project_filename = "BBM{}{}".format(
|
||||
datetime.datetime.now().strftime("%Y%m%d%H%M%S"), "".join(random.choice(chars) for _ in range(6))
|
||||
)
|
||||
addon_version = ".".join(
|
||||
[
|
||||
str(x)
|
||||
for x in [
|
||||
addon.bl_info.get("version", (-1, -1, -1))
|
||||
for addon in addon_utils.modules()
|
||||
if addon.bl_info["name"] == "BlenderBIM"
|
||||
][0]
|
||||
]
|
||||
)
|
||||
|
||||
payload = {
|
||||
"user_token": props.token,
|
||||
"partner_token": "Mmf2zpxdgrkHaUNRm6Cv7GLJdBAeb7Rn",
|
||||
"project_name": props.project_name,
|
||||
"model_filename": props.project_filename + ".ifc",
|
||||
"thumb_filename": props.project_filename + ".png",
|
||||
"app_name": "BlenderBIM",
|
||||
"sw_version": bpy.app.version_string,
|
||||
"plugin_version": addon_version,
|
||||
}
|
||||
response = requests.request("POST", url, data=payload)
|
||||
result = response.json()
|
||||
|
||||
# Upload to S3
|
||||
my_config = Config(
|
||||
region_name=result["s3_region"],
|
||||
)
|
||||
|
||||
client = boto3.client(
|
||||
"s3",
|
||||
aws_access_key_id=result["s3_key"],
|
||||
aws_secret_access_key=result["s3_secret"],
|
||||
aws_session_token=result["s3_token"],
|
||||
config=my_config,
|
||||
)
|
||||
|
||||
# Generate thumb
|
||||
old_file_format = context.scene.render.image_settings.file_format
|
||||
old_filepath = context.scene.render.filepath
|
||||
|
||||
cam = bpy.data.cameras.new("Camera")
|
||||
cam_obj = bpy.data.objects.new("Camera", cam)
|
||||
context.scene.collection.objects.link(cam_obj)
|
||||
context.scene.camera = cam_obj
|
||||
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
thumb_path = os.path.join(tmpdir, "thumb.png")
|
||||
context.scene.render.image_settings.file_format = "PNG"
|
||||
context.scene.render.filepath = thumb_path
|
||||
bpy.ops.render.opengl(write_still=True)
|
||||
|
||||
context.scene.render.image_settings.file_format = old_file_format
|
||||
context.scene.render.filepath = old_filepath
|
||||
|
||||
client.upload_file(bpy.context.scene.BIMProperties.ifc_file, result["s3_bucket"], result["model_path"])
|
||||
client.upload_file(thumb_path, result["s3_bucket"], result["thumb_path"])
|
||||
|
||||
|
||||
# Notify done
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/files_uploaded"
|
||||
payload = {
|
||||
"user_token": props.token,
|
||||
"ifc_filesize": os.path.getsize(bpy.context.scene.BIMProperties.ifc_file),
|
||||
"model_filesize": os.path.getsize(bpy.context.scene.BIMProperties.ifc_file),
|
||||
"thumb_filesize": os.path.getsize(thumb_path),
|
||||
"model_upload_path": result["model_path"],
|
||||
"thumb_upload_path": result["thumb_path"],
|
||||
"model_id": result["model_id"],
|
||||
}
|
||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
response = requests.request("POST", url, headers=headers, data=payload)
|
||||
|
||||
shutil.rmtree(tmpdir)
|
||||
props.is_success = True
|
||||
return {"FINISHED"}
|
||||
@@ -0,0 +1,11 @@
|
||||
import bpy.props
|
||||
import bpy.types
|
||||
|
||||
|
||||
class AuginProperties(bpy.types.PropertyGroup):
|
||||
username: bpy.props.StringProperty(name="Username")
|
||||
password: bpy.props.StringProperty(name="Password")
|
||||
token: bpy.props.StringProperty(name="Token")
|
||||
project_name: bpy.props.StringProperty(name="Project Name")
|
||||
project_filename: bpy.props.StringProperty(name="IFC Filename")
|
||||
is_success: bpy.props.BoolProperty(name="Is Successful Upload", default=False)
|
||||
@@ -0,0 +1,45 @@
|
||||
import bpy.types
|
||||
|
||||
|
||||
class BIM_PT_augin(bpy.types.Panel):
|
||||
bl_label = "Augin"
|
||||
bl_idname = "BIM_PT_augin"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
scene = context.scene
|
||||
props = scene.AuginProperties
|
||||
|
||||
if not props.token:
|
||||
row = layout.row()
|
||||
row.prop(props, "username")
|
||||
row = layout.row()
|
||||
row.prop(props, "password")
|
||||
row = layout.row()
|
||||
row.operator("bim.augin_login")
|
||||
return
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="Logged in as " + props.username)
|
||||
|
||||
if not bpy.context.scene.BIMProperties.ifc_file:
|
||||
row = layout.row()
|
||||
row.label(text="No IFC Found")
|
||||
return
|
||||
|
||||
if props.is_success:
|
||||
row = layout.row()
|
||||
row.label(text="Upload Successful")
|
||||
row = layout.row()
|
||||
row.operator("bim.augin_reset")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.prop(props, "project_name")
|
||||
row = layout.row()
|
||||
row.operator("bim.augin_create_new_model")
|
||||
@@ -17,6 +17,11 @@ from bpy.props import (
|
||||
bcfviewpoints_enum = None
|
||||
|
||||
|
||||
def purge():
|
||||
global bcfviewpoints_enum
|
||||
bcfviewpoints_enum = None
|
||||
|
||||
|
||||
def updateBcfReferenceLink(self, context):
|
||||
if bpy.context.scene.BCFProperties.is_loaded:
|
||||
bpy.ops.bim.edit_bcf_reference_links()
|
||||
@@ -3,9 +3,14 @@ import bpy
|
||||
import tempfile
|
||||
import webbrowser
|
||||
import ifcopenshell
|
||||
import bimtester
|
||||
import bimtester.run
|
||||
import bimtester.reports
|
||||
|
||||
try:
|
||||
import bimtester
|
||||
import bimtester.run
|
||||
import bimtester.reports
|
||||
except:
|
||||
print("Failed to load BIMTester. Try disabling other add-ons, in particular Blender-OSM. See bug #1318.")
|
||||
|
||||
from pathlib import Path
|
||||
from itertools import cycle
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
@@ -31,7 +36,7 @@ class ExecuteBIMTester(bpy.types.Operator):
|
||||
"schema_file": "",
|
||||
"schema_name": "",
|
||||
"lang": "en",
|
||||
"steps": props.steps
|
||||
"steps": props.steps,
|
||||
}
|
||||
use_stored_ifc = props.should_load_from_memory and IfcStore.get_file()
|
||||
runner = bimtester.run.TestRunner(args["ifc"], ifc=IfcStore.get_file() if use_stored_ifc else None)
|
||||
@@ -59,9 +64,9 @@ class BIMTesterPurge(bpy.types.Operator):
|
||||
|
||||
class SelectFeature(bpy.types.Operator):
|
||||
bl_idname = "bim.select_feature"
|
||||
bl_label = "Select Feature"
|
||||
bl_label = "Select Feature / IDS"
|
||||
filename_ext = ".feature"
|
||||
filter_glob: bpy.props.StringProperty(default="*.feature", options={"HIDDEN"})
|
||||
filter_glob: bpy.props.StringProperty(default="*.feature;*.xml", options={"HIDDEN"})
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
@@ -1,6 +1,5 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.prop import StrProperty
|
||||
from blenderbim.bim.module.root.prop import getIfcClasses
|
||||
from bpy.types import PropertyGroup
|
||||
@@ -19,6 +18,13 @@ scenarios_enum = []
|
||||
classes_enum = []
|
||||
|
||||
|
||||
def purge():
|
||||
global scenarios_enum
|
||||
global classes_enum
|
||||
scenarios_enum = []
|
||||
classes_enum = []
|
||||
|
||||
|
||||
def getScenarios(self, context):
|
||||
global scenarios_enum
|
||||
if len(scenarios_enum) < 1:
|
||||
@@ -41,7 +47,7 @@ def refreshScenarios(self, context):
|
||||
|
||||
|
||||
class BimTesterProperties(PropertyGroup):
|
||||
feature: StringProperty(default="", name="Feature File", update=refreshScenarios)
|
||||
feature: StringProperty(default="", name="Feature / IDS", update=refreshScenarios)
|
||||
steps: StringProperty(default="", name="Custom Steps")
|
||||
ifc_file: StringProperty(default="", name="IFC File")
|
||||
audit_ifc_class: EnumProperty(items=getIfcClasses, name="Audit Class")
|
||||
@@ -1,6 +1,5 @@
|
||||
import bpy
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.owner.data import Data
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -1,13 +1,8 @@
|
||||
import bpy
|
||||
import json
|
||||
import blenderbim.bim.module.classification.add_classification as add_classification
|
||||
import blenderbim.bim.module.classification.remove_classification as remove_classification
|
||||
import blenderbim.bim.module.classification.edit_classification as edit_classification
|
||||
import blenderbim.bim.module.classification.add_reference as add_reference
|
||||
import blenderbim.bim.module.classification.remove_reference as remove_reference
|
||||
import blenderbim.bim.module.classification.edit_reference as edit_reference
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.classification.data import Data
|
||||
from ifcopenshell.api.classification.data import Data
|
||||
from blenderbim.bim.module.classification.prop import getClassifications, getReferences
|
||||
|
||||
|
||||
@@ -34,10 +29,12 @@ class AddClassification(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationProperties
|
||||
add_classification.Usecase(
|
||||
IfcStore.get_file(), {"classification": Data.library_file.by_id(int(props.available_classifications))}
|
||||
).execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_classification",
|
||||
IfcStore.get_file(),
|
||||
**{"classification": Data.library_file.by_id(int(props.available_classifications))},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -80,8 +77,12 @@ class RemoveClassification(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
remove_classification.Usecase(self.file, {"classification": self.file.by_id(self.classification)}).execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_classification",
|
||||
self.file,
|
||||
**{"classification": self.file.by_id(self.classification)},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -100,10 +101,12 @@ class EditClassification(bpy.types.Operator):
|
||||
else:
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
self.file = IfcStore.get_file()
|
||||
edit_classification.Usecase(
|
||||
self.file, {"classification": self.file.by_id(props.active_classification_id), "attributes": attributes}
|
||||
).execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_classification",
|
||||
self.file,
|
||||
**{"classification": self.file.by_id(props.active_classification_id), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_classification()
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -152,15 +155,16 @@ class RemoveClassificationReference(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else bpy.context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
remove_reference.Usecase(
|
||||
ifcopenshell.api.run(
|
||||
"classification.remove_reference",
|
||||
self.file,
|
||||
{
|
||||
**{
|
||||
"reference": self.file.by_id(self.reference),
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
},
|
||||
).execute()
|
||||
Data.load(obj.BIMObjectProperties.ifc_definition_id)
|
||||
Data.load()
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -179,10 +183,12 @@ class EditClassificationReference(bpy.types.Operator):
|
||||
else:
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
self.file = IfcStore.get_file()
|
||||
edit_reference.Usecase(
|
||||
self.file, {"reference": self.file.by_id(props.active_reference_id), "attributes": attributes}
|
||||
).execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_reference",
|
||||
self.file,
|
||||
**{"reference": self.file.by_id(props.active_reference_id), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_classification_reference()
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -206,16 +212,17 @@ class AddClassificationReference(bpy.types.Operator):
|
||||
classification = self.file.by_id(classification_id)
|
||||
break
|
||||
|
||||
add_reference.Usecase(
|
||||
ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
self.file,
|
||||
{
|
||||
**{
|
||||
"reference": Data.library_file.by_id(self.reference),
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"classification": classification
|
||||
"classification": classification,
|
||||
},
|
||||
).execute()
|
||||
Data.load(obj.BIMObjectProperties.ifc_definition_id)
|
||||
Data.load()
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import bpy
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from blenderbim.bim.module.classification.data import Data
|
||||
from ifcopenshell.api.classification.data import Data
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
@@ -16,6 +16,11 @@ from bpy.props import (
|
||||
classification_enum = []
|
||||
|
||||
|
||||
def purge():
|
||||
global classification_enum
|
||||
classification_enum = []
|
||||
|
||||
|
||||
def getClassifications(self, context):
|
||||
global classification_enum
|
||||
if len(classification_enum) < 1:
|
||||
@@ -1,6 +1,6 @@
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.classification.data import Data
|
||||
from ifcopenshell.api.classification.data import Data
|
||||
|
||||
|
||||
class BIM_PT_classifications(Panel):
|
||||
@@ -17,7 +17,7 @@ class BIM_PT_classifications(Panel):
|
||||
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load()
|
||||
Data.load(IfcStore.get_file())
|
||||
|
||||
self.props = context.scene.BIMClassificationProperties
|
||||
|
||||
@@ -79,9 +79,9 @@ class BIM_PT_classification_references(Panel):
|
||||
self.props = obj.BIMClassificationReferenceProperties
|
||||
self.file = IfcStore.get_file()
|
||||
if not Data.is_loaded:
|
||||
Data.load()
|
||||
Data.load(IfcStore.get_file())
|
||||
if self.oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(self.oprops.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id)
|
||||
|
||||
self.draw_add_ui()
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import bpy
|
||||
import json
|
||||
import blenderbim.bim.module.constraint.add_objective as add_objective
|
||||
import blenderbim.bim.module.constraint.edit_objective as edit_objective
|
||||
import blenderbim.bim.module.constraint.remove_constraint as remove_constraint
|
||||
import blenderbim.bim.module.constraint.assign_constraint as assign_constraint
|
||||
import blenderbim.bim.module.constraint.unassign_constraint as unassign_constraint
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.util.attribute
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.constraint.data import Data
|
||||
from ifcopenshell.api.constraint.data import Data
|
||||
|
||||
|
||||
class LoadObjectives(bpy.types.Operator):
|
||||
@@ -50,19 +47,18 @@ class EnableEditingConstraint(bpy.types.Operator):
|
||||
data = Data.objectives[self.constraint]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(props.is_editing).all_attributes():
|
||||
data_type = str(attribute.type_of_attribute)
|
||||
if "<entity" in data_type:
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
new = props.constraint_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
if "<string>" in data_type:
|
||||
new.data_type = data_type
|
||||
if data_type == "string":
|
||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||
new.data_type = "string"
|
||||
elif "<enumeration" in data_type:
|
||||
new.enum_items = json.dumps(attribute.type_of_attribute().declared_type().enumeration_items())
|
||||
new.data_type = "enum"
|
||||
elif data_type == "enum":
|
||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||
if data[attribute.name()]:
|
||||
new.enum_value = data[attribute.name()]
|
||||
props.active_constraint_id = self.constraint
|
||||
@@ -83,8 +79,8 @@ class AddObjective(bpy.types.Operator):
|
||||
bl_label = "Add Objective"
|
||||
|
||||
def execute(self, context):
|
||||
result = add_objective.Usecase(IfcStore.get_file()).execute()
|
||||
Data.load()
|
||||
result = ifcopenshell.api.run("constraint.add_objective", IfcStore.get_file())
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_objectives()
|
||||
bpy.ops.bim.enable_editing_constraint(constraint=result.id())
|
||||
return {"FINISHED"}
|
||||
@@ -105,10 +101,12 @@ class EditObjective(bpy.types.Operator):
|
||||
else:
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
self.file = IfcStore.get_file()
|
||||
edit_objective.Usecase(
|
||||
self.file, {"objective": self.file.by_id(props.active_constraint_id), "attributes": attributes}
|
||||
).execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"constraint.edit_objective",
|
||||
self.file,
|
||||
**{"objective": self.file.by_id(props.active_constraint_id), "attributes": attributes}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.load_objectives()
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -121,8 +119,10 @@ class RemoveConstraint(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMConstraintProperties
|
||||
self.file = IfcStore.get_file()
|
||||
remove_constraint.Usecase(self.file, {"constraint": self.file.by_id(self.constraint)}).execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"constraint.remove_constraint", self.file, **{"constraint": self.file.by_id(self.constraint)}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
if props.is_editing == "IfcObjective":
|
||||
bpy.ops.bim.load_objectives()
|
||||
return {"FINISHED"}
|
||||
@@ -163,11 +163,15 @@ class AssignConstraint(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
assign_constraint.Usecase(self.file, {
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"constraint": self.file.by_id(self.constraint)
|
||||
}).execute()
|
||||
Data.load(obj.BIMObjectProperties.ifc_definition_id)
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"constraint": self.file.by_id(self.constraint),
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -180,9 +184,13 @@ class UnassignConstraint(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
unassign_constraint.Usecase(self.file, {
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"constraint": self.file.by_id(self.constraint)
|
||||
}).execute()
|
||||
Data.load(obj.BIMObjectProperties.ifc_definition_id)
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"constraint": self.file.by_id(self.constraint),
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
return {"FINISHED"}
|
||||
@@ -1,6 +1,6 @@
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.constraint.data import Data
|
||||
from ifcopenshell.api.constraint.data import Data
|
||||
|
||||
|
||||
class BIM_PT_constraints(Panel):
|
||||
@@ -17,7 +17,7 @@ class BIM_PT_constraints(Panel):
|
||||
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load()
|
||||
Data.load(IfcStore.get_file())
|
||||
|
||||
self.props = context.scene.BIMConstraintProperties
|
||||
|
||||
@@ -42,7 +42,6 @@ class BIM_PT_constraints(Panel):
|
||||
|
||||
if self.props.active_constraint_id:
|
||||
self.draw_editable_ui(context)
|
||||
return
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
for attribute in self.props.constraint_attributes:
|
||||
@@ -74,9 +73,9 @@ class BIM_PT_object_constraints(Panel):
|
||||
self.props = obj.BIMObjectConstraintProperties
|
||||
self.file = IfcStore.get_file()
|
||||
if not Data.is_loaded:
|
||||
Data.load()
|
||||
Data.load(IfcStore.get_file())
|
||||
if self.oprops.ifc_definition_id not in Data.products:
|
||||
Data.load(self.oprops.ifc_definition_id)
|
||||
Data.load(IfcStore.get_file(), self.oprops.ifc_definition_id)
|
||||
|
||||
self.draw_add_ui()
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import bpy
|
||||
import blenderbim.bim.module.context.add_context as add_context
|
||||
import blenderbim.bim.module.context.remove_context as remove_context
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.context.data import Data
|
||||
from ifcopenshell.api.context.data import Data
|
||||
|
||||
|
||||
class AddSubcontext(bpy.types.Operator):
|
||||
@@ -14,15 +13,16 @@ class AddSubcontext(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
add_context.Usecase(
|
||||
ifcopenshell.api.run(
|
||||
"context.add_context",
|
||||
self.file,
|
||||
{
|
||||
**{
|
||||
"context": self.context or bpy.context.scene.BIMProperties.available_contexts,
|
||||
"subcontext": self.subcontext or bpy.context.scene.BIMProperties.available_subcontexts,
|
||||
"target_view": self.target_view or bpy.context.scene.BIMProperties.available_target_views,
|
||||
},
|
||||
).execute()
|
||||
Data.load()
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -33,7 +33,8 @@ class RemoveSubcontext(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
usecase = remove_context.Usecase(self.file, {"context": self.file.by_id(self.ifc_definition_id)})
|
||||
usecase.execute()
|
||||
Data.load()
|
||||
ifcopenshell.api.run(
|
||||
"context.remove_context", self.file, **{"context": self.file.by_id(self.ifc_definition_id)}
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
@@ -1,5 +1,5 @@
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.module.context.data import Data
|
||||
from ifcopenshell.api.context.data import Data
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class BIM_PT_context(Panel):
|
||||
|
||||
def draw(self, context):
|
||||
if not Data.is_loaded:
|
||||
Data.load()
|
||||
Data.load(IfcStore.get_file())
|
||||
|
||||
props = context.scene.BIMProperties
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import bpy
|
||||
from . import ui, prop, operator
|
||||
|
||||
classes = (
|
||||
operator.AddCostSchedule,
|
||||
operator.RemoveCostSchedule,
|
||||
operator.EditCostSchedule,
|
||||
operator.EditCostItem,
|
||||
operator.EditCostItemQuantity,
|
||||
operator.EditCostItemValue,
|
||||
operator.EnableEditingCostSchedule,
|
||||
operator.EnableEditingCostItems,
|
||||
operator.EnableEditingCostItem,
|
||||
operator.EnableEditingCostItemQuantities,
|
||||
operator.EnableEditingCostItemQuantity,
|
||||
operator.EnableEditingCostItemValues,
|
||||
operator.EnableEditingCostItemValue,
|
||||
operator.DisableEditingCostItem,
|
||||
operator.DisableEditingCostSchedule,
|
||||
operator.DisableEditingCostItemQuantity,
|
||||
operator.DisableEditingCostItemValue,
|
||||
operator.AddCostItem,
|
||||
operator.AddSummaryCostItem,
|
||||
operator.ExpandCostItem,
|
||||
operator.ContractCostItem,
|
||||
operator.RemoveCostItem,
|
||||
operator.AssignControl,
|
||||
operator.UnassignControl,
|
||||
operator.AddCostItemQuantity,
|
||||
operator.RemoveCostItemQuantity,
|
||||
operator.AddCostItemValue,
|
||||
operator.RemoveCostItemValue,
|
||||
prop.CostItem,
|
||||
prop.BIMCostProperties,
|
||||
ui.BIM_PT_cost_schedules,
|
||||
ui.BIM_UL_cost_items,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMCostProperties = bpy.props.PointerProperty(type=prop.BIMCostProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMCostProperties
|
||||
@@ -0,0 +1,608 @@
|
||||
import os
|
||||
import bpy
|
||||
import json
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.cost.data import Data
|
||||
|
||||
|
||||
class AddCostSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.add_cost_schedule"
|
||||
bl_label = "Add Cost Schedule"
|
||||
|
||||
def execute(self, context):
|
||||
ifcopenshell.api.run("cost.add_cost_schedule", IfcStore.get_file())
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_cost_schedule"
|
||||
bl_label = "Edit Cost Schedule"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
attributes = {}
|
||||
for attribute in props.cost_schedule_attributes:
|
||||
if attribute.is_null:
|
||||
attributes[attribute.name] = None
|
||||
else:
|
||||
if attribute.data_type == "string":
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
elif attribute.data_type == "enum":
|
||||
attributes[attribute.name] = attribute.enum_value
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_schedule",
|
||||
self.file,
|
||||
**{"cost_schedule": self.file.by_id(props.active_cost_schedule_id), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_cost_schedule()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveCostSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_cost_schedule"
|
||||
bl_label = "Remove Cost Schedule"
|
||||
cost_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
ifcopenshell.api.run(
|
||||
"cost.remove_cost_schedule",
|
||||
IfcStore.get_file(),
|
||||
cost_schedule=IfcStore.get_file().by_id(self.cost_schedule),
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingCostSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_schedule"
|
||||
bl_label = "Enable Editing Cost Schedule"
|
||||
cost_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
self.props.active_cost_schedule_id = self.cost_schedule
|
||||
while len(self.props.cost_schedule_attributes) > 0:
|
||||
self.props.cost_schedule_attributes.remove(0)
|
||||
self.enable_editing_cost_schedule()
|
||||
self.props.is_editing = "COST_SCHEDULE"
|
||||
return {"FINISHED"}
|
||||
|
||||
def enable_editing_cost_schedule(self):
|
||||
data = Data.cost_schedules[self.cost_schedule]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcCostSchedule").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
new = self.props.cost_schedule_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = data_type
|
||||
if attribute.name() in ["SubmittedOn", "UpdateDate"]:
|
||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
||||
elif data_type == "string":
|
||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||
elif data_type == "enum":
|
||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||
if data[attribute.name()]:
|
||||
new.enum_value = data[attribute.name()]
|
||||
|
||||
|
||||
class EnableEditingCostItems(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_items"
|
||||
bl_label = "Enable Editing Cost Items"
|
||||
cost_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
if context.preferences.addons["blenderbim"].preferences.should_play_chaching_sound:
|
||||
# lol
|
||||
# TODO: make pitch higher as costs rise
|
||||
try:
|
||||
import aud
|
||||
|
||||
device = aud.Device()
|
||||
# chaching.mp3 is by Lucish_ CC-BY-3.0 https://freesound.org/people/Lucish_/sounds/554841/
|
||||
sound = aud.Sound(os.path.join(context.scene.BIMProperties.data_dir, "chaching.mp3"))
|
||||
handle = device.play(sound)
|
||||
sound_buffered = aud.Sound.buffer(sound)
|
||||
handle_buffered = device.play(sound_buffered)
|
||||
handle.stop()
|
||||
handle_buffered.stop()
|
||||
except:
|
||||
pass # ah well
|
||||
self.props = context.scene.BIMCostProperties
|
||||
self.props.active_cost_schedule_id = self.cost_schedule
|
||||
while len(self.props.cost_items) > 0:
|
||||
self.props.cost_items.remove(0)
|
||||
|
||||
self.contracted_cost_items = json.loads(self.props.contracted_cost_items)
|
||||
for related_object_id in Data.cost_schedules[self.cost_schedule]["Controls"]:
|
||||
self.create_new_cost_item_li(related_object_id, 0)
|
||||
self.props.is_editing = "COST_ITEMS"
|
||||
return {"FINISHED"}
|
||||
|
||||
def create_new_cost_item_li(self, related_object_id, level_index):
|
||||
cost_item = Data.cost_items[related_object_id]
|
||||
new = self.props.cost_items.add()
|
||||
new.ifc_definition_id = related_object_id
|
||||
new.name = cost_item["Name"] or "Unnamed"
|
||||
new.is_expanded = related_object_id not in self.contracted_cost_items
|
||||
new.level_index = level_index
|
||||
if cost_item["IsNestedBy"]:
|
||||
new.has_children = True
|
||||
if new.is_expanded:
|
||||
for related_object_id in cost_item["IsNestedBy"]:
|
||||
self.create_new_cost_item_li(related_object_id, level_index + 1)
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingCostSchedule(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_cost_schedule"
|
||||
bl_label = "Disable Editing Cost Schedule"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMCostProperties.active_cost_schedule_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddSummaryCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.add_summary_cost_item"
|
||||
bl_label = "Add Cost Item"
|
||||
cost_schedule: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run("cost.add_cost_item", self.file, **{"cost_schedule": self.file.by_id(self.cost_schedule)})
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.enable_editing_cost_items(cost_schedule=self.cost_schedule)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.add_cost_item"
|
||||
bl_label = "Add Cost Item"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run("cost.add_cost_item", self.file, **{"cost_item": self.file.by_id(self.cost_item)})
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ExpandCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.expand_cost_item"
|
||||
bl_label = "Expand Cost Item"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
self.file = IfcStore.get_file()
|
||||
contracted_cost_items = json.loads(props.contracted_cost_items)
|
||||
contracted_cost_items.remove(self.cost_item)
|
||||
props.contracted_cost_items = json.dumps(contracted_cost_items)
|
||||
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class ContractCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.contract_cost_item"
|
||||
bl_label = "Contract Cost Item"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
self.file = IfcStore.get_file()
|
||||
contracted_cost_items = json.loads(props.contracted_cost_items)
|
||||
contracted_cost_items.append(self.cost_item)
|
||||
props.contracted_cost_items = json.dumps(contracted_cost_items)
|
||||
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_cost_item"
|
||||
bl_label = "Remove Cost item"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.remove_cost_item",
|
||||
self.file,
|
||||
cost_item=self.file.by_id(self.cost_item),
|
||||
)
|
||||
contracted_cost_items = json.loads(props.contracted_cost_items)
|
||||
if props.active_cost_item_index in contracted_cost_items:
|
||||
contracted_cost_items.remove(props.active_cost_item_index)
|
||||
props.contracted_cost_items = json.dumps(contracted_cost_items)
|
||||
Data.load(self.file)
|
||||
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_item"
|
||||
bl_label = "Enable Editing Cost Item"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
while len(props.cost_item_attributes) > 0:
|
||||
props.cost_item_attributes.remove(0)
|
||||
|
||||
data = Data.cost_items[self.cost_item]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name("IfcCostItem").all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity" or isinstance(data_type, tuple):
|
||||
continue
|
||||
new = props.cost_item_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = data_type
|
||||
if data_type == "string":
|
||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||
elif data_type == "enum":
|
||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||
if data[attribute.name()]:
|
||||
new.enum_value = data[attribute.name()]
|
||||
props.active_cost_item_id = self.cost_item
|
||||
props.cost_item_editing_type = "ATTRIBUTES"
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_cost_item"
|
||||
bl_label = "Disable Editing Cost Item"
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMCostProperties.active_cost_item_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostItem(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_cost_item"
|
||||
bl_label = "Edit Cost Item"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
attributes = {}
|
||||
for attribute in props.cost_item_attributes:
|
||||
if attribute.is_null:
|
||||
attributes[attribute.name] = None
|
||||
else:
|
||||
if attribute.data_type == "string":
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
elif attribute.data_type == "boolean":
|
||||
attributes[attribute.name] = attribute.bool_value
|
||||
elif attribute.data_type == "integer":
|
||||
attributes[attribute.name] = attribute.int_value
|
||||
elif attribute.data_type == "enum":
|
||||
attributes[attribute.name] = attribute.enum_value
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_item",
|
||||
self.file,
|
||||
**{"cost_item": self.file.by_id(props.active_cost_item_id), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_cost_item()
|
||||
bpy.ops.bim.enable_editing_cost_items(cost_schedule=props.active_cost_schedule_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AssignControl(bpy.types.Operator):
|
||||
bl_idname = "bim.assign_control"
|
||||
bl_label = "Assign Control"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
related_object: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
related_objects = (
|
||||
[bpy.data.objects.get(self.related_object)] if self.related_object else bpy.context.selected_objects
|
||||
)
|
||||
for related_object in related_objects:
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"control.assign_control",
|
||||
self.file,
|
||||
related_object=self.file.by_id(related_object.BIMObjectProperties.ifc_definition_id),
|
||||
relating_control=self.file.by_id(self.cost_item),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class UnassignControl(bpy.types.Operator):
|
||||
bl_idname = "bim.unassign_control"
|
||||
bl_label = "Unassign Control"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
related_object: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
related_objects = (
|
||||
[bpy.data.objects.get(self.related_object)] if self.related_object else bpy.context.selected_objects
|
||||
)
|
||||
for related_object in related_objects:
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"control.unassign_control",
|
||||
self.file,
|
||||
related_object=self.file.by_id(related_object.BIMObjectProperties.ifc_definition_id),
|
||||
relating_control=self.file.by_id(self.cost_item),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingCostItemQuantities(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_item_quantities"
|
||||
bl_label = "Enable Editing Cost Item Quantities"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
props.active_cost_item_id = self.cost_item
|
||||
props.cost_item_editing_type = "QUANTITIES"
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingCostItemValues(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_item_values"
|
||||
bl_label = "Enable Editing Cost Item Values"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
props.active_cost_item_id = self.cost_item
|
||||
props.cost_item_editing_type = "VALUES"
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddCostItemQuantity(bpy.types.Operator):
|
||||
bl_idname = "bim.add_cost_item_quantity"
|
||||
bl_label = "Add Cost Item Quantity"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
ifc_class: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
self.props = context.scene.BIMCostProperties
|
||||
if self.props.quantity_types == "QTO":
|
||||
self.add_quantities_from_qto_filter()
|
||||
else:
|
||||
self.add_manual_quantity()
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
def add_quantities_from_qto_filter(self):
|
||||
ifcopenshell.api.run(
|
||||
"cost.assign_cost_item_product_quantities",
|
||||
self.file,
|
||||
cost_item=self.file.by_id(self.cost_item),
|
||||
qto_name=self.props.qto_name,
|
||||
prop_name=self.props.prop_name
|
||||
)
|
||||
|
||||
def add_manual_quantity(self):
|
||||
ifcopenshell.api.run(
|
||||
"cost.add_cost_item_quantity",
|
||||
self.file,
|
||||
cost_item=self.file.by_id(self.cost_item),
|
||||
ifc_class=self.ifc_class,
|
||||
)
|
||||
|
||||
|
||||
class RemoveCostItemQuantity(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_cost_item_quantity"
|
||||
bl_label = "Add Cost Item Quantity"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
physical_quantity: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.remove_cost_item_quantity",
|
||||
self.file,
|
||||
cost_item=self.file.by_id(self.cost_item),
|
||||
physical_quantity=self.file.by_id(self.physical_quantity),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingCostItemQuantity(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_item_quantity"
|
||||
bl_label = "Enable Editing Cost Item Quantity"
|
||||
physical_quantity: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
while len(self.props.quantity_attributes) > 0:
|
||||
self.props.quantity_attributes.remove(0)
|
||||
self.props.active_cost_item_quantity_id = self.physical_quantity
|
||||
data = Data.physical_quantities[self.physical_quantity]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(data["type"]).all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity":
|
||||
continue
|
||||
new = self.props.quantity_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = data_type
|
||||
if data_type == "string":
|
||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||
elif data_type == "float":
|
||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
||||
elif data_type == "integer":
|
||||
new.int_value = 0 if new.is_null else data[attribute.name()]
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingCostItemQuantity(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_cost_item_quantity"
|
||||
bl_label = "Disable Editing Cost Item Quantity"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
props.active_cost_item_quantity_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostItemQuantity(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_cost_item_quantity"
|
||||
bl_label = "Edit Cost Item Quantity"
|
||||
physical_quantity: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
attributes = {}
|
||||
for attribute in props.quantity_attributes:
|
||||
if attribute.is_null:
|
||||
attributes[attribute.name] = None
|
||||
else:
|
||||
if attribute.data_type == "string":
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
if attribute.data_type == "float":
|
||||
attributes[attribute.name] = attribute.float_value
|
||||
if attribute.data_type == "integer":
|
||||
attributes[attribute.name] = attribute.int_value
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_item_quantity",
|
||||
self.file,
|
||||
**{"physical_quantity": self.file.by_id(self.physical_quantity), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_cost_item_quantity()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class AddCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.add_cost_item_value"
|
||||
bl_label = "Add Cost Item Value"
|
||||
cost_item: bpy.props.IntProperty()
|
||||
cost_type: bpy.props.StringProperty()
|
||||
cost_category: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
if self.cost_type == "FIXED":
|
||||
category = None
|
||||
elif self.cost_type == "SUM":
|
||||
category = "*"
|
||||
elif self.cost_type == "CATEGORY":
|
||||
category = self.cost_category
|
||||
value = ifcopenshell.api.run("cost.add_cost_item_value", self.file, cost_item=self.file.by_id(self.cost_item))
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_item_value", self.file, cost_value=value, attributes={"Category": category}
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_cost_item_value"
|
||||
bl_label = "Add Cost Item Value"
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.remove_cost_item_value",
|
||||
self.file,
|
||||
cost_value=self.file.by_id(self.cost_value),
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EnableEditingCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_item_value"
|
||||
bl_label = "Enable Editing Cost Item Value"
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
while len(self.props.cost_value_attributes) > 0:
|
||||
self.props.cost_value_attributes.remove(0)
|
||||
self.props.active_cost_item_value_id = self.cost_value
|
||||
data = Data.cost_values[self.cost_value]
|
||||
|
||||
for attribute in IfcStore.get_schema().declaration_by_name(data["type"]).all_attributes():
|
||||
data_type = ifcopenshell.util.attribute.get_primitive_type(attribute)
|
||||
if data_type == "entity" or isinstance(data_type, tuple):
|
||||
continue
|
||||
new = self.props.cost_value_attributes.add()
|
||||
new.name = attribute.name()
|
||||
new.is_null = data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = data_type
|
||||
if attribute.name() == "AppliedValue":
|
||||
# TODO: for now, only support simple values
|
||||
new.data_type = "float"
|
||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
||||
if data_type == "string":
|
||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||
elif data_type == "float":
|
||||
new.float_value = 0.0 if new.is_null else data[attribute.name()]
|
||||
elif data_type == "integer":
|
||||
new.int_value = 0 if new.is_null else data[attribute.name()]
|
||||
elif data_type == "enum":
|
||||
new.enum_items = json.dumps(ifcopenshell.util.attribute.get_enum_items(attribute))
|
||||
if data[attribute.name()]:
|
||||
new.enum_value = data[attribute.name()]
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class DisableEditingCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.disable_editing_cost_item_value"
|
||||
bl_label = "Disable Editing Cost Item Value"
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
props.active_cost_item_value_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_cost_item_value"
|
||||
bl_label = "Edit Cost Item Value"
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
attributes = {}
|
||||
for attribute in props.cost_value_attributes:
|
||||
if attribute.is_null:
|
||||
attributes[attribute.name] = None
|
||||
else:
|
||||
if attribute.data_type == "string":
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
if attribute.data_type == "float":
|
||||
attributes[attribute.name] = attribute.float_value
|
||||
if attribute.data_type == "integer":
|
||||
attributes[attribute.name] = attribute.int_value
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_item_value",
|
||||
self.file,
|
||||
**{"cost_value": self.file.by_id(self.cost_value), "attributes": attributes},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_cost_item_value()
|
||||
return {"FINISHED"}
|
||||
@@ -0,0 +1,90 @@
|
||||
import bpy
|
||||
import ifcopenshell.api
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.cost.data import Data
|
||||
from blenderbim.bim.prop import StrProperty, Attribute
|
||||
from bpy.types import PropertyGroup
|
||||
from bpy.props import (
|
||||
PointerProperty,
|
||||
StringProperty,
|
||||
EnumProperty,
|
||||
BoolProperty,
|
||||
IntProperty,
|
||||
FloatProperty,
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
|
||||
|
||||
quantitytypes_enum = []
|
||||
|
||||
|
||||
def purge():
|
||||
global quantitytypes_enum
|
||||
quantitytypes_enum = []
|
||||
|
||||
|
||||
def getQuantityTypes(self, context):
|
||||
global quantitytypes_enum
|
||||
if len(quantitytypes_enum) == 0 and IfcStore.get_schema():
|
||||
quantitytypes_enum.clear()
|
||||
quantitytypes_enum = [("QTO", "Qto", "Derive quantities from IFC quantity sets")]
|
||||
quantitytypes_enum.extend(
|
||||
[
|
||||
(t.name(), t.name(), "")
|
||||
for t in IfcStore.get_schema().declaration_by_name("IfcPhysicalSimpleQuantity").subtypes()
|
||||
]
|
||||
)
|
||||
return quantitytypes_enum
|
||||
|
||||
|
||||
def updateCostItemName(self, context):
|
||||
if self.name == "Unnamed":
|
||||
return
|
||||
self.file = IfcStore.get_file()
|
||||
props = context.scene.BIMCostProperties
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_item",
|
||||
self.file,
|
||||
**{"cost_item": self.file.by_id(self.ifc_definition_id), "attributes": {"Name": self.name}},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
if props.active_cost_item_id == self.ifc_definition_id:
|
||||
attribute = props.cost_item_attributes.get("Name")
|
||||
attribute.string_value = self.name
|
||||
|
||||
|
||||
class CostItem(PropertyGroup):
|
||||
name: StringProperty(name="Name", update=updateCostItemName)
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
has_children: BoolProperty(name="Has Children")
|
||||
is_expanded: BoolProperty(name="Is Expanded")
|
||||
level_index: IntProperty(name="Level Index")
|
||||
|
||||
|
||||
class BIMCostProperties(PropertyGroup):
|
||||
cost_schedule_attributes: CollectionProperty(name="Cost Schedule Attributes", type=Attribute)
|
||||
is_editing: StringProperty(name="Is Editing")
|
||||
active_cost_schedule_id: IntProperty(name="Active Cost Schedule Id")
|
||||
cost_items: CollectionProperty(name="Work Calendar", type=CostItem)
|
||||
active_cost_item_id: IntProperty(name="Active Cost Id")
|
||||
cost_item_editing_type: StringProperty(name="Cost Item Editing Type")
|
||||
active_cost_item_index: IntProperty(name="Active Cost Item Index")
|
||||
cost_item_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
||||
contracted_cost_items: StringProperty(name="Contracted Cost Items", default="[]")
|
||||
quantity_types: EnumProperty(items=getQuantityTypes, name="Quantity Types")
|
||||
qto_name: StringProperty(name="Qto Name")
|
||||
prop_name: StringProperty(name="Prop Name")
|
||||
active_cost_item_quantity_id: IntProperty(name="Active Cost Item Quantity Id")
|
||||
quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute)
|
||||
cost_types: EnumProperty(
|
||||
items=[
|
||||
("FIXED", "Fixed", "The cost value is a fixed number"),
|
||||
("SUM", "Sum", "The cost value is automatically derived from the sum of all nested cost items"),
|
||||
("CATEGORY", "Category", "The cost value represents a single category"),
|
||||
],
|
||||
name="Cost Types",
|
||||
)
|
||||
cost_category: StringProperty(name="Cost Category")
|
||||
active_cost_item_value_id: IntProperty(name="Active Cost Item Value Id")
|
||||
cost_value_attributes: CollectionProperty(name="Cost Value Attributes", type=Attribute)
|
||||
@@ -0,0 +1,249 @@
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.api.cost.data import Data
|
||||
|
||||
|
||||
class BIM_PT_cost_schedules(Panel):
|
||||
bl_label = "IFC Cost Schedules"
|
||||
bl_idname = "BIM_PT_cost_schedules"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return IfcStore.get_file()
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
|
||||
if not Data.is_loaded:
|
||||
Data.load(IfcStore.get_file())
|
||||
|
||||
row = self.layout.row()
|
||||
row.operator("bim.add_cost_schedule", icon="ADD")
|
||||
|
||||
for cost_schedule_id, cost_schedule in Data.cost_schedules.items():
|
||||
self.draw_cost_schedule_ui(cost_schedule_id, cost_schedule)
|
||||
|
||||
def draw_cost_schedule_ui(self, cost_schedule_id, cost_schedule):
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=cost_schedule["Name"] or "Unnamed", icon="LINENUMBERS_ON")
|
||||
|
||||
if self.props.active_cost_schedule_id and self.props.active_cost_schedule_id == cost_schedule_id:
|
||||
if self.props.is_editing == "COST_SCHEDULE":
|
||||
row.operator("bim.edit_cost_schedule", text="", icon="CHECKMARK")
|
||||
elif self.props.is_editing == "COST_ITEMS":
|
||||
row.operator("bim.add_summary_cost_item", text="", icon="ADD").cost_schedule = cost_schedule_id
|
||||
row.operator("bim.disable_editing_cost_schedule", text="", icon="CANCEL")
|
||||
elif self.props.active_cost_schedule_id:
|
||||
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule_id
|
||||
else:
|
||||
row.operator("bim.enable_editing_cost_items", text="", icon="OUTLINER").cost_schedule = cost_schedule_id
|
||||
row.operator(
|
||||
"bim.enable_editing_cost_schedule", text="", icon="GREASEPENCIL"
|
||||
).cost_schedule = cost_schedule_id
|
||||
row.operator("bim.remove_cost_schedule", text="", icon="X").cost_schedule = cost_schedule_id
|
||||
|
||||
if self.props.active_cost_schedule_id == cost_schedule_id:
|
||||
if self.props.is_editing == "COST_SCHEDULE":
|
||||
self.draw_editable_cost_schedule_ui()
|
||||
elif self.props.is_editing == "COST_ITEMS":
|
||||
self.draw_editable_cost_item_ui(cost_schedule_id)
|
||||
|
||||
def draw_editable_cost_schedule_ui(self):
|
||||
for attribute in self.props.cost_schedule_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
def draw_editable_cost_item_ui(self, cost_schedule_id):
|
||||
self.layout.template_list(
|
||||
"BIM_UL_cost_items",
|
||||
"",
|
||||
self.props,
|
||||
"cost_items",
|
||||
self.props,
|
||||
"active_cost_item_index",
|
||||
)
|
||||
if self.props.active_cost_item_id:
|
||||
if self.props.cost_item_editing_type == "ATTRIBUTES":
|
||||
self.draw_editable_cost_item_attributes_ui()
|
||||
elif self.props.cost_item_editing_type == "QUANTITIES":
|
||||
self.draw_editable_cost_item_quantities_ui()
|
||||
elif self.props.cost_item_editing_type == "VALUES":
|
||||
self.draw_editable_cost_item_values_ui()
|
||||
|
||||
def draw_editable_cost_item_attributes_ui(self):
|
||||
for attribute in self.props.cost_item_attributes:
|
||||
row = self.layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
def draw_editable_cost_item_quantities_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.props, "quantity_types", text="")
|
||||
if self.props.quantity_types == "QTO":
|
||||
row.prop(self.props, "qto_name", text="")
|
||||
row.prop(self.props, "prop_name", text="")
|
||||
op = row.operator("bim.add_cost_item_quantity", text="", icon="ADD")
|
||||
op.cost_item = self.props.active_cost_item_id
|
||||
op.ifc_class = self.props.quantity_types
|
||||
|
||||
for quantity_id in Data.cost_items[self.props.active_cost_item_id]["CostQuantities"]:
|
||||
quantity = Data.physical_quantities[quantity_id]
|
||||
value = quantity[[k for k in quantity.keys() if "Value" in k][0]]
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=quantity["Name"])
|
||||
row.label(text=str(value))
|
||||
if self.props.active_cost_item_quantity_id and self.props.active_cost_item_quantity_id == quantity_id:
|
||||
op = row.operator("bim.edit_cost_item_quantity", text="", icon="CHECKMARK")
|
||||
op.physical_quantity = quantity_id
|
||||
row.operator("bim.disable_editing_cost_item_quantity", text="", icon="CANCEL")
|
||||
elif self.props.active_cost_item_quantity_id:
|
||||
op = row.operator("bim.remove_cost_item_quantity", text="", icon="X")
|
||||
op.cost_item = self.props.active_cost_item_id
|
||||
op.physical_quantity = quantity_id
|
||||
else:
|
||||
op = row.operator("bim.enable_editing_cost_item_quantity", text="", icon="GREASEPENCIL")
|
||||
op.physical_quantity = quantity_id
|
||||
op = row.operator("bim.remove_cost_item_quantity", text="", icon="X")
|
||||
op.cost_item = self.props.active_cost_item_id
|
||||
op.physical_quantity = quantity_id
|
||||
|
||||
if self.props.active_cost_item_quantity_id and self.props.active_cost_item_quantity_id == quantity_id:
|
||||
box = self.layout.box()
|
||||
self.draw_editable_cost_item_quantity_ui(box)
|
||||
|
||||
def draw_editable_cost_item_quantity_ui(self, layout):
|
||||
for attribute in self.props.quantity_attributes:
|
||||
row = layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "float":
|
||||
row.prop(attribute, "float_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
def draw_editable_cost_item_values_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(self.props, "cost_types", text="")
|
||||
if self.props.cost_types == "CATEGORY":
|
||||
row.prop(self.props, "cost_category", text="")
|
||||
op = row.operator("bim.add_cost_item_value", text="", icon="ADD")
|
||||
op.cost_item = self.props.active_cost_item_id
|
||||
op.cost_type = self.props.cost_types
|
||||
if self.props.cost_types == "CATEGORY":
|
||||
op.cost_category = self.props.cost_category
|
||||
|
||||
for cost_value_id in Data.cost_items[self.props.active_cost_item_id]["CostValues"]:
|
||||
cost_value = Data.cost_values[cost_value_id]
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=str(cost_value["Category"]))
|
||||
row.label(text=str(cost_value["AppliedValue"]))
|
||||
if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id:
|
||||
op = row.operator("bim.edit_cost_item_value", text="", icon="CHECKMARK")
|
||||
op.cost_value = cost_value_id
|
||||
row.operator("bim.disable_editing_cost_item_value", text="", icon="CANCEL")
|
||||
elif self.props.active_cost_item_value_id:
|
||||
op = row.operator("bim.remove_cost_item_value", text="", icon="X")
|
||||
op.cost_value = cost_value_id
|
||||
else:
|
||||
op = row.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL")
|
||||
op.cost_value = cost_value_id
|
||||
op = row.operator("bim.remove_cost_item_value", text="", icon="X")
|
||||
op.cost_value = cost_value_id
|
||||
|
||||
if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id:
|
||||
box = self.layout.box()
|
||||
self.draw_editable_cost_item_value_ui(box)
|
||||
|
||||
def draw_editable_cost_item_value_ui(self, layout):
|
||||
for attribute in self.props.cost_value_attributes:
|
||||
row = layout.row(align=True)
|
||||
if attribute.data_type == "string":
|
||||
row.prop(attribute, "string_value", text=attribute.name)
|
||||
elif attribute.data_type == "boolean":
|
||||
row.prop(attribute, "bool_value", text=attribute.name)
|
||||
elif attribute.data_type == "integer":
|
||||
row.prop(attribute, "int_value", text=attribute.name)
|
||||
elif attribute.data_type == "float":
|
||||
row.prop(attribute, "float_value", text=attribute.name)
|
||||
elif attribute.data_type == "enum":
|
||||
row.prop(attribute, "enum_value", text=attribute.name)
|
||||
if attribute.is_optional:
|
||||
row.prop(attribute, "is_null", icon="RADIOBUT_OFF" if attribute.is_null else "RADIOBUT_ON", text="")
|
||||
|
||||
|
||||
class BIM_UL_cost_items(UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||
if item:
|
||||
props = context.scene.BIMCostProperties
|
||||
cost_item = Data.cost_items[item.ifc_definition_id]
|
||||
row = layout.row(align=True)
|
||||
for i in range(0, item.level_index):
|
||||
row.label(text="", icon="BLANK1")
|
||||
if item.has_children:
|
||||
if item.is_expanded:
|
||||
row.operator(
|
||||
"bim.contract_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_DOWN"
|
||||
).cost_item = item.ifc_definition_id
|
||||
else:
|
||||
row.operator(
|
||||
"bim.expand_cost_item", text="", emboss=False, icon="DISCLOSURE_TRI_RIGHT"
|
||||
).cost_item = item.ifc_definition_id
|
||||
else:
|
||||
row.label(text="", icon="DOT")
|
||||
row.prop(item, "name", emboss=False, text="")
|
||||
|
||||
row.label(text="M3")
|
||||
op = row.operator("bim.enable_editing_cost_item_quantities", text="", icon="PROPERTIES")
|
||||
op.cost_item = item.ifc_definition_id
|
||||
row.label(text=str(cost_item["TotalCostQuantity"]))
|
||||
|
||||
op = row.operator("bim.enable_editing_cost_item_values", text="", icon="DISC")
|
||||
op.cost_item = item.ifc_definition_id
|
||||
row.label(text=str(cost_item["TotalAppliedValue"]))
|
||||
row.label(text=str(cost_item["TotalCostValue"]), icon="CON_TRANSLIKE")
|
||||
|
||||
if context.active_object:
|
||||
oprops = context.active_object.BIMObjectProperties
|
||||
row = layout.row(align=True)
|
||||
if oprops.ifc_definition_id in cost_item["Controls"]:
|
||||
op = row.operator("bim.unassign_control", text="", icon="KEYFRAME_HLT", emboss=False)
|
||||
op.cost_item = item.ifc_definition_id
|
||||
else:
|
||||
op = row.operator("bim.assign_control", text="", icon="KEYFRAME", emboss=False)
|
||||
op.cost_item = item.ifc_definition_id
|
||||
|
||||
if props.active_cost_item_id == item.ifc_definition_id:
|
||||
row.operator("bim.edit_cost_item", text="", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_cost_item", text="", icon="CANCEL")
|
||||
elif props.active_cost_item_id:
|
||||
row.operator("bim.add_cost_item", text="", icon="ADD").cost_item = item.ifc_definition_id
|
||||
row.operator("bim.remove_cost_item", text="", icon="X").cost_item = item.ifc_definition_id
|
||||
else:
|
||||
row.operator(
|
||||
"bim.enable_editing_cost_item", text="", icon="GREASEPENCIL"
|
||||
).cost_item = item.ifc_definition_id
|
||||
row.operator("bim.add_cost_item", text="", icon="ADD").cost_item = item.ifc_definition_id
|
||||
row.operator("bim.remove_cost_item", text="", icon="X").cost_item = item.ifc_definition_id
|
||||