mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-14 03:14:23 +00:00
Merge remote-tracking branch 'origin/v0.6.0' into v0.7.0
# Conflicts: # .github/workflows/ci.yml # src/ifcparse/IfcParse.cpp
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
include src/bcf/v2/xsd/*.xsd
|
||||
include src/bcf/v3/xsd/*.xsd
|
||||
@@ -0,0 +1,12 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
"setuptools>=42",
|
||||
"wheel"
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
@@ -0,0 +1,37 @@
|
||||
[metadata]
|
||||
name=bcf-client
|
||||
version=0.0.1
|
||||
author = Ifcopenshell
|
||||
description = A simple Python implementation of BCF
|
||||
url = https://github.com/IfcOpenShell/IfcOpenShell
|
||||
project_urls =
|
||||
Code=https://github.com/IfcOpenShell/IfcOpenShell
|
||||
Issues=https://github.com/IfcOpenShell/IfcOpenShell/issues
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
classifiers =
|
||||
License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
||||
Operating System :: OS Independent
|
||||
Programming Language :: Python :: 3
|
||||
Topic :: Scientific/Engineering
|
||||
Topic :: Utilities
|
||||
keywords =
|
||||
Python
|
||||
file formats
|
||||
engineering
|
||||
|
||||
[options]
|
||||
package_dir =
|
||||
= src
|
||||
packages = find:
|
||||
python_requires = >=3
|
||||
install_requires=
|
||||
xmlschema
|
||||
include_package_data = True
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
||||
[flake8]
|
||||
max-line-length = 120
|
||||
ignore = E24, E121, E123, E126, E203, E226, E704, E741, W503, W504
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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/>.
|
||||
@@ -1,3 +1,22 @@
|
||||
# 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/>.
|
||||
|
||||
|
||||
import os.path
|
||||
import zipfile
|
||||
import tempfile
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.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/>.
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.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/>.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import shutil
|
||||
@@ -1,3 +1,22 @@
|
||||
|
||||
# BCF - BCF Python library
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.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/>.
|
||||
|
||||
class Project:
|
||||
def __init__(self):
|
||||
self.project_id = ""
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
# 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/>.
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
|
||||
# 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/>.
|
||||
|
||||
import uuid
|
||||
import time
|
||||
import json
|
||||
@@ -6,9 +25,8 @@ import requests
|
||||
import webbrowser
|
||||
import http.server
|
||||
import base64
|
||||
|
||||
from werkzeug.datastructures import HeaderSet
|
||||
|
||||
import tempfile
|
||||
import os
|
||||
|
||||
client_id, client_secret = "", ""
|
||||
|
||||
@@ -135,6 +153,7 @@ class BcfClient:
|
||||
self.foundation_client = foundation_client
|
||||
self.version_id = None
|
||||
self.baseurl = None
|
||||
self.filepath = tempfile.mkdtemp()
|
||||
|
||||
def set_version(self, version):
|
||||
self.version_id = version["version_id"]
|
||||
@@ -282,7 +301,7 @@ class BcfClient:
|
||||
headers=headers,
|
||||
)
|
||||
# TODO: write to tmpdir
|
||||
with open(f"{project_id}_{topic_id}_snippet.txt", "w") as f:
|
||||
with open(os.path.join(self.filepath, f"{project_id}_{topic_id}_snippet.txt"), "wb") as f:
|
||||
f.write(response.content.decode("utf-8"))
|
||||
return response.status_code, response.content
|
||||
|
||||
@@ -544,7 +563,7 @@ class BcfClient:
|
||||
f"{self.baseurl}/projects/{project_id}/topics/documents/{document_id}",
|
||||
headers=headers,
|
||||
)
|
||||
with open(f"{project_id}_{topic_id}_{document_id}_document.txt", "w") as f:
|
||||
with open(os.path.join(self.filepath, f"{project_id}_{topic_id}_{document_id}_document.txt"), "wb") as f:
|
||||
f.write(response.content.decode("utf-8"))
|
||||
return response.status_code, response.content
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
|
||||
# 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/>.
|
||||
|
||||
import os
|
||||
import uuid
|
||||
import shutil
|
||||
@@ -1,3 +1,22 @@
|
||||
|
||||
# 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/>.
|
||||
|
||||
class Project:
|
||||
def __init__(self):
|
||||
self.project_id = ""
|
||||
+66
-2
@@ -1,3 +1,21 @@
|
||||
# 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/>.
|
||||
|
||||
VERSION:=`date '+%y%m%d'`
|
||||
PYVERSION:=py37
|
||||
|
||||
@@ -15,11 +33,13 @@ ifeq ($(PYVERSION), py37)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/linux-64/hpp-fcl-1.7.5-py37h5f1835d_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/linux-64/eigenpy-2.6.5-py37h95e2c48_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/linux-64/boost-1.74.0-py37h0379df6_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/30/c0/d0526314971fc661b083ab135747dc68446a3022686da8c16d25fcf6ef07/lxml-4.6.3-cp37-cp37m-manylinux2014_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/linux-64/hpp-fcl-1.7.5-py39hbcdfc36_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/linux-64/eigenpy-2.6.5-py39h5aed9d1_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/linux-64/boost-1.74.0-py39h5472131_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/19/d9/a69c6aff5673554df48120565a14a50eaa41d29ae03b02faa0b023666318/lxml-4.6.3-cp39-cp39-manylinux2014_x86_64.whl
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/linux-64/assimp-5.0.1-hedfc422_6.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.7/download/linux-64/octomap-1.9.7-h4bd325d_0.tar.bz2
|
||||
@@ -31,11 +51,13 @@ ifeq ($(PYVERSION), py37)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/osx-64/hpp-fcl-1.7.5-py37h2d7f23a_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/osx-64/eigenpy-2.6.5-py37h0695097_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/osx-64/boost-1.74.0-py37hd79e0ac_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/1e/3e/f0abc15d5dac50939bccc589aae336d5ead4c72e7ad1039a2e0f3630ea92/lxml-4.6.3-cp37-cp37m-macosx_10_9_x86_64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/osx-64/hpp-fcl-1.7.5-py39h1e32b98_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/osx-64/eigenpy-2.6.5-py39h5405915_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/osx-64/boost-1.74.0-py39ha641261_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/b8/74/a71f7ad72e8db54ce899efab84507b801660750cbbfa6a39e6717557d36a/lxml-4.6.3-cp39-cp39-macosx_10_9_x86_64.whl
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/osx-64/assimp-5.0.1-h1224e73_6.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.7/download/osx-64/octomap-1.9.7-h940c156_0.tar.bz2
|
||||
@@ -47,11 +69,13 @@ ifeq ($(PYVERSION), py37)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/win-64/hpp-fcl-1.7.5-py37h839d6b1_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/win-64/eigenpy-2.6.5-py37h2c32e34_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/win-64/boost-1.74.0-py37h3b38789_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/9e/5e/171ee9d40a600f565fe691ec5bf7596247ec62cfb2edc00c91afe8ea837b/lxml-4.6.3-cp37-cp37m-win_amd64.whl
|
||||
endif
|
||||
ifeq ($(PYVERSION), py39)
|
||||
HPPFCL_URL:=https://anaconda.org/conda-forge/hpp-fcl/1.7.5/download/win-64/hpp-fcl-1.7.5-py39h2e7c763_0.tar.bz2
|
||||
EIGENPY_URL:=https://anaconda.org/conda-forge/eigenpy/2.6.5/download/win-64/eigenpy-2.6.5-py39h3ce40e6_0.tar.bz2
|
||||
BOOST_URL:=https://anaconda.org/conda-forge/boost/1.74.0/download/win-64/boost-1.74.0-py39hefe7e4c_3.tar.bz2
|
||||
LXML_URL:=https://files.pythonhosted.org/packages/72/d4/426ecb8849c47c3e370c87aa0ac05d85768df917ffea27fcd6686a5e6495/lxml-4.6.3-cp39-cp39-win_amd64.whl
|
||||
endif
|
||||
ASSIMP_URL:=https://anaconda.org/conda-forge/assimp/5.0.1/download/win-64/assimp-5.0.1-hc2aa0de_6.tar.bz2
|
||||
OCTOMAP_URL:=https://anaconda.org/conda-forge/octomap/1.9.7/download/win-64/octomap-1.9.7-h5362a0b_0.tar.bz2
|
||||
@@ -69,7 +93,7 @@ endif
|
||||
cp -r blenderbim/* dist/blenderbim/
|
||||
|
||||
# Provides IfcOpenShell Python functionality
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-$(PYNUMBER)-v0.6.0-2f3c79a-$(PLATFORM)64.zip
|
||||
cd dist/working && wget https://s3.amazonaws.com/ifcopenshell-builds/ifcblender-python-$(PYNUMBER)-v0.6.0-721fe47-$(PLATFORM)64.zip
|
||||
cd dist/working && unzip ifcblender*
|
||||
cp -r dist/working/io_import_scene_ifc/ifcopenshell dist/blenderbim/libs/site/packages/
|
||||
|
||||
@@ -99,7 +123,7 @@ endif
|
||||
cp dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/entity_instance.py dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
cp dist/working/IfcOpenShell-0.6.0/src/ifcopenshell-python/ifcopenshell/file.py dist/blenderbim/libs/site/packages/ifcopenshell/
|
||||
# Provides bcf functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/bcf/bcf dist/blenderbim/libs/site/packages/
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/bcf/src/bcf dist/blenderbim/libs/site/packages/
|
||||
# Provides IFCClash functionality
|
||||
cp -r dist/working/IfcOpenShell-0.6.0/src/ifcclash/ifcclash dist/blenderbim/libs/site/packages/
|
||||
# Provides BIMTester functionality
|
||||
@@ -332,6 +356,13 @@ endif
|
||||
cd dist/working/ && patch ../blenderbim/libs/site/packages/behave/runner_util.py < runner_util.patch
|
||||
rm -rf dist/working
|
||||
|
||||
# Required by ids
|
||||
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
|
||||
|
||||
# Required by behave
|
||||
mkdir dist/working
|
||||
cd dist/working && wget https://files.pythonhosted.org/packages/f4/65/220bb4075fddb09d5b3ea2c1c1fa66c1c72be9361ec187aab50fa161e576/parse-1.15.0.tar.gz
|
||||
@@ -413,6 +444,39 @@ endif
|
||||
cd dist && zip -r blenderbim-$(VERSION)-$(PYVERSION)-$(PLATFORM).zip ./*
|
||||
rm -rf dist/blenderbim
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
make test-core
|
||||
make test-bim
|
||||
|
||||
.PHONY: test-core
|
||||
test-core:
|
||||
pytest -p no:pytest-blender test/core
|
||||
|
||||
.PHONY: test-bim
|
||||
test-bim:
|
||||
pytest test/bim
|
||||
|
||||
.PHONY: qa
|
||||
qa:
|
||||
black .
|
||||
pylint ./* --output-format=colorized --disable all --enable E --disable import-error
|
||||
|
||||
.PHONY: coverage
|
||||
coverage:
|
||||
coverage run --source blenderbim.core -m pytest -p no:pytest-blender test/core
|
||||
coverage html
|
||||
xdg-open htmlcov/index.html
|
||||
|
||||
.PHONY: license
|
||||
license:
|
||||
copyright-header --license GPL3 --copyright-holder "Dion Moult <dion@thinkmoult.com>" --copyright-year "2021" --copyright-software "BlenderBIM Add-on" --copyright-software-description "OpenBIM Blender Add-on" -a ./ -o ./
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf dist
|
||||
rm -rf htmlcov
|
||||
|
||||
.PHONY: dev
|
||||
dev:
|
||||
blender -p setup_pytest.py
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -17,10 +16,14 @@
|
||||
# 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 sys
|
||||
import site
|
||||
|
||||
bl_info = {
|
||||
"name": "BlenderBIM",
|
||||
"description": "Author, import, and export files in the " "Industry Foundation Classes (.ifc) file format",
|
||||
"author": "Dion Moult, IfcOpenShell",
|
||||
"description": "Author, import, and export data using the Industry Foundation Classes schema",
|
||||
"author": "IfcOpenShell Contributors",
|
||||
"blender": (2, 80, 0),
|
||||
"version": (0, 0, 999999),
|
||||
"location": "File > Export, File > Import, Scene / Object / Material / Mesh Properties",
|
||||
@@ -28,25 +31,15 @@ bl_info = {
|
||||
"category": "Import-Export",
|
||||
}
|
||||
|
||||
import os
|
||||
import site
|
||||
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"))
|
||||
|
||||
import blenderbim.bim
|
||||
|
||||
# process *.pth in /libs/site/packages to setup globally importable modules
|
||||
# 3 levels deep required by occ static ../../ path
|
||||
# TODO: 3 levels deep is no longer required as we no longer bundle OCC
|
||||
cwd = os.path.dirname(os.path.realpath(__file__))
|
||||
site.addsitedir(os.path.join(cwd, "libs", "site", "packages"))
|
||||
def register():
|
||||
blenderbim.bim.register()
|
||||
|
||||
|
||||
# main import
|
||||
from .bim import *
|
||||
|
||||
|
||||
# Explicitely expose bim.xx when imported with from blenderbim import *
|
||||
# Other bim still are importable using explicit from blenderbim.bim import xxx
|
||||
__all__ = ["export_ifc", "import_ifc"]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
register()
|
||||
def unregister():
|
||||
blenderbim.bim.unregister()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -17,157 +16,152 @@
|
||||
# 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/>.
|
||||
|
||||
# Check if we are running in Blender before loading, to allow for multiprocessing
|
||||
import sys
|
||||
import bpy
|
||||
import importlib
|
||||
from . import handler, ui, prop, operator
|
||||
|
||||
bpy = sys.modules.get("bpy")
|
||||
modules = {
|
||||
"project": None,
|
||||
"search": None,
|
||||
"bcf": None,
|
||||
"root": None,
|
||||
"unit": None,
|
||||
"model": None,
|
||||
"georeference": None,
|
||||
"context": None,
|
||||
"drawing": None,
|
||||
"attribute": None,
|
||||
"type": None,
|
||||
"spatial": None,
|
||||
"void": None,
|
||||
"aggregate": None,
|
||||
"geometry": None,
|
||||
"cobie": None,
|
||||
"resource": None,
|
||||
"cost": None,
|
||||
"sequence": None,
|
||||
"group": None,
|
||||
"system": None,
|
||||
"structural": None,
|
||||
"boundary": None,
|
||||
"profile": None,
|
||||
"material": None,
|
||||
"style": None,
|
||||
"layer": None,
|
||||
"owner": None,
|
||||
"pset": None,
|
||||
"qto": None,
|
||||
"classification": None,
|
||||
"constraint": None,
|
||||
"document": None,
|
||||
"pset_template": None,
|
||||
"clash": None,
|
||||
"lca": None,
|
||||
"csv": None,
|
||||
"bimtester": None,
|
||||
"diff": None,
|
||||
"patch": None,
|
||||
"covetool": None,
|
||||
"augin": None,
|
||||
"debug": None,
|
||||
}
|
||||
|
||||
if bpy is not None:
|
||||
import bpy
|
||||
import importlib
|
||||
from . import handler, ui, prop, operator
|
||||
for name in modules.keys():
|
||||
modules[name] = importlib.import_module(f"blenderbim.bim.module.{name}")
|
||||
|
||||
modules = {
|
||||
"project": None,
|
||||
"search": None,
|
||||
"bcf": None,
|
||||
"root": None,
|
||||
"unit": None,
|
||||
"model": None,
|
||||
"georeference": None,
|
||||
"context": None,
|
||||
"drawing": None,
|
||||
"attribute": None,
|
||||
"type": None,
|
||||
"spatial": None,
|
||||
"void": None,
|
||||
"aggregate": None,
|
||||
"geometry": None,
|
||||
"cobie": None,
|
||||
"resource": None,
|
||||
"cost": None,
|
||||
"sequence": None,
|
||||
"group": None,
|
||||
"system": None,
|
||||
"structural": None,
|
||||
"boundary": None,
|
||||
"profile": None,
|
||||
"material": None,
|
||||
"style": None,
|
||||
"layer": None,
|
||||
"owner": None,
|
||||
"pset": None,
|
||||
"qto": None,
|
||||
"classification": None,
|
||||
"constraint": None,
|
||||
"document": None,
|
||||
"pset_template": None,
|
||||
"clash": None,
|
||||
"lca": None,
|
||||
"csv": None,
|
||||
"bimtester": None,
|
||||
"diff": None,
|
||||
"patch": None,
|
||||
"covetool": None,
|
||||
"augin": None,
|
||||
"debug": None,
|
||||
}
|
||||
classes = [
|
||||
operator.OpenUri,
|
||||
operator.SelectDataDir,
|
||||
operator.SelectSchemaDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.ExportIFC,
|
||||
operator.ImportIFC,
|
||||
operator.OpenUpstream,
|
||||
operator.AddSectionPlane,
|
||||
operator.RemoveSectionPlane,
|
||||
operator.ReloadIfcFile,
|
||||
operator.AddIfcFile,
|
||||
operator.RemoveIfcFile,
|
||||
operator.SetOverrideColour,
|
||||
operator.SetViewportShadowFromSun,
|
||||
operator.SnapSpacesTogether,
|
||||
operator.OverrideDelete,
|
||||
prop.StrProperty,
|
||||
prop.Attribute,
|
||||
prop.BIMProperties,
|
||||
prop.IfcParameter,
|
||||
prop.PsetQto,
|
||||
prop.GlobalId,
|
||||
prop.BIMObjectProperties,
|
||||
prop.BIMMaterialProperties,
|
||||
prop.BIMMeshProperties,
|
||||
ui.BIM_PT_section_plane,
|
||||
ui.BIM_UL_generic,
|
||||
ui.BIM_UL_topics,
|
||||
ui.BIM_ADDON_preferences,
|
||||
]
|
||||
|
||||
for name in modules.keys():
|
||||
modules[name] = importlib.import_module(f"blenderbim.bim.module.{name}")
|
||||
for mod in modules.values():
|
||||
classes.extend(mod.classes)
|
||||
|
||||
classes = [
|
||||
operator.OpenUri,
|
||||
operator.SelectDataDir,
|
||||
operator.SelectSchemaDir,
|
||||
operator.SelectIfcFile,
|
||||
operator.ExportIFC,
|
||||
operator.ImportIFC,
|
||||
operator.OpenUpstream,
|
||||
operator.AddSectionPlane,
|
||||
operator.RemoveSectionPlane,
|
||||
operator.ReloadIfcFile,
|
||||
operator.AddIfcFile,
|
||||
operator.RemoveIfcFile,
|
||||
operator.SetOverrideColour,
|
||||
operator.SetViewportShadowFromSun,
|
||||
operator.LinkIfc,
|
||||
operator.SnapSpacesTogether,
|
||||
prop.StrProperty,
|
||||
prop.Attribute,
|
||||
prop.BIMProperties,
|
||||
prop.IfcParameter,
|
||||
prop.PsetQto,
|
||||
prop.GlobalId,
|
||||
prop.BIMObjectProperties,
|
||||
prop.BIMMaterialProperties,
|
||||
prop.BIMMeshProperties,
|
||||
ui.BIM_PT_section_plane,
|
||||
ui.BIM_UL_generic,
|
||||
ui.BIM_UL_topics,
|
||||
ui.BIM_ADDON_preferences,
|
||||
]
|
||||
|
||||
for module in modules.values():
|
||||
classes.extend(module.classes)
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)")
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(operator.ExportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcjson)")
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(operator.ImportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcxml)")
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(operator.ImportIFC.bl_idname, text="Industry Foundation Classes (.ifc/.ifczip/.ifcxml)")
|
||||
|
||||
def on_register(scene):
|
||||
handler.setDefaultProperties(scene)
|
||||
bpy.app.handlers.depsgraph_update_post.remove(on_register)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.app.handlers.depsgraph_update_post.append(on_register)
|
||||
bpy.app.handlers.undo_pre.append(handler.undo_pre)
|
||||
bpy.app.handlers.undo_post.append(handler.undo_post)
|
||||
bpy.app.handlers.redo_pre.append(handler.redo_pre)
|
||||
bpy.app.handlers.redo_post.append(handler.redo_post)
|
||||
bpy.app.handlers.load_post.append(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.append(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Collection.BIMObjectProperties = bpy.props.PointerProperty(
|
||||
type=prop.BIMObjectProperties
|
||||
) # Check if we need this
|
||||
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
|
||||
bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Curve.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Camera.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.PointLight.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
||||
def on_register(scene):
|
||||
handler.setDefaultProperties(scene)
|
||||
bpy.app.handlers.depsgraph_update_post.remove(on_register)
|
||||
|
||||
for module in modules.values():
|
||||
module.register()
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
del bpy.types.Scene.BIMProperties
|
||||
del bpy.types.Object.BIMObjectProperties
|
||||
del bpy.types.Material.BIMObjectProperties
|
||||
del bpy.types.Collection.BIMObjectProperties # Check if we need this
|
||||
del bpy.types.Material.BIMMaterialProperties
|
||||
del bpy.types.Mesh.BIMMeshProperties
|
||||
del bpy.types.Curve.BIMMeshProperties
|
||||
del bpy.types.Camera.BIMMeshProperties
|
||||
del bpy.types.PointLight.BIMMeshProperties
|
||||
bpy.types.SCENE_PT_unit.remove(ui.ifc_units)
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
bpy.app.handlers.depsgraph_update_post.append(on_register)
|
||||
bpy.app.handlers.undo_pre.append(handler.undo_pre)
|
||||
bpy.app.handlers.undo_post.append(handler.undo_post)
|
||||
bpy.app.handlers.redo_pre.append(handler.redo_pre)
|
||||
bpy.app.handlers.redo_post.append(handler.redo_post)
|
||||
bpy.app.handlers.load_post.append(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.append(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.append(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
|
||||
bpy.types.Scene.BIMProperties = bpy.props.PointerProperty(type=prop.BIMProperties)
|
||||
bpy.types.Object.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMObjectProperties = bpy.props.PointerProperty(type=prop.BIMObjectProperties)
|
||||
bpy.types.Material.BIMMaterialProperties = bpy.props.PointerProperty(type=prop.BIMMaterialProperties)
|
||||
bpy.types.Mesh.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Curve.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.Camera.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.PointLight.BIMMeshProperties = bpy.props.PointerProperty(type=prop.BIMMeshProperties)
|
||||
bpy.types.SCENE_PT_unit.append(ui.ifc_units)
|
||||
|
||||
for module in reversed(list(modules.values())):
|
||||
module.unregister()
|
||||
for mod in modules.values():
|
||||
mod.register()
|
||||
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
||||
bpy.app.handlers.load_post.remove(handler.setDefaultProperties)
|
||||
bpy.app.handlers.load_post.remove(handler.loadIfcStore)
|
||||
bpy.app.handlers.save_pre.remove(handler.ensureIfcExported)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
|
||||
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
|
||||
del bpy.types.Scene.BIMProperties
|
||||
del bpy.types.Object.BIMObjectProperties
|
||||
del bpy.types.Material.BIMObjectProperties
|
||||
del bpy.types.Material.BIMMaterialProperties
|
||||
del bpy.types.Mesh.BIMMeshProperties
|
||||
del bpy.types.Curve.BIMMeshProperties
|
||||
del bpy.types.Camera.BIMMeshProperties
|
||||
del bpy.types.PointLight.BIMMeshProperties
|
||||
bpy.types.SCENE_PT_unit.remove(ui.ifc_units)
|
||||
|
||||
for mod in reversed(list(modules.values())):
|
||||
mod.unregister()
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION((),'2;1');
|
||||
FILE_NAME('EPset_Productivity.ifc','2020-01-01T00:00:00',(),(),'EPset_Productivity','EPset_Productivity',$);
|
||||
FILE_SCHEMA(('IFC4'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPROPERTYSETTEMPLATE('24XxTA2ED4o83uiZBG59D_',$,'EPset_Productivity','',.PSET_TYPEDRIVENOVERRIDE.,'IfcConstructionEquipmentResource,IfcLaborResource',(#2,#3,#4));
|
||||
#2=IFCSIMPLEPROPERTYTEMPLATE('3mL27FQ4X4MQn5fiGqIt8x',$,'BaseQuantityConsumed','',.P_SINGLEVALUE.,'IfcDuration',$,$,$,$,$,.READWRITE.);
|
||||
#3=IFCSIMPLEPROPERTYTEMPLATE('1DdJt5_Ar2mR4UDpO$98Ws',$,'BaseQuantityProducedName','',.P_SINGLEVALUE.,'IfcLabel',$,$,$,$,$,.READWRITE.);
|
||||
#4=IFCSIMPLEPROPERTYTEMPLATE('2OZPZ$Onb2gOvW20q7gacH',$,'BaseQuantityProducedValue','',.P_SINGLEVALUE.,'IfcReal',$,$,$,$,$,.READWRITE.);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -114,7 +113,7 @@ class IfcExporter:
|
||||
IfcStore.edited_objs.clear()
|
||||
|
||||
def sync_object_placement(self, obj):
|
||||
blender_matrix = np.matrix(obj.matrix_world)
|
||||
blender_matrix = np.array(obj.matrix_world)
|
||||
element = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||
if not hasattr(element, "ObjectPlacement"):
|
||||
return
|
||||
@@ -158,7 +157,6 @@ class IfcExporter:
|
||||
else:
|
||||
parent_collection = obj.users_collection[0]
|
||||
|
||||
|
||||
parent_obj = bpy.data.objects.get(parent_collection.name)
|
||||
if not parent_obj or not parent_obj.BIMObjectProperties.ifc_definition_id:
|
||||
return
|
||||
@@ -174,6 +172,7 @@ class IfcExporter:
|
||||
try:
|
||||
# This will throw an exception if the Blender object no longer exists
|
||||
foo = obj.name
|
||||
foo
|
||||
return False
|
||||
except:
|
||||
return True
|
||||
@@ -201,7 +200,6 @@ class IfcExportSettings:
|
||||
|
||||
@staticmethod
|
||||
def factory(context, output_file, logger):
|
||||
scene_bim = context.scene.BIMProperties
|
||||
settings = IfcExportSettings()
|
||||
settings.output_file = output_file
|
||||
settings.logger = logger
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -19,8 +18,11 @@
|
||||
|
||||
import bpy
|
||||
import uuid
|
||||
import zipfile
|
||||
import tempfile
|
||||
import ifcopenshell
|
||||
import blenderbim.bim.handler
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class IfcStore:
|
||||
@@ -183,7 +185,7 @@ class IfcStore:
|
||||
def commit_link_element(data):
|
||||
obj = bpy.data.objects.get(data["obj"])
|
||||
IfcStore.id_map[data["id"]] = obj
|
||||
if data["guid"]:
|
||||
if "guid" in data:
|
||||
IfcStore.guid_map[data["guid"]] = obj
|
||||
blenderbim.bim.handler.subscribe_to(obj, "mode", blenderbim.bim.handler.mode_callback)
|
||||
blenderbim.bim.handler.subscribe_to(obj, "name", blenderbim.bim.handler.name_callback)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -17,31 +16,23 @@
|
||||
# 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 ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.geolocation
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.unit
|
||||
import bpy
|
||||
import bmesh
|
||||
import os
|
||||
import re
|
||||
import bpy
|
||||
import time
|
||||
import bmesh
|
||||
import shutil
|
||||
import threading
|
||||
import json
|
||||
import time
|
||||
import mathutils
|
||||
import math
|
||||
import multiprocessing
|
||||
import zipfile
|
||||
import tempfile
|
||||
import numpy as np
|
||||
from blenderbim.bim.module.drawing.prop import getDiagramScales
|
||||
from pathlib import Path
|
||||
from itertools import cycle
|
||||
from datetime import datetime
|
||||
import multiprocessing
|
||||
import ifcopenshell
|
||||
import ifcopenshell.geom
|
||||
import ifcopenshell.util.unit
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.selector
|
||||
import ifcopenshell.util.geolocation
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.module.drawing.prop import get_diagram_scales
|
||||
|
||||
|
||||
class FileCopy(threading.Thread):
|
||||
@@ -172,12 +163,9 @@ class IfcImporter:
|
||||
self.settings_native.set(self.settings_native.INCLUDE_CURVES, True)
|
||||
self.settings_2d = ifcopenshell.geom.settings()
|
||||
self.settings_2d.set(self.settings_2d.INCLUDE_CURVES, True)
|
||||
self.filter_mode = None
|
||||
self.include_elements = set()
|
||||
self.exclude_elements = set()
|
||||
self.project = None
|
||||
self.spatial_structure_elements = {}
|
||||
self.elements = []
|
||||
self.collections = {}
|
||||
self.elements = set()
|
||||
self.type_collection = None
|
||||
self.type_products = {}
|
||||
self.openings = {}
|
||||
@@ -188,7 +176,6 @@ class IfcImporter:
|
||||
self.added_data = {}
|
||||
self.native_elements = set()
|
||||
self.native_data = {}
|
||||
self.aggregates = {}
|
||||
|
||||
self.material_creator = MaterialCreator(ifc_import_settings, self)
|
||||
|
||||
@@ -208,10 +195,6 @@ class IfcImporter:
|
||||
bpy.context.window_manager.progress_begin(0, 100)
|
||||
self.progress = 0
|
||||
self.profile_code("Starting import process")
|
||||
self.load_diff()
|
||||
self.profile_code("Load diff")
|
||||
self.purge_diff()
|
||||
self.profile_code("Purge diffs")
|
||||
self.load_file()
|
||||
self.profile_code("Loading file")
|
||||
self.calculate_unit_scale()
|
||||
@@ -222,47 +205,41 @@ class IfcImporter:
|
||||
self.profile_code("Set units")
|
||||
self.create_project()
|
||||
self.profile_code("Create project")
|
||||
self.create_spatial_hierarchy()
|
||||
self.profile_code("Create spatial hierarchy")
|
||||
self.process_element_filter()
|
||||
self.profile_code("Process element filter")
|
||||
self.create_aggregates()
|
||||
self.profile_code("Create aggregates")
|
||||
self.create_aggregate_tree()
|
||||
self.profile_code("Create aggregate tree")
|
||||
self.create_collections()
|
||||
self.profile_code("Create collections")
|
||||
self.create_openings_collection()
|
||||
self.profile_code("Create opening collection")
|
||||
self.create_materials()
|
||||
self.profile_code("Create materials")
|
||||
self.create_styles()
|
||||
self.profile_code("Create styles")
|
||||
self.parse_native_elements()
|
||||
self.profile_code("Parsing native elements")
|
||||
self.create_grids()
|
||||
self.profile_code("Create grids")
|
||||
self.create_native_products()
|
||||
self.profile_code("Create native products")
|
||||
self.create_products()
|
||||
self.profile_code("Create products")
|
||||
self.create_empty_and_2d_elements()
|
||||
self.profile_code("Create empty products")
|
||||
self.create_type_products()
|
||||
self.profile_code("Create type products")
|
||||
self.create_annotation()
|
||||
self.profile_code("Create annotation")
|
||||
self.create_structural_elements()
|
||||
self.profile_code("Create structural elements")
|
||||
self.place_objects_in_spatial_tree()
|
||||
self.profile_code("Placing objects in spatial tree")
|
||||
self.parse_native_elements()
|
||||
self.profile_code("Parsing native elements")
|
||||
self.create_native_elements()
|
||||
self.profile_code("Create native elements")
|
||||
self.create_elements()
|
||||
self.profile_code("Create elements")
|
||||
self.create_grids()
|
||||
self.profile_code("Create grids")
|
||||
self.create_spatial_elements()
|
||||
self.profile_code("Create spatial elements")
|
||||
self.create_structural_items()
|
||||
self.profile_code("Create structural items")
|
||||
self.create_type_products()
|
||||
self.profile_code("Create type products")
|
||||
self.place_objects_in_collections()
|
||||
self.profile_code("Place objects in collections")
|
||||
if self.ifc_import_settings.should_merge_by_class:
|
||||
self.merge_by_class()
|
||||
self.profile_code("Merging by class")
|
||||
elif self.ifc_import_settings.should_merge_by_material:
|
||||
self.merge_by_material()
|
||||
self.profile_code("Merging by material")
|
||||
if self.ifc_import_settings.should_merge_materials_by_colour or (
|
||||
self.ifc_import_settings.should_auto_set_workarounds and len(self.material_creator.materials) > 300
|
||||
):
|
||||
if self.ifc_import_settings.should_merge_materials_by_colour or len(self.material_creator.materials) > 300:
|
||||
self.merge_materials_by_colour()
|
||||
self.profile_code("Merging by colour")
|
||||
self.add_project_to_scene()
|
||||
@@ -290,32 +267,32 @@ class IfcImporter:
|
||||
return abs(coords[0]) > limit or abs(coords[1]) > limit or abs(coords[2]) > limit
|
||||
|
||||
def process_element_filter(self):
|
||||
if self.ifc_import_settings.ifc_import_filter == "NONE" or not self.ifc_import_settings.ifc_selector:
|
||||
self.elements = self.file.by_type("IfcElement")
|
||||
return
|
||||
if self.ifc_import_settings.has_filter:
|
||||
self.elements = set(self.ifc_import_settings.elements)
|
||||
self.spatial_elements = self.get_spatial_elements_filtered_by_elements(self.elements)
|
||||
else:
|
||||
self.elements = set(self.file.by_type("IfcElement"))
|
||||
if self.file.schema == "IFC2X3":
|
||||
self.spatial_elements = set(self.file.by_type("IfcSpatialStructureElement"))
|
||||
else:
|
||||
self.spatial_elements = set(self.file.by_type("IfcSpatialElement"))
|
||||
|
||||
selector = ifcopenshell.util.selector.Selector()
|
||||
elements = selector.parse(self.file, self.ifc_import_settings.ifc_selector)
|
||||
if self.ifc_import_settings.ifc_import_filter == "WHITELIST":
|
||||
self.filter_mode = "WHITELIST"
|
||||
self.include_elements = set(elements)
|
||||
self.elements = self.include_elements
|
||||
elif self.ifc_import_settings.ifc_import_filter == "BLACKLIST":
|
||||
self.filter_mode = "BLACKLIST"
|
||||
self.exclude_elements = set(elements)
|
||||
self.elements = [e for e in self.file.by_type("IfcElement") if e not in self.exclude_elements]
|
||||
def get_spatial_elements_filtered_by_elements(self, elements):
|
||||
leaf_spatial_elements = set([ifcopenshell.util.element.get_container(e) for e in elements])
|
||||
results = set()
|
||||
for spatial_element in leaf_spatial_elements:
|
||||
while True:
|
||||
results.add(spatial_element)
|
||||
spatial_element = ifcopenshell.util.element.get_aggregate(spatial_element)
|
||||
if not spatial_element or spatial_element.is_a("IfcContext"):
|
||||
break
|
||||
return results
|
||||
|
||||
def parse_native_elements(self):
|
||||
if self.filter_mode == "WHITELIST":
|
||||
for element in self.include_elements:
|
||||
if self.is_native(element):
|
||||
self.native_elements[element.GlobalId] = element
|
||||
self.include_elements -= self.native_elements
|
||||
elif self.filter_mode == "BLACKLIST":
|
||||
for element in set(self.file.by_type("IfcElement")) - self.exclude_elements:
|
||||
if self.is_native(element):
|
||||
self.native_elements.add(element)
|
||||
self.exclude_elements |= self.native_elements
|
||||
for element in self.elements:
|
||||
if self.is_native(element):
|
||||
self.native_elements.add(element)
|
||||
self.elements -= self.native_elements
|
||||
|
||||
def is_native(self, element):
|
||||
if (
|
||||
@@ -408,7 +385,6 @@ class IfcImporter:
|
||||
props.has_blender_offset = True
|
||||
|
||||
def get_offset_point(self):
|
||||
offset_point = None
|
||||
elements_checked = 0
|
||||
# If more than these points aren't far away, the file probably isn't absolutely positioned
|
||||
element_checking_threshold = 100
|
||||
@@ -444,31 +420,33 @@ class IfcImporter:
|
||||
if props.has_blender_offset:
|
||||
if self.is_point_far_away((matrix[0, 3], matrix[1, 3], matrix[2, 3])):
|
||||
obj.BIMObjectProperties.blender_offset_type = "OBJECT_PLACEMENT"
|
||||
return mathutils.Matrix(
|
||||
ifcopenshell.util.geolocation.global2local(
|
||||
matrix,
|
||||
float(props.blender_eastings) * self.unit_scale,
|
||||
float(props.blender_northings) * self.unit_scale,
|
||||
float(props.blender_orthogonal_height) * self.unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
).tolist()
|
||||
matrix = ifcopenshell.util.geolocation.global2local(
|
||||
matrix,
|
||||
float(props.blender_eastings) * self.unit_scale,
|
||||
float(props.blender_northings) * self.unit_scale,
|
||||
float(props.blender_orthogonal_height) * self.unit_scale,
|
||||
float(props.blender_x_axis_abscissa),
|
||||
float(props.blender_x_axis_ordinate),
|
||||
)
|
||||
else:
|
||||
obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT"
|
||||
|
||||
if self.ifc_import_settings.should_offset_model:
|
||||
matrix[0, 3] += self.ifc_import_settings.model_offset_coordinates[0]
|
||||
matrix[1, 3] += self.ifc_import_settings.model_offset_coordinates[1]
|
||||
matrix[2, 3] += self.ifc_import_settings.model_offset_coordinates[2]
|
||||
|
||||
return mathutils.Matrix(matrix.tolist())
|
||||
|
||||
def find_decomposed_ifc_class(self, element, ifc_class):
|
||||
results = []
|
||||
if element.is_a(ifc_class):
|
||||
return element
|
||||
rel_aggregates = element.IsDecomposedBy
|
||||
if not rel_aggregates:
|
||||
return results
|
||||
for rel_aggregate in rel_aggregates:
|
||||
for part in rel_aggregate.RelatedObjects:
|
||||
if part.is_a(ifc_class):
|
||||
results.append(part)
|
||||
results.extend(self.find_decomposed_ifc_class(part, ifc_class))
|
||||
return results
|
||||
result = self.find_decomposed_ifc_class(part, ifc_class)
|
||||
if result:
|
||||
return result
|
||||
|
||||
def create_grids(self):
|
||||
grids = self.file.by_type("IfcGrid")
|
||||
@@ -503,15 +481,8 @@ class IfcImporter:
|
||||
grid_collection.objects.link(obj)
|
||||
|
||||
def create_type_products(self):
|
||||
for collection in self.project["blender"].children:
|
||||
if collection.name == "Types":
|
||||
self.type_collection = collection
|
||||
break
|
||||
if not self.type_collection:
|
||||
self.type_collection = bpy.data.collections.new("Types")
|
||||
self.project["blender"].children.link(self.type_collection)
|
||||
|
||||
if self.filter_mode in ["WHITELIST", "BLACKLIST"]:
|
||||
# TODO allow filtering of spatial elements too
|
||||
if self.ifc_import_settings.has_filter:
|
||||
type_products = set([ifcopenshell.util.element.get_type(e) for e in self.elements])
|
||||
else:
|
||||
type_products = self.file.by_type("IfcTypeProduct")
|
||||
@@ -553,7 +524,7 @@ class IfcImporter:
|
||||
):
|
||||
return representation_map
|
||||
|
||||
def create_native_products(self):
|
||||
def create_native_elements(self):
|
||||
total = 0
|
||||
checkpoint = time.time()
|
||||
bm = bmesh.new()
|
||||
@@ -586,40 +557,51 @@ class IfcImporter:
|
||||
bm.to_mesh(mesh)
|
||||
bm.clear()
|
||||
bm.free()
|
||||
|
||||
print("Done creating geometry")
|
||||
|
||||
def create_products(self):
|
||||
def create_spatial_elements(self):
|
||||
products = self.create_products(self.spatial_elements)
|
||||
self.spatial_elements -= products
|
||||
products = self.create_curve_products(self.spatial_elements)
|
||||
self.spatial_elements -= products
|
||||
for element in self.spatial_elements:
|
||||
self.create_product(element)
|
||||
|
||||
def create_elements(self):
|
||||
products = self.create_products(self.elements)
|
||||
self.elements -= products
|
||||
products = self.create_curve_products(self.elements)
|
||||
self.elements -= products
|
||||
for element in self.elements:
|
||||
self.create_product(element)
|
||||
|
||||
def create_products(self, products):
|
||||
results = set()
|
||||
if not products:
|
||||
return results
|
||||
if self.ifc_import_settings.should_use_cpu_multiprocessing:
|
||||
iterator = ifcopenshell.geom.iterator(
|
||||
self.settings,
|
||||
self.file,
|
||||
multiprocessing.cpu_count(),
|
||||
include=self.include_elements or None,
|
||||
exclude=self.exclude_elements or None,
|
||||
self.settings, self.file, multiprocessing.cpu_count(), include=products
|
||||
)
|
||||
else:
|
||||
iterator = ifcopenshell.geom.iterator(
|
||||
self.settings, self.file, include=self.include_elements or None, exclude=self.exclude_elements or None
|
||||
)
|
||||
iterator = ifcopenshell.geom.iterator(self.settings, self.file, include=products)
|
||||
valid_file = iterator.initialize()
|
||||
if not valid_file:
|
||||
return False
|
||||
return results
|
||||
checkpoint = time.time()
|
||||
total_created = 0
|
||||
approx_total_products = len(self.include_elements) or len(self.file.by_type("IfcElement"))
|
||||
total = 0
|
||||
start_progress = self.progress
|
||||
progress_range = 85 - start_progress
|
||||
while True:
|
||||
if total_created % 250 == 0:
|
||||
total += 1
|
||||
if total % 250 == 0:
|
||||
print(
|
||||
"{} / ~{} elements processed in {:.2f}s ...".format(
|
||||
total_created, approx_total_products, time.time() - checkpoint
|
||||
"{} ({}%) elements processed in {:.2f}s ...".format(
|
||||
total, iterator.progress(), time.time() - checkpoint
|
||||
)
|
||||
)
|
||||
checkpoint = time.time()
|
||||
if approx_total_products:
|
||||
self.update_progress(((total_created / approx_total_products) * progress_range) + start_progress)
|
||||
#self.update_progress(((total / approx_total_products) * progress_range) + start_progress)
|
||||
shape = iterator.get()
|
||||
if shape:
|
||||
product = self.file.by_id(shape.guid)
|
||||
@@ -628,35 +610,18 @@ class IfcImporter:
|
||||
if shape.context not in ["Body", "Facetation"] and IfcStore.get_element(shape.guid):
|
||||
# We only load a single context, and we prioritise the Body context. See #1290.
|
||||
pass
|
||||
elif product.is_a("IfcAnnotation") and product.ObjectType == "DRAWING":
|
||||
# We have already processed this during the create_annotation step
|
||||
pass
|
||||
else:
|
||||
self.create_product(product, shape)
|
||||
total_created += 1
|
||||
results.add(product)
|
||||
if not iterator.next():
|
||||
break
|
||||
print("Done creating geometry")
|
||||
|
||||
def create_empty_and_2d_elements(self):
|
||||
curve_products = []
|
||||
|
||||
unadded_element_ids = set([e.id() for e in self.elements]) - set(self.added_data.keys())
|
||||
for element_id in unadded_element_ids:
|
||||
element = self.file.by_id(element_id)
|
||||
if element.is_a("IfcPort"):
|
||||
continue
|
||||
if not element.Representation:
|
||||
self.create_product(element)
|
||||
else:
|
||||
curve_products.append(element)
|
||||
if curve_products:
|
||||
self.create_curve_products(curve_products)
|
||||
return results
|
||||
|
||||
def create_annotation(self):
|
||||
self.create_curve_products(self.file.by_type("IfcAnnotation"))
|
||||
|
||||
def create_structural_elements(self):
|
||||
def create_structural_items(self):
|
||||
# Create structural collections
|
||||
self.structural_member_collection = bpy.data.collections.new("Members")
|
||||
self.structural_connection_collection = bpy.data.collections.new("Connections")
|
||||
@@ -695,6 +660,9 @@ class IfcImporter:
|
||||
self.link_element(product, obj)
|
||||
|
||||
def create_curve_products(self, products):
|
||||
results = set()
|
||||
if not products:
|
||||
return results
|
||||
if self.ifc_import_settings.should_use_cpu_multiprocessing:
|
||||
iterator = ifcopenshell.geom.iterator(
|
||||
self.settings_2d, self.file, multiprocessing.cpu_count(), include=products
|
||||
@@ -703,7 +671,7 @@ class IfcImporter:
|
||||
iterator = ifcopenshell.geom.iterator(self.settings_2d, self.file, include=products)
|
||||
valid_file = iterator.initialize()
|
||||
if not valid_file:
|
||||
return False
|
||||
return results
|
||||
checkpoint = time.time()
|
||||
total = 0
|
||||
while True:
|
||||
@@ -713,10 +681,13 @@ class IfcImporter:
|
||||
checkpoint = time.time()
|
||||
shape = iterator.get()
|
||||
if shape:
|
||||
product = self.file.by_id(shape.guid)
|
||||
self.create_product(self.file.by_id(shape.guid), shape)
|
||||
results.add(product)
|
||||
if not iterator.next():
|
||||
break
|
||||
print("Done creating geometry")
|
||||
return results
|
||||
|
||||
def create_product(self, element, shape=None, mesh=None):
|
||||
if element is None:
|
||||
@@ -747,7 +718,7 @@ class IfcImporter:
|
||||
if shape:
|
||||
m = shape.transformation.matrix.data
|
||||
# We use numpy here because Blender mathutils.Matrix is not accurate enough
|
||||
mat = np.matrix(
|
||||
mat = np.array(
|
||||
([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])
|
||||
)
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, mat)
|
||||
@@ -767,7 +738,7 @@ class IfcImporter:
|
||||
def get_representation_item_material_name(self, item):
|
||||
if not item.StyledByItem:
|
||||
return
|
||||
style_ids = [e.id() for e in self.ifc_importer.file.traverse(item.StyledByItem[0]) if e.is_a("IfcSurfaceStyle")]
|
||||
style_ids = [e.id() for e in self.file.traverse(item.StyledByItem[0]) if e.is_a("IfcSurfaceStyle")]
|
||||
return style_ids[0] if style_ids else None
|
||||
|
||||
def create_native_faceted_brep(self, element, mesh_name):
|
||||
@@ -960,15 +931,10 @@ class IfcImporter:
|
||||
return
|
||||
self.openings[element.GlobalId] = obj
|
||||
|
||||
def load_diff(self):
|
||||
if not self.ifc_import_settings.diff_file:
|
||||
return
|
||||
with open(self.ifc_import_settings.diff_file, "r") as file:
|
||||
self.diff = json.load(file)
|
||||
|
||||
def load_file(self):
|
||||
self.ifc_import_settings.logger.info("loading file %s", self.ifc_import_settings.input_file)
|
||||
bpy.context.scene.BIMProperties.ifc_file = self.ifc_import_settings.input_file
|
||||
if not bpy.context.scene.BIMProperties.ifc_file:
|
||||
bpy.context.scene.BIMProperties.ifc_file = self.ifc_import_settings.input_file
|
||||
self.file = IfcStore.get_file()
|
||||
|
||||
def calculate_unit_scale(self):
|
||||
@@ -1004,10 +970,7 @@ class IfcImporter:
|
||||
)
|
||||
|
||||
def create_project(self):
|
||||
if self.file.schema == "IFC2X3":
|
||||
self.project = {"ifc": self.file.by_type("IfcProject")[0]}
|
||||
else:
|
||||
self.project = {"ifc": self.file.by_type("IfcContext")[0]}
|
||||
self.project = {"ifc": self.file.by_type("IfcProject")[0]}
|
||||
self.project["blender"] = bpy.data.collections.new(
|
||||
"{}/{}".format(self.project["ifc"].is_a(), self.project["ifc"].Name)
|
||||
)
|
||||
@@ -1015,66 +978,69 @@ class IfcImporter:
|
||||
if obj:
|
||||
self.project["blender"].objects.link(obj)
|
||||
|
||||
def create_spatial_hierarchy(self):
|
||||
if self.project["ifc"].IsDecomposedBy:
|
||||
for rel_aggregate in self.project["ifc"].IsDecomposedBy:
|
||||
self.add_related_objects(self.project["blender"], rel_aggregate.RelatedObjects)
|
||||
def create_collections(self):
|
||||
if self.ifc_import_settings.collection_mode == "DECOMPOSITION":
|
||||
self.create_decomposition_collections()
|
||||
elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION":
|
||||
self.create_spatial_decomposition_collections()
|
||||
|
||||
def add_related_objects(self, parent, related_objects):
|
||||
def create_decomposition_collections(self):
|
||||
self.create_spatial_decomposition_collections()
|
||||
self.create_aggregate_collections()
|
||||
|
||||
def create_spatial_decomposition_collections(self):
|
||||
for rel_aggregate in self.project["ifc"].IsDecomposedBy or []:
|
||||
self.create_spatial_decomposition_collection(self.project["blender"], rel_aggregate.RelatedObjects)
|
||||
self.create_type_collection()
|
||||
|
||||
def create_type_collection(self):
|
||||
for collection in self.project["blender"].children:
|
||||
if collection.name == "Types":
|
||||
self.type_collection = collection
|
||||
break
|
||||
if not self.type_collection:
|
||||
self.type_collection = bpy.data.collections.new("Types")
|
||||
self.project["blender"].children.link(self.type_collection)
|
||||
|
||||
def create_spatial_decomposition_collection(self, parent, related_objects):
|
||||
for element in related_objects:
|
||||
if element not in self.spatial_elements:
|
||||
continue
|
||||
global_id = element.GlobalId
|
||||
collection = bpy.data.collections.new(self.get_name(element))
|
||||
self.spatial_structure_elements[global_id] = {"blender": collection}
|
||||
self.collections[global_id] = collection
|
||||
parent.children.link(collection)
|
||||
obj = self.create_product(element)
|
||||
if obj:
|
||||
self.spatial_structure_elements[global_id]["blender_obj"] = obj
|
||||
collection.objects.link(obj)
|
||||
if element.IsDecomposedBy:
|
||||
for rel_aggregate in element.IsDecomposedBy:
|
||||
self.add_related_objects(collection, rel_aggregate.RelatedObjects)
|
||||
self.create_spatial_decomposition_collection(collection, rel_aggregate.RelatedObjects)
|
||||
|
||||
def create_aggregates(self):
|
||||
if self.filter_mode in ["WHITELIST", "BLACKLIST"]:
|
||||
rel_aggregates = [e.IsDecomposedBy[0].RelatingObject for e in self.elements if e.IsDecomposedBy]
|
||||
def create_aggregate_collections(self):
|
||||
if self.ifc_import_settings.has_filter:
|
||||
rel_aggregates = [e.IsDecomposedBy[0] for e in self.elements if e.IsDecomposedBy]
|
||||
else:
|
||||
rel_aggregates = [a for a in self.file.by_type("IfcRelAggregates") if a.RelatingObject.is_a("IfcElement")]
|
||||
|
||||
if len(rel_aggregates) > 10000:
|
||||
# More than 10,000 collections makes Blender unhappy
|
||||
print("Falling back to SPATIAL_DECOMPOSITION collection mode")
|
||||
print("Skipping aggregate collections for performance.")
|
||||
self.ifc_import_settings.collection_mode = "SPATIAL_DECOMPOSITION"
|
||||
else:
|
||||
for rel_aggregate in rel_aggregates:
|
||||
self.create_aggregate(rel_aggregate)
|
||||
return
|
||||
|
||||
def create_aggregate_tree(self):
|
||||
for aggregate in self.aggregates.values():
|
||||
if aggregate["container"].is_a("IfcSpatialStructureElement"):
|
||||
self.spatial_structure_elements[aggregate["container"].GlobalId]["blender"].children.link(
|
||||
aggregate["blender"]
|
||||
)
|
||||
else:
|
||||
self.aggregates[aggregate["container"].GlobalId]["blender"].children.link(aggregate["blender"])
|
||||
aggregates = {}
|
||||
for rel_aggregate in rel_aggregates:
|
||||
element = rel_aggregate.RelatingObject
|
||||
collection = bpy.data.collections.new(self.get_name(element))
|
||||
aggregates[element.GlobalId] = {"element": element, "collection": collection}
|
||||
self.collections[element.GlobalId] = collection
|
||||
|
||||
def create_aggregate(self, rel_aggregate):
|
||||
element = rel_aggregate.RelatingObject
|
||||
obj = bpy.data.objects.new("{}/{}".format(element.is_a(), element.Name), None)
|
||||
obj.matrix_world = self.apply_blender_offset_to_matrix_world(obj, self.get_element_matrix(element))
|
||||
self.link_element(element, obj)
|
||||
collection = bpy.data.collections.new(obj.name)
|
||||
collection.objects.link(obj)
|
||||
self.aggregates[element.GlobalId] = {
|
||||
"blender": collection,
|
||||
"blender_obj": obj,
|
||||
"container": self.get_aggregate_container(element),
|
||||
}
|
||||
|
||||
def get_aggregate_container(self, element):
|
||||
if hasattr(element, "ContainedInStructure") and element.ContainedInStructure:
|
||||
container = element.ContainedInStructure[0].RelatingStructure
|
||||
elif hasattr(element, "Decomposes") and element.Decomposes:
|
||||
container = element.Decomposes[0].RelatingObject
|
||||
return container
|
||||
for global_id, aggregate in aggregates.items():
|
||||
parent = ifcopenshell.util.element.get_aggregate(aggregate["element"])
|
||||
if parent:
|
||||
self.collections[parent.GlobalId].children.link(aggregate["collection"])
|
||||
continue
|
||||
parent = ifcopenshell.util.element.get_container(aggregate["element"])
|
||||
if parent:
|
||||
self.collections[parent.GlobalId].children.link(aggregate["collection"])
|
||||
|
||||
def create_openings_collection(self):
|
||||
self.opening_collection = bpy.data.collections.new("IfcOpeningElements")
|
||||
@@ -1135,86 +1101,41 @@ class IfcImporter:
|
||||
def get_name(self, element):
|
||||
return "{}/{}".format(element.is_a(), element.Name)
|
||||
|
||||
def purge_diff(self):
|
||||
if not self.diff:
|
||||
return
|
||||
objects_to_purge = []
|
||||
for obj in bpy.data.objects:
|
||||
if "GlobalId" not in obj.BIMObjectProperties.attributes:
|
||||
continue
|
||||
global_id = obj.BIMObjectProperties.attributes["GlobalId"].string_value
|
||||
if global_id in self.diff["deleted"] or global_id in self.diff["changed"].keys():
|
||||
objects_to_purge.append(obj)
|
||||
bpy.ops.object.delete({"selected_objects": objects_to_purge})
|
||||
|
||||
def place_objects_in_spatial_tree(self):
|
||||
def place_objects_in_collections(self):
|
||||
for ifc_definition_id, obj in self.added_data.items():
|
||||
if isinstance(obj, bpy.types.Object):
|
||||
self.place_object_in_spatial_tree(self.file.by_id(ifc_definition_id), obj)
|
||||
self.place_object_in_collection(self.file.by_id(ifc_definition_id), obj)
|
||||
|
||||
def place_object_in_spatial_tree(self, element, obj):
|
||||
if element.is_a() in ["IfcProject", "IfcProjectLibrary"]:
|
||||
def place_object_in_collection(self, element, obj):
|
||||
if self.ifc_import_settings.collection_mode == "DECOMPOSITION":
|
||||
self.place_object_in_decomposition_collection(element, obj)
|
||||
elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION":
|
||||
self.place_object_in_spatial_decomposition_collection(element, obj)
|
||||
|
||||
def place_object_in_decomposition_collection(self, element, obj):
|
||||
if element.is_a("IfcProject"):
|
||||
return
|
||||
elif element.GlobalId in self.collections:
|
||||
return self.collections[element.GlobalId].objects.link(obj)
|
||||
elif getattr(element, "Decomposes", None):
|
||||
aggregate = ifcopenshell.util.element.get_aggregate(element)
|
||||
return self.collections[aggregate.GlobalId].objects.link(obj)
|
||||
else:
|
||||
return self.place_object_in_spatial_decomposition_collection(element, obj)
|
||||
|
||||
def place_object_in_spatial_decomposition_collection(self, element, obj):
|
||||
if element.is_a("IfcProject"):
|
||||
return
|
||||
elif element.GlobalId in self.collections:
|
||||
return self.collections[element.GlobalId].objects.link(obj)
|
||||
elif element.is_a("IfcTypeObject"):
|
||||
self.type_collection.objects.link(obj)
|
||||
elif element.GlobalId in self.aggregates:
|
||||
return
|
||||
elif element.GlobalId in self.spatial_structure_elements:
|
||||
if not obj.data:
|
||||
return
|
||||
# Since spatial structure elements are generated as empties, we'll replace it with the representation
|
||||
spatial_obj = self.spatial_structure_elements[element.GlobalId]["blender_obj"]
|
||||
spatial_collection = self.spatial_structure_elements[element.GlobalId]["blender"]
|
||||
spatial_name = spatial_obj.name
|
||||
spatial_collection.objects.link(obj)
|
||||
bpy.data.objects.remove(spatial_obj)
|
||||
obj.name = spatial_name
|
||||
elif (
|
||||
hasattr(element, "ContainedInStructure")
|
||||
and element.ContainedInStructure
|
||||
and element.ContainedInStructure[0].RelatingStructure
|
||||
):
|
||||
container = element.ContainedInStructure[0].RelatingStructure
|
||||
if element.is_a("IfcGrid"):
|
||||
grid_collection = bpy.data.collections.get(obj.name)
|
||||
if grid_collection: # Just in case we ran into invalid grids from Revit
|
||||
self.spatial_structure_elements[container.GlobalId]["blender"].children.link(grid_collection)
|
||||
grid_collection.objects.link(obj)
|
||||
else:
|
||||
self.spatial_structure_elements[container.GlobalId]["blender"].objects.link(obj)
|
||||
elif hasattr(element, "Decomposes") and element.Decomposes:
|
||||
collection = None
|
||||
if element.Decomposes[0].RelatingObject.is_a("IfcProject"):
|
||||
collection = self.project["blender"]
|
||||
elif element.Decomposes[0].RelatingObject.is_a("IfcSpatialStructureElement"):
|
||||
if element.is_a("IfcSpatialStructureElement"):
|
||||
global_id = element.GlobalId
|
||||
if global_id in self.spatial_structure_elements:
|
||||
if (
|
||||
element.is_a("IfcSpatialStructureElement")
|
||||
and "blender_obj" in self.spatial_structure_elements[global_id]
|
||||
):
|
||||
bpy.data.objects.remove(self.spatial_structure_elements[global_id]["blender_obj"])
|
||||
collection = self.spatial_structure_elements[global_id]["blender"]
|
||||
elif self.ifc_import_settings.collection_mode == "SPATIAL_DECOMPOSITION":
|
||||
# TODO: refactor this to a more holistic collection mode feature
|
||||
return self.place_object_in_spatial_tree(element.Decomposes[0].RelatingObject, obj)
|
||||
else:
|
||||
aggregate = element.Decomposes[0].RelatingObject
|
||||
aggregate_data = self.aggregates.get(aggregate.GlobalId)
|
||||
if not aggregate_data:
|
||||
return self.place_object_in_spatial_tree(aggregate, obj)
|
||||
collection = aggregate_data["blender"]
|
||||
if collection:
|
||||
collection.objects.link(obj)
|
||||
else:
|
||||
self.ifc_import_settings.logger.error("An element could not be placed in the spatial tree %s", element)
|
||||
return self.type_collection.objects.link(obj)
|
||||
elif element.is_a("IfcOpeningElement"):
|
||||
self.opening_collection.objects.link(obj)
|
||||
return self.opening_collection.objects.link(obj)
|
||||
elif element.is_a("IfcStructuralMember"):
|
||||
self.structural_member_collection.objects.link(obj)
|
||||
return self.structural_member_collection.objects.link(obj)
|
||||
elif element.is_a("IfcStructuralConnection"):
|
||||
self.structural_connection_collection.objects.link(obj)
|
||||
return self.structural_connection_collection.objects.link(obj)
|
||||
elif element.is_a("IfcAnnotation") and element.ObjectType == "DRAWING":
|
||||
view_collection = bpy.data.collections.get("Views")
|
||||
if not view_collection:
|
||||
@@ -1224,6 +1145,18 @@ class IfcImporter:
|
||||
drawing_collection = bpy.data.collections.new("IfcGroup/" + group.Name)
|
||||
view_collection.children.link(drawing_collection)
|
||||
drawing_collection.objects.link(obj)
|
||||
return
|
||||
|
||||
container = ifcopenshell.util.element.get_container(element)
|
||||
if container:
|
||||
if element.is_a("IfcGrid"): # TODO: refactor into a more holistic collection mode feature
|
||||
grid_collection = bpy.data.collections.get(obj.name)
|
||||
if grid_collection: # Just in case we run into invalid grids from Revit
|
||||
self.collections[container.GlobalId].children.link(grid_collection)
|
||||
grid_collection.objects.link(obj)
|
||||
else:
|
||||
self.collections[container.GlobalId].objects.link(obj)
|
||||
|
||||
else:
|
||||
self.ifc_import_settings.logger.warning("Warning: this object is outside the spatial hierarchy %s", element)
|
||||
bpy.context.scene.collection.objects.link(obj)
|
||||
@@ -1344,7 +1277,9 @@ class IfcImporter:
|
||||
if "TargetView" in pset:
|
||||
camera.BIMCameraProperties.target_view = pset["TargetView"]
|
||||
if "Scale" in pset:
|
||||
valid_scales = [i[0] for i in getDiagramScales(None, None) if pset["Scale"] == i[0].split("|")[-1]]
|
||||
valid_scales = [
|
||||
i[0] for i in get_diagram_scales(None, bpy.context) if pset["Scale"] == i[0].split("|")[-1]
|
||||
]
|
||||
if valid_scales:
|
||||
camera.BIMCameraProperties.diagram_scale = valid_scales[0]
|
||||
else:
|
||||
@@ -1391,13 +1326,7 @@ class IfcImporter:
|
||||
num_vertex_indices = len(geometry.faces)
|
||||
|
||||
mesh.vertices.add(num_vertices)
|
||||
if self.ifc_import_settings.should_offset_model:
|
||||
# Potentially, there is a smarter way to do this. See #1047
|
||||
v_index = cycle((0, 1, 2))
|
||||
verts = [v + self.ifc_import_settings.model_offset_coordinates[next(v_index)] for v in verts]
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
else:
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
mesh.vertices.foreach_set("co", verts)
|
||||
mesh.loops.add(num_vertex_indices)
|
||||
mesh.loops.foreach_set("vertex_index", geometry.faces)
|
||||
mesh.polygons.add(num_loops)
|
||||
@@ -1472,7 +1401,6 @@ class IfcImportSettings:
|
||||
self.logger = None
|
||||
self.input_file = None
|
||||
self.diff_file = None
|
||||
self.should_auto_set_workarounds = True
|
||||
self.should_use_cpu_multiprocessing = True
|
||||
self.should_merge_by_class = False
|
||||
self.should_merge_by_material = False
|
||||
@@ -1482,13 +1410,12 @@ class IfcImportSettings:
|
||||
self.angular_tolerance = 0.5
|
||||
self.should_offset_model = False
|
||||
self.model_offset_coordinates = (0, 0, 0)
|
||||
self.ifc_import_filter = "NONE"
|
||||
self.ifc_selector = ""
|
||||
self.has_filter = None
|
||||
self.elements = ""
|
||||
self.collection_mode = "DECOMPOSITION"
|
||||
|
||||
@staticmethod
|
||||
def factory(context, input_file, logger):
|
||||
scene_bim = context.scene.BIMProperties
|
||||
scene_diff = context.scene.DiffProperties
|
||||
settings = IfcImportSettings()
|
||||
settings.input_file = input_file
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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/>.
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -56,7 +55,9 @@ class BIM_PT_aggregate(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
row.prop(props, "relating_object", text="")
|
||||
if props.relating_object:
|
||||
row.operator("bim.assign_object", icon="CHECKMARK", text="").relating_object = props.relating_object.name
|
||||
row.operator(
|
||||
"bim.assign_object", icon="CHECKMARK", text=""
|
||||
).relating_object = props.relating_object.name
|
||||
row.operator("bim.disable_editing_aggregate", icon="CANCEL", text="")
|
||||
else:
|
||||
row = self.layout.row(align=True)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -119,9 +118,7 @@ class EditAttributes(bpy.types.Operator):
|
||||
elif attribute["type"] == "enum":
|
||||
attributes[attribute["name"]] = blender_attribute.enum_value
|
||||
product = self.file.by_id(oprops.ifc_definition_id)
|
||||
ifcopenshell.api.run(
|
||||
"attribute.edit_attributes", self.file, **{"product": product, "attributes": attributes}
|
||||
)
|
||||
ifcopenshell.api.run("attribute.edit_attributes", self.file, **{"product": product, "attributes": attributes})
|
||||
Data.load(IfcStore.get_file(), oprops.ifc_definition_id)
|
||||
bpy.ops.bim.disable_editing_attributes(obj=obj.name, obj_type=self.obj_type)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -32,6 +31,7 @@ from bpy.props import (
|
||||
CollectionProperty,
|
||||
)
|
||||
|
||||
|
||||
class BIMAttributeProperties(PropertyGroup):
|
||||
attributes: CollectionProperty(name="Attributes", type=Attribute)
|
||||
is_editing_attributes: BoolProperty(name="Is Editing Attributes")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -68,6 +67,7 @@ class AuginCreateNewModel(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
import boto3
|
||||
from botocore.config import Config
|
||||
|
||||
props = context.scene.AuginProperties
|
||||
|
||||
# Create project
|
||||
@@ -135,7 +135,6 @@ class AuginCreateNewModel(bpy.types.Operator):
|
||||
client.upload_file(context.scene.BIMProperties.ifc_file, result["s3_bucket"], result["model_path"])
|
||||
client.upload_file(thumb_path, result["s3_bucket"], result["thumb_path"])
|
||||
|
||||
|
||||
# Notify done
|
||||
url = "https://server.auge.pro.br/API/v3/augin_rest.php/files_uploaded"
|
||||
payload = {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -20,6 +19,7 @@
|
||||
import bcf
|
||||
import bcf.v2.bcfxml
|
||||
|
||||
|
||||
class BcfStore:
|
||||
bcfxml = None
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -31,6 +30,7 @@ from blenderbim.bim.ifc import IfcStore
|
||||
from math import radians, degrees, atan, tan, cos, sin
|
||||
from mathutils import Vector, Matrix, Euler, geometry
|
||||
|
||||
|
||||
class NewBcfProject(bpy.types.Operator):
|
||||
bl_idname = "bim.new_bcf_project"
|
||||
bl_label = "New BCF Project"
|
||||
@@ -79,7 +79,7 @@ class LoadBcfTopics(bpy.types.Operator):
|
||||
context.scene.BCFProperties.topics.clear()
|
||||
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)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic_guid, topic_index=index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class LoadBcfTopic(bpy.types.Operator):
|
||||
"modified_author": topic.modified_author,
|
||||
"assigned_to": topic.assigned_to,
|
||||
"due_date": topic.due_date,
|
||||
"description": topic.description
|
||||
"description": topic.description,
|
||||
}
|
||||
for key, value in data_map.items():
|
||||
if value is not None:
|
||||
@@ -128,7 +128,7 @@ class LoadBcfTopic(bpy.types.Operator):
|
||||
"type": topic.bim_snippet.snippet_type,
|
||||
"is_external": topic.bim_snippet.is_external,
|
||||
"reference": topic.bim_snippet.reference,
|
||||
"schema": topic.bim_snippet.reference_schema
|
||||
"schema": topic.bim_snippet.reference_schema,
|
||||
}
|
||||
for key, value in data_map.items():
|
||||
if value is not None:
|
||||
@@ -141,7 +141,7 @@ class LoadBcfTopic(bpy.types.Operator):
|
||||
"reference": doc.referenced_document,
|
||||
"description": doc.description,
|
||||
"guid": doc.guid,
|
||||
"is_external": doc.is_external
|
||||
"is_external": doc.is_external,
|
||||
}
|
||||
for key, value in data_map.items():
|
||||
if value is not None:
|
||||
@@ -152,7 +152,7 @@ class LoadBcfTopic(bpy.types.Operator):
|
||||
new_related_topic = new.related_topics.add()
|
||||
new_related_topic.name = related_topic.guid
|
||||
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid=topic.guid)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -287,11 +287,12 @@ class AddBcfBimSnippet(bpy.types.Operator):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return all((getattr(context.scene.BCFProperties, attr, False) for attr in (
|
||||
"bim_snippet_reference",
|
||||
"bim_snippet_schema",
|
||||
"bim_snippet_type"
|
||||
)))
|
||||
return all(
|
||||
(
|
||||
getattr(context.scene.BCFProperties, attr, False)
|
||||
for attr in ("bim_snippet_reference", "bim_snippet_schema", "bim_snippet_type")
|
||||
)
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
@@ -303,7 +304,7 @@ class AddBcfBimSnippet(bpy.types.Operator):
|
||||
bim_snippet.reference_schema = props.bim_snippet_schema
|
||||
bim_snippet.snippet_type = props.bim_snippet_type
|
||||
bcfxml.add_bim_snippet(topic, bim_snippet)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic.guid, topic_index=props.active_topic_index)
|
||||
bim_snippet.reference = ""
|
||||
bim_snippet.reference_schema = ""
|
||||
bim_snippet.snippet_type = ""
|
||||
@@ -316,7 +317,7 @@ class AddBcfRelatedTopic(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
def poll(cls, context):
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
props = context.scene.BCFProperties
|
||||
blender_topic = props.active_topic
|
||||
@@ -347,7 +348,7 @@ class AddBcfRelatedTopic(bpy.types.Operator):
|
||||
topic = bcfxml.topics[blender_topic.name]
|
||||
topic.related_topics.append(related_topic)
|
||||
bcfxml.edit_topic(topic)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic.guid, topic_index=props.active_topic_index)
|
||||
props.related_topic = ""
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -516,7 +517,7 @@ class AddBcfReferenceLink(bpy.types.Operator):
|
||||
topic = bcfxml.topics[blender_topic.name]
|
||||
topic.reference_links.append(props.reference_link)
|
||||
bcfxml.edit_topic(topic)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic.guid, topic_index=props.active_topic_index)
|
||||
props.reference_link = ""
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -539,7 +540,7 @@ class AddBcfDocumentReference(bpy.types.Operator):
|
||||
document_reference.referenced_document = props.document_reference
|
||||
document_reference.description = props.document_reference_description or None
|
||||
bcfxml.add_document_reference(topic, document_reference)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic.guid, topic_index=props.active_topic_index)
|
||||
props.document_reference = ""
|
||||
props.document_reference_description = ""
|
||||
return {"FINISHED"}
|
||||
@@ -668,7 +669,7 @@ class RemoveBcfDocumentReference(bpy.types.Operator):
|
||||
blender_topic = props.active_topic
|
||||
topic = bcfxml.topics[blender_topic.name]
|
||||
bcfxml.delete_document_reference(topic, self.index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic.guid, topic_index=props.active_topic_index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -685,7 +686,7 @@ class RemoveBcfRelatedTopic(bpy.types.Operator):
|
||||
topic = bcfxml.topics[blender_topic.name]
|
||||
del topic.related_topics[self.index]
|
||||
bcfxml.edit_topic(topic)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid = topic.guid, topic_index = props.active_topic_index)
|
||||
bpy.ops.bim.load_bcf_topic(topic_guid=topic.guid, topic_index=props.active_topic_index)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -701,7 +702,7 @@ class RemoveBcfComment(bpy.types.Operator):
|
||||
blender_topic = props.active_topic
|
||||
topic = bcfxml.topics[blender_topic.name]
|
||||
bcfxml.delete_comment(self.comment_guid, topic)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid=topic.guid)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -720,7 +721,7 @@ class EditBcfComment(bpy.types.Operator):
|
||||
comment = topic.comments[self.comment_guid]
|
||||
comment.comment = blender_comment.comment
|
||||
bcfxml.edit_comment(comment, topic)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid=topic.guid)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -750,7 +751,7 @@ class AddBcfComment(bpy.types.Operator):
|
||||
comment.viewpoint = bcf.v2.data.Viewpoint()
|
||||
comment.viewpoint.guid = blender_topic.viewpoints
|
||||
bcfxml.add_comment(topic, comment)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid = topic.guid)
|
||||
bpy.ops.bim.load_bcf_comments(topic_guid=topic.guid)
|
||||
props.comment = ""
|
||||
props.has_related_viewpoint = False
|
||||
return {"FINISHED"}
|
||||
@@ -787,14 +788,12 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
cam_width = context.scene.render.resolution_x
|
||||
cam_height = context.scene.render.resolution_y
|
||||
cam_aspect = cam_width / cam_height
|
||||
|
||||
|
||||
if viewpoint.snapshot:
|
||||
obj.data.show_background_images = True
|
||||
obj.data.background_images.clear()
|
||||
background = obj.data.background_images.new()
|
||||
background.image = bpy.data.images.load(
|
||||
os.path.join(bcfxml.filepath, topic.guid, viewpoint.snapshot)
|
||||
)
|
||||
background.image = bpy.data.images.load(os.path.join(bcfxml.filepath, topic.guid, viewpoint.snapshot))
|
||||
src_width = background.image.size[0]
|
||||
src_height = background.image.size[1]
|
||||
src_aspect = src_width / src_height
|
||||
@@ -839,19 +838,25 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
obj.data.angle = radians(camera.field_of_view)
|
||||
else:
|
||||
# https://blender.stackexchange.com/questions/23431/how-to-set-camera-horizontal-and-vertical-fov
|
||||
obj.data.angle = 2 * atan((0.5 * cam_height) / (0.5 * cam_width / tan(radians(camera.field_of_view) / 2)))
|
||||
obj.data.angle = 2 * atan(
|
||||
(0.5 * cam_height) / (0.5 * cam_width / tan(radians(camera.field_of_view) / 2))
|
||||
)
|
||||
|
||||
z_axis = Vector((-camera.camera_direction.x, -camera.camera_direction.y, -camera.camera_direction.z)).normalized()
|
||||
z_axis = Vector(
|
||||
(-camera.camera_direction.x, -camera.camera_direction.y, -camera.camera_direction.z)
|
||||
).normalized()
|
||||
y_axis = Vector((camera.camera_up_vector.x, camera.camera_up_vector.y, camera.camera_up_vector.z)).normalized()
|
||||
x_axis = y_axis.cross(z_axis).normalized()
|
||||
rotation = Matrix((x_axis, y_axis, z_axis))
|
||||
rotation.invert()
|
||||
matrix = np.matrix((
|
||||
[x_axis[0], y_axis[0], z_axis[0], camera.camera_view_point.x],
|
||||
[x_axis[1], y_axis[1], z_axis[1], camera.camera_view_point.y],
|
||||
[x_axis[2], y_axis[2], z_axis[2], camera.camera_view_point.z],
|
||||
[0, 0, 0, 1],
|
||||
))
|
||||
matrix = np.matrix(
|
||||
(
|
||||
[x_axis[0], y_axis[0], z_axis[0], camera.camera_view_point.x],
|
||||
[x_axis[1], y_axis[1], z_axis[1], camera.camera_view_point.y],
|
||||
[x_axis[2], y_axis[2], z_axis[2], camera.camera_view_point.z],
|
||||
[0, 0, 0, 1],
|
||||
)
|
||||
)
|
||||
props = context.scene.BIMGeoreferenceProperties
|
||||
if props.has_blender_offset:
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file)
|
||||
@@ -961,7 +966,9 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
stroke.points.add(len(viewpoint.lines) * 2)
|
||||
coords = []
|
||||
for l in viewpoint.lines:
|
||||
coords.extend([l.start_point.x, l.start_point.y, l.start_point.z, l.end_point.x, l.end_point.y, l.end_point.z])
|
||||
coords.extend(
|
||||
[l.start_point.x, l.start_point.y, l.start_point.z, l.end_point.x, l.end_point.y, l.end_point.z]
|
||||
)
|
||||
stroke.points.foreach_set("co", coords)
|
||||
|
||||
def create_clipping_planes(self, viewpoint):
|
||||
@@ -1025,6 +1032,7 @@ class ActivateBcfViewpoint(bpy.types.Operator):
|
||||
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):
|
||||
bl_idname = "bim.open_bcf_reference_link"
|
||||
bl_label = "Open BCF Reference Link"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -73,7 +72,7 @@ def updateBcfTopicIsEditable(self, context):
|
||||
|
||||
def updateBcfCommentIsEditable(self, context):
|
||||
if context.scene.BCFProperties.is_loaded and not self.is_editable:
|
||||
bpy.ops.bim.edit_bcf_comment(comment_guid = self.name)
|
||||
bpy.ops.bim.edit_bcf_comment(comment_guid=self.name)
|
||||
|
||||
|
||||
def refreshBcfTopic(self, context):
|
||||
@@ -91,7 +90,7 @@ class BcfLabel(PropertyGroup):
|
||||
|
||||
def getBcfViewpoints(self, context, force_update=False):
|
||||
global bcfviewpoints_enum
|
||||
if bcfviewpoints_enum is None or force_update: # Retrieving Viewpoints is slow. Make sure we only do when needed
|
||||
if bcfviewpoints_enum is None or force_update: # Retrieving Viewpoints is slow. Make sure we only do when needed
|
||||
bcfviewpoints_enum = []
|
||||
props = context.scene.BCFProperties
|
||||
bcfxml = bcfstore.BcfStore.get_bcfxml()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -22,6 +21,7 @@ import bpy
|
||||
from . import bcfstore
|
||||
from bpy.types import Panel
|
||||
|
||||
|
||||
class BIM_PT_bcf(Panel):
|
||||
bl_label = "BCF Project"
|
||||
bl_idname = "BIM_PT_bcf"
|
||||
@@ -231,12 +231,12 @@ class BIM_PT_bcf_metadata(Panel):
|
||||
row.operator("bim.add_bcf_document_reference")
|
||||
|
||||
layout.label(text="Related Topics:")
|
||||
for index, related_topic in enumerate(topic.related_topics):
|
||||
for index, related_topic in enumerate(topic.related_topics):
|
||||
try:
|
||||
row = layout.row(align=True)
|
||||
op = row.operator(
|
||||
"bim.view_bcf_topic",
|
||||
text=f"Select {bcfxml.topics[related_topic.name.lower()].title}")
|
||||
"bim.view_bcf_topic", text=f"Select {bcfxml.topics[related_topic.name.lower()].title}"
|
||||
)
|
||||
op.topic_guid = related_topic.name
|
||||
row.operator("bim.remove_bcf_related_topic", icon="X", text="").index = index
|
||||
except KeyError:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -21,7 +20,6 @@ import os
|
||||
import bpy
|
||||
import tempfile
|
||||
import webbrowser
|
||||
import ifcopenshell
|
||||
|
||||
try:
|
||||
import bimtester
|
||||
@@ -31,7 +29,6 @@ except:
|
||||
print("Failed to load BIMTester. Try disabling other add-ons, in particular Blender-OSM. See bug #1318.")
|
||||
|
||||
from pathlib import Path
|
||||
from itertools import cycle
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
@@ -42,7 +39,7 @@ class ExecuteBIMTester(bpy.types.Operator):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
return props.ifc_file and props.feature
|
||||
return (props.ifc_file or props.should_load_from_memory) and props.feature
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BimTesterProperties
|
||||
@@ -75,10 +72,6 @@ class BIMTesterPurge(bpy.types.Operator):
|
||||
bl_label = "Purge Tests"
|
||||
|
||||
def execute(self, context):
|
||||
filename = os.path.join(
|
||||
context.scene.BimTesterProperties.features_dir,
|
||||
context.scene.BimTesterProperties.features_file + ".feature",
|
||||
)
|
||||
cwd = os.getcwd()
|
||||
os.chdir(context.scene.BimTesterProperties.features_dir)
|
||||
bimtester.clean.TestPurger().purge()
|
||||
@@ -243,19 +236,3 @@ class QAHelper:
|
||||
is_in_scenario = False
|
||||
destination.write(source_line)
|
||||
os.remove(filename + "~")
|
||||
|
||||
|
||||
colour_list = [
|
||||
(0.651, 0.81, 0.892, 1),
|
||||
(0.121, 0.471, 0.706, 1),
|
||||
(0.699, 0.876, 0.54, 1),
|
||||
(0.199, 0.629, 0.174, 1),
|
||||
(0.983, 0.605, 0.602, 1),
|
||||
(0.89, 0.101, 0.112, 1),
|
||||
(0.989, 0.751, 0.427, 1),
|
||||
(0.986, 0.497, 0.1, 1),
|
||||
(0.792, 0.699, 0.839, 1),
|
||||
(0.414, 0.239, 0.603, 1),
|
||||
(0.993, 0.999, 0.6, 1),
|
||||
(0.693, 0.349, 0.157, 1),
|
||||
]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -20,9 +19,7 @@
|
||||
import bpy
|
||||
from . import ui
|
||||
|
||||
classes = (
|
||||
ui.BIM_PT_boundary,
|
||||
)
|
||||
classes = (ui.BIM_PT_boundary,)
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -232,9 +231,7 @@ class ExecuteIfcClash(bpy.types.Operator):
|
||||
context.scene.render.resolution_x = 480
|
||||
context.scene.render.resolution_y = 270
|
||||
context.scene.render.image_settings.file_format = "PNG"
|
||||
context.scene.render.filepath = os.path.join(
|
||||
context.scene.BIMProperties.data_dir, "snapshot.png"
|
||||
)
|
||||
context.scene.render.filepath = os.path.join(context.scene.BIMProperties.data_dir, "snapshot.png")
|
||||
bpy.ops.render.opengl(write_still=True)
|
||||
return context.scene.render.filepath
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -76,6 +75,7 @@ class EnableEditingClassification(bpy.types.Operator):
|
||||
new.name = attribute.name()
|
||||
new.is_null = classification_data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = "string"
|
||||
if attribute.name() == "ReferenceTokens":
|
||||
new.string_value = "" if new.is_null else json.dumps(classification_data[attribute.name()])
|
||||
else:
|
||||
@@ -162,6 +162,7 @@ class EnableEditingClassificationReference(bpy.types.Operator):
|
||||
new.name = attribute.name()
|
||||
new.is_null = reference_data[attribute.name()] is None
|
||||
new.is_optional = attribute.optional()
|
||||
new.data_type = "string"
|
||||
new.string_value = "" if new.is_null else reference_data[attribute.name()]
|
||||
props.active_reference_id = self.reference
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -69,13 +68,14 @@ class ExecuteIfcCobie(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
from cobie import IfcCobieParser
|
||||
|
||||
props = context.scene.COBieProperties
|
||||
|
||||
if props.should_load_from_memory:
|
||||
output_dir = tempfile.gettempdir()
|
||||
else:
|
||||
output_dir = os.path.dirname(props.cobie_ifc_file)
|
||||
|
||||
output_dir = os.path.dirname(props.cobie_ifc_file)
|
||||
|
||||
output = os.path.join(output_dir, "output")
|
||||
logger = logging.getLogger("IFCtoCOBie")
|
||||
fh = logging.FileHandler(os.path.join(output_dir, "cobie.log"))
|
||||
@@ -92,10 +92,10 @@ class ExecuteIfcCobie(bpy.types.Operator):
|
||||
parser = IfcCobieParser(logger, selector)
|
||||
|
||||
ifc_file = IfcStore.get_file()
|
||||
|
||||
|
||||
if not (ifc_file and props.should_load_from_memory):
|
||||
ifc_file = props.cobie_ifc_file
|
||||
|
||||
|
||||
parser.parse(
|
||||
ifc_file,
|
||||
props.cobie_types,
|
||||
@@ -122,4 +122,3 @@ class ExecuteIfcCobie(bpy.types.Operator):
|
||||
webbrowser.open("file://" + output_dir)
|
||||
webbrowser.open("file://" + output_dir + "/cobie.log")
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -37,4 +36,3 @@ class COBieProperties(PropertyGroup):
|
||||
cobie_components: StringProperty(default=".COBie", name="COBie Components")
|
||||
cobie_json_file: StringProperty(default="", name="COBie JSON File")
|
||||
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -36,11 +35,10 @@ class BIM_PT_cobie(Panel):
|
||||
scene = context.scene
|
||||
props = scene.COBieProperties
|
||||
|
||||
|
||||
if IfcStore.get_file():
|
||||
if IfcStore.get_file():
|
||||
row = layout.row()
|
||||
row.prop(props, "should_load_from_memory")
|
||||
|
||||
|
||||
if not IfcStore.get_file() or not props.should_load_from_memory:
|
||||
row = layout.row(align=True)
|
||||
row.prop(props, "cobie_ifc_file")
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -187,17 +186,21 @@ class AssignConstraint(bpy.types.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"constraint": self.file.by_id(self.constraint),
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||
for obj in objs:
|
||||
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if not obj_id:
|
||||
continue
|
||||
ifcopenshell.api.run(
|
||||
"constraint.assign_constraint",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj_id),
|
||||
"constraint": self.file.by_id(self.constraint),
|
||||
}
|
||||
)
|
||||
Data.load(self.file, obj_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -212,15 +215,19 @@ class UnassignConstraint(bpy.types.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"constraint": self.file.by_id(self.constraint),
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||
for obj in objs:
|
||||
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if not obj_id:
|
||||
continue
|
||||
ifcopenshell.api.run(
|
||||
"constraint.unassign_constraint",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj_id),
|
||||
"constraint": self.file.by_id(self.constraint),
|
||||
}
|
||||
)
|
||||
Data.load(self.file, obj_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -105,7 +104,7 @@ class BIM_PT_object_constraints(Panel):
|
||||
constraint = Data.objectives[constraint_id]
|
||||
icon = "LIGHT"
|
||||
except:
|
||||
pass # Metric not implemented
|
||||
pass # Metric not implemented
|
||||
row = self.layout.row(align=True)
|
||||
row.label(text=constraint.get("Name") or "Unnamed")
|
||||
row.operator("bim.unassign_constraint", text="", icon="X").constraint = constraint_id
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -26,7 +25,8 @@ classes = (
|
||||
operator.EditCostSchedule,
|
||||
operator.EditCostItem,
|
||||
operator.EditCostItemQuantity,
|
||||
operator.EditCostValue,
|
||||
operator.EditCostItemValue,
|
||||
operator.EditCostItemValueFormula,
|
||||
operator.EnableEditingCostSchedule,
|
||||
operator.EnableEditingCostItems,
|
||||
operator.EnableEditingCostItem,
|
||||
@@ -34,6 +34,7 @@ classes = (
|
||||
operator.EnableEditingCostItemQuantity,
|
||||
operator.EnableEditingCostItemValues,
|
||||
operator.EnableEditingCostItemValue,
|
||||
operator.EnableEditingCostItemValueFormula,
|
||||
operator.DisableEditingCostItem,
|
||||
operator.DisableEditingCostSchedule,
|
||||
operator.DisableEditingCostItemQuantity,
|
||||
@@ -63,6 +64,7 @@ classes = (
|
||||
operator.LoadScheduleOfRates,
|
||||
operator.ExpandCostItemRate,
|
||||
operator.ContractCostItemRate,
|
||||
operator.CalculateCostItemResourceValue,
|
||||
prop.CostItem,
|
||||
prop.CostItemQuantity,
|
||||
prop.CostItemType,
|
||||
|
||||
@@ -27,6 +27,7 @@ from blenderbim.bim.ifc import IfcStore
|
||||
from bpy_extras.io_utils import ImportHelper
|
||||
from ifcopenshell.api.cost.data import Data
|
||||
from ifcopenshell.api.unit.data import Data as UnitData
|
||||
from ifcopenshell.api.resource.data import Data as ResourceData
|
||||
|
||||
|
||||
class AddCostSchedule(bpy.types.Operator):
|
||||
@@ -590,20 +591,27 @@ class AddCostValue(bpy.types.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
parent = self.file.by_id(self.parent)
|
||||
if self.cost_type == "FIXED":
|
||||
category = None
|
||||
attributes = {"AppliedValue": 0.0}
|
||||
elif self.cost_type == "SUM":
|
||||
category = "*"
|
||||
attributes = {"Category": category}
|
||||
elif self.cost_type == "CATEGORY":
|
||||
category = self.cost_category
|
||||
value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=self.file.by_id(self.parent))
|
||||
ifcopenshell.api.run("cost.edit_cost_value", self.file, cost_value=value, attributes={"Category": category})
|
||||
Data.load(self.file)
|
||||
attributes = {"Category": category}
|
||||
value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=parent)
|
||||
ifcopenshell.api.run("cost.edit_cost_value", self.file, cost_value=value, attributes=attributes)
|
||||
if parent.is_a("IfcConstructionResource"):
|
||||
ResourceData.load(self.file)
|
||||
else:
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class RemoveCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.remove_cost_item_value"
|
||||
bl_idname = "bim.remove_cost_value"
|
||||
bl_label = "Add Cost Item Value"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
parent: bpy.props.IntProperty()
|
||||
@@ -614,13 +622,17 @@ class RemoveCostItemValue(bpy.types.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
parent = self.file.by_id(self.parent)
|
||||
ifcopenshell.api.run(
|
||||
"cost.remove_cost_item_value",
|
||||
"cost.remove_cost_value",
|
||||
self.file,
|
||||
parent=self.file.by_id(self.parent),
|
||||
parent=parent,
|
||||
cost_value=self.file.by_id(self.cost_value),
|
||||
)
|
||||
Data.load(self.file)
|
||||
if parent.is_a("IfcConstructionResource"):
|
||||
ResourceData.load(self.file)
|
||||
else:
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -633,21 +645,25 @@ class EnableEditingCostItemValue(bpy.types.Operator):
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
self.props.cost_value_attributes.clear()
|
||||
self.props.active_cost_item_value_id = self.cost_value
|
||||
self.props.active_cost_value_id = self.cost_value
|
||||
self.props.cost_value_editing_type = "ATTRIBUTES"
|
||||
data = Data.cost_values[self.cost_value]
|
||||
|
||||
blenderbim.bim.helper.import_attributes(
|
||||
data["type"],
|
||||
self.props.cost_value_attributes,
|
||||
data,
|
||||
lambda name, prop, data: self.import_attributes(name, prop, data, context)
|
||||
data["type"],
|
||||
self.props.cost_value_attributes,
|
||||
data,
|
||||
lambda name, prop, data: self.import_attributes(name, prop, data, context),
|
||||
)
|
||||
return {"FINISHED"}
|
||||
|
||||
def import_attributes(self, name, prop, data, context):
|
||||
if name == "AppliedValue":
|
||||
# TODO: for now, only support simple values
|
||||
# TODO: for now, only support simple IfcValues (which are effectively IfcMonetaryMeasure)
|
||||
prop = self.props.cost_value_attributes.add()
|
||||
prop.data_type = "float"
|
||||
prop.name = "AppliedValue"
|
||||
prop.is_optional = True
|
||||
prop.float_value = 0.0 if prop.is_null else data[name]
|
||||
return True
|
||||
if (
|
||||
@@ -699,13 +715,51 @@ class DisableEditingCostItemValue(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
props.active_cost_item_value_id = 0
|
||||
props.active_cost_value_id = 0
|
||||
props.cost_value_editing_type = ""
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostValue(bpy.types.Operator):
|
||||
class EnableEditingCostItemValueFormula(bpy.types.Operator):
|
||||
bl_idname = "bim.enable_editing_cost_item_value_formula"
|
||||
bl_label = "Enable Editing Cost Item Value Formula"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
self.props = context.scene.BIMCostProperties
|
||||
self.props.cost_value_attributes.clear()
|
||||
self.props.active_cost_value_id = self.cost_value
|
||||
self.props.cost_value_editing_type = "FORMULA"
|
||||
self.props.cost_value_formula = Data.cost_values[self.cost_value]["Formula"]
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostItemValueFormula(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_cost_value_formula"
|
||||
bl_label = "Edit Cost Value Formula"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_value_formula",
|
||||
self.file,
|
||||
**{"cost_value": self.file.by_id(self.cost_value), "formula": props.cost_value_formula},
|
||||
)
|
||||
Data.load(IfcStore.get_file())
|
||||
bpy.ops.bim.disable_editing_cost_item_value()
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class EditCostItemValue(bpy.types.Operator):
|
||||
bl_idname = "bim.edit_cost_value"
|
||||
bl_label = "Edit Cost Item Value"
|
||||
bl_label = "Edit Cost Value"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_value: bpy.props.IntProperty()
|
||||
|
||||
@@ -715,8 +769,8 @@ class EditCostValue(bpy.types.Operator):
|
||||
def _execute(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
attributes = blenderbim.bim.helper.export_attributes(
|
||||
props.cost_value_attributes,
|
||||
lambda attributes, prop: self.export_attributes(attributes, prop, context))
|
||||
props.cost_value_attributes, lambda attributes, prop: self.export_attributes(attributes, prop, context)
|
||||
)
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.edit_cost_value",
|
||||
@@ -1000,3 +1054,21 @@ class ContractCostItemRate(bpy.types.Operator):
|
||||
props.contracted_cost_item_rates = json.dumps(contracted_cost_item_rates)
|
||||
bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(props.schedule_of_rates))
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class CalculateCostItemResourceValue(bpy.types.Operator):
|
||||
bl_idname = "bim.calculate_cost_item_resource_value"
|
||||
bl_label = "Calculate Cost Item Resource Value"
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
cost_item: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"cost.calculate_cost_item_resource_value", self.file, cost_item=self.file.by_id(self.cost_item)
|
||||
)
|
||||
Data.load(self.file)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -79,7 +79,7 @@ def update_schedule_of_rates(self, context):
|
||||
bpy.ops.bim.load_schedule_of_rates(cost_schedule=int(self.schedule_of_rates))
|
||||
|
||||
|
||||
def getQuantityTypes(self, context):
|
||||
def get_quantity_types(self, context):
|
||||
global quantitytypes_enum
|
||||
if len(quantitytypes_enum) == 0 and IfcStore.get_schema():
|
||||
quantitytypes_enum.extend(
|
||||
@@ -91,7 +91,7 @@ def getQuantityTypes(self, context):
|
||||
return quantitytypes_enum
|
||||
|
||||
|
||||
def getProductQuantityNames(self, context):
|
||||
def get_product_quantity_names(self, context):
|
||||
global productquantitynames_enum
|
||||
global productquantitynames_count
|
||||
ifc_file = IfcStore.get_file()
|
||||
@@ -115,7 +115,7 @@ def getProductQuantityNames(self, context):
|
||||
return productquantitynames_enum
|
||||
|
||||
|
||||
def getProcessQuantityNames(self, context):
|
||||
def get_process_quantity_names(self, context):
|
||||
global processquantitynames_enum
|
||||
global processquantitynames_id
|
||||
ifc_file = IfcStore.get_file()
|
||||
@@ -137,7 +137,7 @@ def getProcessQuantityNames(self, context):
|
||||
return processquantitynames_enum
|
||||
|
||||
|
||||
def getResourceQuantityNames(self, context):
|
||||
def get_resource_quantity_names(self, context):
|
||||
global resourcequantitynames_enum
|
||||
global resourcequantitynames_id
|
||||
ifc_file = IfcStore.get_file()
|
||||
@@ -166,7 +166,7 @@ def update_active_cost_item_index(self, context):
|
||||
bpy.ops.bim.load_cost_item_quantities()
|
||||
|
||||
|
||||
def updateCostItemIdentification(self, context):
|
||||
def update_cost_item_identification(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
if not props.is_cost_update_enabled or self.identification == "XXX":
|
||||
return
|
||||
@@ -182,7 +182,7 @@ def updateCostItemIdentification(self, context):
|
||||
attribute.string_value = self.identification
|
||||
|
||||
|
||||
def updateCostItemName(self, context):
|
||||
def update_cost_item_name(self, context):
|
||||
props = context.scene.BIMCostProperties
|
||||
if not props.is_cost_update_enabled or self.name == "Unnamed":
|
||||
return
|
||||
@@ -199,8 +199,8 @@ def updateCostItemName(self, context):
|
||||
|
||||
|
||||
class CostItem(PropertyGroup):
|
||||
name: StringProperty(name="Name", update=updateCostItemName)
|
||||
identification: StringProperty(name="Identification", update=updateCostItemIdentification)
|
||||
name: StringProperty(name="Name", update=update_cost_item_name)
|
||||
identification: StringProperty(name="Identification", update=update_cost_item_identification)
|
||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||
has_children: BoolProperty(name="Has Children")
|
||||
is_expanded: BoolProperty(name="Is Expanded")
|
||||
@@ -229,10 +229,10 @@ class BIMCostProperties(PropertyGroup):
|
||||
active_cost_item_index: IntProperty(name="Active Cost Item Index", update=update_active_cost_item_index)
|
||||
cost_item_attributes: CollectionProperty(name="Task Attributes", type=Attribute)
|
||||
contracted_cost_items: StringProperty(name="Contracted Cost Items", default="[]")
|
||||
quantity_types: EnumProperty(items=getQuantityTypes, name="Quantity Types")
|
||||
product_quantity_names: EnumProperty(items=getProductQuantityNames, name="Product Quantity Names")
|
||||
process_quantity_names: EnumProperty(items=getProcessQuantityNames, name="Process Quantity Names")
|
||||
resource_quantity_names: EnumProperty(items=getResourceQuantityNames, name="Resource Quantity Names")
|
||||
quantity_types: EnumProperty(items=get_quantity_types, name="Quantity Types")
|
||||
product_quantity_names: EnumProperty(items=get_product_quantity_names, name="Product Quantity Names")
|
||||
process_quantity_names: EnumProperty(items=get_process_quantity_names, name="Process Quantity Names")
|
||||
resource_quantity_names: EnumProperty(items=get_resource_quantity_names, name="Resource Quantity Names")
|
||||
active_cost_item_quantity_id: IntProperty(name="Active Cost Item Quantity Id")
|
||||
quantity_attributes: CollectionProperty(name="Quantity Attributes", type=Attribute)
|
||||
cost_types: EnumProperty(
|
||||
@@ -244,8 +244,10 @@ class BIMCostProperties(PropertyGroup):
|
||||
name="Cost Types",
|
||||
)
|
||||
cost_category: StringProperty(name="Cost Category")
|
||||
active_cost_item_value_id: IntProperty(name="Active Cost Item Value Id")
|
||||
active_cost_value_id: IntProperty(name="Active Cost Item Value Id")
|
||||
cost_value_editing_type: StringProperty(name="Cost Value Editing Type")
|
||||
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", default=False)
|
||||
columns: CollectionProperty(name="Columns", type=StrProperty)
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
# 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 blenderbim.bim.helper
|
||||
import blenderbim.bim.module.cost.prop as CostProp
|
||||
from bpy.types import Panel, UIList
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
from blenderbim.bim.helper import draw_attributes
|
||||
from ifcopenshell.api.cost.data import Data
|
||||
from ifcopenshell.api.unit.data import Data as UnitData
|
||||
|
||||
@@ -94,7 +94,7 @@ class BIM_PT_cost_schedules(Panel):
|
||||
self.layout.template_list("BIM_UL_cost_columns", "", self.props, "columns", self.props, "active_column_index")
|
||||
|
||||
def draw_editable_cost_schedule_ui(self):
|
||||
draw_attributes(self.props.cost_schedule_attributes, self.layout)
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_schedule_attributes, self.layout)
|
||||
|
||||
def draw_editable_cost_item_ui(self, cost_schedule_id):
|
||||
row = self.layout.row(align=True)
|
||||
@@ -140,7 +140,7 @@ class BIM_PT_cost_schedules(Panel):
|
||||
self.draw_editable_cost_item_values_ui()
|
||||
|
||||
def draw_editable_cost_item_attributes_ui(self):
|
||||
draw_attributes(self.props.cost_item_attributes, self.layout)
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_item_attributes, self.layout)
|
||||
|
||||
def draw_editable_cost_item_quantities_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
@@ -175,7 +175,7 @@ class BIM_PT_cost_schedules(Panel):
|
||||
self.draw_editable_cost_item_quantity_ui(box)
|
||||
|
||||
def draw_editable_cost_item_quantity_ui(self, layout):
|
||||
draw_attributes(self.props.quantity_attributes, self.layout)
|
||||
blenderbim.bim.helper.draw_attributes(self.props.quantity_attributes, self.layout)
|
||||
|
||||
def draw_editable_cost_item_values_ui(self):
|
||||
row = self.layout.row(align=True)
|
||||
@@ -192,68 +192,46 @@ class BIM_PT_cost_schedules(Panel):
|
||||
row = self.layout.row(align=True)
|
||||
self.draw_readonly_cost_value_ui(row, cost_value_id)
|
||||
|
||||
if self.props.active_cost_item_value_id:
|
||||
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||
box = self.layout.box()
|
||||
self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_item_value_id])
|
||||
self.draw_editable_cost_value_ui(box, Data.cost_values[self.props.active_cost_value_id])
|
||||
|
||||
def draw_readonly_cost_value_ui(self, layout, cost_value_id):
|
||||
# This UI is really poor. Delete and start again.
|
||||
cost_value = Data.cost_values[cost_value_id]
|
||||
cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"])
|
||||
if cost_value["Category"]:
|
||||
cost_value_label += " ({})".format(cost_value["Category"])
|
||||
layout.label(text="", icon="DISC")
|
||||
|
||||
if self.props.active_cost_value_id == cost_value_id and self.props.cost_value_editing_type == "FORMULA":
|
||||
layout.prop(self.props, "cost_value_formula", text="")
|
||||
else:
|
||||
cost_value_label = "{0:.2f}".format(cost_value["AppliedValue"])
|
||||
cost_value_label += " = " + cost_value["Formula"]
|
||||
layout.label(text=cost_value_label, icon="DISC")
|
||||
|
||||
self.draw_cost_value_operator_ui(layout, cost_value_id, self.props.active_cost_item_id)
|
||||
layout.label(text=cost_value_label)
|
||||
|
||||
for component_id in cost_value["Components"] or []:
|
||||
self.draw_readonly_component_cost_value_ui(layout, component_id, cost_value["id"])
|
||||
|
||||
def draw_readonly_component_cost_value_ui(self, layout, cost_value_id, parent_id, level=1):
|
||||
self.draw_cost_value_operator_ui(layout, cost_value_id, parent_id)
|
||||
cost_value = Data.cost_values[cost_value_id]
|
||||
cost_value_label = ">" * level
|
||||
cost_value_label += "{0:.2f}".format(cost_value["AppliedValue"])
|
||||
if cost_value["Category"]:
|
||||
cost_value_label += " ({})".format(cost_value["Category"])
|
||||
layout.label(text=cost_value_label)
|
||||
|
||||
for component_id in cost_value["Components"] or []:
|
||||
self.draw_readonly_component_cost_value_ui(layout, component_id, cost_value["id"], level + 1)
|
||||
|
||||
def draw_cost_value_operator_ui(self, layout, cost_value_id, parent_id):
|
||||
if self.props.active_cost_item_value_id and self.props.active_cost_item_value_id == cost_value_id:
|
||||
op = layout.operator("bim.edit_cost_value", text="", icon="CHECKMARK")
|
||||
op.cost_value = cost_value_id
|
||||
op = layout.operator("bim.add_cost_value", text="", icon="ADD")
|
||||
op.parent = cost_value_id
|
||||
op.cost_type = self.props.cost_types
|
||||
if self.props.cost_types == "CATEGORY":
|
||||
op.cost_category = self.props.cost_category
|
||||
if self.props.active_cost_value_id and self.props.active_cost_value_id == cost_value_id:
|
||||
if self.props.cost_value_editing_type == "ATTRIBUTES":
|
||||
op = layout.operator("bim.edit_cost_value", text="", icon="CHECKMARK")
|
||||
op.cost_value = cost_value_id
|
||||
elif self.props.cost_value_editing_type == "FORMULA":
|
||||
op = layout.operator("bim.edit_cost_value_formula", text="", icon="CHECKMARK")
|
||||
op.cost_value = cost_value_id
|
||||
layout.operator("bim.disable_editing_cost_item_value", text="", icon="CANCEL")
|
||||
elif self.props.active_cost_item_value_id:
|
||||
op = layout.operator("bim.add_cost_value", text="", icon="ADD")
|
||||
op.parent = cost_value_id
|
||||
op.cost_type = self.props.cost_types
|
||||
if self.props.cost_types == "CATEGORY":
|
||||
op.cost_category = self.props.cost_category
|
||||
op = layout.operator("bim.remove_cost_item_value", text="", icon="X")
|
||||
elif self.props.active_cost_value_id:
|
||||
op = layout.operator("bim.remove_cost_value", text="", icon="X")
|
||||
op.parent = parent_id
|
||||
op.cost_value = cost_value_id
|
||||
else:
|
||||
op = layout.operator("bim.enable_editing_cost_item_value_formula", text="", icon="CON_TRANSLIKE")
|
||||
op.cost_value = cost_value_id
|
||||
op = layout.operator("bim.enable_editing_cost_item_value", text="", icon="GREASEPENCIL")
|
||||
op.cost_value = cost_value_id
|
||||
op = layout.operator("bim.add_cost_value", text="", icon="ADD")
|
||||
op.parent = cost_value_id
|
||||
op.cost_type = self.props.cost_types
|
||||
if self.props.cost_types == "CATEGORY":
|
||||
op.cost_category = self.props.cost_category
|
||||
op = layout.operator("bim.remove_cost_item_value", text="", icon="X")
|
||||
op = layout.operator("bim.remove_cost_value", text="", icon="X")
|
||||
op.parent = parent_id
|
||||
op.cost_value = cost_value_id
|
||||
|
||||
def draw_editable_cost_value_ui(self, layout, cost_value):
|
||||
draw_attributes(self.props.cost_value_attributes, layout)
|
||||
blenderbim.bim.helper.draw_attributes(self.props.cost_value_attributes, layout)
|
||||
|
||||
|
||||
class BIM_PT_cost_item_types(Panel):
|
||||
@@ -373,11 +351,29 @@ class BIM_PT_cost_item_quantities(Panel):
|
||||
# Column1
|
||||
col = grid.column()
|
||||
|
||||
has_quantity_names = CostProp.get_product_quantity_names(self, context)
|
||||
|
||||
row2 = col.row(align=True)
|
||||
row2.label(text="Elements")
|
||||
op = row2.operator("bim.select_cost_item_products", icon="RESTRICT_SELECT_OFF", text="")
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
|
||||
if context.selected_objects:
|
||||
if has_quantity_names:
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
|
||||
op.related_object_type = "PRODUCT"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = self.props.product_quantity_names
|
||||
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||
op.related_object_type = "PRODUCT"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = ""
|
||||
|
||||
op = row2.operator("bim.unassign_cost_item_quantity", text="", icon="REMOVE")
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.related_object = 0
|
||||
|
||||
row2 = col.row()
|
||||
row2.template_list(
|
||||
"BIM_UL_cost_item_quantities",
|
||||
@@ -388,23 +384,32 @@ class BIM_PT_cost_item_quantities(Panel):
|
||||
"active_cost_item_product_index",
|
||||
)
|
||||
|
||||
row2 = col.row(align=True)
|
||||
row2.prop(self.props, "product_quantity_names", text="")
|
||||
op = row2.operator("bim.unassign_cost_item_quantity", text="", icon="REMOVE")
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.related_object = 0
|
||||
if CostProp.productquantitynames_enum:
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||
op.related_object_type = "PRODUCT"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = self.props.product_quantity_names
|
||||
if has_quantity_names:
|
||||
row2 = col.row()
|
||||
row2.prop(self.props, "product_quantity_names", text="")
|
||||
|
||||
# Column2
|
||||
col = grid.column()
|
||||
|
||||
has_quantity_names = CostProp.get_process_quantity_names(self, context)
|
||||
|
||||
row2 = col.row(align=True)
|
||||
row2.label(text="Tasks")
|
||||
|
||||
tprops = context.scene.BIMTaskTreeProperties
|
||||
wprops = context.scene.BIMWorkScheduleProperties
|
||||
if tprops.tasks and wprops.active_task_index < len(tprops.tasks):
|
||||
if has_quantity_names:
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
|
||||
op.related_object_type = "PROCESS"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = self.props.process_quantity_names
|
||||
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||
op.related_object_type = "PROCESS"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = ""
|
||||
|
||||
row2 = col.row()
|
||||
row2.template_list(
|
||||
"BIM_UL_cost_item_quantities",
|
||||
@@ -415,20 +420,35 @@ class BIM_PT_cost_item_quantities(Panel):
|
||||
"active_cost_item_process_index",
|
||||
)
|
||||
|
||||
row2 = col.row(align=True)
|
||||
row2.prop(self.props, "process_quantity_names", text="")
|
||||
if CostProp.processquantitynames_enum:
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||
op.related_object_type = "PROCESS"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = self.props.process_quantity_names
|
||||
if has_quantity_names:
|
||||
row2 = col.row()
|
||||
row2.prop(self.props, "process_quantity_names", text="")
|
||||
|
||||
# Column3
|
||||
col = grid.column()
|
||||
|
||||
has_quantity_names = CostProp.get_resource_quantity_names(self, context)
|
||||
|
||||
row2 = col.row(align=True)
|
||||
row2.label(text="Resources")
|
||||
|
||||
op = row2.operator("bim.calculate_cost_item_resource_value", text="", icon="DISC")
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
|
||||
rtprops = context.scene.BIMResourceTreeProperties
|
||||
rprops = context.scene.BIMResourceProperties
|
||||
if rtprops.resources and rprops.active_resource_index < len(rtprops.resources):
|
||||
if has_quantity_names:
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="PROPERTIES")
|
||||
op.related_object_type = "RESOURCE"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = self.props.resource_quantity_names
|
||||
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||
op.related_object_type = "RESOURCE"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = ""
|
||||
|
||||
row2 = col.row()
|
||||
row2.template_list(
|
||||
"BIM_UL_cost_item_quantities",
|
||||
@@ -439,13 +459,9 @@ class BIM_PT_cost_item_quantities(Panel):
|
||||
"active_cost_item_resource_index",
|
||||
)
|
||||
|
||||
row2 = col.row(align=True)
|
||||
row2.prop(self.props, "resource_quantity_names", text="")
|
||||
if CostProp.resourcequantitynames_enum:
|
||||
op = row2.operator("bim.assign_cost_item_quantity", text="", icon="ADD")
|
||||
op.related_object_type = "RESOURCE"
|
||||
op.cost_item = cost_item.ifc_definition_id
|
||||
op.prop_name = self.props.resource_quantity_names
|
||||
if has_quantity_names:
|
||||
row2 = col.row()
|
||||
row2.prop(self.props, "resource_quantity_names", text="")
|
||||
|
||||
|
||||
class BIM_PT_cost_item_rates(Panel):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -32,11 +31,9 @@ classes = (
|
||||
)
|
||||
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.CsvProperties = bpy.props.PointerProperty(type=prop.CsvProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.CsvProperties
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -18,6 +17,7 @@
|
||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import bpy
|
||||
import time
|
||||
import logging
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.placement
|
||||
@@ -88,10 +88,7 @@ class ProfileImportIFC(bpy.types.Operator):
|
||||
import cProfile
|
||||
import pstats
|
||||
|
||||
# For Windows
|
||||
filepath = context.scene.BIMProperties.ifc_file.replace("\\", "\\\\")
|
||||
|
||||
cProfile.run(f"import bpy; bpy.ops.import_ifc.bim(filepath='{filepath}')", "blender.prof")
|
||||
cProfile.run("import bpy; bpy.ops.bim.load_project_elements()", "blender.prof")
|
||||
p = pstats.Stats("blender.prof")
|
||||
p.sort_stats("cumulative").print_stats(50)
|
||||
return {"FINISHED"}
|
||||
@@ -116,9 +113,16 @@ class CreateAllShapes(bpy.types.Operator):
|
||||
if element.GlobalId in excludes:
|
||||
continue
|
||||
print(f"{i}/{total}:", element)
|
||||
start = time.time()
|
||||
try:
|
||||
shape = ifcopenshell.geom.create_shape(settings, element)
|
||||
print("Success", len(shape.geometry.verts), len(shape.geometry.edges), len(shape.geometry.faces))
|
||||
print(
|
||||
"Success",
|
||||
time.time() - start,
|
||||
len(shape.geometry.verts),
|
||||
len(shape.geometry.edges),
|
||||
len(shape.geometry.faces),
|
||||
)
|
||||
except:
|
||||
failures.append(element)
|
||||
print("***** FAILURE *****")
|
||||
@@ -164,9 +168,11 @@ class SelectHighPolygonMeshes(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
[o.select_set(True) for o in context.view_layer.objects
|
||||
if o.type == "MESH"
|
||||
and len(o.data.polygons) > context.scene.BIMDebugProperties.number_of_polygons]
|
||||
[
|
||||
o.select_set(True)
|
||||
for o in context.view_layer.objects
|
||||
if o.type == "MESH" and len(o.data.polygons) > context.scene.BIMDebugProperties.number_of_polygons
|
||||
]
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -31,11 +30,9 @@ classes = (
|
||||
)
|
||||
|
||||
|
||||
|
||||
def register():
|
||||
bpy.types.Scene.DiffProperties = bpy.props.PointerProperty(type=prop.DiffProperties)
|
||||
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.DiffProperties
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -24,7 +23,6 @@ import json
|
||||
from blenderbim.bim.ifc import IfcStore
|
||||
|
||||
|
||||
|
||||
class SelectDiffJsonFile(bpy.types.Operator):
|
||||
bl_idname = "bim.select_diff_json_file"
|
||||
bl_label = "Select Diff JSON File"
|
||||
@@ -46,8 +44,8 @@ class VisualiseDiff(bpy.types.Operator):
|
||||
bl_options = {"REGISTER", "UNDO"}
|
||||
|
||||
def execute(self, context):
|
||||
#ifc_file = IfcStore.get_file() # In case we get from Store
|
||||
ifc_file = ifcopenshell.open(context.scene.DiffProperties.diff_new_file) # for Now refer to the new file
|
||||
# ifc_file = IfcStore.get_file() # In case we get from Store
|
||||
ifc_file = ifcopenshell.open(context.scene.DiffProperties.diff_new_file) # for Now refer to the new file
|
||||
with open(context.scene.DiffProperties.diff_json_file, "r") as file:
|
||||
diff = json.load(file)
|
||||
for obj in context.visible_objects:
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
@@ -276,17 +275,21 @@ class AssignDocument(bpy.types.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"document.assign_document",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"document": self.file.by_id(self.document),
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||
for obj in objs:
|
||||
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if not obj_id:
|
||||
continue
|
||||
ifcopenshell.api.run(
|
||||
"document.assign_document",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj_id),
|
||||
"document": self.file.by_id(self.document),
|
||||
}
|
||||
)
|
||||
Data.load(self.file, obj_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -301,15 +304,19 @@ class UnassignDocument(bpy.types.Operator):
|
||||
return IfcStore.execute_ifc_operator(self, context)
|
||||
|
||||
def _execute(self, context):
|
||||
obj = bpy.data.objects.get(self.obj) if self.obj else context.active_object
|
||||
self.file = IfcStore.get_file()
|
||||
ifcopenshell.api.run(
|
||||
"document.unassign_document",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj.BIMObjectProperties.ifc_definition_id),
|
||||
"document": self.file.by_id(self.document),
|
||||
}
|
||||
)
|
||||
Data.load(IfcStore.get_file(), obj.BIMObjectProperties.ifc_definition_id)
|
||||
objs = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
|
||||
for obj in objs:
|
||||
obj_id = obj.BIMObjectProperties.ifc_definition_id
|
||||
if not obj_id:
|
||||
continue
|
||||
ifcopenshell.api.run(
|
||||
"document.unassign_document",
|
||||
self.file,
|
||||
**{
|
||||
"product": self.file.by_id(obj_id),
|
||||
"document": self.file.by_id(self.document),
|
||||
}
|
||||
)
|
||||
Data.load(self.file, obj_id)
|
||||
return {"FINISHED"}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com>
|
||||
#
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user