Compare commits

..

3 Commits

Author SHA1 Message Date
Ryan Schultz 8c9e4bae2f Merge branch 'switch_camera_only' of https://github.com/IfcOpenShell/IfcOpenShell into switch_camera_only
# Conflicts:
#	src/blenderbim/blenderbim/bim/module/drawing/operator.py
2024-06-05 11:12:01 -05:00
Ryan Schultz 777dea3756 shift + click with bim.activate_drawing switches view without turning off/off objects in scene 2024-06-05 11:03:33 -05:00
Ryan Schultz 2cc583b88b shift + click with bim.activate_drawing switches view without turning off/off objects in scene 2024-06-02 09:41:59 -05:00
1369 changed files with 354669 additions and 168930 deletions
-24
View File
@@ -1,24 +0,0 @@
# We'll use defaults from the LLVM style with modifications
BasedOnStyle: LLVM
ColumnLimit: 0 # we do not enforce column lenght, please format responsibly
IndentWidth: 4
---
Language: Cpp
AllowShortEnumsOnASingleLine: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
IncludeBlocks: Regroup
InsertBraces: true
InsertNewlineAtEOF: true
PackConstructorInitializers: CurrentLine
PointerAlignment: Left
ReflowComments: false # keep licenze comment blocks
SortIncludes: CaseInsensitive
SpacesInLineCommentPrefix:
Maximum: 1
TabWidth: 4
-5
View File
@@ -1,5 +0,0 @@
Checks: 'bugprone-*,cert-*,clang-analyzer-*,readability-*'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: none
@@ -1,10 +1,8 @@
name: ci-ifcopenshell-docker
name: CD
on:
workflow_dispatch:
push:
tags:
- v0.**
jobs:
@@ -31,7 +29,7 @@ jobs:
sudo apt-get install --no-install-recommends \
git cmake gcc g++ libboost-all-dev python3-all-dev swig libpcre3-dev libxml2-dev \
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
libhdf5-dev libcgal-dev nlohmann-json3-dev libeigen3-dev
libhdf5-dev libcgal-dev nlohmann-json3-dev
-
name: ccache
@@ -52,8 +50,8 @@ jobs:
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
-DOCC_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3 \
-DPYTHON_INCLUDE_DIR:PATH=/usr/include/python3.10 \
-DPYTHON_LIBRARY:FILEPATH=/usr/lib/x86_64-linux-gnu/libpython3.10.so \
-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 \
@@ -65,7 +63,6 @@ jobs:
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include \
-DEIGEN_DIR=/usr/include/eigen3 \
../cmake
make -j $(nproc)
make install
+17 -1
View File
@@ -1,8 +1,24 @@
name: ci-bcf-pypi
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
push:
paths:
- '.github/workflows/ci-bcf-pypi.yml'
workflow_dispatch:
env:
major: 0
minor: 0
name: ifcopenshell
jobs:
activate:
runs-on: ubuntu-latest
@@ -38,4 +54,4 @@ jobs:
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: src/bcf/dist
packages_dir: src/bcf/dist
+54 -7
View File
@@ -28,18 +28,65 @@ jobs:
build:
needs: activate
name: "choco_release"
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
pyver: [py310]
config:
- {
name: "Windows Build",
short_name: win,
}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
fetch-tags: true
fetch-depth: 0
python-version: '3.10.9' # 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: Check in release tags if we should do a choco release and perform the release if needed
id: do_choco_release
- name: Check in published releases if we should do a choco release
id: do_choco
run: |
echo "::set-output name=choco_release::$(python3 /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/check_repo_infos.py --do_choco_release?)"
- name: Fill chocolatey scripts on win with latest blender python
if: ${{steps.do_choco.outputs.choco_release}} == 'do_choco_release'
run: |
yesterday_non_iso="$(date --date='yesterday' +'%y%m%d' | tr -d '\n')" &&
target_os=${{ matrix.config.short_name }} &&
latest_blender_python_version_maj_min=$(python3 /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/check_repo_infos.py --latest_blender_python_version_maj_min?) &&
echo "latest_blender_python_version_maj_min?: $latest_blender_python_version_maj_min" &&
pyver=$(python3 /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/check_repo_infos.py --pyver?) &&
export latest_blender_version_maj_min=$(python3 /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/check_repo_infos.py --latest_blender_release_maj_min?) &&
export latest_blender_version_maj_min_pat=$(python3 /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/check_repo_infos.py --latest_blender_release_maj_min_pat?) &&
echo latest_blender_version_maj_min_pat?: $latest_blender_version_maj_min_pat &&
export blenderbim_build_version="${{ env.major }}.${{ env.minor }}.$yesterday_non_iso" &&
export url_blenderbim_py310_win_zip="https://github.com/IfcOpenShell/IfcOpenShell/releases/download/blenderbim-$yesterday_non_iso/blenderbim-$yesterday_non_iso-$pyver-$target_os.zip" &&
wget $url_blenderbim_py310_win_zip --no-verbose &&
export sha256sum_blenderbim_py310_win_zip=$( sha256sum blenderbim-$yesterday_non_iso-$pyver-$target_os.zip --tag | cut -d ' ' -f 4 | tr -d '\n') &&
echo sha256sum_blenderbim_py310_win_zip: $sha256sum_blenderbim_py310_win_zip &&
python3 choco/blenderbim/fill_dynamic_parameters.py &&
echo __build choco with mono &&
wget "https://github.com/chocolatey/choco/archive/refs/tags/$choco_version.tar.gz" --quiet &&
tar -xzf "$choco_version.tar.gz" &&
cd choco-$choco_version &&
chmod +x build.sh zip.sh &&
./build.sh &&
cp -r build_output/chocolatey /opt/chocolatey &&
cd /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/ &&
python3 choco_release.py
echo __choco pack &&
mono /opt/chocolatey/choco.exe --version &&
mono /opt/chocolatey/choco.exe pack --allow-unofficial &&
echo __choco set apiKey &&
mono /opt/chocolatey/choco.exe setapikey --key="$CHOCO_TOKEN" --source="https://push.chocolatey.org/" --allow-unofficial # &&
echo __choco push &&
mono /opt/chocolatey/choco.exe push --source="https://push.chocolatey.org/" --key="$CHOCO_TOKEN" --allow-unofficial --verbose
- name: Inform user about not packaging
if: ${{steps.do_choco.outputs.choco_release}} != 'do_choco_release'
run: |
echo "no releases found today ${{ env.DATE }}, therefore choco packaging is skipped."
@@ -1,4 +1,4 @@
name: ci-blenderbim-daily
name: Publish-blenderbim-multiplatform
on:
push:
@@ -16,8 +16,12 @@ on:
- 'src/ifc5d/ifc5d/**'
- 'src/ifccityjson/**'
branches:
- v0.8.0
workflow_dispatch:
- v0.7.0
env:
major: 0
minor: 0
name: blenderbim
jobs:
activate:
@@ -59,23 +63,21 @@ jobs:
with:
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
python-version: '3.11'
- name: Get current version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- run: echo ${{ env.DATE }}
- name: Get current date
id: date
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
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
- name: Upload Zip file to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
asset_name: blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
release_name: "blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}} (unstable)"
tag: "blenderbim-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}"
file: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blenderbim-${{steps.date.outputs.date}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
asset_name: blenderbim-${{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}}"
-62
View File
@@ -1,62 +0,0 @@
name: ci-blenderbim
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
pyver: [py39, py310, py311, py312]
config:
- {
name: "Windows Build",
short_name: win,
}
- {
name: "Linux Build",
short_name: linux
}
- {
name: "MacOS Build",
short_name: macos
}
- {
name: "MacOS ARM Build",
short_name: macosm1
}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
python-version: '3.11'
- name: Get current version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- name: 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 }} IS_STABLE=TRUE
- name: Upload zip file to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: src/blenderbim_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/blenderbim-${{steps.version.outputs.version}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
asset_name: blenderbim-${{steps.version.outputs.version}}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
release_name: "blenderbim-${{steps.version.outputs.version}}"
tag: "blenderbim-${{steps.version.outputs.version}}"
overwrite: true
+13
View File
@@ -1,8 +1,21 @@
name: ci-bsdd-pypi
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
workflow_dispatch:
env:
major: 0
minor: 0
name: ifcopenshell
jobs:
activate:
runs-on: ubuntu-latest
-35
View File
@@ -1,35 +0,0 @@
name: ci-ifc4d-pypi
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
- name: Compile
run: |
pip install build
cd src/ifc4d &&
make dist
- name: Publish a Python distribution to PyPI
uses: ortega2247/pypi-upload-action@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: src/ifc4d/dist
-35
View File
@@ -1,35 +0,0 @@
name: ci-ifc5d-pypi
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
- name: Compile
run: |
pip install build
cd src/ifc5d &&
make dist
- name: Publish a Python distribution to PyPI
uses: ortega2247/pypi-upload-action@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: src/ifc5d/dist
@@ -1,35 +0,0 @@
name: ci-ifccityjson-pypi
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
- name: Compile
run: |
pip install build
cd src/ifccityjson &&
make dist
- name: Publish a Python distribution to PyPI
uses: ortega2247/pypi-upload-action@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: src/ifccityjson/dist
+13
View File
@@ -1,8 +1,21 @@
name: ci-ifcclash-pypi
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
workflow_dispatch:
env:
major: 0
minor: 0
name: ifcopenshell
jobs:
activate:
runs-on: ubuntu-latest
+13
View File
@@ -1,8 +1,21 @@
name: ci-ifccsv-pypi
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
workflow_dispatch:
env:
major: 0
minor: 0
name: ifcopenshell
jobs:
activate:
runs-on: ubuntu-latest
-35
View File
@@ -1,35 +0,0 @@
name: ci-ifcdiff-pypi
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
- name: Compile
run: |
pip install build
cd src/ifcdiff &&
make dist
- name: Publish a Python distribution to PyPI
uses: ortega2247/pypi-upload-action@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: src/ifcdiff/dist
-35
View File
@@ -1,35 +0,0 @@
name: ci-ifcfm-pypi
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
- name: Compile
run: |
pip install build
cd src/ifcfm &&
make dist
- name: Publish a Python distribution to PyPI
uses: ortega2247/pypi-upload-action@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
packages_dir: src/ifcfm/dist
@@ -1,101 +0,0 @@
name: ci-ifcopenshell-conda-daily-cleaner
on:
workflow_dispatch:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "00 23 * * *" # 11min before utc midnight every day
env:
ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
NUM_SUPPORTED_VERSIONS: 5
jobs:
activate:
runs-on: ubuntu-latest
defaults:
run:
shell: bash -l {0}
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- uses: mamba-org/setup-micromamba@v1 # https://github.com/mamba-org/setup-micromamba
with:
environment-name: test-env
create-args: >-
python=3.11
anaconda-client=1.12.3
- name: Run conda cleaner
run: |
python - << EOF
import os
from datetime import datetime, timedelta
from binstar_client.utils import get_server_api
from binstar_client.errors import BinstarError
# Configuration
api_token = os.environ.get('ANACONDA_TOKEN')
pkg_name = 'ifcopenshell'
channel_name = 'ifcopenshell'
# Authenticate with Anaconda
aserver_api = get_server_api(token=api_token)
# Get the list of packages in the channel
def get_package(filter_package_name: str = None):
try:
user_packages = aserver_api.user_packages(channel_name)
if filter_package_name:
user_packages = [pkg for pkg in user_packages if pkg['name'] == filter_package_name]
if len(user_packages) == 0:
print(f"No packages found for {filter_package_name}.")
if len(user_packages) > 1:
raise ValueError(f"Found {len(user_packages)} package for {filter_package_name}. Will only support 1 package.")
return user_packages[0]
except BinstarError as err:
raise ValueError(f"Failed to fetch packages: {err}")
# Delete a package version
def delete_package(package_name, version):
try:
aserver_api.remove_release(channel_name, package_name, version)
print(f"Deleted {package_name} version {version}")
except BinstarError as err:
print(f"Failed to delete {package_name} version {version}: {err}")
# Main logic
def main():
package = get_package(pkg_name)
if not package:
print("No packages found.")
return
number_of_supported_versions = ${{ env.NUM_SUPPORTED_VERSIONS }}
package_name = package['name']
versions = package["versions"]
if len(versions) <= number_of_supported_versions:
print(f"Number of versions {len(versions)} is less than or equal to {number_of_supported_versions}.")
return
# sort the versions in descending order
versions = sorted(versions, reverse=True)
releases = versions[number_of_supported_versions:]
for release in releases:
delete_package(package_name, release)
main()
EOF
@@ -1,4 +1,4 @@
name: ci-ifcopenshell-conda-daily-v0.8.0
name: ci-ifcopenshell-conda-daily
on:
workflow_dispatch:
@@ -12,35 +12,8 @@ on:
- cron: "49 23 * * *" # 11min before utc midnight every day
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
outputs:
version: ${{ steps.version.outputs.version }}
date: ${{ steps.date.outputs.date }}
verdate: ${{ steps.verdate.outputs.verdate }}
steps:
- uses: actions/checkout@v4
- name: Set env
run: echo ok go
- name: Get current version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- name: Get current date
id: date
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
- name: Version + date str
id: verdate
run: echo "verdate='${{ steps.version.outputs.version }}.${{ steps.date.outputs.date }}'" >> $GITHUB_OUTPUT
test:
name: ${{ matrix.platform.distver }}-${{ matrix.pyver.name }}-${{ matrix.variant }}
needs: activate
runs-on: ${{ matrix.platform.distver }}
defaults:
run:
@@ -48,57 +21,47 @@ jobs:
strategy:
fail-fast: false
matrix:
variant: [novtk, all]
pyver: [
# { name: py311, distver: '3.11'},
{ name: py311, distver: '3.11'},
{ name: py312, distver: '3.12'}
]
platform: [
{ name: win, distver: windows-latest, pkg_dir: 'win-64' },
{ name: linux, distver: ubuntu-latest, pkg_dir: 'linux-64' },
{ name: macOS, distver: macos-latest, pkg_dir: 'osx-64' }
{ name: Windows, distver: windows-2022, upload: 'true' },
{ name: Linux, distver: ubuntu-22.04, upload: 'true' },
{ name: macOS, distver: macos-12, upload: 'true' }
]
variant: [
'novtk',
# 'all'
]
steps:
- name: Set up swap space
if: runner.os == 'Linux'
uses: pierotofy/set-swap-space@v1.0
with:
swap-size-gb: 10
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Download and extract MacOSX SDK
if: ${{ runner.os == 'macOS' }}
- name: Download MacOSX SDK
if: ${{ matrix.platform.name == 'macOS' }}
run: |
curl -L https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX10.13.sdk.tar.xz | tar -xvJf - -C /Users/runner/work/
curl -o MacOSX10.13.sdk.tar.xz -L https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX10.13.sdk.tar.xz && \
tar xf MacOSX10.13.sdk.tar.xz && \
sudo mv -v MacOSX10.13.sdk /opt/ && \
ls /opt/
- uses: mamba-org/setup-micromamba@v1 # https://github.com/mamba-org/setup-micromamba
with:
environment-name: test-env
environment-name: build-env
cache-environment: true
condarc: |
channels:
- conda-forge
channel_priority: strict
create-args: >-
python=3.11
anaconda-client
boa
- name: create conda package dist dir
- name: build, test and upload ifcopenshell
if: ${{ matrix.platform.upload == 'true' }}
run: |
mkdir -p ${{ github.workspace }}/dist
- name: build & test ifcopenshell
run: |
conda mambabuild . --python ${{ matrix.pyver.distver }} --no-remove-work-dir --output-folder '${{ github.workspace }}/dist' --variants='{variant: ${{ matrix.variant }}}'
conda mambabuild . --python ${{ matrix.pyver.distver }} -c conda-forge --variants "{variant: ${{ matrix.variant }}}" --token ${{ secrets.ANACONDA_TOKEN }} --user ifcopenshell
working-directory: ./conda
env:
VERSION_OVERRIDE: ${{ needs.activate.outputs.verdate }}
- name: upload to anaconda
if: ${{ matrix.platform.name == 'win' }}
run: |
anaconda -t ${{ secrets.ANACONDA_TOKEN }} upload --force --user ifcopenshell '${{ github.workspace }}/dist/${{ matrix.platform.pkg_dir }}/*.tar.bz2'
- name: upload to anaconda
if: ${{ matrix.platform.name != 'win' }}
run: |
anaconda -t ${{ secrets.ANACONDA_TOKEN }} upload --force --user ifcopenshell ${{ github.workspace }}/dist/${{ matrix.platform.pkg_dir }}/*.tar.bz2
@@ -1,7 +1,19 @@
name: ci-ifcopenshell-python-pypi
name: ci-ifcopenshell-pypi
on:
workflow_dispatch:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
push:
paths:
- '.github/workflows/ci-ifcopenshell-pypi.yml'
env:
major: 0
@@ -27,20 +39,20 @@ jobs:
pyver: [py39, py310, py311, py312]
config:
- {
name: "Windows 64bit",
short_name: win64,
name: "Windows Build",
short_name: win,
}
- {
name: "Linux 64bit",
short_name: linux64
name: "Linux Build",
short_name: linux
}
- {
name: "MacOS Intel 64bit",
short_name: macos64
name: "MacOS Build",
short_name: macos
}
- {
name: "MacOS Silicon 64bit",
short_name: macosm164
name: "MacOS ARM Build",
short_name: macosm1
}
steps:
- uses: actions/checkout@v2
@@ -1,67 +0,0 @@
name: ci-ifcopenshell-python
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
name: ${{ matrix.config.name }}-${{ matrix.pyver }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
pyver: [py39, py310, py311, py312]
config:
- {
name: "Windows 64bit",
short_name: win64,
}
- {
name: "Windows 32bit",
short_name: win32,
}
- {
name: "Linux 64bit",
short_name: linux64
}
- {
name: "MacOS Intel 64bit",
short_name: macos64
}
- {
name: "MacOS Silicon 64bit",
short_name: macosm164
}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
python-version: '3.11' # Version range or exact version of a Python version to use, using SemVer's version range syntax
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
- run: echo ${{ env.DATE }}
- name: Get current version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- name: Compile
run: |
cp -r src/ifcopenshell-python src/ifcopenshell_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
cd src/ifcopenshell_${{ matrix.config.short_name }}_${{ matrix.pyver }} &&
make zip 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/ifcopenshell_${{ matrix.config.short_name }}_${{ matrix.pyver }}/dist/ifcopenshell-python-${{ steps.version.outputs.version }}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
asset_name: ifcopenshell-python-${{ steps.version.outputs.version }}-${{ matrix.pyver }}-${{ matrix.config.short_name }}.zip
release_name: "ifcopenshell-python-${{steps.version.outputs.version}}"
tag: "ifcopenshell-python-${{steps.version.outputs.version}}"
overwrite: true
+13
View File
@@ -1,8 +1,21 @@
name: ci-ifcpatch-pypi
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
workflow_dispatch:
env:
major: 0
minor: 0
name: ifcopenshell
jobs:
activate:
runs-on: ubuntu-latest
@@ -1,13 +1,17 @@
name: ci-ifcsverchok-daily
name: Publish-ifcsverchok
on:
workflow_dispatch:
push:
paths:
- '.github/workflows/ci-ifcsverchok-build.yml'
- 'src/ifcsverchok/*'
branches:
- v0.8.0
- v0.7.0
env:
major: 0
minor: 0
name: ifcsverchok
jobs:
activate:
@@ -30,22 +34,20 @@ jobs:
with:
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
python-version: '3.11'
- name: Get current version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- run: echo ${{ env.DATE }}
- name: Get current date
id: date
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
run: echo "::set-output name=date::$(date +'%y%m%d')"
- name: Compile
run: |
cd src/ifcsverchok
make dist
- name: Upload zip file to release
- name: Upload Zip file to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: src/ifcsverchok/dist/ifcsverchok-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}.zip
asset_name: ifcsverchok-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}.zip
release_name: "ifcsverchok-${{steps.version.outputs.version}}.${{steps.date.outputs.date}} (unstable)"
tag: "ifcsverchok-${{steps.version.outputs.version}}.${{steps.date.outputs.date}}"
file: src/ifcsverchok/dist/ifcsverchok-${{steps.date.outputs.date}}.zip
asset_name: ifcsverchok-${{steps.date.outputs.date}}.zip
tag: "ifcsverchok-${{steps.date.outputs.date}}"
overwrite: true
body: "ifcsverchok build for ${{steps.date.outputs.date}}"
-42
View File
@@ -1,42 +0,0 @@
name: ci-ifcsverchok
on:
workflow_dispatch:
jobs:
activate:
runs-on: ubuntu-latest
if: |
github.repository == 'IfcOpenShell/IfcOpenShell'
steps:
- name: Set env
run: echo ok go
build:
needs: activate
name: ifcsverchok
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2 # https://github.com/actions/setup-python
with:
architecture: 'x64' # optional x64 or x86. Defaults to x64 if not specified
python-version: '3.11'
- name: Get current version
id: version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
- name: Compile
run: |
cd src/ifcsverchok
make dist IS_STABLE=TRUE
- name: Upload zip file to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: src/ifcsverchok/dist/ifcsverchok-${{steps.version.outputs.version}}.zip
asset_name: ifcsverchok-${{steps.version.outputs.version}}.zip
release_name: "ifcsverchok-${{steps.version.outputs.version}}"
tag: "ifcsverchok-${{steps.version.outputs.version}}"
overwrite: true
+13
View File
@@ -1,8 +1,21 @@
name: ci-ifctester-pypi
on:
schedule:
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
# * * * * *
- cron: "0 0 18 * *"
workflow_dispatch:
env:
major: 0
minor: 0
name: ifcopenshell
jobs:
activate:
runs-on: ubuntu-latest
@@ -0,0 +1,34 @@
name: Restart failed daily conda builds
on:
workflow_run:
workflows: [ ci-ifcopenshell-conda-daily ]
types:
- completed
env:
REPO_OWNER: IfcOpenShell/IfcOpenShell
MY_WORKFLOW: ci-ifcopenshell-conda-daily
jobs:
restart-failed-runs:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
steps:
- name: checkout
uses: actions/checkout@v3
- name: Use python 3.11
uses: actions/setup-python@v2
with:
python-version: 3.11
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install requests
- name: Check for failed runs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
run: |
python check_repo_ci_jobs.py
working-directory: .github/workflows
+2 -3
View File
@@ -65,7 +65,7 @@ jobs:
swig libpcre3-dev libxml2-dev \
libtbb-dev nlohmann-json3-dev \
libocct-foundation-dev libocct-modeling-algorithms-dev libocct-modeling-data-dev libocct-ocaf-dev libocct-visualization-dev libocct-data-exchange-dev \
libhdf5-dev libcgal-dev libeigen3-dev
libhdf5-dev libcgal-dev
- name: ccache
uses: hendrikmuhs/ccache-action@v1
@@ -90,7 +90,7 @@ jobs:
-DPYTHON_INCLUDE_DIR:PATH=${{ env.pythonLocation }}/include/python3.11 \
-DPYTHON_LIBRARY:FILEPATH=${{ env.pythonLocation }}/lib/libpython3.11.so \
-DCOLLADA_SUPPORT=Off \
"-DSCHEMA_VERSIONS=2x3;4;4x3_add2" \
"-DSCHEMA_VERSIONS=2x3;4;4x3;4x3_add1;4x3_add2" \
-DGLTF_SUPPORT=On \
-DJSON_INCLUDE_DIR=/usr/include \
-DCGAL_INCLUDE_DIR=/usr/include \
@@ -99,7 +99,6 @@ jobs:
-DGMP_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DMPFR_LIBRARY_DIR=/usr/lib/x86_64-linux-gnu \
-DHDF5_INCLUDE_DIR=/usr/include/hdf5/serial \
-DEIGEN_DIR=/usr/include/eigen3 \
../cmake
sudo make -j $(nproc)
sudo make install
-3
View File
@@ -11,9 +11,6 @@
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
path = src/ifcopenshell-python/test/Sample-BIM-Files
url = https://github.com/IfcOpenShell/ids-test-files
[submodule "src/ifcconvert/cityjson"]
path = src/ifcconvert/cityjson
url = https://github.com/IfcOpenShell/ifc-to-cityjson
[submodule "docs/cpp-api/assets/doxygen-awesome-css"]
path = docs/cpp-api/assets/doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git
+30 -26
View File
@@ -26,45 +26,49 @@ For more information, see:
* [BlenderBIM Add-on Documentation](https://docs.blenderbim.org/index.html)
* [Add-on Installation](https://docs.blenderbim.org/users/installation.html)
* [Exploring an IFC model](https://docs.blenderbim.org/users/exploring_an_ifc_model.html)
Development is sponsored through your generous donations!
[![Open Collective Contributors](https://img.shields.io/opencollective/all/opensourcebim?label=Sponsors&color=22ce5f)](https://opencollective.com/opensourcebim/)
| Service | Status |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| Anaconda Daily Build | [![Anaconda-Server Badge](https://img.shields.io/conda/vn/ifcopenshell/ifcopenshell)](https://anaconda.org/ifcopenshell/ifcopenshell) |
| Anaconda v0.7.0 Stable | [![Anaconda-Server Badge](https://img.shields.io/conda/vn/conda-forge/ifcopenshell)](https://anaconda.org/conda-forge/ifcopenshell) |
| PyPi Daily Build | [![PyPi Badge](https://img.shields.io/pypi/v/ifcopenshell)](https://pypi.org/project/ifcopenshell/) |
| ArchLinux AUR Package Stable | [![AUR Badge](https://img.shields.io/aur/version/ifcopenshell)](https://aur.archlinux.org/packages/ifcopenshell) |
| ArchLinux AUR Package git | [![AUR Badge](https://img.shields.io/aur/version/ifcopenshell-git)](https://aur.archlinux.org/packages/ifcopenshell-git) |
| BlenderBIM Add-on Chocolatey (under moderation) | [![Chocolatey Badge](https://img.shields.io/chocolatey/v/blenderbim-nightly)](https://community.chocolatey.org/packages/blenderbim-nightly/) |
| Sponsor development on OpenCollective | [![Financial Contributors](https://opencollective.com/opensourcebim/tiers/badge.svg)](https://opencollective.com/opensourcebim/) |
| Docker hub | [![Docker Pulls](https://img.shields.io/docker/pulls/aecgeeks/ifcopenshell)](https://hub.docker.com/r/aecgeeks/ifcopenshell) |
Contents
--------
| Name | Description | License | Service |
| ------------------------- | --------------------------------------------------------------------- | ------------------- | ------- |
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/bcf-client?label=PyPI&color=006dad)](https://pypi.org/project/bcf-client/) |
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later | [![Official](https://img.shields.io/badge/BlenderBIM.org-Download-70ba35)](https://blenderbim.org/download.html) [![GitHub Unstable](https://img.shields.io/github/v/release/ifcopenshell/ifcopenshell?filter=blenderbim-*&label=GitHub-Unstable&color=f6f8fa)](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=blenderbim&expanded=true) [![Chocolatey](https://img.shields.io/chocolatey/v/blenderbim-nightly?label=Chocolatey&color=5c9fd8)](https://community.chocolatey.org/packages/blenderbim-nightly/) |
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/bsdd?label=PyPI&color=006dad)](https://pypi.org/project/bsdd/) |
| ifc2ca | Utility to convert IFC structural analysis models to Code_Aster | LGPL-3.0-or-later |
| ifc4d | Convert to and from IFC and project management software | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifc4d?label=PyPI&color=006dad)](https://pypi.org/project/ifc4d/) |
| ifc5d | Report and optimise cost information from IFC | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifc5d?label=PyPI&color=006dad)](https://pypi.org/project/ifc5d/) |
| ifcbimtester | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later |
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later\* |
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifccityjson?label=PyPI&color=006dad)](https://pypi.org/project/ifccityjson/) |
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifcclash?label=PyPI&color=006dad)](https://pypi.org/project/ifcclash/) |
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* | [![Official](https://img.shields.io/badge/IfcOpenShell.org-Download-70ba35)](https://docs.ifcopenshell.org/ifcconvert/installation.html)
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifccsv?label=PyPI&color=006dad)](https://pypi.org/project/ifccsv/) |
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifcdiff?label=PyPI&color=006dad)](https://pypi.org/project/ifcdiff/) |
| ifcfm | Extract IFC data for FM handover requirements | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifcfm?label=PyPI&color=006dad)](https://pypi.org/project/ifcfm/) |
| ifcmax | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later\* | [![Official](https://img.shields.io/badge/IfcOpenShell.org-Download-70ba35)](https://docs.ifcopenshell.org/ifcmax.html)
| ifcopenshell-python | Python library for IFC manipulation | LGPL-3.0-or-later\* | [![GitHub](https://img.shields.io/github/v/release/ifcopenshell/ifcopenshell?filter=ifcopenshell-python-*&label=GitHub&color=f6f8fa)](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcopenshell-python&expanded=true) [![PyPI](https://img.shields.io/pypi/v/ifcopenshell?label=PyPI&color=006dad)](https://pypi.org/project/ifcopenshell/) [![Anaconda](https://img.shields.io/conda/vn/conda-forge/ifcopenshell?label=Anaconda&color=43b02a)](https://anaconda.org/conda-forge/ifcopenshell) [![Anaconda](https://img.shields.io/conda/vn/ifcopenshell/ifcopenshell?label=Anaconda-Unstable&color=43b02a)](https://anaconda.org/ifcopenshell/ifcopenshell) [![Docker](https://img.shields.io/docker/pulls/aecgeeks/ifcopenshell?label=Docker&color=1D63ED)](https://hub.docker.com/r/aecgeeks/ifcopenshell) [![AUR](https://img.shields.io/aur/version/ifcopenshell?label=AUR&color=1793d1)](https://aur.archlinux.org/packages/ifcopenshell) [![AUR Unstable](https://img.shields.io/aur/version/ifcopenshell-git?label=AUR-Unstable&color=1793d1)](https://aur.archlinux.org/packages/ifcopenshell-git) |
| ifcpatch | Utility to run pre-packaged scripts to manipulate IFCs | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifcpatch?label=PyPI&color=006dad)](https://pypi.org/project/ifcpatch/) |
| ifcsverchok | Blender Add-on for visual node programming with IFC | GPL-3.0-or-later | [![GitHub Unstable](https://img.shields.io/github/v/release/ifcopenshell/ifcopenshell?filter=ifcsverchok-*.*.*.*&label=GitHub-Unstable&color=f6f8fa)](https://github.com/IfcOpenShell/IfcOpenShell/releases?q=ifcsverchok&expanded=true)
| ifctester | Library, CLI and webapp for IDS model auditing | LGPL-3.0-or-later | [![PyPI](https://img.shields.io/pypi/v/ifctester?label=PyPI&color=006dad)](https://pypi.org/project/ifctester/) |
The IfcOpenShell C++ codebase is split into multiple interal libraries:
Those marked with an asterisk are part of IfcOpenShell.
| Name | Description | License |
| ------------------------- | --------------------------------------------------------------------- | ------------------- |
| bcf | Library to read and write BCF-XML and query OpenCDE BCF-API modules | LGPL-3.0-or-later |
| blenderbim | Add-on to Blender providing a graphical native IFC authoring platform | GPL-3.0-or-later |
| bsdd | Library to query the bSDD API | LGPL-3.0-or-later |
| ifc2ca | Utility to convert IFC structural analysis models to Code_Aster | LGPL-3.0-or-later |
| ifc4d | Convert to and from IFC and project management software | LGPL-3.0-or-later |
| ifc5d | Report and optimise cost information from IFC | LGPL-3.0-or-later |
| ifcbimtester | Wrapper for Gherkin based unit testing for IFC models | LGPL-3.0-or-later |
| ifcblender | Historic Blender IFC import add-on | LGPL-3.0-or-later\* |
| ifccityjson | Convert CityJSON to IFC | LGPL-3.0-or-later |
| ifcclash | Clash detection library and CLI app | LGPL-3.0-or-later |
| ifcconvert | CLI app to convert IFC to many other formats | LGPL-3.0-or-later\* |
| ifccsv | Library and CLI app to export and import schedules from IFC | LGPL-3.0-or-later |
| ifcdiff | Compare changes between IFC models | LGPL-3.0-or-later |
| ifcfm | Extract IFC data for FM handover requirements | LGPL-3.0-or-later |
| ifcgeom | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| ifcgeom\_schema\_agnostic | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| ifcgeomserver | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| ifcjni | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| ifcmax | Historic extension for IFC support in 3DS Max | LGPL-3.0-or-later\* |
| ifcopenshell-python | Python library for IFC manipulation | LGPL-3.0-or-later\* |
| ifcparse | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| ifcpatch | Utility to run pre-packaged scripts to manipulate IFCs | LGPL-3.0-or-later |
| ifcsverchok | Blender Add-on for visual node programming with IFC | GPL-3.0-or-later |
| ifctester | Library, CLI and webapp for IDS model auditing | LGPL-3.0-or-later |
| ifcwrap | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| qtviewer | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
| serializers | Internal library for IfcOpenShell | LGPL-3.0-or-later\* |
-1
View File
@@ -1 +0,0 @@
0.7.10
+1 -1
View File
@@ -12,7 +12,7 @@
<projectUrl>https://github.com/IfcOpenShell/IfcOpenShell</projectUrl>
<iconUrl>https://rawcdn.githack.com/IfcOpenShell/IfcOpenShell/c6ee1d1679d1298de0d7447ff108c22709c68e54/choco/blenderbim/blenderbim.png</iconUrl>
<!-- <copyright>Year Software Vendor</copyright> -->
<licenseUrl>https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.8.0/COPYING</licenseUrl>
<licenseUrl>https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.7.0/COPYING</licenseUrl>
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<projectSourceUrl>https://github.com/IfcOpenShell/IfcOpenShell</projectSourceUrl>
<docsUrl>https://docs.blenderbim.org/</docsUrl>
+89
View File
@@ -0,0 +1,89 @@
import datetime
import re
import sys
from urllib import request
def request_repo_info(url: str):
req = request.Request(url)
resp = request.urlopen(req)
if not resp.status == 200:
print(f"[ERROR] could not contact server: {url}")
quit(1)
return resp
def get_choco_package_info() -> str:
resp = request_repo_info(URL_CHOCO_PACKAGE)
html_txt = str(resp.read())
return html_txt
def get_latest_blender_version() -> list:
html_txt = get_choco_package_info()
return re.findall(RE_BLENDER_VERSION_MIN_MAJ_PAT, html_txt)
URL_IFCOS_RELEASES = "https://github.com/IfcOpenShell/IfcOpenShell/releases"
URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"(?:set|SET)\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
if sys.argv[1] == "--do_choco_release?":
now = datetime.datetime.now()
blenderbim_date = (now - datetime.timedelta(days=1)).strftime("%y%m%d")
resp = request_repo_info(URL_IFCOS_RELEASES)
text = str(resp.read())
if blenderbim_date in text:
print("do_choco_release", end="")
elif sys.argv[1] == "--latest_blender_release_maj_min_pat?":
latest_blender_version = get_latest_blender_version()
if latest_blender_version:
print(latest_blender_version[0], end="")
else:
print("[ERROR] could not determine blender_version_min_maj_pat")
quit(1)
elif sys.argv[1] == "--latest_blender_release_maj_min?":
html_txt = get_choco_package_info()
blender_version_min_maj = re.findall(RE_BLENDER_VERSION_MIN_MAJ, html_txt)
if blender_version_min_maj:
print(blender_version_min_maj[0], end="")
else:
print("[ERROR] could not determine blender_version_min_maj")
quit(1)
elif sys.argv[1] == "--latest_blender_python_version_maj_min?":
latest_blender_version = get_latest_blender_version()
if latest_blender_version:
latest_blender_version_tag = f"v{latest_blender_version[0]}"
resp = request_repo_info(URL_BLENDER_CMAKE.format(latest_blender_version_tag))
html_txt = str(resp.read())
found = re.findall(RE_BLENDER_PYTHON_VERSION_MAJ_MIN, html_txt)
if found:
print(found[0], end="")
else:
print("[ERROR] could not determine blender_python_version_maj_min")
quit(1)
elif sys.argv[1] == "--pyver?":
latest_blender_version = get_latest_blender_version()
if latest_blender_version:
latest_blender_version_tag = f"v{latest_blender_version[0]}"
resp = request_repo_info(URL_BLENDER_CMAKE.format(latest_blender_version_tag))
html_txt = str(resp.read())
found = re.findall(RE_BLENDER_PYTHON_VERSION_MAJ_MIN, html_txt)
if found:
print(f"py{found[0].replace('.', '')}", end="")
else:
print("[ERROR] could not determine pyver")
quit(1)
-212
View File
@@ -1,212 +0,0 @@
# commands to run it on a generic ubuntu 2404 oci container:
"""
apt update && apt install git wget curl ptpython mono-devel micro
mkdir -p /home/runner/work/IfcOpenShell && cd /home/runner/work/IfcOpenShell
git clone https://github.com/IfcOpenShell/IfcOpenShell
cd /home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/
micro choco_release.py # paste this script, comment out push command
export CHOCO_TOKEN="secret_choco_release_token"
python3 choco_release.py
"""
import datetime
import hashlib
import os
import pathlib
import re
from urllib import request
def get_repo_tag_names():
git_return = os.popen("git tag -l").read()
tag_names = [tag_name for tag_name in git_return.split("\n") if tag_name]
print(f"{len(tag_names)} tag_names found in repo")
return tag_names
def request_repo_info(url: str):
req = request.Request(url)
resp = request.urlopen(req)
if not resp.status == 200:
print(f"[ERROR] could not contact server: {url}")
quit(1)
return resp
def get_choco_package_info() -> str:
resp = request_repo_info(URL_CHOCO_PACKAGE)
html_txt = str(resp.read())
return html_txt
def get_latest_choco_blender_version() -> list:
html_txt = get_choco_package_info()
return re.findall(RE_BLENDER_VERSION_MIN_MAJ_PAT, html_txt)
def get_file_sha256_hash(file_path):
BLOCKSIZE = 65536
hasher = hashlib.sha256()
with open(file_path, "rb") as input_file:
buffer = input_file.read(BLOCKSIZE)
while len(buffer) > 0:
hasher.update(buffer)
buffer = input_file.read(BLOCKSIZE)
return hasher.hexdigest()
def quit_with_error_message(message: str):
print(f"ERROR: {message}")
quit(0)
start = datetime.datetime.now()
URL_CHOCO_PACKAGE = "https://community.chocolatey.org/packages/blender"
URL_BLENDER_CMAKE = "https://raw.githubusercontent.com/blender/blender/{}/build_files/cmake/Modules/FindPythonLibsUnix.cmake"
URL_IFCOS_RELEASES = "https://github.com/IfcOpenShell/IfcOpenShell/releases/download/"
RE_BLENDER_VERSION_MIN_MAJ = r"Latest Version.+<span>Blender (\d+\.\d+)\..+</span>"
RE_BLENDER_VERSION_MIN_MAJ_PAT = r"Latest Version.+<span>Blender (\d+\.\d+\.\d+)</span>"
RE_BLENDER_PYTHON_VERSION_MAJ_MIN = r"\(_PYTHON_VERSION_SUPPORTED (\d+\.\d+)\)"
BLENDERBIM_DIR = pathlib.Path("/home/runner/work/IfcOpenShell/IfcOpenShell/choco/blenderbim/")
print("_____ check choco release needed?")
os.chdir(BLENDERBIM_DIR)
blenderbim_date_yesterday = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%y%m%d")
should_release = False
target_release_tag = ""
target_os = "win"
git_status = os.popen("git status").read()
print(git_status)
for tag_name in get_repo_tag_names():
print(tag_name)
if blenderbim_date_yesterday in tag_name:
should_release = True
target_release_tag = tag_name
print(f"found {tag_name=} - {should_release=}")
break
if not should_release:
print(f"INFO: no blenderbim release tags found for {blenderbim_date_yesterday} -> no choco release today.")
quit(0)
print(f"{should_release=}")
if not os.environ.get("CHOCO_TOKEN"):
quit_with_error_message("could retrieve CHOCO_TOKEN env var")
choco_token = os.environ["CHOCO_TOKEN"]
print("\n_____ get blender info")
# blender_version_min_maj_pat - from chocolatey.org
latest_blender_release_maj_min_pat = get_latest_choco_blender_version()
if not latest_blender_release_maj_min_pat:
quit_with_error_message("could not determine blender_version_min_maj_pat")
latest_blender_release_maj_min_pat = latest_blender_release_maj_min_pat[0]
print(f"{latest_blender_release_maj_min_pat=}")
# blender_version_min_maj - from chocolatey.org
blender_version_min_maj = latest_blender_release_maj_min_pat.rsplit(".", 1)[0]
print(f"{blender_version_min_maj=}")
# blender_python_version_maj_min - from blender repo
python_version = ""
latest_blender_version_tag = f"v{latest_blender_release_maj_min_pat}"
resp = request_repo_info(URL_BLENDER_CMAKE.format(latest_blender_version_tag))
html_txt = str(resp.read())
found = re.findall(RE_BLENDER_PYTHON_VERSION_MAJ_MIN, html_txt)
if not found:
quit_with_error_message("could not determine blender_python_version_maj_min")
blender_python_version_maj_min = found[0]
print(f"{blender_python_version_maj_min=}")
python_version = f"py{found[0].replace('.', '')}"
print(f"{python_version=}")
blenderbim_build_version = target_release_tag.replace("blenderbim-", "")
# url_blenderbim_py3x_win_zip
release_zip_file_name = f"{target_release_tag}-{python_version}-{target_os}.zip"
# download release
url_blenderbim_py3x_win_zip = f"{URL_IFCOS_RELEASES}{target_release_tag}/{release_zip_file_name}"
os.popen(f"wget {url_blenderbim_py3x_win_zip} --no-verbose").read()
# sha256sum_blenderbim_py310_win_zip
sha256sum_blenderbim_py3x_win_zip = get_file_sha256_hash(release_zip_file_name)
print("\n_____ fill dynamic chocolatey package parameters")
HERE_DIR = pathlib.Path(__file__).parent.absolute()
# print(f"[INFO] HERE_DIR: {HERE_DIR}")
topics = {
"spec": {
"path": HERE_DIR / "blenderbim.nuspec",
"key_values": {
"latest_blender_version_maj_min_pat": latest_blender_release_maj_min_pat,
"blenderbim_build_version" : blenderbim_build_version,
},
},
"install": {
"path": HERE_DIR / "tools" / "chocolateyinstall.ps1",
"key_values": {
"url_blenderbim_py3x_win_zip" : url_blenderbim_py3x_win_zip,
"sha256sum_blenderbim_py3x_win_zip": sha256sum_blenderbim_py3x_win_zip,
"latest_blender_version_maj_min" : blender_version_min_maj,
},
},
"uninstall": {
"path": HERE_DIR / "tools" / "chocolateyuninstall.ps1",
"key_values": {
"latest_blender_version_maj_min": blender_version_min_maj,
},
},
}
for topic, info in topics.items():
print(f" {topic}:")
with open(info["path"], encoding="utf-8") as txt:
content = txt.read()
for key, value in info["key_values"].items():
# print(f"[INFO] replace: {env_var_name}")
if not key in content:
print(f" {key=} not found in {info['path']}")
content = content.replace(key, value)
with open(info["path"], "w", encoding="utf-8") as txt:
txt.write(content)
print(f" written: {info['path']}")
print("[INFO] inserting dynamic chocolatey package parameters successful")
print("\n_____ build choco.exe with mono")
choco_version = "1.1.0"
os.popen(f"wget https://github.com/chocolatey/choco/archive/refs/tags/{choco_version}.tar.gz --quiet").read()
os.popen(f"tar -xzf {choco_version}.tar.gz").read()
print("choco tar unpack successful")
os.chdir("choco-1.1.0")
os.popen("./build.sh").read()
os.popen("cp -r build_output/chocolatey /opt/chocolatey").read()
os.chdir(BLENDERBIM_DIR)
if pathlib.Path("/opt/chocolatey/choco.exe").exists():
print("choco build successful")
print("\n_____ build choco pack")
os.popen("mono /opt/chocolatey/choco.exe pack --allow-unofficial").read()
os.popen('mono /opt/chocolatey/choco.exe setapikey --key="{choco_token}" --source="https://push.chocolatey.org/" --allow-unofficial').read()
print("\n_____ build choco push")
os.popen('mono /opt/chocolatey/choco.exe push --source="https://push.chocolatey.org/" --key="$CHOCO_TOKEN" --allow-unofficial --verbose').read()
print(f"choco push of version: {target_release_tag} successful!")
print(f"it took: {datetime.datetime.now() - start}")
@@ -0,0 +1,49 @@
import os
from pathlib import Path
print("[INFO] inserting dynamic chocolatey package parameters")
HERE_DIR = Path(__file__).parent.absolute()
# print(f"[INFO] HERE_DIR: {HERE_DIR}")
topics = {
"spec": {
"path": HERE_DIR / "blenderbim.nuspec",
"env_vars": {
"latest_blender_version_maj_min_pat",
"blenderbim_build_version",
},
},
"install": {
"path": HERE_DIR / "tools" / "chocolateyinstall.ps1",
"env_vars": {
"url_blenderbim_py310_win_zip",
"sha256sum_blenderbim_py310_win_zip",
"latest_blender_version_maj_min",
},
},
"uninstall": {
"path": HERE_DIR / "tools" / "chocolateyuninstall.ps1",
"env_vars": {
"latest_blender_version_maj_min",
},
},
}
for topic, info in topics.items():
print(f"[INFO] {topic}:")
for env_var_name in info["env_vars"]:
print(f"[INFO] {env_var_name} exists?: {os.environ[env_var_name]}")
with open(info["path"], encoding="utf-8") as txt:
content = txt.read()
for env_var_name in info["env_vars"]:
# print(f"[INFO] replace: {env_var_name}")
content = content.replace(env_var_name, os.environ[env_var_name])
with open(info["path"], "w", encoding="utf-8") as txt:
txt.write(content)
print(f"[INFO] written: {info['path']}")
print("[INFO] inserting dynamic chocolatey package parameters successful")
+2 -2
View File
@@ -1,7 +1,7 @@
$ErrorActionPreference = 'Stop'
$url64 = 'url_blenderbim_py3x_win_zip'
$checksum64 = 'sha256sum_blenderbim_py3x_win_zip'
$url64 = 'url_blenderbim_py310_win_zip'
$checksum64 = 'sha256sum_blenderbim_py310_win_zip'
$checksumType64 = 'sha256'
$appDataUserDir = [System.Environment]::GetEnvironmentVariable('appdata')
+195 -275
View File
@@ -17,31 +17,24 @@
# #
################################################################################
cmake_minimum_required(VERSION 3.21)
set(CMAKE_CXX_STANDARD 17)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
endif()
project(IfcOpenShell VERSION 0.7.0)
cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0074 NEW)
cmake_policy(SET CMP0078 OLD)
cmake_policy(SET CMP0086 NEW)
if (POLICY CMP0144)
cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case <PACKAGENAME>_ROOT variables.
cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case <PACKAGENAME>_ROOT variables.
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release")
endif()
# Include utility macros and functions
include(utilities.cmake)
# use extra version to make pre-release using eg semver
if(NOT DEFINED EXTRA_VERSION)
set(EXTRA_VERSION "-alpha.3")
@@ -67,36 +60,20 @@ option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF)
option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) # QtViewer requires Qt6
option(BUILD_PACKAGE "" OFF)
option(WITH_OPENCASCADE "Enable geometry interpretation using Open CASCADE" ON)
option(WITH_CGAL "Enable geometry interpretation using CGAL" ON)
option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
option(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
option(WITH_PROJ "Enable output of Earth-Centered Earth-Fixed glTF output using the PROJ library" OFF)
option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF)
option(CITYJSON_SUPPORT "Build IfcConvert with CityJSON support (requires CityJSON library)." ON)
option(WITH_RELATIONSHIP_VALIDATION "Build IfcConvert with option to validate geometrical relationships." OFF)
option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF)
option(ADD_COMMIT_SHA "Add commit sha and branch in version number, warning results in many rebuilds, requires git" OFF)
option(VERSION_OVERRIDE "Override the version defined in IfcParse.h with the file VERSION in the repository root" OFF)
if (VERSION_OVERRIDE)
file(READ "../VERSION" "RELEASE_VERSION_")
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
message(STATUS "Detected version '${RELEASE_VERSION}'")
else()
set(RELEASE_VERSION "0.8.0")
endif()
project(IfcOpenShell VERSION ${RELEASE_VERSION})
if(MINIMAL_BUILD)
message(STATUS "Setting options for minimal build")
set(BUILD_GEOMSERVER OFF)
set(BUILD_IFCPYTHON OFF)
set(WITH_CGAL OFF)
set(COLLADA_SUPPORT OFF)
set(GLTF_SUPPORT OFF)
set(HDF5_SUPPORT OFF)
@@ -162,11 +139,17 @@ if(BUILD_SHARED_LIBS)
set(IFCOPENSHELL_LIBRARY_DIR "${LIBDIR}")
endif()
# Create cache entries if absent for environment variables
macro(UNIFY_ENVVARS_AND_CACHE VAR)
if((NOT DEFINED ${VAR}) AND(NOT "$ENV{${VAR}}" STREQUAL ""))
set(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
endif()
endmacro()
UNIFY_ENVVARS_AND_CACHE(OCC_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(OCC_LIBRARY_DIR)
UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT)
UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR)
UNIFY_ENVVARS_AND_CACHE(EIGEN_DIR)
if(NOT MINIMAL_BUILD)
UNIFY_ENVVARS_AND_CACHE(OPENCOLLADA_INCLUDE_DIR)
@@ -186,14 +169,6 @@ if(NOT MINIMAL_BUILD)
UNIFY_ENVVARS_AND_CACHE(MPFR_LIBRARY_DIR)
endif()
# Get a list of all OPTION flags from the CMakeLists.txt
get_all_option_flags(option_flags)
# Loop through the list of OPTION flags and convert the corresponding environment variables
foreach(option_flag IN LISTS option_flags)
convert_env_var_to_bool("${option_flag}")
endforeach()
if(WASM_BUILD)
# when using the nix/build-all.py build script we should not
# look into the sysroot for most of the dependencies but rather
@@ -202,24 +177,7 @@ if(WASM_BUILD)
set(CMAKE_FIND_ROOT_PATH "")
endif()
if(WITH_CGAL)
add_definitions(-DIFOPSH_WITH_CGAL)
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_CGAL)
if(CITYJSON_SUPPORT)
add_definitions(-DIFOPSH_WITH_CITYJSON)
endif()
list(APPEND GEOMETRY_KERNELS cgal)
endif()
if(WITH_OPENCASCADE)
add_definitions(-DIFOPSH_WITH_OPENCASCADE)
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_OPENCASCADE)
list(APPEND GEOMETRY_KERNELS opencascade)
endif()
if(GLTF_SUPPORT OR CITYJSON_SUPPORT)
if(GLTF_SUPPORT AND BUILD_CONVERT)
UNIFY_ENVVARS_AND_CACHE(JSON_INCLUDE_DIR)
find_file(json_hpp "json.hpp" ${JSON_INCLUDE_DIR}/nlohmann)
@@ -233,7 +191,7 @@ if(GLTF_SUPPORT OR CITYJSON_SUPPORT)
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_GLTF)
endif()
# Add USD support to serializers
# Add USD support to serializers
if(USD_SUPPORT)
UNIFY_ENVVARS_AND_CACHE(USD_INCLUDE_DIR)
UNIFY_ENVVARS_AND_CACHE(USD_LIBRARY_DIR)
@@ -256,13 +214,13 @@ if(USD_SUPPORT)
endif()
set(USD_LIBRARIES
usd_usd
usd_usd
usd_usdGeom
usd_usdShade
usd_usdLux
usd_vt
usd_sdf
usd_tf
usd_usdShade
usd_usdLux
usd_vt
usd_sdf
usd_tf
usd_gf
)
@@ -278,7 +236,23 @@ if(USD_SUPPORT)
add_definitions(-DWITH_USD)
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_USD)
endif(USD_SUPPORT)
endif()
# Set INSTALL_RPATH for target
macro(SET_INSTALL_RPATHS _target _paths)
set(${_target}_rpaths "")
foreach(_path ${_paths})
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
if("${isSystemDir}" STREQUAL "-1")
list(APPEND ${_target}_rpaths ${_path})
endif()
endforeach()
message(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
set_target_properties(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
endmacro()
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
# runtime, when doing running conda-build we pick what conda prepared for us.
@@ -308,7 +282,7 @@ else()
endif()
endif()
if(WASM_BUILD)
if (WASM_BUILD)
set(BOOST_COMPONENTS)
else()
# @todo review this, shouldn't this be all possible header-only now?
@@ -341,13 +315,50 @@ if(IFCXML_SUPPORT)
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_IFCXML)
endif()
# Usage:
# set(SOME_LIRARIES foo bar)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d)
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
# or
# set(SOME_LIRARIES path/foo.lib)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
# TODO Could be refined: take the library file extension as a parameter and
# make sure the lib variable ends with not just contains it.
function(add_debug_variants NAME LIBRARIES POSTFIX)
set(LIBRARIES_STR "${LIBRARIES}")
set(LIBRARIES "")
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
foreach(lib ${LIBRARIES_STR})
list(APPEND LIBRARIES optimized)
if("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}.lib)
else()
list(APPEND LIBRARIES ${lib})
endif()
list(APPEND LIBRARIES debug)
if("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
else()
list(APPEND LIBRARIES ${lib}${POSTFIX})
endif()
endforeach()
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
endfunction()
if(BUILD_IFCGEOM)
if(MSVC)
add_debug_variants(LIBXML2_LIBRARIES "${LIBXML2_LIBRARIES}" d)
endif()
# Open CASCADE
if(WITH_OPENCASCADE)
if("${OCC_INCLUDE_DIR}" STREQUAL "")
find_path(OCC_INCLUDE_DIR Standard_Version.hxx
PATHS
@@ -379,7 +390,7 @@ if(BUILD_IFCGEOM)
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAINT
REGEX "#define OCC_VERSION_MAINTENANCE.*"
)
string(REGEX MATCH "[0-9]+" OCC_MAINT ${OCC_MAINT})
string(REGEX MATCH "[0-9]+" OCC_MAINT ${OCC_MAINT})
set(OCC_VERSION_STRING "${OCC_MAJOR}.${OCC_MINOR}.${OCC_MAINT}")
endif(OCC_INCLUDE_DIR)
@@ -390,7 +401,6 @@ if(BUILD_IFCGEOM)
# @todo investigate the exact conditions when this is necessary
TKBin
)
if(OCC_VERSION_STRING VERSION_LESS 7.8.0)
list(APPEND OPENCASCADE_LIBRARY_NAMES TKIGES TKSTEPBase TKSTEPAttr TKSTEP209 TKSTEP)
else(OCC_VERSION_STRING VERSION_LESS 7.8.0)
@@ -451,7 +461,7 @@ if(BUILD_IFCGEOM)
if(OCCT_STATIC)
find_package(Threads)
if(WASM_BUILD)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
else()
@@ -463,15 +473,15 @@ if(BUILD_IFCGEOM)
set(OPENCASCADE_LIBRARIES -Wl,--start-group ${OPENCASCADE_LIBRARIES} -Wl,--end-group ${CMAKE_THREAD_LIBS_INIT})
endif()
endif()
if(NOT APPLE AND NOT WIN32)
if (NOT APPLE AND NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "rt")
endif()
if(NOT WIN32)
if (NOT WIN32)
set(OPENCASCADE_LIBRARIES ${OPENCASCADE_LIBRARIES} "dl")
endif()
endif()
endif(WITH_OPENCASCADE)
endif(BUILD_IFCGEOM)
if(COLLADA_SUPPORT)
@@ -556,7 +566,7 @@ if(COLLADA_SUPPORT)
message(FATAL_ERROR "COLLADA_SUPPORT enabled, but unable to find OpenCOLLADA headers. "
"Disable COLLADA_SUPPORT or fix OpenCOLLADA paths to proceed.")
endif()
endif(COLLADA_SUPPORT)
endif()
if(HDF5_SUPPORT)
if("${HDF5_INCLUDE_DIR}" STREQUAL "")
@@ -599,26 +609,32 @@ if(HDF5_SUPPORT)
else()
message(STATUS "Packaging hdf5 and zlib for conda distribution")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# macOS
set(zlib_post libz)
set(lib_ext dylib)
set(HDF5_LIBRARIES
"${HDF5_LIBRARY_DIR}/libhdf5_cpp.${lib_ext}"
"${HDF5_LIBRARY_DIR}/libhdf5.${lib_ext}"
"${HDF5_LIBRARY_DIR}/${zlib_post}.${lib_ext}"
)
if(WIN32)
# Windows
set(HDF5_LIBRARIES)
find_package(HDF5 COMPONENTS CXX)
if (HDF5_FOUND)
set(HDF5_LIBRARIES ${HDF5_CXX_LIBRARIES})
endif()
list(APPEND HDF5_LIBRARIES
"${HDF5_LIBRARY_DIR}/zlib.lib"
)
else()
# linux and windows
# Find HDF5 package
find_package(HDF5 REQUIRED COMPONENTS C CXX)
# Find ZLIB package
find_package(ZLIB REQUIRED)
# Include directories
include_directories(${HDF5_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS})
# Link libraries
set(HDF5_LIBRARIES ${HDF5_LIBRARIES} ${ZLIB_LIBRARIES})
message(STATUS "HDF5 libraries: ${HDF5_LIBRARIES}")
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# macOS
set(zlib_post libz)
set(lib_ext dylib)
else()
# linux
set(zlib_post libz)
set(lib_ext so)
endif()
set(HDF5_LIBRARIES
"${HDF5_LIBRARY_DIR}/libhdf5_cpp.${lib_ext}"
"${HDF5_LIBRARY_DIR}/libhdf5.${lib_ext}"
"${HDF5_LIBRARY_DIR}/${zlib_post}.${lib_ext}"
)
endif()
endif()
endif()
@@ -636,7 +652,7 @@ if(HDF5_SUPPORT)
add_definitions(-DWITH_HDF5)
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_HDF5)
endif(HDF5_SUPPORT)
endif()
if(WASM_BUILD)
# reset to use sysroot
@@ -667,17 +683,15 @@ if(ENABLE_BUILD_OPTIMIZATIONS)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -O3")
endif()
else()
# @tfk I commented this out as this kind of defeats the purpose of RelWithDebInfo. For the
# best debugging experience simply use Debug. Note that in MSVC you can selectively toggle
# optimization on a specific file if you're investigating a specific issue.
# if(MSVC)
# set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od")
# endif()
endif(ENABLE_BUILD_OPTIMIZATIONS)
if(MSVC)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od")
endif()
endif()
if(MSVC)
# warning due to virtual inheritance
add_definitions(-wd4250)
# warning due to select definitions in the schema being redundant
add_definitions(-wd4584)
@@ -713,22 +727,20 @@ if(MSVC)
add_definitions(-permissive-)
endif()
# Link against the static VC runtime
# TODO Make this configurable
# if("$ENV{CONDA_BUILD}" STREQUAL "")
# foreach(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
# CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
# CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
# if(${flag} MATCHES "/MD")
# STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
# endif()
# if(${flag} MATCHES "/MDd")
# STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
# endif()
# endforeach()
# endif()
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
# Link against the static VC runtime
# TODO Make this configurable
# IF("$ENV{CONDA_BUILD}" STREQUAL "")
# FOREACH(flag CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL
# CMAKE_CXX_FLAGS_RELWITHDEBINFO CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
# CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
# IF(${flag} MATCHES "/MD")
# STRING(REGEX REPLACE "/MD" "/MT" ${flag} "${${flag}}")
# ENDIF()
# IF(${flag} MATCHES "/MDd")
# STRING(REGEX REPLACE "/MDd" "/MTd" ${flag} "${${flag}}")
# ENDIF()
# ENDFOREACH()
# ENDIF()
else()
add_definitions(-Wall -Wextra)
@@ -747,20 +759,29 @@ else()
if(UNIX)
add_definitions(-fPIC)
endif()
endif(MSVC)
endif()
include_directories(${INCLUDE_DIRECTORIES} ${OCC_INCLUDE_DIR} ${OPENCOLLADA_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS} ${LIBXML2_INCLUDE_DIR} ${JSON_INCLUDE_DIR} ${HDF5_INCLUDE_DIR}
${EIGEN_DIR} ${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR} ${USD_INCLUDE_DIR}
${TBB_INCLUDE_DIR}
${USD_INCLUDE_DIR}
)
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
set(${RESULT_NAME}
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
PARENT_SCOPE
)
endfunction()
if(NOT SCHEMA_VERSIONS)
if(WASM_BUILD)
# super arbitrarily try to keep size down at least a little bit
set(SCHEMA_VERSIONS "2x3" "4")
else()
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3" "4x3_tc1" "4x3_add1" "4x3_add2")
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3_rc1" "4x3_rc2" "4x3_rc3" "4x3_rc4" "4x3" "4x3_tc1" "4x3_add1" "4x3_add2")
endif()
endif()
@@ -833,7 +854,7 @@ if(COMPILE_SCHEMA)
list(REMOVE_ITEM IFC_RELEASE_NOT_USED "${schema}")
endif()
endforeach()
endif(COMPILE_SCHEMA)
endif()
# Boost >= 1.58 requires BOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE to build on some Linux distros.
if(NOT Boost_VERSION LESS 105800)
@@ -841,37 +862,22 @@ if(NOT Boost_VERSION LESS 105800)
endif()
set(IFCOPENSHELL_LIBRARIES IfcParse)
if(BUILD_IFCGEOM)
if (BUILD_IFCGEOM)
foreach(schema ${SCHEMA_VERSIONS})
set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} geometry_mapping_ifc${schema})
set(IFCGEOM_SCHEMA_LIBRARIES ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom_ifc${schema})
endforeach()
if(WASM_BUILD)
if (WASM_BUILD)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
else()
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES})
endif()
endif()
if(BUILD_CONVERT OR BUILD_IFCPYTHON)
if (BUILD_CONVERT OR BUILD_IFCPYTHON)
foreach(schema ${SCHEMA_VERSIONS})
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${schema})
endforeach()
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} Serializers ${SERIALIZER_SCHEMA_LIBRARIES})
if(WITH_OPENCASCADE)
foreach(schema ${SCHEMA_VERSIONS})
set(GEOM_SERIALIZER_SCHEMA_LIBRARIES ${GEOM_SERIALIZER_SCHEMA_LIBRARIES} GeometrySerializers_ifc${schema})
add_library(geometry_serializer_ifc${schema} STATIC ../src/ifcgeom/Serialization/schema/Serialization.cpp)
set_target_properties(geometry_serializer_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
list(APPEND geometry_serializer_libraries geometry_serializer_ifc${schema})
endforeach()
add_library(geometry_serializer STATIC ../src/ifcgeom/Serialization/Serialization.cpp)
target_link_libraries(geometry_serializer ${geometry_serializer_libraries})
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} geometry_serializer ${geometry_serializer_libraries})
endif()
endif()
# IfcParse
@@ -910,70 +916,29 @@ set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
add_library(IfcParse ${IFCPARSE_FILES})
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if(WASM_BUILD)
if (WASM_BUILD)
target_link_libraries(IfcParse ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES})
else()
target_link_libraries(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES} ${LIBXML2_LIBRARIES})
endif()
if(BUILD_IFCGEOM)
if(WITH_CGAL)
find_library(libGMP NAMES gmp mpir PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH)
find_library(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH)
if(NOT libGMP)
message(FATAL_ERROR "Unable to find GMP library files, aborting")
endif()
if(NOT libMPFR)
message(FATAL_ERROR "Unable to find MPFR library files, aborting")
endif()
list(APPEND CGAL_LIBRARIES "${libMPFR}")
list(APPEND CGAL_LIBRARIES "${libGMP}")
endif()
foreach(kernel ${GEOMETRY_KERNELS})
string(TOUPPER ${kernel} KERNEL_UPPER)
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/${kernel}/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/kernels/${kernel}/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
add_library(geometry_kernel_${kernel} ${IFCGEOM_FILES})
set_property(TARGET geometry_kernel_${kernel} APPEND PROPERTY COMPILE_FLAGS "-DIFC_GEOM_EXPORTS")
# needed?
# if(NOT WASM_BUILD)
# endif()
target_link_libraries(geometry_kernel_${kernel} ${${KERNEL_UPPER}_LIBRARIES})
list(APPEND kernel_libraries geometry_kernel_${kernel})
if(${kernel} STREQUAL "cgal")
set_property(TARGET geometry_kernel_${kernel} APPEND_STRING PROPERTY COMPILE_FLAGS " -DCGAL_HAS_THREADS")
add_library(geometry_kernel_${kernel}_simple ${IFCGEOM_FILES})
set_target_properties(geometry_kernel_${kernel}_simple PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIFOPSH_SIMPLE_KERNEL -DCGAL_HAS_THREADS")
# needed?
# if(NOT WASM_BUILD)
# endif()
target_link_libraries(geometry_kernel_${kernel}_simple ${${KERNEL_UPPER}_LIBRARIES})
list(APPEND kernel_libraries geometry_kernel_${kernel}_simple)
endif()
endforeach()
# IfcGeom
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/*.h ../src/ifcgeom/*.i)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
foreach(schema ${SCHEMA_VERSIONS})
file(GLOB IFCGEOM_I_FILES ../src/ifcgeom/mapping/*.i)
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/mapping/*.h)
file(GLOB IFCGEOM_CPP_FILES ../src/ifcgeom/mapping/*.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES} ${IFCGEOM_I_FILES})
add_library(geometry_mapping_ifc${schema} STATIC ${IFCGEOM_FILES})
set_target_properties(geometry_mapping_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
target_link_libraries(geometry_mapping_ifc${schema} IfcParse)
list(APPEND mapping_libraries geometry_mapping_ifc${schema})
add_library(IfcGeom_ifc${schema} STATIC ${IFCGEOM_FILES})
set_target_properties(IfcGeom_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
if (NOT WASM_BUILD)
target_link_libraries(IfcGeom_ifc${schema} IfcParse ${OPENCASCADE_LIBRARIES})
endif()
endforeach()
# IfcGeom (schema agnostic)
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom/*.cpp)
file(GLOB SCHEMA_AGNOSTIC_H_FILES ../src/ifcgeom_schema_agnostic/*.h)
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES ../src/ifcgeom_schema_agnostic/*.cpp)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
@@ -983,10 +948,10 @@ if(BUILD_IFCGEOM)
find_package(Threads)
endif()
if(WASM_BUILD)
target_link_libraries(IfcGeom ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT})
if (WASM_BUILD)
target_link_libraries(IfcGeom ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
else()
target_link_libraries(IfcGeom IfcParse ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(IfcGeom IfcParse ${IFCGEOM_SCHEMA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
endif()
endif(BUILD_IFCGEOM)
@@ -1003,8 +968,8 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON)
foreach(schema ${SCHEMA_VERSIONS})
add_library(Serializers_ifc${schema} STATIC ${SERIALIZERS_S_FILES})
set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
if(WASM_BUILD)
if (WASM_BUILD)
target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES})
else()
target_link_libraries(Serializers_ifc${schema} IfcGeom ${OPENCASCADE_LIBRARIES} ${HDF5_LIBRARIES})
@@ -1014,61 +979,27 @@ if(BUILD_CONVERT OR BUILD_IFCPYTHON)
add_library(Serializers ${SERIALIZERS_FILES})
set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS" VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if(WITH_PROJ)
target_compile_definitions(Serializers PRIVATE "WITH_PROJ")
if (PROJ_STATIC)
target_compile_definitions(Serializers PRIVATE "PROJ_DLL=")
endif()
target_include_directories(Serializers PRIVATE ${PROJ_INCLUDE_DIR} ${SQLITE_INCLUDE_DIR})
target_link_libraries(Serializers ${PROJ_LIBRARIES})
endif()
if (WITH_PROJ)
target_compile_definitions(Serializers PRIVATE "WITH_PROJ")
if (PROJ_STATIC)
target_compile_definitions(Serializers PRIVATE "PROJ_DLL=")
endif()
target_include_directories(Serializers PRIVATE ${PROJ_INCLUDE_DIR} ${SQLITE_INCLUDE_DIR})
target_link_libraries(Serializers ${PROJ_LIBRARIES})
endif()
target_link_libraries(Serializers ${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES})
endif(BUILD_CONVERT OR BUILD_IFCPYTHON)
if(BUILD_CONVERT)
if(WITH_CGAL AND CITYJSON_SUPPORT)
message(STATUS "Building CityJSON support")
set(CITYJSON_CONVERT_FILES
../src/ifcconvert/cityjson/geobim.cpp
../src/ifcconvert/cityjson/global_execution_context.cpp
../src/ifcconvert/cityjson/opening_collector.cpp
../src/ifcconvert/cityjson/processing.cpp
../src/ifcconvert/cityjson/radius_comparison.cpp
../src/ifcconvert/cityjson/radius_execution_context.cpp
../src/ifcconvert/cityjson/settings.cpp
../src/ifcconvert/cityjson/writer.cpp
)
add_library(cityjson_converter ${CITYJSON_CONVERT_FILES})
target_include_directories(cityjson_converter PRIVATE ../src)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} cityjson_converter)
add_executable(cityjson_converter_exe ${CITYJSON_CONVERT_FILES})
set_target_properties(cityjson_converter_exe PROPERTIES COMPILE_FLAGS "-DCITYJSON_EXECUTABLE")
target_include_directories(cityjson_converter_exe PRIVATE ../src)
target_link_libraries(cityjson_converter_exe ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES})
endif()
# IfcConvert
if (WITH_RELATIONSHIP_VALIDATION)
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
else()
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/IfcConvert.cpp)
file(GLOB IFCCONVERT_H_FILES)
endif()
file(GLOB IFCCONVERT_CPP_FILES ../src/ifcconvert/*.cpp)
file(GLOB IFCCONVERT_H_FILES ../src/ifcconvert/*.h)
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
add_executable(IfcConvert ${IFCCONVERT_FILES})
target_link_libraries(IfcConvert ${IFCOPENSHELL_LIBRARIES} ${OPENCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES})
if (WITH_RELATIONSHIP_VALIDATION)
set_property(TARGET IfcConvert APPEND_STRING PROPERTY COMPILE_FLAGS " -DWITH_RELATIONSHIP_VALIDATION")
endif()
if(WITH_CGAL AND CITYJSON_SUPPORT)
set_property(TARGET IfcConvert APPEND_STRING PROPERTY COMPILE_FLAGS " -DIFOPSH_WITH_CITYJSON")
endif()
if((NOT WIN32) AND BUILD_SHARED_LIBS)
# Only set RPATHs when building shared libraries (i.e. IfcParse and
@@ -1101,32 +1032,28 @@ if(BUILD_GEOMSERVER)
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif(BUILD_GEOMSERVER)
endif()
if(ADD_COMMIT_SHA)
find_package(Git)
if(GIT_FOUND)
if (VERSION_OVERRIDE)
set (git_branch ${RELEASE_VERSION})
else()
message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}")
execute_process(
COMMAND ${GIT_EXECUTABLE} branch -a --contains HEAD
OUTPUT_VARIABLE git_branches
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REPLACE "\n" ";" git_branch_list "${git_branches}")
message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}")
execute_process(
COMMAND ${GIT_EXECUTABLE} branch -a --contains HEAD
OUTPUT_VARIABLE git_branches
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REPLACE "\n" ";" git_branch_list "${git_branches}")
foreach(git_branch_candidate IN ITEMS ${git_branch_list})
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
if(NOT git_branch_candidate_2 MATCHES "^HEAD$")
string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}")
list(GET git_branch_candidate_2_list -1 git_branch)
endif()
endforeach()
endif()
foreach(git_branch_candidate IN ITEMS ${git_branch_list})
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
if (NOT git_branch_candidate_2 MATCHES "^HEAD$")
string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}")
list(GET git_branch_candidate_2_list -1 git_branch)
endif()
endforeach()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
@@ -1138,13 +1065,6 @@ if(ADD_COMMIT_SHA)
add_definitions(-DIFCOPENSHELL_BRANCH=${git_branch})
add_definitions(-DIFCOPENSHELL_COMMIT=${git_sha})
endif()
endif(ADD_COMMIT_SHA)
if(MSVC)
# @todo still needs to be understood better, but the cgal and cgal-simple kernel cause multiply defined boost lambda placeholders _1 ... _3
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /FORCE:MULTIPLE")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /FORCE:MULTIPLE")
endif()
# Documentation
@@ -1165,8 +1085,8 @@ if(BUILD_IFCMAX)
add_subdirectory(../src/ifcmax ifcmax)
endif()
if(WITH_CGAL)
add_subdirectory(../src/svgfill svgfill)
if(NOT MINIMAL_BUILD)
add_subdirectory(../src/svgfill svgfill)
endif()
if(BUILD_QTVIEWER)
@@ -1193,12 +1113,12 @@ if(BUILD_IFCGEOM)
DESTINATION ${INCLUDEDIR}/ifcgeom_schema_agnostic
)
install(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} ${kernel_libraries} IfcGeom
install(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} IfcGeom
ARCHIVE DESTINATION ${LIBDIR}
LIBRARY DESTINATION ${LIBDIR}
RUNTIME DESTINATION ${BINDIR}
)
endif(BUILD_IFCGEOM)
endif()
if(BUILD_CONVERT)
install(TARGETS Serializers ${SERIALIZER_SCHEMA_LIBRARIES}
@@ -1214,7 +1134,7 @@ if(BUILD_CONVERT)
install(FILES ${SERIALIZERS_S_FILES}
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
)
endif(BUILD_CONVERT)
endif()
# Cmake uninstall target
if(NOT TARGET uninstall)
@@ -1262,6 +1182,6 @@ 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")
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst")
include(CPack)
-124
View File
@@ -1,124 +0,0 @@
################################################################################
# #
# This file is part of IfcOpenShell. #
# #
# IfcOpenShell is free software: you can redistribute it and/or modify #
# it under the terms of the Lesser GNU General Public License as published by #
# the Free Software Foundation, either version 3.0 of the License, or #
# (at your option) any later version. #
# #
# IfcOpenShell is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# Lesser GNU General Public License for more details. #
# #
# You should have received a copy of the Lesser GNU General Public License #
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
# #
################################################################################
# Create a cache entry if absent for environment variables
macro(UNIFY_ENVVARS_AND_CACHE VAR)
if((NOT DEFINED ${VAR}) AND(NOT "$ENV{${VAR}}" STREQUAL ""))
set(${VAR} "$ENV{${VAR}}" CACHE STRING "${VAR}" FORCE)
endif()
endmacro()
# Set INSTALL_RPATH for target with given paths
macro(SET_INSTALL_RPATHS _target _paths)
set(${_target}_rpaths "")
foreach(_path ${_paths})
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_path}" isSystemDir)
if("${isSystemDir}" STREQUAL "-1")
list(APPEND ${_target}_rpaths ${_path})
endif()
endforeach()
message(STATUS "Set INSTALL_RPATH for ${_target}: ${${_target}_rpaths}")
set_target_properties(${_target} PROPERTIES INSTALL_RPATH "${${_target}_rpaths}")
endmacro()
# Get a list of all OPTION flags from the CMakeLists.txt and store in an output LIST
function(get_all_option_flags output_list)
# Read the contents of the CMakeLists.txt
file(READ "${CMAKE_SOURCE_DIR}/CMakeLists.txt" cmake_contents)
# Find all OPTION flags using a regular expression
string(REGEX MATCHALL "[oO][pP][tT][iI][oO][nN]\\s*\\(\\s*([A-Za-z0-9_]+)" matches "${cmake_contents}")
# Extract the variable names from the matches
set(option_flags)
foreach(match IN LISTS matches)
string(REGEX REPLACE "[oO][pP][tT][iI][oO][nN]\\s*\\(\\s*([A-Za-z0-9_]+)" "\\1" option_flag "${match}")
list(APPEND option_flags "${option_flag}")
endforeach()
# Return the list of OPTION flags
set(${output_list} "${option_flags}" PARENT_SCOPE)
endfunction()
# Loop through a LIST of OPTION flags and convert to corresponding environment variables
function(convert_env_var_to_bool var_name)
if(DEFINED ENV{${var_name}})
string(TOUPPER "$ENV{${var_name}}" bool_value)
if(bool_value STREQUAL "ON" OR bool_value STREQUAL "TRUE" OR bool_value STREQUAL "1")
set(${var_name} ON CACHE BOOL "${var_name} as boolean" FORCE)
elseif(bool_value STREQUAL "OFF" OR bool_value STREQUAL "FALSE" OR bool_value STREQUAL "0")
set(${var_name} OFF CACHE BOOL "${var_name} as boolean" FORCE)
else()
# Not a bool, leave it as a string
endif()
else()
# Not defined, leave it as a string
endif()
endfunction()
# Usage:
# set(SOME_LIRARIES foo bar)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" d)
# "foo bar" -> "optimized foo debug food optimized bar debug bard"
# or
# set(SOME_LIRARIES path/foo.lib)
# add_debug_variants(SOME_LIRARIES "${SOME_LIRARIES}" "d")
# "path/foo.lib" -> "optimized path/foo.lib debug path/food.lib"
# TODO Could be refined: take the library file extension as a parameter and
# make sure the lib variable ends with not just contains it.
function(add_debug_variants NAME LIBRARIES POSTFIX)
set(LIBRARIES_STR "${LIBRARIES}")
set(LIBRARIES "")
# the result, "optimized <lib> debug <lib>", needs to be a list instead of a string
foreach(lib ${LIBRARIES_STR})
list(APPEND LIBRARIES optimized)
if("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}.lib)
else()
list(APPEND LIBRARIES ${lib})
endif()
list(APPEND LIBRARIES debug)
if("${lib}" MATCHES ".lib")
string(REPLACE ".lib" "" lib ${lib})
list(APPEND LIBRARIES ${lib}${POSTFIX}.lib)
else()
list(APPEND LIBRARIES ${lib}${POSTFIX})
endif()
endforeach()
set(${NAME} ${LIBRARIES} PARENT_SCOPE)
endfunction()
function(files_for_ifc_version IFC_VERSION RESULT_NAME)
set(IFC_PARSE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcparse)
set(${RESULT_NAME}
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}enum.h
${IFC_PARSE_DIR}/Ifc${IFC_VERSION}.cpp
PARENT_SCOPE
)
endfunction()
+9 -15
View File
@@ -1,13 +1,10 @@
mkdir build && cd build
REM Remove dot from PY_VER for use in library name
REM From https://github.com/tpaviot/pythonocc-core/blob/master/ci/conda/bld.bat
set MY_PY_VER=%PY_VER:.=%
set LIBXML2="%LIBRARY_PREFIX%/lib/libxml2.lib"
cmake -G "Ninja" ^
-D SCHEMA_VERSIONS="2x3;4;4x1;4x3_add2" ^
-D SCHEMA_VERSIONS="2x3;4;4x1;4x3;4x3_add1" ^
-D CMAKE_BUILD_TYPE:STRING=Release ^
-D CMAKE_INSTALL_PREFIX:FILEPATH="%LIBRARY_PREFIX%" ^
-D CMAKE_PREFIX_PATH:FILEPATH="%LIBRARY_PREFIX%" ^
@@ -15,9 +12,6 @@ cmake -G "Ninja" ^
-D OCC_INCLUDE_DIR:FILEPATH="%LIBRARY_PREFIX%\include\opencascade" ^
-D OCC_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
-D CGAL_INCLUDE_DIR:FILEPATH="%LIBRARY_PREFIX%\include" ^
-D EIGEN_DIR:FILEPATH="%LIBRARY_PREFIX%\include\eigen3" ^
-D LIBXML2_INCLUDE_DIR=%LIBRARY_PREFIX%/include/libxml2 ^
-D LIBXML2_LIBRARIES=%LIBRARY_PREFIX%/lib/libxml2.lib ^
-D GMP_INCLUDE_DIR:FILEPATH="%LIBRARY_PREFIX%\include" ^
-D GMP_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
-D MPFR_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
@@ -38,14 +32,14 @@ cmake -G "Ninja" ^
-D BUILD_CONVERT:BOOL=ON ^
-D BUILD_IFCMAX:BOOL=OFF ^
-D IFCXML_SUPPORT:BOOL=ON ^
-D Boost_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
-D Boost_INCLUDE_DIR:FILEPATH="%LIBRARY_PREFIX%\include" ^
-D Boost_LIBRARYDIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
-D Boost_INCLUDEDIR:FILEPATH="%LIBRARY_PREFIX%\include" ^
-D Boost_USE_STATIC_LIBS:BOOL=OFF ^
-D CITYJSON_SUPPORT:BOOL=OFF ^
../cmake
if errorlevel 1 exit 1
ninja install -j 1
%SRC_DIR%/cmake
if errorlevel 1 exit 1
:: Build and install
cmake --build . -- install
if errorlevel 1 exit 1
+12 -16
View File
@@ -1,19 +1,19 @@
#!/bin/bash
# IF osx use file lib suffix .dylib
# IF linux use file lib suffix .so
# IF windows use file lib suffix .dll
declare -a CMAKE_PLATFORM_FLAGS
if [ "$(uname)" == "Darwin" ]; then
export FSUFFIX=dylib
export LDFLAGS="$LDFLAGS -Wl,-flat_namespace,-undefined,suppress"
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
export FSUFFIX=so
if [[ ${HOST} =~ .*linux.* ]]; then
CMAKE_PLATFORM_FLAGS+=(-DCMAKE_TOOLCHAIN_FILE=$RECIPE_DIR/cross-linux.cmake)
fi
if [ `uname` == Darwin ]; then
export CFLAGS="$CFLAGS -Wl,-flat_namespace,-undefined,suppress"
export CXXFLAGS="$CXXFLAGS -Wl,-flat_namespace,-undefined,suppress"
export LDFLAGS="$LDFLAGS -Wl,-flat_namespace,-undefined,suppress"
fi
cmake ${CMAKE_ARGS} -G Ninja \
-DSCHEMA_VERSIONS="2x3;4;4x1;4x3_add2" \
cmake -G Ninja \
-DSCHEMA_VERSIONS="2x3;4;4x1;4x3;4x3_add1" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
${CMAKE_PLATFORM_FLAGS[@]} \
@@ -29,10 +29,7 @@ cmake ${CMAKE_ARGS} -G Ninja \
-DHDF5_LIBRARY_DIR=$PREFIX/lib \
-DJSON_INCLUDE_DIR=$PREFIX/include \
-DCGAL_INCLUDE_DIR=$PREFIX/include \
-DLIBXML2_INCLUDE_DIR=$PREFIX/include/libxml2 \
-DLIBXML2_LIBRARIES=$PREFIX/lib/libxml2.$FSUFFIX \
-DEIGEN_DIR:FILEPATH=$PREFIX/include/eigen3 \
-DCOLLADA_SUPPORT:BOOL=OFF \
-DCOLLADA_SUPPORT=0 \
-DBUILD_EXAMPLES:BOOL=OFF \
-DIFCXML_SUPPORT:BOOL=ON \
-DGLTF_SUPPORT:BOOL=ON \
@@ -41,9 +38,8 @@ cmake ${CMAKE_ARGS} -G Ninja \
-DBUILD_IFCGEOM:BOOL=ON \
-DBUILD_GEOMSERVER:BOOL=OFF \
-DBOOST_USE_STATIC_LIBS:BOOL=OFF \
-DCITYJSON_SUPPORT:BOOL=OFF \
./cmake
ninja
ninja install -j 1
ninja install -j 1
+4 -56
View File
@@ -1,58 +1,6 @@
CONDA_BUILD_SYSROOT:
- /opt/MacOSX10.13.sdk # [osx]
variant:
- novtk
- all
occt:
- 7.8.1
c_compiler:
- vs2022 # [win]
- gcc # [linux]
- clang # [osx]
c_stdlib:
- vs # [win]
- sysroot # [linux]
- macosx_deployment_target # [osx]
cxx_compiler:
- vs2022 # [win]
- gcc # [linux]
- clangxx # [osx]
c_compiler_version:
- '12' # [linux]
- '16' # [osx]
cxx_compiler_version:
- '12' # [linux]
- '16' # [osx]
c_stdlib_version:
- '2.12' # [linux]
- '10.13' # [osx]
hdf5:
- 1.14.3
libboost_devel:
- '1.84'
libxml2:
- '2'
mpfr:
- '4'
gmp:
- '6' # [not win]
pin_run_as_build:
python:
min_pin: x.x
max_pin: x.x
zlib:
- '1'
target_platform:
- win-64 # [win]
- linux-64 # [linux]
- osx-64 # [osx]
macos_machine:
- x86_64-apple-darwin13.4.0
MACOSX_DEPLOYMENT_TARGET:
- '10.13'
MACOSX_SDK_VERSION:
- '10.13'
CONDA_BUILD_SYSROOT:
- "/Users/runner/work/MacOSX10.13.sdk" # [osx]
- all
+16
View File
@@ -0,0 +1,16 @@
# this one is important
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_PLATFORM Linux)
# specify the cross compiler
set(CMAKE_C_COMPILER $ENV{CC})
set(CMAKE_CXX_COMPILER $ENV{CXX})
# where is the target environment
set(CMAKE_FIND_ROOT_PATH $ENV{PREFIX} $ENV{BUILD_PREFIX}/$ENV{HOST}/sysroot)
# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+27 -262
View File
@@ -1,303 +1,68 @@
{% set version = environ.get('VERSION_OVERRIDE', '0.8.0') %}
{% set build = 0 %}
{% set name = "ifcopenshell" %}
{% set version = "0.7.0" %}
{% set build = 1 %}
# Higher number -> Always prioritize "novtk" variant over "all" variant
{% set build = build + 200 %} # [variant == "novtk"]
{% set build = build + 100 %} # [variant == "all"]
package:
name: ifcopenshell
name: {{ name }}
version: {{ version }}
source:
path: ../
path: ..
build:
number: {{ build }}
skip: true # [py<39]
binary_relocation: false # [osx]
string: py{{ CONDA_PY }}_{{ variant }}_h{{ PKG_HASH }}_{{ build }}
run_exports:
- {{ pin_subpackage('ifcopenshell', max_pin='x.x.x') }} *{{ variant }}*
binary_relocation: false [osx]
number: {{ build }}
requirements:
build:
- cmake
- ninja
- swig >=4.1.1
- {{ stdlib("c") }}
- {{ compiler('c') }}
- {{ compiler('cxx') }}
- ninja >=1.10.2
- cmake
- swig 4.1.1
host:
- python
- libboost-devel
- occt *=*{{ variant }}*
- boost-cpp
- occt 7.7.2 *{{ variant }}*
- libxml2
- cgal-cpp
- hdf5
- eigen
- mpfr
- nlohmann_json
- gmp # [unix]
- mpir # [win]
- nlohmann_json
- zlib
run:
- python
- {{ pin_compatible('occt', max_pin='x.x.x') }} *{{ variant }}*
- {{ pin_compatible('cgal-cpp', max_pin='x.x') }}
- occt 7.7.2 *{{ variant }}*
- {{ pin_compatible('cgal-cpp', max_pin='x.x.x') }}
- {{ pin_compatible('boost-cpp', max_pin='x.x.x') }}
- {{ pin_compatible('hdf5', max_pin='x.x.x') }}
- libxml2
- mpfr
- gmp # [unix]
- mpir # [win]
- nlohmann_json
- zlib
test:
imports:
- ifcopenshell
about:
home: https://ifcopenshell.org
license: LGPL-3.0-or-later
license_file: COPYING
summary: 'IfcOpenShell is a library to support the IFC file format'
description: |
IfcOpenShell
============
IfcOpenShell is an open source ([LGPL]) software library for working with Industry Foundation Classes ([IFC]). Complete
parsing support is provided for [IFC2x3 TC1], [IFC4 Add2 TC1], IFC4x1, IFC4x3, and IFC4x3. Extensive geometric support
is implemented for the IFC releases [IFC2x3 TC1] and [IFC4 Add2 TC1]. Extending with support for arbitrary IFC schemas
is possible at compile-time when using C++ and at run-time when using Python.
In addition to a C++ and Python API, IfcOpenShell comes with an ecosystem of tools, notably including IfcConvert (an
application to convert IFC models to
other formats), the BlenderBIM Add-on (an add-on to Blender providing a graphical IFC authoring platform), and many
other libraries, CLI apps, and more. Support is also provided for auxiliary standards such as BCF and IDS.
For more information, see:
* [IfcOpenShell Website](http://ifcopenshell.org)
* [IfcOpenShell Documentation](http://blenderbim.org/docs-python)
* [IfcOpenShell C++ Installation](https://blenderbim.org/docs-python/ifcopenshell/installation.html)
* [IfcOpenShell Python Installation](https://blenderbim.org/docs-python/ifcopenshell-python/installation.html)
* [IfcOpenShell Python Hello World Tutorial](https://blenderbim.org/docs-python/ifcopenshell-python/hello_world.html)
* [BlenderBIM Add-on Website](https://blenderbim.org)
* [BlenderBIM Add-on Documentation](http://blenderbim.org/docs)
* [Add-on Installation](https://blenderbim.org/docs/users/installation.html)
* [Exploring an IFC model](https://blenderbim.org/docs/users/exploring_an_ifc_model.html)
<table>
<thead>
<tr>
<th>Service</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Anaconda Daily Build</td>
<td><a href="https://anaconda.org/ifcopenshell/ifcopenshell"><img src="https://img.shields.io/conda/vn/ifcopenshell/ifcopenshell" alt="Anaconda-Server Badge"></a></td>
</tr>
<tr>
<td>Anaconda v0.8.0 Stable</td>
<td><a href="https://anaconda.org/conda-forge/ifcopenshell"><img src="https://img.shields.io/conda/vn/conda-forge/ifcopenshell" alt="Anaconda-Server Badge"></a></td>
</tr>
<tr>
<td>PyPi Daily Build</td>
<td><a href="https://pypi.org/project/ifcopenshell/"><img src="https://img.shields.io/pypi/v/ifcopenshell" alt="PyPi Badge"></a></td>
</tr>
<tr>
<td>ArchLinux AUR Package Stable</td>
<td><a href="https://aur.archlinux.org/packages/ifcopenshell"><img src="https://img.shields.io/aur/version/ifcopenshell" alt="AUR Badge"></a></td>
</tr>
<tr>
<td>ArchLinux AUR Package git</td>
<td><a href="https://aur.archlinux.org/packages/ifcopenshell-git"><img src="https://img.shields.io/aur/version/ifcopenshell-git" alt="AUR Badge"></a></td>
</tr>
<tr>
<td>BlenderBIM Add-on Chocolatey (under moderation)</td>
<td><a href="https://community.chocolatey.org/packages/blenderbim-nightly/"><img src="https://img.shields.io/chocolatey/v/blenderbim-nightly" alt="Chocolatey Badge"></a></td>
</tr>
<tr>
<td>Sponsor development on OpenCollective</td>
<td><a href="https://opencollective.com/opensourcebim/"><img src="https://opencollective.com/opensourcebim/tiers/badge.svg" alt="Financial Contributors"></a></td>
</tr>
<tr>
<td>Docker hub</td>
<td><a href="https://hub.docker.com/r/aecgeeks/ifcopenshell"><img src="https://img.shields.io/docker/pulls/aecgeeks/ifcopenshell" alt="Docker Pulls"></a></td>
</tr>
</tbody>
</table>
Contents
--------
Those marked with an asterisk are part of IfcOpenShell.
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>License</th>
</tr>
</thead>
<tbody>
<tr>
<td>bcf</td>
<td>Library to read and write BCF-XML and query OpenCDE BCF-API modules</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>blenderbim</td>
<td>Add-on to Blender providing a graphical native IFC authoring platform</td>
<td>GPL-3.0-or-later</td>
</tr>
<tr>
<td>bsdd</td>
<td>Library to query the bSDD API</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifc2ca</td>
<td>Utility to convert IFC structural analysis models to Code_Aster</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifc4d</td>
<td>Convert to and from IFC and project management software</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifc5d</td>
<td>Report and optimise cost information from IFC</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcbimtester</td>
<td>Wrapper for Gherkin based unit testing for IFC models</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcblender</td>
<td>Historic Blender IFC import add-on</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifccityjson</td>
<td>Convert CityJSON to IFC</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcclash</td>
<td>Clash detection library and CLI app</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifccobie</td>
<td>Extract IFC data for COBie handover requirements</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcconvert</td>
<td>CLI app to convert IFC to many other formats</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifccsv</td>
<td>Library and CLI app to export and import schedules from IFC</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcdiff</td>
<td>Compare changes between IFC models</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcfm</td>
<td>Extract IFC data for FM handover requirements</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcgeom</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcgeom_schema_agnostic</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcgeomserver</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcjni</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcmax</td>
<td>Historic extension for IFC support in 3DS Max</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcopenshell-python</td>
<td>Python library for IFC manipulation</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcparse</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>ifcpatch</td>
<td>Utility to run pre-packaged scripts to manipulate IFCs</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcsverchok</td>
<td>Blender Add-on for visual node programming with IFC</td>
<td>GPL-3.0-or-later</td>
</tr>
<tr>
<td>ifctester</td>
<td>Library, CLI and webapp for IDS model auditing</td>
<td>LGPL-3.0-or-later</td>
</tr>
<tr>
<td>ifcwrap</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>qtviewer</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
<tr>
<td>serializers</td>
<td>Internal library for IfcOpenShell</td>
<td>LGPL-3.0-or-later*</td>
</tr>
</tbody>
</table>
[LGPL]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/COPYING.LESSER "LGPL-3.0-or-later"
[IFC]: https://technical.buildingsmart.org/standards/ifc/ "IFC"
[IFC2x3 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/ "IFC2x3 TC1"
[IFC4 Add2 TC1]: https://standards.buildingsmart.org/IFC/RELEASE/IFC4/ADD2_TC1/HTML/ "IFC4 Add2 TC1"
[Visual Studio]: https://www.visualstudio.com/ "Visual Studio"
[Visual C++ Build Tools]: http://landinghub.visualstudio.com/visual-cpp-build-tools "Visual C++ Build Tools"
[MSYS2]: https://msys2.github.io/ "MSYS2"
[win/readme.md]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/win/readme.md "win/readme.md"
[nix/build-all.py]: https://github.com/IfcOpenShell/IfcOpenShell/tree/master/nix/build-all.py "nix/build-all.py"
IfcOpenShell is an open source (LGPL) software library for
working with the Industry Foundation Classes (IFC) file format.
doc_url: https://ifcopenshell.org/
dev_url: https://github.com/IfcOpenShell/IfcOpenShell
extra:
recipe-maintainers:
- adrianinsaval
- looooo
- Krande
+7 -79
View File
@@ -51,9 +51,7 @@
###############################################################################
import logging
import os
import re
import sys
import glob
import subprocess as sp
import shutil
import tarfile
@@ -81,7 +79,7 @@ ADD_COMMIT_SHA = os.getenv("ADD_COMMIT_SHA")
PYTHON_VERSIONS = ["3.9.11", "3.10.3", "3.11.8", "3.12.1"]
JSON_VERSION = "v3.6.1"
OCE_VERSION = "0.18.3"
OCCT_VERSION = "7.7.1"
OCCT_VERSION = "7.5.3"
BOOST_VERSION = "1.80.0"
PCRE_VERSION = "8.41"
LIBXML2_VERSION = "2.9.11"
@@ -92,8 +90,6 @@ HDF5_VERSION = "1.12.1"
GMP_VERSION = "6.2.1"
MPFR_VERSION = "3.1.6" # latest is 4.1.0
CGAL_VERSION = "5.3"
USD_VERSION = "23.05"
TBB_VERSION = "2021.9.0"
# binaries
cp = "cp"
@@ -190,7 +186,7 @@ cecho(""" - How many compiler processes may be run in parallel.
dependency_tree = {
'IfcParse': ('boost', 'libxml2', 'hdf5'),
'IfcGeom': ('IfcParse', 'occ', 'json', 'cgal', 'eigen'),
'IfcGeom': ('IfcParse', 'occ', 'json', 'cgal'),
'IfcConvert': ('IfcGeom',),
'OpenCOLLADA': ('libxml2', 'pcre'),
'IfcGeomServer': ('IfcGeom',),
@@ -204,9 +200,7 @@ dependency_tree = {
'json': (),
'hdf5': (),
'cgal': (),
'eigen': (),
'freetype': (),
# 'usd': ('boost', 'oneTBB')
}
def v(dep):
@@ -473,8 +467,6 @@ if "wasm" in flags:
# If the linker supports GC sections, set it up to reduce binary file size
# -fPIC is required for the shared libraries to work
compiler_flags = "CFLAGS", "CXXFLAGS", "LDFLAGS"
CXXFLAGS = os.environ.get("CXXFLAGS", "")
CFLAGS = os.environ.get("CFLAGS", "")
LDFLAGS = os.environ.get("LDFLAGS", "")
@@ -500,11 +492,7 @@ else:
CXXFLAGS=CXXFLAGS_MINIMAL
CFLAGS=CFLAGS_MINIMAL
LDFLAGS = f"{LDFLAGS} {ADDITIONAL_ARGS_STR}"
if "lto" in flags:
for f in compiler_flags:
locals()[f] += f" -flto={IFCOS_NUM_BUILD_PROCS}"
os.environ["CXXFLAGS"] = CXXFLAGS
os.environ["CFLAGS"] = CFLAGS
os.environ["LDFLAGS"] = LDFLAGS
@@ -514,11 +502,6 @@ os.environ["LDFLAGS"] = LDFLAGS
# build_dependency(name="cmake-%s" % (CMAKE_VERSION,), mode="autoconf", build_tool_args=[], download_url="https://cmake.org/files/v%s" % (CMAKE_VERSION_2,), download_name="cmake-%s.tar.gz" % (CMAKE_VERSION,))
if 'hdf5' in targets:
# not supported
orig = [os.environ[f] for f in compiler_flags]
for f in compiler_flags:
os.environ[f] = re.sub("-flto(=\w+)?", "", os.environ[f])
HDF5_MAJOR = ".".join(HDF5_VERSION.split(".")[:-1])
build_dependency(
name=f"hdf5-{HDF5_VERSION}",
@@ -529,10 +512,6 @@ if 'hdf5' in targets:
ctest_result=f"HDF5-{HDF5_VERSION}-{platform.system()}",
ctest_result_path=f"HDF_Group/HDF5/{HDF5_VERSION}"
)
for f, o in zip(compiler_flags, orig):
os.environ[f] = o
if "json" in targets:
json_url = f"https://github.com/nlohmann/json/releases/download/{JSON_VERSION}/json.hpp"
@@ -541,9 +520,6 @@ if "json" in targets:
os.makedirs(os.path.dirname(json_install_path))
if not os.path.exists(json_install_path):
urlretrieve(json_url, json_install_path)
if "eigen" in targets:
git_clone_or_pull_repository("https://gitlab.com/libeigen/eigen.git", f"{DEPS_DIR}/install/eigen-3.3.9", revision="3.3.9")
if "pcre" in targets:
build_dependency(
@@ -577,16 +553,12 @@ if "freetype" in targets:
download_url = "https://github.com/freetype/freetype",
download_name = "freetype2",
download_tool=download_tool_git,
revision="VER-2-11-1"
)
if USE_OCCT and "occ" in targets:
patches = []
if OCCT_VERSION < "7.4":
patches.append("./patches/occt/enable-exception-handling.patch")
if OCCT_VERSION == "7.7.1":
patches.append("./patches/occt/no_ExpToCasExe.patch")
if "wasm" in flags:
patches.append("./patches/occt/no_em_js.patch")
@@ -601,7 +573,7 @@ if USE_OCCT and "occ" in targets:
"-DBUILD_RELEASE_DISABLE_EXCEPTIONS=Off",
f"-D3RDPARTY_FREETYPE_DIR={DEPS_DIR}/install/freetype"
],
download_url = "https://git.dev.opencascade.org/repos/occt.git",
download_url = "https://github.com/Open-Cascade-SAS/OCCT",
download_name = "occt",
download_tool=download_tool_git,
patch=patches,
@@ -775,42 +747,7 @@ if "cgal" in targets:
download_tool=download_tool_git,
revision=f"v{CGAL_VERSION}"
)
if "usd" in targets:
build_dependency(
name=f"oneTBB-{TBB_VERSION}",
mode="cmake",
build_tool_args=[
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/tbb-{TBB_VERSION}",
f"-DTBB_TEST=OFF"
],
download_url="https://github.com/oneapi-src/oneTBB",
download_name="oneTBB",
download_tool=download_tool_git,
revision=f"v{TBB_VERSION}"
)
build_dependency(
name=f"usd-{USD_VERSION}",
mode="cmake",
build_tool_args=[
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/usd-{USD_VERSION}",
f"-DBOOST_ROOT={DEPS_DIR}/install/boost-{BOOST_VERSION}",
f"-DTBB_ROOT_DIR={DEPS_DIR}/install/tbb-{TBB_VERSION}",
f"-DPXR_ENABLE_PYTHON_SUPPORT=FALSE",
f"-DPXR_ENABLE_GL_SUPPORT=FALSE",
f"-DPXR_BUILD_IMAGING=FALSE",
f"-DPXR_BUILD_TUTORIALS=FALSE",
f"-DPXR_BUILD_EXAMPLES=FALSE",
f"-DPXR_BUILD_USD_TOOLS=FALSE",
f"-DPXR_BUILD_TESTS=FALSE"
],
download_url="https://github.com/PixarAnimationStudios/USD",
download_name="USD",
download_tool=download_tool_git,
revision=f"v{USD_VERSION}"
)
cecho("Building IfcOpenShell:", GREEN)
IFCOS_DIR = os.path.join(DEPS_DIR, "build", "ifcopenshell")
@@ -830,10 +767,8 @@ cmake_args = [
"-DBOOST_ROOT=" f"{DEPS_DIR}/install/boost-{BOOST_VERSION}",
"-DGLTF_SUPPORT=" "ON",
"-DJSON_INCLUDE_DIR=" f"{DEPS_DIR}/install/json",
"-DEIGEN_DIR=" f"{DEPS_DIR}/install/eigen-3.3.9",
"-DBoost_NO_BOOST_CMAKE=" "On",
"-DADD_COMMIT_SHA=" +("On" if ADD_COMMIT_SHA else "Off"),
"-DVERSION_OVERRIDE=" +("On" if ADD_COMMIT_SHA else "Off")
"-DADD_COMMIT_SHA=" +("On" if ADD_COMMIT_SHA else "Off")
]
if "wasm" in flags:
@@ -895,13 +830,6 @@ if "hdf5" in targets:
else:
cmake_args.append("-DHDF5_SUPPORT=Off")
if "usd" in targets:
cmake_args.extend([
"-DUSD_SUPPORT=" "On",
"-DUSD_INCLUDE_DIR=" f"{DEPS_DIR}/install/usd-{USD_VERSION}/include",
"-DUSD_LIBRARY_DIR=" f"{DEPS_DIR}/install/usd-{USD_VERSION}/lib"
])
if not explicit_targets or {"IfcGeom", "IfcConvert", "IfcGeomServer"} & set(explicit_targets):
logger.info("\rConfiguring executables...")
@@ -972,7 +900,7 @@ if "IfcOpenShell-Python" in targets:
if platform.system() != "Darwin":
if BUILD_CFG == "Release":
# TODO: This symbol name depends on the Python version?
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", glob.glob(os.path.join(module_dir, "_ifcopenshell_wrapper*.so"))[0]], cwd=module_dir)
run([strip, "-s", "-K", "PyInit__ifcopenshell_wrapper", "_ifcopenshell_wrapper.so"], cwd=module_dir)
return module_dir
-13
View File
@@ -1,13 +0,0 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fd17283f77..6cecf9dad3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -826,6 +826,8 @@ if (EMSCRIPTEN)
list (REMOVE_ITEM BUILD_TOOLKITS ExpToCasExe)
endif()
+list (REMOVE_ITEM BUILD_TOOLKITS ExpToCasExe)
+
# bison
if (BUILD_YACCLEX)
OCCT_INCLUDE_CMAKE_FILE ("adm/cmake/bison")
+1 -1
View File
@@ -1,6 +1,6 @@
package:
name: ifcopenshell
version: 0.8.0
version: 0.7.0
source:
path: IfcOpenShell
+1 -1
View File
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages
setup(name='IfcOpenShell',
version='0.8.0',
version='0.7.0',
description='IfcOpenShell is an open source (LGPL) software library for working with the Industry Foundation Classes (IFC) file format.',
author='Thomas Krijnen',
author_email='thomas@aecgeeks.com',
+1 -5
View File
@@ -1,6 +1,2 @@
[tool.black]
line-length = 120
[tool.pyright]
reportInvalidTypeForm = false
disableBytesTypePromotions = true
line-length = 120
+1 -1
View File
@@ -10,7 +10,7 @@ type: software
authors:
- name: "IfcOpenShell contributors"
repository-code: >-
https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.8.0/src/bcf
https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.7.0/src/bcf
abstract: >-
Library to read and write BCF-XML and query OpenCDE
BCF-API modules
+4 -26
View File
@@ -1,22 +1,4 @@
# BCF - BCF Python library
# Copyright (C) 2021 Prabhat Singh <singh01prabhat@gmail.com>
#
# This file is part of BCF.
#
# BCF is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BCF is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
VERSION:=$(shell cat ../../VERSION)
VERSION:=`date '+%y%m%d'`
SED:=sed -i
ifeq ($(UNAME_S),Darwin)
SED:=sed -i '' -e
@@ -39,14 +21,10 @@ models:
.PHONY: dist
dist:
rm -rf dist
cp pyproject.toml pyproject.toml.bak
cp src/bcf/__init__.py __init__.py.bak
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' pyproject.toml
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' src/bcf/__init__.py
$(SED) "s/999999/$(VERSION)/" pyproject.toml
python -m build
mv pyproject.toml.bak pyproject.toml
mv __init__.py.bak src/bcf/__init__.py
$(SED) "s/$(VERSION)/999999/" pyproject.toml
# .PHONY
# api:
# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0
# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0
+2 -2
View File
@@ -17,7 +17,7 @@ dependencies = [
"numpy",
"ifcopenshell",
]
version = "0.0.0"
version = "0.0.999999"
classifiers = [
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent",
@@ -138,4 +138,4 @@ max-attributes = 10
[tool.pylint.format]
expected-line-ending-format = "LF"
max-line-length = 120
max-line-length = 120
-2
View File
@@ -15,5 +15,3 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with BCF. If not, see <http://www.gnu.org/licenses/>.
__version__ = version = "0.0.0"
+1 -1
View File
@@ -10,7 +10,7 @@ type: software
authors:
- name: "IfcOpenShell contributors"
repository-code: >-
https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.8.0/src/blenderbim
https://github.com/IfcOpenShell/IfcOpenShell/tree/v0.7.0/src/blenderbim
url: 'https://blenderbim.org/'
repository-artifact: 'https://blenderbim.org/download.html'
abstract: >-
+38 -62
View File
@@ -16,8 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
PYTHON:=python3.11
PIP:=pip3.11
PYTHON:=python3.10
PIP:=pip3.10
PATCH:=patch
SED:=sed -i
ifeq ($(OS),Windows_NT)
@@ -35,12 +35,7 @@ SED:=sed -i '' -e
endif
endif
IS_STABLE:=FALSE
VERSION:=$(shell cat ../../VERSION)
VERSION_MAJOR:=$(shell cat '../../VERSION' | cut -d '.' -f 1)
VERSION_MINOR:=$(shell cat '../../VERSION' | cut -d '.' -f 2)
VERSION_PATCH:=$(shell cat '../../VERSION' | cut -d '.' -f 3)
VERSION_DATE:=$(shell date '+%y%m%d')
VERSION:=`date '+%y%m%d'`
LAST_COMMIT_HASH:=$(shell git rev-parse HEAD)
PYVERSION:=py310
PYPI_IMP:=cp
@@ -82,13 +77,12 @@ ifeq ($(PLATFORM), win)
PYPI_PLATFORM:=--platform win_amd64
endif
# Current build commit hash.
OLD:=c18e4ea
.PHONY: bump
bump:
cd . && $(SED) -b "s/$(OLD)/$(NEW)/" Makefile
cd ../ifcopenshell-python/ && $(SED) -b "s/$(OLD)/$(NEW)/" Makefile
cd ../ifcopenshell-python/docs/ifcconvert/ && $(SED) -b "s/$(OLD)/$(NEW)/" installation.rst
cd . && $(SED) "s/$(OLD)/$(NEW)/" Makefile
cd ../ifcopenshell-python/ && $(SED) "s/$(OLD)/$(NEW)/" Makefile
cd ../ifcopenshell-python/docs/ifcconvert/ && $(SED) "s/$(OLD)/$(NEW)/" installation.rst
cd ../ifcopenshell-python/docs/ifcopenshell-python/ && $(SED) "s/$(OLD)/$(NEW)/" installation.rst
.PHONY: dist
dist:
@@ -101,52 +95,54 @@ endif
cp -r blenderbim/* dist/blenderbim/
# Provides IfcOpenShell Python functionality
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.9-${OLD}-$(PLATFORM)64.zip
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-c7830e9-$(PLATFORM)64.zip
cd dist/working && unzip ifcopenshell-python*
cp -r dist/working/ifcopenshell dist/blenderbim/libs/site/packages/
# See bug #812
cd dist/working && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/blenderbim/occ_utils.py
cd dist/working && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.7.0/src/blenderbim/occ_utils.py
cd dist/working && mv occ_utils.py ../blenderbim/libs/site/packages/ifcopenshell/geom/occ_utils.py
rm -rf dist/working
# Provides dependencies that are part of IfcOpenShell
mkdir dist/working
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/archive/refs/heads/v0.8.0.zip
cd dist/working && unzip v0.8.0.zip
# IfcOpenBot sometimes lags behind, so we only use its binaries
mv dist/blenderbim/libs/site/packages/ifcopenshell/*ifcopenshell_wrapper* dist/working/
rm -rf dist/blenderbim/libs/site/packages/ifcopenshell
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcopenshell-python/ifcopenshell dist/blenderbim/libs/site/packages/
mv dist/working/*ifcopenshell_wrapper* dist/blenderbim/libs/site/packages/ifcopenshell/
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/archive/v0.7.0.zip
cd dist/working && unzip v0.7.0.zip
# IfcOpenBot sometimes lags behind, so we hotfix the Python utilities
rm -rf dist/blenderbim/libs/site/packages/ifcopenshell/util/
rm -rf dist/blenderbim/libs/site/packages/ifcopenshell/api/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcopenshell-python/ifcopenshell/util dist/blenderbim/libs/site/packages/ifcopenshell/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcopenshell-python/ifcopenshell/api dist/blenderbim/libs/site/packages/ifcopenshell/
cp dist/working/IfcOpenShell-0.7.0/src/ifcopenshell-python/ifcopenshell/*.py dist/blenderbim/libs/site/packages/ifcopenshell/
cp dist/working/IfcOpenShell-0.7.0/src/ifcopenshell-python/ifcopenshell/express/rule_executor.py dist/blenderbim/libs/site/packages/ifcopenshell/express/
# Provides bcf functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/bcf/src/bcf dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/bcf/src/bcf dist/blenderbim/libs/site/packages/
# Provides IFCClash functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcclash/ifcclash dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcclash/ifcclash dist/blenderbim/libs/site/packages/
# Provides BIMTester functionality
cd dist/working && $(PYTHON) -m venv env
cd dist/working && . env/bin/activate && $(PIP) install pybabel
cd dist/working && . env/bin/activate && $(PIP) install babel
cd dist/working && . env/bin/activate && ./env/bin/pybabel compile -d ./IfcOpenShell-0.8.0/src/ifcbimtester/bimtester/locale/
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
cd dist/working && . env/bin/activate && ./env/bin/pybabel compile -d ./IfcOpenShell-0.7.0/src/ifcbimtester/bimtester/locale/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcbimtester/bimtester dist/blenderbim/libs/site/packages/
# Provides IFCTester functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifctester/ifctester dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifctester/ifctester dist/blenderbim/libs/site/packages/
# Provides IFCFM functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcfm/ifcfm dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcfm/ifcfm dist/blenderbim/libs/site/packages/
# Provides bSDD functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/bsdd/* dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/bsdd/* dist/blenderbim/libs/site/packages/
# Provides IFCDiff functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcdiff/* dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcdiff/* dist/blenderbim/libs/site/packages/
# Provides IFCCSV functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifccsv/* dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifccsv/* dist/blenderbim/libs/site/packages/
# Provides IFCPatch functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcpatch/ifcpatch dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifcpatch/ifcpatch dist/blenderbim/libs/site/packages/
# Provides IFC4D functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifc4d/ifc4d dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifc4d/ifc4d dist/blenderbim/libs/site/packages/
# Provides IFC5D functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifc5d/ifc5d dist/blenderbim/libs/site/packages/
# Provides IFCCityJSON functionality
cp -r dist/working/IfcOpenShell-0.8.0/src/ifccityjson dist/blenderbim/libs/site/packages/
cp -r dist/working/IfcOpenShell-0.7.0/src/ifccityjson dist/blenderbim/libs/site/packages/
# Provides IfcGit functionality
cd dist/working && . env/bin/activate && $(PIP) install GitPython --target=./site-packages
cp -r dist/working/site-packages/smmap dist/blenderbim/libs/site/packages/
@@ -171,8 +167,6 @@ endif
mkdir dist/working
cd dist/working && $(PYTHON) -m venv env
cd dist/working && mkdir site-packages
# IfcOpenShell dependency - support for new typing features
cd dist/working && . env/bin/activate && $(PIP) install typing_extensions --target=./site-packages
# Required by IfcCSV
cd dist/working && . env/bin/activate && $(PIP) install pandas $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
# Pandas ships with very heavy tests
@@ -214,18 +208,6 @@ endif
cd dist/working && . env/bin/activate && $(PIP) install lark --target=./site-packages
# Required by IFC4D
cd dist/working && . env/bin/activate && $(PIP) install PyP6Xer --target=./site-packages
# Required by web module
cd dist/working && . env/bin/activate && $(PIP) install python-socketio[asyncio_client] --target=./site-packages
cd dist/working && . env/bin/activate && $(PIP) install aiohttp --target=./site-packages
# Required by light module
ifeq ($(PLATFORM), linux)
# See https://github.com/LBNL-ETA/pyradiance/issues/34
cd dist/working && . env/bin/activate && $(PIP) install pyradiance --platform manylinux1_x86_64 --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
else ifneq ($(PLATFORM), macos)
# No support for MacOS Intel from upstream. Too bad :(
cd dist/working && . env/bin/activate && $(PIP) install pyradiance $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
endif
cp -r dist/working/site-packages/* dist/blenderbim/libs/site/packages/
rm -rf dist/working
@@ -235,12 +217,12 @@ endif
cd dist/working && tar -xzvf behave*
cd dist/working/behave-1.2.6/ && cp -r behave ../../blenderbim/libs/site/packages/
# See bug #1294
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/ifcbimtester/patch/model_core.patch
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/ifcbimtester/patch/runner_util.patch
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.7.0/src/ifcbimtester/patch/model_core.patch
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.7.0/src/ifcbimtester/patch/runner_util.patch
cd dist/working/ && $(PATCH) ../blenderbim/libs/site/packages/behave/model_core.py < model_core.patch
cd dist/working/ && $(PATCH) ../blenderbim/libs/site/packages/behave/runner_util.py < runner_util.patch
# See bug #2159
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.8.0/src/ifcbimtester/patch/junit.patch
cd dist/working/ && wget https://raw.githubusercontent.com/IfcOpenShell/IfcOpenShell/v0.7.0/src/ifcbimtester/patch/junit.patch
cd dist/working/ && $(PATCH) ../blenderbim/libs/site/packages/behave/reporter/junit.py < junit.patch
rm -rf dist/working
@@ -275,7 +257,7 @@ endif
# Required by brickschema
# This is a bit of a dodgy one, it should be provided by setuptools which Blender doesn't ship.
mkdir dist/working
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/raw/v0.8.0/src/blenderbim/scripts/pkg_resources.tar.gz
cd dist/working && wget https://github.com/IfcOpenShell/IfcOpenShell/raw/v0.7.0/src/blenderbim/scripts/pkg_resources.tar.gz
cd dist/working && tar -xzvf pkg_resources*
cd dist/working/ && cp -r pkg_resources ../blenderbim/libs/site/packages/
rm -rf dist/working
@@ -299,16 +281,10 @@ endif
rm -rf dist/blenderbim/libs/site/packages/numpy
rm -rf dist/blenderbim/libs/site/packages/numpy.libs
ifeq ($(IS_STABLE), TRUE)
cd dist/blenderbim && $(SED) "s/0, 0, 0/$(VERSION_MAJOR), $(VERSION_MINOR), $(VERSION_PATCH)/" __init__.py
cd dist/blenderbim && $(SED) "s/0.0.0/$(VERSION)/" blender_manifest.toml
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
else
cd dist/blenderbim && $(SED) "s/0, 0, 0/$(VERSION_MAJOR), $(VERSION_MINOR), $(VERSION_PATCH), $(VERSION_DATE)/" __init__.py
cd dist/blenderbim && $(SED) "s/0.0.0/$(VERSION).$(VERSION_DATE)/" blender_manifest.toml
cd dist/blenderbim && $(SED) "s/999999/$(VERSION)/" __init__.py
cd dist/blenderbim && $(SED) "s/999999/$(VERSION)/" blender_manifest.toml
cd dist/blenderbim/bim && $(SED) "s/8888888/$(LAST_COMMIT_HASH)/" __init__.py
cd dist && zip -r blenderbim-$(VERSION).$(VERSION_DATE)-$(PYVERSION)-$(PLATFORM).zip ./*
endif
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
rm -rf dist/blenderbim
.PHONY: test
+4 -16
View File
@@ -27,20 +27,19 @@ import sys
IN_BLENDER = sys.modules.get("bpy", None)
if IN_BLENDER:
import bpy
import addon_utils
import platform
import traceback
import subprocess
import webbrowser
import addon_utils
from collections import deque
# NOTE: bl_info is superseded by blender_manifest.toml
# if addon is installed as an extension (Blender 4.2+)
bl_info = {
"name": "BlenderBIM",
"description": "Transforms Blender into a native Building Information Model authoring platform using IFC.",
"author": "IfcOpenShell Contributors",
"blender": (3, 1, 0),
"version": (0, 0, 0),
"version": (0, 0, 999999),
"location": "File Menu, Scene Properties Tab. See documentation for more.",
"doc_url": "https://docs.blenderbim.org/",
"tracker_url": "https://github.com/IfcOpenShell/IfcOpenShell/issues",
@@ -94,6 +93,7 @@ if IN_BLENDER:
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), "libs", "site", "packages"))
try:
import blenderbim.bim
import ifcopenshell.api
def log_api(usecase_path, ifc_file, settings):
@@ -108,21 +108,9 @@ if IN_BLENDER:
ifcopenshell.api.add_pre_listener("*", "action_logger", log_api)
def register():
global BLENDER_PACKAGE_NAME, __name__, __package__
BLENDER_PACKAGE_NAME = __name__
if bpy.app.version >= (4, 2, 0):
sys.modules["blenderbim"] = sys.modules[__name__]
__name__ = "blenderbim"
# Only renaming __name__ is actually required to make imports work.
# We renaming __package__ just for consistency.
__package__ = "blenderbim"
import blenderbim.bim
blenderbim.bim.register()
def unregister():
import blenderbim.bim
blenderbim.bim.unregister()
except:
+5 -3
View File
@@ -84,8 +84,6 @@ modules = {
"debug": None,
"ifcgit": None,
"covering": None,
"web": None,
"light": None,
# Uncomment this line to enable loading of the demo module. Happy hacking!
# The name "demo" must correlate to a folder name in `bim/module/`.
# "demo": None,
@@ -132,6 +130,7 @@ classes = [
prop.GlobalId,
prop.BIMObjectProperties,
prop.BIMCollectionProperties,
prop.BIMMaterialProperties,
prop.BIMMeshProperties,
prop.BIMFacet,
prop.BIMFilterGroup,
@@ -142,7 +141,6 @@ classes = [
# Tabs panel
ui.BIM_PT_tabs,
# Project overview
ui.BIM_PT_tab_new_project_wizard,
ui.BIM_PT_tab_project_info,
ui.BIM_PT_tab_spatial_decomposition,
ui.BIM_PT_tab_project_setup,
@@ -225,6 +223,8 @@ def register():
bpy.types.Screen.BIMTabProperties = bpy.props.PointerProperty(type=prop.BIMTabProperties)
bpy.types.Collection.BIMCollectionProperties = bpy.props.PointerProperty(type=prop.BIMCollectionProperties)
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
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)
@@ -283,6 +283,8 @@ def unregister():
del bpy.types.Scene.BIMProperties
del bpy.types.Collection.BIMCollectionProperties
del bpy.types.Object.BIMObjectProperties
del bpy.types.Material.BIMObjectProperties
del bpy.types.Material.BIMMaterialProperties
del bpy.types.Mesh.BIMMeshProperties
del bpy.types.Curve.BIMMeshProperties
del bpy.types.Camera.BIMMeshProperties
@@ -67,11 +67,11 @@ DATA;
#60=IFCMATERIALPROFILESET($,$,(#62),$);
#61=IFCRELASSOCIATESMATERIAL('09FXUZCnrFEffxBrtg16gx',$,$,$,(#59),#60);
#62=IFCMATERIALPROFILE($,$,#20,#58,$,$);
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR200',$,$,$,$,$,$,.NOTDEFINED.);
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.);
#64=IFCMATERIALLAYERSET((#66),$,$);
#65=IFCRELASSOCIATESMATERIAL('0jzkXlkBL4HhmQ_FTWW6Cj',$,$,$,(#63),#64);
#66=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR300',$,$,$,$,$,$,.NOTDEFINED.);
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.);
#68=IFCMATERIALLAYERSET((#70),$,$);
#69=IFCRELASSOCIATESMATERIAL('3a6kjEM29DleYTlSkA8_DK',$,$,$,(#67),#68);
#70=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$);
@@ -67,11 +67,11 @@ DATA;
#60=IFCMATERIALPROFILESET($,$,(#62),$);
#61=IFCRELASSOCIATESMATERIAL('09FXUZCnrFEffxBrtg16gx',$,$,$,(#59),#60);
#62=IFCMATERIALPROFILE($,$,#20,#58,$,$);
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR200',$,$,$,$,$,$,.NOTDEFINED.);
#63=IFCSLABTYPE('1Akbal7tP5DAPW0ti$Qp30',$,'FLR150',$,$,$,$,$,$,.NOTDEFINED.);
#64=IFCMATERIALLAYERSET((#66),$,$);
#65=IFCRELASSOCIATESMATERIAL('0jzkXlkBL4HhmQ_FTWW6Cj',$,$,$,(#63),#64);
#66=IFCMATERIALLAYER(#20,0.2,$,$,$,$,$);
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR300',$,$,$,$,$,$,.NOTDEFINED.);
#67=IFCSLABTYPE('0$gpYNi3T08BrxaR67CxgI',$,'FLR250',$,$,$,$,$,$,.NOTDEFINED.);
#68=IFCMATERIALLAYERSET((#70),$,$);
#69=IFCRELASSOCIATESMATERIAL('3a6kjEM29DleYTlSkA8_DK',$,$,$,(#67),#68);
#70=IFCMATERIALLAYER(#20,0.3,$,$,$,$,$);
@@ -1,122 +0,0 @@
import argparse
from aiohttp import web
import socketio
import pystache
import json
sio_port = 8080 # default port
sio = socketio.AsyncServer(
cors_allowed_origins="*",
async_mode="aiohttp",
)
# sio.instrument(
# auth={
# "username": "admin",
# "password": "admin",
# }
# )
app = web.Application()
sio.attach(app)
blender_messages = {}
# Web namespace
class WebNamespace(socketio.AsyncNamespace):
def __init__(self, namespace):
super().__init__(namespace)
async def on_connect(self, sid, environ):
print(f"Web client connected: {sid}")
async def on_disconnect(self, sid):
print(f"Web client disconnected: {sid}")
async def on_web_operator(self, sid, data):
await sio.emit(
"web_operator",
data,
namespace="/blender",
room=data["blenderId"],
)
# Blender namespace
class BlenderNamespace(socketio.AsyncNamespace):
def __init__(self, namespace):
super().__init__(namespace)
async def on_connect(self, sid, environ):
print(f"Blender client connected: {sid}")
# Notify web client about new connection
blender_messages[sid] = {}
await sio.emit("blender_connect", sid, namespace="/web")
async def on_disconnect(self, sid):
print(f"Blender client disconnected: {sid}")
# Remove client message and notify web client about disconnection
if sid in blender_messages:
del blender_messages[sid]
await sio.emit("blender_disconnect", sid, namespace="/web")
async def on_data(self, sid, data):
print(f"Data from Blender client {sid}")
# blender_messages[sid]["default_data"] = data
# await sio.emit("default_data", {"blenderId": sid, "data": data}, namespace="/web")
async def on_csv_data(self, sid, data):
print(f"CSV data from Blender client {sid}")
# Store the message and forward it to the web client
blender_messages[sid]["csv_data"] = data
await sio.emit("csv_data", {"blenderId": sid, "data": data}, namespace="/web")
async def on_gantt_data(self, sid, data):
print(f"Gant Chart data from Blender client {sid}")
blender_messages[sid]["gantt_data"] = data
await sio.emit("gantt_data", {"blenderId": sid, "data": data}, namespace="/web")
# Attach namespaces
sio.register_namespace(WebNamespace("/web"))
sio.register_namespace(BlenderNamespace("/blender"))
# Define a route to render the index.html template
async def index(request):
with open("templates/index.html", "r") as f:
template = f.read()
html_content = pystache.render(template, {"port": sio_port})
return web.Response(text=html_content, content_type="text/html")
async def gantt(request):
with open("templates/gantt.html", "r") as f:
template = f.read()
html_content = pystache.render(template, {"port": sio_port})
return web.Response(text=html_content, content_type="text/html")
app.router.add_get("/", index)
app.router.add_get("/gantt", gantt)
app.router.add_static("/jsgantt/", path="../gantt", name="jsgantt")
app.router.add_static("/static/", path="./static", name="static")
def main():
global sio_port
parser = argparse.ArgumentParser(description="SocketIO server")
parser.add_argument("--host", type=str, default="127.0.0.1", help="Host to run the server on")
parser.add_argument("--port", type=int, default=8080, help="Port to run the server on")
args = parser.parse_args()
sio_port = args.port
web.run_app(app, host=args.host, port=sio_port)
if __name__ == "__main__":
main()
# web.run_app(app, host="127.0.0.1", port=sio_port)
@@ -1,280 +0,0 @@
:root {
color-scheme: dark;
}
body {
background-color: #252525;
color: #e0e0e0;
margin: 0;
font-family: Arial, sans-serif;
}
#container {
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
margin-bottom: 20px;
}
h3 {
margin-top: 0;
}
nav {
background-color: #121212;
padding: 1em 0;
display: flex;
align-items: center;
position: relative;
}
nav .logo {
margin-left: 40px;
height: 40px;
/* Adjust height as needed */
}
nav ul {
list-style-type: none;
margin: 0;
margin-left: 1px;
display: flex;
flex-grow: 1;
justify-content: center;
}
nav ul li {
margin-right: 50px;
}
nav ul li a {
text-decoration: none;
color: #fff;
font-size: 1.2em;
}
nav ul li a:hover,
nav ul li a.active {
color: #3fb449;
}
nav .bottom-bar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background-color: #25682a;
}
.table-description {
margin-bottom: 1rem;
width: 50%;
background-color: transparent;
border-collapse: collapse;
border-spacing: 0;
border-color: #464444;
border: 1px solid #464444;
border-radius: 0.25rem;
box-shadow: 0 0 0.7rem rgba(95, 95, 95, 0.4);
text-align: center;
}
.table-description tr {
display: table-row;
border-bottom: 1px solid #464444;
}
.gantt-info {
margin: 0.5rem;
font-size: 1rem;
font-weight: bold;
}
.btn {
margin: 0.5rem;
font-size: 1rem;
cursor: pointer;
}
@media print {
.no-print {
display: none;
}
}
/* ------------ Overwriting JSGantt CSS rules ------------ */
div.gantt {
background-color: #252525;
color: #c7c7c7;
}
.gantt table {
border-color: #464444;
;
}
.gantt td {
border-color: #464444;
;
}
/* Headings and cell defaults */
.gmajorheading,
.gminorheading,
.gminorheadingwkend,
.gtaskcell,
.gtaskcellcurrent,
.gtaskcellwkend,
.gname,
.ggroupitem,
.gtaskheading {
background-color: #252525;
border-color: #464444;
;
}
.gtaskheading,
.gname,
.gtaskname,
.gres,
.gdur,
.gcomp,
.gstartdate,
.gplanstartdate,
.gplanenddate,
.gcost,
.gchartlbl,
.gcontainercol,
.genddate {
color: #c7c7c7;
border-color: #464444;
;
}
.gtaskname>div {
color: #c7c7c7;
}
.gtaskbarcontainer.gplan,
.gchartlbl.gcontainercol {
background: #252525;
border-color: #464444;
}
.gtaskname div,
.gtaskheading div,
.gtaskname span {
color: #c7c7c7;
}
.gtasklist,
.gadditional {
border: #464444 1px solid
}
.gchartgrid {
background-color: #252525;
}
.glistgrid,
.glistlbl {
background-color: #252525;
border-color: #464444;
;
}
/* .gTaskInfo {
background-color: #2e2e2e;
color: #c7c7c7;
border-color: #c7c7c7;;
} */
/* Dark mode scrollbar */
.frame::-webkit-scrollbar-thumb {
background-color: #252525;
}
.frame::-webkit-scrollbar-track {
background-color: #252525;
}
/* Highlight row */
.gitemhighlight td {
background-color: #009136;
color: #ffffff;
}
/* Differentiate Group, Milestone and Ordinary task items (applied to row) */
.ggroupitem {
background-color: #252525;
font-weight: bold;
border-color: #464444;
}
.gmileitem,
.glineitem {
background-color: #252525;
}
/* Task bar caption text styles */
.gmilecaption,
.ggroupcaption,
.gcaption {
color: #ffffff;
}
/* Task complete %age bar */
.gtaskcomplete {
background-color: #777777;
}
/* Milestones */
.gmdtop {
border-bottom: 5px solid #ffffff;
}
.gmdbottom {
border-top: 5px solid #ffffff;
}
.gfoldercollapse {
color: #c7c7c7;
cursor: pointer;
font-weight: bold;
font-size: 12px;
font-family: Courier, "Courier New", monospace;
}
/* Highlight for collapsible row */
.gname.ggroupitem {
background-color: rgb(75, 75, 75);
}
/* Form label and selected highlighting */
.gformlabel {
background-color: #2e2e2e;
color: #c7c7c7;
border: #4a4a4a 1px solid;
}
span.gformlabel:hover {
background-color: #3a3a3a;
border-color: #565656;
}
span.gselected {
background-color: #565656;
border-color: #777777;
color: #ffffff;
}
.gantt-inputtable {
background-color: #3b3b3b;
box-sizing: border-box;
border: 1px solid #000;
color: #c7c7c7;
}
@@ -1,76 +0,0 @@
:root {
color-scheme: dark;
}
body {
background-color: #252525;
color: #e0e0e0;
margin: 0;
font-family: Arial, sans-serif;
}
#container {
margin-top: 20px;
margin-left: 10px;
margin-right: 10px;
margin-bottom: 20px
}
.table-container {
margin-bottom: 40px;
}
.csv-table {
margin-top: 10px;
}
h3 {
margin-top: 0;
}
nav {
background-color: #121212;
padding: 1em 0;
display: flex;
align-items: center;
position: relative;
}
nav .logo {
margin-left: 40px;
height: 40px;
/* Adjust height as needed */
}
nav ul {
list-style-type: none;
margin: 0;
margin-left: 1px;
display: flex;
flex-grow: 1;
justify-content: center;
}
nav ul li {
margin-right: 50px;
}
nav ul li a {
text-decoration: none;
color: #fff;
font-size: 1.2em;
}
nav ul li a:hover,
nav ul li a.active {
color: #3fb449;
}
nav .bottom-bar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 2px;
background-color: #25682a;
}
@@ -1,339 +0,0 @@
// keeps track of blenders connected in form of
// shown:bool, workSchedule: {}, ganttTasks: {},
const connectedClients = {};
let socket;
// print options
const pageSizes = [
{ value: "210,297", text: "A4 Portrait" },
{ value: "297,210", text: "A4 Landscape" },
{ value: "297,420", text: "A3 Portrait" },
{ value: "420,297", text: "A3 Landscape" },
{ value: "420,594", text: "A2 Portrait" },
{ value: "594,420", text: "A2 Landscape" },
{ value: "594,841", text: "A1 Portrait" },
{ value: "841,594", text: "A1 Landscape" },
{ value: "841,1189", text: "A0 Portrait" },
{ value: "1189,841", text: "A0 Landscape" },
];
// Document ready function
$(document).ready(function () {
connectSocket();
});
// Function to connect to Socket.IO server
function connectSocket() {
const url = "ws://localhost:" + SOCKET_PORT + "/web";
socket = io(url);
console.log("socket: ", socket);
// Register socket event handlers
socket.on("blender_connect", handleBlenderConnect);
socket.on("blender_disconnect", handleBlenderDisconnect);
socket.on("gantt_data", handleGanttData);
}
// Function to handle 'blender_connect' event
function handleBlenderConnect(blenderId) {
console.log("blender_connect: ", blenderId);
if (!connectedClients.hasOwnProperty(blenderId)) {
connectedClients[blenderId] = {
shown: false,
workSchedule: {},
ganttTasks: {},
};
}
}
// Function to handle 'blender_disconnect' event
function handleBlenderDisconnect(blenderId) {
console.log("blender_disconnect: ", blenderId);
if (connectedClients.hasOwnProperty(blenderId)) {
delete connectedClients[blenderId];
removeGanttElement(blenderId);
}
}
// Function to handle 'gantt_data' event
function handleGanttData(data) {
const blenderId = data["blenderId"];
console.log(data);
const filename = data["data"]["IFC_File"];
const ganttTasks = data["data"]["gantt_data"]["tasks"];
const ganttWorkSched = data["data"]["gantt_data"]["work_schedule"];
// const ganttWorkSched = {};
if (connectedClients.hasOwnProperty(blenderId)) {
if (!connectedClients[blenderId].shown) {
connectedClients[blenderId] = {
shown: true,
ganttTasks: ganttTasks,
workSchedule: ganttWorkSched,
};
addGanttElement(blenderId, ganttTasks, ganttWorkSched, filename);
} else {
updateGanttElement(blenderId, ganttTasks, ganttWorkSched, filename);
connectedClients[blenderId].workSchedule = ganttWorkSched;
connectedClients[blenderId].ganttTasks = ganttTasks;
}
} else {
connectedClients[blenderId] = {
shown: true,
ganttTasks: ganttTasks,
workSchedule: ganttWorkSched,
};
addGanttElement(blenderId, ganttTasks, ganttWorkSched, filename);
}
}
// Function to add a new gantt with data and filename
function addGanttElement(blenderId, tasks, workSched, filename) {
const ganttContainer = $("<div></div>")
.addClass("gantt-container")
.attr("id", "container-" + blenderId);
const ganttTitle = $("<h3></h3>")
.attr("id", "title-" + blenderId)
.text(filename)
.addClass("no-print")
.css("margin-bottom", "10px");
const workSchedDiv = $("<div></div>").attr("id", "workSched" + blenderId);
const scheduleTable = $("<table></table>")
.addClass("no-print table-description")
.attr("id", "workSchedTable-" + blenderId)
.hide();
$.each(workSched, (key, value) => {
value = value ? value : "null";
$("<tr></tr>")
.append($("<td></td>").text(key))
.append($("<td></td>").text(value))
.appendTo(scheduleTable);
});
const toggleButton = $("<button></button>")
.text("Show Schedule Info")
.addClass("btn no-print")
.on("click", function () {
scheduleTable.toggle();
const buttonText = scheduleTable.is(":visible")
? "Hide Schedule Info"
: "Show Schedule Info";
toggleButton.text(buttonText);
});
var ganttInfoDiv = $("<div></div>")
.addClass("gantt-info")
.attr("id", "gantt-info-" + blenderId);
const scheduleName = $("<span></span>").text("Schedule: " + workSched.Name);
const createdOn = $("<span></span>")
.text("Created: " + new Date(workSched.CreationDate).toLocaleDateString())
.css("float", "right");
const ganttDiv = $("<div></div>")
.addClass("gantt-chart")
.attr("id", "gantt-" + blenderId);
ganttInfoDiv.append(scheduleName);
ganttInfoDiv.append(createdOn);
workSchedDiv.append(toggleButton);
workSchedDiv.append(scheduleTable);
ganttContainer.append(ganttTitle);
ganttContainer.append(workSchedDiv);
ganttContainer.append(ganttInfoDiv);
ganttContainer.append(ganttDiv);
$("#container").append(ganttContainer);
let g = new JSGantt.GanttChart($("#gantt-" + blenderId)[0], "week");
g.setOptions({
vCaptionType: "Caption", // Set to Show Caption : None,Caption,Resource,Duration,Complete,
vQuarterColWidth: 36,
vDateTaskDisplayFormat: "day dd month yyyy", // Shown in tool tip box
vDayMajorDateDisplayFormat: "mon yyyy - Week ww", // Set format to dates in the "Major" header of the "Day" view
vWeekMinorDateDisplayFormat: "dd mon", // Set format to display dates in the "Minor" header of the "Week" view
vLang: "en",
vShowTaskInfoLink: 1, // Show link in tool tip (0/1)
vShowEndWeekDate: 0, // Show/Hide the date for the last day of the week in header for daily
vUseSingleCell: 10000, // Set the threshold cell per table row (Helps performance for large data.
vFormatArr: ["Day", "Week", "Month", "Quarter"], // Even with setUseSingleCell using Hour format on such a large chart can cause issues in some browsers,
vShowRes: true, // Disable the resource column.
vShowComp: false, // Disable the completion column.
vShowDur: false, // Disable the duration column, because jsgantt doesn't calculate durations the way we want.
vAdditionalHeaders: {
ifcduration: { title: "Duration" },
resourceUsage: { title: "Resource Usage" },
},
vUseToolTip: true, // Disable tooltips.
vTooltipTemplate: generateTooltip,
vTotalHeight: 900,
vEventsChange: {
taskname: editValue, // if you need to use the this scope, do: editValue.bind(this)
res: editValue,
dur: editValue,
comp: editValue,
start: editValue,
end: editValue,
planstart: editValue,
planend: editValue,
cost: editValue,
additional_category: editValue,
},
});
JSGantt.addJSONTask(g, tasks);
g.setEditable(true);
g.Draw();
connectedClients[blenderId]["gantt"] = g;
let printButton = $("<button>", {
id: "print-btn-" + blenderId,
html: "Print",
class: "btn no-print",
});
let printOptions = $("<select>", {
id: "print-options-" + blenderId,
class: "no-print",
});
$.each(pageSizes, function (index, size) {
printOptions.append(
$("<option>", {
value: size.value,
text: size.text,
})
);
});
printButton.on("click", function () {
// make it only the corresponding gantt chart is printed
$(".gantt-chart").removeClass("no-print");
$(".gantt-chart")
.not("#gantt-" + blenderId)
.addClass("your-css-class");
var values = $("#print-options-" + blenderId)
.val()
.split(",");
g.setEditable(false);
g.setTotalHeight("");
g.Draw();
addEventListener("afterprint", (event) => {
g.setEditable(true);
},);
let css =
"@media print {\n" +
" @page {\n" +
" size: " +
values[0] +
"mm " +
values[1] +
"mm;\n" +
" }\n" +
" /* Make all text black */\n" +
" body, p, span, h1, h2, h3, h4, h5, h6, div, a, li, td, th, * {\n" +
" color: black !important;\n" +
" }\n" +
"}";
g.printChart(values[0], values[1], css);
g.setTotalHeight(900);
g.Draw();
});
ganttContainer.append(printOptions);
ganttContainer.append(printButton);
}
// Function to update gantt and filename
function updateGanttElement(blenderId, tasks, workSched, filename) {
// update work schedule table
const table = $("#workSchedTable-" + blenderId);
table.empty();
$.each(workSched, (key, value) => {
value = value ? value : "null";
$("<tr></tr>")
.append($("<td></td>").text(key))
.append($("<td></td>").text(value))
.appendTo(table);
});
// update gantt chart with new data
let g = connectedClients[blenderId]["gantt"];
g.ClearTasks();
g.Draw();
JSGantt.addJSONTask(g, tasks);
g.Draw();
$("#title-" + blenderId).text(filename);
}
// Function to remove gantt element
function removeGanttElement(blenderId) {
$("#container-" + blenderId).remove();
}
// Utility function to create a tooltip for the gantt chars
function generateTooltip(task) {
var dataObject = task.getDataObject();
var numberResources = dataObject.resourceUsage
? dataObject.resourceUsage
: "NULL";
return `
<dl>
<dt>Name:</dt><dd>{{pName}}</dd>
<dt>Start:</dt><dd>{{pStart}}</dd>
<dt>End:</dt><dd>{{pEnd}}</dd>
<dt>Duration:</dt><dd>${dataObject.ifcduration}</dd>
<dt>Number of Resources:</dt><dd>${numberResources}</dd>
<dt>Resources:</dt><dd>{{pRes}}</dd>
</dl>
`;
}
// Event handlers for editing gantt table data
function editValue(list, task, event, cell, column) {
console.log("editValue function called with the following parameters:");
console.log("list:", list);
console.log("task:", task);
console.log("event:", event);
console.log("cell:", cell);
console.log("column:", column);
const ganttId = task.getGantt()["vDiv"].id;
const index = ganttId.indexOf("-") + 1;
const blenderId = ganttId.substring(index);
const workSchedId = connectedClients[blenderId].workSchedule.id;
// update data object reprsenting the task
const dataObj = task.getDataObject();
dataObj[column] = event.target.value;
task.setDataObject(dataObj);
const msg = {
sourcePage: "gantt",
blenderId: blenderId,
operator: {
type: "editTask",
workScheduleId: workSchedId,
taskId: task.getOriginalID(),
column: column,
value: event.target.value,
},
};
socket.emit("web_operator", msg);
}
@@ -1,221 +0,0 @@
// keeps track of blenders connected in form of
// {shown:bool, filename:string, headers:array}
const connectedClients = {};
let socket;
// Document ready function
$(document).ready(function () {
connectSocket();
});
// Function to connect to Socket.IO server
function connectSocket() {
const url = "ws://localhost:" + SOCKET_PORT + "/web";
socket = io(url);
console.log("socket: ", socket);
// Register socket event handlers
socket.on("blender_connect", handleBlenderConnect);
socket.on("blender_disconnect", handleBlenderDisconnect);
socket.on("csv_data", handleCsvData);
}
// Function to handle 'blender_connect' event
function handleBlenderConnect(blenderId) {
console.log("blender_connect: ", blenderId);
if (!connectedClients.hasOwnProperty(blenderId)) {
connectedClients[blenderId] = { shown: false, ifc_file: "" };
}
}
// Function to handle 'blender_disconnect' event
function handleBlenderDisconnect(blenderId) {
console.log("blender_disconnect: ", blenderId);
if (connectedClients.hasOwnProperty(blenderId)) {
delete connectedClients[blenderId];
removeTableElement(blenderId);
}
}
// Function to handle 'csv_data' event
function handleCsvData(data) {
const blenderId = data["blenderId"];
const csvData = data["data"]["csv_data"];
const filename = data["data"]["IFC_File"];
console.log(data);
if (connectedClients.hasOwnProperty(blenderId)) {
if (!connectedClients[blenderId].shown) {
connectedClients[blenderId] = {
shown: true,
ifc_file: filename,
headers: [],
};
addTableElement(blenderId, csvData, filename);
} else {
updateTableElement(blenderId, csvData, filename);
}
} else {
connectedClients[blenderId] = {
shown: true,
ifc_file: filename,
headers: [],
};
addTableElement(blenderId, csvData, filename);
}
}
// Function to add a new table with data and filename
function addTableElement(blenderId, csvData, filename) {
// store headers of the csv data
const firstLine = csvData.indexOf("\n");
const csvHeaders = csvData.substring(0, firstLine).split(",");
connectedClients[blenderId].headers = csvHeaders;
console.log(connectedClients[blenderId]);
const tableContainer = $("<div></div>")
.addClass("table-container")
.attr("id", "container-" + blenderId);
const tableTitle = $("<h3></h3>")
.attr("id", "title-" + blenderId)
.text(filename)
.css("margin-bottom", "10px");
const tableDiv = $("<div></div>")
.addClass("csv-table")
.attr("id", "table-" + blenderId);
tableContainer.append(tableTitle);
tableContainer.append(tableDiv);
$("#container").append(tableContainer);
function createHeaderMenu(definitions) {
var menu = [];
for (let column of definitions) {
// Create text element for checkbox
if (!column.hasOwnProperty("key")) {
column.visible = true;
}
let checkbox = document.createElement("span");
checkbox.textContent = column.visible ? "\u2611" : "\u2610"; // ☑ or ☐
// Build label
let label = document.createElement("span");
let title = document.createElement("span");
title.textContent = " " + column.title;
label.appendChild(checkbox);
label.appendChild(title);
// Create menu item
menu.push({
label: label,
action: function (e) {
// Prevent menu closing
e.stopPropagation();
// Toggle current column visibility
column.visible = !column.visible;
console.log(column.title, column.visible);
// Change menu item checkbox
if (column.visible) {
table.showColumn(column.title);
checkbox.textContent = "\u2611"; // ☑
} else {
table.hideColumn(column.title);
checkbox.textContent = "\u2610"; // ☐
}
},
});
}
return menu;
}
var table = new Tabulator("#table-" + blenderId, {
height: "400px",
resizableColumnGuide: true,
index: "GlobalId",
data: csvData,
importFormat: "csv",
autoColumns: true,
selectableRows: 1,
layout: "fitColumns",
autoColumnsDefinitions: function (definitions) {
menu = createHeaderMenu(definitions, table);
definitions.forEach((column) => {
column.visible = true;
column.headerMenu = menu;
});
return definitions;
},
});
table.on("rowSelected", function (row) {
var index = row.getIndex(); // the guid of the object
if (!index) {
console.log("No Global ID found");
return;
}
// table id is usually "table-BlenderId" so blender id is always
// after the first 6 characters
var tableId = row.getTable().element.id.substr(6);
const msg = {
sourcePage: "csv",
blenderId: tableId,
operator: {
type: "selection",
globalId: index,
},
};
socket.emit("web_operator", msg);
});
}
// Function to update table and filename
function updateTableElement(blenderId, csvData, filename) {
// check if the headers are the same
// if yes, just replace the data
// else, replace the whole data and column definations
const firstLine = csvData.indexOf("\n");
const newHeaders = csvData.substring(0, firstLine).split(",");
const sameHeaders = compareHeaders(
connectedClients[blenderId].headers,
newHeaders
);
const table = Tabulator.findTable("#table-" + blenderId)[0];
if (table) {
if (sameHeaders) {
table.replaceData(csvData, { importFormat: "csv" });
} else {
table.setData(csvData);
connectedClients[blenderId].headers = newHeaders;
}
$("#title-" + blenderId).text(filename);
}
}
// Function to remove table element
function removeTableElement(blenderId) {
$("#container-" + blenderId).remove();
}
// Utility function to compare two csv header
function compareHeaders(headers1, headers2) {
if (headers1.length !== headers2.length) {
return false;
}
for (let i = 0; i < headers1.length; i++) {
if (headers1[i] !== headers2[i]) {
return false;
}
}
return true;
}
@@ -1,34 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Web Client</title>
<link rel="stylesheet" type="text/css" href="/jsgantt/jsgantt.css" />
<link rel="stylesheet" href="/static/css/gantt.css" />
<script
type="text/javascript"
src="https://code.jquery.com/jquery-3.6.0.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.socket.io/4.0.0/socket.io.min.js"
></script>
<script type="text/javascript" src="./jsgantt/jsgantt.js"></script>
<script>
var SOCKET_PORT = {{port}};
</script>
<script defer src="./static/js/gantt.js"></script>
</head>
<body>
<nav class="no-print">
<img src="https://blenderbim.org/assets/images/blender/blender-logo.png" alt="Logo" class="logo" />
<ul>
<li><a href="/">IFC Data</a></li>
<li><a href="/gantt" class="active">Gantt Chart</a></li>
</ul>
<div class="bottom-bar"></div>
</nav>
<div id="container"></div>
</body>
</html>
@@ -1,40 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Web Client</title>
<link rel="stylesheet" href="/static/css/index.css" />
<link
rel="stylesheet"
href="https://unpkg.com/tabulator-tables/dist/css/tabulator_site_dark.min.css"
/>
<script
type="text/javascript"
src="https://code.jquery.com/jquery-3.6.0.min.js"
></script>
<script
type="text/javascript"
src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"
></script>
<script
type="text/javascript"
src="https://cdn.socket.io/4.0.0/socket.io.min.js"
></script>
<script>
var SOCKET_PORT = {{port}};
</script>
<script defer src="./static/js/index.js"></script>
</head>
<body>
<nav>
<img src="https://blenderbim.org/assets/images/blender/blender-logo.png" alt="Logo" class="logo" />
<ul>
<li><a href="/" class="active">IFC Data</a></li>
<li><a href="/gantt">Gantt Chart</a></li>
</ul>
<div class="bottom-bar"></div>
</nav>
<div id="container"></div>
</body>
</html>
+6 -5
View File
@@ -89,7 +89,7 @@ class IfcExporter:
self.get_application_name(), tool.Blender.get_blenderbim_version()
)
def sync_all_objects(self) -> list[ifcopenshell.entity_instance]:
def sync_all_objects(self, skip_unlinking=False) -> list[ifcopenshell.entity_instance]:
results: list[ifcopenshell.entity_instance] = []
self.unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
for ifc_definition_id in list(IfcStore.id_map.keys()):
@@ -99,6 +99,7 @@ class IfcExporter:
continue
if obj.library:
continue
tool.Collector.sync(obj, skip_unlinking)
result = self.sync_object_placement(obj)
if result:
results.append(result)
@@ -118,8 +119,8 @@ class IfcExporter:
continue
try:
if isinstance(obj, bpy.types.Material):
# TODO: do we add materials to edited_objs?
continue
if tool.Ifc.has_changed_shading(obj):
blenderbim.core.style.update_style_colours(tool.Ifc, tool.Style, obj=obj)
else:
element = tool.Ifc.get_entity(obj)
if element:
@@ -137,9 +138,9 @@ class IfcExporter:
return
bpy.ops.bim.update_representation(obj=obj.name)
def has_changed_materials(self, obj: bpy.types.Object) -> bool:
def has_changed_materials(self, obj):
checksum = obj.data.BIMMeshProperties.material_checksum
return checksum != tool.Geometry.get_material_checksum(obj)
return checksum != str([s.id() for s in tool.Geometry.get_styles(obj) if s])
def sync_object_placement(self, obj: bpy.types.Object) -> Union[ifcopenshell.entity_instance, None]:
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
+12 -10
View File
@@ -20,8 +20,6 @@ import os
import bpy
import json
import addon_utils
import ifcopenshell.util.element
import ifcopenshell.util.representation
import ifcopenshell.api.owner.settings
import blenderbim.bim
import blenderbim.tool as tool
@@ -53,8 +51,10 @@ def name_callback(obj, data):
return
if isinstance(obj, bpy.types.Material):
if ifc_definition_id := obj.BIMStyleProperties.ifc_definition_id:
IfcStore.get_file().by_id(ifc_definition_id).Name = obj.name
if obj.BIMObjectProperties.ifc_definition_id:
IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id).Name = obj.name
if obj.BIMMaterialProperties.ifc_style_id:
IfcStore.get_file().by_id(obj.BIMMaterialProperties.ifc_style_id).Name = obj.name
refresh_ui_data()
return
@@ -86,6 +86,11 @@ def name_callback(obj, data):
refresh_ui_data()
def color_callback(obj, data):
if obj.BIMMaterialProperties.ifc_style_id:
tool.Ifc.edit(obj)
def active_object_callback():
refresh_ui_data()
update_bim_tool_props()
@@ -188,8 +193,6 @@ def refresh_ui_data():
tool.Ifc.get().clear_cache()
bpy.context.scene.DocProperties.should_draw_decorations = bpy.context.scene.DocProperties.should_draw_decorations
if bpy.context.scene.WebProperties.is_connected:
tool.Web.send_webui_data()
@persistent
@@ -293,13 +296,12 @@ def load_post(scene):
ifcopenshell.api.owner.settings.get_application = get_application
AuthoringData.type_thumbnails = {}
preferences = tool.Blender.get_addon_preferences()
if not preferences.should_setup_toolbar:
if not bpy.context.preferences.addons["blenderbim"].preferences.should_setup_toolbar:
tool.Blender.unregister_toolbar()
if preferences.should_setup_workspace:
if bpy.context.preferences.addons["blenderbim"].preferences.should_setup_workspace:
if "BIM" in bpy.data.workspaces:
if preferences.activate_workspace:
if bpy.context.preferences.addons["blenderbim"].preferences.activate_workspace:
bpy.context.window.workspace = bpy.data.workspaces["BIM"]
else:
bpy.ops.workspace.append_activate(idname="BIM", filepath=os.path.join(cwd, "data", "workspace.blend"))
+48
View File
@@ -20,6 +20,7 @@
import bpy
import json
import math
import zipfile
import ifcopenshell
import ifcopenshell.util.attribute
import ifcopenshell.util.element
@@ -321,3 +322,50 @@ def draw_filter(layout, filter_groups, data, module):
op.group_index = i
op.index = j
op.module = module
# TODO this should move into ifcopenshell.util
class IfcHeaderExtractor:
def __init__(self, filepath: str):
self.filepath = filepath
def extract(self):
extension = self.filepath.split(".")[-1]
if extension.lower() == "ifc":
with open(self.filepath) as ifc_file:
return self.extract_ifc_spf(ifc_file)
elif extension.lower() == "ifczip":
return self.extract_ifc_zip()
elif extension.lower() == "ifcsqlite":
return {} # TODO
def extract_ifc_spf(self, ifc_file):
# https://www.steptools.com/stds/step/IS_final_p21e3.html#clause-8
data = {}
max_lines_to_parse = 50
for _ in range(max_lines_to_parse):
line = next(ifc_file)
if isinstance(line, bytes):
line = line.decode("utf-8")
if line.startswith("FILE_DESCRIPTION"):
for i, part in enumerate(line.split("'")):
if i == 1:
data["description"] = part
elif i == 3:
data["implementation_level"] = part
elif line.startswith("FILE_NAME"):
for i, part in enumerate(line.split("'")):
if i == 1:
data["name"] = part
elif i == 3:
data["time_stamp"] = part
elif line.startswith("FILE_SCHEMA"):
data["schema_name"] = line.split("'")[1]
break
return data
def extract_ifc_zip(self):
archive = zipfile.ZipFile(self.filepath, "r")
return self.extract_ifc_spf(archive.open(archive.filelist[0]))
+72 -98
View File
@@ -32,29 +32,12 @@ import blenderbim.bim.handler
import blenderbim.tool as tool
from pathlib import Path
from blenderbim.tool.brick import BrickStore
from typing import Set, Union, Optional, TypedDict, Callable
from typing import Set, Union, Optional
IFC_CONNECTED_TYPE = Union[bpy.types.Material, bpy.types.Object]
class OperationData(TypedDict):
id: int
guid: Union[str, None]
obj: str
class Operation(TypedDict):
rollback: Callable
commit: Callable
data: OperationData
class TransactionStep(TypedDict):
key: str
operations: list[Operation]
class IfcStore:
path: str = ""
file: Optional[ifcopenshell.file] = None
@@ -72,9 +55,9 @@ class IfcStore:
library_file: Optional[ifcopenshell.file] = None
current_transaction = ""
last_transaction = ""
history: list[TransactionStep] = []
future: list[TransactionStep] = []
schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3_ADD2"]
history = []
future = []
schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3"]
session_files: dict[str, ifcopenshell.file] = {}
@staticmethod
@@ -94,7 +77,7 @@ class IfcStore:
IfcStore.last_transaction = ""
IfcStore.history = []
IfcStore.future = []
IfcStore.schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3_ADD2"]
IfcStore.schema_identifiers = ["IFC4", "IFC2X3", "IFC4X3"]
IfcStore.session_files = {}
@staticmethod
@@ -117,6 +100,7 @@ class IfcStore:
ifc_hash = hashlib.md5(ifc_key.encode("utf-8")).hexdigest()
IfcStore.cache_path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "cache", f"{ifc_hash}.h5")
cache_settings = ifcopenshell.geom.settings()
cache_settings.set(cache_settings.STRICT_TOLERANCE, True)
try:
IfcStore.cache = ifcopenshell.geom.serializers.hdf5(IfcStore.cache_path, cache_settings)
except:
@@ -167,25 +151,26 @@ class IfcStore:
IfcStore.file = ifcopenshell.open(path)
@staticmethod
def get_schema() -> ifcopenshell.ifcopenshell_wrapper.schema_definition:
def get_schema():
if IfcStore.file is None:
IfcStore.schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(
bpy.context.scene.BIMProjectProperties.export_schema
)
elif IfcStore.schema is None:
IfcStore.schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(IfcStore.file.schema_identifier)
IfcStore.schema = ifcopenshell.ifcopenshell_wrapper.schema_by_name(IfcStore.file.schema)
return IfcStore.schema
@staticmethod
def get_element(id_or_guid: Union[int, str]) -> IFC_CONNECTED_TYPE:
if isinstance(id_or_guid, int):
obj = IfcStore.id_map.get(id_or_guid)
map_object = IfcStore.id_map
else:
obj = IfcStore.guid_map.get(id_or_guid)
if obj is None:
return None
if not tool.Blender.is_valid_data_block(obj):
return None
map_object = IfcStore.guid_map
try:
obj = map_object[id_or_guid]
obj.name # In case the object has been deleted, this triggers an exception
except:
return
return obj
@staticmethod
@@ -205,26 +190,21 @@ class IfcStore:
def relink_object(obj: IFC_CONNECTED_TYPE) -> None:
if not obj:
return
if isinstance(obj, bpy.types.Object):
ifc_definition_id = obj.BIMObjectProperties.ifc_definition_id
if not ifc_definition_id:
return
if obj.BIMObjectProperties.ifc_definition_id:
try:
element = IfcStore.get_file().by_id(ifc_definition_id)
except RuntimeError:
element = IfcStore.get_file().by_id(obj.BIMObjectProperties.ifc_definition_id)
except:
return
data = OperationData(id=element.id(), obj=obj.name)
data = {"id": element.id(), "obj": obj.name}
if hasattr(element, "GlobalId"):
data["guid"] = element.GlobalId
IfcStore.commit_link_element(data)
return
else: # bpy.types.Material
ifc_definition_id = obj.BIMStyleProperties.ifc_definition_id
if hasattr(obj, "BIMMaterialProperties") and obj.BIMMaterialProperties.ifc_style_id:
try:
element = IfcStore.get_file().by_id(ifc_definition_id)
except RuntimeError:
element = IfcStore.get_file().by_id(obj.BIMMaterialProperties.ifc_style_id)
except:
return
data = OperationData(id=element.id(), obj=obj.name)
data = {"id": element.id(), "obj": obj.name}
IfcStore.commit_link_element(data)
@staticmethod
@@ -239,40 +219,44 @@ class IfcStore:
existing_obj = IfcStore.id_map.get(element.id(), None)
if existing_obj == obj:
return
# TODO: When does this occur?
elif existing_obj and tool.Blender.is_valid_data_block(existing_obj):
IfcStore.unlink_element(obj=existing_obj)
elif existing_obj:
try:
existing_obj.name
IfcStore.unlink_element(element=element, obj=existing_obj)
except:
pass
IfcStore.id_map[element.id()] = obj
if hasattr(element, "GlobalId"):
IfcStore.guid_map[element.GlobalId] = obj
if element.is_a("IfcSurfaceStyle"):
obj.BIMStyleProperties.ifc_definition_id = element.id()
obj.BIMMaterialProperties.ifc_style_id = element.id()
else:
obj.BIMObjectProperties.ifc_definition_id = element.id()
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
if isinstance(obj, bpy.types.Object):
if isinstance(obj, bpy.types.Material):
blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_callback)
elif isinstance(obj, bpy.types.Object):
blenderbim.bim.handler.subscribe_to(
obj, "active_material_index", blenderbim.bim.handler.active_material_index_callback
)
if IfcStore.history:
data = OperationData(id=element.id(), guid=getattr(element, "GlobalId", None), obj=obj.name)
data = {"id": element.id(), "guid": getattr(element, "GlobalId", None), "obj": obj.name}
IfcStore.history[-1]["operations"].append(
Operation(rollback=IfcStore.rollback_link_element, commit=IfcStore.commit_link_element, data=data)
{"rollback": IfcStore.rollback_link_element, "commit": IfcStore.commit_link_element, "data": data}
)
@staticmethod
def rollback_link_element(data: OperationData) -> None:
def rollback_link_element(data):
del IfcStore.id_map[data["id"]]
if data["guid"]:
del IfcStore.guid_map[data["guid"]]
@staticmethod
def commit_link_element(data: OperationData) -> None:
def commit_link_element(data):
obj = bpy.data.objects.get(data["obj"])
if not obj:
obj = bpy.data.materials.get(data["obj"])
@@ -280,7 +264,9 @@ class IfcStore:
if "guid" in data:
IfcStore.guid_map[data["guid"]] = obj
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
if isinstance(obj, bpy.types.Object):
if isinstance(obj, bpy.types.Material):
blenderbim.bim.handler.subscribe_to(obj, "diffuse_color", blenderbim.bim.handler.color_callback)
elif isinstance(obj, bpy.types.Object):
blenderbim.bim.handler.subscribe_to(
obj, "active_material_index", blenderbim.bim.handler.active_material_index_callback
)
@@ -288,7 +274,7 @@ class IfcStore:
# TODO We're handling id_map and guid_map, but what about edited_objs? This might cause big problems.
@staticmethod
def rollback_unlink_element(data: OperationData) -> None:
def rollback_unlink_element(data) -> None:
if "id" not in data or "obj" not in data:
return
obj = bpy.data.objects.get(data["obj"])
@@ -297,7 +283,7 @@ class IfcStore:
IfcStore.guid_map[data["guid"]] = obj
@staticmethod
def commit_unlink_element(data: OperationData) -> None:
def commit_unlink_element(data) -> None:
del IfcStore.id_map[data["id"]]
if data["guid"]:
del IfcStore.guid_map[data["guid"]]
@@ -306,62 +292,50 @@ class IfcStore:
def unlink_element(
element: Optional[ifcopenshell.entity_instance] = None, obj: Optional[IFC_CONNECTED_TYPE] = None
) -> None:
"""Unlink IFC `element` or Blender `obj`.
if element is None:
try:
element = tool.Ifc.get_entity(obj)
except:
pass
If element is provided then it will be unlinked from the related Blender object.
Blender object's IFC information is also will be purged.
If Blender object is provided then all IFC information will be purged from this object.
Method won't be searching for related IFC elements as Blender object might come from
different Blender session and there might be an ids/guids clash.
Only one argument must be provided and other should be omitted as they have different meaning.
:raises TypeError: If both arguments or no arguments provided.
"""
if not bool(element) ^ bool(obj):
raise TypeError("Only one argument must be provided - element or obj.")
if obj:
IfcStore.purge_blender_ifc_data(obj)
return
assert element # Type checker.
if obj is None:
try:
potential_obj = IfcStore.id_map[element.id()]
if tool.Blender.is_valid_data_block(potential_obj):
obj = potential_obj
IfcStore.purge_blender_ifc_data(obj)
potential_obj.name
obj = potential_obj
except:
pass
try:
del IfcStore.id_map[element.id()]
if element:
del IfcStore.id_map[element.id()]
else:
del IfcStore.id_map[obj.BIMObjectProperties.ifc_definition_id]
except:
pass
if global_id := getattr(element, "GlobalId", None):
try:
del IfcStore.guid_map[global_id]
except:
pass
try:
if element and hasattr(element, "GlobalId"):
del IfcStore.guid_map[element.GlobalId]
except:
pass
if element and element.is_a("IfcSurfaceStyle"):
obj.BIMMaterialProperties.ifc_style_id = 0
elif obj:
obj.BIMObjectProperties.ifc_definition_id = 0
if IfcStore.history:
data = OperationData(id=element.id(), guid=global_id)
data = {}
if element:
data["id"] = element.id()
data["guid"] = getattr(element, "GlobalId", None)
if obj:
data["obj"] = obj.name
IfcStore.history[-1]["operations"].append(
Operation(rollback=IfcStore.rollback_unlink_element, commit=IfcStore.commit_unlink_element, data=data)
{"rollback": IfcStore.rollback_unlink_element, "commit": IfcStore.commit_unlink_element, "data": data}
)
@staticmethod
def purge_blender_ifc_data(obj: IFC_CONNECTED_TYPE) -> None:
if isinstance(obj, bpy.types.Material):
obj.BIMStyleProperties.ifc_definition_id = 0
else: # bpy.types.Object
obj.BIMObjectProperties.ifc_definition_id = 0
@staticmethod
def execute_ifc_operator(operator: bpy.types.Operator, context: bpy.types.Context, is_invoke=False):
blenderbim.last_actions.append({"type": "operator", "name": operator.bl_idname})
@@ -420,15 +394,15 @@ class IfcStore:
rollback = rollback or getattr(operator, "rollback", lambda data: True)
commit = commit or getattr(operator, "commit", lambda data: True)
if IfcStore.history and IfcStore.history[-1]["key"] == key:
IfcStore.history[-1]["operations"].append(OperationData(rollback=rollback, commit=commit, data=data))
IfcStore.history[-1]["operations"].append({"rollback": rollback, "commit": commit, "data": data})
else:
IfcStore.history.append(
TransactionStep(key=key, operations=[OperationData(rollback=rollback, commit=commit, data=data)])
{"key": key, "operations": [{"rollback": rollback, "commit": commit, "data": data}]}
)
IfcStore.future = []
@staticmethod
def undo(until_key: str = None) -> None:
def undo(until_key=None) -> None:
BrickStore.undo()
if not IfcStore.history:
return
@@ -443,7 +417,7 @@ class IfcStore:
IfcStore.future.append(event)
@staticmethod
def redo(until_key: str = None) -> None:
def redo(until_key=None) -> None:
BrickStore.redo()
if not IfcStore.future:
File diff suppressed because it is too large Load Diff
@@ -26,7 +26,14 @@ import blenderbim.bim.handler
from blenderbim.bim.ifc import IfcStore
class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator):
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
"""Create aggregation relationship between two ifc elements"""
bl_idname = "bim.aggregate_assign_object"
@@ -68,7 +75,7 @@ class BIM_OT_aggregate_assign_object(bpy.types.Operator, tool.Ifc.Operator):
self.report({"ERROR"}, f"Cannot aggregate to {relating_obj.name} with a body representation")
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, tool.Ifc.Operator):
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
"""Remove aggregation relationship between two ifc elements"""
bl_idname = "bim.aggregate_unassign_object"
@@ -92,14 +99,14 @@ class BIM_OT_aggregate_unassign_object(bpy.types.Operator, tool.Ifc.Operator):
)
# Removes Pset related to Linked Aggregates
if not element.is_a("IfcElementAssembly"):
pset = ifcopenshell.util.element.get_pset(element, "BBIM_Linked_Aggregate")
if not element.is_a('IfcElementAssembly'):
pset = ifcopenshell.util.element.get_pset(element, 'BBIM_Linked_Aggregate')
if pset:
pset = tool.Ifc.get().by_id(pset["id"])
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=element, pset=pset)
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, tool.Ifc.Operator):
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator):
"""Enable editing aggregation relationship"""
bl_idname = "bim.enable_editing_aggregate"
@@ -110,7 +117,7 @@ class BIM_OT_enable_editing_aggregate(bpy.types.Operator, tool.Ifc.Operator):
core.enable_editing_aggregate(tool.Aggregate, obj=context.active_object)
class BIM_OT_disable_editing_aggregate(bpy.types.Operator, tool.Ifc.Operator):
class BIM_OT_disable_editing_aggregate(bpy.types.Operator, Operator):
"""Disable editing aggregation relationship"""
bl_idname = "bim.disable_editing_aggregate"
@@ -152,6 +159,7 @@ class BIM_OT_add_aggregate(bpy.types.Operator, tool.Ifc.Operator):
if not element:
continue
tool.Collector.sync(obj)
current_aggregate = ifcopenshell.util.element.get_aggregate(element)
current_container = ifcopenshell.util.element.get_container(element)
if current_aggregate:
@@ -225,7 +233,7 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
# obj = bpy.data.objects.get(self.obj) or context.active_object
# aggregate = ifcopenshell.util.element.get_aggregate(tool.Ifc.get_entity(obj))
# aggregate_obj = tool.Ifc.get_object(aggregate)
all_parts = []
for obj in context.selected_objects:
element = tool.Ifc.get_entity(obj)
@@ -238,7 +246,7 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
pass
if not element:
obj.select_set(False)
if self.select_parts:
all_objs = []
for part in all_parts:
@@ -256,12 +264,12 @@ class BIM_OT_select_aggregate(bpy.types.Operator):
for aggregate_element in all_parts:
aggregate_obj = tool.Ifc.get_object(aggregate_element)
aggregate_obj.select_set(True)
bpy.context.view_layer.objects.active = aggregate_obj
bpy.context.view_layer.objects.active = aggregate_obj
return {"FINISHED"}
class BIM_OT_add_part_to_object(bpy.types.Operator, tool.Ifc.Operator):
class BIM_OT_add_part_to_object(bpy.types.Operator, Operator):
bl_idname = "bim.add_part_to_object"
bl_label = "Add Part to Object"
bl_options = {"REGISTER", "UNDO"}
@@ -283,10 +291,10 @@ class BIM_OT_add_part_to_object(bpy.types.Operator, tool.Ifc.Operator):
part_class=self.part_class,
part_name=self.part_name,
)
blenderbim.core.spatial.import_spatial_decomposition(tool.Spatial)
tool.Spatial.load_container_manager()
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, tool.Ifc.Operator):
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
bl_idname = "bim.break_link_to_other_aggregates"
bl_label = "Break link to other aggregates"
bl_options = {"REGISTER", "UNDO"}
@@ -317,7 +325,7 @@ class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, tool.Ifc.Operato
return {"FINISHED"}
class BIM_OT_select_linked_aggregates(bpy.types.Operator, tool.Ifc.Operator):
class BIM_OT_select_linked_aggregates(bpy.types.Operator, Operator):
bl_idname = "bim.select_linked_aggregates"
bl_label = "Select linked aggregates"
bl_options = {"REGISTER", "UNDO"}
@@ -331,7 +339,7 @@ class BIM_OT_select_linked_aggregates(bpy.types.Operator, tool.Ifc.Operator):
return "Select all aggregates"
def _execute(self, context):
for obj in context.selected_objects:
obj.select_set(False)
element = tool.Ifc.get_entity(obj)
@@ -28,6 +28,13 @@ import blenderbim.core.attribute as core
from blenderbim.bim.ifc import IfcStore
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class EnableEditingAttributes(bpy.types.Operator):
bl_idname = "bim.enable_editing_attributes"
bl_label = "Enable Editing Attributes"
@@ -82,7 +89,7 @@ class DisableEditingAttributes(bpy.types.Operator):
return {"FINISHED"}
class EditAttributes(bpy.types.Operator, tool.Ifc.Operator):
class EditAttributes(bpy.types.Operator, Operator):
bl_idname = "bim.edit_attributes"
bl_label = "Edit Attributes"
bl_options = {"REGISTER", "UNDO"}
@@ -111,7 +118,7 @@ class EditAttributes(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class GenerateGlobalId(bpy.types.Operator, tool.Ifc.Operator):
class GenerateGlobalId(bpy.types.Operator, Operator):
bl_idname = "bim.generate_global_id"
bl_label = "Regenerate GlobalId"
bl_description = "Regenerate GlobalId\n\nSHIFT+CLICK to regenerate GlobalIds for all selected objects"
@@ -154,7 +161,7 @@ class GenerateGlobalId(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class CopyAttributeToSelection(bpy.types.Operator, tool.Ifc.Operator):
class CopyAttributeToSelection(bpy.types.Operator, Operator):
bl_idname = "bim.copy_attribute_to_selection"
bl_label = "Copy Attribute To Selection"
name: bpy.props.StringProperty()
@@ -59,20 +59,6 @@ class LoadBcfProject(bpy.types.Operator):
if self.filepath:
bcfstore.BcfStore.set_by_filepath(self.filepath)
bcfxml = bcfstore.BcfStore.get_bcfxml()
# a BCFv2.1 does not need to have a project, but BBIM likes to have one
# https://github.com/buildingSMART/BCF-XML/tree/release_2_1/Documentation#bcf-file-structure
nameless = "Unknown"
if bcfxml.project is None:
if bcfxml.version.version_id.startswith("2"):
print("No project, we will create one for BBIM.")
bcfxml.project_info = bcf.v2.model.ProjectExtension(
project=bcf.v2.model.Project(
name=nameless,
project_id=str(uuid.uuid4())
), extension_schema=""
)
if bcfxml.project.name is None:
bcfxml.project.name = nameless
context.scene.BCFProperties.name = bcfxml.project.name
bpy.ops.bim.load_bcf_topics()
return {"FINISHED"}
@@ -100,19 +86,7 @@ class LoadBcfTopics(bpy.types.Operator):
def execute(self, context):
bcfxml = bcfstore.BcfStore.get_bcfxml()
context.scene.BCFProperties.topics.clear()
# workaround, one non standard topic would break reading entire bcf
# ignored these topics ATM
# happens on non standard nodes or on missing nodes in markup
topics2use = []
for topic_guid in bcfxml.topics.keys():
# print("topic guid: {}".format(topic_guid))
try:
topic_titel = bcfxml.topics[topic_guid].topic.title
topics2use.append(topic_guid)
except:
print("Problems on reading topic, thus ignored: {}".format(topic_guid))
continue
for index, topic_guid in enumerate(topics2use):
for index, topic_guid in enumerate(bcfxml.topics.keys()):
new = context.scene.BCFProperties.topics.add()
bpy.ops.bim.load_bcf_topic(topic_guid=topic_guid, topic_index=index)
return {"FINISHED"}
@@ -949,9 +923,9 @@ class ActivateBcfViewpoint(bpy.types.Operator):
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
matrix = ifcopenshell.util.geolocation.global2local(
matrix,
float(props.blender_offset_x) * unit_scale,
float(props.blender_offset_y) * unit_scale,
float(props.blender_offset_z) * unit_scale,
float(props.blender_eastings) * unit_scale,
float(props.blender_northings) * unit_scale,
float(props.blender_orthogonal_height) * unit_scale,
float(props.blender_x_axis_abscissa),
float(props.blender_x_axis_ordinate),
)
@@ -964,42 +938,22 @@ class ActivateBcfViewpoint(bpy.types.Operator):
# Operators with context overrides are used because they are
# significantly faster than looping through all objects
self.set_exceptions(viewpoint, context)
self.set_view_setup_hints(viewpoint, context)
# set selection at the end not to conflict with .hide_spaces
self.set_selection(viewpoint)
self.set_colours(viewpoint)
def set_exceptions(self, viewpoint, context):
if (
not hasattr(viewpoint.visualization_info.components, "visibility")
or not hasattr(viewpoint.visualization_info.components.visibility.exceptions, "component")
):
return
exception_global_ids = {v.ifc_guid for v in viewpoint.visualization_info.components.visibility.exceptions.component or []}
# print("default_visibility: {}".format(viewpoint.visualization_info.components.visibility.default_visibility))
if viewpoint.visualization_info.components.visibility.default_visibility:
# default_visibility is True: show all objs, hide the exceptions
old = context.area.type
context.area.type = "VIEW_3D"
bpy.ops.object.hide_view_clear()
context.area.type = old
for global_id in exception_global_ids:
# print("{}: hide".format(global_id))
obj = IfcStore.get_element(global_id)
if obj and bpy.context.view_layer.objects.get(obj.name):
# print(" obj found")
obj.hide_set(True)
else:
# default_visibility is False: hide all objs, show the exceptions
objs = []
for global_id in exception_global_ids:
# print("{}: show".format(global_id))
obj = IfcStore.get_element(global_id)
if obj:
# print(" obj found")
objs.append(obj)
if objs:
old = context.area.type
@@ -1013,7 +967,6 @@ class ActivateBcfViewpoint(bpy.types.Operator):
bpy.data.objects["Viewpoint"].hide_set(False)
context.area.type = old
def set_view_setup_hints(self, viewpoint, context):
if viewpoint.visualization_info.components.view_setup_hints:
if not viewpoint.visualization_info.components.view_setup_hints.spaces_visible:
self.hide_spaces(context)
@@ -1025,6 +978,10 @@ class ActivateBcfViewpoint(bpy.types.Operator):
self.hide_spaces(context)
self.set_openings_visibility(False, context)
# set selection at the end not to conflict with .hide_spaces
self.set_selection(viewpoint)
self.set_colours(viewpoint)
def hide_spaces(self, context):
old = context.area.type
context.area.type = "VIEW_3D"
@@ -1042,25 +999,19 @@ class ActivateBcfViewpoint(bpy.types.Operator):
selected_global_ids = [s.ifc_guid for s in viewpoint.visualization_info.components.selection.component or []]
bpy.ops.object.select_all(action="DESELECT")
for global_id in selected_global_ids:
# print("{}: selected".format(global_id))
obj = IfcStore.get_element(global_id)
if obj:
# print(" obj found")
obj.select_set(True)
obj.hide_set(False)
def set_colours(self, viewpoint):
if not viewpoint.visualization_info.components or not viewpoint.visualization_info.components.coloring:
return
global_id_colours = {}
for acoloring in viewpoint.visualization_info.components.coloring.color:
for acomponent in acoloring.component:
global_id_colours.setdefault(acomponent.ifc_guid, acoloring.color)
for coloring in viewpoint.visualization_info.components.coloring or []:
for component in coloring.components:
global_id_colours.setdefault(component.ifc_guid, coloring.color)
for global_id, color in global_id_colours.items():
# print("{}: color: {}: {}".format(global_id, color, self.hex_to_rgb(color)))
obj = IfcStore.get_element(global_id)
if obj:
# print(" obj found ")
obj.color = self.hex_to_rgb(color)
def draw_lines(self, viewpoint, context):
@@ -1144,14 +1095,8 @@ class ActivateBcfViewpoint(bpy.types.Operator):
def hex_to_rgb(self, value):
value = value.lstrip("#")
lv = len(value)
# https://github.com/buildingSMART/BCF-XML/tree/release_3_0/Documentation#coloring
if lv == 8:
t = tuple(int(value[i : i + lv // 4], 16) for i in range(0, lv, lv // 4))
col = [t[1] / 255.0, t[2] / 255.0, t[3] / 255.0, t[0] / 255.0]
else:
t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3))
col = [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1]
return col
t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3))
return [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1]
class OpenBcfReferenceLink(bpy.types.Operator):
@@ -49,7 +49,7 @@ class BoundaryDecorator:
batch.draw(shader)
def __call__(self, context):
self.addon_prefs = tool.Blender.get_addon_preferences()
self.addon_prefs = context.preferences.addons["blenderbim"].preferences
selected_elements_color = self.addon_prefs.decorator_color_selected
unselected_elements_color = self.addon_prefs.decorator_color_unselected
special_elements_color = self.addon_prefs.decorator_color_special
@@ -133,11 +133,14 @@ class Loader:
return mesh
def load_settings(self):
return ifcopenshell.geom.settings()
settings = ifcopenshell.geom.settings()
settings.set(settings.EXCLUDE_SOLIDS_AND_SURFACES, False)
settings.set(settings.USE_BREP_DATA, False)
return settings
def load_fallback_settings(self):
settings = ifcopenshell.geom.settings()
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
settings.set(settings.INCLUDE_CURVES, True)
return settings
def load_importer(self):
@@ -551,9 +554,9 @@ class HideBoundaries(bpy.types.Operator, tool.Ifc.Operator):
for boundary in element.BoundedBy or []:
boundary_obj = tool.Ifc.get_object(boundary)
if boundary_obj:
to_delete.add((boundary, boundary_obj))
for boundary, boundary_obj in to_delete:
tool.Ifc.unlink(element=boundary)
to_delete.add(boundary_obj)
for boundary_obj in to_delete:
tool.Ifc.unlink(obj=boundary_obj)
bpy.data.objects.remove(boundary_obj)
context.scene.BIMBoundaryProperties.boundaries.clear()
return {"FINISHED"}
@@ -602,11 +605,6 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
parent_boundaries = []
objs = context.selected_objects
if not any((element:=tool.Ifc.get_entity(obj)) and element.is_a("IfcSpace") for obj in objs):
self.report({"INFO"}, "No IfcSpace elements selected.")
return {"FINISHED"}
if len(objs) == 2:
# The user may select two objects, a space and its related building element
for obj in objs:
@@ -634,18 +632,24 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
# TODO : refactor to be able to generate all boundaries for selected space automatically or with an option
def msg(self, context):
self.layout.label(text="Please set an active container to detect space boundaries from.")
self.layout.label(text="NO ACTIVE STOREY")
element = tool.Ifc.get_entity(objs[0])
if element.is_a("IfcSpace"):
relating_space = element
relating_space_obj = objs[0]
if not (container := tool.Root.get_default_container()):
collection = context.view_layer.active_layer_collection.collection
collection_obj = bpy.data.objects.get(collection.name)
if not collection_obj:
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
return
spatial_element = tool.Ifc.get_entity(collection_obj)
if not spatial_element:
bpy.context.window_manager.popup_menu(msg, title="Error", icon="ERROR")
return
for subelement in ifcopenshell.util.element.get_decomposition(container):
for subelement in ifcopenshell.util.element.get_decomposition(spatial_element):
if not (
subelement.is_a("IfcWall") or subelement.is_a("IfcSlab") or subelement.is_a("IfcVirtualElement")
):
@@ -688,7 +692,8 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
tree = ifcopenshell.geom.tree()
shapes = {}
settings = ifcopenshell.geom.settings()
settings.set("disable-opening-subtractions", True)
settings.set(settings.STRICT_TOLERANCE, True)
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, True)
iterator = ifcopenshell.geom.iterator(settings, tool.Ifc.get(), multiprocessing.cpu_count(), include=include)
if iterator.initialize():
while True:
@@ -826,10 +831,17 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
# Create shape of opening as a dissolved BMesh
settings = ifcopenshell.geom.settings()
settings.set(settings.STRICT_TOLERANCE, True)
shape = ifcopenshell.geom.create_shape(settings, opening)
m = shape.transformation.matrix
mat = Matrix(ifcopenshell.util.shape.get_shape_matrix(shape))
mat.translation = (0, 0, 0)
m = shape.transformation.matrix.data
mat = Matrix(
(
[m[0], m[3], m[6], m[9]],
[m[1], m[4], m[7], m[10]],
[m[2], m[5], m[8], m[11]],
[0, 0, 0, 1],
)
)
opening_bm = bmesh.new()
verts = ifcopenshell.util.shape.get_vertices(shape.geometry)
for vert in verts:
@@ -1020,10 +1032,12 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
settings = ifcopenshell.geom.settings()
if not element.is_a("IfcOpeningElement"):
settings.set("disable-opening-subtractions", True)
settings.set(settings.DISABLE_OPENING_SUBTRACTIONS, True)
settings.set(settings.STRICT_TOLERANCE, True)
# geometry = ifcopenshell.geom.create_shape(settings, body)
shape = ifcopenshell.geom.create_shape(settings, element)
mat = Matrix(ifcopenshell.util.shape.get_shape_matrix(shape))
m = shape.transformation.matrix.data
mat = Matrix(([m[0], m[3], m[6], m[9]], [m[1], m[4], m[7], m[10]], [m[2], m[5], m[8], m[11]], [0, 0, 0, 1]))
verts = [space_matrix_i @ mat @ Vector(v) for v in ifcopenshell.util.shape.get_vertices(shape.geometry)]
faces = ifcopenshell.util.shape.get_faces(shape.geometry)
polygons = []
@@ -26,7 +26,14 @@ from blenderbim.bim.ifc import IfcStore
from blenderbim.tool.brick import BrickStore
class LoadBrickProject(bpy.types.Operator, tool.Ifc.Operator):
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class LoadBrickProject(bpy.types.Operator, Operator):
bl_idname = "bim.load_brick_project"
bl_label = "Load Brickschema Project"
bl_options = {"REGISTER", "UNDO"}
@@ -39,14 +46,14 @@ class LoadBrickProject(bpy.types.Operator, tool.Ifc.Operator):
root = context.scene.BIMBrickProperties.brick_list_root
core.load_brick_project(tool.Brick, filepath=self.filepath, brick_root=root)
else:
self.report({"ERROR"}, f"Failed to load {self.filepath}")
self.report({'ERROR'}, f'Failed to load {self.filepath}')
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ViewBrickClass(bpy.types.Operator, tool.Ifc.Operator):
class ViewBrickClass(bpy.types.Operator, Operator):
bl_idname = "bim.view_brick_class"
bl_label = "View Brick Class"
bl_options = {"REGISTER", "UNDO"}
@@ -58,7 +65,7 @@ class ViewBrickClass(bpy.types.Operator, tool.Ifc.Operator):
core.view_brick_class(tool.Brick, brick_class=self.brick_class, split_screen=self.split_screen)
class ViewBrickItem(bpy.types.Operator, tool.Ifc.Operator):
class ViewBrickItem(bpy.types.Operator, Operator):
bl_idname = "bim.view_brick_item"
bl_label = "View Brick Item"
bl_options = {"REGISTER", "UNDO"}
@@ -70,10 +77,10 @@ class ViewBrickItem(bpy.types.Operator, tool.Ifc.Operator):
try:
core.view_brick_item(tool.Brick, item=self.item, split_screen=self.split_screen)
except:
self.report({"ERROR"}, f"Could not find {self.item}")
self.report({'ERROR'}, f'Could not find {self.item}')
class RewindBrickClass(bpy.types.Operator, tool.Ifc.Operator):
class RewindBrickClass(bpy.types.Operator, Operator):
bl_idname = "bim.rewind_brick_class"
bl_label = "Rewind Brick Class"
bl_options = {"REGISTER", "UNDO"}
@@ -84,7 +91,7 @@ class RewindBrickClass(bpy.types.Operator, tool.Ifc.Operator):
core.rewind_brick_class(tool.Brick, split_screen=self.split_screen)
class CloseBrickProject(bpy.types.Operator, tool.Ifc.Operator):
class CloseBrickProject(bpy.types.Operator, Operator):
bl_idname = "bim.close_brick_project"
bl_label = "Close Brick Project"
bl_options = {"REGISTER", "UNDO"}
@@ -94,7 +101,7 @@ class CloseBrickProject(bpy.types.Operator, tool.Ifc.Operator):
core.close_brick_project(tool.Brick)
class ConvertBrickProject(bpy.types.Operator, tool.Ifc.Operator):
class ConvertBrickProject(bpy.types.Operator, Operator):
bl_idname = "bim.convert_brick_project"
bl_label = "Convert Brick Project"
bl_options = {"REGISTER", "UNDO"}
@@ -104,7 +111,7 @@ class ConvertBrickProject(bpy.types.Operator, tool.Ifc.Operator):
core.convert_brick_project(tool.Ifc, tool.Brick)
class AssignBrickReference(bpy.types.Operator, tool.Ifc.Operator):
class AssignBrickReference(bpy.types.Operator, Operator):
bl_idname = "bim.assign_brick_reference"
bl_label = "Assign Brick Reference"
bl_options = {"REGISTER", "UNDO"}
@@ -112,13 +119,13 @@ class AssignBrickReference(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
if not context.active_object:
self.report({"ERROR"}, f"No Ifc selected")
self.report({'ERROR'}, f'No Ifc selected')
return
props = context.scene.BIMBrickProperties
try:
props.bricks[props.active_brick_index]
except:
self.report({"ERROR"}, f"No Brick selected")
self.report({'ERROR'}, f'No Brick selected')
return
core.assign_brick_reference(
tool.Ifc,
@@ -129,7 +136,7 @@ class AssignBrickReference(bpy.types.Operator, tool.Ifc.Operator):
)
class AddBrick(bpy.types.Operator, tool.Ifc.Operator):
class AddBrick(bpy.types.Operator, Operator):
bl_idname = "bim.add_brick"
bl_label = "Add Brick"
bl_options = {"REGISTER", "UNDO"}
@@ -148,7 +155,7 @@ class AddBrick(bpy.types.Operator, tool.Ifc.Operator):
)
class AddBrickRelation(bpy.types.Operator, tool.Ifc.Operator):
class AddBrickRelation(bpy.types.Operator, Operator):
bl_idname = "bim.add_brick_relation"
bl_label = "Add Brick Relation"
bl_options = {"REGISTER", "UNDO"}
@@ -163,10 +170,15 @@ class AddBrickRelation(bpy.types.Operator, tool.Ifc.Operator):
object = props.split_screen_bricks[props.split_screen_active_brick_index].uri
else:
object = props.namespace + props.new_brick_relation_object
core.add_brick_relation(tool.Brick, brick_uri=brick.uri, predicate=props.new_brick_relation_type, object=object)
core.add_brick_relation(
tool.Brick,
brick_uri=brick.uri,
predicate=props.new_brick_relation_type,
object=object
)
class ConvertIfcToBrick(bpy.types.Operator, tool.Ifc.Operator):
class ConvertIfcToBrick(bpy.types.Operator, Operator):
bl_idname = "bim.convert_ifc_to_brick"
bl_label = "Convert IFC To Brick"
bl_options = {"REGISTER", "UNDO"}
@@ -213,7 +225,7 @@ class NewBrickFile(bpy.types.Operator):
BrickStore.graph = data["graph"]
class RefreshBrickViewer(bpy.types.Operator, tool.Ifc.Operator):
class RefreshBrickViewer(bpy.types.Operator, Operator):
bl_idname = "bim.refresh_brick_viewer"
bl_label = "Refresh Brick Viewer"
bl_options = {"REGISTER", "UNDO"}
@@ -223,7 +235,7 @@ class RefreshBrickViewer(bpy.types.Operator, tool.Ifc.Operator):
core.refresh_brick_viewer(tool.Brick)
class RemoveBrick(bpy.types.Operator, tool.Ifc.Operator):
class RemoveBrick(bpy.types.Operator, Operator):
bl_idname = "bim.remove_brick"
bl_label = "Remove Brick"
bl_options = {"REGISTER", "UNDO"}
@@ -267,7 +279,7 @@ class SerializeBrick(bpy.types.Operator):
return "Save the Brick project"
class AddBrickNamespace(bpy.types.Operator, tool.Ifc.Operator):
class AddBrickNamespace(bpy.types.Operator, Operator):
bl_idname = "bim.add_brick_namespace"
bl_label = "Add Brick Namespace"
bl_description = "Bind a new namespace to the Brick project"
@@ -279,7 +291,7 @@ class AddBrickNamespace(bpy.types.Operator, tool.Ifc.Operator):
core.add_brick_namespace(tool.Brick, alias=alias, uri=uri)
class RemoveBrickRelation(bpy.types.Operator, tool.Ifc.Operator):
class RemoveBrickRelation(bpy.types.Operator, Operator):
bl_idname = "bim.remove_brick_relation"
bl_label = "Remove Relation"
bl_options = {"REGISTER", "UNDO"}
@@ -290,4 +302,4 @@ class RemoveBrickRelation(bpy.types.Operator, tool.Ifc.Operator):
def _execute(self, context):
props = context.scene.BIMBrickProperties
brick = props.bricks[props.active_brick_index]
core.remove_brick_relation(tool.Brick, brick_uri=brick.uri, predicate=self.predicate, object=self.object)
core.remove_brick_relation(tool.Brick, brick_uri=brick.uri, predicate=self.predicate, object=self.object)
@@ -55,7 +55,7 @@ class ClashDecorator:
batch.draw(shader)
def draw_text(self, context):
self.addon_prefs = tool.Blender.get_addon_preferences()
self.addon_prefs = context.preferences.addons["blenderbim"].preferences
selected_elements_color = self.addon_prefs.decorator_color_selected
unselected_elements_color = self.addon_prefs.decorator_color_unselected
special_elements_color = self.addon_prefs.decorator_color_special
@@ -75,7 +75,7 @@ class ClashDecorator:
blf.draw(font_id, text) # Set your text here
def draw_geometry(self, context):
self.addon_prefs = tool.Blender.get_addon_preferences()
self.addon_prefs = context.preferences.addons["blenderbim"].preferences
selected_elements_color = self.addon_prefs.decorator_color_selected
unselected_elements_color = self.addon_prefs.decorator_color_unselected
special_elements_color = self.addon_prefs.decorator_color_special
@@ -24,7 +24,14 @@ import blenderbim.bim.handler
from blenderbim.bim.ifc import IfcStore
class AddContext(bpy.types.Operator, tool.Ifc.Operator):
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class AddContext(bpy.types.Operator, Operator):
bl_idname = "bim.add_context"
bl_label = "Add Subcontext"
bl_options = {"REGISTER", "UNDO"}
@@ -43,7 +50,7 @@ class AddContext(bpy.types.Operator, tool.Ifc.Operator):
)
class RemoveContext(bpy.types.Operator, tool.Ifc.Operator):
class RemoveContext(bpy.types.Operator, Operator):
bl_idname = "bim.remove_context"
bl_label = "Remove Context"
bl_description = (
@@ -57,7 +64,7 @@ class RemoveContext(bpy.types.Operator, tool.Ifc.Operator):
core.remove_context(tool.Ifc, context=tool.Ifc.get().by_id(self.context))
class EnableEditingContext(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingContext(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_context"
bl_label = "Enable Editing Context"
bl_options = {"REGISTER", "UNDO"}
@@ -67,7 +74,7 @@ class EnableEditingContext(bpy.types.Operator, tool.Ifc.Operator):
core.enable_editing_context(tool.Context, context=tool.Ifc.get().by_id(self.context))
class DisableEditingContext(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingContext(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_context"
bl_label = "Disable Editing Context"
bl_options = {"REGISTER", "UNDO"}
@@ -76,7 +83,7 @@ class DisableEditingContext(bpy.types.Operator, tool.Ifc.Operator):
core.disable_editing_context(tool.Context)
class EditContext(bpy.types.Operator, tool.Ifc.Operator):
class EditContext(bpy.types.Operator, Operator):
bl_idname = "bim.edit_context"
bl_label = "Edit Context"
bl_options = {"REGISTER", "UNDO"}
@@ -28,6 +28,13 @@ from blenderbim.bim.ifc import IfcStore
import blenderbim.bim.handler
# declaring it here to avoid circular import problems
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class CoveringTool(WorkSpaceTool):
bl_space_type = "VIEW_3D"
bl_context_mode = "OBJECT"
@@ -46,19 +53,18 @@ class CoveringTool(WorkSpaceTool):
def draw_settings(cls, context, layout, ws_tool):
CoveringToolUI.draw(context, layout, ifc_element_type=cls.ifc_element_type)
def add_layout_hotkey(layout, text, hotkey, description):
args = ["covering", layout, text, hotkey, description]
tool.Blender.add_layout_hotkey_operator(*args)
class CoveringToolUI:
@classmethod
def draw(cls, context, layout, ifc_element_type=None):
def draw(cls, context, layout, ifc_element_type = None):
cls.layout = layout
cls.props = context.scene.BIMModelProperties
cls.covering_props = context.scene.BIMCoveringProperties
row = cls.layout.row(align=True)
if not tool.Ifc.get():
row.label(text="No IFC Project", icon="ERROR")
@@ -76,6 +82,8 @@ class CoveringToolUI:
cls.draw_default_interface()
@classmethod
def draw_header_interface(cls):
cls.draw_type_selection_interface()
@@ -87,35 +95,122 @@ class CoveringToolUI:
row = cls.layout.row(align=True)
row.prop(data=cls.covering_props, property="ceiling_height", text="Ceiling Height")
if AuthoringData.data["ifc_classes"]:
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
row.operator("bim.add_constr_type_instance", text="Add")
active_obj = bpy.context.active_object
element = tool.Ifc.get_entity(active_obj)
collection = bpy.context.view_layer.active_layer_collection.collection
collection_obj = collection.BIMCollectionProperties.obj
relating_type_id = int(cls.props.relating_type_id)
type_material_usage = ifcopenshell.util.element.get_material(tool.Ifc.get().by_id(relating_type_id)).is_a()
# PLEASE KEEP COMMENTS AS A REMINDER
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
# if (type_material_usage == "IfcMaterialLayerSet" and
# not bpy.context.selected_objects):
# row = cls.layout.row(align=True)
# row.label(text="", icon="EVENT_SHIFT")
# row.label(text="", icon="EVENT_A")
# if tool.Ifc.get_entity(collection_obj):
# if AuthoringData.data["predefined_type"] == "FLOORING":
# op = row.operator("bim.add_instance_flooring_covering_from_cursor")
# elif AuthoringData.data["predefined_type"] == "CEILING":
# op = row.operator("bim.add_instance_ceiling_covering_from_cursor")
# else:
# op = row.operator("bim.add_constr_type_instance", text="Add")
# op.from_invoke = True
# if cls.props.relating_type_id.isnumeric():
# op.relating_type_id = int(cls.props.relating_type_id)
#
# else:
# op = row.operator("bim.add_constr_type_instance", text="Add")
# op.from_invoke = True
# if cls.props.relating_type_id.isnumeric():
# op.relating_type_id = int(cls.props.relating_type_id)
#
# elif (AuthoringData.data["predefined_type"] == "FLOORING" and
# type_material_usage == "IfcMaterialLayerSet" and
# element and
# bpy.context.selected_objects and
# element.is_a("IfcWall")):
# row = cls.layout.row(align=True)
# row.label(text="", icon="EVENT_SHIFT")
# row.label(text="", icon="EVENT_A")
# op = row.operator("bim.add_instance_flooring_coverings_from_walls")
#
# elif (AuthoringData.data["predefined_type"] == "CEILING" and
# type_material_usage == "IfcMaterialLayerSet" and
# element and
# bpy.context.selected_objects and
# element.is_a("IfcWall")):
# row = cls.layout.row(align=True)
# row.label(text="", icon="EVENT_SHIFT")
# row.label(text="", icon="EVENT_A")
# op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
#
# elif (element and
# bpy.context.selected_objects and
# element.is_a("IfcCovering") and
## AuthoringData.data["predefined_type"] == "FLOORING" and
# AuthoringData.data["active_material_usage"] == "LAYER3"):
# row = cls.layout.row(align=True)
# row.label(text="", icon="EVENT_SHIFT")
# row.label(text="", icon="EVENT_G")
# op = row.operator("bim.regen_selected_covering_object")
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
row.operator("bim.add_instance_flooring_covering_from_cursor")
op = row.operator("bim.add_constr_type_instance", text="Add")
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
row.operator("bim.add_instance_ceiling_covering_from_cursor")
op = row.operator("bim.add_instance_flooring_covering_from_cursor")
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
row.operator("bim.add_instance_flooring_coverings_from_walls")
op = row.operator("bim.add_instance_ceiling_covering_from_cursor")
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
row.operator("bim.add_instance_ceiling_coverings_from_walls")
op = row.operator("bim.add_instance_flooring_coverings_from_walls")
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_A")
op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
row = cls.layout.row(align=True)
row.label(text="", icon="EVENT_SHIFT")
row.label(text="", icon="EVENT_G")
row.operator("bim.regen_selected_covering_object")
op = row.operator("bim.regen_selected_covering_object")
# elif AuthoringData.data["predefined_type"] == "CEILING":
# row = cls.layout.row(align=True)
# row.prop(data=cls.props, property="ceiling_height", text="ceiling height")
# if element and bpy.context.selected_objects and element.is_a("IfcWall"):
# op = row.operator("bim.add_instance_ceiling_coverings_from_walls")
# elif element and bpy.context.selected_objects and element.is_a("IfcSpace"):
# op. = row.operator("bim.add_istance_flooring_from_spaces"):
# else:
# op = row.operator("bim.add_instance_ceiling_from_cursor")
# op = row.operator("bim.add_constr_type_instance", text="Add")
# op.from_invoke = True
# if cls.props.relating_type_id.isnumeric():
# op.relating_type_id = int(cls.props.relating_type_id)
# else:
# row = cls.layout.row(align=True)
# row.label(text="", icon="EVENT_SHIFT")
# row.label(text="", icon="EVENT_A")
# op = row.operator("bim.add_constr_type_instance", text="Add")
# op.from_invoke = True
# if cls.props.relating_type_id.isnumeric():
# op.relating_type_id = int(cls.props.relating_type_id)
@classmethod
def draw_type_selection_interface(cls):
@@ -145,7 +240,7 @@ class CoveringToolUI:
op.ifc_class = cls.props.ifc_class
class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
class Hotkey(bpy.types.Operator, Operator):
bl_idname = "bim.covering_hotkey"
bl_label = "Hotkey"
bl_options = {"REGISTER", "UNDO"}
@@ -161,7 +256,7 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
return operator.description or ""
def _execute(self, context):
# self.props = context.scene.BIMCoveringProperties
# self.props = context.scene.BIMCoveringProperties
getattr(self, f"hotkey_{self.hotkey}")()
def invoke(self, context, event):
@@ -175,19 +270,20 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
def hotkey_S_A(self):
active_obj = bpy.context.active_object
element = tool.Ifc.get_entity(active_obj)
container = tool.Root.get_default_container()
collection = bpy.context.view_layer.active_layer_collection.collection
collection_obj = collection.BIMCollectionProperties.obj
if AuthoringData.data["predefined_type"] == "FLOORING":
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
bpy.ops.bim.add_instance_flooring_coverings_from_walls()
elif container:
elif tool.Ifc.get_entity(collection_obj):
bpy.ops.bim.add_instance_flooring_covering_from_cursor()
else:
bpy.ops.bim.add_constr_type_instance()
elif AuthoringData.data["predefined_type"] == "CEILING":
if element and bpy.context.selected_objects and element.is_a("IfcWall"):
bpy.ops.bim.add_instance_ceiling_coverings_from_walls()
elif container:
elif tool.Ifc.get_entity(collection_obj):
bpy.ops.bim.add_instance_ceiling_covering_from_cursor()
else:
bpy.ops.bim.add_constr_type_instance()
@@ -197,10 +293,9 @@ class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
def hotkey_S_G(self):
active_obj = bpy.context.active_object
element = tool.Ifc.get_entity(active_obj)
if (
element
and bpy.context.selected_objects
and element.is_a("IfcCovering")
and AuthoringData.data["active_material_usage"] == "LAYER3"
):
bpy.ops.bim.regen_selected_covering_object()
if (element and
bpy.context.selected_objects and
element.is_a("IfcCovering") and
AuthoringData.data["active_material_usage"] == "LAYER3"):
bpy.ops.bim.regen_selected_covering_object()
@@ -185,8 +185,6 @@ class ExportIfcCsv(bpy.types.Operator):
def invoke(self, context, event):
props = context.scene.CsvProperties
if props.format == "web":
return self.execute(context)
self.filepath = bpy.path.ensure_ext(bpy.data.filepath, f".{props.format}")
WindowManager = context.window_manager
WindowManager.fileselect_add(self)
@@ -224,10 +222,6 @@ class ExportIfcCsv(bpy.types.Operator):
if attribute.formatting != "{{value}}" and "{{value}}" in attribute.formatting:
formatting.append({"name": attribute.name, "format": attribute.formatting})
file_format = props.format
if props.format == "web":
file_format = "pd"
sep = props.csv_custom_delimiter if props.csv_delimiter == "CUSTOM" else props.csv_delimiter
ifc_csv.export(
ifc_file,
@@ -235,7 +229,7 @@ class ExportIfcCsv(bpy.types.Operator):
attributes,
headers=headers,
output=self.filepath,
format=file_format,
format=props.format,
should_preserve_existing=props.should_preserve_existing,
delimiter=sep,
include_global_id=props.include_global_id,
@@ -253,10 +247,6 @@ class ExportIfcCsv(bpy.types.Operator):
if props.format != "csv" and props.should_generate_svg:
schedule_creator = scheduler.Scheduler()
schedule_creator.schedule(self.filepath, tool.Drawing.get_path_with_ext(self.filepath, "svg"))
if props.format == "web":
tool.Web.send_webui_data(
extra_data=ifc_csv.dataframe.to_csv(index=False), extra_data_key="csv_data", event="csv_data"
)
self.report({"INFO"}, f"Data is exported to {props.format.upper()}.")
return {"FINISHED"}
@@ -88,7 +88,6 @@ class CsvProperties(PropertyGroup):
("csv", "csv", ""),
("xlsx", "xlsx", ""),
("ods", "ods", ""),
("web", "web", ""),
],
name="Output format",
default="csv",
@@ -87,11 +87,6 @@ class BIM_PT_ifccsv(Panel):
blenderbim.bim.helper.draw_filter(self.layout, props.filter_groups, SearchData, "csv")
row = layout.row(align=True)
op = row.operator("bim.search", text="Select", icon="VIEWZOOM")
op.property_group = "CsvProperties"
layout.separator()
row = layout.row(align=True)
row.operator("bim.add_csv_attribute", icon="ADD")
row.prop(props, "should_show_sort", icon="SORTSIZE", text="")
@@ -128,6 +123,3 @@ class BIM_PT_ifccsv(Panel):
row = layout.row(align=True)
row.operator("bim.export_ifccsv", icon="EXPORT", text="Export IFC to " + props.format.upper())
row.operator("bim.import_ifccsv", icon="IMPORT")
@@ -40,7 +40,6 @@ classes = (
operator.SelectExpressFile,
operator.SelectHighPolygonMeshes,
operator.SelectHighestPolygonMeshes,
operator.ToggleDetailedIOSLogs,
operator.ValidateIfcFile,
prop.BIMDebugProperties,
ui.BIM_PT_debug,
@@ -26,7 +26,6 @@ import platform
import subprocess
import ifcopenshell
import ifcopenshell.api
import ifcopenshell.geom
import ifcopenshell.util.element
import ifcopenshell.util.placement
import ifcopenshell.util.representation
@@ -34,7 +33,6 @@ import blenderbim.tool as tool
import blenderbim.core.debug as core
import blenderbim.bim.handler
import blenderbim.bim.import_ifc as import_ifc
from pathlib import Path
from blenderbim import get_debug_info, format_debug_info
from blenderbim.bim.ifc import IfcStore
@@ -91,11 +89,12 @@ class ConvertToBlender(bpy.types.Operator):
def execute(self, context):
for obj in bpy.data.objects:
if obj.type in {"MESH", "EMPTY"}:
tool.Ifc.unlink(obj=obj)
obj.BIMObjectProperties.ifc_definition_id = 0
if obj.data:
obj.data.BIMMeshProperties.ifc_definition_id = 0
for material in bpy.data.materials:
tool.Ifc.unlink(obj=material)
material.BIMObjectProperties.ifc_definition_id = 0
material.BIMMaterialProperties.ifc_style_id = 0
context.scene.BIMProperties.ifc_file = ""
context.scene.BIMDebugProperties.attributes.clear()
IfcStore.purge()
@@ -140,30 +139,20 @@ class ValidateIfcFile(bpy.types.Operator):
class ProfileImportIFC(bpy.types.Operator):
profile_filename = "blender.prof"
bl_idname = "bim.profile_import_ifc"
bl_label = "Profile Import IFC"
bl_description = f"Reload currently loaded project and save cprofile stats for reloading to '{profile_filename}'"
@classmethod
def poll(cls, context):
if not tool.Ifc.get():
cls.poll_message_set("No IFC file loaded.")
return False
if not context.scene.BIMProperties.ifc_file:
cls.poll_message_set("Current IFC file is not saved.")
return False
return True
return IfcStore.get_file() and context.scene.BIMProperties.ifc_file
def execute(self, context):
import cProfile
import pstats
profile_file = Path(profile_filename)
cProfile.run("import bpy; bpy.ops.bim.load_project_elements()", str(profile_file))
p = pstats.Stats(str(profile_file))
cProfile.run("import bpy; bpy.ops.bim.load_project_elements()", "blender.prof")
p = pstats.Stats("blender.prof")
p.sort_stats("cumulative").print_stats(50)
self.report({"INFO"}, f'Profile stats are saved to "{profile_file.absolute()}".')
return {"FINISHED"}
@@ -182,9 +171,8 @@ class CreateAllShapes(bpy.types.Operator):
total = len(elements)
settings = ifcopenshell.geom.settings()
settings.set("keep-bounding-boxes", True)
settings_2d = ifcopenshell.geom.settings()
settings_2d.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
settings_2d.set(settings_2d.INCLUDE_CURVES, True)
failures = []
excludes = () # For the developer to debug with
for i, element in enumerate(elements, 1):
@@ -236,9 +224,8 @@ class CreateShapeFromStepId(bpy.types.Operator):
self.file = IfcStore.get_file()
element = self.file.by_id(self.step_id or int(context.scene.BIMDebugProperties.step_id))
settings = ifcopenshell.geom.settings()
settings.set("keep-bounding-boxes", True)
if self.should_include_curves:
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
settings.set(settings.INCLUDE_CURVES, True)
shape = ifcopenshell.geom.create_shape(settings, element)
if shape:
ifc_importer = import_ifc.IfcImporter(self.ifc_import_settings)
@@ -672,9 +659,7 @@ class DebugActiveDrawing(bpy.types.Operator):
def drawing_fails_to_load(chunk_to_include: set) -> bool:
current_elements = all_elements - chunk_to_include
excluded_guids = ", ".join([e.GlobalId for e in current_elements if hasattr(e, "GlobalId")])
new_exclude = "" if not original_exclude else f"{original_exclude}, "
new_exclude += excluded_guids
tool.Ifc.run("pset.edit_pset", pset=pset, properties={"Exclude": new_exclude})
tool.Ifc.run("pset.edit_pset", pset=pset, properties={"Exclude": f"{original_exclude}, {excluded_guids}"})
try:
bpy.ops.bim.create_drawing(sync=False)
@@ -737,36 +722,3 @@ class DebugActiveDrawing(bpy.types.Operator):
self.report({"INFO"}, "See system console for the results")
return {"FINISHED"}
class ToggleDetailedIOSLogs(bpy.types.Operator):
bl_idname = "bim.toggle_detailed_ios_logs"
bl_label = "Toggle Detailed IfcOpenShell Logs"
bl_options = {"REGISTER", "UNDO"}
bl_description = (
"Turn on detailed IfcOpenShell logs in the system console.\n"
+ "Could be useful debugging issues "
+ "loading IFC representations / serializing IFC geometry."
+ "\n\nALT+CLICK to disable the logs"
)
# NOTE: No idea if it's possible to check from Python
# whether detailed logs are currently enabled or not.
# Therefore we just distinguish between click
# and alt-click to allow enabling/disabling the logs.
turn_on_logs: bpy.props.BoolProperty(name="Turn On Logs", default=True, options={"SKIP_SAVE"})
def invoke(self, context, event):
if event.type == "LEFTMOUSE" and event.alt:
self.turn_on_logs = False
return self.execute(context)
def execute(self, context):
import ifcopenshell.ifcopenshell_wrapper as wrapper
if self.turn_on_logs:
wrapper.turn_on_detailed_logging()
self.report({"INFO"}, "Detailed IfcOpenShell logs turned on.")
else:
wrapper.turn_off_detailed_logging()
self.report({"INFO"}, "Detailed IfcOpenShell logs turned off.")
return {"FINISHED"}
@@ -75,9 +75,6 @@ class BIM_PT_debug(Panel):
row = layout.row()
row.operator("bim.debug_active_drawing")
row = layout.row()
row.operator("bim.toggle_detailed_ios_logs")
row = layout.split(factor=0.5, align=True)
row.operator("bim.create_shape_from_step_id").should_include_curves = False
row.operator("bim.create_shape_from_step_id", text="", icon="IPO_ELASTIC").should_include_curves = True
@@ -188,6 +188,7 @@ class ExecuteIfcDiff(bpy.types.Operator):
tool.Ifc.set(ifc_diff.old)
ifc_importer.file = ifc_diff.old
ifc_importer.process_context_filter()
ifc_importer.create_materials()
ifc_importer.create_styles()
elements = {ifc_diff.old.by_guid(guid) for guid in ifc_diff.deleted_elements}
@@ -203,6 +204,7 @@ class ExecuteIfcDiff(bpy.types.Operator):
tool.Ifc.set(ifc_diff.new)
ifc_importer.file = ifc_diff.new
ifc_importer.process_context_filter()
ifc_importer.create_materials()
ifc_importer.create_styles()
elements = {ifc_diff.new.by_guid(guid) for guid in ifc_diff.added_elements}
@@ -71,8 +71,6 @@ classes = (
operator.OpenReference,
operator.OpenSchedule,
operator.OpenSheet,
operator.OrderTextLiteralDown,
operator.OrderTextLiteralUp,
operator.ReloadDrawingStyles,
operator.RemoveDrawing,
operator.RemoveDrawingFromSheet,
@@ -335,7 +335,7 @@ class BaseDecorator:
"""`verts` should be in winspace with `(0,0,0)` in the screen left bottom corner, not in the center"""
region = context.region
if not color:
color = tool.Blender.get_addon_preferences().decorations_colour
color = context.preferences.addons["blenderbim"].preferences.decorations_colour
self.line_shader.bind()
# POLYLINE_UNIFORM_COLOR specific uniforms
@@ -404,7 +404,7 @@ class BaseDecorator:
font_id = self.font_id
color = tool.Blender.get_addon_preferences().decorations_colour
color = context.preferences.addons["blenderbim"].preferences.decorations_colour
ang = -Vector((1, 0)).angle_signed(text_dir)
cos = math.cos(ang)
@@ -812,7 +812,7 @@ class AngleDecorator(BaseDecorator):
arcs_color = None
edges_color = UNSPECIAL_ELEMENT_COLOR
if context.active_object == obj and obj.data.is_editmode:
arcs_color = tool.Blender.get_addon_preferences().decorator_color_special
arcs_color = context.preferences.addons["blenderbim"].preferences.decorator_color_special
edges_color = None
self.draw_lines(
@@ -1093,7 +1093,7 @@ class HiddenDecorator(BaseDecorator):
else:
verts, idxs = self.get_mesh_geom(obj)
winspace_verts = worldspace_to_winspace(verts, context)
color = [i for i in tool.Blender.get_addon_preferences().decorations_colour]
color = [i for i in context.preferences.addons["blenderbim"].preferences.decorations_colour]
color[3] = 0.5
self.draw_lines(context, obj, winspace_verts, idxs, color)
@@ -1409,7 +1409,7 @@ class GridDecorator(BaseDecorator):
# stem with gaps for circles
add_verts_sequence([v0 + gap, v1 - gap], start_i, **out_kwargs)
color = [i for i in tool.Blender.get_addon_preferences().decorations_colour]
color = [i for i in context.preferences.addons["blenderbim"].preferences.decorations_colour]
color[3] = 0.5
self.draw_lines(context, obj, output_verts, output_edges, color)
self.draw_labels(context, obj, verts)
@@ -1591,7 +1591,7 @@ class CutDecorator:
cls.installed = None
def __call__(self, context):
self.addon_prefs = tool.Blender.get_addon_preferences()
self.addon_prefs = context.preferences.addons["blenderbim"].preferences
selected_elements_color = self.addon_prefs.decorator_color_selected
all_vertices = []
@@ -121,13 +121,7 @@ class BoundingBox:
# This function stolen from https://github.com/kevancress/MeasureIt_ARCH/blob/dcf607ce0896aa2284463c6b4ae9cd023fc54cbe/measureit_arch_baseclass.py
# MeasureIt-ARCH is GPL-v3
def format_distance(
value,
isArea=False,
hide_units=True,
precision=None,
decimal_places=None,
suppress_zero_inches=False,
in_unit_length = False
value, isArea=False, hide_units=True, precision=None, decimal_places=None, suppress_zero_inches=False
):
s_code = "\u00b2" # Superscript two THIS IS LEGACY (but being kept for when Area Measurements are re-implimented)
@@ -136,22 +130,17 @@ def format_distance(
unit_system = bpy.context.scene.unit_settings.system
unit_length = bpy.context.scene.unit_settings.length_unit
toInches = 39.3700787401574887
inPerFoot = 11.9999
if isArea:
toInches = 1550
inPerFoot = 143.999
value *= scaleFactor
# Imperial Formatting
if unit_system == "IMPERIAL":
if in_unit_length:
if unit_length == 'INCHES':
toInches = 1
if unit_length == 'FEET':
toInches = 11.9999
else:
toInches = 39.3700787401574887
inPerFoot = 11.9999
if isArea:
toInches = 1550
inPerFoot = 143.999
if not precision:
precision = 256
elif precision == "1":
@@ -221,12 +210,6 @@ def format_distance(
# METRIC FORMATTING
elif unit_system == "METRIC":
if in_unit_length:
if unit_length == 'CENTIMETERS':
value = value/100
if unit_length == 'MILLIMETERS':
value = value/1000
if precision:
value = precision * round(float(value) / precision)
@@ -46,11 +46,11 @@ import blenderbim.bim.module.drawing.helper as helper
import blenderbim.bim.export_ifc
from blenderbim.bim.module.drawing.decoration import CutDecorator
from blenderbim.bim.module.drawing.data import DecoratorData, DrawingsData
from typing import NamedTuple, List, Union, Optional, Literal
from typing import NamedTuple, List, Union, Optional
from lxml import etree
from mathutils import Vector, Color, Matrix
from timeit import default_timer as timer
from blenderbim.bim.module.drawing.prop import RasterStyleProperty, RASTER_STYLE_PROPERTIES_EXCLUDE
from blenderbim.bim.module.drawing.prop import RasterStyleProperty, Literal, RASTER_STYLE_PROPERTIES_EXCLUDE
from blenderbim.bim.ifc import IfcStore
from pathlib import Path
from bpy_extras.image_utils import load_image
@@ -73,12 +73,19 @@ class profile:
print(self.task, timer() - self.start)
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class LineworkContexts(NamedTuple):
body: List[List[int]]
annotation: List[List[int]]
class AddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
class AddAnnotationType(bpy.types.Operator, Operator):
bl_idname = "bim.add_annotation_type"
bl_label = "Add Annotation Type"
bl_options = {"REGISTER", "UNDO"}
@@ -109,7 +116,7 @@ class AddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.add_reference_image("INVOKE_DEFAULT", use_existing_object_by_name=obj.name)
class EnableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
class EnableAddAnnotationType(bpy.types.Operator, Operator):
bl_idname = "bim.enable_add_annotation_type"
bl_label = "Enable Add Annotation Type"
bl_options = {"REGISTER", "UNDO"}
@@ -118,7 +125,7 @@ class EnableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
bpy.context.scene.BIMAnnotationProperties.is_adding_type = True
class DisableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
class DisableAddAnnotationType(bpy.types.Operator, Operator):
bl_idname = "bim.disable_add_annotation_type"
bl_label = "Disable Add Annotation Type"
bl_options = {"REGISTER", "UNDO"}
@@ -127,7 +134,7 @@ class DisableAddAnnotationType(bpy.types.Operator, tool.Ifc.Operator):
bpy.context.scene.BIMAnnotationProperties.is_adding_type = False
class AddDrawing(bpy.types.Operator, tool.Ifc.Operator):
class AddDrawing(bpy.types.Operator, Operator):
bl_idname = "bim.add_drawing"
bl_label = "Add Drawing"
bl_options = {"REGISTER", "UNDO"}
@@ -151,7 +158,7 @@ class AddDrawing(bpy.types.Operator, tool.Ifc.Operator):
pass
class DuplicateDrawing(bpy.types.Operator, tool.Ifc.Operator):
class DuplicateDrawing(bpy.types.Operator, Operator):
bl_idname = "bim.duplicate_drawing"
bl_label = "Duplicate Drawing"
bl_options = {"REGISTER", "UNDO"}
@@ -271,7 +278,9 @@ class CreateDrawing(bpy.types.Operator):
with profile("Combine SVG layers"):
svg_path = self.combine_svgs(context, underlay_svg, linework_svg, annotation_svg)
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg_path)
tool.Drawing.open_with_user_command(
context.preferences.addons["blenderbim"].preferences.svg_command, svg_path
)
if self.print_all:
bpy.ops.bim.activate_drawing(drawing=original_drawing_id, camera_view_point=False)
@@ -456,25 +465,25 @@ class CreateDrawing(bpy.types.Operator):
ifc: ifcopenshell.file,
tree: ifcopenshell.geom.tree,
contexts: LineworkContexts,
context_type: Literal["body", "annotation"],
context_type: str,
drawing_elements: set[ifcopenshell.entity_instance],
target_view: str,
) -> None:
drawing_elements = drawing_elements.copy()
contexts: list[list[int]] = getattr(contexts, context_type)
contexts = getattr(contexts, context_type)
for context in contexts:
with profile(f"Processing {context_type} context"):
if not context or not drawing_elements:
continue
geom_settings = ifcopenshell.geom.settings()
geom_settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
geom_settings.set("iterator-output", ifcopenshell.ifcopenshell_wrapper.NATIVE)
geom_settings = ifcopenshell.geom.settings(
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
)
if ifc.by_id(context[0]).ContextType == "Plan" and "PLAN_VIEW" in target_view:
offset = ifcopenshell.ifcopenshell_wrapper.float_array_3()
# A 2mm Z offset to combat Z-fighting in plan or RCPs
offset[2] = 0.002 if target_view == "PLAN_VIEW" else -0.002
geom_settings.offset = offset
geom_settings.set("context-ids", context)
geom_settings.set_context_ids(context)
it = ifcopenshell.geom.iterator(
geom_settings, ifc, multiprocessing.cpu_count(), include=drawing_elements
)
@@ -498,7 +507,7 @@ class CreateDrawing(bpy.types.Operator):
# All very hackish whilst prototyping
exporter = blenderbim.bim.export_ifc.IfcExporter(None)
exporter.file = tool.Ifc.get()
invalidated_elements = exporter.sync_all_objects()
invalidated_elements = exporter.sync_all_objects(skip_unlinking=True)
invalidated_elements += exporter.sync_edited_objects()
invalidated_guids = [e.GlobalId for e in invalidated_elements if hasattr(e, "GlobalId")]
cache = IfcStore.get_cache()
@@ -552,8 +561,7 @@ class CreateDrawing(bpy.types.Operator):
if tool.Ifc.get() == ifc and self.camera_element not in drawing_elements:
with profile("Camera element"):
# The camera must always be included, regardless of any include/exclude filters.
geom_settings = ifcopenshell.geom.settings()
geom_settings.set("iterator-output", ifcopenshell.ifcopenshell_wrapper.NATIVE)
geom_settings = ifcopenshell.geom.settings(DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True)
it = ifcopenshell.geom.iterator(geom_settings, ifc, include=[self.camera_element])
for elem in it:
self.serialiser.write(elem)
@@ -866,14 +874,11 @@ class CreateDrawing(bpy.types.Operator):
return svg_path
def setup_serialiser(self, target_view):
self.svg_settings = ifcopenshell.geom.settings()
self.svg_settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
self.svg_settings.set("iterator-output", ifcopenshell.ifcopenshell_wrapper.NATIVE)
self.svg_buffer = ifcopenshell.geom.serializers.buffer()
self.serialiser_settings = ifcopenshell.geom.serializer_settings()
self.serialiser = ifcopenshell.geom.serializers.svg(
self.svg_buffer, self.svg_settings, self.serialiser_settings
self.svg_settings = ifcopenshell.geom.settings(
DISABLE_TRIANGULATION=True, STRICT_TOLERANCE=True, INCLUDE_CURVES=True
)
self.svg_buffer = ifcopenshell.geom.serializers.buffer()
self.serialiser = ifcopenshell.geom.serializers.svg(self.svg_buffer, self.svg_settings)
self.serialiser.setWithoutStoreys(True)
self.serialiser.setPolygonal(True)
self.serialiser.setUseHlrPoly(True)
@@ -977,7 +982,7 @@ class CreateDrawing(bpy.types.Operator):
obj = tool.Ifc.get_object(element)
if not obj: # This is a linked model object. For now, do nothing.
if not obj: # This is a linked model object. For now, do nothing.
continue
if not self.is_manifold(obj):
@@ -1176,7 +1181,7 @@ class CreateDrawing(bpy.types.Operator):
return drawing_path
class AddAnnotation(bpy.types.Operator, tool.Ifc.Operator):
class AddAnnotation(bpy.types.Operator, Operator):
bl_idname = "bim.add_annotation"
bl_label = "Add Annotation"
bl_options = {"REGISTER", "UNDO"}
@@ -1203,7 +1208,7 @@ class AddAnnotation(bpy.types.Operator, tool.Ifc.Operator):
self.report({"WARNING"}, r)
class AddSheet(bpy.types.Operator, tool.Ifc.Operator):
class AddSheet(bpy.types.Operator, Operator):
bl_idname = "bim.add_sheet"
bl_label = "Add Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -1212,7 +1217,7 @@ class AddSheet(bpy.types.Operator, tool.Ifc.Operator):
core.add_sheet(tool.Ifc, tool.Drawing, titleblock=context.scene.DocProperties.titleblock)
class OpenSheet(bpy.types.Operator, tool.Ifc.Operator):
class OpenSheet(bpy.types.Operator, Operator):
bl_idname = "bim.open_sheet"
bl_label = "Open Sheet Layout"
bl_options = {"REGISTER", "UNDO"}
@@ -1225,7 +1230,7 @@ class OpenSheet(bpy.types.Operator, tool.Ifc.Operator):
core.open_sheet(tool.Drawing, sheet=sheet)
class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
class AddDrawingToSheet(bpy.types.Operator, Operator):
bl_idname = "bim.add_drawing_to_sheet"
bl_label = "Add Drawing To Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -1277,7 +1282,7 @@ class AddDrawingToSheet(bpy.types.Operator, tool.Ifc.Operator):
tool.Drawing.import_sheets()
class RemoveDrawingFromSheet(bpy.types.Operator, tool.Ifc.Operator):
class RemoveDrawingFromSheet(bpy.types.Operator, Operator):
bl_idname = "bim.remove_drawing_from_sheet"
bl_label = "Remove Drawing From Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -1296,7 +1301,7 @@ class RemoveDrawingFromSheet(bpy.types.Operator, tool.Ifc.Operator):
tool.Drawing.import_sheets()
class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
class CreateSheets(bpy.types.Operator, Operator):
bl_idname = "bim.create_sheets"
bl_label = "Create Sheets"
bl_description = "Build a sheet from the sheet layout"
@@ -1365,8 +1370,8 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
),
)
svg2pdf_command = tool.Blender.get_addon_preferences().svg2pdf_command
svg2dxf_command = tool.Blender.get_addon_preferences().svg2dxf_command
svg2pdf_command = context.preferences.addons["blenderbim"].preferences.svg2pdf_command
svg2dxf_command = context.preferences.addons["blenderbim"].preferences.svg2dxf_command
if svg2pdf_command:
# With great power comes great responsibility. Example:
@@ -1384,9 +1389,9 @@ class CreateSheets(bpy.types.Operator, tool.Ifc.Operator):
subprocess.run([replacements.get(c, c) for c in command])
if svg2pdf_command:
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().pdf_command, pdf)
tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.pdf_command, pdf)
else:
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, svg)
tool.Drawing.open_with_user_command(context.preferences.addons["blenderbim"].preferences.svg_command, svg)
class SelectAllDrawings(bpy.types.Operator):
@@ -1453,7 +1458,9 @@ class OpenDrawing(bpy.types.Operator):
return {"CANCELLED"}
for drawing_uri in drawing_uris:
tool.Drawing.open_with_user_command(tool.Blender.get_addon_preferences().svg_command, drawing_uri)
tool.Drawing.open_with_user_command(
context.preferences.addons["blenderbim"].preferences.svg_command, drawing_uri
)
return {"FINISHED"}
@@ -1512,47 +1519,48 @@ class ActivateDrawing(bpy.types.Operator):
bl_idname = "bim.activate_drawing"
bl_label = "Activate Drawing"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Activates the selected drawing view.\n\n" + "ALT+CLICK to keep the viewport position"
bl_description = "Activates the selected drawing view.\n\n" + "ALT+CLICK to keep the viewport position.\n\n" + "SHIFT+CLICK activiate drawing without turning objects on/off."
drawing: bpy.props.IntProperty()
camera_view_point: bpy.props.BoolProperty(name="Camera View Point", default=True, options={"SKIP_SAVE"})
switch_camera_only: bpy.props.BoolProperty(name="Only Changes Camera View", default=False, options={"SKIP_SAVE"})
def invoke(self, context, event):
# keep the viewport position on alt+click
# make sure to use SKIP_SAVE on property, otherwise it might get stuck
if event.type == "LEFTMOUSE" and event.alt:
self.camera_view_point = False
# Only activates the camera view on alt+shift. Does not turn on/off objects in scene
if event.type == "LEFTMOUSE" and event.shift:
self.switch_camera_only = True
return self.execute(context)
def execute(self, context):
drawing = tool.Ifc.get().by_id(self.drawing)
dprops = bpy.context.scene.DocProperties
camera = tool.Drawing.import_drawing(drawing)
if not self.camera_view_point:
viewport_position = tool.Blender.get_viewport_position()
if self.switch_camera_only:
tool.Blender.activate_camera(camera)
else:
if not self.camera_view_point:
viewport_position = tool.Blender.get_viewport_position()
core.activate_drawing_view(tool.Ifc, tool.Blender, tool.Drawing, drawing=drawing)
if not self.camera_view_point:
tool.Blender.set_viewport_position(viewport_position)
dprops.active_drawing_id = self.drawing
# reset DrawingsData to reload_drawing_styles work correctly
DrawingsData.is_loaded = False
dprops.drawing_styles.clear()
if ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing", "HasUnderlay"):
bpy.ops.bim.reload_drawing_styles()
bpy.ops.bim.activate_drawing_style()
core.sync_references(tool.Ifc, tool.Collector, tool.Drawing, drawing=tool.Ifc.get().by_id(self.drawing))
CutDecorator.install(context)
tool.Drawing.show_decorations()
# Save drawing bounds to the .ifc file
camera = context.scene.camera
camera_props = camera.data.BIMCameraProperties
if camera_props.update_representation(camera):
bpy.ops.bim.update_representation(obj=camera.name, ifc_representation_class="")
if not self.camera_view_point:
tool.Blender.set_viewport_position(viewport_position)
dprops.active_drawing_id = self.drawing
# reset DrawingsData to reload_drawing_styles work correctly
DrawingsData.is_loaded = False
dprops.drawing_styles.clear()
if ifcopenshell.util.element.get_pset(drawing, "EPset_Drawing", "HasUnderlay"):
bpy.ops.bim.reload_drawing_styles()
bpy.ops.bim.activate_drawing_style()
core.sync_references(tool.Ifc, tool.Collector, tool.Drawing, drawing=tool.Ifc.get().by_id(self.drawing))
CutDecorator.install(context)
tool.Drawing.show_decorations()
return {"FINISHED"}
@@ -1586,7 +1594,7 @@ class ResizeText(bpy.types.Operator):
return {"FINISHED"}
class RemoveDrawing(bpy.types.Operator, tool.Ifc.Operator):
class RemoveDrawing(bpy.types.Operator, Operator):
bl_idname = "bim.remove_drawing"
bl_label = "Remove Drawing"
bl_options = {"REGISTER", "UNDO"}
@@ -1689,7 +1697,7 @@ class ReloadDrawingStyles(bpy.types.Operator):
return {"FINISHED"}
class AddDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
class AddDrawingStyle(bpy.types.Operator, Operator):
bl_idname = "bim.add_drawing_style"
bl_label = "Add Drawing Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1703,7 +1711,7 @@ class AddDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class RemoveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
class RemoveDrawingStyle(bpy.types.Operator, Operator):
bl_idname = "bim.remove_drawing_style"
bl_label = "Remove Drawing Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1716,7 +1724,7 @@ class RemoveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class SaveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
class SaveDrawingStyle(bpy.types.Operator, Operator):
bl_idname = "bim.save_drawing_style"
bl_label = "Save Drawing Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1781,7 +1789,7 @@ class SaveDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
return space
class SaveDrawingStylesData(bpy.types.Operator, tool.Ifc.Operator):
class SaveDrawingStylesData(bpy.types.Operator, Operator):
bl_idname = "bim.save_drawing_styles_data"
bl_label = "Save Drawing Styles Data"
bl_options = {"REGISTER", "UNDO"}
@@ -1834,7 +1842,7 @@ class SaveDrawingStylesData(bpy.types.Operator, tool.Ifc.Operator):
return {"FINISHED"}
class ActivateDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
class ActivateDrawingStyle(bpy.types.Operator, Operator):
bl_idname = "bim.activate_drawing_style"
bl_label = "Activate Drawing Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1884,10 +1892,10 @@ class ActivateDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
except:
continue
if self.drawing_style.include_query:
results = ifcopenshell.util.selector.filter_elements(ifc, self.drawing_style.include_query)
results = ifcopenshell.util.selector.Selector.parse(ifc, self.drawing_style.include_query)
self.include_global_ids.extend([e.GlobalId for e in results])
if self.drawing_style.exclude_query:
results = ifcopenshell.util.selector.filter_elements(ifc, self.drawing_style.exclude_query)
results = ifcopenshell.util.selector.Selector.parse(ifc, self.drawing_style.exclude_query)
self.exclude_global_ids.extend([e.GlobalId for e in results])
if self.drawing_style.include_query:
self.parse_filter_query("INCLUDE", context)
@@ -1923,7 +1931,7 @@ class ActivateDrawingStyle(bpy.types.Operator, tool.Ifc.Operator):
return space
class RemoveSheet(bpy.types.Operator, tool.Ifc.Operator):
class RemoveSheet(bpy.types.Operator, Operator):
bl_idname = "bim.remove_sheet"
bl_label = "Remove Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -1933,7 +1941,7 @@ class RemoveSheet(bpy.types.Operator, tool.Ifc.Operator):
core.remove_sheet(tool.Ifc, tool.Drawing, sheet=tool.Ifc.get().by_id(self.sheet))
class AddSchedule(bpy.types.Operator, tool.Ifc.Operator):
class AddSchedule(bpy.types.Operator, Operator):
bl_idname = "bim.add_schedule"
bl_label = "Add Schedule"
bl_options = {"REGISTER", "UNDO"}
@@ -1963,7 +1971,7 @@ class AddSchedule(bpy.types.Operator, tool.Ifc.Operator):
return {"RUNNING_MODAL"}
class RemoveSchedule(bpy.types.Operator, tool.Ifc.Operator):
class RemoveSchedule(bpy.types.Operator, Operator):
bl_idname = "bim.remove_schedule"
bl_label = "Remove Schedule"
bl_options = {"REGISTER", "UNDO"}
@@ -1973,7 +1981,7 @@ class RemoveSchedule(bpy.types.Operator, tool.Ifc.Operator):
core.remove_document(tool.Ifc, tool.Drawing, "SCHEDULE", document=tool.Ifc.get().by_id(self.schedule))
class OpenSchedule(bpy.types.Operator, tool.Ifc.Operator):
class OpenSchedule(bpy.types.Operator, Operator):
bl_idname = "bim.open_schedule"
bl_label = "Open Schedule"
bl_options = {"REGISTER", "UNDO"}
@@ -1983,7 +1991,7 @@ class OpenSchedule(bpy.types.Operator, tool.Ifc.Operator):
core.open_schedule(tool.Drawing, schedule=tool.Ifc.get().by_id(self.schedule))
class BuildSchedule(bpy.types.Operator, tool.Ifc.Operator):
class BuildSchedule(bpy.types.Operator, Operator):
bl_idname = "bim.build_schedule"
bl_label = "Build Schedule"
schedule: bpy.props.IntProperty()
@@ -1992,7 +2000,7 @@ class BuildSchedule(bpy.types.Operator, tool.Ifc.Operator):
core.build_schedule(tool.Drawing, schedule=tool.Ifc.get().by_id(self.schedule))
class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
class AddScheduleToSheet(bpy.types.Operator, Operator):
bl_idname = "bim.add_schedule_to_sheet"
bl_label = "Add Schedule To Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -2048,7 +2056,7 @@ class AddScheduleToSheet(bpy.types.Operator, tool.Ifc.Operator):
tool.Drawing.import_sheets()
class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
class AddReferenceToSheet(bpy.types.Operator, Operator):
bl_idname = "bim.add_reference_to_sheet"
bl_label = "Add Reference To Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -2105,7 +2113,7 @@ class AddReferenceToSheet(bpy.types.Operator, tool.Ifc.Operator):
tool.Drawing.import_sheets()
class AddReference(bpy.types.Operator, tool.Ifc.Operator):
class AddReference(bpy.types.Operator, Operator):
bl_idname = "bim.add_reference"
bl_label = "Add Reference"
bl_options = {"REGISTER", "UNDO"}
@@ -2135,7 +2143,7 @@ class AddReference(bpy.types.Operator, tool.Ifc.Operator):
return {"RUNNING_MODAL"}
class RemoveReference(bpy.types.Operator, tool.Ifc.Operator):
class RemoveReference(bpy.types.Operator, Operator):
bl_idname = "bim.remove_reference"
bl_label = "Remove Reference"
bl_options = {"REGISTER", "UNDO"}
@@ -2145,7 +2153,7 @@ class RemoveReference(bpy.types.Operator, tool.Ifc.Operator):
core.remove_document(tool.Ifc, tool.Drawing, "REFERENCE", document=tool.Ifc.get().by_id(self.reference))
class OpenReference(bpy.types.Operator, tool.Ifc.Operator):
class OpenReference(bpy.types.Operator, Operator):
bl_idname = "bim.open_reference"
bl_label = "Open Reference"
bl_options = {"REGISTER", "UNDO"}
@@ -2258,7 +2266,7 @@ class EditTextPopup(bpy.types.Operator):
return {"FINISHED"}
class EditText(bpy.types.Operator, tool.Ifc.Operator):
class EditText(bpy.types.Operator, Operator):
bl_idname = "bim.edit_text"
bl_label = "Edit Text"
bl_options = {"REGISTER", "UNDO"}
@@ -2268,7 +2276,7 @@ class EditText(bpy.types.Operator, tool.Ifc.Operator):
tool.Blender.update_viewport()
class EnableEditingText(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingText(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_text"
bl_label = "Enable Editing Text"
bl_options = {"REGISTER", "UNDO"}
@@ -2277,7 +2285,7 @@ class EnableEditingText(bpy.types.Operator, tool.Ifc.Operator):
core.enable_editing_text(tool.Drawing, obj=context.active_object)
class DisableEditingText(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingText(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_text"
bl_label = "Disable Editing Text"
bl_options = {"REGISTER", "UNDO"}
@@ -2340,32 +2348,6 @@ class RemoveTextLiteral(bpy.types.Operator):
return {"FINISHED"}
class OrderTextLiteralUp(bpy.types.Operator):
bl_idname = "bim.order_text_literal_up"
bl_label = "Move Text Literal Up"
bl_options = {"REGISTER", "UNDO"}
literal_prop_id: bpy.props.IntProperty()
def execute(self, context):
obj = context.active_object
obj.BIMTextProperties.literals.move(self.literal_prop_id, self.literal_prop_id - 1)
return {"FINISHED"}
class OrderTextLiteralDown(bpy.types.Operator):
bl_idname = "bim.order_text_literal_down"
bl_label = "Move Text Literal Down"
bl_options = {"REGISTER", "UNDO"}
literal_prop_id: bpy.props.IntProperty()
def execute(self, context):
obj = context.active_object
obj.BIMTextProperties.literals.move(self.literal_prop_id, self.literal_prop_id + 1)
return {"FINISHED"}
class AssignSelectedObjectAsProduct(bpy.types.Operator):
bl_idname = "bim.assign_selected_as_product"
bl_label = "Assign Selected Object As Product"
@@ -2395,7 +2377,7 @@ class AssignSelectedObjectAsProduct(bpy.types.Operator):
return {"FINISHED"}
class EditAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
class EditAssignedProduct(bpy.types.Operator, Operator):
bl_idname = "bim.edit_assigned_product"
bl_label = "Edit Text Product"
bl_options = {"REGISTER", "UNDO"}
@@ -2408,7 +2390,7 @@ class EditAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
tool.Blender.update_viewport()
class EnableEditingAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingAssignedProduct(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_assigned_product"
bl_label = "Enable Editing Assigned Product"
bl_options = {"REGISTER", "UNDO"}
@@ -2417,7 +2399,7 @@ class EnableEditingAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
core.enable_editing_assigned_product(tool.Drawing, obj=context.active_object)
class DisableEditingAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingAssignedProduct(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_assigned_product"
bl_label = "Disable Editing Assigned Product"
bl_options = {"REGISTER", "UNDO"}
@@ -2426,7 +2408,7 @@ class DisableEditingAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
core.disable_editing_assigned_product(tool.Drawing, obj=context.active_object)
class LoadSheets(bpy.types.Operator, tool.Ifc.Operator):
class LoadSheets(bpy.types.Operator, Operator):
bl_idname = "bim.load_sheets"
bl_label = "Load Sheets"
bl_options = {"REGISTER", "UNDO"}
@@ -2453,7 +2435,7 @@ class LoadSheets(bpy.types.Operator, tool.Ifc.Operator):
self.report({"ERROR"}, "Some sheets svg files are missing:\n" + "\n".join(sheets_not_found))
class EditSheet(bpy.types.Operator, tool.Ifc.Operator):
class EditSheet(bpy.types.Operator, Operator):
bl_idname = "bim.edit_sheet"
bl_label = "Edit Sheet"
bl_options = {"REGISTER", "UNDO"}
@@ -2509,7 +2491,7 @@ class EditSheet(bpy.types.Operator, tool.Ifc.Operator):
tool.Drawing.import_sheets()
class DisableEditingSheets(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingSheets(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_sheets"
bl_label = "Disable Editing Sheets"
bl_options = {"REGISTER", "UNDO"}
@@ -2518,7 +2500,7 @@ class DisableEditingSheets(bpy.types.Operator, tool.Ifc.Operator):
core.disable_editing_sheets(tool.Drawing)
class LoadSchedules(bpy.types.Operator, tool.Ifc.Operator):
class LoadSchedules(bpy.types.Operator, Operator):
bl_idname = "bim.load_schedules"
bl_label = "Load Schedules"
bl_options = {"REGISTER", "UNDO"}
@@ -2527,7 +2509,7 @@ class LoadSchedules(bpy.types.Operator, tool.Ifc.Operator):
core.load_schedules(tool.Drawing)
class DisableEditingSchedules(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingSchedules(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_schedules"
bl_label = "Disable Editing Schedules"
bl_options = {"REGISTER", "UNDO"}
@@ -2536,7 +2518,7 @@ class DisableEditingSchedules(bpy.types.Operator, tool.Ifc.Operator):
core.disable_editing_schedules(tool.Drawing)
class LoadReferences(bpy.types.Operator, tool.Ifc.Operator):
class LoadReferences(bpy.types.Operator, Operator):
bl_idname = "bim.load_references"
bl_label = "Load References"
bl_options = {"REGISTER", "UNDO"}
@@ -2545,7 +2527,7 @@ class LoadReferences(bpy.types.Operator, tool.Ifc.Operator):
core.load_references(tool.Drawing)
class DisableEditingReferences(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingReferences(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_references"
bl_label = "Disable Editing References"
bl_options = {"REGISTER", "UNDO"}
@@ -2554,7 +2536,7 @@ class DisableEditingReferences(bpy.types.Operator, tool.Ifc.Operator):
core.disable_editing_references(tool.Drawing)
class LoadDrawings(bpy.types.Operator, tool.Ifc.Operator):
class LoadDrawings(bpy.types.Operator, Operator):
bl_idname = "bim.load_drawings"
bl_label = "Load Drawings"
bl_options = {"REGISTER", "UNDO"}
@@ -2563,7 +2545,7 @@ class LoadDrawings(bpy.types.Operator, tool.Ifc.Operator):
core.load_drawings(tool.Drawing)
class DisableEditingDrawings(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingDrawings(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_drawings"
bl_label = "Disable Editing Drawings"
bl_options = {"REGISTER", "UNDO"}
@@ -2628,7 +2610,7 @@ class ContractSheet(bpy.types.Operator):
return {"FINISHED"}
class SelectAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
class SelectAssignedProduct(bpy.types.Operator, Operator):
bl_idname = "bim.select_assigned_product"
bl_label = "Select Assigned Product"
bl_options = {"REGISTER", "UNDO"}
@@ -2637,7 +2619,7 @@ class SelectAssignedProduct(bpy.types.Operator, tool.Ifc.Operator):
core.select_assigned_product(tool.Drawing, context)
class EnableEditingElementFilter(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingElementFilter(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_element_filter"
bl_label = "Enable Editing Element Filter"
bl_options = {"REGISTER", "UNDO"}
@@ -2657,7 +2639,7 @@ class EnableEditingElementFilter(bpy.types.Operator, tool.Ifc.Operator):
pass
class EditElementFilter(bpy.types.Operator, tool.Ifc.Operator):
class EditElementFilter(bpy.types.Operator, Operator):
bl_idname = "bim.edit_element_filter"
bl_label = "Edit Element Filter"
bl_options = {"REGISTER", "UNDO"}
@@ -2678,7 +2660,7 @@ class EditElementFilter(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.activate_drawing(drawing=element.id(), camera_view_point=False)
class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
class AddReferenceImage(bpy.types.Operator, Operator):
bl_idname = "bim.add_reference_image"
bl_label = "Add Reference Image"
bl_options = {"REGISTER", "UNDO"}
@@ -2764,7 +2746,7 @@ class AddReferenceImage(bpy.types.Operator, tool.Ifc.Operator):
obj.material_slots[0].material = material
bpy.ops.bim.add_style()
style = ifc_file.by_id(material.BIMStyleProperties.ifc_definition_id)
style = ifc_file.by_id(material.BIMMaterialProperties.ifc_style_id)
tool.Style.assign_style_to_object(style, obj)
# TODO: IfcSurfaceStyleRendering is unnecessary here, added it only because
@@ -371,7 +371,6 @@ class DocProperties(PropertyGroup):
shadingstyle_default: StringProperty(default="Blender Default", name="Default Shading Style")
drawing_font: StringProperty(default="OpenGost Type B TT.ttf", name="Drawing Font")
magic_font_scale: bpy.props.FloatProperty(default=0.004118616, name="Font Scale Factor")
imperial_precision: StringProperty(default="1/32", name="Imperial Precision")
class BIMCameraProperties(PropertyGroup):
@@ -507,9 +506,31 @@ class BIMAssignedProductProperties(PropertyGroup):
relating_product: PointerProperty(name="Relating Product", type=bpy.types.Object)
annotation_classes = [
(x, *tool.Drawing.ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(tool.Drawing.ANNOTATION_TYPES_DATA)
]
# ObjectType: annotation_name, description, icon, data_type
# fmt: off
ANNOTATION_TYPES_DATA = {
"DIMENSION": ("Dimension", "Add dimensions annotation.\nMeasurement values can be hidden through ShowDescriptionOnly property\nof BBIM_Dimension property set", "FIXED_SIZE", "curve"),
"ANGLE": ("Angle", "", "DRIVER_ROTATIONAL_DIFFERENCE", "curve"),
"RADIUS": ("Radius", "", "FORWARD", "curve"),
"DIAMETER": ("Diameter", "Add diameter annotation.\nMeasurement values can be hidden through ShowDescriptionOnly property\nof BBIM_Dimension property set", "ARROW_LEFTRIGHT", "curve"),
"TEXT": ("Text", "", "SMALL_CAPS", "empty"),
"TEXT_LEADER": ("Leader", "", "TRACKING_BACKWARDS", "curve"),
"STAIR_ARROW": ("Stair Arrow", "Add stair arrow annotation.\nIf you have IfcStairFlight object selected, it will be used as a reference for the annotation", "SCREEN_BACK", "curve"),
"PLAN_LEVEL": ("Level (Plan)", "", "SORTBYEXT", "curve"),
"SECTION_LEVEL": ("Level (Section)", "", "TRIA_DOWN", "curve"),
"BREAKLINE": ("Breakline", "", "FCURVE", "mesh"),
"SYMBOL": ("Symbol", "", "KEYFRAME", "empty"),
"MULTI_SYMBOL": ("Multi-Symbol", "", "OUTLINER_DATA_POINTCLOUD", "mesh"),
"LINEWORK": ("Line", "", "SNAP_MIDPOINT", "mesh"),
"BATTING": ("Batting", "Add batting annotation.\nThickness could be changed through Thickness property of BBIM_Batting property set", "FORCE_FORCE", "mesh"),
"REVISION_CLOUD":("Revision Cloud", "Add revision cloud", "VOLUME_DATA", "mesh"),
"FILL_AREA": ("Fill Area", "", "NODE_TEXTURE", "mesh"),
"FALL": ("Fall", "", "SORT_ASC", "curve"),
"IMAGE": ("Image", "Add reference image attached to the drawing", "TEXTURE", "mesh"),
}
# fmt: on
annotation_classes = [(x, *ANNOTATION_TYPES_DATA[x][:3], i) for i, x in enumerate(ANNOTATION_TYPES_DATA)]
def get_relating_type_id(self, context):
@@ -28,6 +28,7 @@ from blenderbim.bim.module.drawing.data import (
ElementFiltersData,
DecoratorData,
)
from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA
class BIM_PT_camera(Panel):
@@ -524,10 +525,6 @@ class BIM_PT_text(Panel):
row = box.row(align=True)
row.label(text=f"Literal[{i}]:")
if i > 0:
row.operator("bim.order_text_literal_up", icon="TRIA_UP", text="").literal_prop_id = i
if i < len(props.literals) - 1:
row.operator("bim.order_text_literal_down", icon="TRIA_DOWN", text="").literal_prop_id = i
row.operator("bim.remove_text_literal", icon="X", text="").literal_prop_id = i
# skip BoxAlignment since we're going to format it ourselves
@@ -23,11 +23,21 @@ import blenderbim.tool as tool
from blenderbim.bim.helper import prop_with_search
from bpy.types import WorkSpaceTool
from blenderbim.bim.module.drawing.prop import ANNOTATION_TYPES_DATA
from blenderbim.bim.module.drawing.data import DecoratorData, AnnotationData
from blenderbim.bim.ifc import IfcStore
import blenderbim.bim.handler
# TODO: Fix circular import.
# Declaring it here to avoid circular import problems
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class LaunchAnnotationTypeManager(bpy.types.Operator):
bl_idname = "bim.launch_annotation_type_manager"
bl_label = "Launch Annotation Type Manager"
@@ -186,9 +196,7 @@ def create_annotation():
create_annotation_occurrence(bpy.context)
else:
object_type = props.object_type
bpy.ops.bim.add_annotation(
object_type=object_type, data_type=tool.Drawing.ANNOTATION_TYPES_DATA[object_type][-1]
)
bpy.ops.bim.add_annotation(object_type=object_type, data_type=ANNOTATION_TYPES_DATA[object_type][-1])
if props.object_type == "IMAGE":
bpy.ops.bim.add_reference_image(
"INVOKE_DEFAULT", use_existing_object_by_name=bpy.context.active_object.name
@@ -258,7 +266,7 @@ class AnnotationToolUI:
)
class Hotkey(bpy.types.Operator, tool.Ifc.Operator):
class Hotkey(bpy.types.Operator, Operator):
bl_idname = "bim.annotation_hotkey"
bl_label = "Hotkey"
bl_options = {"REGISTER", "UNDO"}
@@ -24,21 +24,32 @@ import logging
import tempfile
import ifcopenshell
import blenderbim.tool as tool
from blenderbim.bim.operator import MultipleFileSelector
class SelectFMIfcFile(MultipleFileSelector):
class SelectFMIfcFile(bpy.types.Operator):
bl_idname = "bim.select_fm_ifc_file"
bl_label = "Select FM IFC File"
bl_options = {"REGISTER", "UNDO"}
filename_ext = ".ifc"
filter_glob: bpy.props.StringProperty(default="*.ifc;*.ifczip;*.ifcxml", options={"HIDDEN"})
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
files: bpy.props.CollectionProperty(name="File Path", type=bpy.types.OperatorFileListElement)
def execute(self, context):
props = context.scene.BIMFMProperties
self.update_props(props, "ifc_file", props.ifc_files)
props.ifc_files.clear()
dirname = os.path.dirname(self.filepath)
for f in self.files:
new = props.ifc_files.add()
new.name = os.path.join(dirname, f.name)
props.ifc_file = self.filepath
return {"FINISHED"}
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class ExecuteIfcFM(bpy.types.Operator):
bl_idname = "bim.execute_ifcfm"
bl_label = "Execute IfcFM"
@@ -24,7 +24,6 @@ from mathutils import Vector
def refresh():
ViewportData.is_loaded = False
PlacementData.is_loaded = False
DerivedCoordinatesData.is_loaded = False
RepresentationsData.is_loaded = False
@@ -32,28 +31,6 @@ def refresh():
ConnectionsData.is_loaded = False
class ViewportData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.is_loaded = True
cls.data = {"mode": cls.mode()}
@classmethod
def mode(cls):
obj = bpy.context.active_object
obj_mode = [("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0)]
mesh_modes = [
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
]
if not obj or not tool.Blender.is_editable(obj):
return obj_mode
return mesh_modes
class RepresentationsData:
data = {}
is_loaded = False
@@ -62,10 +39,7 @@ class RepresentationsData:
def load(cls):
cls.data = {"representations": cls.representations()}
cls.data["contexts"] = cls.contexts()
# Only after cls.representations().
cls.data["shape_aspects"] = cls.shape_aspects()
cls.is_loaded = True
@classmethod
@@ -77,7 +51,12 @@ class RepresentationsData:
if bpy.context.active_object.data and hasattr(bpy.context.active_object.data, "BIMMeshProperties"):
active_representation_id = bpy.context.active_object.data.BIMMeshProperties.ifc_definition_id
for representation in tool.Geometry.get_representations_iter(element):
representations = []
if element.is_a("IfcProduct") and element.Representation:
representations = element.Representation.Representations
elif element.is_a("IfcTypeProduct"):
representations = [rm.MappedRepresentation for rm in element.RepresentationMaps or []]
for representation in representations:
representation_type = representation.RepresentationType
if representation_type == "MappedRepresentation":
representation_type = representation.Items[0].MappingSource.MappedRepresentation.RepresentationType
@@ -116,11 +95,7 @@ class RepresentationsData:
return results
@classmethod
def shape_aspects(cls) -> list[tuple[str, str, str]]:
"""Get list of current's representation shape aspects for prop's enum_items."""
# Ignore objects without representations, e.g. IfcRelSpaceBoundary.
if not cls.data["representations"]:
return []
def shape_aspects(cls):
obj = bpy.context.active_object
if not obj.data:
return []
@@ -152,12 +127,12 @@ class RepresentationItemsData:
cls.is_loaded = True
@classmethod
def total_items(cls) -> int:
def total_items(cls):
active_representation_id = None
result = 0
obj = bpy.context.active_object
assert obj
element = tool.Geometry.get_active_representation(obj)
if element:
if bpy.context.active_object.data and hasattr(bpy.context.active_object.data, "BIMMeshProperties"):
active_representation_id = bpy.context.active_object.data.BIMMeshProperties.ifc_definition_id
element = tool.Ifc.get().by_id(active_representation_id)
if not element.is_a("IfcShapeRepresentation"):
return 0
queue = list(element.Items)
@@ -353,19 +328,12 @@ class PlacementData:
@classmethod
def load(cls):
cls.data = {"has_placement": cls.has_placement()}
props = bpy.context.scene.BIMGeoreferenceProperties
obj = bpy.context.active_object
if obj and props.has_blender_offset:
xyz = cls.original_xyz(obj)
cls.data.update(
{
"original_x": str(xyz[0]),
"original_y": str(xyz[1]),
"original_z": str(xyz[2]),
}
)
cls.data = {
"has_placement": cls.has_placement(),
"original_x": cls.original_x(),
"original_y": cls.original_y(),
"original_z": cls.original_z(),
}
cls.is_loaded = True
@classmethod
@@ -376,18 +344,40 @@ class PlacementData:
return False
@classmethod
def original_xyz(cls, obj):
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
def original_x(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
xyz = ifcopenshell.util.geolocation.xyz2enh(
obj.matrix_world[0][3],
obj.matrix_world[1][3],
obj.matrix_world[2][3],
float(props.blender_offset_x) * unit_scale,
float(props.blender_offset_y) * unit_scale,
float(props.blender_offset_z) * unit_scale,
obj = bpy.context.active_object
if not obj or not props.has_blender_offset:
return
return str(round(cls.original_xyz(obj.location)[0], 3))
@classmethod
def original_y(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
obj = bpy.context.active_object
if not obj or not props.has_blender_offset:
return
return str(round(cls.original_xyz(obj.location)[1], 3))
@classmethod
def original_z(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
obj = bpy.context.active_object
if not obj or not props.has_blender_offset:
return
return str(round(cls.original_xyz(obj.location)[2], 3))
@classmethod
def original_xyz(cls, location):
props = bpy.context.scene.BIMGeoreferenceProperties
return ifcopenshell.util.geolocation.xyz2enh(
location[0],
location[1],
location[2],
float(props.blender_eastings),
float(props.blender_northings),
float(props.blender_orthogonal_height),
float(props.blender_x_axis_abscissa),
float(props.blender_x_axis_ordinate),
1.0,
)
return [round(o, 3) / unit_scale for o in xyz] # To nearest mm of precision
@@ -43,13 +43,16 @@ from ifcopenshell.util.shape_builder import ShapeBuilder
from typing import Any
class EditObjectPlacement(bpy.types.Operator, tool.Ifc.Operator):
class Operator:
def execute(self, context):
IfcStore.execute_ifc_operator(self, context)
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
class EditObjectPlacement(bpy.types.Operator, Operator):
bl_idname = "bim.edit_object_placement"
bl_label = "Edit Object Placement"
bl_description = (
"Write selected objects placements to IFC.\n"
"A star in the operator name indicates that active object placement in IFC is not yet synced with Blender"
)
bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty()
@@ -59,7 +62,7 @@ class EditObjectPlacement(bpy.types.Operator, tool.Ifc.Operator):
core.edit_object_placement(tool.Ifc, tool.Geometry, tool.Surveyor, obj=obj)
class OverrideMeshSeparate(bpy.types.Operator, tool.Ifc.Operator):
class OverrideMeshSeparate(bpy.types.Operator, Operator):
bl_idname = "bim.override_mesh_separate"
bl_label = "IFC Mesh Separate"
bl_options = {"REGISTER", "UNDO"}
@@ -95,7 +98,7 @@ class OverrideMeshSeparate(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.update_representation(obj=new_obj.name)
class OverrideOriginSet(bpy.types.Operator, tool.Ifc.Operator):
class OverrideOriginSet(bpy.types.Operator, Operator):
bl_idname = "bim.override_origin_set"
bl_label = "IFC Origin Set"
bl_options = {"REGISTER", "UNDO"}
@@ -120,7 +123,7 @@ class OverrideOriginSet(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.update_representation(obj=obj.name)
class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
class AddRepresentation(bpy.types.Operator, Operator):
bl_idname = "bim.add_representation"
bl_label = "Add Representation"
bl_options = {"REGISTER", "UNDO"}
@@ -135,23 +138,8 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
"for Profile - 2D bounding box by local XZ axes.\n"
"For other contexts - bounding box is 3d.",
),
(
"OBJECT",
"From Object",
(
"Copies geometry from another object.\n"
"Final version of the geometry will be used (e.g. with all modifiers, shape keys applied)"
),
),
("OBJECT", "From Object", "Copies geometry from another object"),
("PROJECT", "Full Representation", "Reuses the current representation"),
(
"CUBE",
"Cube",
(
"Add cube representation.\n"
"Useful for adding a representation to an object without any representations"
),
),
],
name="Representation Conversion Method",
)
@@ -167,17 +155,7 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
original_data = obj.data
conversion_method = self.representation_conversion_method
if not original_data and conversion_method not in ("OBJECT", "CUBE"):
self.report(
{"ERROR"},
(f"No mesh data found for the active object. Mesh data required for '{conversion_method}' method."),
)
return {"FINISH"}
# NOTE: `data` is temporary data generated to add a representation.
data: bpy.types.Mesh
if conversion_method == "OUTLINE":
if self.representation_conversion_method == "OUTLINE":
if ifc_context.ContextType == "Plan":
data = tool.Geometry.generate_outline_mesh(obj, axis="+Z")
elif ifc_context.ContextIdentifier == "Profile":
@@ -185,7 +163,7 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
else:
data = tool.Geometry.generate_outline_mesh(obj, axis="+Z")
tool.Geometry.change_object_data(obj, data, is_global=True)
elif conversion_method == "BOX":
elif self.representation_conversion_method == "BOX":
if ifc_context.ContextType == "Plan":
data = tool.Geometry.generate_2d_box_mesh(obj, axis="Z")
elif ifc_context.ContextIdentifier == "Profile":
@@ -193,25 +171,13 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
else:
data = tool.Geometry.generate_3d_box_mesh(obj)
tool.Geometry.change_object_data(obj, data, is_global=True)
elif conversion_method in ("OBJECT", "CUBE"):
if conversion_method == "OBJECT":
if not (source_obj := props.representation_from_object):
self.report({"ERROR"}, "No object is selected to copy a representation from.")
return {"FINISHED"}
depsgraph = context.evaluated_depsgraph_get()
eval_obj = source_obj.evaluated_get(depsgraph)
data = bpy.data.meshes.new_from_object(eval_obj)
else: # CUBE
data = bpy.data.meshes.new("Cube")
bm = tool.Blender.get_bmesh_for_mesh(data)
bmesh.ops.create_cube(bm, size=1)
tool.Blender.apply_bmesh(data, bm)
if original_data:
tool.Geometry.change_object_data(obj, data, is_global=True)
else:
obj = tool.Geometry.recreate_object_with_data(obj, data, is_global=True)
elif (
self.representation_conversion_method == "OBJECT"
and props.representation_from_object
and props.representation_from_object.data
):
data = tool.Geometry.duplicate_object_data(props.representation_from_object)
tool.Geometry.change_object_data(obj, data, is_global=True)
try:
core.add_representation(
@@ -224,10 +190,6 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
ifc_representation_class=None,
profile_set_usage=None,
)
# Object might be recreated, need to set it as active again.
if context.active_object != obj:
tool.Blender.set_active_object(obj)
bpy.data.meshes.remove(data)
except core.IncompatibleRepresentationError:
if obj.data != original_data:
tool.Geometry.change_object_data(obj, original_data, is_global=True)
@@ -246,7 +208,7 @@ class AddRepresentation(bpy.types.Operator, tool.Ifc.Operator):
row.prop(context.scene.BIMGeometryProperties, "representation_from_object", text="")
class SelectConnection(bpy.types.Operator, tool.Ifc.Operator):
class SelectConnection(bpy.types.Operator, Operator):
bl_idname = "bim.select_connection"
bl_label = "Select Connection"
bl_options = {"REGISTER", "UNDO"}
@@ -256,7 +218,7 @@ class SelectConnection(bpy.types.Operator, tool.Ifc.Operator):
core.select_connection(tool.Geometry, connection=tool.Ifc.get().by_id(self.connection))
class RemoveConnection(bpy.types.Operator, tool.Ifc.Operator):
class RemoveConnection(bpy.types.Operator, Operator):
bl_idname = "bim.remove_connection"
bl_label = "Remove Connection"
bl_options = {"REGISTER", "UNDO"}
@@ -266,7 +228,7 @@ class RemoveConnection(bpy.types.Operator, tool.Ifc.Operator):
core.remove_connection(tool.Geometry, connection=tool.Ifc.get().by_id(self.connection))
class SwitchRepresentation(bpy.types.Operator, tool.Ifc.Operator):
class SwitchRepresentation(bpy.types.Operator, Operator):
bl_idname = "bim.switch_representation"
bl_label = "Switch Representation"
bl_options = {"REGISTER", "UNDO"}
@@ -315,7 +277,7 @@ class SwitchRepresentation(bpy.types.Operator, tool.Ifc.Operator):
)
class RemoveRepresentation(bpy.types.Operator, tool.Ifc.Operator):
class RemoveRepresentation(bpy.types.Operator, Operator):
bl_idname = "bim.remove_representation"
bl_label = "Remove Representation"
bl_options = {"REGISTER", "UNDO"}
@@ -330,7 +292,7 @@ class RemoveRepresentation(bpy.types.Operator, tool.Ifc.Operator):
)
class PurgeUnusedRepresentations(bpy.types.Operator, tool.Ifc.Operator):
class PurgeUnusedRepresentations(bpy.types.Operator, Operator):
bl_idname = "bim.purge_unused_representations"
bl_label = "Purge Unused Representations"
bl_options = {"REGISTER", "UNDO"}
@@ -340,13 +302,9 @@ class PurgeUnusedRepresentations(bpy.types.Operator, tool.Ifc.Operator):
self.report({"INFO"}, f"{purged_representations} representations were purged.")
class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
class UpdateRepresentation(bpy.types.Operator, Operator):
bl_idname = "bim.update_representation"
bl_label = "Update Representation"
bl_description = (
"Write selected objects representations to IFC.\n"
"A star in the operator name indicates that active object representation in IFC is not yet synced with Blender"
)
bl_options = {"REGISTER", "UNDO"}
obj: bpy.props.StringProperty()
ifc_representation_class: bpy.props.StringProperty()
@@ -356,9 +314,8 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
# Ensure mode is object to prevent invalid mesh data causing CTD
bpy.ops.object.mode_set(mode="OBJECT", toggle=False)
obj_name: str = self.obj
objs = [bpy.data.objects[obj_name]] if obj_name else context.selected_objects
self.file = tool.Ifc.get()
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
self.file = IfcStore.get_file()
for obj in objs:
# TODO: write unit tests to see how this bulk operation handles
@@ -367,10 +324,10 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
if not obj.data:
continue
self.update_obj_mesh_representation(context, obj)
tool.Ifc.finish_edit(obj)
IfcStore.edited_objs.discard(obj)
return {"FINISHED"}
def update_obj_mesh_representation(self, context: bpy.types.Context, obj: bpy.types.Object) -> None:
def update_obj_mesh_representation(self, context, obj):
product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
material = ifcopenshell.util.element.get_material(product, should_skip_usage=True)
@@ -400,9 +357,7 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
element_type = ifcopenshell.util.element.get_type(product)
if element_type: # Some invalid IFCs use material sets without a type.
ifcopenshell.api.run("material.unassign_material", tool.Ifc.get(), products=[element_type])
tool.Material.ensure_material_unassigned([element_type])
ifcopenshell.api.run("material.unassign_material", tool.Ifc.get(), products=[product])
tool.Material.ensure_material_unassigned([product])
else:
# These objects are parametrically based on an axis and should not be modified as a mesh
return
@@ -419,12 +374,14 @@ class UpdateRepresentation(bpy.types.Operator, tool.Ifc.Operator):
gprop = context.scene.BIMGeoreferenceProperties
coordinate_offset = None
if (
gprop.has_blender_offset
and obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT"
and obj.BIMObjectProperties.cartesian_point_offset
):
coordinate_offset = Vector(map(float, obj.BIMObjectProperties.cartesian_point_offset.split(",")))
if gprop.has_blender_offset and obj.BIMObjectProperties.blender_offset_type == "CARTESIAN_POINT":
coordinate_offset = Vector(
(
float(gprop.blender_eastings),
float(gprop.blender_northings),
float(gprop.blender_orthogonal_height),
)
)
representation_data = {
"context": context_of_items,
@@ -521,7 +478,7 @@ class UpdateParametricRepresentation(bpy.types.Operator):
return {"FINISHED"}
class GetRepresentationIfcParameters(bpy.types.Operator, tool.Ifc.Operator):
class GetRepresentationIfcParameters(bpy.types.Operator, Operator):
bl_idname = "bim.get_representation_ifc_parameters"
bl_label = "Get Representation IFC Parameters"
bl_options = {"REGISTER", "UNDO"}
@@ -532,7 +489,7 @@ class GetRepresentationIfcParameters(bpy.types.Operator, tool.Ifc.Operator):
self.report({"INFO"}, f"{len(parameters)} parameters found.")
class CopyRepresentation(bpy.types.Operator, tool.Ifc.Operator):
class CopyRepresentation(bpy.types.Operator, Operator):
bl_idname = "bim.copy_representation"
bl_label = "Copy Representation"
bl_options = {"REGISTER", "UNDO"}
@@ -991,7 +948,7 @@ class OverrideDuplicateMove(bpy.types.Operator):
pset = ifcopenshell.util.element.get_pset(new[0], "BBIM_Linked_Aggregate")
if pset:
pset = tool.Ifc.get().by_id(pset["id"])
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=new[0], pset=pset)
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), product=new[0],pset=pset)
if new[0].is_a("IfcElementAssembly"):
linked_aggregate_group = [
@@ -1171,6 +1128,7 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
location_diff = new_obj.location - base_obj_location
new_obj.location = context.scene.cursor.location + location_diff
if len(context.selected_objects) != 1:
return {"FINISHED"}
@@ -1218,10 +1176,7 @@ class DuplicateLinkedAggregateTo3dCursor(bpy.types.Operator):
return OverrideDuplicateMove.execute_duplicate_operator(self, context, linked=False)
def _execute(self, context):
return DuplicateMoveLinkedAggregate.execute_ifc_duplicate_linked_aggregate_operator(
self, context, location_from_3d_cursor=True
)
return DuplicateMoveLinkedAggregate.execute_ifc_duplicate_linked_aggregate_operator(self, context, location_from_3d_cursor=True)
class RefreshLinkedAggregate(bpy.types.Operator):
bl_idname = "bim.refresh_linked_aggregate"
@@ -1450,7 +1405,7 @@ class RefreshLinkedAggregate(bpy.types.Operator):
return {"FINISHED"}
class OverrideJoin(bpy.types.Operator, tool.Ifc.Operator):
class OverrideJoin(bpy.types.Operator, Operator):
bl_idname = "bim.override_object_join"
bl_label = "IFC Join"
bl_options = {"REGISTER", "UNDO"}
@@ -1575,7 +1530,7 @@ class OverrideModeSetEdit(bpy.types.Operator):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
selected_objs = tool.Blender.get_selected_objects()
selected_objs = context.selected_objects or ([context.active_object] if context.active_object else [])
active_obj = context.active_object
if context.active_object:
@@ -1586,13 +1541,23 @@ class OverrideModeSetEdit(bpy.types.Operator):
return bpy.ops.bim.enable_editing_boundary_geometry()
for obj in selected_objs:
if not tool.Blender.is_editable(obj):
self.report({"INFO"}, f"Object cannot be edited: {obj.name}")
if not obj:
continue
obj_supports_edit_mode, message = tool.Blender.object_supports_edit_mode(obj)
if not obj_supports_edit_mode:
self.report({"INFO"}, message)
obj.select_set(False)
continue
element = tool.Ifc.get_entity(obj)
if not element:
continue
usage_type = tool.Model.get_usage_type(element)
if usage_type is not None and usage_type not in ("PROFILE", "LAYER3"):
# Parametric objects shall not be edited as meshes as they
# can be modified to be incompatible with the parametric
# constraints.
obj.select_set(False)
continue
representation = tool.Geometry.get_active_representation(obj)
if not representation:
continue
@@ -1600,7 +1565,6 @@ class OverrideModeSetEdit(bpy.types.Operator):
obj.select_set(False)
continue
usage_type = tool.Model.get_usage_type(element)
is_profile = True
representation_class = tool.Geometry.get_ifc_representation_class(element, representation)
if usage_type == "PROFILE":
@@ -1651,7 +1615,6 @@ class OverrideModeSetEdit(bpy.types.Operator):
should_sync_changes_first=False,
apply_openings=False,
)
tool.Geometry.apply_item_ids_as_vertex_groups(obj)
tool.Geometry.dissolve_triangulated_edges(obj)
obj.data.BIMMeshProperties.mesh_checksum = tool.Geometry.get_mesh_checksum(obj.data)
else:
@@ -1699,8 +1662,6 @@ class OverrideModeSetObject(bpy.types.Operator):
return IfcStore.execute_ifc_operator(self, context)
def _execute(self, context):
if not context.active_object:
return {"FINISHED"}
for obj in self.edited_objs:
if self.should_save:
bpy.ops.bim.update_representation(obj=obj.name, ifc_representation_class="")
@@ -1732,8 +1693,6 @@ class OverrideModeSetObject(bpy.types.Operator):
return IfcStore.execute_ifc_operator(self, context, is_invoke=True)
def _invoke(self, context, event):
if not context.active_object:
return {"FINISHED"}
self.is_valid = True
bpy.ops.object.mode_set(mode="EDIT", toggle=True)
@@ -1815,7 +1774,7 @@ class FlipObject(bpy.types.Operator):
return {"FINISHED"}
class EnableEditingRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingRepresentationItems(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_representation_items"
bl_label = "Enable Editing Representation Items"
bl_options = {"REGISTER", "UNDO"}
@@ -1866,7 +1825,7 @@ class EnableEditingRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
props.items.move(props.items[:].index(item), i)
class DisableEditingRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingRepresentationItems(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_representation_items"
bl_label = "Disable Editing Representation Items"
bl_options = {"REGISTER", "UNDO"}
@@ -1876,7 +1835,7 @@ class DisableEditingRepresentationItems(bpy.types.Operator, tool.Ifc.Operator):
obj.BIMGeometryProperties.is_editing = False
class RemoveRepresentationItem(bpy.types.Operator, tool.Ifc.Operator):
class RemoveRepresentationItem(bpy.types.Operator, Operator):
bl_idname = "bim.remove_representation_item"
bl_label = "Remove Representation Item"
bl_options = {"REGISTER", "UNDO"}
@@ -1934,7 +1893,7 @@ def poll_editing_representaiton_item_style(cls, context):
return True
class EnableEditingRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingRepresentationItemStyle(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_representation_item_style"
bl_label = "Enable Editing Representation Item Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1956,7 +1915,7 @@ class EnableEditingRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator
props.representation_item_style = str(style.id())
class EditRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator):
class EditRepresentationItemStyle(bpy.types.Operator, Operator):
bl_idname = "bim.edit_representation_item_style"
bl_label = "Edit Representation Item Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1978,7 +1937,7 @@ class EditRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.enable_editing_representation_items()
class DisableEditingRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingRepresentationItemStyle(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_representation_item_style"
bl_label = "Disable Editing Representation Item Style"
bl_options = {"REGISTER", "UNDO"}
@@ -1988,7 +1947,7 @@ class DisableEditingRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operato
props.is_editing_item_style = False
class UnassignRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator):
class UnassignRepresentationItemStyle(bpy.types.Operator, Operator):
bl_idname = "bim.unassign_representation_item_style"
bl_label = "Unassign Representation Item Style"
bl_options = {"REGISTER", "UNDO"}
@@ -2016,7 +1975,7 @@ class UnassignRepresentationItemStyle(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.enable_editing_representation_items()
class EnableEditingRepresentationItemShapeAspect(bpy.types.Operator, tool.Ifc.Operator):
class EnableEditingRepresentationItemShapeAspect(bpy.types.Operator, Operator):
bl_idname = "bim.enable_editing_representation_item_shape_aspect"
bl_label = "Enable Editing Representation Item Shape Aspect"
bl_options = {"REGISTER", "UNDO"}
@@ -2031,7 +1990,7 @@ class EnableEditingRepresentationItemShapeAspect(bpy.types.Operator, tool.Ifc.Op
props.representation_item_shape_aspect = str(shape_aspect_id)
class EditRepresentationItemShapeAspect(bpy.types.Operator, tool.Ifc.Operator):
class EditRepresentationItemShapeAspect(bpy.types.Operator, Operator):
bl_idname = "bim.edit_representation_item_shape_aspect"
bl_label = "Edit Representation Item Shape Aspect"
bl_options = {"REGISTER", "UNDO"}
@@ -2087,7 +2046,7 @@ class EditRepresentationItemShapeAspect(bpy.types.Operator, tool.Ifc.Operator):
bpy.ops.bim.enable_editing_representation_items()
class DisableEditingRepresentationItemShapeAspect(bpy.types.Operator, tool.Ifc.Operator):
class DisableEditingRepresentationItemShapeAspect(bpy.types.Operator, Operator):
bl_idname = "bim.disable_editing_representation_item_shape_aspect"
bl_label = "Disable Editing Representation Item Shape Aspect"
bl_options = {"REGISTER", "UNDO"}
@@ -2097,7 +2056,7 @@ class DisableEditingRepresentationItemShapeAspect(bpy.types.Operator, tool.Ifc.O
props.is_editing_item_shape_aspect = False
class RemoveRepresentationItemFromShapeAspect(bpy.types.Operator, tool.Ifc.Operator):
class RemoveRepresentationItemFromShapeAspect(bpy.types.Operator, Operator):
bl_idname = "bim.remove_representation_item_from_shape_aspect"
bl_label = "Remove Representation Item From Shape Aspect"
bl_options = {"REGISTER", "UNDO"}
@@ -19,7 +19,7 @@
import bpy
import blenderbim.tool as tool
from blenderbim.bim.prop import StrProperty, Attribute
from blenderbim.bim.module.geometry.data import RepresentationsData, ViewportData
from blenderbim.bim.module.geometry.data import RepresentationsData
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -48,12 +48,6 @@ def update_mode(self, context):
bpy.ops.bim.override_mode_set_edit("INVOKE_DEFAULT")
def get_mode(self, context):
if not ViewportData.is_loaded:
ViewportData.load()
return ViewportData.data["mode"]
def get_styles(self, context):
# postponed import to avoid circular import
from blenderbim.bim.module.material.data import MaterialsData
@@ -135,13 +129,13 @@ class BIMGeometryProperties(PropertyGroup):
# Navisworks workaround
should_force_triangulation: BoolProperty(name="Force Triangulation", default=False)
is_changing_mode: BoolProperty(name="Is Changing Mode", default=False)
mode: EnumProperty(items=get_mode, name="IFC Interaction Mode", update=update_mode)
def is_object_valid_for_representation_copy(self, obj: bpy.types.Object) -> bool:
return bool(obj != bpy.context.active_object and obj.data)
representation_from_object: PointerProperty(
name="Object to copy a representation from.\nIt doesn't have to be an IFC object.",
type=bpy.types.Object,
poll=is_object_valid_for_representation_copy,
mode: EnumProperty(
default="OBJECT",
items=[
("OBJECT", "IFC Object Mode", "", "OBJECT_DATAMODE", 0),
("EDIT", "IFC Edit Mode", "", "EDITMODE_HLT", 1),
],
name="IFC Interaction Mode",
update=update_mode,
)
representation_from_object: PointerProperty(type=bpy.types.Object)
@@ -33,8 +33,6 @@ from blenderbim.bim.module.layer.data import LayersData
def mode_menu(self, context):
if not tool.Ifc.get():
return
row = self.layout.row(align=True)
if context.scene.BIMGeometryProperties.mode == "EDIT":
row.operator("bim.override_mode_set_object", icon="CANCEL", text="Discard Changes").should_save = False
@@ -352,10 +350,7 @@ class BIM_PT_mesh(Panel):
layout = self.layout
row = layout.row()
text = "Manually Save Representation"
if tool.Ifc.is_edited(context.active_object):
text += "*"
row.operator("bim.update_representation", text=text)
row.operator("bim.update_representation", text="Manually Save Representation")
row = layout.row()
row.operator("bim.copy_representation", text="Copy Mesh From Active To Selected")
@@ -424,11 +419,10 @@ class BIM_PT_placement(Panel):
row.label(text="Blender Offset", icon="TRACKING_REFINE_FORWARDS")
row.label(text=context.active_object.BIMObjectProperties.blender_offset_type)
if context.active_object.BIMObjectProperties.blender_offset_type != "NOT_APPLICABLE":
row = self.layout.row(align=True)
row.label(text=PlacementData.data["original_x"], icon="EMPTY_AXIS")
row.label(text=PlacementData.data["original_y"])
row.label(text=PlacementData.data["original_z"])
row = self.layout.row(align=True)
row.label(text=PlacementData.data["original_x"], icon="EMPTY_AXIS")
row.label(text=PlacementData.data["original_y"])
row.label(text=PlacementData.data["original_z"])
class BIM_PT_derived_coordinates(Panel):
@@ -450,10 +444,7 @@ class BIM_PT_derived_coordinates(Panel):
DerivedCoordinatesData.load()
row = self.layout.row()
text = "Edit Object Placement"
if tool.Ifc.is_moved(context.active_object):
text += "*"
row.operator("bim.edit_object_placement", text=text, icon="EXPORT")
row.operator("bim.edit_object_placement", icon="EXPORT")
row = self.layout.row()
row.label(text="XYZ Dimensions")
@@ -20,32 +20,23 @@ import bpy
from . import ui, prop, operator
classes = (
operator.AddGeoreferencing,
operator.ConvertAngleToCoordinates,
operator.ConvertGlobalToLocal,
operator.ConvertLocalToGlobal,
operator.DisableEditingGeoreferencing,
operator.DisableEditingTrueNorth,
operator.DisableEditingWCS,
operator.EditGeoreferencing,
operator.EditTrueNorth,
operator.EditWCS,
operator.EnableEditingGeoreferencing,
operator.EnableEditingTrueNorth,
operator.EnableEditingWCS,
operator.GetCursorLocation,
operator.ImportPlot,
operator.RemoveGeoreferencing,
operator.RemoveTrueNorth,
operator.SetBlenderGridNorth,
operator.SetBlenderTrueNorth,
operator.DisableEditingGeoreferencing,
operator.EditGeoreferencing,
operator.SetIfcGridNorth,
operator.SetBlenderGridNorth,
operator.SetIfcTrueNorth,
operator.SetBlenderTrueNorth,
operator.RemoveGeoreferencing,
operator.AddGeoreferencing,
operator.ConvertLocalToGlobal,
operator.ConvertGlobalToLocal,
operator.GetCursorLocation,
operator.SetCursorLocation,
operator.ConvertAngleToCoordinates,
operator.ImportPlot,
prop.BIMGeoreferenceProperties,
ui.BIM_PT_gis,
ui.BIM_PT_gis_blender,
ui.BIM_PT_gis_wcs,
ui.BIM_PT_gis_true_north,
ui.BIM_PT_gis_calculator,
)
@@ -18,11 +18,8 @@
import bpy
import numpy as np
import blenderbim.tool as tool
import ifcopenshell.util.geolocation
from mathutils import Matrix
from ifcopenshell.util.doc import get_entity_doc
import blenderbim.tool as tool
def refresh():
@@ -35,59 +32,58 @@ class GeoreferenceData:
@classmethod
def load(cls):
cls.data["coordinate_operation_class"] = cls.coordinate_operation_class()
cls.data["coordinate_operation"] = cls.coordinate_operation()
cls.data["blender_derived_angle"] = cls.blender_derived_angle()
cls.data["map_conversion"] = cls.map_conversion()
cls.data["map_derived_angle"] = cls.map_derived_angle()
cls.data["projected_crs"] = cls.projected_crs()
cls.data["true_north"] = cls.true_north()
cls.data["true_derived_angle"] = cls.true_derived_angle()
cls.data["local_unit_symbol"] = cls.local_unit_symbol()
cls.data["map_unit_symbol"] = cls.map_unit_symbol()
cls.data["world_coordinate_system"] = cls.world_coordinate_system()
cls.is_loaded = True
@classmethod
def coordinate_operation_class(cls):
if tool.Ifc.get_schema() == "IFC2X3":
return []
declaration = tool.Ifc.schema().declaration_by_name("IfcCoordinateOperation")
declarations = ifcopenshell.util.schema.get_subtypes(declaration)
names = [d.name() for d in declarations]
version = tool.Ifc.get_schema()
return [(c, c, get_entity_doc(version, c).get("description", "")) for c in sorted(names)]
def blender_derived_angle(cls):
props = bpy.context.scene.BIMGeoreferenceProperties
if props.has_blender_offset:
return str(
round(
ifcopenshell.util.geolocation.xaxis2angle(
float(props.blender_x_axis_abscissa), float(props.blender_x_axis_ordinate)
),
3,
)
)
@classmethod
def coordinate_operation(cls):
def map_conversion(cls):
if tool.Ifc.get_schema() == "IFC2X3":
project = tool.Ifc.get().by_type("IfcProject")[0]
coordinate_operation = ifcopenshell.util.element.get_pset(project, "ePSet_MapConversion")
if not coordinate_operation:
map_conversion = ifcopenshell.util.element.get_pset(project, "ePSet_MapConversion")
if not map_conversion:
return {}
del coordinate_operation["id"]
coordinate_operation["type"] = "ePSet_MapConversion"
return coordinate_operation
del map_conversion["id"]
return map_conversion
for context in tool.Ifc.get().by_type("IfcGeometricRepresentationContext", include_subtypes=False):
if context.HasCoordinateOperation:
coordinate_operation = context.HasCoordinateOperation[0].get_info()
del coordinate_operation["id"]
del coordinate_operation["SourceCRS"]
del coordinate_operation["TargetCRS"]
return coordinate_operation
map_conversion = context.HasCoordinateOperation[0].get_info()
del map_conversion["id"]
del map_conversion["type"]
del map_conversion["SourceCRS"]
del map_conversion["TargetCRS"]
return map_conversion
return {}
@classmethod
def map_derived_angle(cls):
if (
cls.data["coordinate_operation"]
and cls.data["coordinate_operation"].get("XAxisAbscissa", None) is not None
and cls.data["coordinate_operation"].get("XAxisOrdinate", None) is not None
cls.data["map_conversion"]
and cls.data["map_conversion"].get("XAxisAbscissa", None) is not None
and cls.data["map_conversion"].get("XAxisOrdinate", None) is not None
):
return str(
round(
ifcopenshell.util.geolocation.xaxis2angle(
cls.data["coordinate_operation"]["XAxisAbscissa"],
cls.data["coordinate_operation"]["XAxisOrdinate"],
cls.data["map_conversion"]["XAxisAbscissa"], cls.data["map_conversion"]["XAxisOrdinate"]
),
3,
)
@@ -134,41 +130,4 @@ class GeoreferenceData:
@classmethod
def true_derived_angle(cls):
if cls.data["true_north"]:
return str(round(ifcopenshell.util.geolocation.yaxis2angle(*cls.data["true_north"][:2]), 3))
@classmethod
def local_unit_symbol(cls):
if not (unit := ifcopenshell.util.unit.get_project_unit(tool.Ifc.get(), "LENGTHUNIT")):
return "n/a"
return ifcopenshell.util.unit.get_unit_symbol(unit)
@classmethod
def map_unit_symbol(cls):
if tool.Ifc.get().schema == "IFC2X3":
return cls.local_unit_symbol()
if crs := tool.Ifc.get().by_type("IfcProjectedCRS"):
crs = crs[0]
if not (unit := crs.MapUnit):
return cls.local_unit_symbol()
return ifcopenshell.util.unit.get_unit_symbol(unit)
return "n/a"
@classmethod
def world_coordinate_system(cls):
wcs = ifcopenshell.util.geolocation.get_wcs(tool.Ifc.get())
result = {}
if wcs is None:
result["has_transformation"] = False
return result
if np.allclose(wcs, np.eye(4)):
result["has_transformation"] = False
else:
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(tool.Ifc.get())
result["has_transformation"] = True
result["rotation"] = str(round(ifcopenshell.util.geolocation.yaxis2angle(*wcs[:, 1][:2]), 3))
result["x"], result["y"], result["z"] = wcs[:, 3][:3]
wcs[0][3] *= unit_scale
wcs[1][3] *= unit_scale
wcs[2][3] *= unit_scale
result["matrix"] = Matrix(wcs)
return result
return str(round(ifcopenshell.util.geolocation.yaxis2angle(*cls.data["true_north"][0:2]), 3))
@@ -1,298 +0,0 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2024 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import blf
import gpu
import bmesh
import ifcopenshell
import blenderbim.tool as tool
from math import radians
from bpy.types import SpaceView3D
from mathutils import Vector, Matrix
from gpu_extras.batch import batch_for_shader
from bpy_extras.view3d_utils import location_3d_to_region_2d
from blenderbim.bim.module.georeference.data import GeoreferenceData
class GeoreferenceDecorator:
is_installed = False
handlers = []
@classmethod
def install(cls, context):
if cls.is_installed:
cls.uninstall()
handler = cls()
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_text, (context,), "WINDOW", "POST_PIXEL"))
cls.handlers.append(SpaceView3D.draw_handler_add(handler.draw_geometry, (context,), "WINDOW", "POST_VIEW"))
cls.is_installed = True
@classmethod
def uninstall(cls):
for handler in cls.handlers:
try:
SpaceView3D.draw_handler_remove(handler, "WINDOW")
except ValueError:
pass
cls.is_installed = False
def draw_batch(self, shader_type, content_pos, color, indices=None):
shader = self.line_shader if shader_type == "LINES" else self.shader
batch = batch_for_shader(shader, shader_type, {"pos": content_pos}, indices=indices)
shader.uniform_float("color", color)
batch.draw(shader)
def draw_text(self, context):
self.calculate_angles(context)
props = context.scene.BIMGeoreferenceProperties
e, n, h = [round(float(o), 7) for o in props.model_origin.split(",")]
wcs_matrix = None
if GeoreferenceData.data["world_coordinate_system"]["has_transformation"]:
wcs_matrix = GeoreferenceData.data["world_coordinate_system"]["matrix"]
self.addon_prefs = tool.Blender.get_addon_preferences()
self.font_id = 0
blf.size(self.font_id, 12)
color = self.addon_prefs.decorations_colour
blf.color(self.font_id, *color)
text = "X: 0, Y: 0, Z: 0"
self.draw_text_at_position(context, text, Vector((0, -0.1, 0)))
angle = Matrix.Rotation(radians(self.pn_angle), 4, "Z")
p = angle @ Vector((0, 1.55, 0))
self.draw_text_at_position(context, "Project North", p)
if not tool.Cad.is_x(self.pn_angle, 0):
arc_start = Vector((0, 1.05, 0))
angle_half = Matrix.Rotation(radians(self.pn_angle / 2), 4, "Z")
arc_mid = angle_half @ arc_start
self.draw_text_at_position(context, f"{self.pn_angle}deg", arc_mid)
if GeoreferenceData.data["coordinate_operation"]:
angle = Matrix.Rotation(radians(self.gn_angle), 4, "Z")
grid_north_p = angle @ Vector((0, 1.05, 0))
self.draw_text_at_position(context, "Grid North", grid_north_p)
arc_start = Vector((0, 0.55, 0))
angle_half = Matrix.Rotation(radians(self.gn_angle / 2), 4, "Z")
arc_mid = angle_half @ arc_start
self.draw_text_at_position(context, f"{self.gn_angle}deg", arc_mid)
text = f"\nE: {e}, N: {n}, H: {h}"
self.draw_text_at_position(context, text, Vector((0, -0.1, 0)))
if GeoreferenceData.data["true_north"]:
angle = Matrix.Rotation(radians(self.tn_angle), 4, "Z")
grid_north_p = angle @ Vector((0, 0.8, 0))
self.draw_text_at_position(context, "True North", grid_north_p)
arc_start = Vector((0, 0.3, 0))
angle_half = Matrix.Rotation(radians(self.tn_angle / 2), 4, "Z")
arc_mid = angle_half @ arc_start
self.draw_text_at_position(context, f"{self.tn_angle}deg", arc_mid)
if wcs_matrix:
x, y, z = wcs_matrix.translation
if operation := GeoreferenceData.data["coordinate_operation"]:
e = operation.get("Eastings")
n = operation.get("Northings")
h = operation.get("OrthogonalHeight")
text = f"WCS\n X: {x}, Y: {y}, Z: {z}\nE: {e}, N: {n}, H: {h}"
else:
text = f"WCS\n X: {x}, Y: {y}, Z: {z}"
if wcs_matrix.translation.length < 1000:
position = wcs_matrix.translation.copy()
else:
position = wcs_matrix.translation.normalized() * 3
text += "\n(Warning: Actual XYZ Not Shown)"
position -= Vector((0, 0.1, 0))
self.draw_text_at_position(context, text, position)
def draw_text_at_position(self, context, text, position):
coords_2d = location_3d_to_region_2d(context.region, context.region_data, position)
if not coords_2d:
return
for i, line in enumerate(text.split("\n")):
w, h = blf.dimensions(self.font_id, line)
co = coords_2d.copy()
co -= Vector((w * 0.5, 15 * i))
blf.position(self.font_id, co[0], co[1], 0)
blf.draw(self.font_id, line)
def draw_geometry(self, context):
self.calculate_angles(context)
wcs_matrix = None
if GeoreferenceData.data["world_coordinate_system"]["has_transformation"]:
wcs_matrix = GeoreferenceData.data["world_coordinate_system"]["matrix"]
self.addon_prefs = tool.Blender.get_addon_preferences()
decorator_color = self.addon_prefs.decorations_colour
decorator_color_special = self.addon_prefs.decorator_color_special
decorator_color_selected = self.addon_prefs.decorator_color_selected
decorator_color_error = self.addon_prefs.decorator_color_error
gpu.state.blend_set("ALPHA")
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
self.line_shader.bind() # required to be able to change uniforms of the shader
# POLYLINE_UNIFORM_COLOR specific uniforms
self.line_shader.uniform_float("viewportSize", (context.region.width, context.region.height))
# general shader
self.shader = gpu.shader.from_builtin("UNIFORM_COLOR")
# A crosshair to emphasize the coordinate system, in case they have grids turned off
self.line_shader.uniform_float("lineWidth", 2.0)
verts = [Vector((0, -1.25, 0)), Vector((0, 1.25, 0)), Vector((-1.25, 0, 0)), Vector((1.25, 0, 0))]
edges = [[0, 1], [2, 3]]
self.draw_batch("LINES", verts, decorator_color, edges)
self.line_shader.uniform_float("lineWidth", 5.0)
# A point at the origin to emphasize its significance as a Blender origin
points = [Vector((0, 0, 0))]
gpu.state.point_size_set(10)
self.draw_batch("POINTS", points, decorator_color_selected)
# A project north arrow always exists
angle = Matrix.Rotation(radians(self.pn_angle), 4, "Z")
points = [angle @ Vector((0, 1.5, 0))]
gpu.state.point_size_set(4)
self.draw_batch("POINTS", points, decorator_color_selected)
verts = [Vector((0, 0, 0)), angle @ Vector((0, 1.5, 0))]
edges = [[0, 1]]
self.draw_batch("LINES", verts, decorator_color_selected, edges)
verts = [Vector((0, 1.5, 0)), Vector((-0.15, 1.35, 0)), Vector((0.15, 1.35, 0))]
edges = [[0, 1], [0, 2]]
verts = [angle @ v for v in verts]
self.draw_batch("LINES", verts, decorator_color_selected, edges)
self.line_shader.uniform_float("lineWidth", 2.0)
# If we have a Blender offset, project north may not be up
if not tool.Cad.is_x(self.pn_angle, 0):
arc_start = Vector((0, 1, 0))
arc_end = angle @ arc_start
angle_half = Matrix.Rotation(radians(self.pn_angle / 2), 4, "Z")
arc_mid = angle_half @ arc_start
arc_segments = tool.Cad.create_arc_segments(
pts=[arc_start, arc_mid, arc_end], num_verts=12, make_edges=True
)
verts, edges = arc_segments
self.draw_batch("LINES", verts, decorator_color_selected, edges)
if GeoreferenceData.data["coordinate_operation"]:
points = [Vector((0, 0, 0)), Vector((0, 1, 0))]
angle = Matrix.Rotation(radians(self.gn_angle), 4, "Z")
points = [angle @ v for v in points]
self.draw_batch("POINTS", points, decorator_color_special)
verts = [Vector((0, 0, 0)), Vector((0, 1, 0))]
edges = [[0, 1]]
angle = Matrix.Rotation(radians(self.gn_angle), 4, "Z")
verts = [angle @ v for v in verts]
self.draw_batch("LINES", verts, decorator_color_special, edges)
verts = [Vector((0, 1, 0)), Vector((-0.15, 0.85, 0)), Vector((0.15, 0.85, 0))]
edges = [[0, 1], [0, 2]]
verts = [angle @ v for v in verts]
self.line_shader.uniform_float("lineWidth", 5.0)
self.draw_batch("LINES", verts, decorator_color_special, edges)
self.line_shader.uniform_float("lineWidth", 2.0)
arc_start = Vector((0, 0.5, 0))
arc_end = angle @ arc_start
angle_half = Matrix.Rotation(radians(self.gn_angle / 2), 4, "Z")
arc_mid = angle_half @ arc_start
arc_segments = tool.Cad.create_arc_segments(
pts=[arc_start, arc_mid, arc_end], num_verts=12, make_edges=True
)
verts, edges = arc_segments
self.draw_batch("LINES", verts, decorator_color_special, edges)
if GeoreferenceData.data["true_north"]:
points = [Vector((0, 0, 0)), Vector((0, 0.75, 0))]
angle = Matrix.Rotation(radians(self.tn_angle), 4, "Z")
points = [angle @ v for v in points]
self.draw_batch("POINTS", points, decorator_color_special)
verts = [Vector((0, 0, 0)), Vector((0, 0.75, 0))]
edges = [[0, 1]]
angle = Matrix.Rotation(radians(self.tn_angle), 4, "Z")
verts = [angle @ v for v in verts]
self.draw_batch("LINES", verts, decorator_color_special, edges)
verts = [Vector((0, 0.75, 0)), Vector((-0.15, 0.6, 0)), Vector((0.15, 0.6, 0))]
edges = [[0, 1], [0, 2]]
verts = [angle @ v for v in verts]
self.line_shader.uniform_float("lineWidth", 5.0)
self.draw_batch("LINES", verts, decorator_color_special, edges)
self.line_shader.uniform_float("lineWidth", 2.0)
arc_start = Vector((0, 0.25, 0))
arc_end = angle @ arc_start
angle_half = Matrix.Rotation(radians(self.tn_angle / 2), 4, "Z")
arc_mid = angle_half @ arc_start
arc_segments = tool.Cad.create_arc_segments(
pts=[arc_start, arc_mid, arc_end], num_verts=12, make_edges=True
)
verts, edges = arc_segments
self.draw_batch("LINES", verts, decorator_color_special, edges)
if wcs_matrix:
if wcs_matrix.translation.length < 1000:
verts = [Vector((0, 0, 0)), wcs_matrix.translation]
edges = [[0, 1]]
self.draw_batch("LINES", verts, decorator_color_special, edges)
self.draw_batch("POINTS", verts[1:], decorator_color_special)
else:
edges = [[0, 1]]
verts = [Vector((0, 0, 0)), wcs_matrix.translation.normalized() * 3]
self.draw_batch("LINES", verts, decorator_color_special, edges)
verts = [wcs_matrix.translation.normalized() * 3, wcs_matrix.translation.normalized() * 3.1]
self.draw_batch("LINES", verts, decorator_color_error, edges)
verts = [wcs_matrix.translation.normalized() * 3.12, wcs_matrix.translation.normalized() * 3.2]
self.draw_batch("LINES", verts, decorator_color_error, edges)
verts = [wcs_matrix.translation.normalized() * 3.22, wcs_matrix.translation.normalized() * 3.3]
self.draw_batch("LINES", verts, decorator_color_error, edges)
verts = [wcs_matrix.translation.normalized() * 3.32, wcs_matrix.translation.normalized() * 3.4]
self.draw_batch("LINES", verts, decorator_color_error, edges)
def calculate_angles(self, context):
self.pn_angle = 0.0
self.gn_angle = float(GeoreferenceData.data["map_derived_angle"] or 0)
self.tn_angle = float(GeoreferenceData.data["true_derived_angle"] or 0)
props = context.scene.BIMGeoreferenceProperties
if props.has_blender_offset:
blender_angle = ifcopenshell.util.geolocation.xaxis2angle(
float(props.blender_x_axis_abscissa), float(props.blender_x_axis_ordinate)
)
self.pn_angle += blender_angle
self.gn_angle += blender_angle
self.tn_angle += blender_angle
self.pn_angle = tool.Cad.normalise_angle(self.pn_angle)
self.gn_angle = tool.Cad.normalise_angle(self.gn_angle)
self.tn_angle = tool.Cad.normalise_angle(self.tn_angle)
@@ -20,7 +20,6 @@ import bpy
import blenderbim.tool as tool
import blenderbim.core.georeference as core
from blenderbim.bim.module.georeference.decorator import GeoreferenceDecorator
class AddGeoreferencing(bpy.types.Operator, tool.Ifc.Operator):
@@ -30,7 +29,7 @@ class AddGeoreferencing(bpy.types.Operator, tool.Ifc.Operator):
bl_description = "Add a new georeference"
def _execute(self, context):
core.add_georeferencing(tool.Georeference)
core.add_georeferencing(tool.Ifc)
class EnableEditingGeoreferencing(bpy.types.Operator, tool.Ifc.Operator):
@@ -107,6 +106,21 @@ class GetCursorLocation(bpy.types.Operator, tool.Ifc.Operator):
core.get_cursor_location(tool.Georeference)
class SetCursorLocation(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.set_cursor_location"
bl_label = "Set Cursor Location"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Move cursor location to the specified coordinates"
@classmethod
def poll(cls, context):
props = context.scene.BIMGeoreferenceProperties
return tool.Ifc.get() and props.coordinate_output.count(",") == 2
def _execute(self, context):
core.set_cursor_location(tool.Georeference)
class SetIfcTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.set_ifc_true_north"
bl_label = "Set IFC True North"
@@ -137,7 +151,7 @@ class ConvertLocalToGlobal(bpy.types.Operator, tool.Ifc.Operator):
def poll(cls, context):
file = tool.Ifc.get()
props = context.scene.BIMGeoreferenceProperties
return file and props.local_coordinates.count(",") == 2
return file and props.coordinate_input.count(",") == 2
def _execute(self, context):
core.convert_local_to_global(tool.Georeference)
@@ -153,7 +167,7 @@ class ConvertGlobalToLocal(bpy.types.Operator, tool.Ifc.Operator):
def poll(cls, context):
file = tool.Ifc.get()
props = context.scene.BIMGeoreferenceProperties
return file and file.by_type("IfcUnitAssignment") and props.local_coordinates.count(",") == 2
return file and file.by_type("IfcUnitAssignment") and props.coordinate_input.count(",") == 2
def _execute(self, context):
core.convert_global_to_local(tool.Georeference)
@@ -190,73 +204,3 @@ class ImportPlot(bpy.types.Operator, tool.Ifc.Operator):
def invoke(self, context, event):
context.window_manager.fileselect_add(self)
return {"RUNNING_MODAL"}
class EnableEditingWCS(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_wcs"
bl_label = "Enable Editing WCS"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Enable editing WCS"
def _execute(self, context):
core.enable_editing_wcs(tool.Georeference)
class EditWCS(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_wcs"
bl_label = "Edit WCS"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Edit the WCS"
def _execute(self, context):
core.edit_wcs(tool.Ifc, tool.Georeference)
class DisableEditingWCS(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_wcs"
bl_label = "Disable Editing WCS"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Close editing panel"
def _execute(self, context):
core.disable_editing_wcs(tool.Georeference)
class EnableEditingTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.enable_editing_true_north"
bl_label = "Enable Editing True North"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Enable editing True North"
def _execute(self, context):
core.enable_editing_true_north(tool.Georeference)
class EditTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.edit_true_north"
bl_label = "Edit True North"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Edit the True North"
def _execute(self, context):
core.edit_true_north(tool.Ifc, tool.Georeference)
class DisableEditingTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.disable_editing_true_north"
bl_label = "Disable Editing True North"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Close editing panel"
def _execute(self, context):
core.disable_editing_true_north(tool.Georeference)
class RemoveTrueNorth(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.remove_true_north"
bl_label = "Remove True North"
bl_options = {"REGISTER", "UNDO"}
bl_description = "Remove true north"
def _execute(self, context):
core.remove_true_north(tool.Ifc)
@@ -17,8 +17,7 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import ifcopenshell.util.geolocation
from blenderbim.bim.prop import Attribute
from blenderbim.bim.prop import StrProperty, Attribute
from bpy.types import PropertyGroup
from bpy.props import (
PointerProperty,
@@ -30,132 +29,26 @@ from bpy.props import (
FloatVectorProperty,
CollectionProperty,
)
from blenderbim.bim.module.georeference.data import GeoreferenceData
from blenderbim.bim.module.georeference.decorator import GeoreferenceDecorator
def get_coordinate_operation_class(self, context):
if not GeoreferenceData.is_loaded:
GeoreferenceData.load()
return GeoreferenceData.data["coordinate_operation_class"]
def update_true_north_angle(self, context):
if self.is_changing_angle:
return
self.is_changing_angle = True
try:
x, y = ifcopenshell.util.geolocation.angle2yaxis(float(self.true_north_angle))
self.true_north_abscissa = str(x)
self.true_north_ordinate = str(y)
except:
pass
self.is_changing_angle = False
def update_true_north_vector(self, context):
if self.is_changing_angle:
return
self.is_changing_angle = True
try:
x = float(self.true_north_abscissa)
y = float(self.true_north_ordinate)
self.true_north_angle = str(round(ifcopenshell.util.geolocation.yaxis2angle(x, y), 7))
except:
pass
self.is_changing_angle = False
def update_grid_north_angle(self, context):
if self.is_changing_angle:
return
self.is_changing_angle = True
try:
x, y = ifcopenshell.util.geolocation.angle2xaxis(float(self.grid_north_angle))
self.x_axis_abscissa = str(x)
self.x_axis_ordinate = str(y)
self.x_axis_is_null = False
except:
pass
self.is_changing_angle = False
def update_grid_north_vector(self, context):
if self.is_changing_angle:
return
self.is_changing_angle = True
try:
x = float(self.x_axis_abscissa)
y = float(self.x_axis_ordinate)
self.grid_north_angle = str(round(ifcopenshell.util.geolocation.xaxis2angle(x, y), 7))
self.x_axis_is_null = False
except:
pass
self.is_changing_angle = False
def update_should_visualise(self, context):
if self.should_visualise:
GeoreferenceDecorator.install(bpy.context)
else:
GeoreferenceDecorator.uninstall()
class BIMGeoreferenceProperties(PropertyGroup):
coordinate_operation_class: bpy.props.EnumProperty(
items=get_coordinate_operation_class, name="Coordinate Operation Class"
)
is_changing_angle: BoolProperty(name="Is Changing Angle", default=False)
is_editing: BoolProperty(name="Is Editing")
is_editing_wcs: BoolProperty(name="Is Editing WCS")
is_editing_true_north: BoolProperty(name="Is Editing True North")
coordinate_operation: CollectionProperty(name="Coordinate Operation", type=Attribute)
map_conversion: CollectionProperty(name="Map Conversion", type=Attribute)
projected_crs: CollectionProperty(name="Projected CRS", type=Attribute)
local_coordinates: StringProperty(
name="Local Coordinates", description='Formatted "x,y,z" (without quotes)', default="0,0,0"
)
map_coordinates: StringProperty(
name="Map Coordinates", description='Formatted "x,y,z" (without quotes)', default="0,0,0"
)
should_visualise: BoolProperty(
name="Should Visualise",
description="Displays a visualisation of all georeferencing data at the origin",
default=False,
update=update_should_visualise,
)
grid_north_angle: StringProperty(name="Grid North Angle", update=update_grid_north_angle)
x_axis_abscissa: StringProperty(name="X Axis Abscissa", update=update_grid_north_vector)
x_axis_ordinate: StringProperty(name="X Axis Ordinate", update=update_grid_north_vector)
x_axis_is_null: BoolProperty(name="X Axis Is Null")
# These are only for reference to capture data about a host model from a linked model
# If you relink a model from a new host origin, we can autodetect it in theory with this
host_model_origin: StringProperty(name="Host Model Origin")
host_model_origin_si: StringProperty(name="Host Model Origin SI")
host_model_project_north: StringProperty(name="Host Model Angle to Grid North")
# This is the ENH in project units and SI units of the Blender session's 0,0,0.
# These are only for reference, using tool.Georeference.set_model_origin on
# project load, project create, and when linking for the first time from an
# empty Blender session.
model_origin: StringProperty(name="Model Origin")
model_origin_si: StringProperty(name="Model Origin SI")
model_project_north: StringProperty(name="Model Angle to Grid North")
# True if there is a temporary Blender session coordinate system
coordinate_input: StringProperty(name="Coordinate Input", description='Formatted "x,y,z" (without quotes)')
coordinate_output: StringProperty(name="Coordinate Output", description='Formatted "x,y,z" (without quotes)')
angle_degree_input_x: FloatProperty(name="Angle Degree Input", description="Angle (in degrees) rel to Easting")
angle_degree_input_y: FloatProperty(name="Angle Degree Input", description="Angle (in degrees) rel to +Y")
x_axis_abscissa_output: StringProperty(name="X Axis Abscissa Ordinate Output", description="X axis abscissa and ordinate", )
x_axis_ordinate_output: StringProperty(name="X Axis Abscissa Ordinate Output", description="X axis abscissa and ordinate", )
y_axis_abscissa_output: StringProperty(name="Y Axis Abscissa Ordinate Output", description="Y axis abscissa and ordinate", )
y_axis_ordinate_output: StringProperty(name="Y Axis Abscissa Ordinate Output", description="Y axis abscissa and ordinate", )
has_blender_offset: BoolProperty(name="Has Blender Offset")
# These are the helmert transformation parameters of the Blender session
blender_offset_x: StringProperty(name="Blender Offset X", default="0")
blender_offset_y: StringProperty(name="Blender Offset Y", default="0")
blender_offset_z: StringProperty(name="Blender Offset Z", default="0")
blender_eastings: StringProperty(name="Blender Eastings", default="0")
blender_northings: StringProperty(name="Blender Northings", default="0")
blender_orthogonal_height: StringProperty(name="Blender Orthogonal Height", default="0")
blender_x_axis_abscissa: StringProperty(name="Blender X Axis Abscissa", default="1")
blender_x_axis_ordinate: StringProperty(name="Blender X Axis Ordinate", default="0")
true_north_angle: StringProperty(name="True North Angle", update=update_true_north_angle)
true_north_abscissa: StringProperty(name="True North Abscissa", update=update_true_north_vector)
true_north_ordinate: StringProperty(name="True North Ordinate", update=update_true_north_vector)
wcs_x: StringProperty(name="WCS X", default="0")
wcs_y: StringProperty(name="WCS Y", default="0")
wcs_z: StringProperty(name="WCS Z", default="0")
wcs_rotation: StringProperty(name="WCS Rotation", default="0")
has_true_north: BoolProperty(name="Has True North", default=True)
true_north_abscissa: StringProperty(name="True North Abscissa")
true_north_ordinate: StringProperty(name="True North Ordinate")

Some files were not shown because too many files have changed in this diff Show More