mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 16:01:36 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0f835ca739 | |||
| 87442f549f | |||
| bf27e41275 | |||
| 66cf06c990 | |||
| 5757a62b6f | |||
| e2552e3d46 | |||
| 1b91540c96 | |||
| 274b12e5a0 | |||
| 496ba6f22d |
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
+15
-13
@@ -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:
|
||||
@@ -35,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pyver: [py39, py310, py311, py312]
|
||||
pyver: [py39, py310, py311]
|
||||
config:
|
||||
- {
|
||||
name: "Windows Build",
|
||||
@@ -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}}"
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+21
-9
@@ -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
|
||||
@@ -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
|
||||
|
||||
+14
-12
@@ -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}}"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil shapely
|
||||
pip install xmlschema xsdata numpy lxml pytest isodate lark networkx tabulate python-dateutil
|
||||
pip install src/bcf --no-deps
|
||||
pip install https://github.com/Andrej730/aud/archive/refs/heads/master-reduced-size.zip
|
||||
|
||||
@@ -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_add1" \
|
||||
-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
|
||||
|
||||
@@ -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
|
||||
|
||||
+198
-280
@@ -17,35 +17,26 @@
|
||||
# #
|
||||
################################################################################
|
||||
|
||||
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")
|
||||
endif()
|
||||
set(EXTRA_VERSION "-alpha.3")
|
||||
|
||||
option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF)
|
||||
option(WASM_BUILD "Build a WebAssembly binary." OFF)
|
||||
@@ -67,36 +58,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 +137,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 +167,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 +175,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 +189,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 +212,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 +234,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 +280,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 +313,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 +388,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 +399,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 +459,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 +471,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 +564,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 +607,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 +650,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 +681,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 +725,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,19 +757,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}
|
||||
${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()
|
||||
|
||||
@@ -832,7 +852,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)
|
||||
@@ -840,37 +860,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
|
||||
@@ -909,70 +914,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})
|
||||
@@ -982,10 +946,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)
|
||||
@@ -1002,8 +966,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})
|
||||
@@ -1013,61 +977,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
|
||||
@@ -1100,32 +1030,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
|
||||
@@ -1137,13 +1063,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
|
||||
@@ -1164,8 +1083,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)
|
||||
@@ -1192,12 +1111,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}
|
||||
@@ -1213,7 +1132,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)
|
||||
@@ -1228,10 +1147,9 @@ endif()
|
||||
|
||||
# Packaging
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
||||
"/\\\\.git"
|
||||
"/build/"
|
||||
.git
|
||||
.gitignore
|
||||
)
|
||||
set(CPACK_SOURCE_INSTALLED_DIRECTORIES "${CMAKE_SOURCE_DIR}/..;/")
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}")
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}")
|
||||
@@ -1261,6 +1179,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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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.7.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
|
||||
|
||||
+6
-77
@@ -51,7 +51,6 @@
|
||||
###############################################################################
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import subprocess as sp
|
||||
import shutil
|
||||
@@ -80,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"
|
||||
@@ -91,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"
|
||||
@@ -189,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',),
|
||||
@@ -203,9 +200,7 @@ dependency_tree = {
|
||||
'json': (),
|
||||
'hdf5': (),
|
||||
'cgal': (),
|
||||
'eigen': (),
|
||||
'freetype': (),
|
||||
# 'usd': ('boost', 'oneTBB')
|
||||
}
|
||||
|
||||
def v(dep):
|
||||
@@ -472,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", "")
|
||||
@@ -499,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
|
||||
@@ -513,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}",
|
||||
@@ -528,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"
|
||||
@@ -540,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(
|
||||
@@ -576,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")
|
||||
@@ -600,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,
|
||||
@@ -774,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")
|
||||
@@ -829,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:
|
||||
@@ -894,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...")
|
||||
|
||||
|
||||
@@ -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
-4
@@ -1,5 +1,2 @@
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.pyright]
|
||||
reportInvalidTypeForm = false
|
||||
line-length = 120
|
||||
+4
-26
@@ -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
|
||||
@@ -13,11 +13,11 @@ readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
keywords = ["IFC", "BCF", "BIM"]
|
||||
dependencies = [
|
||||
"xsdata>=24.4",
|
||||
"xsdata",
|
||||
"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
|
||||
@@ -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"
|
||||
|
||||
@@ -10,14 +10,14 @@ from xsdata.formats.dataclass.serializers.config import SerializerConfig
|
||||
def build_xml_parser(context: Optional[XmlContext] = None) -> XmlParser:
|
||||
"""Return a parser for an XML file."""
|
||||
parser = XmlParser(context=context or XmlContext())
|
||||
parser.register_namespace(ns_map=parser.ns_map, prefix="xs", uri="http://www.w3.org/2001/XMLSchema")
|
||||
parser.register_namespace("xs", "http://www.w3.org/2001/XMLSchema")
|
||||
return parser
|
||||
|
||||
|
||||
def build_serializer(context: Optional[XmlContext] = None) -> XmlSerializer:
|
||||
"""Return a serializer for an XML file."""
|
||||
return XmlSerializer(
|
||||
config=SerializerConfig(indent=" "),
|
||||
config=SerializerConfig(pretty_print=True),
|
||||
context=context or XmlContext(),
|
||||
)
|
||||
|
||||
@@ -36,9 +36,8 @@ class AbstractXmlParserSerializer(Protocol):
|
||||
xml: The XML file as bytes.
|
||||
clazz: The class to parse to.
|
||||
"""
|
||||
...
|
||||
|
||||
def serialize(self, obj: object, ns_map: Optional[dict[str, str]] = None) -> str:
|
||||
def serialize(self, obj: T, ns_map: Optional[dict[str, str]] = None) -> str:
|
||||
"""
|
||||
Serialize an object to XML.
|
||||
|
||||
@@ -49,7 +48,6 @@ class AbstractXmlParserSerializer(Protocol):
|
||||
Returns:
|
||||
The XML as string.
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
class XmlParserSerializer:
|
||||
@@ -70,7 +68,7 @@ class XmlParserSerializer:
|
||||
"""
|
||||
return self.parser.from_bytes(xml, clazz)
|
||||
|
||||
def serialize(self, obj: object, ns_map: Optional[dict[Optional[str], str]] = None) -> str:
|
||||
def serialize(self, obj: T, ns_map: Optional[dict[str, str]] = None) -> str:
|
||||
"""
|
||||
Serialize an object to XML.
|
||||
|
||||
@@ -81,5 +79,5 @@ class XmlParserSerializer:
|
||||
Returns:
|
||||
The XML as string.
|
||||
"""
|
||||
ns_map = ns_map or self.parser.ns_map or {"xs": "http://www.w3.org/2001/XMLSchema"}
|
||||
ns_map = ns_map or {"xs": "http://www.w3.org/2001/XMLSchema"}
|
||||
return self.serializer.render(obj, ns_map)
|
||||
|
||||
+243
-80
@@ -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
|
||||
@@ -60,33 +55,76 @@ PYLIBDIR:=python3.11
|
||||
PYNUMBER:=311
|
||||
PYPI_VERSION:=3.11
|
||||
endif
|
||||
ifeq ($(PYVERSION), py312)
|
||||
PYLIBDIR:=python3.12
|
||||
PYNUMBER:=312
|
||||
PYPI_VERSION:=3.12
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), linux)
|
||||
PYPI_PLATFORM:=--platform manylinux_2_17_x86_64
|
||||
LXML_ARCH:=manylinux_2_28_x86_64
|
||||
SHAPELY_ARCH:=manylinux_2_17_x86_64.manylinux2014_x86_64
|
||||
PILLOW_ARCH:=manylinux_2_28_x86_64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macos)
|
||||
PYPI_PLATFORM:=--platform macosx_10_10_x86_64
|
||||
PYPI_PLATFORM:=--platform macosx_10_9_x86_64
|
||||
SHAPELY_ARCH:=macosx_10_9_x86_64
|
||||
PILLOW_ARCH:=macosx_10_10_x86_64
|
||||
ifeq ($(PYVERSION), py39)
|
||||
LXML_ARCH:=macosx_11_0_x86_64
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
LXML_ARCH:=macosx_11_0_x86_64
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
LXML_ARCH:=macosx_11_0_universal2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
PYPI_PLATFORM:=--platform macosx_11_0_arm64
|
||||
LXML_ARCH:=macosx_11_0_universal2
|
||||
SHAPELY_ARCH:=macosx_11_0_arm64
|
||||
PILLOW_ARCH:=macosx_11_0_arm64
|
||||
endif
|
||||
|
||||
ifeq ($(PLATFORM), win)
|
||||
PYPI_PLATFORM:=--platform win_amd64
|
||||
LXML_ARCH:=win_amd64
|
||||
SHAPELY_ARCH:=win_amd64
|
||||
PILLOW_ARCH:=win_amd64
|
||||
endif
|
||||
|
||||
LXML_NAME:=lxml
|
||||
LXML_VER:=4.9.4
|
||||
SHAPELY_NAME:=shapely
|
||||
SHAPELY_VER:=2.0.2
|
||||
PILLOW_NAME:=pillow
|
||||
PILLOW_PKG_NAME:=Pillow
|
||||
PILLOW_VER:=9.5.0
|
||||
SHAPELY_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/s/$(SHAPELY_NAME)/$(SHAPELY_NAME)-$(SHAPELY_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(SHAPELY_ARCH).whl
|
||||
PILLOW_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/p/$(PILLOW_NAME)/$(PILLOW_PKG_NAME)-$(PILLOW_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(PILLOW_ARCH).whl
|
||||
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
ifeq ($(PYVERSION), py39)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py39h0520ce3_1.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py310)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py310h02f21da_0.tar.bz2
|
||||
endif
|
||||
ifeq ($(PYVERSION), py311)
|
||||
LXML_URL:=https://anaconda.org/conda-forge/lxml/4.9.1/download/osx-arm64/lxml-4.9.1-py311h246f609_1.tar.bz2
|
||||
endif
|
||||
else
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/cp$(PYNUMBER)/l/$(LXML_NAME)/$(LXML_NAME)-$(LXML_VER)-cp$(PYNUMBER)-cp$(PYNUMBER)-$(LXML_ARCH).whl
|
||||
endif
|
||||
$(info $$LXML_URL is [${LXML_URL}])
|
||||
$(info $$SHAPELY_URL is [${SHAPELY_URL}])
|
||||
$(info $$PILLOW_URL is [${PILLOW_URL}])
|
||||
|
||||
.PHONY: bump
|
||||
bump:
|
||||
cd . && $(SED) "s/$(OLD)/$(NEW)/" Makefile
|
||||
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:
|
||||
@@ -99,54 +137,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.8.0-90ae709-$(PLATFORM)64.zip
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcopenshell-python-$(PYNUMBER)-v0.7.0-f7c03db-$(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
|
||||
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.8.0/src/ifcopenshell-python/ifcopenshell/util dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
cp -r dist/working/IfcOpenShell-0.8.0/src/ifcopenshell-python/ifcopenshell/api dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
cp dist/working/IfcOpenShell-0.8.0/src/ifcopenshell-python/ifcopenshell/*.py dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
cp dist/working/IfcOpenShell-0.8.0/src/ifcopenshell-python/ifcopenshell/express/rule_executor.py dist/blenderbim/libs/site/packages/ifcopenshell/express/
|
||||
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/
|
||||
@@ -154,6 +192,49 @@ endif
|
||||
cp -r dist/working/site-packages/git dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides Mustache templating in construction documentation
|
||||
# TODO: remove this dependency, it seems overkill and we seem to get by with str replaces
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/3f/e7/8750ba6c6101d6aa5ceeb20c013adf2c6f3554a12c71d75654b468404bfa/pystache-0.6.0.tar.gz
|
||||
cd dist/working && tar -xzvf pystache*
|
||||
cd dist/working/pystache-0.6.0/ && $(PYTHON) setup.py build && cp -r build/lib/pystache ../../blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides SVG export in construction documentation
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/79/e8/7eb2ba188eda14a4b47e33b51f3b4978985f4116655c699bcd18c79279b5/svgwrite-1.3.1.zip
|
||||
cd dist/working && unzip svgwrite*
|
||||
cp -r dist/working/svgwrite-1.3.1/svgwrite dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides fuzzy date parsing for construction sequencing
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/be/ed/5bbc91f03fa4c839c4c7360375da77f9659af5f7086b7a7bdda65771c8e0/python-dateutil-2.8.1.tar.gz
|
||||
cd dist/working && tar -xzvf python-dateutil*
|
||||
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides duration parsing for construction sequencing
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/b1/80/fb8c13a4cd38eb5021dc3741a9e588e4d1de88d895c1910c6fc8a08b7a70/isodate-0.6.0.tar.gz
|
||||
cd dist/working && tar -xzvf isodate*
|
||||
cp -r dist/working/isodate-0.6.0/src/isodate dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides networkx graph analysis for project dependency calculations
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/b0/21/adfbf6168631e28577e4af9eb9f26d75fe72b2bb1d33762a5f2c425e6c2a/networkx-2.5.1.tar.gz
|
||||
cd dist/working && tar -xzvf networkx*
|
||||
cp -r dist/working/networkx-2.5.1/networkx dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by networkx
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/4f/51/15a4f6b8154d292e130e5e566c730d8ec6c9802563d58760666f1818ba58/decorator-5.0.9.tar.gz
|
||||
cd dist/working && tar -xzvf decorator*
|
||||
cp -r dist/working/decorator-5.0.9/src/decorator.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Provides audio playback for costing
|
||||
mkdir -p dist/working
|
||||
git clone https://github.com/Andrej730/aud.git --branch master-reduced-size --depth 1 dist/working/aud
|
||||
@@ -168,6 +249,107 @@ endif
|
||||
cp dist/working/jsgantt* dist/blenderbim/bim/data/gantt/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCDiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/0f/ca/caead2949fbb824c7142e3774fa841aa853bb4d4331b440da8c8514dfc6f/deepdiff-5.8.1.tar.gz
|
||||
cd dist/working && tar -xzvf deepdiff*
|
||||
cp -r dist/working/deepdiff-5.8.1/deepdiff dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by deepdiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/00/55/ce2cbc6d64034b30cad81a29ba61bdba456f190f5e83c09831304bf68d6b/jsonpickle-1.2.tar.gz
|
||||
cd dist/working && tar -xzvf jsonpickle*
|
||||
cp -r dist/working/jsonpickle-1.2/jsonpickle dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by deepdiff
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/a3/b7/d4d69641cbe707a45c23b190f2d717466ba5accc4c70b5f7a8a450387895/ordered-set-3.1.1.tar.gz
|
||||
cd dist/working && tar -xzvf ordered-set*
|
||||
cp -r dist/working/ordered-set-3.1.1/ordered_set.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by lark
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/00/32/8076fa13e832bb4dcff379f18f228e5a53412be0631808b9ca2610c0f566/pyparsing-2.4.5.tar.gz
|
||||
cd dist/working && tar -xzvf pyparsing*
|
||||
cp -r dist/working/pyparsing-2.4.5/pyparsing.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/5b/ef/f97c3e1a7efa00e989a793fe15297214fc95ad7d9e3810586bd08ce9f0f3/xmlschema-2.0.2.tar.gz
|
||||
cd dist/working && tar -xzvf xmlschema*
|
||||
cp -r dist/working/xmlschema-2.0.2/xmlschema dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/ad/c7/17c9d16320d8e2cfdb27d2fd298b5e8f7a3f211025b0c1bc7a39a85bd690/xsdata-22.11.tar.gz
|
||||
cd dist/working && tar -xzvf xsdata*
|
||||
cp -r dist/working/xsdata-22.11/xsdata dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/11/bc/5afb61dd5d863e5cf77cd952445c50c17e65953405986f19e97e4389692a/elementpath-3.0.2.tar.gz
|
||||
cd dist/working && tar -xzvf elementpath*
|
||||
cp -r dist/working/elementpath-3.0.2/elementpath dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by bcf
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/21/9f/b251f7f8a76dec1d6651be194dfba8fb8d7781d10ab3987190de8391d08e/six-1.14.0.tar.gz
|
||||
cd dist/working && tar -xzvf six*
|
||||
cp -r dist/working/six-1.14.0/six.py dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFCCSV and ifcopenshell.util.selector
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/18/4d/8d522136c37d9e1ea74062b41b8d5e1318ebf45063ae46ce72ed60af223b/lark-parser-0.8.5.tar.gz
|
||||
cd dist/working && tar -xzvf lark-parser*
|
||||
cp -r dist/working/lark-parser-0.8.5/lark dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by IFC4D
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/b0/bb/9c4dddd3ca173cb56241cfb2eddfae24690dc676d357ac4cab17d0a36d9d/PyP6Xer-1.13.0.tar.gz
|
||||
cd dist/working && tar -xzvf PyP6Xer*
|
||||
cp -r dist/working/PyP6Xer-1.13.0/xerparser dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by QTOCalculator
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(SHAPELY_URL)
|
||||
cd dist/working && cp *.whl shapely.zip && unzip shapely.zip
|
||||
cp -r dist/working/shapely dist/blenderbim/libs/site/packages/
|
||||
ifeq ($(PLATFORM), win)
|
||||
cp -r dist/working/shapely.libs dist/blenderbim/libs/site/packages/
|
||||
endif
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/shapely.libs dist/blenderbim/libs/site/packages/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by the BIM tool thumbnail generator
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(PILLOW_URL)
|
||||
cd dist/working && cp *.whl pillow.zip && unzip pillow.zip
|
||||
cp -r dist/working/PIL dist/blenderbim/libs/site/packages/
|
||||
ifeq ($(PLATFORM), linux)
|
||||
cp -r dist/working/Pillow.libs dist/blenderbim/libs/site/packages/
|
||||
endif
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by xerparser and IFC4D
|
||||
# TODO: remove this dependency. It's only used to show a progress bar.
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/9f/7b/76c4e5ef1a1b528fcaada4133f972e77d33c252831676cf414119ca6093d/tqdm-4.50.0.tar.gz
|
||||
cd dist/working && tar -xzvf tqdm*
|
||||
cp -r dist/working/tqdm-4.50.0/tqdm dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
mkdir dist/working
|
||||
cd dist/working && $(PYTHON) -m venv env
|
||||
cd dist/working && mkdir site-packages
|
||||
@@ -184,38 +366,7 @@ endif
|
||||
# Provides Brickschema functionality
|
||||
cd dist/working && . env/bin/activate && $(PIP) install "brickschema[persistence]==0.7.6a2" --target=./site-packages
|
||||
# Required for SVG to DXF conversion
|
||||
cd dist/working && . env/bin/activate && $(PIP) install ezdxf --target=./site-packages
|
||||
# Required by bcf
|
||||
cd dist/working && . env/bin/activate && $(PIP) install xsdata --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install xmlschema --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install elementpath --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install six --target=./site-packages
|
||||
# Required by drawing module
|
||||
cd dist/working && . env/bin/activate && $(PIP) install lxml $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Required by qto and drawing module
|
||||
cd dist/working && . env/bin/activate && $(PIP) install shapely $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Required by the BIM type manager thumbnail generator
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pillow $(PYPI_PLATFORM) --python-version $(PYPI_VERSION) --implementation $(PYPI_IMP) --only-binary=:all: --target=./site-packages
|
||||
# Provides mustache templating in construction docs and web UI data
|
||||
cd dist/working && . env/bin/activate && $(PIP) install pystache --target=./site-packages
|
||||
# Provides SVG export in construction documentation
|
||||
cd dist/working && . env/bin/activate && $(PIP) install svgwrite --target=./site-packages
|
||||
# Provides fuzzy date parsing for construction sequencing
|
||||
cd dist/working && . env/bin/activate && $(PIP) install python-dateutil --target=./site-packages
|
||||
# Provides duration parsing for construction sequencing
|
||||
cd dist/working && . env/bin/activate && $(PIP) install isodate --target=./site-packages
|
||||
# Provides networkx graph analysis for project dependency calculations
|
||||
cd dist/working && . env/bin/activate && $(PIP) install networkx --target=./site-packages
|
||||
# Required by IFCDiff
|
||||
cd dist/working && . env/bin/activate && $(PIP) install deepdiff --target=./site-packages
|
||||
# Required by IFCCSV and ifcopenshell.util.selector
|
||||
cd dist/working && . env/bin/activate && $(PIP) install lark --target=./site-packages
|
||||
# Required by IFC4D
|
||||
cd dist/working && . env/bin/activate && $(PIP) install PyP6Xer --target=./site-packages
|
||||
# Required by Web module
|
||||
cd dist/working && . env/bin/activate && $(PIP) install python-socketio[asyncio_client] --target=./site-packages
|
||||
cd dist/working && . env/bin/activate && $(PIP) install aiohttp --target=./site-packages
|
||||
|
||||
cd dist/working && . env/bin/activate && $(PIP) install "ezdxf" --target=./site-packages
|
||||
cp -r dist/working/site-packages/* dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
|
||||
@@ -225,15 +376,33 @@ 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
|
||||
|
||||
# Required by ids - uh, not any more, but I'm trying it out in the drawing module
|
||||
ifeq ($(PLATFORM), macosm1)
|
||||
# No wheels available for MacOS M1, but turns out this Anaconda build works
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(LXML_URL)
|
||||
cd dist/working && tar -xf lxml*
|
||||
cp -r dist/working/lib/$(PYLIBDIR)/site-packages/lxml dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
else
|
||||
# Wheels are preferred for other OSes. A first attempt at using Anaconda
|
||||
# builds for everything shows it breaks on windows. See #2422.
|
||||
mkdir dist/working
|
||||
cd dist/working && wget $(LXML_URL)
|
||||
cd dist/working && cp *.whl lxml.zip && unzip lxml.zip
|
||||
cp -r dist/working/lxml dist/blenderbim/libs/site/packages/
|
||||
rm -rf dist/working
|
||||
endif
|
||||
|
||||
# Required by behave
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/f4/65/220bb4075fddb09d5b3ea2c1c1fa66c1c72be9361ec187aab50fa161e576/parse-1.15.0.tar.gz
|
||||
@@ -265,7 +434,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
|
||||
@@ -289,16 +458,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
|
||||
|
||||
@@ -18,17 +18,10 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Ensure we don't try to import bpy or blenderbim.bim
|
||||
# to support running core tests.
|
||||
# We assume if bpy was never loaded in current python session
|
||||
# then we're not in Blender. It's still possible to use
|
||||
# bpy in core and core tests for annotations using TYPE_CHECKING.
|
||||
IN_BLENDER = sys.modules.get("bpy", None)
|
||||
if IN_BLENDER:
|
||||
import bpy
|
||||
import bpy
|
||||
import platform
|
||||
import traceback
|
||||
import subprocess
|
||||
import webbrowser
|
||||
import addon_utils
|
||||
from collections import deque
|
||||
@@ -38,7 +31,7 @@ bl_info = {
|
||||
"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",
|
||||
@@ -85,7 +78,7 @@ def format_debug_info(info: dict):
|
||||
return text.strip()
|
||||
|
||||
|
||||
if IN_BLENDER:
|
||||
if sys.modules.get("bpy", None):
|
||||
# Process *.pth in /libs/site/packages to setup globally importable modules
|
||||
# This is 3 levels deep as required by the static RPATH of ../../ from dependencies taken from Anaconda
|
||||
# site.addsitedir(os.path.join(os.path.dirname(os.path.realpath(__file__)), "libs", "site", "packages"))
|
||||
@@ -127,16 +120,11 @@ if IN_BLENDER:
|
||||
bl_context = "scene"
|
||||
|
||||
def draw(self, context):
|
||||
info = get_debug_info()
|
||||
|
||||
layout = self.layout
|
||||
layout.alert = True
|
||||
layout.label(text="BlenderBIM could not load.", icon="ERROR")
|
||||
if info["os"] == "Windows":
|
||||
layout.operator("wm.console_toggle", text="View the console for full logs.", icon="CONSOLE")
|
||||
else:
|
||||
layout.label(text="View the console for full logs.", icon="CONSOLE")
|
||||
layout.label(text="View the console for full logs.", icon="CONSOLE")
|
||||
box = layout.box()
|
||||
info = get_debug_info()
|
||||
py = ".".join(info["python_version"].split(".")[0:2])
|
||||
b3d = ".".join(info["blender_version"].split(".")[0:2])
|
||||
box.label(text=f"Blender {b3d} {info['os']} {info['machine']}", icon="BLENDER")
|
||||
@@ -145,21 +133,6 @@ if IN_BLENDER:
|
||||
op = layout.operator("bim.open_uri", text="How Can I Fix This?")
|
||||
op.uri = "https://docs.blenderbim.org/users/troubleshooting.html#installation-issues"
|
||||
|
||||
layout.label(text="Try Reinstalling:", icon="IMPORT")
|
||||
op = layout.operator("bim.open_uri", text="Re-download Add-on")
|
||||
bbim_date = info["blenderbim_version"].split(".")[-1]
|
||||
py_tag = py.replace(".", "")
|
||||
if "Linux" in info["os"]:
|
||||
os = "linux"
|
||||
elif "Darwin" in info["os"]:
|
||||
if "arm64" in info["machine"]:
|
||||
os = "macosm1"
|
||||
else:
|
||||
os = "macos"
|
||||
else:
|
||||
os = "win"
|
||||
op.uri = f"https://github.com/IfcOpenShell/IfcOpenShell/releases/download/blenderbim-{bbim_date}/blenderbim-{bbim_date}-py{py_tag}-{os}.zip"
|
||||
|
||||
class OpenUri(bpy.types.Operator):
|
||||
bl_idname = "bim.open_uri"
|
||||
bl_label = "Open URI"
|
||||
@@ -176,7 +149,14 @@ if IN_BLENDER:
|
||||
|
||||
def execute(self, context):
|
||||
info = format_debug_info(get_debug_info())
|
||||
context.window_manager.clipboard = info
|
||||
|
||||
if platform.system() == "Windows":
|
||||
command = "echo | set /p nul=" + info
|
||||
elif platform.system() == "Darwin": # for MacOS
|
||||
command = 'printf "' + info.replace("\n", "\\n").replace('"', "") + '" | pbcopy'
|
||||
else: # Linux
|
||||
command = 'printf "' + info.replace("\n", "\\n").replace('"', "") + '" | xclip -selection clipboard'
|
||||
subprocess.run(command, shell=True, check=True)
|
||||
return {"FINISHED"}
|
||||
|
||||
class HiddenPanel:
|
||||
|
||||
@@ -84,7 +84,6 @@ modules = {
|
||||
"debug": None,
|
||||
"ifcgit": None,
|
||||
"covering": None,
|
||||
"web": 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,
|
||||
@@ -143,7 +142,6 @@ classes = [
|
||||
ui.BIM_PT_tabs,
|
||||
# Project overview
|
||||
ui.BIM_PT_tab_project_info,
|
||||
ui.BIM_PT_tab_spatial_decomposition,
|
||||
ui.BIM_PT_tab_project_setup,
|
||||
ui.BIM_PT_tab_geometry,
|
||||
ui.BIM_PT_tab_stakeholders,
|
||||
@@ -156,10 +154,9 @@ classes = [
|
||||
ui.BIM_PT_tab_representations,
|
||||
ui.BIM_PT_tab_geometric_relationships,
|
||||
ui.BIM_PT_tab_parametric_geometry,
|
||||
ui.BIM_PT_tab_object_materials,
|
||||
ui.BIM_PT_tab_profiles,
|
||||
ui.BIM_PT_tab_materials,
|
||||
ui.BIM_PT_tab_styles,
|
||||
ui.BIM_PT_tab_profiles,
|
||||
# Drawings and documents
|
||||
ui.BIM_PT_tab_sheets,
|
||||
ui.BIM_PT_tab_drawings,
|
||||
@@ -172,7 +169,6 @@ classes = [
|
||||
ui.BIM_PT_tab_structural,
|
||||
# Construction scheduling
|
||||
ui.BIM_PT_tab_status,
|
||||
ui.BIM_PT_tab_qto,
|
||||
ui.BIM_PT_tab_resources,
|
||||
ui.BIM_PT_tab_cost,
|
||||
ui.BIM_PT_tab_sequence,
|
||||
@@ -224,6 +220,7 @@ 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)
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
* Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
*
|
||||
* This file is part of BlenderBIM Add-on.
|
||||
*
|
||||
* BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY, without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* You may copy this `schedule.css` template alongside your input schedule
|
||||
* document with the same filename. For example if you have a schedule called
|
||||
* `door_types.ods`, you can create a `door_types.css` in the same folder to
|
||||
* style that schedule.
|
||||
*/
|
||||
|
||||
/**
|
||||
* If you specify a font size in CSS, such as text { font-size: 5; }, all fonts
|
||||
* will be overriden to match that size.
|
||||
*
|
||||
* If your CSS, ODS, XLSX does not specify a font size, the variables below
|
||||
* will specify the default font size.
|
||||
*
|
||||
* If your ODS, XLSX does specify a font size, they will scale linearly based
|
||||
* on the variables below.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--font-size-pt: 12;
|
||||
--font-size-px: 4.13;
|
||||
--font-width: 0.45;
|
||||
}
|
||||
|
||||
text, tspan { /* 2.5mm */ fill: black; stroke: none; font-family: 'OpenGost Type B TT', 'DejaVu Sans Condensed', 'Liberation Sans', 'Arial Narrow', 'Arial'; }
|
||||
@@ -5,7 +5,6 @@ FILE_NAME('EQto_BodyGeometryValidation.ifc','2020-01-01T00:00:00',(),(),'EQto_Bo
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
/* This quantity set is Qto_BodyGeometryValidation backport from IFC4X3 to support IFC4. */
|
||||
#1=IFCPROPERTYSETTEMPLATE('2KS9su6r517uLXTGKwwDdn',$,'EQto_BodyGeometryValidation','Quantities supplied for validating the correct interpretation of the body shape representation at import. In case of multiple representation items, the quantities are summed for each of the items (irrespective of any overlap). Choosing a suitable tolerance value for comparing the supplied numbers to the numbers calculated from the reconstructed geometry is at the discretion of the importing application.',.QTO_OCCURRENCEDRIVEN.,'IfcProduct',(#2,#3,#4,#5,#6,#7));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('3iCdOOLRjCwQ_HRTB41Xh8',$,'GrossSurfaceArea','Total gross area of the object, normally generated as perimeter * length + 2 * cross section area. It is the sum of OuterSurfaceArea + (2 x CrossSectionArea) and shall only be given, if the OuterSurfaceArea and CrossSectionArea cannot be established separately.\X2\000A000A\X0\Total gross surface area of the element before applying product-level geometric features such as openings and projections.',.Q_AREA.,$,$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('0juemEqF5889vg7HwR87Fv',$,'NetSurfaceArea','Net surface area of the object, normally generated as perimeter * length + 2 * cross section area taking into account possible processing features (cut-out''s, etc.) or openings and recesses.\X2\000A000A\X0\Total net surface area of the element after applying product-level geometric features such as openings and projections.',.Q_AREA.,$,$,$,$,$,$,.READWRITE.);
|
||||
|
||||
@@ -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>
|
||||
Binary file not shown.
@@ -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)
|
||||
|
||||
@@ -51,6 +51,8 @@ def name_callback(obj, data):
|
||||
return
|
||||
|
||||
if isinstance(obj, bpy.types.Material):
|
||||
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()
|
||||
@@ -84,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()
|
||||
@@ -186,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
|
||||
@@ -296,8 +301,7 @@ def load_post(scene):
|
||||
|
||||
if bpy.context.preferences.addons["blenderbim"].preferences.should_setup_workspace:
|
||||
if "BIM" in bpy.data.workspaces:
|
||||
if bpy.context.preferences.addons["blenderbim"].preferences.activate_workspace:
|
||||
bpy.context.window.workspace = bpy.data.workspaces["BIM"]
|
||||
bpy.context.window.workspace = bpy.data.workspaces["BIM"]
|
||||
else:
|
||||
bpy.ops.workspace.append_activate(idname="BIM", filepath=os.path.join(cwd, "data", "workspace.blend"))
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from mathutils import geometry
|
||||
from mathutils import Vector
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from typing import Optional, Callable, Any, Union
|
||||
from typing import Optional, Callable, Any
|
||||
|
||||
|
||||
def draw_attributes(props, layout, copy_operator=None, popup_active_attribute=None):
|
||||
@@ -91,11 +91,7 @@ def import_attributes(ifc_class, props, data, callback=None):
|
||||
|
||||
|
||||
# A more elegant attribute importer signature, intended to supersede import_attributes
|
||||
def import_attributes2(
|
||||
element: Union[str, ifcopenshell.entity_instance],
|
||||
props: bpy.types.PropertyGroup,
|
||||
callback: Optional[Callable] = None,
|
||||
) -> None:
|
||||
def import_attributes2(element, props, callback=None):
|
||||
if isinstance(element, str):
|
||||
attributes = tool.Ifc.schema().declaration_by_name(element).as_entity().all_attributes()
|
||||
info = {a.name(): None for a in attributes}
|
||||
@@ -225,6 +221,15 @@ def get_enum_items(data, prop_name, context=None):
|
||||
return items
|
||||
|
||||
|
||||
# hack to close popup
|
||||
# https://blender.stackexchange.com/a/202576/130742
|
||||
def close_operator_panel(event):
|
||||
x, y = event.mouse_x, event.mouse_y
|
||||
bpy.context.window.cursor_warp(10, 10)
|
||||
move_back = lambda: bpy.context.window.cursor_warp(x, y)
|
||||
bpy.app.timers.register(move_back, first_interval=0.01)
|
||||
|
||||
|
||||
def convert_property_group_from_si(property_group, skip_props=()):
|
||||
"""Method converts property group values from si to current ifc project units
|
||||
|
||||
@@ -304,9 +309,6 @@ def draw_filter(layout, filter_groups, data, module):
|
||||
elif ifc_filter.type == "group":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="OUTLINER_COLLECTION")
|
||||
elif ifc_filter.type == "parent":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "value", text="", icon="FILE_PARENT")
|
||||
elif ifc_filter.type == "query":
|
||||
row = box.row(align=True)
|
||||
row.prop(ifc_filter, "name", text="", icon="POINTCLOUD_DATA")
|
||||
|
||||
@@ -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
|
||||
@@ -210,7 +195,7 @@ class IfcStore:
|
||||
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)
|
||||
@@ -219,7 +204,7 @@ class IfcStore:
|
||||
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
|
||||
@@ -234,10 +219,12 @@ 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(obj=existing_obj)
|
||||
except:
|
||||
pass
|
||||
IfcStore.id_map[element.id()] = obj
|
||||
if hasattr(element, "GlobalId"):
|
||||
IfcStore.guid_map[element.GlobalId] = obj
|
||||
@@ -249,25 +236,27 @@ class IfcStore:
|
||||
|
||||
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"])
|
||||
@@ -275,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
|
||||
)
|
||||
@@ -283,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"])
|
||||
@@ -292,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"]]
|
||||
@@ -301,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.BIMMaterialProperties.ifc_style_id = 0
|
||||
else:
|
||||
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})
|
||||
@@ -415,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
|
||||
@@ -438,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
@@ -36,6 +36,7 @@ class AggregateData:
|
||||
"relating_object_label": cls.get_relating_object_label(),
|
||||
"has_related_objects": cls.has_related_objects(),
|
||||
"total_parts": cls.total_parts(),
|
||||
"ifc_class": cls.ifc_class(),
|
||||
"total_linked_aggregate": cls.total_linked_aggregate(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
@@ -67,6 +68,12 @@ class AggregateData:
|
||||
def has_related_objects(cls) -> bool:
|
||||
return bool(cls.get_related_objects())
|
||||
|
||||
@classmethod
|
||||
def ifc_class(cls) -> str:
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
if element:
|
||||
return element.is_a()
|
||||
|
||||
@classmethod
|
||||
def total_linked_aggregate(cls):
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object)
|
||||
|
||||
@@ -40,39 +40,36 @@ class BIM_OT_aggregate_assign_object(bpy.types.Operator, Operator):
|
||||
bl_label = "Assign Object To Aggregation"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
relating_object: bpy.props.IntProperty()
|
||||
related_object: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
relating_obj = None
|
||||
if self.relating_object:
|
||||
relating_obj = tool.Ifc.get_object(tool.Ifc.get().by_id(self.relating_object))
|
||||
elif self.related_object:
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(tool.Ifc.get().by_id(self.related_object))
|
||||
if aggregate:
|
||||
relating_obj = tool.Ifc.get_object(aggregate)
|
||||
element = tool.Ifc.get().by_id(self.relating_object)
|
||||
if element.IsDecomposedBy:
|
||||
relating_obj = tool.Ifc.get_object(element)
|
||||
else:
|
||||
assembly = element.Decomposes[0].RelatingObject
|
||||
relating_obj = tool.Ifc.get_object(assembly)
|
||||
elif context.active_object:
|
||||
relating_obj = context.active_object
|
||||
if not relating_obj:
|
||||
return
|
||||
|
||||
for obj in tool.Blender.get_selected_objects():
|
||||
for obj in bpy.context.selected_objects:
|
||||
if obj == relating_obj:
|
||||
continue
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
continue
|
||||
try:
|
||||
core.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=relating_obj,
|
||||
related_obj=obj,
|
||||
)
|
||||
except core.IncompatibleAggregateError:
|
||||
self.report({"ERROR"}, f"Cannot aggregate {obj.name} to {relating_obj.name}")
|
||||
except core.AggregateRepresentationError:
|
||||
self.report({"ERROR"}, f"Cannot aggregate to {relating_obj.name} with a body representation")
|
||||
result = core.assign_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
relating_obj=relating_obj,
|
||||
related_obj=obj,
|
||||
)
|
||||
if not result:
|
||||
self.report({"ERROR"}, f" Cannot aggregate {obj.name} to {relating_obj.name}")
|
||||
|
||||
|
||||
class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
|
||||
@@ -103,7 +100,7 @@ class BIM_OT_aggregate_unassign_object(bpy.types.Operator, Operator):
|
||||
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)
|
||||
ifcopenshell.api.run("pset.remove_pset", tool.Ifc.get(), pset=pset)
|
||||
|
||||
|
||||
class BIM_OT_enable_editing_aggregate(bpy.types.Operator, Operator):
|
||||
@@ -159,6 +156,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:
|
||||
@@ -274,23 +272,23 @@ class BIM_OT_add_part_to_object(bpy.types.Operator, Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
part_class: bpy.props.StringProperty(name="Class", options={"HIDDEN"})
|
||||
part_name: bpy.props.StringProperty(name="Name")
|
||||
element: bpy.props.IntProperty(options={"HIDDEN"})
|
||||
obj: bpy.props.StringProperty(options={"HIDDEN"})
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.part_name = "My " + self.part_class.lstrip("Ifc")
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) or context.active_object
|
||||
core.add_part_to_object(
|
||||
tool.Ifc,
|
||||
tool.Aggregate,
|
||||
tool.Collector,
|
||||
tool.Blender,
|
||||
obj=tool.Ifc.get_object(tool.Ifc.get().by_id(self.element)) if self.element else context.active_object,
|
||||
obj=obj,
|
||||
part_class=self.part_class,
|
||||
part_name=self.part_name,
|
||||
)
|
||||
blenderbim.core.spatial.import_spatial_decomposition(tool.Spatial)
|
||||
|
||||
|
||||
class BIM_OT_break_link_to_other_aggregates(bpy.types.Operator, Operator):
|
||||
|
||||
@@ -34,27 +34,15 @@ from bpy.props import (
|
||||
|
||||
def update_relating_object(self, context):
|
||||
def message(self, context):
|
||||
self.layout.label(text="Please select a valid IFC Element")
|
||||
self.layout.label(text="Please select a valid Ifc Element")
|
||||
|
||||
if self.relating_object:
|
||||
self.related_object = None
|
||||
if not self.relating_object.BIMObjectProperties.ifc_definition_id:
|
||||
context.window_manager.popup_menu(message, title="Invalid Element Selected", icon="INFO")
|
||||
self.relating_object = None
|
||||
|
||||
|
||||
def update_related_object(self, context):
|
||||
def message(self, context):
|
||||
self.layout.label(text="Please select a valid IFC Element")
|
||||
|
||||
if self.related_object:
|
||||
if self.relating_object is None:
|
||||
return
|
||||
if not self.relating_object.BIMObjectProperties.ifc_definition_id:
|
||||
context.window_manager.popup_menu(message, title="Invalid Element Selected", icon="INFO")
|
||||
self.relating_object = None
|
||||
if not self.related_object.BIMObjectProperties.ifc_definition_id:
|
||||
context.window_manager.popup_menu(message, title="Invalid Element Selected", icon="INFO")
|
||||
self.related_object = None
|
||||
|
||||
|
||||
class BIMObjectAggregateProperties(PropertyGroup):
|
||||
is_editing: BoolProperty(name="Is Editing")
|
||||
relating_object: PointerProperty(name="Relating Whole", type=bpy.types.Object, update=update_relating_object)
|
||||
related_object: PointerProperty(name="Related Part", type=bpy.types.Object, update=update_related_object)
|
||||
relating_object: PointerProperty(name="Aggregate", type=bpy.types.Object, update=update_relating_object)
|
||||
|
||||
@@ -53,21 +53,12 @@ class BIM_PT_aggregate(Panel):
|
||||
props = context.active_object.BIMObjectAggregateProperties
|
||||
|
||||
if props.is_editing:
|
||||
row = layout.row()
|
||||
row.prop(props, "relating_object", text="Whole")
|
||||
row = layout.row()
|
||||
row.prop(props, "related_object", text="Or Part")
|
||||
row = layout.row(align=True)
|
||||
col = row.column(align=True)
|
||||
if not props.relating_object and not props.related_object:
|
||||
col.enabled = False
|
||||
op = col.operator("bim.aggregate_assign_object", icon="CHECKMARK")
|
||||
row.prop(props, "relating_object", text="")
|
||||
if props.relating_object:
|
||||
op = row.operator("bim.aggregate_assign_object", icon="CHECKMARK", text="")
|
||||
op.relating_object = props.relating_object.BIMObjectProperties.ifc_definition_id
|
||||
elif props.related_object:
|
||||
op.related_object = props.related_object.BIMObjectProperties.ifc_definition_id
|
||||
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
|
||||
return
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
if AggregateData.data["has_relating_object"]:
|
||||
@@ -82,7 +73,7 @@ class BIM_PT_aggregate(Panel):
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
op = row.operator("bim.aggregate_unassign_object", icon="X", text="")
|
||||
else:
|
||||
row.label(text="No Whole Relationship Found", icon="TRIA_UP")
|
||||
row.label(text="No Whole relation defined", icon="TRIA_UP")
|
||||
row.operator("bim.enable_editing_aggregate", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.add_aggregate", icon="ADD", text="")
|
||||
|
||||
@@ -99,6 +90,19 @@ class BIM_PT_aggregate(Panel):
|
||||
op = row.operator("bim.select_parts", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.obj = context.active_object.name
|
||||
|
||||
ifc_class = AggregateData.data["ifc_class"]
|
||||
part_class = ""
|
||||
if ifc_class == "IfcBuilding":
|
||||
part_class = "IfcBuildingStorey"
|
||||
elif ifc_class == "IfcSite":
|
||||
part_class = "IfcBuilding"
|
||||
elif ifc_class == "IfcProject":
|
||||
part_class = "IfcSite"
|
||||
if part_class != "":
|
||||
op = layout.operator("bim.add_part_to_object", text="Add " + part_class.lstrip("Ifc"))
|
||||
op.part_class = part_class
|
||||
op.obj = context.active_object.name
|
||||
|
||||
|
||||
class BIM_PT_linked_aggregate(Panel):
|
||||
bl_label = "Linked Aggregates"
|
||||
@@ -140,7 +144,7 @@ class BIM_PT_linked_aggregate(Panel):
|
||||
row.label(text="Not a Linked Aggregate")
|
||||
else:
|
||||
row.label(text=f"{Number_Linked_Aggregates} Linked Aggregates")
|
||||
op = row.operator("bim.duplicate_linked_aggregate_to_3d_cursor", text="", icon="DUPLICATE")
|
||||
op = row.operator("bim.object_duplicate_move_linked_aggregate", text="", icon="DUPLICATE")
|
||||
if type(Number_Linked_Aggregates) is int:
|
||||
if Number_Linked_Aggregates > 0:
|
||||
op = row.operator("bim.select_linked_aggregates", text="", icon="OUTLINER_DATA_POINTCLOUD")
|
||||
|
||||
@@ -27,12 +27,15 @@ classes = (
|
||||
operator.CopyAttributeToSelection,
|
||||
prop.BIMAttributeProperties,
|
||||
ui.BIM_PT_object_attributes,
|
||||
ui.BIM_PT_material_attributes,
|
||||
)
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Object.BIMAttributeProperties = bpy.props.PointerProperty(type=prop.BIMAttributeProperties)
|
||||
bpy.types.Material.BIMAttributeProperties = bpy.props.PointerProperty(type=prop.BIMAttributeProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Object.BIMAttributeProperties
|
||||
del bpy.types.Material.BIMAttributeProperties
|
||||
|
||||
@@ -23,6 +23,7 @@ import blenderbim.tool as tool
|
||||
|
||||
def refresh():
|
||||
AttributesData.is_loaded = False
|
||||
MaterialAttributesData.is_loaded = False
|
||||
|
||||
|
||||
class AttributesData:
|
||||
@@ -50,3 +51,28 @@ class AttributesData:
|
||||
key = "STEP ID"
|
||||
results.append({"name": key, "value": str(value)})
|
||||
return results
|
||||
|
||||
|
||||
class MaterialAttributesData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {"ifc_definition_id": cls.ifc_definition_id(), "attributes": cls.attributes()}
|
||||
cls.is_loaded = True
|
||||
|
||||
@classmethod
|
||||
def ifc_definition_id(cls):
|
||||
return bpy.context.active_object.active_material.BIMObjectProperties.ifc_definition_id
|
||||
|
||||
@classmethod
|
||||
def attributes(cls):
|
||||
results = []
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object.active_material)
|
||||
data = element.get_info()
|
||||
for key, value in data.items():
|
||||
if value is None or isinstance(value, ifcopenshell.entity_instance) or key in ["id", "type"]:
|
||||
continue
|
||||
results.append({"name": key, "value": str(value)})
|
||||
return results
|
||||
|
||||
@@ -40,10 +40,14 @@ class EnableEditingAttributes(bpy.types.Operator):
|
||||
bl_label = "Enable Editing Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
if self.obj_type == "Object":
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
elif self.obj_type == "Material":
|
||||
obj = bpy.data.materials.get(self.obj)
|
||||
props = obj.BIMAttributeProperties
|
||||
props.attributes.clear()
|
||||
|
||||
@@ -81,9 +85,13 @@ class DisableEditingAttributes(bpy.types.Operator):
|
||||
bl_label = "Disable Editing Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
if self.obj_type == "Object":
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
elif self.obj_type == "Material":
|
||||
obj = bpy.data.materials.get(self.obj)
|
||||
props = obj.BIMAttributeProperties
|
||||
props.is_editing_attributes = False
|
||||
return {"FINISHED"}
|
||||
@@ -94,10 +102,14 @@ class EditAttributes(bpy.types.Operator, Operator):
|
||||
bl_label = "Edit Attributes"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
if self.obj_type == "Object":
|
||||
obj = bpy.data.objects.get(self.obj)
|
||||
elif self.obj_type == "Material":
|
||||
obj = bpy.data.materials.get(self.obj)
|
||||
props = obj.BIMAttributeProperties
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
|
||||
@@ -114,7 +126,7 @@ class EditAttributes(bpy.types.Operator, Operator):
|
||||
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.attributes, callback=callback)
|
||||
ifcopenshell.api.run("attribute.edit_attributes", self.file, product=product, attributes=attributes)
|
||||
bpy.ops.bim.disable_editing_attributes(obj=obj.name)
|
||||
bpy.ops.bim.disable_editing_attributes(obj=obj.name, obj_type=self.obj_type)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -19,34 +19,34 @@
|
||||
import blenderbim.bim.helper
|
||||
from bpy.types import Panel
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.attribute.data import AttributesData
|
||||
from blenderbim.bim.module.attribute.data import AttributesData, MaterialAttributesData
|
||||
|
||||
|
||||
def draw_ui(context, layout, attributes):
|
||||
obj = context.active_object
|
||||
def draw_ui(context, layout, obj_type, attributes):
|
||||
obj = context.active_object if obj_type == "Object" else context.active_object.active_material
|
||||
oprops = obj.BIMObjectProperties
|
||||
props = obj.BIMAttributeProperties
|
||||
|
||||
if props.is_editing_attributes:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator("bim.edit_attributes", icon="CHECKMARK", text="Save Attributes")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
op = row.operator("bim.disable_editing_attributes", icon="CANCEL", text="")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
|
||||
blenderbim.bim.helper.draw_attributes(props.attributes, layout, copy_operator="bim.copy_attribute_to_selection")
|
||||
else:
|
||||
row = layout.row()
|
||||
op = row.operator("bim.enable_editing_attributes", icon="GREASEPENCIL", text="Edit")
|
||||
op.obj_type = obj_type
|
||||
op.obj = obj.name
|
||||
|
||||
for attribute in attributes:
|
||||
row = layout.row(align=True)
|
||||
row.label(text=attribute["name"])
|
||||
# row.label(text=attribute["value"])
|
||||
op = row.operator("bim.select_similar", text=attribute["value"], icon="NONE", emboss=False)
|
||||
op.key = attribute['name']
|
||||
|
||||
row.label(text=attribute["value"])
|
||||
|
||||
# TODO: reimplement, see #1222
|
||||
# if "IfcSite/" in context.active_object.name or "IfcBuilding/" in context.active_object.name:
|
||||
@@ -72,4 +72,32 @@ class BIM_PT_object_attributes(Panel):
|
||||
def draw(self, context):
|
||||
if not AttributesData.is_loaded:
|
||||
AttributesData.load()
|
||||
draw_ui(context, self.layout, AttributesData.data["attributes"])
|
||||
draw_ui(context, self.layout, "Object", AttributesData.data["attributes"])
|
||||
|
||||
|
||||
class BIM_PT_material_attributes(Panel):
|
||||
bl_label = "Material Attributes"
|
||||
bl_idname = "BIM_PT_material_attributes"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "material"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not IfcStore.get_file():
|
||||
return False
|
||||
try:
|
||||
return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id)
|
||||
except:
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not MaterialAttributesData.is_loaded:
|
||||
MaterialAttributesData.load()
|
||||
elif (
|
||||
context.active_object.active_material.BIMObjectProperties.ifc_definition_id
|
||||
!= MaterialAttributesData.data["ifc_definition_id"]
|
||||
):
|
||||
MaterialAttributesData.load()
|
||||
|
||||
draw_ui(context, self.layout, "Material", MaterialAttributesData.data["attributes"])
|
||||
|
||||
@@ -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"}
|
||||
@@ -964,56 +938,33 @@ 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)
|
||||
exception_global_ids = {v.ifc_guid for v in viewpoint.visualization_info.components.visibility.exceptions or []}
|
||||
|
||||
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
|
||||
context.area.type = "VIEW_3D"
|
||||
bpy.ops.object.hide_view_clear()
|
||||
context_override = {}
|
||||
context_override["object"] = context_override["active_object"] = objs[0]
|
||||
context_override["selected_objects"] = context_override["selected_editable_objects"] = objs
|
||||
with context.temp_override(**context_override):
|
||||
bpy.ops.object.hide_view_set(unselected=True)
|
||||
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 +976,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 +997,18 @@ 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 +1092,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):
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
@@ -54,11 +54,11 @@ classes = (
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.BIMClassificationProperties = bpy.props.PointerProperty(type=prop.BIMClassificationProperties)
|
||||
bpy.types.Scene.BIMClassificationReferenceProperties = bpy.props.PointerProperty(
|
||||
bpy.types.Object.BIMClassificationReferenceProperties = bpy.props.PointerProperty(
|
||||
type=prop.BIMClassificationReferenceProperties
|
||||
)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.BIMClassificationProperties
|
||||
del bpy.types.Scene.BIMClassificationReferenceProperties
|
||||
del bpy.types.Object.BIMClassificationReferenceProperties
|
||||
|
||||
@@ -88,7 +88,7 @@ class ClassificationReferencesData(ReferencesData):
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "Object"
|
||||
cls.data["object_type"] = "OBJECT"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
@@ -112,21 +112,17 @@ class MaterialClassificationsData(ReferencesData):
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "Material"
|
||||
cls.data["object_type"] = "MATERIAL"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
results = []
|
||||
|
||||
props = bpy.context.scene.BIMMaterialProperties
|
||||
if props.materials and props.active_material_index < len(props.materials):
|
||||
material = props.materials[props.active_material_index]
|
||||
if material.ifc_definition_id:
|
||||
element = tool.Ifc.get().by_id(material.ifc_definition_id)
|
||||
for reference in ifcopenshell.util.classification.get_references(element):
|
||||
data = reference.get_info()
|
||||
del data["ReferencedSource"]
|
||||
results.append(data)
|
||||
element = tool.Ifc.get_entity(bpy.context.active_object.active_material)
|
||||
if element:
|
||||
for reference in ifcopenshell.util.classification.get_references(element):
|
||||
data = reference.get_info()
|
||||
del data["ReferencedSource"]
|
||||
results.append(data)
|
||||
return results
|
||||
|
||||
|
||||
@@ -140,7 +136,7 @@ class CostClassificationsData(ReferencesData):
|
||||
cls.data["references"] = cls.references()
|
||||
cls.data["active_classification_library"] = cls.active_classification_library()
|
||||
cls.data["classifications"] = cls.classifications()
|
||||
cls.data["object_type"] = "Cost"
|
||||
cls.data["object_type"] = "COST"
|
||||
|
||||
@classmethod
|
||||
def references(cls):
|
||||
|
||||
@@ -77,37 +77,26 @@ class AddManualClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.add_manual_classification_reference"
|
||||
bl_label = "Add Manual Classification Reference"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
obj: bpy.props.StringProperty()
|
||||
obj_type: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
if self.obj_type == "Object":
|
||||
if context.selected_objects:
|
||||
objects = [o.name for o in context.selected_objects]
|
||||
else:
|
||||
objects = [context.active_object.name]
|
||||
else:
|
||||
objects = [self.obj]
|
||||
props = context.scene.BIMClassificationReferenceProperties
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(props.reference_attributes)
|
||||
products = [
|
||||
tool.Ifc.get().by_id(ifc_definition_id)
|
||||
for obj in objects
|
||||
if (ifc_definition_id := tool.Blender.get_obj_ifc_definition_id(obj, self.obj_type, context))
|
||||
]
|
||||
if products:
|
||||
classification = tool.Ifc.get().by_id(int(props.classifications))
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
tool.Ifc.get(),
|
||||
products=products,
|
||||
classification=classification,
|
||||
identification="X",
|
||||
name="Unnamed",
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_reference", tool.Ifc.get(), reference=reference, attributes=attributes
|
||||
)
|
||||
product = tool.Ifc.get_entity(obj)
|
||||
# TODO: refactor and support material and cost item classifications
|
||||
classification = tool.Ifc.get().by_id(int(props.classifications))
|
||||
reference = ifcopenshell.api.run(
|
||||
"classification.add_reference",
|
||||
tool.Ifc.get(),
|
||||
products=[product],
|
||||
classification=classification,
|
||||
identification="X",
|
||||
name="Unnamed",
|
||||
)
|
||||
ifcopenshell.api.run(
|
||||
"classification.edit_reference", tool.Ifc.get(), reference=reference, attributes=attributes
|
||||
)
|
||||
props.is_adding = False
|
||||
|
||||
|
||||
@@ -161,7 +150,8 @@ class EnableAddingManualClassificationReference(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationReferenceProperties
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.is_adding = True
|
||||
props.reference_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2("IfcClassificationReference", props.reference_attributes)
|
||||
@@ -174,7 +164,8 @@ class DisableAddingManualClassificationReference(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationReferenceProperties
|
||||
obj = context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.is_adding = False
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -266,7 +257,8 @@ class EnableEditingClassificationReference(bpy.types.Operator):
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMClassificationReferenceProperties
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
props.reference_attributes.clear()
|
||||
blenderbim.bim.helper.import_attributes2(tool.Ifc.get().by_id(self.reference), props.reference_attributes)
|
||||
props.active_reference_id = self.reference
|
||||
@@ -280,7 +272,8 @@ class DisableEditingClassificationReference(bpy.types.Operator):
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
context.scene.BIMClassificationReferenceProperties.active_reference_id = 0
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
obj.BIMClassificationReferenceProperties.active_reference_id = 0
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -333,7 +326,8 @@ class EditClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
obj: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMClassificationReferenceProperties
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
props = obj.BIMClassificationReferenceProperties
|
||||
attributes = {}
|
||||
for attribute in props.reference_attributes:
|
||||
if attribute.is_null:
|
||||
@@ -374,8 +368,9 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
classification = element
|
||||
break
|
||||
|
||||
ifc_file = tool.Ifc.get()
|
||||
products = [
|
||||
tool.Ifc.get().by_id(ifc_definition_id)
|
||||
ifc_file.by_id(ifc_definition_id)
|
||||
for obj in objects
|
||||
if (ifc_definition_id := tool.Blender.get_obj_ifc_definition_id(obj, self.obj_type, context))
|
||||
]
|
||||
|
||||
@@ -118,9 +118,10 @@ class BIM_PT_classifications(Panel):
|
||||
class ReferenceUI:
|
||||
def draw_ui(self, context):
|
||||
obj = context.active_object
|
||||
self.oprops = obj.BIMObjectProperties
|
||||
self.sprops = context.scene.BIMClassificationProperties
|
||||
self.bprops = context.scene.BIMBSDDProperties
|
||||
self.props = context.scene.BIMClassificationReferenceProperties
|
||||
self.props = obj.BIMClassificationReferenceProperties
|
||||
self.file = IfcStore.get_file()
|
||||
|
||||
self.draw_add_ui(context)
|
||||
@@ -154,7 +155,7 @@ class ReferenceUI:
|
||||
blenderbim.bim.helper.draw_attributes(self.props.reference_attributes, self.layout)
|
||||
row = self.layout.row(align=True)
|
||||
op = row.operator("bim.add_manual_classification_reference", text="Save", icon="CHECKMARK")
|
||||
op.obj_type = self.data.data["object_type"]
|
||||
op.type = self.data.data["object_type"]
|
||||
row.operator("bim.disable_adding_manual_classification_reference", text="", icon="CANCEL")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
@@ -294,31 +295,28 @@ class BIM_PT_material_classifications(Panel, ReferenceUI):
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_materials"
|
||||
bl_context = "material"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not tool.Ifc.get():
|
||||
return False
|
||||
props = context.scene.BIMMaterialProperties
|
||||
if props.materials and props.active_material_index < len(props.materials):
|
||||
material = props.materials[props.active_material_index]
|
||||
if material.ifc_definition_id:
|
||||
return True
|
||||
return False
|
||||
try:
|
||||
return bool(context.active_object.active_material.BIMObjectProperties.ifc_definition_id)
|
||||
except:
|
||||
return False
|
||||
|
||||
def draw(self, context):
|
||||
if not MaterialClassificationsData.is_loaded:
|
||||
MaterialClassificationsData.load()
|
||||
self.data = MaterialClassificationsData
|
||||
self.obj = ""
|
||||
self.obj = context.active_object.active_material.name
|
||||
self.obj_type = "Material"
|
||||
self.draw_ui(context)
|
||||
|
||||
|
||||
class BIM_PT_cost_classifications(Panel, ReferenceUI):
|
||||
bl_label = "Cost Item Classifications"
|
||||
bl_label = "Cost Classifications"
|
||||
bl_idname = "BIM_PT_cost_classifications"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
|
||||
@@ -82,7 +82,6 @@ classes = (
|
||||
prop.CostItem,
|
||||
prop.CostItemQuantity,
|
||||
prop.CostItemType,
|
||||
prop.ScheduleColumn,
|
||||
prop.BIMCostProperties,
|
||||
ui.BIM_PT_cost_schedules,
|
||||
ui.BIM_PT_cost_item_quantities,
|
||||
|
||||
@@ -19,13 +19,10 @@
|
||||
import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.cost
|
||||
import ifcopenshell.util.date
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.schema
|
||||
from ifcopenshell.util.doc import get_entity_doc, get_predefined_type_doc
|
||||
from typing import Any
|
||||
|
||||
|
||||
def refresh():
|
||||
@@ -37,7 +34,6 @@ def refresh():
|
||||
class CostSchedulesData:
|
||||
data = {}
|
||||
is_loaded = False
|
||||
_cost_values: dict[int, dict[str, Any]]
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
@@ -140,7 +136,7 @@ class CostSchedulesData:
|
||||
data["UnitBasisUnitSymbol"] = "U"
|
||||
if cost_value.Category == "*":
|
||||
is_sum = True
|
||||
cost_quantity = 1 if data["TotalCostQuantity"] is None else data["TotalCostQuantity"]
|
||||
cost_quantity = data["TotalCostQuantity"] or 1
|
||||
if has_unit_basis:
|
||||
data["TotalCost"] = data["TotalAppliedValue"] * cost_quantity / data["UnitBasisValueComponent"]
|
||||
else:
|
||||
@@ -159,7 +155,6 @@ class CostSchedulesData:
|
||||
data["UnitSymbol"] = "-"
|
||||
if cost_item.CostQuantities:
|
||||
quantity = cost_item.CostQuantities[0]
|
||||
data["QuantityType"] = quantity.is_a()
|
||||
unit = ifcopenshell.util.unit.get_property_unit(quantity, tool.Ifc.get())
|
||||
if unit:
|
||||
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
|
||||
@@ -198,16 +193,10 @@ class CostSchedulesData:
|
||||
# data["DerivedUnitSymbol"] = "?"
|
||||
# print("Total Cost", data["DerivedTotalCostQuantity"], cost_item.Name)
|
||||
|
||||
# TODO: dead code?
|
||||
@classmethod
|
||||
def _get_object_quantities(
|
||||
cls, cost_item: ifcopenshell.entity_instance, element: ifcopenshell.entity_instance
|
||||
) -> list[int]:
|
||||
def _get_object_quantities(cls, cost_item, element):
|
||||
if not element.is_a("IfcObject"):
|
||||
return []
|
||||
cost_quantities = cost_item.CostQuantities
|
||||
if not cost_quantities:
|
||||
return []
|
||||
results = []
|
||||
for relationship in element.IsDefinedBy:
|
||||
if not relationship.is_a("IfcRelDefinesByProperties"):
|
||||
@@ -216,7 +205,7 @@ class CostSchedulesData:
|
||||
if not qto.is_a("IfcElementQuantity"):
|
||||
continue
|
||||
for prop in qto.Quantities:
|
||||
if prop in cost_quantities:
|
||||
if prop in cost_item.CostQuantities or []:
|
||||
results.append(prop.id())
|
||||
return results
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ class RemoveCostSchedule(bpy.types.Operator, tool.Ifc.Operator):
|
||||
cost_schedule: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
core.remove_cost_schedule(tool.Ifc, tool.Cost, cost_schedule=tool.Ifc.get().by_id(self.cost_schedule))
|
||||
core.remove_cost_schedule(tool.Ifc, cost_schedule=tool.Ifc.get().by_id(self.cost_schedule))
|
||||
|
||||
|
||||
class EnableEditingCostSchedule(bpy.types.Operator):
|
||||
@@ -223,40 +223,36 @@ class EditCostItem(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
class AssignCostItemType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.assign_cost_item_type"
|
||||
bl_label = "Assign Cost Item To Product Types"
|
||||
bl_description = "Assign cost item to currently selected or active product types"
|
||||
bl_label = "Assign Cost Item Type Product"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_item: bpy.props.IntProperty()
|
||||
prop_name: bpy.props.StringProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
product_types = core.assign_cost_item_type(
|
||||
core.assign_cost_item_type(
|
||||
tool.Ifc,
|
||||
tool.Cost,
|
||||
tool.Spatial,
|
||||
cost_item=tool.Ifc.get().by_id(self.cost_item),
|
||||
prop_name=self.prop_name, # TODO: REVIEW PROP_NAME USABILITY
|
||||
)
|
||||
self.report({"INFO"}, f"Cost item was assigned to {len(product_types)} product types.")
|
||||
|
||||
|
||||
class UnassignCostItemType(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.unassign_cost_item_type"
|
||||
bl_label = "Unassign Cost Item Type"
|
||||
bl_description = "Unassign cost item from currently selected or active product types"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_item: bpy.props.IntProperty()
|
||||
related_object: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
product_types = core.unassign_cost_item_type(
|
||||
core.unassign_cost_item_type(
|
||||
tool.Ifc,
|
||||
tool.Cost,
|
||||
tool.Spatial,
|
||||
cost_item=tool.Ifc.get().by_id(self.cost_item),
|
||||
product_types=[tool.Ifc.get().by_id(self.related_object)] if self.related_object else None,
|
||||
product_types=[tool.Ifc.get().by_id(self.related_object)] if self.related_object else [],
|
||||
)
|
||||
self.report({"INFO"}, f"Cost item was unassigned from {len(product_types)} product types.")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -291,11 +287,9 @@ class UnassignCostItemQuantity(bpy.types.Operator, tool.Ifc.Operator):
|
||||
tool.Ifc,
|
||||
tool.Cost,
|
||||
cost_item=tool.Ifc.get().by_id(self.cost_item),
|
||||
products=(
|
||||
[tool.Ifc.get().by_id(self.related_object)]
|
||||
if self.related_object
|
||||
else tool.Spatial.get_selected_products()
|
||||
),
|
||||
products=[tool.Ifc.get().by_id(self.related_object)]
|
||||
if self.related_object
|
||||
else tool.Spatial.get_selected_products(),
|
||||
)
|
||||
|
||||
|
||||
@@ -515,7 +509,7 @@ class SelectCostScheduleProducts(bpy.types.Operator):
|
||||
|
||||
|
||||
class ImportCostScheduleCsv(bpy.types.Operator, ImportHelper, tool.Ifc.Operator):
|
||||
bl_idname = "bim.import_cost_schedule_csv"
|
||||
bl_idname = "import_cost_schedule_csv.bim"
|
||||
bl_label = "Import Cost Schedule CSV"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
filename_ext = ".csv"
|
||||
@@ -533,13 +527,6 @@ class AddCostColumn(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
name: bpy.props.StringProperty()
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
if not context.scene.BIMCostProperties.cost_column:
|
||||
cls.poll_message_set("Cost column name is empty")
|
||||
return False
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
core.add_cost_column(tool.Cost, self.name)
|
||||
return {"FINISHED"}
|
||||
@@ -551,7 +538,7 @@ class RemoveCostColumn(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
name: bpy.props.StringProperty()
|
||||
|
||||
def execute(self, context):
|
||||
def _execute(self, context):
|
||||
core.remove_cost_column(tool.Cost, self.name)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -669,17 +656,13 @@ class ExportCostSchedules(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
bl_description = "Export a cost schedule to a CSV, XSLX OR ODS file"
|
||||
cost_schedule: bpy.props.IntProperty()
|
||||
format: bpy.props.EnumProperty(name="Format", items=(("CSV", "CSV", ""), ("XLSX", "XLSX", ""), ("ODS", "ODS", "")))
|
||||
directory: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
filter_folder: bpy.props.BoolProperty(
|
||||
name="Filter Folders",
|
||||
default=True,
|
||||
)
|
||||
format: bpy.props.EnumProperty("Format", items=(("CSV", "CSV", ""), ("XLSX", "XLSX", ""), ("ODS", "ODS", "")))
|
||||
filepath: bpy.props.StringProperty(subtype="FILE_PATH")
|
||||
|
||||
def execute(self, context):
|
||||
cost_schedule = tool.Ifc.get().by_id(self.cost_schedule) if self.cost_schedule else None
|
||||
r = core.export_cost_schedules(
|
||||
tool.Cost, filepath=self.directory, format=self.format, cost_schedule=cost_schedule
|
||||
tool.Cost, filepath=self.filepath, format=self.format, cost_schedule=cost_schedule
|
||||
)
|
||||
if isinstance(r, str):
|
||||
self.report({"ERROR"}, r)
|
||||
@@ -693,7 +676,6 @@ class ExportCostSchedules(bpy.types.Operator):
|
||||
def draw(self, context):
|
||||
self.layout.label(text="Choose a format")
|
||||
self.layout.prop(self, "format")
|
||||
self.layout.label(text="Select a directory.")
|
||||
|
||||
|
||||
class ClearCostItemAssignments(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
@@ -175,10 +175,6 @@ def update_active_cost_item_resources(self, context):
|
||||
bpy.ops.bim.load_cost_item_resource_quantities()
|
||||
|
||||
|
||||
class ScheduleColumn(PropertyGroup):
|
||||
schedule_id: IntProperty()
|
||||
|
||||
|
||||
class BIMCostProperties(PropertyGroup):
|
||||
cost_schedule_predefined_types: EnumProperty(
|
||||
items=get_schedule_predefined_types, name="Predefined Type", default=None
|
||||
@@ -214,14 +210,9 @@ class BIMCostProperties(PropertyGroup):
|
||||
cost_value_attributes: CollectionProperty(name="Cost Value Attributes", type=Attribute)
|
||||
cost_value_formula: StringProperty(name="Cost Value Formula")
|
||||
cost_column: StringProperty(name="Cost Column")
|
||||
should_show_column_ui: BoolProperty(
|
||||
name="Should Show Column UI",
|
||||
description="Display UI for adding cost schedule columns, column names represent a category for cost item values",
|
||||
default=False,
|
||||
)
|
||||
should_show_column_ui: BoolProperty(name="Should Show Column UI", default=False)
|
||||
should_show_currency_ui: BoolProperty(name="Should Show Currency UI", default=False)
|
||||
columns: CollectionProperty(name="Active Schedule Columns", type=StrProperty)
|
||||
columns_storage: CollectionProperty(name="Columns", type=ScheduleColumn)
|
||||
columns: CollectionProperty(name="Columns", type=StrProperty)
|
||||
active_column_index: IntProperty(name="Active Column Index")
|
||||
cost_item_products: CollectionProperty(name="Cost Item Products", type=CostItemQuantity)
|
||||
active_cost_item_product_index: IntProperty(name="Active Cost Item Product Index")
|
||||
|
||||
@@ -21,7 +21,6 @@ import blenderbim.bim.module.cost.prop as CostProp
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.cost.data import CostSchedulesData
|
||||
from typing import Any
|
||||
|
||||
|
||||
class BIM_PT_cost_schedules(Panel):
|
||||
@@ -54,7 +53,7 @@ class BIM_PT_cost_schedules(Panel):
|
||||
row.label(text="No Cost Schedules found.", icon="TEXT")
|
||||
|
||||
row.operator("bim.add_cost_schedule", icon="ADD", text="")
|
||||
row.operator("bim.import_cost_schedule_csv",icon="IMPORT",text="")
|
||||
row.operator("import_cost_schedule_csv.bim",icon="IMPORT",text="")
|
||||
|
||||
for schedule in CostSchedulesData.data["schedules"]:
|
||||
self.draw_cost_schedule_ui(schedule)
|
||||
@@ -179,33 +178,24 @@ class BIM_PT_cost_schedules(Panel):
|
||||
"active_cost_item_index",
|
||||
)
|
||||
if self.props.active_cost_item_id:
|
||||
cost_item = CostSchedulesData.data["cost_items"][ifc_definition_id]
|
||||
if self.props.cost_item_editing_type == "ATTRIBUTES":
|
||||
self.draw_editable_cost_item_attributes_ui()
|
||||
elif self.props.cost_item_editing_type == "QUANTITIES":
|
||||
self.draw_editable_cost_item_quantities_ui(cost_item)
|
||||
self.draw_editable_cost_item_quantities_ui()
|
||||
elif self.props.cost_item_editing_type == "VALUES":
|
||||
self.draw_editable_cost_item_values_ui()
|
||||
|
||||
def draw_editable_cost_item_attributes_ui(self):
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_item_attributes, self.layout)
|
||||
|
||||
def draw_editable_cost_item_quantities_ui(self, cost_item: dict[str, Any]):
|
||||
quantities = CostSchedulesData.data["cost_quantities"]
|
||||
def draw_editable_cost_item_quantities_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
# In IFC, all quantities of IfcCostTime should have 1 type.
|
||||
if quantities:
|
||||
quantity_class = cost_item["QuantityType"]
|
||||
row.label(text=quantity_class)
|
||||
else:
|
||||
row.prop(self.props, "quantity_types", text="")
|
||||
quantity_class = self.props.quantity_types
|
||||
|
||||
row.prop(self.props, "quantity_types", text="")
|
||||
op = row.operator("bim.add_cost_item_quantity", text="", icon="ADD")
|
||||
op.cost_item = self.props.active_cost_item_id
|
||||
op.ifc_class = quantity_class
|
||||
op.ifc_class = self.props.quantity_types
|
||||
|
||||
for quantity in quantities:
|
||||
for quantity in CostSchedulesData.data["cost_quantities"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=quantity["name"])
|
||||
row.label(text=quantity["value"])
|
||||
@@ -644,7 +634,7 @@ class BIM_UL_cost_items_trait:
|
||||
layout.label(text=cost_item["UnitBasisUnitSymbol"])
|
||||
|
||||
def draw_total_quantity_column(self, layout, cost_item):
|
||||
if cost_item["TotalCostQuantity"] is not None:
|
||||
if cost_item["TotalCostQuantity"]:
|
||||
label = "{0:.2f}".format(cost_item["TotalCostQuantity"]) + f" {cost_item['UnitSymbol'] or '-'}"
|
||||
layout.label(text=label)
|
||||
else:
|
||||
@@ -755,11 +745,9 @@ class BIM_UL_product_cost_items(UIList):
|
||||
class BIM_PT_Costing_Tools(Panel):
|
||||
bl_label = "5D Tools"
|
||||
bl_idname = "BIM_PT_Costing_Tools"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_tab_cost"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "4D/5D Toolkit"
|
||||
|
||||
def draw(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
|
||||
@@ -29,9 +29,13 @@ def register():
|
||||
if not bpy.app.background:
|
||||
bpy.utils.register_tool(workspace.CoveringTool, after={"bim.structural_tool"}, separator=False, group=False)
|
||||
bpy.types.Scene.BIMCoveringProperties = bpy.props.PointerProperty(type=prop.BIMCoveringProperties)
|
||||
# bpy.types.Object.BIMObjectSpatialProperties = bpy.props.PointerProperty(type=prop.BIMObjectSpatialProperties)
|
||||
# bpy.types.Scene.BIMSpatialManagerProperties = bpy.props.PointerProperty(type=prop.BIMSpatialManagerProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
if not bpy.app.background:
|
||||
bpy.utils.unregister_tool(workspace.CoveringTool)
|
||||
del bpy.types.Scene.BIMCoveringProperties
|
||||
# del bpy.types.Object.BIMObjectSpatialProperties
|
||||
# del bpy.types.Scene.BIMSpatialManagerProperties
|
||||
|
||||
@@ -35,7 +35,6 @@ class Operator:
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CoveringTool(WorkSpaceTool):
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_context_mode = "OBJECT"
|
||||
@@ -54,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")
|
||||
@@ -84,6 +82,8 @@ class CoveringToolUI:
|
||||
|
||||
cls.draw_default_interface()
|
||||
|
||||
|
||||
|
||||
@classmethod
|
||||
def draw_header_interface(cls):
|
||||
cls.draw_type_selection_interface()
|
||||
@@ -95,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):
|
||||
@@ -169,7 +256,7 @@ class Hotkey(bpy.types.Operator, 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):
|
||||
@@ -183,19 +270,20 @@ class Hotkey(bpy.types.Operator, 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()
|
||||
@@ -205,10 +293,9 @@ class Hotkey(bpy.types.Operator, 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()
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import ifccsv
|
||||
import logging
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.selector
|
||||
import blenderbim.tool as tool
|
||||
import blenderbim.bim.module.drawing.scheduler as scheduler
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
@@ -185,8 +184,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 +221,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 +228,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 +246,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",
|
||||
|
||||
@@ -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
|
||||
@@ -41,7 +40,7 @@ from blenderbim.bim.ifc import IfcStore
|
||||
class CopyDebugInformation(bpy.types.Operator):
|
||||
bl_idname = "bim.copy_debug_information"
|
||||
bl_label = "Copy Debug Information"
|
||||
bl_description = "Copies debugging information to your clipboard for use in bug reports"
|
||||
bl_description = "Copies debugging information to your clipboard for use in bugreports"
|
||||
|
||||
def execute(self, context):
|
||||
info = get_debug_info()
|
||||
@@ -57,13 +56,17 @@ class CopyDebugInformation(bpy.types.Operator):
|
||||
|
||||
text = format_debug_info(info)
|
||||
|
||||
text_with_backticks = f"```\n{text}\n```"
|
||||
|
||||
print("-" * 80)
|
||||
print(text_with_backticks)
|
||||
print(text)
|
||||
print("-" * 80)
|
||||
|
||||
context.window_manager.clipboard = text_with_backticks
|
||||
if platform.system() == "Windows":
|
||||
command = "echo | set /p nul=" + text
|
||||
elif platform.system() == "Darwin": # for MacOS
|
||||
command = 'printf "' + text.replace("\n", "\\n").replace('"', "") + '" | pbcopy'
|
||||
else: # Linux
|
||||
command = 'printf "' + text.replace("\n", "\\n").replace('"', "") + '" | xclip -selection clipboard'
|
||||
subprocess.run(command, shell=True, check=True)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -94,8 +97,7 @@ class ConvertToBlender(bpy.types.Operator):
|
||||
if obj.data:
|
||||
obj.data.BIMMeshProperties.ifc_definition_id = 0
|
||||
for material in bpy.data.materials:
|
||||
material.BIMObjectProperties.ifc_definition_id = 0
|
||||
material.BIMMaterialProperties.ifc_style_id = 0
|
||||
material.BIMMaterialProperties.ifc_style_id = False
|
||||
context.scene.BIMProperties.ifc_file = ""
|
||||
context.scene.BIMDebugProperties.attributes.clear()
|
||||
IfcStore.purge()
|
||||
@@ -173,7 +175,7 @@ class CreateAllShapes(bpy.types.Operator):
|
||||
total = len(elements)
|
||||
settings = ifcopenshell.geom.settings()
|
||||
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):
|
||||
@@ -226,7 +228,7 @@ class CreateShapeFromStepId(bpy.types.Operator):
|
||||
element = self.file.by_id(self.step_id or int(context.scene.BIMDebugProperties.step_id))
|
||||
settings = ifcopenshell.geom.settings()
|
||||
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)
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -159,7 +159,9 @@ class BaseDecorator:
|
||||
objecttype = "NOTDEFINED"
|
||||
|
||||
def __init__(self):
|
||||
self.font_id = 0 # 0 is the default font
|
||||
self.font_id = blf.load(
|
||||
os.path.join(bpy.context.scene.BIMProperties.data_dir, "fonts", "OpenGost Type B TT.ttf")
|
||||
)
|
||||
|
||||
# POLYLINE_UNIFORM_COLOR is good for smoothed lines since `bgl.enable(GL_LINE_SMOOTH)` is deprecated
|
||||
self.line_shader = gpu.shader.from_builtin("POLYLINE_UNIFORM_COLOR")
|
||||
@@ -402,6 +404,7 @@ class BaseDecorator:
|
||||
line_no += 1 if multiline_to_bottom else -1
|
||||
return
|
||||
|
||||
# 0 is the default font, but we're fancier than that
|
||||
font_id = self.font_id
|
||||
|
||||
color = context.preferences.addons["blenderbim"].preferences.decorations_colour
|
||||
@@ -415,14 +418,12 @@ class BaseDecorator:
|
||||
factor = self.camera_zoom_to_factor(context.space_data.region_3d.view_camera_zoom)
|
||||
camera_width_px = factor * context.region.width
|
||||
mm_to_px = camera_width_px / self.get_camera_width_mm()
|
||||
# magic_font_scale's default of (0.004118616) is a magic constant number I visually discovered to get the right number.
|
||||
# 0.004118616 is a magic constant number I visually discovered to get the right number.
|
||||
# In particular it works only for the OpenGOST font and produces a 2.5mm font size.
|
||||
# It probably should be dynamically calculated using system.dpi or something.
|
||||
# font_size = 16 <-- this is a good default
|
||||
# TODO: need to synchronize it better with svg
|
||||
|
||||
magic_font_scale = bpy.context.scene.DocProperties.magic_font_scale
|
||||
font_size_px = int(magic_font_scale * mm_to_px) * font_size_mm / 2.5
|
||||
font_size_px = int(0.004118616 * mm_to_px) * font_size_mm / 2.5
|
||||
pos = pos - line_no * font_size_px * rotation_matrix[1]
|
||||
|
||||
blf.size(font_id, font_size_px)
|
||||
@@ -2013,13 +2014,6 @@ class DecorationsHandler:
|
||||
for object_type in ("SLOPE_ANGLE", "SLOPE_FRACTION", "SLOPE_PERCENT"):
|
||||
self.decorators[object_type] = self.decorators["FALL"]
|
||||
self.decorators["MULTI_SYMBOL"] = self.decorators["SYMBOL"]
|
||||
if drawing_font := bpy.context.scene.DocProperties.drawing_font:
|
||||
drawing_font_path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "fonts", drawing_font)
|
||||
if os.path.exists(drawing_font_path):
|
||||
font_id = blf.load(drawing_font_path)
|
||||
for decorator in self.decorators.values():
|
||||
decorator.font_id = font_id
|
||||
|
||||
|
||||
def get_objects_and_decorators(self, collection):
|
||||
# TODO: do it in data instead of the handler for performance?
|
||||
|
||||
@@ -29,7 +29,6 @@ import subprocess
|
||||
import numpy as np
|
||||
import multiprocessing
|
||||
import ifcopenshell
|
||||
import ifcopenshell.api
|
||||
import ifcopenshell.ifcopenshell_wrapper
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.selector
|
||||
@@ -475,15 +474,15 @@ class CreateDrawing(bpy.types.Operator):
|
||||
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
|
||||
)
|
||||
@@ -507,7 +506,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()
|
||||
@@ -530,39 +529,31 @@ class CreateDrawing(bpy.types.Operator):
|
||||
|
||||
files = {context.scene.BIMProperties.ifc_file: tool.Ifc.get()}
|
||||
|
||||
for link in context.scene.BIMProjectProperties.links:
|
||||
if link.name not in IfcStore.session_files:
|
||||
IfcStore.session_files[link.name] = ifcopenshell.open(link.name)
|
||||
files[link.name] = IfcStore.session_files[link.name]
|
||||
|
||||
target_view = ifcopenshell.util.element.get_psets(self.camera_element)["EPset_Drawing"]["TargetView"]
|
||||
self.setup_serialiser(target_view)
|
||||
|
||||
tree = ifcopenshell.geom.tree()
|
||||
tree.enable_face_styles(True)
|
||||
|
||||
for ifc_path, ifc in files.items():
|
||||
# Don't use draw.main() just whilst we're prototyping and experimenting
|
||||
# TODO: hash paths are never used
|
||||
ifc_hash = hashlib.md5(ifc_path.encode("utf-8")).hexdigest()
|
||||
ifc_cache_path = os.path.join(context.scene.BIMProperties.data_dir, "cache", f"{ifc_hash}.h5")
|
||||
|
||||
self.serialiser.setFile(ifc)
|
||||
drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element, ifc_file=ifc)
|
||||
|
||||
# Get all representation contexts to see what we're dealing with.
|
||||
# Drawings only draw bodies and annotations (and facetation, due to a Revit bug).
|
||||
# A drawing prioritises a target view context first, followed by a model view context as a fallback.
|
||||
# Specifically for PLAN_VIEW and REFLECTED_PLAN_VIEW, any Plan context is also prioritised.
|
||||
target_view = ifcopenshell.util.element.get_psets(self.camera_element)["EPset_Drawing"]["TargetView"]
|
||||
contexts = self.get_linework_contexts(ifc, target_view)
|
||||
drawing_elements = tool.Drawing.get_drawing_elements(self.camera_element)
|
||||
|
||||
self.setup_serialiser(ifc, target_view)
|
||||
tree = ifcopenshell.geom.tree()
|
||||
tree.enable_face_styles(True)
|
||||
|
||||
self.serialize_contexts_elements(ifc, tree, contexts, "body", drawing_elements, target_view)
|
||||
self.serialize_contexts_elements(ifc, tree, contexts, "annotation", drawing_elements, target_view)
|
||||
|
||||
if tool.Ifc.get() == ifc and self.camera_element not in drawing_elements:
|
||||
if self.camera_element not in drawing_elements:
|
||||
with profile("Camera element"):
|
||||
# The camera must always be included, regardless of any include/exclude filters.
|
||||
geom_settings = ifcopenshell.geom.settings()
|
||||
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)
|
||||
@@ -874,15 +865,13 @@ 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
|
||||
def setup_serialiser(self, ifc, target_view):
|
||||
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.setFile(ifc)
|
||||
self.serialiser.setWithoutStoreys(True)
|
||||
self.serialiser.setPolygonal(True)
|
||||
self.serialiser.setUseHlrPoly(True)
|
||||
@@ -946,18 +935,6 @@ class CreateDrawing(bpy.types.Operator):
|
||||
self.is_manifold_cache[obj.data.name] = True
|
||||
return True
|
||||
|
||||
def get_element_by_guid(self, guid):
|
||||
try:
|
||||
return tool.Ifc.get().by_guid(guid)
|
||||
except:
|
||||
for link in bpy.context.scene.BIMProjectProperties.links:
|
||||
if link.name not in IfcStore.session_files:
|
||||
IfcStore.session_files[link.name] = ifcopenshell.open(link.name)
|
||||
try:
|
||||
return IfcStore.session_files[link.name].by_guid(guid)
|
||||
except:
|
||||
continue
|
||||
|
||||
def merge_linework_and_add_metadata(self, root):
|
||||
join_criteria = ifcopenshell.util.element.get_pset(self.camera_element, "EPset_Drawing", "JoinCriteria")
|
||||
if join_criteria:
|
||||
@@ -972,7 +949,7 @@ class CreateDrawing(bpy.types.Operator):
|
||||
|
||||
ifc = tool.Ifc.get()
|
||||
for el in root.findall(".//{http://www.w3.org/2000/svg}g[@{http://www.ifcopenshell.org/ns}guid]"):
|
||||
element = self.get_element_by_guid(el.get("{http://www.ifcopenshell.org/ns}guid"))
|
||||
element = ifc.by_guid(el.get("{http://www.ifcopenshell.org/ns}guid"))
|
||||
|
||||
if "projection" in el.get("class", "").split():
|
||||
classes = self.get_svg_classes(element)
|
||||
@@ -985,10 +962,6 @@ class CreateDrawing(bpy.types.Operator):
|
||||
el.set("class", " ".join(classes))
|
||||
|
||||
obj = tool.Ifc.get_object(element)
|
||||
|
||||
if not obj: # This is a linked model object. For now, do nothing.
|
||||
continue
|
||||
|
||||
if not self.is_manifold(obj):
|
||||
continue
|
||||
|
||||
@@ -1542,7 +1515,14 @@ class ActivateDrawing(bpy.types.Operator):
|
||||
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)
|
||||
try:
|
||||
core.activate_drawing_view(tool.Ifc, tool.Blender, tool.Drawing, drawing=drawing)
|
||||
except core.CameraNotAvailableError:
|
||||
self.report(
|
||||
{"ERROR"},
|
||||
"The drawing view is not available. Ensure you have not excluded it in the active view layer.",
|
||||
)
|
||||
return {"CANCELLED"}
|
||||
|
||||
if not self.camera_view_point:
|
||||
tool.Blender.set_viewport_position(viewport_position)
|
||||
@@ -1557,14 +1537,6 @@ class ActivateDrawing(bpy.types.Operator):
|
||||
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="")
|
||||
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -1644,7 +1616,7 @@ class ReloadDrawingStyles(bpy.types.Operator):
|
||||
if not DrawingsData.is_loaded:
|
||||
DrawingsData.load()
|
||||
drawing_pset_data = DrawingsData.data["active_drawing_pset_data"]
|
||||
camera_props = context.scene.camera.data.BIMCameraProperties
|
||||
camera_props = context.active_object.data.BIMCameraProperties
|
||||
|
||||
# added this part as a temporary fallback
|
||||
# TODO: should remove it a bit later when projects get more accommodated
|
||||
@@ -1896,10 +1868,10 @@ class ActivateDrawingStyle(bpy.types.Operator, 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)
|
||||
|
||||
@@ -315,7 +315,9 @@ class RasterStyleProperty(enum.Enum):
|
||||
SPACE_SHADING = "space.shading"
|
||||
|
||||
|
||||
RASTER_STYLE_PROPERTIES_EXCLUDE = ("scene.render.filepath",)
|
||||
RASTER_STYLE_PROPERTIES_EXCLUDE = (
|
||||
"scene.render.filepath",
|
||||
)
|
||||
|
||||
|
||||
class DocProperties(PropertyGroup):
|
||||
@@ -369,8 +371,6 @@ class DocProperties(PropertyGroup):
|
||||
default=os.path.join("drawings", "assets", "shading_styles.json"), name="Default Shading Styles"
|
||||
)
|
||||
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")
|
||||
|
||||
|
||||
class BIMCameraProperties(PropertyGroup):
|
||||
|
||||
@@ -16,21 +16,22 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import re
|
||||
import bpy
|
||||
import string
|
||||
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
|
||||
import svgwrite
|
||||
import openpyxl
|
||||
|
||||
from blenderbim.bim.module.drawing.svgwriter import SvgWriter
|
||||
from odf.opendocument import load as load_ods
|
||||
from odf.table import Table, TableRow, TableColumn, TableCell
|
||||
from odf.text import P
|
||||
from odf.style import Style
|
||||
from textwrap import wrap
|
||||
from pathlib import Path
|
||||
import string
|
||||
|
||||
FONT_SIZE = 4.13
|
||||
FONT_WIDTH = lambda size: size * 0.45
|
||||
FONT_SIZE_PT = 12
|
||||
FONT_FAMILY = "OpenGost Type B TT"
|
||||
DEBUG = False
|
||||
|
||||
|
||||
@@ -62,29 +63,11 @@ class Scheduler:
|
||||
)
|
||||
self.padding = 1
|
||||
self.margin = 1
|
||||
|
||||
self.parse_css(infile)
|
||||
if infile.endswith("ods"):
|
||||
self.schedule_ods(infile, outfile)
|
||||
elif infile.endswith("xlsx"):
|
||||
self.schedule_xlsx(infile, outfile)
|
||||
|
||||
def parse_css(self, infile):
|
||||
stylesheet_path = os.path.splitext(infile)[0] + ".css"
|
||||
if not os.path.exists(stylesheet_path):
|
||||
stylesheet_path = os.path.join(bpy.context.scene.BIMProperties.data_dir, "assets", "schedule.css")
|
||||
with open(stylesheet_path, "r") as stylesheet:
|
||||
css = stylesheet.read()
|
||||
|
||||
matches = re.search("--font-size-pt:\s*([0-9.]+);", css)
|
||||
self.font_size_pt = float(matches.groups()[0]) if matches else 12 # Default to 12pt
|
||||
matches = re.search("--font-size-px:\s*([0-9.]+);", css)
|
||||
self.font_size_px = float(matches.groups()[0]) if matches else 4.13 # Magic number 4.13px ~= 12pt
|
||||
matches = re.search("--font-width:\s*([0-9.]+);", css)
|
||||
self.font_width = float(matches.groups()[0]) if matches else 0.45 # A magic number for OpenGost
|
||||
|
||||
self.svg.defs.add(self.svg.style(css))
|
||||
|
||||
def schedule_xlsx(self, infile, outfile):
|
||||
workbook = openpyxl.open(infile, data_only=True)
|
||||
sheet = workbook.active
|
||||
@@ -161,8 +144,8 @@ class Scheduler:
|
||||
x += unmerged_width
|
||||
continue
|
||||
|
||||
font_size = cell.font.size or self.font_size_pt # 12pt default
|
||||
font_size = font_size / self.font_size_pt * self.font_size_px # Magic?
|
||||
font_size = cell.font.size or 11 # 11pt default
|
||||
font_size = font_size / FONT_SIZE_PT * FONT_SIZE # Magic?
|
||||
|
||||
text_position = [0.0, 0.0]
|
||||
if cell.alignment.horizontal == "left":
|
||||
@@ -441,9 +424,9 @@ class Scheduler:
|
||||
italic_text = final_cell_style.get("font-style", None) == "italic"
|
||||
# NOTE: very naive since we're scaling text proportionally
|
||||
font_size = (
|
||||
float(final_cell_style.get("font-size", f"{self.font_size_pt}pt")[:-2])
|
||||
/ self.font_size_pt
|
||||
* self.font_size_px
|
||||
float(final_cell_style.get("font-size", f"{FONT_SIZE_PT}pt")[:-2])
|
||||
/ FONT_SIZE_PT
|
||||
* FONT_SIZE
|
||||
)
|
||||
|
||||
if p_tags:
|
||||
@@ -540,7 +523,10 @@ class Scheduler:
|
||||
"""
|
||||
text_lines = [str(p) for p in p_tags]
|
||||
box_alignment_params = SvgWriter.get_box_alignment_parameters(box_alignment)
|
||||
text_params = {"font-size": font_size}
|
||||
text_params = {
|
||||
"font-size": font_size,
|
||||
"font-family": FONT_FAMILY,
|
||||
}
|
||||
if bold:
|
||||
text_params["font-weight"] = "bold"
|
||||
if italic:
|
||||
@@ -560,13 +546,13 @@ class Scheduler:
|
||||
|
||||
text_tag = self.svg.text("", **(text_params | {"font-size": "0"} | box_alignment_params))
|
||||
|
||||
# TODO: Should be done without using magic number for self.font_width
|
||||
# TODO: should be done in less naive way
|
||||
# without using magic number for FONT_WIDTH
|
||||
# currently it might not work for all fonts and font sizes
|
||||
if wrap_text:
|
||||
wrapped_lines = []
|
||||
for line in text_lines:
|
||||
wrapped_line = wrap(
|
||||
line, width=int(cell_width // (font_size * self.font_width)), break_long_words=False
|
||||
)
|
||||
wrapped_line = wrap(line, width=int(cell_width // FONT_WIDTH(font_size)), break_long_words=False)
|
||||
wrapped_lines.extend(wrapped_line)
|
||||
else:
|
||||
wrapped_lines = text_lines
|
||||
|
||||
@@ -22,6 +22,7 @@ import bpy
|
||||
import math
|
||||
import bmesh
|
||||
import shutil
|
||||
import pystache
|
||||
import mathutils
|
||||
import xml.etree.ElementTree as ET
|
||||
import svgwrite
|
||||
|
||||
@@ -22,20 +22,13 @@ from . import ui, prop, operator
|
||||
classes = (
|
||||
operator.AddRepresentation,
|
||||
operator.CopyRepresentation,
|
||||
operator.DisableEditingRepresentationItemShapeAspect,
|
||||
operator.DisableEditingRepresentationItemStyle,
|
||||
operator.DisableEditingRepresentationItems,
|
||||
operator.DuplicateLinkedAggregateTo3dCursor,
|
||||
operator.DuplicateMoveLinkedAggregate,
|
||||
operator.DuplicateMoveLinkedAggregateMacro,
|
||||
operator.EditObjectPlacement,
|
||||
operator.EditRepresentationItemShapeAspect,
|
||||
operator.EditRepresentationItemStyle,
|
||||
operator.EnableEditingRepresentationItemShapeAspect,
|
||||
operator.EnableEditingRepresentationItemStyle,
|
||||
operator.EnableEditingRepresentationItems,
|
||||
operator.FlipObject,
|
||||
operator.GetRepresentationIfcParameters,
|
||||
operator.DuplicateMoveLinkedAggregate,
|
||||
operator.DuplicateMoveLinkedAggregateMacro,
|
||||
operator.OverrideDelete,
|
||||
operator.OverrideDuplicateMove,
|
||||
operator.OverrideDuplicateMoveLinked,
|
||||
@@ -52,13 +45,19 @@ classes = (
|
||||
operator.RefreshLinkedAggregate,
|
||||
operator.RemoveConnection,
|
||||
operator.RemoveRepresentation,
|
||||
operator.RemoveRepresentationItem,
|
||||
operator.RemoveRepresentationItemFromShapeAspect,
|
||||
operator.SelectConnection,
|
||||
operator.SwitchRepresentation,
|
||||
operator.UnassignRepresentationItemStyle,
|
||||
operator.UpdateParametricRepresentation,
|
||||
operator.UpdateRepresentation,
|
||||
operator.RemoveRepresentationItem,
|
||||
operator.EnableEditingRepresentationItemStyle,
|
||||
operator.EditRepresentationItemStyle,
|
||||
operator.DisableEditingRepresentationItemStyle,
|
||||
operator.UnassignRepresentationItemStyle,
|
||||
operator.EnableEditingRepresentationItemShapeAspect,
|
||||
operator.EditRepresentationItemShapeAspect,
|
||||
operator.DisableEditingRepresentationItemShapeAspect,
|
||||
operator.RemoveRepresentationItemFromShapeAspect,
|
||||
prop.RepresentationItem,
|
||||
prop.ShapeAspect,
|
||||
prop.BIMObjectGeometryProperties,
|
||||
@@ -120,7 +119,6 @@ def register():
|
||||
|
||||
km = wm.keyconfigs.addon.keymaps.new(name="Mesh", space_type="EMPTY")
|
||||
kmi = km.keymap_items.new("bim.override_mode_set_object", "TAB", "PRESS")
|
||||
kmi.properties.should_save = True
|
||||
addon_keymaps.append((km, kmi))
|
||||
kmi = km.keymap_items.new("wm.call_menu", "P", "PRESS")
|
||||
kmi.properties.name = ui.BIM_MT_hotkey_separate.bl_idname
|
||||
|
||||
@@ -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
|
||||
@@ -351,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
|
||||
@@ -374,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_eastings) * unit_scale,
|
||||
float(props.blender_northings) * unit_scale,
|
||||
float(props.blender_orthogonal_height) / 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
|
||||
|
||||
@@ -28,7 +28,6 @@ import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.placement
|
||||
import ifcopenshell.api
|
||||
import blenderbim.core.geometry
|
||||
import blenderbim.core.geometry as core
|
||||
import blenderbim.core.aggregate
|
||||
import blenderbim.core.style
|
||||
@@ -40,7 +39,6 @@ from mathutils import Vector, Matrix
|
||||
from time import time
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.util.shape_builder import ShapeBuilder
|
||||
from typing import Any
|
||||
|
||||
|
||||
class Operator:
|
||||
@@ -324,7 +322,7 @@ class UpdateRepresentation(bpy.types.Operator, 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, obj):
|
||||
@@ -374,12 +372,14 @@ class UpdateRepresentation(bpy.types.Operator, 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,
|
||||
@@ -400,11 +400,7 @@ class UpdateRepresentation(bpy.types.Operator, Operator):
|
||||
representation_data["profile_set_usage"] = tool.Geometry.get_profile_set_usage(product)
|
||||
representation_data["text_literal"] = tool.Geometry.get_text_literal(old_representation)
|
||||
|
||||
# TODO: replace with core.add_representation?
|
||||
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
|
||||
if new_representation is None:
|
||||
self.report({"ERROR"}, "Error creating representation for Blender object.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
if tool.Geometry.is_body_representation(new_representation):
|
||||
[
|
||||
@@ -713,10 +709,6 @@ class OverrideOutlinerDelete(bpy.types.Operator):
|
||||
else:
|
||||
bpy.data.objects.remove(obj)
|
||||
for collection in collections_to_delete:
|
||||
# Removing an aggregate object would also remove it's collection
|
||||
# making the collection data-block invalid.
|
||||
if not tool.Blender.is_valid_data_block(collection):
|
||||
continue
|
||||
bpy.data.collections.remove(collection)
|
||||
if self.is_batch:
|
||||
old_file = tool.Ifc.get()
|
||||
@@ -728,7 +720,7 @@ class OverrideOutlinerDelete(bpy.types.Operator):
|
||||
IfcStore.add_transaction_operation(self)
|
||||
return {"FINISHED"}
|
||||
|
||||
def get_collection_objects_and_children(self, collection: bpy.types.Collection) -> dict[str, Any]:
|
||||
def get_collection_objects_and_children(self, collection):
|
||||
objects = set()
|
||||
children = set()
|
||||
queue = [collection]
|
||||
@@ -946,7 +938,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(), pset=pset)
|
||||
|
||||
if new[0].is_a("IfcElementAssembly"):
|
||||
linked_aggregate_group = [
|
||||
@@ -981,15 +973,15 @@ class OverrideDuplicateMoveLinked(bpy.types.Operator):
|
||||
|
||||
|
||||
class DuplicateMoveLinkedAggregateMacro(bpy.types.Macro):
|
||||
bl_description = "Create and move a new linked aggregate"
|
||||
bl_description = "Create a new linked aggregate"
|
||||
bl_idname = "bim.object_duplicate_move_linked_aggregate_macro"
|
||||
bl_label = "IFC Duplicate and Move Linked Aggregate"
|
||||
bl_label = "IFC Duplicate Linked Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
|
||||
class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.object_duplicate_move_linked_aggregate"
|
||||
bl_label = "IFC Duplicate and Move Linked Aggregate"
|
||||
bl_label = "IFC Duplicate Linked Aggregate"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
is_interactive: bpy.props.BoolProperty(name="Is Interactive", default=True)
|
||||
|
||||
@@ -1004,7 +996,7 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
||||
return DuplicateMoveLinkedAggregate.execute_ifc_duplicate_linked_aggregate_operator(self, context)
|
||||
|
||||
@staticmethod
|
||||
def execute_ifc_duplicate_linked_aggregate_operator(self, context, location_from_3d_cursor=False):
|
||||
def execute_ifc_duplicate_linked_aggregate_operator(self, context):
|
||||
self.new_active_obj = None
|
||||
self.group_name = "BBIM_Linked_Aggregate"
|
||||
self.pset_name = "BBIM_Linked_Aggregate"
|
||||
@@ -1058,7 +1050,7 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
||||
if self.group_name in product_groups_name:
|
||||
return
|
||||
|
||||
linked_aggregate_group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), name=self.group_name)
|
||||
linked_aggregate_group = ifcopenshell.api.run("group.add_group", tool.Ifc.get(), Name=self.group_name)
|
||||
ifcopenshell.api.run("group.assign_group", tool.Ifc.get(), products=[element], group=linked_aggregate_group)
|
||||
|
||||
def custom_incremental_naming_for_element_assembly(old_to_new):
|
||||
@@ -1117,16 +1109,6 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
||||
]
|
||||
tool.Ifc.run("group.assign_group", group=linked_aggregate_group[0], products=new)
|
||||
|
||||
def get_location_from_3d_cursor(old_to_new, aggregate):
|
||||
base_obj = tool.Ifc.get_object(aggregate)
|
||||
base_obj_location = base_obj.location.copy()
|
||||
|
||||
for new in old_to_new.values():
|
||||
new_obj = tool.Ifc.get_object(new[0])
|
||||
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"}
|
||||
|
||||
@@ -1153,32 +1135,11 @@ class DuplicateMoveLinkedAggregate(bpy.types.Operator):
|
||||
|
||||
custom_incremental_naming_for_element_assembly(old_to_new)
|
||||
|
||||
if location_from_3d_cursor:
|
||||
get_location_from_3d_cursor(old_to_new, selected_element)
|
||||
|
||||
blenderbim.bim.handler.refresh_ui_data()
|
||||
|
||||
return old_to_new
|
||||
|
||||
|
||||
class DuplicateLinkedAggregateTo3dCursor(bpy.types.Operator):
|
||||
bl_idname = "bim.duplicate_linked_aggregate_to_3d_cursor"
|
||||
bl_label = "IFC Duplicate Linked Aggregate to 3d Cursor"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return len(context.selected_objects) > 0
|
||||
|
||||
def execute(self, context):
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
class RefreshLinkedAggregate(bpy.types.Operator):
|
||||
bl_idname = "bim.refresh_linked_aggregate"
|
||||
bl_label = "IFC Refresh Linked Aggregate"
|
||||
@@ -1531,7 +1492,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:
|
||||
@@ -1542,13 +1503,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
|
||||
@@ -1556,7 +1527,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":
|
||||
@@ -1681,11 +1651,20 @@ class OverrideModeSetObject(bpy.types.Operator):
|
||||
apply_openings=True,
|
||||
)
|
||||
|
||||
def draw(self, context):
|
||||
if self.is_valid:
|
||||
row = self.layout.row()
|
||||
row.prop(self, "should_save")
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.label(text="No Geometry Found: Object will revert to previous state.")
|
||||
|
||||
def invoke(self, context, event):
|
||||
return IfcStore.execute_ifc_operator(self, context, is_invoke=True)
|
||||
|
||||
def _invoke(self, context, event):
|
||||
self.is_valid = True
|
||||
self.should_save = True
|
||||
|
||||
bpy.ops.object.mode_set(mode="EDIT", toggle=True)
|
||||
|
||||
@@ -1747,6 +1726,8 @@ class OverrideModeSetObject(bpy.types.Operator):
|
||||
else:
|
||||
tool.Ifc.finish_edit(obj)
|
||||
|
||||
if self.edited_objs:
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
return self.execute(context)
|
||||
|
||||
|
||||
|
||||
@@ -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,5 +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)
|
||||
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,11 +33,7 @@ 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
|
||||
row.prop(context.scene.BIMGeometryProperties, "mode", text="", icon_value=blenderbim.bim.icons["IFC"].icon_id)
|
||||
|
||||
|
||||
@@ -421,11 +417,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):
|
||||
|
||||
@@ -20,31 +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_wcs,
|
||||
ui.BIM_PT_gis_true_north,
|
||||
ui.BIM_PT_gis_calculator,
|
||||
)
|
||||
|
||||
|
||||
@@ -18,10 +18,8 @@
|
||||
|
||||
|
||||
import bpy
|
||||
import numpy as np
|
||||
import blenderbim.tool as tool
|
||||
import ifcopenshell.util.geolocation
|
||||
from ifcopenshell.util.doc import get_entity_doc
|
||||
import blenderbim.tool as tool
|
||||
|
||||
|
||||
def refresh():
|
||||
@@ -34,26 +32,14 @@ class GeoreferenceData:
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data["coordinate_operation_class"] = cls.coordinate_operation_class()
|
||||
cls.data["blender_derived_angle"] = cls.blender_derived_angle()
|
||||
cls.data["coordinate_operation"] = cls.coordinate_operation()
|
||||
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):
|
||||
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)]
|
||||
|
||||
@classmethod
|
||||
def blender_derived_angle(cls):
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
@@ -68,37 +54,36 @@ class GeoreferenceData:
|
||||
)
|
||||
|
||||
@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,
|
||||
)
|
||||
@@ -145,36 +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:
|
||||
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]
|
||||
return result
|
||||
return str(round(ifcopenshell.util.geolocation.yaxis2angle(*cls.data["true_north"][0:2]), 3))
|
||||
|
||||
@@ -29,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):
|
||||
@@ -106,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"
|
||||
@@ -136,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)
|
||||
@@ -152,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)
|
||||
@@ -189,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,104 +29,26 @@ from bpy.props import (
|
||||
FloatVectorProperty,
|
||||
CollectionProperty,
|
||||
)
|
||||
from blenderbim.bim.module.georeference.data import GeoreferenceData
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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"
|
||||
)
|
||||
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")
|
||||
host_model_origin: StringProperty(name="Host Model Origin")
|
||||
model_origin: StringProperty(name="Model Origin")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
|
||||
@@ -40,9 +40,8 @@ class BIM_PT_gis(Panel):
|
||||
GeoreferenceData.load()
|
||||
|
||||
if props.is_editing:
|
||||
self.draw_editable_ui(context)
|
||||
else:
|
||||
self.draw_ui(context)
|
||||
return self.draw_editable_ui(context)
|
||||
self.draw_ui(context)
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
@@ -54,54 +53,53 @@ class BIM_PT_gis(Panel):
|
||||
draw_attributes(props.projected_crs, self.layout)
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="Coordinate Operation", icon="GRID")
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
|
||||
for attribute in props.coordinate_operation:
|
||||
if attribute.name == "XAxisAbscissa":
|
||||
for attribute in props.map_conversion:
|
||||
if attribute.name == "Scale" and hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "grid_north_angle", text="Angle")
|
||||
row.prop(props, "x_axis_is_null", icon="RADIOBUT_OFF" if props.x_axis_is_null else "RADIOBUT_ON", text="")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "x_axis_abscissa", text="XAxis Abscissa")
|
||||
row.prop(props, "x_axis_is_null", icon="RADIOBUT_OFF" if props.x_axis_is_null else "RADIOBUT_ON", text="")
|
||||
elif attribute.name == "XAxisOrdinate":
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "x_axis_ordinate", text="XAxis Ordinate")
|
||||
row.prop(props, "x_axis_is_null", icon="RADIOBUT_OFF" if props.x_axis_is_null else "RADIOBUT_ON", text="")
|
||||
if hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.set_ifc_grid_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_grid_north", text="Set Blender North")
|
||||
else:
|
||||
draw_attribute(attribute, self.layout.row())
|
||||
row.operator("bim.set_ifc_grid_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_grid_north", text="Set Blender North")
|
||||
draw_attribute(attribute, self.layout.row())
|
||||
|
||||
row = self.layout.row()
|
||||
row.label(text="True North", icon="LIGHT_SUN")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "has_true_north")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "true_north_abscissa")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "true_north_ordinate")
|
||||
if hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.set_ifc_true_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_true_north", text="Set Blender North")
|
||||
|
||||
def draw_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
row = self.layout.row()
|
||||
row.label(text="IFC2X3 Fallback In Use", icon="INFO")
|
||||
row.label(text="IFC2X3 Fallback In Use", icon="ERROR")
|
||||
|
||||
if not GeoreferenceData.data["projected_crs"]:
|
||||
row = self.layout.row()
|
||||
row.label(text="Not Georeferenced", icon="ERROR")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Not Georeferenced")
|
||||
if tool.Ifc.get_schema() != "IFC2X3":
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "coordinate_operation_class", text="")
|
||||
row.operator("bim.add_georeferencing", icon="ADD", text="")
|
||||
|
||||
if props.has_blender_offset:
|
||||
row = self.layout.row()
|
||||
row.label(text="Blender Session Origin", icon="TRACKING_REFINE_FORWARDS")
|
||||
row.label(text="Blender Offset", icon="TRACKING_REFINE_FORWARDS")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"Eastings ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.label(text="Eastings")
|
||||
row.label(text=props.blender_eastings)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"Northings ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.label(text="Northings")
|
||||
row.label(text=props.blender_northings)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"OrthogonalHeight ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.label(text="OrthogonalHeight")
|
||||
row.label(text=props.blender_orthogonal_height)
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="XAxisAbscissa")
|
||||
@@ -127,140 +125,30 @@ class BIM_PT_gis(Panel):
|
||||
row.label(text=key)
|
||||
row.label(text=str(value))
|
||||
|
||||
if GeoreferenceData.data["coordinate_operation"]:
|
||||
if GeoreferenceData.data["map_conversion"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Coordinate Operation", icon="GRID")
|
||||
row.label(text="Map Conversion", icon="GRID")
|
||||
|
||||
for key, value in GeoreferenceData.data["coordinate_operation"].items():
|
||||
for key, value in GeoreferenceData.data["map_conversion"].items():
|
||||
if value is None:
|
||||
continue
|
||||
if key == "type":
|
||||
key = "Type"
|
||||
row = self.layout.row(align=True)
|
||||
if key in ("Eastings", "Northings", "OrthogonalHeight"):
|
||||
row.label(text=f"{key} ({GeoreferenceData.data['map_unit_symbol']})")
|
||||
else:
|
||||
row.label(text=key)
|
||||
row.label(text=key)
|
||||
row.label(text=str(value))
|
||||
if key == "XAxisOrdinate":
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Derived Angle")
|
||||
row.label(text=GeoreferenceData.data["map_derived_angle"])
|
||||
|
||||
|
||||
class BIM_PT_gis_true_north(Panel):
|
||||
bl_idname = "BIM_PT_gis_true_north"
|
||||
bl_label = "True North"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_gis"
|
||||
|
||||
def draw(self, context):
|
||||
if not GeoreferenceData.is_loaded:
|
||||
GeoreferenceData.load()
|
||||
|
||||
self.props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
if self.props.is_editing_true_north:
|
||||
self.draw_editable_ui(context)
|
||||
else:
|
||||
self.draw_ui()
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
row = self.layout.row()
|
||||
row.prop(self.props, "true_north_angle", text="Angle")
|
||||
row = self.layout.row()
|
||||
row.prop(self.props, "true_north_abscissa", text="Abscissa")
|
||||
row = self.layout.row()
|
||||
row.prop(self.props, "true_north_ordinate", text="Ordinate")
|
||||
if hasattr(context.scene, "sun_pos_properties"):
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.set_ifc_true_north", text="Set IFC North")
|
||||
row.operator("bim.set_blender_true_north", text="Set Blender North")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.edit_true_north", icon="CHECKMARK")
|
||||
row.operator("bim.disable_editing_true_north", icon="CANCEL", text="")
|
||||
|
||||
def draw_ui(self):
|
||||
if GeoreferenceData.data["true_north"]:
|
||||
row = self.layout.row()
|
||||
row.label(text="True North", icon="LIGHT_SUN")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Abscissa")
|
||||
row.label(text=str(GeoreferenceData.data["true_north"][0]))
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Ordinate")
|
||||
row.label(text=str(GeoreferenceData.data["true_north"][1]))
|
||||
row.operator("bim.enable_editing_true_north", icon="GREASEPENCIL", text="")
|
||||
row.operator("bim.remove_true_north", icon="X", text="")
|
||||
row.label(text="Vector")
|
||||
row.label(text=str(GeoreferenceData.data["true_north"][0:2])[1:-1])
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Derived Angle")
|
||||
row.label(text=GeoreferenceData.data["true_derived_angle"])
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="No True North Found", icon="LIGHT_SUN")
|
||||
row.operator("bim.enable_editing_true_north", icon="GREASEPENCIL", text="")
|
||||
|
||||
|
||||
class BIM_PT_gis_wcs(Panel):
|
||||
bl_idname = "BIM_PT_gis_wcs"
|
||||
bl_label = "World Coordinate System"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_parent_id = "BIM_PT_gis"
|
||||
|
||||
def draw(self, context):
|
||||
if not GeoreferenceData.is_loaded:
|
||||
GeoreferenceData.load()
|
||||
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
if props.is_editing_wcs:
|
||||
self.draw_editable_ui(context)
|
||||
else:
|
||||
self.draw_ui()
|
||||
|
||||
def draw_ui(self):
|
||||
if GeoreferenceData.data["world_coordinate_system"]["has_transformation"]:
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Unrecommended Transformation Found", icon="ERROR")
|
||||
row.operator("bim.enable_editing_wcs", icon="GREASEPENCIL", text="")
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"X ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.label(text=str(GeoreferenceData.data["world_coordinate_system"]["x"]))
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"Y ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.label(text=str(GeoreferenceData.data["world_coordinate_system"]["y"]))
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=f"Z ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.label(text=str(GeoreferenceData.data["world_coordinate_system"]["z"]))
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Rotation")
|
||||
row.label(text=str(GeoreferenceData.data["world_coordinate_system"]["rotation"]))
|
||||
else:
|
||||
row = self.layout.row()
|
||||
row.label(text="No WCS Transformation", icon="CHECKMARK")
|
||||
row.operator("bim.enable_editing_wcs", icon="GREASEPENCIL", text="")
|
||||
|
||||
def draw_editable_ui(self, context):
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="World Coordinate System", icon="EMPTY_ARROWS")
|
||||
row.operator("bim.edit_wcs", icon="CHECKMARK", text="")
|
||||
row.operator("bim.disable_editing_wcs", icon="CANCEL", text="")
|
||||
|
||||
row = self.layout.row()
|
||||
row.prop(props, "wcs_x")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "wcs_y")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "wcs_z")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "wcs_rotation")
|
||||
|
||||
|
||||
class BIM_PT_gis_calculator(Panel):
|
||||
@@ -273,17 +161,33 @@ class BIM_PT_gis_calculator(Panel):
|
||||
bl_parent_id = "BIM_PT_gis"
|
||||
|
||||
def draw(self, context):
|
||||
if not GeoreferenceData.is_loaded:
|
||||
GeoreferenceData.load()
|
||||
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "local_coordinates", text=f"Local ({GeoreferenceData.data['local_unit_symbol']})")
|
||||
row.prop(props, "coordinate_input", text="Input")
|
||||
row.operator("bim.get_cursor_location", text="", icon="TRACKER")
|
||||
row = self.layout.row()
|
||||
row.prop(props, "map_coordinates", text=f"Map ({GeoreferenceData.data['map_unit_symbol']})")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "coordinate_output", text="Output")
|
||||
row.operator("bim.set_cursor_location", text="", icon="TRACKER")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.operator("bim.convert_local_to_global", text="Local to Global")
|
||||
row.operator("bim.convert_global_to_local", text="Global to Local")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text="Orientation Calculator", icon="TRACKING_REFINE_FORWARDS")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "angle_degree_input_x", text="Angle (°) rel to Easting")
|
||||
row.operator("bim.convert_angle_to_coord", text="", icon="FILE_REFRESH").type = "rel_x"
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "x_axis_abscissa_output", text="XAxis Abscissa")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "x_axis_ordinate_output", text="XAxis Ordinate")
|
||||
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "angle_degree_input_y", text="Angle (°) rel to to +Y")
|
||||
row.operator("bim.convert_angle_to_coord", text="", icon="FILE_REFRESH").type = "rel_y"
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "y_axis_abscissa_output", text="North Abscissa")
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "y_axis_ordinate_output", text="North Ordinate")
|
||||
|
||||
@@ -31,6 +31,7 @@ classes = (
|
||||
operator.SelectGroupProducts,
|
||||
operator.ToggleGroup,
|
||||
operator.UnassignGroup,
|
||||
operator.UpdateGroup,
|
||||
operator.SelectGroupElements,
|
||||
prop.ExpandedGroups,
|
||||
prop.Group,
|
||||
|
||||
@@ -22,6 +22,7 @@ import ifcopenshell.api
|
||||
import blenderbim.bim.helper
|
||||
import blenderbim.tool as tool
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from ifcopenshell.util.selector import Selector
|
||||
import json
|
||||
|
||||
|
||||
@@ -47,6 +48,7 @@ class LoadGroups(bpy.types.Operator, tool.Ifc.Operator):
|
||||
new = self.props.groups.add()
|
||||
new.ifc_definition_id = group.id()
|
||||
new.name = group.Name or "Unnamed"
|
||||
new.selection_query = ""
|
||||
new.tree_depth = tree_depth
|
||||
new.has_children = False
|
||||
new.is_expanded = group.id() in self.expanded_groups
|
||||
@@ -111,6 +113,7 @@ class EditGroup(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.edit_group"
|
||||
bl_label = "Edit Group"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
copy_from_selector: bpy.props.BoolProperty(name="Copy from Selector", default=False)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMGroupProperties
|
||||
@@ -121,6 +124,9 @@ class EditGroup(bpy.types.Operator, tool.Ifc.Operator):
|
||||
else:
|
||||
attributes[attribute.name] = attribute.string_value
|
||||
|
||||
if self.copy_from_selector:
|
||||
attributes["Description"] = context.scene.IFCSelector.selection_query
|
||||
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"group.edit_group", self.file, **{"group": self.file.by_id(props.active_group_id), "attributes": attributes}
|
||||
@@ -236,6 +242,31 @@ class SelectGroupProducts(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class UpdateGroup(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_idname = "bim.update_group"
|
||||
bl_label = "Update Group"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
query: bpy.props.StringProperty()
|
||||
group_id: bpy.props.IntProperty()
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
group = self.file.by_id(self.group_id)
|
||||
query = self.query
|
||||
|
||||
new_products = Selector.parse(self.file, query)
|
||||
ifcopenshell.api.run(
|
||||
"group.update_group_products",
|
||||
self.file,
|
||||
**{
|
||||
"group": group,
|
||||
"products": new_products,
|
||||
}
|
||||
)
|
||||
bpy.ops.bim.load_groups()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SelectGroupElements(bpy.types.Operator):
|
||||
bl_idname = "bim.select_group_elements"
|
||||
bl_label = "Select Group elements"
|
||||
|
||||
@@ -44,6 +44,7 @@ class ExpandedGroups(StrProperty):
|
||||
class Group(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
selection_query: StringProperty(name="Selection Query")
|
||||
is_expanded: BoolProperty(name="Is Expanded", default=False)
|
||||
has_children: BoolProperty(name="Has Children", default=False)
|
||||
tree_depth: IntProperty(name="Tree Depth")
|
||||
|
||||
@@ -131,7 +131,7 @@ class BIM_UL_groups(UIList):
|
||||
else:
|
||||
row.label(text="", icon="BLANK1")
|
||||
|
||||
row.label(text=item.name)
|
||||
row.label(text=f"*{item.name}") if item.selection_query != "" else row.label(text=item.name)
|
||||
group_id = item.ifc_definition_id
|
||||
if context.scene.BIMGroupProperties.active_group_id == group_id:
|
||||
op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||
@@ -145,6 +145,10 @@ class BIM_UL_groups(UIList):
|
||||
op.group = group_id
|
||||
op = row.operator("bim.remove_group", text="", icon="X")
|
||||
op.group = group_id
|
||||
if item.selection_query != "":
|
||||
op = row.operator("bim.update_group", text="", icon="FILE_REFRESH")
|
||||
op.group_id = item.ifc_definition_id
|
||||
op.query = item.selection_query
|
||||
else:
|
||||
op = row.operator("bim.select_group_products", text="", icon="RESTRICT_SELECT_OFF")
|
||||
op.group = group_id
|
||||
@@ -154,6 +158,10 @@ class BIM_UL_groups(UIList):
|
||||
op.group = group_id
|
||||
op = row.operator("bim.remove_group", text="", icon="X")
|
||||
op.group = group_id
|
||||
if item.selection_query != "":
|
||||
op = row.operator("bim.update_group", text="", icon="FILE_REFRESH")
|
||||
op.group_id = item.ifc_definition_id
|
||||
op.query = item.selection_query
|
||||
|
||||
|
||||
class BIM_UL_object_groups(UIList):
|
||||
|
||||
@@ -247,11 +247,9 @@ class IFCGIT_PT_revision_inspector(bpy.types.Panel):
|
||||
bl_idname = "IFCGIT_PT_revision_inspector"
|
||||
bl_label = "Git History"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
bl_parent_id = "IFCGIT_PT_panel"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "BlenderBIM"
|
||||
|
||||
def draw(self, context):
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ classes = (
|
||||
operator.AssignMaterial,
|
||||
operator.AssignParameterizedProfile,
|
||||
operator.ContractMaterialCategory,
|
||||
operator.CopyMaterial,
|
||||
operator.DisableEditingAssignedMaterial,
|
||||
operator.DisableEditingMaterial,
|
||||
operator.DisableEditingMaterialSetItem,
|
||||
@@ -58,10 +59,12 @@ classes = (
|
||||
operator.SelectByMaterial,
|
||||
operator.UnassignMaterial,
|
||||
operator.UnassignMaterialStyle,
|
||||
operator.UnlinkMaterial,
|
||||
prop.Material,
|
||||
prop.BIMMaterialProperties,
|
||||
prop.BIMObjectMaterialProperties,
|
||||
ui.BIM_PT_materials,
|
||||
ui.BIM_PT_material,
|
||||
ui.BIM_PT_object_material,
|
||||
ui.BIM_UL_materials,
|
||||
)
|
||||
|
||||
@@ -36,17 +36,31 @@ class MaterialsData:
|
||||
|
||||
@classmethod
|
||||
def load(cls):
|
||||
cls.data = {
|
||||
"total_materials": cls.total_materials(),
|
||||
"material_types": cls.material_types(),
|
||||
"profiles": cls.profiles(),
|
||||
"styles": cls.styles(),
|
||||
"contexts": cls.contexts(),
|
||||
"active_styles": cls.active_styles(),
|
||||
}
|
||||
cls.is_loaded = True
|
||||
cls.data["material_types"] = cls.material_types()
|
||||
cls.data["total_materials"] = cls.total_materials()
|
||||
cls.data["profiles"] = cls.profiles()
|
||||
cls.data["styles"] = cls.styles()
|
||||
cls.data["contexts"] = cls.contexts()
|
||||
cls.data["active_styles"] = cls.active_styles()
|
||||
|
||||
@classmethod
|
||||
def total_materials(cls):
|
||||
return len(tool.Ifc.get().by_type(bpy.context.scene.BIMMaterialProperties.material_type))
|
||||
if tool.Ifc.get_schema() == "IFC2X3":
|
||||
return (
|
||||
len(tool.Ifc.get().by_type("IfcMaterial"))
|
||||
+ len(tool.Ifc.get().by_type("IfcMaterialLayerSet"))
|
||||
+ len(tool.Ifc.get().by_type("IfcMaterialList"))
|
||||
)
|
||||
return (
|
||||
len(tool.Ifc.get().by_type("IfcMaterial"))
|
||||
+ len(tool.Ifc.get().by_type("IfcMaterialConstituentSet"))
|
||||
+ len(tool.Ifc.get().by_type("IfcMaterialLayerSet"))
|
||||
+ len(tool.Ifc.get().by_type("IfcMaterialProfileSet"))
|
||||
+ len(tool.Ifc.get().by_type("IfcMaterialList"))
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def material_types(cls):
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user