From 2cbc7a10abcdea866b39c34fea3c5bb0e7248cb6 Mon Sep 17 00:00:00 2001 From: Andrea Ghensi Date: Tue, 8 Nov 2022 22:54:23 +0100 Subject: [PATCH] [BCF] New BCF XML handler with better performances (#2355) BREAKING CHANGE: incompatible methods and objects with previous version. closes #2321 --- .github/workflows/ci-bcf.yml | 11 +- .gitignore | 4 + src/bcf/.gitignore | 1 + src/bcf/Makefile | 37 + src/bcf/README.md | 79 +- src/bcf/environment.yml | 7 + src/bcf/pyproject.toml | 118 +- src/bcf/requirements-dev.txt | 7 + src/bcf/requirements.txt | 1 - src/bcf/setup.cfg | 37 - src/bcf/setup.py | 3 + src/bcf/src/bcf/bcfxml.py | 108 +- src/bcf/src/bcf/geometry.py | 44 + src/bcf/src/bcf/inmemory_zipfile.py | 55 + src/bcf/src/bcf/py.typed | 0 src/bcf/src/bcf/v2/__init__.py | 2 - src/bcf/src/bcf/v2/bcfxml.py | 1019 ++++----------- src/bcf/src/bcf/v2/data.py | 198 --- src/bcf/src/bcf/v2/model/__init__.py | 70 ++ src/bcf/src/bcf/v2/model/markup.py | 461 +++++++ src/bcf/src/bcf/v2/model/project.py | 41 + src/bcf/src/bcf/v2/model/version.py | 21 + src/bcf/src/bcf/v2/model/visinfo.py | 476 +++++++ src/bcf/src/bcf/v2/topic.py | 240 ++++ src/bcf/src/bcf/v2/visinfo.py | 246 ++++ src/bcf/src/bcf/v3/__init__.py | 20 +- src/bcf/src/bcf/v3/bcfapi.py | 356 +++--- src/bcf/src/bcf/v3/bcfxml.py | 1094 ++++------------- src/bcf/src/bcf/v3/data.py | 200 --- src/bcf/src/bcf/v3/document.py | 61 + src/bcf/src/bcf/v3/model/__init__.py | 110 ++ src/bcf/src/bcf/v3/model/documents.py | 61 + src/bcf/src/bcf/v3/model/extensions.py | 181 +++ src/bcf/src/bcf/v3/model/markup.py | 616 ++++++++++ src/bcf/src/bcf/v3/model/project.py | 37 + src/bcf/src/bcf/v3/model/version.py | 12 + src/bcf/src/bcf/v3/model/visinfo.py | 524 ++++++++ src/bcf/src/bcf/v3/topic.py | 188 +++ src/bcf/src/bcf/v3/visinfo.py | 247 ++++ src/bcf/src/bcf/xml_parser.py | 83 ++ src/bcf/tests/__init__.py | 1 + src/bcf/tests/conftest.py | 8 + src/bcf/tests/v2/MaximumInformation.bcf | Bin 0 -> 368484 bytes src/bcf/tests/v2/__init__.py | 0 src/bcf/tests/v2/test_bcf_xml.py | 122 ++ src/bcf/tests/v2/test_example_files.py | 365 ++++++ .../tests/v3/Document reference internal.bcf | Bin 0 -> 100614 bytes src/bcf/tests/v3/__init__.py | 0 src/bcf/tests/v3/test_bcf_xml.py | 129 ++ src/bcf/tests/v3/test_example_files.py | 230 ++++ 50 files changed, 5591 insertions(+), 2340 deletions(-) create mode 100644 src/bcf/.gitignore create mode 100644 src/bcf/Makefile create mode 100644 src/bcf/environment.yml create mode 100644 src/bcf/requirements-dev.txt delete mode 100644 src/bcf/requirements.txt delete mode 100644 src/bcf/setup.cfg create mode 100644 src/bcf/setup.py create mode 100644 src/bcf/src/bcf/geometry.py create mode 100644 src/bcf/src/bcf/inmemory_zipfile.py create mode 100644 src/bcf/src/bcf/py.typed delete mode 100644 src/bcf/src/bcf/v2/data.py create mode 100644 src/bcf/src/bcf/v2/model/__init__.py create mode 100644 src/bcf/src/bcf/v2/model/markup.py create mode 100644 src/bcf/src/bcf/v2/model/project.py create mode 100644 src/bcf/src/bcf/v2/model/version.py create mode 100644 src/bcf/src/bcf/v2/model/visinfo.py create mode 100644 src/bcf/src/bcf/v2/topic.py create mode 100644 src/bcf/src/bcf/v2/visinfo.py delete mode 100644 src/bcf/src/bcf/v3/data.py create mode 100644 src/bcf/src/bcf/v3/document.py create mode 100644 src/bcf/src/bcf/v3/model/__init__.py create mode 100644 src/bcf/src/bcf/v3/model/documents.py create mode 100644 src/bcf/src/bcf/v3/model/extensions.py create mode 100644 src/bcf/src/bcf/v3/model/markup.py create mode 100644 src/bcf/src/bcf/v3/model/project.py create mode 100644 src/bcf/src/bcf/v3/model/version.py create mode 100644 src/bcf/src/bcf/v3/model/visinfo.py create mode 100644 src/bcf/src/bcf/v3/topic.py create mode 100644 src/bcf/src/bcf/v3/visinfo.py create mode 100644 src/bcf/src/bcf/xml_parser.py create mode 100644 src/bcf/tests/__init__.py create mode 100644 src/bcf/tests/conftest.py create mode 100644 src/bcf/tests/v2/MaximumInformation.bcf create mode 100644 src/bcf/tests/v2/__init__.py create mode 100644 src/bcf/tests/v2/test_bcf_xml.py create mode 100644 src/bcf/tests/v2/test_example_files.py create mode 100644 src/bcf/tests/v3/Document reference internal.bcf create mode 100644 src/bcf/tests/v3/__init__.py create mode 100644 src/bcf/tests/v3/test_bcf_xml.py create mode 100644 src/bcf/tests/v3/test_example_files.py diff --git a/.github/workflows/ci-bcf.yml b/.github/workflows/ci-bcf.yml index 8d689cc2fd..2d82036975 100644 --- a/.github/workflows/ci-bcf.yml +++ b/.github/workflows/ci-bcf.yml @@ -19,20 +19,19 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: - python-version: '3.x' + python-version: '3.10' - name: Build package run: | cd src/bcf pip install build python -m build + - name: Test + run: | + cd src/bcf + make test - name: Publish package uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} packages_dir: src/bcf/dist - - - - - diff --git a/.gitignore b/.gitignore index b1783fad92..7c5d7a2e19 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,7 @@ _build/ # IDS Docs src/ifcopenshell-python/test/build + +# tox cache +.tox/ +*.egg-info/ diff --git a/src/bcf/.gitignore b/src/bcf/.gitignore new file mode 100644 index 0000000000..172bf5786d --- /dev/null +++ b/src/bcf/.gitignore @@ -0,0 +1 @@ +.tox diff --git a/src/bcf/Makefile b/src/bcf/Makefile new file mode 100644 index 0000000000..2baaaac259 --- /dev/null +++ b/src/bcf/Makefile @@ -0,0 +1,37 @@ +.PHONY: test +test: + tox + +.PHONY: qa +qa: + black . + isort . + pylint ./src --output-format=colorized + +.PHONY: typecheck +typecheck: + mypy src/bcf + +.PHONY: license +license: + copyright-header --license LGPL3 --copyright-holder "Andrea Ghensi " --copyright-year "2022" --copyright-software "IfcOpenShell" --copyright-software-description "BCF XML file handling" -a ./ -o ./ + +.PHONY: coverage +coverage: + coverage run --source bcf -m pytest tests + coverage html + xdg-open htmlcov/index.html + +.PHONY: clean +clean: + rm -rf htmlcov + +# TODO: make this based on xsd file presence +.PHONY: models +models: + cd src && xsdata generate -p bcf.v2.model --unnest-classes --kw-only --slots -ds Google bcf/v2/xsd + cd src && xsdata generate -p bcf.v3.model --unnest-classes --kw-only --slots -ds Google bcf/v3/xsd + +# .PHONY +# api: +# openapi-python-client generate --url https://api.swaggerhub.com/apis/buildingSMART/BCF/3.0 diff --git a/src/bcf/README.md b/src/bcf/README.md index 812c0d6f04..5aeade120f 100644 --- a/src/bcf/README.md +++ b/src/bcf/README.md @@ -1,64 +1,54 @@ # bcf -A simple Python implementation of BCF. The data model is described in `data.py`. +A simple Python implementation of BCF. Manipulation of BCF-XML is available via `bcfxml.py` and manipulation of BCF-API is available via `bcfapi.py`. -- BCF-XML version 2.1: Fully supported -- BCF-API version 2.1: Not supported, will probably tackle this after BCF-API v3.0 -- BCF-XML version 3.0: Almost fully supported, except for the documents module -- BCF-API version 3.0: Almost fully supported, except for two requests. +It tries to support BCF-XML version 2.1 and 3.0, and BCF-API 3.0. ## bcfxml -The `bcfxml` module lets you interact with the BCF-XML standard. +The `bcfxml.load` function lets you read a BCF-XML file. +It takes care of using the right version based on the "bcf.version" file contained in the BCF package. + +The BCF files are extracted and parsed on-demand, and edits are stored in memory until you call the `save` method. ```python -from bcf import bcfxml - +from bcf.bcfxml import load # Load a project -bcfxml = bcfxml.load("/path/to/file.bcf") +with load("/path/to/file.bcf") as bcfxml: + project = bcfxml.project + print(project.name) + # To edit a project, just modify the object directly + bcfxml.project.name = "New name" -# The project is also stored in the module -# project == bcfxml.project -project=bcfxml.get_project() -print(project.name) + # Get a dictionary of topics + topics = bcfxml.topics -# To edit a project, just modify the object directly -bcfxml.project.name = "New name" -bcfxml.edit_project() + for topic_handler in bcfxml.topics: + topic = topic_handler.topic + print("Topic guid is", topic.guid) + print("Topic title is", topic.title) -# The BCF file is extracted to this temporary directory -print(bcfxml.filepath) + # Fetch extra data about a topic + header = topic_handler.header + comments = topic_handler.comments + viewpoints = topic_handler.viewpoints -# Get a dictionary of topics -topics = bcfxml.get_topics() + for comment in comments: + print(comment.guid) + print(comment.comment) + print(comment.author) -# Note: topics == bcfxml.topics -for guid, topic in bcfxml.topics.items(): - print("Topic guid is", guid) - print("Topic guid is", topic.guid) - print("Topic title is", topic.title) + # Get a particular topic + topic = bcfxml.get_topic(guid) - # Fetch extra data about a topic - header = bcfxml.get_header(guid) - comments = bcfxml.get_comments(guid) - viewpoints = bcfxml.get_viewpoints(guid) + # Modify a topic + topic.title = "New title" - # Note: comments == topic.comments, and so on - for comment_guid, comment in comments.items(): - print(comment_guid) - print(comment.comment) - print(comment.author) - -# Get a particular topic -topic = bcfxml.get_topic(guid) - -# Modify a topic -topic.title = "New title" -bcfxml.edit_topic(topic) + bcfxml.save() ``` ## bcfapi @@ -92,10 +82,3 @@ print(data) data = bcf_client.get_extensions(project_id) print(data) ``` - -## Todo List - -The remaining work that needs to be completed in `bcfxml.py` and `bcfapi.py`. - -- For `bcfxml.py` two xsds support is remaining namely 'documents.xsd`and`extensions.xsd`. -- For `bcfapi.py` two requests that are `get_topics` and `get_comments` are remaining. diff --git a/src/bcf/environment.yml b/src/bcf/environment.yml new file mode 100644 index 0000000000..01fe5b7a8c --- /dev/null +++ b/src/bcf/environment.yml @@ -0,0 +1,7 @@ +name: bcf-client +channels: + - conda-forge +dependencies: + - ifcopenshell + - xsdata + - numpy diff --git a/src/bcf/pyproject.toml b/src/bcf/pyproject.toml index dadda3ed02..49ce8c4ecb 100644 --- a/src/bcf/pyproject.toml +++ b/src/bcf/pyproject.toml @@ -1,12 +1,126 @@ [build-system] requires = [ - "setuptools>=42", + "setuptools>=61", "wheel" ] build-backend = "setuptools.build_meta" +[project] +name = "bcf-client" +# author = "IfcOpenShell" +description = "BCF-XML file handler." +readme = "README.md" +requires-python = ">=3.8" +keywords = ["IFC", "BCF", "BIM", "eingineering"] +dependencies = [ + "xsdata", + "numpy", +] +version = "0.0.1" +classifiers = [ + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Topic :: Scientific/Engineering", + "Topic :: Utilities", +] + +[project.urls] +Source = "https://github.com/IfcOpenShell/IfcOpenShell" +Issues = "https://github.com/IfcOpenShell/IfcOpenShell/issues" + [tool.black] line-length = 120 +extend-exclude = "model" [tool.isort] -profile = "black" \ No newline at end of file +profile = "black" +extend_skip_glob = ["src/bcf/*/model/*"] + +[tool.coverage.paths] +source = ["src"] + +[tool.coverage.run] +branch = true +source = ["bcf"] +omit = ["*/model/*"] + +[tool.coverage.report] +show_missing = true +fail_under = 65 +exclude_lines = [ + "pragma: no cover", + "if TYPE_CHECKING", + "if __name__ == .__main__.:", + "Protocol", +] + +[tool.tox] +legacy_tox_ini = """ +[tox] +envlist = py310 +isolated_build = true +skip_missing_interpreters = true +requires = tox-conda + +[testenv] +conda_deps = + pytest + pytest-cov + coverage +conda_channels = + conda-forge +conda_env = environment.yml +commands = pytest --cov --cov-report=term tests +""" + +[tool.mypy] +check_untyped_defs = true +disallow_any_generics = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_defs = true +no_implicit_optional = true +#no_implicit_reexport = true +show_column_numbers = true +show_error_codes = true +show_error_context = true +strict_equality = true +strict_optional = true +warn_redundant_casts = true +#warn_return_any = true +warn_unreachable = true +warn_unused_configs = true +warn_unused_ignores = true +exclude= "src/bcf/v(2|3)/model" +plugins = "numpy.typing.mypy_plugin" + +[[tool.mypy.overrides]] +module = "tests" +disallow_untyped_decorators = false +disallow_untyped_defs = false + +[[tool.mypy.overrides]] +module = [ + "pytest", + "pytest_mock", + "ifcopenshell", + "ifcopenshell.*", +] +ignore_missing_imports = true + +[tool.pylint.main] +ignore = ["model"] +ignored-modules = ["bcf.v2.model", "bcf.v3.model", "xsdata"] +jobs = 0 +disable="all" +enable="E" # B,B9,BLK,C,D,E,F,I,N,S,W + +[tool.pylint.design] +max-args = 10 +max-attributes = 10 + +[tool.pylint.format] +expected-line-ending-format = "LF" +max-line-length = 120 diff --git a/src/bcf/requirements-dev.txt b/src/bcf/requirements-dev.txt new file mode 100644 index 0000000000..12033556c7 --- /dev/null +++ b/src/bcf/requirements-dev.txt @@ -0,0 +1,7 @@ +black +mypy +pylint +isort +xsdata +tox +tox-conda diff --git a/src/bcf/requirements.txt b/src/bcf/requirements.txt deleted file mode 100644 index 648a39d330..0000000000 --- a/src/bcf/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -xmlschema \ No newline at end of file diff --git a/src/bcf/setup.cfg b/src/bcf/setup.cfg deleted file mode 100644 index 3eba915750..0000000000 --- a/src/bcf/setup.cfg +++ /dev/null @@ -1,37 +0,0 @@ -[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 diff --git a/src/bcf/setup.py b/src/bcf/setup.py new file mode 100644 index 0000000000..606849326a --- /dev/null +++ b/src/bcf/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup() diff --git a/src/bcf/src/bcf/bcfxml.py b/src/bcf/src/bcf/bcfxml.py index e9bcde349f..00a2871e99 100644 --- a/src/bcf/src/bcf/bcfxml.py +++ b/src/bcf/src/bcf/bcfxml.py @@ -1,61 +1,69 @@ -# BCF - BCF Python library -# Copyright (C) 2021 Prabhat Singh -# -# 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 . +""" +BCF - BCF Python library +Copyright (C) 2021 Prabhat Singh +Copyright (C) 2022 Andrea Ghensi +This file is part of BCF. -import os.path +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 . +""" import zipfile -import tempfile -from xml.dom import minidom +from pathlib import Path +from typing import Optional, Union + +from bcf.v2.bcfxml import BcfXml as BcfXml2 +from bcf.v3.bcfxml import BcfXml as BcfXml3 +from bcf.v3.model import Version +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer -def load(filepath): - filepath = extract_project(filepath) - if os.path.isfile(os.path.join(filepath, "bcf.version")): - version_path = os.path.join(filepath, "bcf.version") - version_id = get_version(version_path) - # TODO: we actually coded it for 2.1, let's check the difference between 2.0 and 2.1 - if version_id == "2.1" or version_id == "2.0": - from bcf.v2.bcfxml import BcfXml +def load( + filepath: Path, xml_handler: Optional[AbstractXmlParserSerializer] = None +) -> Optional[Union[BcfXml2, BcfXml3]]: + """ + Load a BCF file. - bcfxml = BcfXml() - bcfxml.filepath = filepath - return bcfxml - elif version_id == "3.0": - from bcf.v3.bcfxml import BcfXml + Args: + filepath: The path to the BCF file. - bcfxml = BcfXml() - bcfxml.filepath = filepath - return bcfxml - else: - raise Exception(f"Version {version_id} not supported.") + Returns: + The loaded BCF file. + + Raises: + ValueError: If the BCF version is not supported. + """ + xml_handler = xml_handler or XmlParserSerializer() + version_id = _get_version(filepath, xml_handler) + if version_id in {"2.1", "2.0"}: + return BcfXml2.load(filepath, xml_handler) + if version_id == "3.0": + return BcfXml3.load(filepath, xml_handler) + raise ValueError(f"Version {version_id} not supported.") -def get_version(version_path): - xmlparse = minidom.parse(version_path) - version_el = xmlparse.getElementsByTagName("Version")[0] - version = version_el.getAttribute("VersionId") - return version +def _get_version(filepath: Union[str, Path], xml_handler: Optional[AbstractXmlParserSerializer] = None) -> str: + """ + Returns the version of the BCF file. + Args: + filepath: The path to the BCF file. + xml_handler: The XML handler. If none is given, XmlParserSerializer is used. -def extract_project(filepath): - if not filepath: - return - zip_file = zipfile.ZipFile(filepath) - filepath = tempfile.mkdtemp() - zip_file.extractall(filepath) - return filepath + Returns: + The version of the BCF file. + """ + xml_handler = xml_handler or XmlParserSerializer() + with zipfile.ZipFile(filepath) as bcf_zip: + version = xml_handler.parse(bcf_zip.read("bcf.version"), Version) + return version.version_id diff --git a/src/bcf/src/bcf/geometry.py b/src/bcf/src/bcf/geometry.py new file mode 100644 index 0000000000..130befcdb7 --- /dev/null +++ b/src/bcf/src/bcf/geometry.py @@ -0,0 +1,44 @@ +import numpy as np +from numpy.typing import NDArray + + +def calc_camera_vectors( + elem_placement: NDArray[np.float_], +) -> tuple[NDArray[np.float_], NDArray[np.float_], NDArray[np.float_]]: + """ + Calculate the vectors of a camera pointing to an element. + + Args: + elem_placement: Placement matrix of an element. + + Returns: + Camera position, direction and up vectors + """ + target_position = elem_placement[:3, 3] + camera_position = target_position + np.array((5, 5, 5)) + camera_direction = unit_vector(camera_position - target_position) + camera_right = unit_vector(np.cross(np.array([0.0, 0.0, 1.0]), camera_direction)) + camera_up = unit_vector(np.cross(camera_direction, camera_right)) + rotation_transform = np.eye(4) + rotation_transform[0, :3] = camera_right + rotation_transform[1, :3] = camera_up + rotation_transform[2, :3] = camera_direction + translation_transform = np.eye(4) + translation_transform[:3, -1] = -camera_position + look_at_transform = np.matmul(rotation_transform, translation_transform) + mat = np.linalg.inv(look_at_transform) + return camera_position, -mat[:3, 2], mat[:3, 1] + + +def unit_vector(v: NDArray[np.float_]) -> NDArray[np.float_]: + """ + Return the unit vector of a vector. + + Args: + v: vector + + Returns: + unit vector. + """ + norm = np.linalg.norm(v) + return v if norm == 0 else v / norm diff --git a/src/bcf/src/bcf/inmemory_zipfile.py b/src/bcf/src/bcf/inmemory_zipfile.py new file mode 100644 index 0000000000..c78e9f9a74 --- /dev/null +++ b/src/bcf/src/bcf/inmemory_zipfile.py @@ -0,0 +1,55 @@ +""" +In Memory Zip File management, taken from ruamel.std.zipfile + +Copyright (c) 2017-2020 Anthon van der Neut, Ruamel bvba + +original idea from https://stackoverflow.com/a/19722365/1307905 +""" +import zipfile +from io import BytesIO +from os import PathLike +from pathlib import Path +from typing import Any, Optional, Protocol + + +class ZipFileInterface(Protocol): + def writestr(self, filename_in_zip: str | zipfile.ZipInfo, file_contents: bytes | str) -> None: + ... + + +class InMemoryZipFile: + def __init__( + self, file_name: Optional[str | Path] = None, compression: int = zipfile.ZIP_DEFLATED, debug: int = 0 + ) -> None: + # Create the in-memory file-like object + self._file_name: Optional[str | Path] = str(file_name) if hasattr(file_name, "_from_parts") else file_name + self.in_memory_data = BytesIO() + # Create the in-memory zipfile + self.in_memory_zip = zipfile.ZipFile(self.in_memory_data, "w", compression, False) + self.in_memory_zip.debug = debug + + def writestr(self, filename_in_zip: str | zipfile.ZipInfo, file_contents: bytes | str) -> None: + """Appends a file with name filename_in_zip and contents of + file_contents to the in-memory zip.""" + self.in_memory_zip.writestr(filename_in_zip, file_contents) + + def write_to_file(self, filename: str | bytes | PathLike[str] | PathLike[bytes] | int) -> None: + """Writes the in-memory zip to a file.""" + # Mark the files as having been created on Windows so that + # Unix permissions are not inferred as 0000 + for zfile in self.in_memory_zip.filelist: + zfile.create_system = 0 + self.in_memory_zip.close() + with open(filename, "wb") as f: + f.write(self.data) + + @property + def data(self) -> bytes: + return self.in_memory_data.getvalue() + + def __enter__(self) -> "InMemoryZipFile": + return self + + def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: + if self._file_name: + self.write_to_file(self._file_name) diff --git a/src/bcf/src/bcf/py.typed b/src/bcf/src/bcf/py.typed new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bcf/src/bcf/v2/__init__.py b/src/bcf/src/bcf/v2/__init__.py index adb79b4034..d4e76a1eb8 100644 --- a/src/bcf/src/bcf/v2/__init__.py +++ b/src/bcf/src/bcf/v2/__init__.py @@ -1,4 +1,3 @@ - # BCF - BCF Python library # Copyright (C) 2020, 2021 Dion Moult # @@ -16,4 +15,3 @@ # # You should have received a copy of the GNU Lesser General Public License # along with BCF. If not, see . - diff --git a/src/bcf/src/bcf/v2/bcfxml.py b/src/bcf/src/bcf/v2/bcfxml.py index 61a91d0267..4702526379 100644 --- a/src/bcf/src/bcf/v2/bcfxml.py +++ b/src/bcf/src/bcf/v2/bcfxml.py @@ -1,790 +1,273 @@ - -# BCF - BCF Python library -# Copyright (C) 2020, 2021 Dion Moult -# -# 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 . - -import os +"""BCF XML V2 handler.""" import uuid -import shutil +import warnings import zipfile -import logging -import tempfile -import bcf.v2.data -from datetime import datetime -from xml.dom import minidom -from xmlschema import XMLSchema -from contextlib import contextmanager -from shutil import copyfile +from pathlib import Path +from typing import Any, Optional, TypeVar +import bcf.v2.model as mdl +from bcf.inmemory_zipfile import InMemoryZipFile, ZipFileInterface +from bcf.v2.topic import TopicHandler +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer -cwd = os.path.dirname(os.path.realpath(__file__)) - - -@contextmanager -def cd(newdir): - prevdir = os.getcwd() - os.chdir(os.path.expanduser(newdir)) - try: - yield - finally: - os.chdir(prevdir) +T = TypeVar("T") class BcfXml: - def __init__(self): - self.filepath = None - self.logger = logging.getLogger("bcfxml") - self.author = "john@doe.com" - self.project = bcf.v2.data.Project() - self.version = "2.1" - self.topics = {} + """BCF XML handler.""" - def new_project(self): - self.project.project_id = str(uuid.uuid4()) - self.project.name = "New Project" - self.topics = {} - if self.filepath: - self.close_project() - self.filepath = tempfile.mkdtemp() - self.edit_project() - self.edit_version() + def __init__( + self, filename: Optional[Path] = None, xml_handler: Optional[AbstractXmlParserSerializer] = None + ) -> None: + self._filename = filename + self._xml_handler = xml_handler or XmlParserSerializer() + self._version: Optional[mdl.Version] = None + self._project_info: Optional[mdl.ProjectExtension] = None + self._topics: dict[str, TopicHandler] = {} + self._extension_schema: Optional[bytes] = None + self._zip_file = self._load_zip_file() - def get_project(self, filepath=None): - if not filepath: - return self.project - if os.path.isfile(os.path.join(self.filepath, "project.bcfp")): - data = self._read_xml("project.bcfp", "project.xsd") - self.project.extension_schema = data["ExtensionSchema"] - if "Project" in data: - self.project.project_id = data["Project"]["@ProjectId"] - self.project.name = data["Project"].get("Name") + def __enter__(self) -> "BcfXml": + return self + + def __exit__(self, *args: Any) -> None: + self.close() + + def __del__(self) -> None: + self.close() + + def close(self) -> None: + if self._zip_file: + self._zip_file.close() + + def _load_zip_file(self) -> Optional[zipfile.ZipFile]: + return zipfile.ZipFile(self._filename) if self._filename else None + + @property + def version(self) -> mdl.Version: + """Bcf Version.""" + if not self._version: + self._version = ( + self._xml_handler.parse(self._zip_file.read("bcf.version"), mdl.Version) + if self._zip_file + else mdl.Version(version_id="3.0") + ) + return self._version + + @version.setter + def version(self, value: mdl.Version) -> None: + self._version = value + + @property + def project_info(self) -> Optional[mdl.ProjectExtension]: + """BCF project information.""" + if not self._project_info and self._zip_file and zipfile.Path(self._zip_file, "project.bcfp").exists(): + self._project_info = self._xml_handler.parse(self._zip_file.read("project.bcfp"), mdl.ProjectExtension) + return self._project_info + + @project_info.setter + def project_info(self, value: Optional[mdl.ProjectExtension]) -> None: + self._project_info = value + + @property + def project(self) -> Optional[mdl.Project]: + """BCF project.""" + return self.project_info.project if self.project_info else None + + @property + def extension_schema(self) -> Optional[bytes]: + if not self._extension_schema and self._zip_file and self.project_info and self.project_info.extension_schema: + self._extension_schema = self._zip_file.read(self.project_info.extension_schema) + return self._extension_schema + + @extension_schema.setter + def extension_schema(self, value: bytes) -> None: + self._extension_schema = value + + @property + def topics(self) -> dict[str, TopicHandler]: + """BCF topics.""" + if not self._topics and self._zip_file: + self._topics = self._load_topics(self._zip_file, self._xml_handler) + return self._topics + + def _load_topics( + self, zip_file: zipfile.ZipFile, xml_handler: AbstractXmlParserSerializer + ) -> dict[str, TopicHandler]: + topics = {} + for topic_dir in zipfile.Path(zip_file).iterdir(): + if not topic_dir.is_dir(): + continue + markup_path = topic_dir.joinpath("markup.bcf") + if not markup_path.exists(): + continue + topics[topic_dir.name] = TopicHandler(topic_dir, xml_handler) + return topics + + @classmethod + def load(cls, filename: Path, xml_handler: Optional[AbstractXmlParserSerializer] = None) -> Optional["BcfXml"]: + """ + Create a BcfXml object from a file. + + Args: + filename: Path to the file. + xml_handler: XML parser and serializer. + + Returns: + A BcfXml object with the file contents. + + Raises: + ValueError: If the file name is null or empty + """ + if not filename: + raise ValueError("filename is required") + xml_handler = xml_handler or XmlParserSerializer() + return cls(xml_handler=xml_handler, filename=filename) + + @classmethod + def create_new( + cls, + project_name: Optional[str] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> "BcfXml": + """ + Create a new BcfXml object. + + Args: + project_name: The name of the project. + xml_handler: XML parser and serializer. + + Returns: + A new BcfXml object. + """ + instance = cls(xml_handler=xml_handler or XmlParserSerializer()) + instance.project_info = mdl.ProjectExtension( + project=mdl.Project(name=project_name, project_id=str(uuid.uuid4())), extension_schema="" + ) + return instance + + def save(self, filename: Optional[Path] = None, keep_open: bool = False) -> None: + """Save the BCF file to the given filename.""" + if not filename and not self._filename: + raise ValueError("No file name specified, cannot save BCF file.") + if filename: + self._filename = filename + with InMemoryZipFile(self._filename) as bcf_zip: + self._save_project(bcf_zip) + self._save_version(bcf_zip) + self._save_topics(bcf_zip) + if keep_open: + self._zip_file = self._load_zip_file() + + def _save_project(self, destination_zip: ZipFileInterface) -> None: + self._smart_save_xml(destination_zip, self._project_info, "project.bcfp") + if self.extension_schema and self.project_info: + destination_zip.writestr(self.project_info.extension_schema, self.extension_schema) + + def _save_version(self, destination_zip: ZipFileInterface) -> None: + if not self._version and self._zip_file: + destination_zip.writestr("bcf.version", self._zip_file.read("bcf.version")) + else: + self._save_xml(destination_zip, "bcf.version", self.version) + + def _smart_save_xml(self, destination_zip: ZipFileInterface, item: Any, target: str) -> None: + if item: + self._save_xml(destination_zip, target, item) + elif self._zip_file and zipfile.Path(self._zip_file, target).exists(): + destination_zip.writestr(target, self._zip_file.read(target)) + + def _save_xml(self, destination_zip: ZipFileInterface, inner_file: str, xml_obj: Any) -> None: + destination_zip.writestr(inner_file, self._xml_handler.serialize(xml_obj)) + + def _save_topics(self, destination_zip: ZipFileInterface) -> None: + for topic_handler in self.topics.values(): + topic_handler.save(destination_zip) + + def add_topic( + self, title: str, description: str, author: str, topic_type: str = "", topic_status: str = "" + ) -> TopicHandler: + """ + Add a new topic to the BCF. + + Args: + title: The title of the topic. + description: The description of the topic. + author: The author of the topic. + topic_type: The type of the topic. + topic_status: The status of the topic. + + Returns: + The newly created topic wrapped inside a TopicHandler object. + """ + topic_handler = TopicHandler.create_new( + title, + description, + author, + topic_type=topic_type, + topic_status=topic_status, + xml_handler=self._xml_handler, + ) + self.topics[topic_handler.guid] = topic_handler + return topic_handler + + def __eq__(self, other: object) -> bool: + if not isinstance(other, BcfXml): + raise TypeError("Equality needs a BcfXml object.") + return self.version == other.version and self.project_info == other.project_info + + # region Deprecated methods + def new_project(self) -> "BcfXml": + """Deprecated method.""" + warnings.warn("new_project is deprecated, use create_new instead.", DeprecationWarning) + return self.create_new() + + def get_project(self, _filepath: Optional[str] = None) -> Optional[mdl.Project]: + """Deprecated method.""" + warnings.warn("get_project is deprecated, use project_info.project instead.", DeprecationWarning) return self.project - def edit_project(self): - self.document = minidom.Document() - root = self._create_element(self.document, "ProjectExtension") - project = self._create_element(root, "Project", {"ProjectId": self.project.project_id}) - self._create_element(project, "Name", text=self.project.name) - self._create_element(root, "ExtensionSchema", text="extensions.xsd") - with open(os.path.join(self.filepath, "project.bcfp"), "wb") as f: - f.write(self.document.toprettyxml(encoding="utf-8")) + def edit_project(self) -> None: + """Deprecated method.""" + warnings.warn("edit_project is deprecated, there's no need to use it.", DeprecationWarning) - def save_project(self, filepath): - with cd(self.filepath): - zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED) - for root, dirs, files in os.walk("./"): - for file in files: - zip_file.write(os.path.join(root, file)) - zip_file.close() + def save_project(self, filepath: Path) -> None: + """Deprecated method.""" + warnings.warn("save_project is deprecated, use save instead.", DeprecationWarning) + self.save(filepath) - def get_version(self): - data = self._read_xml("bcf.version", "version.xsd") - self.version = data["@VersionId"] - return self.version + def get_version(self) -> Optional[str]: + warnings.warn("get_version is deprecated, use version.version_id instead.", DeprecationWarning) + return self.version.version_id - def edit_version(self): - self.document = minidom.Document() - root = self._create_element(self.document, "Version", {"VersionId": self.version}) - version = self._create_element(root, "DetailedVersion", text=self.version) - with open(os.path.join(self.filepath, "bcf.version"), "wb") as f: - f.write(self.document.toprettyxml(encoding="utf-8")) + def edit_version(self) -> None: + """Deprecated method.""" + warnings.warn("edit_version is deprecated, there's no need to use it.", DeprecationWarning) - def get_topics(self): - self.topics = {} - topics = [] - subdirs = [] - for (dirpath, dirnames, filenames) in os.walk(self.filepath): - subdirs = dirnames - break - for subdir in subdirs: - try: - uuid.UUID(subdir) - except ValueError: - continue - if not os.path.exists(os.path.join(self.filepath, subdir, "markup.bcf")): - continue - self.topics[subdir] = self.get_topic(subdir) + def get_topics(self) -> dict[str, TopicHandler]: + """Deprecated method.""" + warnings.warn("get_topics is deprecated, use topics instead.", DeprecationWarning) return self.topics - def get_header(self, guid): - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - if "Header" not in data: - return - header = bcf.v2.data.Header() - for item in data["Header"]["File"]: - header_file = bcf.v2.data.HeaderFile() - optional_keys = { - "filename": "Filename", - "date": "Date", - "reference": "Reference", - "ifc_project": "@IfcProject", - "ifc_spatial_structure_element": "@IfcSpatialStructureElement", - "is_external": "@isExternal", - } - for key, value in optional_keys.items(): - if value in item: - setattr(header_file, key, item[value]) - header.files.append(header_file) - self.topics[guid].header = header - return header + def get_topic(self, guid: str) -> TopicHandler: + """Return a topic by its GUID.""" + warnings.warn("get_topic is deprecated, use topics[guid] instead", DeprecationWarning) + return self.topics[guid] - def get_topic(self, guid): - if guid in self.topics: - return self.topics[guid] - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - topic = bcf.v2.data.Topic() - self.topics[guid] = topic + def get_header(self, guid: str) -> Optional[mdl.Header]: + """Return the header of a Topic by its GUID.""" + return self.topics[guid].header - mandatory_keys = { - "guid": "@Guid", - "title": "Title", - "creation_date": "CreationDate", - "creation_author": "CreationAuthor", - } - for key, value in mandatory_keys.items(): - setattr(topic, key, data["Topic"][value]) + def edit_topic(self) -> None: + """Deprecated method.""" + warnings.warn("edit_topic is deprecated, there's no need to use it.", DeprecationWarning) - optional_keys = { - "priority": "Priority", - "index": "Index", - "labels": "Labels", - "reference_links": "ReferenceLink", - "modified_date": "ModifiedDate", - "modified_author": "ModifiedAuthor", - "due_date": "DueDate", - "assigned_to": "AssignedTo", - "stage": "Stage", - "description": "Description", - "topic_status": "@TopicStatus", - "topic_type": "@TopicType", - } - for key, value in optional_keys.items(): - if value in data["Topic"]: - setattr(topic, key, data["Topic"][value]) + def add_comment(self, _topic: mdl.Topic, _comment: Optional[mdl.Comment] = None) -> None: + """Deprecated method.""" + warnings.warn("add_comment is deprecated, use topics methods instead.", DeprecationWarning) - if "BimSnippet" in data["Topic"]: - bim_snippet = bcf.v2.data.BimSnippet() - keys = { - "snippet_type": "@SnippetType", - "is_external": "@IsExternal", - "reference": "Reference", - "reference_schema": "ReferenceSchema", - } - for key, value in keys.items(): - if value in data["Topic"]["BimSnippet"]: - setattr(bim_snippet, key, data["Topic"]["BimSnippet"][value]) - topic.bim_snippet = bim_snippet + def edit_comment(self) -> None: + """Deprecated method.""" + warnings.warn("edit_comment is deprecated, there's no need to use it.", DeprecationWarning) - if "DocumentReference" in data["Topic"]: - for item in data["Topic"]["DocumentReference"]: - document_reference = bcf.v2.data.DocumentReference() - keys = { - "referenced_document": "ReferencedDocument", - "is_external": "@IsExternal", - "guid": "@Guid", - "description": "Description", - } - for key, value in keys.items(): - if value in item: - setattr(document_reference, key, item[value]) - topic.document_references.append(document_reference) - - if "RelatedTopic" in data["Topic"]: - for item in data["Topic"]["RelatedTopic"]: - related_topic = bcf.v2.data.RelatedTopic() - related_topic.guid = item["@Guid"] - topic.related_topics.append(related_topic) - return topic - - def add_topic(self, topic=None): - if topic is None: - topic = bcf.v2.data.Topic() - if not topic.guid: - topic.guid = str(uuid.uuid4()) - if not topic.title: - topic.title = "New Topic" - os.mkdir(os.path.join(self.filepath, topic.guid)) - self.edit_topic(topic) - return topic - - def edit_topic(self, topic): - if not topic.creation_date: - topic.creation_date = datetime.utcnow().replace(microsecond=0).isoformat() - topic.creation_author = self.author - else: - topic.modified_date = datetime.utcnow().replace(microsecond=0).isoformat() - topic.modified_author = self.author - - self.document = minidom.Document() - root = self._create_element(self.document, "Markup") - - self.write_header(topic.header, root) - - topic_el = self._create_element( - root, - "Topic", - { - "Guid": topic.guid, - "TopicType": topic.topic_type, - "TopicStatus": topic.topic_status, - }, - ) - - for reference_link in topic.reference_links: - self._create_element(topic_el, "ReferenceLink", text=reference_link) - - text_map = { - "Title": topic.title, - "Priority": topic.priority, - "Index": topic.index, - } - for key, value in text_map.items(): - if value: - self._create_element(topic_el, key, text=value) - - for label in topic.labels: - self._create_element(topic_el, "Labels", text=label) - - text_map = { - "CreationDate": topic.creation_date, - "CreationAuthor": topic.creation_author, - "ModifiedDate": topic.modified_date, - "ModifiedAuthor": topic.modified_author, - "DueDate": topic.due_date, - "AssignedTo": topic.assigned_to, - "Stage": topic.stage, - "Description": topic.description, - } - for key, value in text_map.items(): - if value: - self._create_element(topic_el, key, text=value) - - if topic.bim_snippet: - bim_snippet = self._create_element( - topic_el, - "BimSnippet", - {"SnippetType": topic.bim_snippet.snippet_type, "isExternal": topic.bim_snippet.is_external}, - ) - self._create_element(bim_snippet, "Reference", text=topic.bim_snippet.reference) - self._create_element(bim_snippet, "ReferenceSchema", text=topic.bim_snippet.reference_schema) - for reference in topic.document_references: - reference_el = self._create_element( - topic_el, "DocumentReference", {"Guid": reference.guid, "isExternal": reference.is_external} - ) - self._create_element(reference_el, "ReferencedDocument", text=reference.referenced_document) - self._create_element(reference_el, "Description", text=reference.description) - for related_topic in topic.related_topics: - self._create_element(topic_el, "RelatedTopic", {"Guid": related_topic.guid}) - - self.write_comments(topic.comments, root) - self.write_viewpoints(topic.viewpoints, root, topic) - - with open(os.path.join(self.filepath, topic.guid, "markup.bcf"), "wb") as f: - f.write(self.document.toprettyxml(encoding="utf-8")) - - def write_header(self, header, root): - if not header or not header.files: - return - header_el = self._create_element(root, "Header") - for f in header.files: - file_el = self._create_element( - header_el, - "File", - { - "IfcProject": f.ifc_project, - "IfcSpatialStructureElement": f.ifc_spatial_structure_element, - "isExternal": f.is_external, - }, - ) - if f.filename: - self._create_element(file_el, "Filename", text=f.filename) - if f.date: - self._create_element(file_el, "Date", text=f.date) - if f.reference: - self._create_element(file_el, "Reference", text=f.reference) - - def write_comments(self, comments, root): - for comment in comments.values(): - comment_el = self._create_element(root, "Comment", {"Guid": comment.guid}) - text_map = { - "Date": comment.date, - "Author": comment.author, - "Comment": comment.comment, - "ModifiedDate": comment.modified_date, - "ModifiedAuthor": comment.modified_author, - } - for key, value in text_map.items(): - if value: - self._create_element(comment_el, key, text=value) - if comment.viewpoint: - self._create_element(comment_el, "Viewpoint", {"Guid": comment.viewpoint.guid}) - - def add_comment(self, topic, comment=None): - if comment is None: - comment = bcf.v2.data.Comment() - if not comment.guid: - comment.guid = str(uuid.uuid4()) - if not comment.comment: - comment.comment = "'Free software' is a matter of liberty, not price. To understand the concept, you should think of 'free' as in 'free speech,' not as in 'free beer'." - topic.comments[comment.guid] = comment - self.edit_comment(comment, topic) - - def edit_comment(self, comment, topic): - if not comment.date: - comment.date = datetime.utcnow().replace(microsecond=0).isoformat() - comment.author = self.author - else: - comment.modified_date = datetime.utcnow().replace(microsecond=0).isoformat() - comment.modified_author = self.author - self.edit_topic(topic) - - def delete_comment(self, guid, topic): - if guid in topic.comments: - del topic.comments[guid] - self.edit_topic(topic) - - def delete_topic(self, guid): - if guid in self.topics: - del self.topics[guid] - shutil.rmtree(os.path.join(self.filepath, guid)) - - def write_viewpoints(self, viewpoints, root, topic): - for viewpoint in viewpoints.values(): - viewpoint_el = self._create_element(root, "Viewpoints", {"Guid": viewpoint.guid}) - text_map = {"Viewpoint": viewpoint.viewpoint, "Snapshot": viewpoint.snapshot, "Index": viewpoint.index} - for key, value in text_map.items(): - if value: - self._create_element(viewpoint_el, key, text=value) - self.write_viewpoint(viewpoint, topic) - - def write_viewpoint(self, viewpoint, topic): - document = minidom.Document() - root = self._create_element(document, "VisualizationInfo", {"Guid": viewpoint.guid}) - self.write_viewpoint_components(viewpoint, root) - self.write_viewpoint_orthogonal_camera(viewpoint, root) - self.write_viewpoint_perspective_camera(viewpoint, root) - self.write_viewpoint_lines(viewpoint, root) - self.write_viewpoint_clipping_planes(viewpoint, root) - self.write_viewpoint_bitmaps(viewpoint, root) - with open(os.path.join(self.filepath, topic.guid, viewpoint.viewpoint), "wb") as f: - f.write(document.toprettyxml(encoding="utf-8")) - - def write_viewpoint_components(self, viewpoint, parent): - if not viewpoint.components: - return - components_el = self._create_element(parent, "Components") - if viewpoint.components.view_setup_hints: - view_setup_hints = self._create_element( - components_el, - "ViewSetupHints", - { - "SpacesVisible": viewpoint.components.view_setup_hints.spaces_visible, - "SpaceBoundariesVisible": viewpoint.components.view_setup_hints.space_boundaries_visible, - "OpeningsVisible": viewpoint.components.view_setup_hints.openings_visible, - }, - ) - if viewpoint.components.selection: - selection_el = self._create_element(components_el, "Selection") - for selection in viewpoint.components.selection: - self.write_component(selection, selection_el) - visibility = self._create_element( - components_el, "Visibility", {"DefaultVisibility": viewpoint.components.visibility.default_visibility} - ) - if viewpoint.components.visibility.exceptions: - exceptions_el = self._create_element(visibility, "Exceptions") - for exception in viewpoint.components.visibility.exceptions: - self.write_component(exception, exceptions_el) - if viewpoint.components.coloring: - coloring_el = self._create_element(components_el, "Coloring") - for color in viewpoint.components.coloring: - color_el = self._create_element(coloring_el, "Color", {"Color": color.color}) - for component in color.components: - self.write_component(component, color_el) - - def write_viewpoint_orthogonal_camera(self, viewpoint, parent): - if not viewpoint.orthogonal_camera: - return - camera = viewpoint.orthogonal_camera - camera_el = self._create_element(parent, "OrthogonalCamera") - camera_view_point = self._create_element(camera_el, "CameraViewPoint") - self.write_vector(camera_view_point, camera.camera_view_point) - camera_direction = self._create_element(camera_el, "CameraDirection") - self.write_vector(camera_direction, camera.camera_direction) - camera_up_vector = self._create_element(camera_el, "CameraUpVector") - self.write_vector(camera_up_vector, camera.camera_up_vector) - self._create_element(camera_el, "ViewToWorldScale", text=camera.view_to_world_scale) - - def write_viewpoint_perspective_camera(self, viewpoint, parent): - if not viewpoint.perspective_camera: - return - camera = viewpoint.perspective_camera - camera_el = self._create_element(parent, "PerspectiveCamera") - camera_view_point = self._create_element(camera_el, "CameraViewPoint") - self.write_vector(camera_view_point, camera.camera_view_point) - camera_direction = self._create_element(camera_el, "CameraDirection") - self.write_vector(camera_direction, camera.camera_direction) - camera_up_vector = self._create_element(camera_el, "CameraUpVector") - self.write_vector(camera_up_vector, camera.camera_up_vector) - self._create_element(camera_el, "FieldOfView", text=camera.field_of_view) - - def write_viewpoint_lines(self, viewpoint, parent): - if not viewpoint.lines: - return - lines_el = self._create_element(parent, "Lines") - for line in viewpoint.lines: - line_el = self._create_element(lines_el, "Line") - start_point_el = self._create_element(line_el, "StartPoint") - self.write_vector(start_point_el, line.start_point) - end_point_el = self._create_element(line_el, "EndPoint") - self.write_vector(end_point_el, line.end_point) - - def write_viewpoint_clipping_planes(self, viewpoint, parent): - if not viewpoint.clipping_planes: - return - planes_el = self._create_element(parent, "ClippingPlanes") - for plane in viewpoint.clipping_planes: - plane_el = self._create_element(planes_el, "ClippingPlane") - location_el = self._create_element(plane_el, "Location") - self.write_vector(location_el, plane.location) - direction_el = self._create_element(plane_el, "Direction") - self.write_vector(direction_el, plane.direction) - - def write_viewpoint_bitmaps(self, viewpoint, parent): - if not viewpoint.bitmaps: - return - for bitmap in viewpoint.bitmaps: - bitmap_el = self._create_element(parent, "Bitmap") - - text_map = {"Bitmap": bitmap.bitmap_format, "Reference": bitmap.reference} - for key, value in text_map.items(): - self._create_element(bitmap_el, key, text=value) - - location_el = self._create_element(bitmap_el, "Location") - self.write_vector(location_el, bitmap.location) - normal_el = self._create_element(bitmap_el, "Normal") - self.write_vector(normal_el, bitmap.normal) - up_el = self._create_element(bitmap_el, "Up") - self.write_vector(up_el, bitmap.up) - - self._create_element(bitmap_el, "Height", text=bitmap.height) - - def write_vector(self, parent, from_obj): - self._create_element(parent, "X", text=from_obj.x) - self._create_element(parent, "Y", text=from_obj.y) - self._create_element(parent, "Z", text=from_obj.z) - - def write_component(self, data, parent): - component_el = self._create_element(parent, "Component", {"IfcGuid": data.ifc_guid}) - text_map = {"OriginatingSystem": data.originating_system, "AuthoringToolId": data.authoring_tool_id} - for key, value in text_map.items(): - if value: - self._create_element(component_el, key, text=value) - - def add_viewpoint(self, topic, viewpoint=None): - if not viewpoint: - viewpoint = bcf.v2.data.Viewpoint() - if not viewpoint.guid: - viewpoint.guid = str(uuid.uuid4()) - if not viewpoint.viewpoint: - viewpoint.viewpoint = f"{viewpoint.guid}.bcfv" - if viewpoint.snapshot: - topic_filepath = os.path.join(self.filepath, topic.guid) - filepath = os.path.join(topic_filepath, viewpoint.snapshot) - if not os.path.exists(filepath): - filename = viewpoint.guid + os.path.splitext(viewpoint.snapshot)[-1] - copyfile(viewpoint.snapshot, os.path.join(topic_filepath, filename)) - viewpoint.snapshot = filename - topic.viewpoints[viewpoint.guid] = viewpoint - self.edit_topic(topic) - - def delete_viewpoint(self, guid, topic): - if guid not in topic.viewpoints: - return - viewpoint = topic.viewpoints[guid] - if viewpoint.snapshot: - filepath = os.path.join(self.filepath, topic.guid, viewpoint.snapshot) - if os.path.exists(filepath): - os.remove(filepath) - if viewpoint.viewpoint: - filepath = os.path.join(self.filepath, topic.guid, viewpoint.viewpoint) - if os.path.exists(filepath): - os.remove(filepath) - for bitmap in viewpoint.bitmaps: - if not bitmap.reference: - continue - filepath = os.path.join(self.filepath, topic.guid, bitmap.reference) - if os.path.exists(filepath): - os.remove(filepath) - del topic.viewpoints[guid] - self.edit_topic(topic) - - def delete_file(self, topic, index): - if not topic.header: - return - f = topic.header.files.pop(index) - filepath = os.path.join(self.filepath, topic.guid, f.reference) - if not f.is_external and os.path.exists(filepath): - os.remove(filepath) - self.edit_topic(topic) - - def delete_bim_snippet(self, topic): - if not topic.bim_snippet: - return - if topic.bim_snippet.reference and not topic.bim_snippet.is_external: - filepath = os.path.join(self.filepath, topic.guid, topic.bim_snippet.reference) - if os.path.exists(filepath): - os.remove(filepath) - topic.bim_snippet = None - self.edit_topic(topic) - - def delete_document_reference(self, topic, index): - document_reference = topic.document_references[index] - if document_reference.referenced_document and not document_reference.is_external: - filepath = os.path.join(self.filepath, topic.guid, document_reference.referenced_document) - if os.path.exists(filepath): - os.remove(filepath) - del topic.document_references[index] - self.edit_topic(topic) - - def add_document_reference(self, topic, document_reference): - if os.path.exists(document_reference.referenced_document): - topic_filepath = os.path.join(self.filepath, topic.guid) - filename = os.path.basename(document_reference.referenced_document) - copyfile(document_reference.referenced_document, os.path.join(topic_filepath, filename)) - document_reference.referenced_document = filename - document_reference.is_external = False - else: - document_reference.is_external = True - if not document_reference.guid: - document_reference.guid = str(uuid.uuid4()) - topic.document_references.append(document_reference) - self.edit_topic(topic) - - def add_bim_snippet(self, topic, bim_snippet): - if topic.bim_snippet: - self.delete_bim_snippet(topic) - if os.path.exists(bim_snippet.reference): - topic_filepath = os.path.join(self.filepath, topic.guid) - filename = os.path.basename(bim_snippet.reference) - copyfile(bim_snippet.reference, os.path.join(topic_filepath, filename)) - bim_snippet.reference = filename - bim_snippet.is_external = False - else: - bim_snippet.is_external = True - topic.bim_snippet = bim_snippet - self.edit_topic(topic) - - def add_file(self, topic, header_file): - if os.path.exists(header_file.reference): - topic_filepath = os.path.join(self.filepath, topic.guid) - header_file.filename = os.path.basename(header_file.reference) - copyfile(header_file.reference, os.path.join(topic_filepath, header_file.filename)) - header_file.reference = header_file.filename - header_file.is_external = False - header_file.date = datetime.utcnow().replace(microsecond=0).isoformat() - if not topic.header: - topic.header = bcf.v2.data.Header() - topic.header.files.append(header_file) - self.edit_topic(topic) - - def get_comments(self, guid): - comments = {} - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - if "Comment" not in data: - return comments - for item in data["Comment"]: - comment = bcf.v2.data.Comment() - mandatory_keys = {"guid": "@Guid", "date": "Date", "author": "Author", "comment": "Comment"} - for key, value in mandatory_keys.items(): - setattr(comment, key, item[value]) - optional_keys = {"modified_date": "ModifiedDate", "modified_author": "ModifiedAuthor"} - for key, value in optional_keys.items(): - if value in item: - setattr(comment, key, item[value]) - if "Viewpoint" in item: - viewpoint = bcf.v2.data.Viewpoint() - viewpoint.guid = item["Viewpoint"]["@Guid"] - comment.viewpoint = viewpoint - comments[comment.guid] = comment - self.topics[guid].comments = comments - return comments - - def get_viewpoints(self, guid): - viewpoints = {} - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - if "Viewpoints" not in data: - return viewpoints - for item in data["Viewpoints"]: - viewpoint = self.get_viewpoint(item, guid) - viewpoints[viewpoint.guid] = viewpoint - self.topics[guid].viewpoints = viewpoints - return viewpoints - - def get_viewpoint(self, data, topic_guid): - viewpoint = bcf.v2.data.Viewpoint() - viewpoint.guid = data["@Guid"] - optional_keys = {"viewpoint": "Viewpoint", "snapshot": "Snapshot", "index": "Index"} - for key, value in optional_keys.items(): - if value in data: - setattr(viewpoint, key, data[value]) - visinfo = self._read_xml(os.path.join(topic_guid, viewpoint.viewpoint), "visinfo.xsd") - viewpoint.components = self.get_viewpoint_components(visinfo) - viewpoint.orthogonal_camera = self.get_viewpoint_orthogonal_camera(visinfo) - viewpoint.perspective_camera = self.get_viewpoint_perspective_camera(visinfo) - viewpoint.lines = self.get_viewpoint_lines(visinfo) - viewpoint.clipping_planes = self.get_viewpoint_clipping_planes(visinfo) - viewpoint.bitmaps = self.get_viewpoint_bitmaps(visinfo) - return viewpoint - - def get_viewpoint_components(self, visinfo): - if "Components" not in visinfo: - return None - components = bcf.v2.data.Components() - data = visinfo["Components"] - if "ViewSetupHints" in data: - view_setup_hints = bcf.v2.data.ViewSetupHints() - optional_keys = { - "spaces_visible": "@SpacesVisible", - "space_boundaries_visible": "@SpaceBoundariesVisible", - "openings_visible": "@OpeningsVisible", - } - for key, value in optional_keys.items(): - if value in data["ViewSetupHints"]: - setattr(view_setup_hints, key, data["ViewSetupHints"][value]) - components.view_setup_hints = view_setup_hints - if "Selection" in data and "Component" in data["Selection"]: - for item in data["Selection"]["Component"]: - components.selection.append(self.get_component(item)) - if "Visibility" in data: - component_visibility = bcf.v2.data.ComponentVisibility() - if "@DefaultVisibility" in data["Visibility"]: - component_visibility.default_visibility = data["Visibility"]["@DefaultVisibility"] - if "Exceptions" in data["Visibility"] and "Component" in data["Visibility"]["Exceptions"]: - for item in data["Visibility"]["Exceptions"]["Component"]: - component_visibility.exceptions.append(self.get_component(item)) - components.visibility = component_visibility - if "Coloring" in data and "Color" in data["Coloring"]: - for item in data["Coloring"]["Color"]: - color = bcf.v2.data.Color() - color.color = item["@Color"] - for item2 in item["Component"]: - color.components.append(self.get_component(item2)) - components.coloring.append(color) - return components - - def get_viewpoint_orthogonal_camera(self, visinfo): - if "OrthogonalCamera" not in visinfo: - return None - camera = bcf.v2.data.OrthogonalCamera() - data = visinfo["OrthogonalCamera"] - self.set_vector(camera.camera_view_point, data["CameraViewPoint"]) - self.set_vector(camera.camera_direction, data["CameraDirection"]) - self.set_vector(camera.camera_up_vector, data["CameraUpVector"]) - camera.view_to_world_scale = data["ViewToWorldScale"] - return camera - - def get_viewpoint_perspective_camera(self, visinfo): - if "PerspectiveCamera" not in visinfo: - return None - camera = bcf.v2.data.PerspectiveCamera() - data = visinfo["PerspectiveCamera"] - self.set_vector(camera.camera_view_point, data["CameraViewPoint"]) - self.set_vector(camera.camera_direction, data["CameraDirection"]) - self.set_vector(camera.camera_up_vector, data["CameraUpVector"]) - camera.field_of_view = data["FieldOfView"] - return camera - - def get_viewpoint_lines(self, visinfo): - if "Lines" not in visinfo: - return [] - lines = [] - for item in visinfo["Lines"]["Line"]: - line = bcf.v2.data.Line() - self.set_vector(line.start_point, item["StartPoint"]) - self.set_vector(line.end_point, item["EndPoint"]) - lines.append(line) - return lines - - def get_viewpoint_clipping_planes(self, visinfo): - if "ClippingPlanes" not in visinfo: - return [] - planes = [] - for item in visinfo["ClippingPlanes"]["ClippingPlane"]: - plane = bcf.v2.data.ClippingPlane() - self.set_vector(plane.location, item["Location"]) - self.set_vector(plane.direction, item["Direction"]) - planes.append(plane) - return planes - - def get_viewpoint_bitmaps(self, visinfo): - if "Bitmap" not in visinfo: - return [] - bitmaps = [] - for item in visinfo["Bitmap"]: - bitmap = bcf.v2.data.Bitmap() - bitmap.reference = item["Reference"] - bitmap.bitmap_format = item["Bitmap"].upper() - self.set_vector(bitmap.location, item["Location"]) - self.set_vector(bitmap.normal, item["Normal"]) - self.set_vector(bitmap.up, item["Up"]) - bitmap.height = item["Height"] - bitmaps.append(bitmap) - return bitmaps - - def set_vector(self, to_obj, from_xml): - to_obj.x = from_xml["X"] - to_obj.y = from_xml["Y"] - to_obj.z = from_xml["Z"] - - def get_component(self, data): - component = bcf.v2.data.Component() - optional_keys = { - "originating_system": "OriginatingSystem", - "authoring_tool_id": "AuthoringToolId", - "ifc_guid": "@IfcGuid", - } - for key, value in optional_keys.items(): - if value in data: - setattr(component, key, data[value]) - return component - - def close_project(self): - shutil.rmtree(self.filepath) - - def _read_xml(self, filename, xsd): - schema = XMLSchema(os.path.join(cwd, "xsd", xsd)) - filepath = os.path.join(self.filepath, filename) - (data, errors) = schema.to_dict(filepath, validation="lax") - for error in errors: - self.logger.error(error) - return data - - def _create_element(self, parent, name, attributes={}, text=None): - element = self.document.createElement(name) - for key, value in attributes.items(): - if isinstance(value, bool): - element.setAttribute(key, str(value).lower()) - elif value: - element.setAttribute(key, value) - if text is not None: - text = self.document.createTextNode(str(text)) - element.appendChild(text) - parent.appendChild(element) - return element - - def __del__(self): - self.close_project() + # TODO: deprecate other methods + # endregion diff --git a/src/bcf/src/bcf/v2/data.py b/src/bcf/src/bcf/v2/data.py deleted file mode 100644 index e79352dbd0..0000000000 --- a/src/bcf/src/bcf/v2/data.py +++ /dev/null @@ -1,198 +0,0 @@ - -# BCF - BCF Python library -# Copyright (C) 2020, 2021 Dion Moult -# -# 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 . - -class Project: - def __init__(self): - self.project_id = "" - self.name = "" - self.extension_schema = "" - - -class BimSnippet: - def __init__(self): - self.snippet_type = None - self.is_external = False - self.reference = None - self.reference_schema = None - - -class DocumentReference: - def __init__(self): - self.referenced_document = None - self.description = None - self.guid = None - self.is_external = False - - -class RelatedTopic: - def __init__(self): - self.guid = None - - -class HeaderFile: - def __init__(self): - self.filename = None - self.date = None - self.reference = None - self.ifc_project = None - self.ifc_spatial_structure_element = None - self.is_external = True - - -class Header: - def __init__(self): - self.files = [] - - -class Topic: - def __init__(self): - self.reference_links = [] - self.title = "" - self.priority = None - self.index = None # Deprecated, stored, but ignored - self.labels = [] - self.creation_date = None - self.creation_author = None - self.modified_date = None - self.modified_author = None - self.due_date = None - self.assigned_to = None - self.stage = None - self.description = None - self.bim_snippet = None - self.document_references = [] - self.related_topics = [] - self.topic_status = None - self.topic_type = None - self.guid = None - - self.header = None - self.comments = {} - self.viewpoints = {} - - -class Comment: - def __init__(self): - self.guid = None - self.date = None - self.author = None - self.comment = None - self.viewpoint = None - self.modified_date = None - self.modified_author = None - self.topic_guid = None # Part of BCF-API - - -class ViewSetupHints: - def __init__(self): - self.spaces_visible = False - self.space_boundaries_visible = False - self.openings_visible = False - - -class Component: - def __init__(self): - self.originating_system = None - self.authoring_tool_id = None - self.ifc_guid = None - - -class ComponentVisibility: - def __init__(self): - self.exceptions = [] - self.default_visibility = False - - -class Color: - def __init__(self): - self.color = None - self.components = [] - - -class Components: - def __init__(self): - self.view_setup_hints = None - self.selection = [] - self.visibility = None - self.coloring = [] - - -class Point: - def __init__(self): - self.x = 0 - self.y = 0 - self.z = 0 - - -class Direction(Point): - pass - - -class OrthogonalCamera: - def __init__(self): - self.camera_view_point = Point() - self.camera_direction = Direction() - self.camera_up_vector = Direction() - self.view_to_world_scale = 1.0 - - -class PerspectiveCamera: - def __init__(self): - self.camera_view_point = Point() - self.camera_direction = Direction() - self.camera_up_vector = Direction() - self.field_of_view = 60.0 - - -class Line: - def __init__(self): - self.start_point = Point() - self.end_point = Point() - - -class ClippingPlane: - def __init__(self): - self.location = Point() - self.direction = Direction() - - -class Bitmap: - def __init__(self): - self.reference = "" # Only in BCF-XML - self.bitmap_data = None # Only in BCF-API - self.bitmap_format = "PNG" # Enum of png or jpg - self.location = Point() - self.normal = Direction() - self.up = Direction() - self.height = 1.0 - - -class Viewpoint: - def __init__(self): - self.guid = None - self.viewpoint = None - self.snapshot = None - self.index = None - - self.components = None # It's not a list, despite the plural name - self.orthogonal_camera = None - self.perspective_camera = None - self.lines = [] - self.clipping_planes = [] - self.bitmaps = [] diff --git a/src/bcf/src/bcf/v2/model/__init__.py b/src/bcf/src/bcf/v2/model/__init__.py new file mode 100644 index 0000000000..3bb55fd922 --- /dev/null +++ b/src/bcf/src/bcf/v2/model/__init__.py @@ -0,0 +1,70 @@ +from bcf.v2.model.markup import ( + BimSnippet, + Comment, + CommentViewpoint, + Header, + HeaderFile, + Markup, + Topic, + TopicDocumentReference, + TopicRelatedTopic, + ViewPoint, +) +from bcf.v2.model.project import Project, ProjectExtension +from bcf.v2.model.version import Version +from bcf.v2.model.visinfo import ( + BitmapFormat, + ClippingPlane, + Component, + ComponentColoring, + ComponentColoringColor, + Components, + ComponentSelection, + ComponentVisibility, + ComponentVisibilityExceptions, + Direction, + Line, + OrthogonalCamera, + PerspectiveCamera, + Point, + ViewSetupHints, + VisualizationInfo, + VisualizationInfoBitmap, + VisualizationInfoClippingPlanes, + VisualizationInfoLines, +) + +__all__ = [ + "BimSnippet", + "Comment", + "CommentViewpoint", + "Header", + "HeaderFile", + "Markup", + "Topic", + "TopicDocumentReference", + "TopicRelatedTopic", + "ViewPoint", + "Project", + "ProjectExtension", + "Version", + "BitmapFormat", + "ClippingPlane", + "Component", + "ComponentColoring", + "ComponentColoringColor", + "ComponentSelection", + "ComponentVisibility", + "ComponentVisibilityExceptions", + "Components", + "Direction", + "Line", + "OrthogonalCamera", + "PerspectiveCamera", + "Point", + "ViewSetupHints", + "VisualizationInfo", + "VisualizationInfoBitmap", + "VisualizationInfoClippingPlanes", + "VisualizationInfoLines", +] diff --git a/src/bcf/src/bcf/v2/model/markup.py b/src/bcf/src/bcf/v2/model/markup.py new file mode 100644 index 0000000000..88ddd3e3a4 --- /dev/null +++ b/src/bcf/src/bcf/v2/model/markup.py @@ -0,0 +1,461 @@ +from dataclasses import dataclass, field +from typing import List, Optional + +from xsdata.models.datatype import XmlDateTime + + +@dataclass(slots=True, kw_only=True) +class BimSnippet: + reference: str = field( + metadata={ + "name": "Reference", + "type": "Element", + "namespace": "", + "required": True, + } + ) + reference_schema: str = field( + metadata={ + "name": "ReferenceSchema", + "type": "Element", + "namespace": "", + "required": True, + } + ) + snippet_type: str = field( + metadata={ + "name": "SnippetType", + "type": "Attribute", + "required": True, + } + ) + is_external: bool = field( + default=False, + metadata={ + "name": "isExternal", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class CommentViewpoint: + class Meta: + global_type = False + + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class HeaderFile: + class Meta: + global_type = False + + filename: Optional[str] = field( + default=None, + metadata={ + "name": "Filename", + "type": "Element", + "namespace": "", + } + ) + date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "Date", + "type": "Element", + "namespace": "", + } + ) + reference: Optional[str] = field( + default=None, + metadata={ + "name": "Reference", + "type": "Element", + "namespace": "", + } + ) + ifc_project: Optional[str] = field( + default=None, + metadata={ + "name": "IfcProject", + "type": "Attribute", + "length": 22, + "pattern": r"[0-9,A-Z,a-z,_$]*", + } + ) + ifc_spatial_structure_element: Optional[str] = field( + default=None, + metadata={ + "name": "IfcSpatialStructureElement", + "type": "Attribute", + "length": 22, + "pattern": r"[0-9,A-Z,a-z,_$]*", + } + ) + is_external: bool = field( + default=True, + metadata={ + "name": "isExternal", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicDocumentReference: + class Meta: + global_type = False + + referenced_document: Optional[str] = field( + default=None, + metadata={ + "name": "ReferencedDocument", + "type": "Element", + "namespace": "", + } + ) + description: Optional[str] = field( + default=None, + metadata={ + "name": "Description", + "type": "Element", + "namespace": "", + } + ) + guid: Optional[str] = field( + default=None, + metadata={ + "name": "Guid", + "type": "Attribute", + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) + is_external: bool = field( + default=False, + metadata={ + "name": "isExternal", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicRelatedTopic: + class Meta: + global_type = False + + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ViewPoint: + viewpoint: Optional[str] = field( + default=None, + metadata={ + "name": "Viewpoint", + "type": "Element", + "namespace": "", + } + ) + snapshot: Optional[str] = field( + default=None, + metadata={ + "name": "Snapshot", + "type": "Element", + "namespace": "", + } + ) + index: Optional[int] = field( + default=None, + metadata={ + "name": "Index", + "type": "Element", + "namespace": "", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Comment: + date: XmlDateTime = field( + metadata={ + "name": "Date", + "type": "Element", + "namespace": "", + "required": True, + } + ) + author: str = field( + metadata={ + "name": "Author", + "type": "Element", + "namespace": "", + "required": True, + } + ) + comment: str = field( + metadata={ + "name": "Comment", + "type": "Element", + "namespace": "", + "required": True, + } + ) + viewpoint: Optional[CommentViewpoint] = field( + default=None, + metadata={ + "name": "Viewpoint", + "type": "Element", + "namespace": "", + } + ) + modified_date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "ModifiedDate", + "type": "Element", + "namespace": "", + } + ) + modified_author: Optional[str] = field( + default=None, + metadata={ + "name": "ModifiedAuthor", + "type": "Element", + "namespace": "", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Header: + file: List[HeaderFile] = field( + default_factory=list, + metadata={ + "name": "File", + "type": "Element", + "namespace": "", + "min_occurs": 1, + } + ) + + +@dataclass(slots=True, kw_only=True) +class Topic: + reference_link: List[str] = field( + default_factory=list, + metadata={ + "name": "ReferenceLink", + "type": "Element", + "namespace": "", + } + ) + title: str = field( + metadata={ + "name": "Title", + "type": "Element", + "namespace": "", + "required": True, + } + ) + priority: Optional[str] = field( + default=None, + metadata={ + "name": "Priority", + "type": "Element", + "namespace": "", + } + ) + index: Optional[int] = field( + default=None, + metadata={ + "name": "Index", + "type": "Element", + "namespace": "", + } + ) + labels: List[str] = field( + default_factory=list, + metadata={ + "name": "Labels", + "type": "Element", + "namespace": "", + } + ) + creation_date: XmlDateTime = field( + metadata={ + "name": "CreationDate", + "type": "Element", + "namespace": "", + "required": True, + } + ) + creation_author: str = field( + metadata={ + "name": "CreationAuthor", + "type": "Element", + "namespace": "", + "required": True, + } + ) + modified_date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "ModifiedDate", + "type": "Element", + "namespace": "", + } + ) + modified_author: Optional[str] = field( + default=None, + metadata={ + "name": "ModifiedAuthor", + "type": "Element", + "namespace": "", + } + ) + due_date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "DueDate", + "type": "Element", + "namespace": "", + } + ) + assigned_to: Optional[str] = field( + default=None, + metadata={ + "name": "AssignedTo", + "type": "Element", + "namespace": "", + } + ) + stage: Optional[str] = field( + default=None, + metadata={ + "name": "Stage", + "type": "Element", + "namespace": "", + } + ) + description: Optional[str] = field( + default=None, + metadata={ + "name": "Description", + "type": "Element", + "namespace": "", + } + ) + bim_snippet: Optional[BimSnippet] = field( + default=None, + metadata={ + "name": "BimSnippet", + "type": "Element", + "namespace": "", + } + ) + document_reference: List[TopicDocumentReference] = field( + default_factory=list, + metadata={ + "name": "DocumentReference", + "type": "Element", + "namespace": "", + } + ) + related_topic: List[TopicRelatedTopic] = field( + default_factory=list, + metadata={ + "name": "RelatedTopic", + "type": "Element", + "namespace": "", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) + topic_type: Optional[str] = field( + default=None, + metadata={ + "name": "TopicType", + "type": "Attribute", + } + ) + topic_status: Optional[str] = field( + default=None, + metadata={ + "name": "TopicStatus", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Markup: + header: Optional[Header] = field( + default=None, + metadata={ + "name": "Header", + "type": "Element", + "namespace": "", + } + ) + topic: Topic = field( + metadata={ + "name": "Topic", + "type": "Element", + "namespace": "", + "required": True, + } + ) + comment: List[Comment] = field( + default_factory=list, + metadata={ + "name": "Comment", + "type": "Element", + "namespace": "", + } + ) + viewpoints: List[ViewPoint] = field( + default_factory=list, + metadata={ + "name": "Viewpoints", + "type": "Element", + "namespace": "", + } + ) diff --git a/src/bcf/src/bcf/v2/model/project.py b/src/bcf/src/bcf/v2/model/project.py new file mode 100644 index 0000000000..fea44c6f50 --- /dev/null +++ b/src/bcf/src/bcf/v2/model/project.py @@ -0,0 +1,41 @@ +from dataclasses import dataclass, field +from typing import Optional + + +@dataclass(slots=True, kw_only=True) +class Project: + name: Optional[str] = field( + default=None, + metadata={ + "name": "Name", + "type": "Element", + "namespace": "", + } + ) + project_id: str = field( + metadata={ + "name": "ProjectId", + "type": "Attribute", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ProjectExtension: + project: Optional[Project] = field( + default=None, + metadata={ + "name": "Project", + "type": "Element", + "namespace": "", + } + ) + extension_schema: str = field( + metadata={ + "name": "ExtensionSchema", + "type": "Element", + "namespace": "", + "required": True, + } + ) diff --git a/src/bcf/src/bcf/v2/model/version.py b/src/bcf/src/bcf/v2/model/version.py new file mode 100644 index 0000000000..777572c6ae --- /dev/null +++ b/src/bcf/src/bcf/v2/model/version.py @@ -0,0 +1,21 @@ +from dataclasses import dataclass, field +from typing import Optional + + +@dataclass(slots=True, kw_only=True) +class Version: + detailed_version: Optional[str] = field( + default=None, + metadata={ + "name": "DetailedVersion", + "type": "Element", + "namespace": "", + } + ) + version_id: Optional[str] = field( + default=None, + metadata={ + "name": "VersionId", + "type": "Attribute", + } + ) diff --git a/src/bcf/src/bcf/v2/model/visinfo.py b/src/bcf/src/bcf/v2/model/visinfo.py new file mode 100644 index 0000000000..f9976e1c78 --- /dev/null +++ b/src/bcf/src/bcf/v2/model/visinfo.py @@ -0,0 +1,476 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import List, Optional + + +class BitmapFormat(Enum): + PNG = "PNG" + JPG = "JPG" + + +@dataclass(slots=True, kw_only=True) +class Component: + originating_system: Optional[str] = field( + default=None, + metadata={ + "name": "OriginatingSystem", + "type": "Element", + } + ) + authoring_tool_id: Optional[str] = field( + default=None, + metadata={ + "name": "AuthoringToolId", + "type": "Element", + } + ) + ifc_guid: Optional[str] = field( + default=None, + metadata={ + "name": "IfcGuid", + "type": "Attribute", + "length": 22, + "pattern": r"[0-9,A-Z,a-z,_$]*", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Direction: + x: float = field( + metadata={ + "name": "X", + "type": "Element", + "required": True, + } + ) + y: float = field( + metadata={ + "name": "Y", + "type": "Element", + "required": True, + } + ) + z: float = field( + metadata={ + "name": "Z", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class Point: + x: float = field( + metadata={ + "name": "X", + "type": "Element", + "required": True, + } + ) + y: float = field( + metadata={ + "name": "Y", + "type": "Element", + "required": True, + } + ) + z: float = field( + metadata={ + "name": "Z", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ViewSetupHints: + spaces_visible: Optional[bool] = field( + default=None, + metadata={ + "name": "SpacesVisible", + "type": "Attribute", + } + ) + space_boundaries_visible: Optional[bool] = field( + default=None, + metadata={ + "name": "SpaceBoundariesVisible", + "type": "Attribute", + } + ) + openings_visible: Optional[bool] = field( + default=None, + metadata={ + "name": "OpeningsVisible", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ClippingPlane: + location: Point = field( + metadata={ + "name": "Location", + "type": "Element", + "required": True, + } + ) + direction: Direction = field( + metadata={ + "name": "Direction", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentColoringColor: + class Meta: + global_type = False + + component: List[Component] = field( + default_factory=list, + metadata={ + "name": "Component", + "type": "Element", + "min_occurs": 1, + } + ) + color: Optional[str] = field( + default=None, + metadata={ + "name": "Color", + "type": "Attribute", + "pattern": r"[0-9,a-f,A-F]{6}([0-9,a-f,A-F]{2})?", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentSelection: + component: List[Component] = field( + default_factory=list, + metadata={ + "name": "Component", + "type": "Element", + "min_occurs": 1, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentVisibilityExceptions: + class Meta: + global_type = False + + component: List[Component] = field( + default_factory=list, + metadata={ + "name": "Component", + "type": "Element", + "min_occurs": 1, + } + ) + + +@dataclass(slots=True, kw_only=True) +class Line: + start_point: Point = field( + metadata={ + "name": "StartPoint", + "type": "Element", + "required": True, + } + ) + end_point: Point = field( + metadata={ + "name": "EndPoint", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class OrthogonalCamera: + """ + Attributes + camera_view_point: + camera_direction: + camera_up_vector: + view_to_world_scale: view's visible size in meters + """ + camera_view_point: Point = field( + metadata={ + "name": "CameraViewPoint", + "type": "Element", + "required": True, + } + ) + camera_direction: Direction = field( + metadata={ + "name": "CameraDirection", + "type": "Element", + "required": True, + } + ) + camera_up_vector: Direction = field( + metadata={ + "name": "CameraUpVector", + "type": "Element", + "required": True, + } + ) + view_to_world_scale: float = field( + metadata={ + "name": "ViewToWorldScale", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class PerspectiveCamera: + """ + Attributes + camera_view_point: + camera_direction: + camera_up_vector: + field_of_view: It is currently limited to a value between 45 and + 60 degrees. This limitation will be dropped in the next + release and viewers should be expect values outside this + range in current implementations. + """ + camera_view_point: Point = field( + metadata={ + "name": "CameraViewPoint", + "type": "Element", + "required": True, + } + ) + camera_direction: Direction = field( + metadata={ + "name": "CameraDirection", + "type": "Element", + "required": True, + } + ) + camera_up_vector: Direction = field( + metadata={ + "name": "CameraUpVector", + "type": "Element", + "required": True, + } + ) + field_of_view: float = field( + metadata={ + "name": "FieldOfView", + "type": "Element", + "required": True, + "min_inclusive": 1.0, + "max_inclusive": 170.0, + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfoBitmap: + class Meta: + global_type = False + + bitmap: BitmapFormat = field( + metadata={ + "name": "Bitmap", + "type": "Element", + "required": True, + } + ) + reference: str = field( + metadata={ + "name": "Reference", + "type": "Element", + "required": True, + } + ) + location: Point = field( + metadata={ + "name": "Location", + "type": "Element", + "required": True, + } + ) + normal: Direction = field( + metadata={ + "name": "Normal", + "type": "Element", + "required": True, + } + ) + up: Direction = field( + metadata={ + "name": "Up", + "type": "Element", + "required": True, + } + ) + height: float = field( + metadata={ + "name": "Height", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentColoring: + color: List[ComponentColoringColor] = field( + default_factory=list, + metadata={ + "name": "Color", + "type": "Element", + "min_occurs": 1, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentVisibility: + exceptions: Optional[ComponentVisibilityExceptions] = field( + default=None, + metadata={ + "name": "Exceptions", + "type": "Element", + } + ) + default_visibility: Optional[bool] = field( + default=None, + metadata={ + "name": "DefaultVisibility", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfoClippingPlanes: + class Meta: + global_type = False + + clipping_plane: List[ClippingPlane] = field( + default_factory=list, + metadata={ + "name": "ClippingPlane", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfoLines: + class Meta: + global_type = False + + line: List[Line] = field( + default_factory=list, + metadata={ + "name": "Line", + "type": "Element", + "min_occurs": 1, + } + ) + + +@dataclass(slots=True, kw_only=True) +class Components: + view_setup_hints: Optional[ViewSetupHints] = field( + default=None, + metadata={ + "name": "ViewSetupHints", + "type": "Element", + } + ) + selection: Optional[ComponentSelection] = field( + default=None, + metadata={ + "name": "Selection", + "type": "Element", + } + ) + visibility: ComponentVisibility = field( + metadata={ + "name": "Visibility", + "type": "Element", + "required": True, + } + ) + coloring: Optional[ComponentColoring] = field( + default=None, + metadata={ + "name": "Coloring", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfo: + """ + VisualizationInfo documentation. + """ + components: Optional[Components] = field( + default=None, + metadata={ + "name": "Components", + "type": "Element", + } + ) + orthogonal_camera: Optional[OrthogonalCamera] = field( + default=None, + metadata={ + "name": "OrthogonalCamera", + "type": "Element", + } + ) + perspective_camera: Optional[PerspectiveCamera] = field( + default=None, + metadata={ + "name": "PerspectiveCamera", + "type": "Element", + } + ) + lines: Optional[VisualizationInfoLines] = field( + default=None, + metadata={ + "name": "Lines", + "type": "Element", + } + ) + clipping_planes: Optional[VisualizationInfoClippingPlanes] = field( + default=None, + metadata={ + "name": "ClippingPlanes", + "type": "Element", + } + ) + bitmap: List[VisualizationInfoBitmap] = field( + default_factory=list, + metadata={ + "name": "Bitmap", + "type": "Element", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}", + } + ) diff --git a/src/bcf/src/bcf/v2/topic.py b/src/bcf/src/bcf/v2/topic.py new file mode 100644 index 0000000000..0180427350 --- /dev/null +++ b/src/bcf/src/bcf/v2/topic.py @@ -0,0 +1,240 @@ +"""BCF XML V2 Topic handler.""" +import datetime +import uuid +import zipfile +from pathlib import Path +from typing import Any, Optional + +from ifcopenshell import entity_instance +from xsdata.models.datatype import XmlDateTime + +import bcf.v2.model as mdl +from bcf.inmemory_zipfile import ZipFileInterface +from bcf.v2.visinfo import VisualizationInfoHandler +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer + + +class TopicHandler: + """BCF Topic and related objects handler.""" + + def __init__( + self, + topic_dir: Optional[zipfile.Path] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> None: + self._markup: Optional[mdl.Markup] = None + self._viewpoints: dict[str, VisualizationInfoHandler] = {} + self._reference_files: dict[str, bytes] = {} + self._document_references: dict[str, bytes] = {} + self._bim_snippet: Optional[bytes] = None + self._xml_handler = xml_handler or XmlParserSerializer() + self._topic_dir = topic_dir + + @property + def markup(self) -> Optional[mdl.Markup]: + if not self._markup: + markup_path = self._topic_dir.joinpath("markup.bcf") + if markup_path.exists(): + self._markup = self._xml_handler.parse(markup_path.read_bytes(), mdl.Markup) + return self._markup + + @markup.setter + def markup(self, value: mdl.Markup) -> None: + self._markup = value + + @property + def topic(self) -> mdl.Topic: + """Return the Topic object.""" + return self.markup.topic + + @property + def guid(self) -> str: + """Return the GUID of the topic.""" + if self._markup: + return self.topic.guid + return self._topic_dir.name if self._topic_dir else "" + + @property + def header(self) -> Optional[mdl.Header]: + """Return the header of the topic.""" + return self.markup.header if self.markup else None + + @property + def comments(self) -> list[mdl.Comment]: + """Return the comments of the topic.""" + return self.markup.comment if self.markup else [] + + @property + def bim_snippet(self) -> Optional[bytes]: + if not self._bim_snippet and self._topic_dir: + self._bim_snippet = self._load_bim_snippet() + return self._bim_snippet + + @bim_snippet.setter + def bim_snippet(self, value: bytes) -> None: + self._bim_snippet = value + + @property + def viewpoints(self) -> dict[str, VisualizationInfoHandler]: + if not self._viewpoints and self._topic_dir: + self._viewpoints = self._load_viewpoints() + return self._viewpoints + + @property + def reference_files(self) -> dict[str, bytes]: + if self._reference_files or not self.header: + return self._reference_files + for ref in self.header.file: + if ref.is_external: + continue + real_path = self._topic_dir + for path_part in ref.reference.split("/"): + real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part) + self._reference_files[ref.reference] = real_path.read_bytes() + return self._reference_files + + @property + def document_references(self) -> dict[str, bytes]: + if self._document_references or not self.topic: + return self._document_references + for doc in self.topic.document_reference: + if doc.is_external or not doc.referenced_document: + continue + real_path = self._topic_dir + for path_part in doc.referenced_document.split("/"): + real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part) + self._document_references[doc.referenced_document] = real_path.read_bytes() + return self._document_references + + def _load_bim_snippet(self) -> Optional[bytes]: + bim_snippet_obj = self.topic.bim_snippet + if bim_snippet_obj and not bim_snippet_obj.is_external: + bim_snippet_path = self._topic_dir.joinpath(bim_snippet_obj.reference) + if bim_snippet_path.exists(): + return bim_snippet_path.read_bytes() + return None + + def _load_viewpoints(self) -> dict[str, VisualizationInfoHandler]: + if self.markup and (viewpoints := self.markup.viewpoints): + return VisualizationInfoHandler.from_topic_viewpoints(self._topic_dir, viewpoints) + return {} + + @classmethod + def create_new( + cls, + title: str, + description: str, + author: str, + topic_type: str = "", + topic_status: str = "", + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> "TopicHandler": + """ + Create a new BCF topic. + + Args: + title: The title of the topic. + description: The description of the topic. + author: The author of the topic. + topic_type: The type of the topic. + topic_status: The status of the topic. + xml_handler: The XML parser/serializer to use. + + Returns: + The BCF topic definition. + """ + creation_date = XmlDateTime.from_datetime(datetime.datetime.now()) + guid = str(uuid.uuid4()) + topic = mdl.Topic( + title=title, + description=description, + creation_author=author, + creation_date=creation_date, + guid=guid, + topic_type=topic_type, + topic_status=topic_status, + ) + markup = mdl.Markup(topic=topic) + obj = cls(topic_dir=Path(guid), xml_handler=xml_handler or XmlParserSerializer()) + obj.markup = markup + return obj + + def save(self, destination_zip: ZipFileInterface) -> None: + """ + Save the topic to a BCF zip file. + + Args: + bcf_zip: The BCF zip file to save to. + """ + topic_dir = self.guid + self._save_xml(destination_zip, self._markup, "markup.bcf") + self._save_viewpoints(destination_zip, topic_dir) + self._save_bim_snippet(destination_zip) + self._save_reference_files(destination_zip) + self._save_document_references(destination_zip) + + def _save_viewpoints(self, destination_zip: ZipFileInterface, topic_dir: str) -> None: + if not self.markup or not (viewpoints := self.markup.viewpoints): + return + for vpt in viewpoints: + if vpt.viewpoint: + self.viewpoints[vpt.viewpoint].save(destination_zip, topic_dir, vpt) + + def _save_xml(self, destination_zip: ZipFileInterface, item: Any, target: str) -> None: + if self._topic_dir is None: + return + to_write = self._xml_handler.serialize(item) if item else self._topic_dir.joinpath(target).read_bytes() + destination_zip.writestr(f"{self._topic_dir.name}/{target}", to_write) + + def _save_bim_snippet(self, destination_zip: ZipFileInterface) -> None: + snippet = self.topic.bim_snippet + if not snippet or snippet.is_external: + return + ref_filename = Path(snippet.reference).name + if self.bim_snippet: + destination_zip.writestr(f"{self.topic.guid}/{ref_filename}", self.bim_snippet) + + def _save_reference_files(self, destination_zip: ZipFileInterface) -> None: + if not self.header: + return + for ref in self.header.file: + if ref.is_external or not ref.reference: + continue + real_path = self._topic_dir + for path_part in ref.reference.split("/"): + real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part) + destination_zip.writestr(real_path.at, self.reference_files[ref.reference]) + + def _save_document_references(self, destination_zip: ZipFileInterface) -> None: + if not self.topic: + return + for doc in self.topic.document_reference: + if doc.is_external or not doc.referenced_document: + continue + real_path = self._topic_dir + for path_part in doc.referenced_document.split("/"): + real_path = real_path.parent if path_part == ".." else real_path.joinpath(path_part) + destination_zip.writestr(real_path.at, self.document_references[doc.referenced_document]) + + def add_viewpoint(self, element: entity_instance) -> None: + """ + Add a viewpoint tergeting an IFC element to the topic. + + Args: + element: The IFC element. + """ + new_viewpoint = VisualizationInfoHandler.create_new(element, self._xml_handler) + self.add_visinfo_handler(new_viewpoint) + + def add_visinfo_handler(self, new_viewpoint: VisualizationInfoHandler) -> None: + self.viewpoints[new_viewpoint.guid] = new_viewpoint + self.markup.viewpoints.append(mdl.ViewPoint(viewpoint=new_viewpoint.guid, guid=new_viewpoint.guid)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, TopicHandler): + raise TypeError("Equality needs a BcfXml object.") + return ( + self.markup == other.markup + and self.viewpoints == other.viewpoints + and self.bim_snippet == other.bim_snippet + ) diff --git a/src/bcf/src/bcf/v2/visinfo.py b/src/bcf/src/bcf/v2/visinfo.py new file mode 100644 index 0000000000..1a15086b99 --- /dev/null +++ b/src/bcf/src/bcf/v2/visinfo.py @@ -0,0 +1,246 @@ +import uuid +import zipfile +from functools import lru_cache +from typing import Any, Iterable, Optional + +import numpy as np +from ifcopenshell import entity_instance +from ifcopenshell.util import placement +from numpy.typing import NDArray + +import bcf.v2.model as mdl +from bcf.geometry import calc_camera_vectors +from bcf.inmemory_zipfile import ZipFileInterface +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer + + +class VisualizationInfoHandler: + """Handle the VisualizationInfo and related objects.""" + + def __init__( + self, + visualization_info: mdl.VisualizationInfo, + snapshot: Optional[bytes] = None, + bitmaps: Optional[dict[str, bytes]] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> None: + self.visualization_info = visualization_info + self.snapshot = snapshot + self.bitmaps = bitmaps or {} + self._xml_handler = xml_handler or XmlParserSerializer() + + @property + def guid(self) -> str: + """Return the GUID of the visualization info.""" + return self.visualization_info.guid + + @classmethod + def from_topic_viewpoints( + cls, + topic_dir: zipfile.Path, + vps: Iterable[mdl.ViewPoint], + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> dict[str, "VisualizationInfoHandler"]: + """Create VisualizationInfoHandler objects of a Topic's ViewPoints.""" + viewpoints = {} + for vpt in vps: + visinfo = cls.load(topic_dir, vpt, xml_handler) + if visinfo and vpt.viewpoint: + viewpoints[vpt.viewpoint] = visinfo + return viewpoints + + @classmethod + def load( + cls, + topic_dir: zipfile.Path, + vpt: mdl.ViewPoint, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> Optional["VisualizationInfoHandler"]: + """ + Load the VisualizationInfo and related objects from a BCF zip file. + + Args: + topic_dir: The directory in the BCF zip file to load from. + vpt: The ViewPoint to load. + xml_handler: The XML handler to use to parse the VisualizationInfo. + + Returns: + The VisualizationInfoHandler object. + """ + visinfo = cls._load_visinfo(topic_dir, vpt.viewpoint, xml_handler) + if not visinfo: + return None + snapshot = cls._load_snapshot(topic_dir, vpt.snapshot) + bitmaps = cls._load_bitmaps(topic_dir, visinfo) + return cls(visinfo, snapshot, bitmaps, xml_handler) + + @staticmethod + def _load_visinfo( + topic_dir: zipfile.Path, + vp_name: Optional[str], + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> Optional[mdl.VisualizationInfo]: + if not vp_name: + return None + vp_path = topic_dir.joinpath(vp_name) + if vp_path.exists(): + xml_handler = xml_handler or XmlParserSerializer() + return xml_handler.parse(vp_path.read_bytes(), mdl.VisualizationInfo) + return None + + @staticmethod + def _load_snapshot(topic_dir: zipfile.Path, vp_snapshot: Optional[str]) -> Optional[bytes]: + if vp_snapshot: + snapshot_path = topic_dir.joinpath(vp_snapshot) + if snapshot_path.exists(): + return snapshot_path.read_bytes() + return None + + @staticmethod + def _load_bitmaps(topic_dir: zipfile.Path, visinfo: Optional[mdl.VisualizationInfo]) -> dict[str, bytes]: + if not visinfo or not (bitmaps := visinfo.bitmap): + return {} + bitmaps_dict = {} + for bitmap in bitmaps: + if not bitmap.reference: + continue + bitmap_path = topic_dir.joinpath(bitmap.reference) + if bitmap_path.exists(): + bitmaps_dict[bitmap.reference] = bitmap_path.read_bytes() + return bitmaps_dict + + def save( + self, + bcf_zip: ZipFileInterface, + topic_dir: str, + vpt: mdl.ViewPoint, + ) -> None: + """ + Save the VisualizationInfo and related objects to a BCF zip file. + + Args: + bcf_zip: The BCF zip file to save to. + topic_dir: The directory in the BCF zip file to save to. + vpt: The ViewPoint to save. + """ + if not (vp_name := vpt.viewpoint): + return + self._save_visinfo(bcf_zip, topic_dir, vp_name) + self._save_snapshot(bcf_zip, topic_dir, vpt.snapshot) + self._save_bitmaps(bcf_zip, topic_dir) + + def _save_snapshot(self, bcf_zip: ZipFileInterface, topic_dir: str, filename: Optional[str]) -> None: + if self.snapshot and filename: + bcf_zip.writestr(f"{topic_dir}/{filename}", self.snapshot) + + def _save_visinfo(self, bcf_zip: ZipFileInterface, topic_dir: str, vp_name: str) -> None: + bcf_zip.writestr( + f"{topic_dir}/{vp_name}", + self._xml_handler.serialize(self.visualization_info), + ) + + def _save_bitmaps(self, bcf_zip: ZipFileInterface, topic_dir: str) -> None: + if not self.bitmaps: + return + if not (bitmaps_defs := self.visualization_info.bitmap): + return + for bitmap_def in bitmaps_defs: + if not (bitmap_name := bitmap_def.reference): + continue + if bitmap_name in self.bitmaps: + bcf_zip.writestr(f"{topic_dir}/{bitmap_name}", self.bitmaps[bitmap_name]) + + @classmethod + def create_new( + cls, + element: entity_instance, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> "VisualizationInfoHandler": + """ + Create a new VisualizationInfoHandler object from an IFC element. + + Args: + element: The IFC element to point at. + xml_handler: The XML handler to use. + + Returns: + The VisualizationInfoHandler object. + """ + xml_handler = xml_handler or XmlParserSerializer() + return cls(visualization_info=build_viewpoint(element), xml_handler=xml_handler) + + +@lru_cache(maxsize=None) +def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo: + """ + Return a BCF viewpoint of an IFC element. + + This function is cached to speedudp the creation of multiple BCF topics regarding the same element. + + Args: + element: The IFC element to point at. + + Returns: + The BCF viewpoint definition. + """ + elem_placement = placement.get_local_placement(element.ObjectPlacement) + + return mdl.VisualizationInfo( + guid=str(uuid.uuid4()), + components=build_components(element.GlobalId), + perspective_camera=build_camera(elem_placement), + ) + + +def build_components(guid: str) -> mdl.Components: + """ + Return the BCF components from an IFC element GUID. + + Args: + guid: The IFC element GUID. + + Returns: + The BCF components definition. + """ + return mdl.Components( + selection=mdl.ComponentSelection(component=[mdl.Component(ifc_guid=guid)]), + visibility=mdl.ComponentVisibility(default_visibility=True), + ) + + +def build_camera(elem_placement: NDArray[np.float_]) -> mdl.PerspectiveCamera: + """ + Return a BCF camera for an IFC element placement matrix. + + Args: + elem_placement: The IFC element placement as a rototranslation matrix. + + Returns: + The BCF camera definition. + """ + return build_camera_from_vectors(*calc_camera_vectors(elem_placement)) + + +def build_camera_from_vectors( + camera_position: NDArray[np.float_], camera_dir: NDArray[np.float_], camera_up: NDArray[np.float_] +) -> mdl.PerspectiveCamera: + """ + Return a BCF camera for an IFC element placement matrix. + + Args: + camera_position: camera position array + camera_dir: camera direction versor + camera_up_vector: camera up versor + + Returns: + The BCF camera definition. + """ + camera_viewpoint = mdl.Point(x=camera_position[0], y=camera_position[1], z=camera_position[2]) + camera_direction = mdl.Direction(x=camera_dir[0], y=camera_dir[1], z=camera_dir[2]) + camera_up_vector = mdl.Direction(x=camera_up[0], y=camera_up[1], z=camera_up[2]) + return mdl.PerspectiveCamera( + camera_view_point=camera_viewpoint, + camera_direction=camera_direction, + camera_up_vector=camera_up_vector, + field_of_view=60.0, + ) diff --git a/src/bcf/src/bcf/v3/__init__.py b/src/bcf/src/bcf/v3/__init__.py index 5828265521..32d3e3f1c3 100644 --- a/src/bcf/src/bcf/v3/__init__.py +++ b/src/bcf/src/bcf/v3/__init__.py @@ -1,19 +1 @@ - -# BCF - BCF Python library -# Copyright (C) 2021 Prabhat Singh -# -# 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 . - +"""BCF XML v3 handler.""" diff --git a/src/bcf/src/bcf/v3/bcfapi.py b/src/bcf/src/bcf/v3/bcfapi.py index 308f323eb8..7303ed8d7e 100644 --- a/src/bcf/src/bcf/v3/bcfapi.py +++ b/src/bcf/src/bcf/v3/bcfapi.py @@ -1,4 +1,3 @@ - # BCF - BCF Python library # Copyright (C) 2021 Prabhat Singh # @@ -17,25 +16,27 @@ # You should have received a copy of the GNU Lesser General Public License # along with BCF. If not, see . -import uuid -import time -import json -import urllib -import requests -import webbrowser -import http.server import base64 -import tempfile +import http.server import os +import tempfile +import time +import urllib +import uuid +import webbrowser +from re import A +from typing import Any, Optional, Tuple + +import requests client_id, client_secret = "", "" class OAuthReceiver(http.server.BaseHTTPRequestHandler): - def do_GET(self): + def do_GET(self) -> None: query = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query) - self.server.auth_code = query.get("code", [""])[0] - self.server.auth_state = query.get("state", [""])[0] + self.server.auth_code = query.get("code", [""])[0] # type:ignore + self.server.auth_state = query.get("state", [""])[0] # type:ignore self.send_response(200) self.send_header("Content-type", "text/plain") self.end_headers() @@ -43,20 +44,21 @@ class OAuthReceiver(http.server.BaseHTTPRequestHandler): class FoundationClient: - def __init__(self, client_id, client_secret, base_url=None, redirect_subdir=None): + def __init__( + self, client_id: str, client_secret: str, base_url: Optional[str] = None, redirect_subdir: Optional[str] = None + ) -> None: self.baseurl = base_url self.access_token = "" self.refresh_token = "" self.access_token_expires_on = time.time() self.refresh_token_expires_on = float("inf") - self.auth_endpoint = None - self.token_endpoint = None + self.token_endpoint = "" self.client_id = client_id self.client_secret = client_secret - self.auth_method = None + self.auth_method: Optional[str] = None self.redirect_subdir = redirect_subdir - def get_access_token(self): + def get_access_token(self) -> str: if self.access_token and self.access_token_expires_on > time.time(): return self.access_token elif self.refresh_token and self.refresh_token_expires_on > time.time(): @@ -65,18 +67,18 @@ class FoundationClient: self.login() return self.access_token - def get_auth_methods(self): + def get_auth_methods(self) -> list[Any]: resp = requests.get(f"{self.baseurl}foundation/1.0/auth") return resp.json()["supported_oauth2_flows"] - def get_versions(self): + def get_versions(self) -> list[Any]: resp = requests.get(f"{self.baseurl}foundation/versions") return resp.json()["versions"] - def login(self): + def login(self) -> None: resp = requests.get(f"{self.baseurl}foundation/1.0/auth") values = resp.json() - self.auth_endpoint = values["oauth2_auth_url"] + auth_endpoint = values["oauth2_auth_url"] self.token_endpoint = values["oauth2_token_url"] with http.server.HTTPServer(("", 8080), OAuthReceiver) as server: @@ -89,25 +91,22 @@ class FoundationClient: "redirect_uri": f"http://localhost:{server.server_address[1]}/{self.redirect_subdir}", } ) - if "?" in self.auth_endpoint: - webbrowser.open(f"{self.auth_endpoint}&{query}") + if "?" in auth_endpoint: + webbrowser.open(f"{auth_endpoint}&{query}") else: - webbrowser.open(f"{self.auth_endpoint}?{query}") + webbrowser.open(f"{auth_endpoint}?{query}") server.timeout = 100 - server.state = state server.handle_request() - if server.auth_code and server.auth_state == state: + if server.auth_code and server.auth_state == state: # pylint: disable=E1101 data = { "grant_type": "authorization_code", - "code": server.auth_code, + "code": server.auth_code, # pylint: disable=E1101 type:ignore "redirect_uri": f"http://localhost:{server.server_address[1]}/{self.redirect_subdir}", } - auth_string = f"{self.client_id}:{self.client_secret}" - header_string = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8") - headers = {"Authorization": f"Basic {header_string}"} + headers = self._get_access_token_headers() self.set_tokens_from_response(requests.post(self.token_endpoint, data=data, headers=headers)) - def get_refresh_token(self): + def get_refresh_token(self) -> None: self.set_tokens_from_response( requests.post( self.token_endpoint, @@ -118,10 +117,8 @@ class FoundationClient: ).json() ) - def get_new_access_token(self): - auth_string = f"{self.client_id}:{self.client_secret}" - header_string = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8") - headers = {"Authorization": f"Basic {header_string}"} + def get_new_access_token(self) -> None: + headers = self._get_access_token_headers() self.set_tokens_from_response( requests.post( self.token_endpoint, @@ -133,35 +130,41 @@ class FoundationClient: ).json() ) - def set_auth_method(self, method="authorization_code_grant"): + def _get_access_token_headers(self) -> dict[str, str]: + auth_string = f"{self.client_id}:{self.client_secret}" + header_string = base64.b64encode(auth_string.encode("utf-8")).decode("utf-8") + return {"Authorization": f"Basic {header_string}"} + + def set_auth_method(self, method: str = "authorization_code_grant") -> None: if method != "authorization_code_grant": raise NotImplementedError(f"{method} not supported") else: self.auth_method = method - def set_tokens_from_response(self, response): - response = response.json() - self.access_token = response["access_token"] - self.refresh_token = response["refresh_token"] - self.access_token_expires_on = time.time() + response["expires_in"] - if "refresh_token_expires_in" in response: - self.refresh_token_expires_on = time.time() + response["refresh_token_expires_in"] + def set_tokens_from_response(self, response: requests.Response) -> None: + response_dict = response.json() + self.access_token = response_dict["access_token"] + self.refresh_token = response_dict["refresh_token"] + self.access_token_expires_on = time.time() + response_dict["expires_in"] + if "refresh_token_expires_in" in response_dict: + self.refresh_token_expires_on = time.time() + response_dict["refresh_token_expires_in"] class BcfClient: - def __init__(self, foundation_client): + def __init__(self, foundation_client: FoundationClient) -> None: self.foundation_client = foundation_client - self.version_id = None - self.baseurl = None + self.version_id: Optional[str] = None + self.baseurl: Optional[str] = None self.filepath = tempfile.mkdtemp() - def set_version(self, version): + def set_version(self, version: dict[str, str]) -> None: self.version_id = version["version_id"] self.baseurl = version["api_base_url"] - def get(self, endpoint, params=None, is_auth_required=False): + def get(self, endpoint: str, params: Any = None, is_auth_required: bool = False) -> Any: # TODO: handle error http status codes and raise exception. Follow error.json standard. - headers = {"Authorization": "Bearer " + self.foundation_client.get_access_token()} + headers = {"Authorization": f"Bearer {self.foundation_client.get_access_token()}"} + response = requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None) try: response = requests.get(f"{self.baseurl}{endpoint}", headers=headers, params=params or None) @@ -171,68 +174,62 @@ class BcfClient: except requests.exceptions.HTTPError as e: print(f"message: {response.reason}' '{response.status_code}' '{ e }") - def post(self, endpoint, data=None, params=None): + def post(self, endpoint: str, data: Any = None, params: Any = None) -> Tuple[int, str]: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/json", } + try: response = requests.post( - f"{self.baseurl}{endpoint}", - headers=headers, - params=params or None, - data=data or None, + f"{self.baseurl}{endpoint}", headers=headers, params=params or None, data=data or None ) - if response.status_code == 201: - return response.status_code, response.text - response.raise_for_status() + + if response.status_code != 201: + response.raise_for_status() + return response.status_code, response.text except requests.exceptions.HTTPError as errh: print(f"message: {response.reason}' '{response.status_code}, {errh}") + return response.status_code, response.reason - def put(self, endpoint, data=None, params=None): + def put(self, endpoint: str, data: Any = None, params: Any = None) -> Tuple[int, str]: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/json", } + try: response = requests.put( - f"{self.baseurl}{endpoint}", - headers=headers, - params=params or None, - data=data or None, + f"{self.baseurl}{endpoint}", headers=headers, params=params or None, data=data or None ) - if response.status_code == 200: - return response.status_code, response.text - response.raise_for_status() + + if response.status_code != 200: + response.raise_for_status() + return response.status_code, response.text except requests.exceptions.HTTPError as errh: print(f"message: {response.reason}' '{response.status_code}, {errh}") + return response.status_code, response.reason - def delete(self, endpoint, params=None): + def delete(self, endpoint: str, params: Any = None) -> Tuple[int, str]: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/json", } + try: - response = requests.delete( - f"{self.baseurl}{endpoint}", - headers=headers, - params=params or None, - ) - if response.status_code == 200: - return response.status_code, response.text - response.raise_for_status() + response = requests.delete(f"{self.baseurl}{endpoint}", headers=headers, params=params or None) + + if response.status_code != 200: + response.raise_for_status() + return response.status_code, response.text except requests.exceptions.HTTPError as errh: print(f"message: {response.reason}' '{response.status_code}, {errh}") + return response.status_code, response.reason - def get_projects(self) -> list: - return self.get( - f"/projects", - ) + def get_projects(self) -> list[Any]: + return self.get("/projects") - def get_project( - self, - project_id="", - ) -> dict: + def get_project(self, project_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}", { @@ -240,16 +237,13 @@ class BcfClient: }, ) - def update_project(self, project_id="", data=None) -> dict: + def update_project(self, project_id: str = "", data: Any = None) -> Tuple[int, str]: url = f"{self.baseurl}/projects/{project_id}" - headers = {"Authorization": "Bearer " + self.foundation_client.get_access_token()} + headers = {"Authorization": f"Bearer {self.foundation_client.get_access_token()}"} resp = requests.put(url, headers=headers, data=data) return resp.status_code, resp.text - def get_extensions( - self, - project_id="", - ) -> dict: + def get_extensions(self, project_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/extensions", { @@ -259,10 +253,10 @@ class BcfClient: def get_topics( self, - project_id="", - topics="", - query_string=None, - ) -> list: + project_id: str = "", + topics: str = "", + query_string: Optional[str] = None, + ) -> list[Any]: # return self.get( # f"/projects/{project_id}/topics", # { @@ -273,7 +267,7 @@ class BcfClient: # ) pass - def get_topic(self, project_id="", topic_id="") -> dict: + def get_topic(self, project_id: str = "", topic_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}", { @@ -282,42 +276,40 @@ class BcfClient: }, ) - def create_topic(self, project_id="", data=None): + def create_topic(self, project_id: str = "", data: Any = None) -> Tuple[int, str]: return self.post(f"/projects/{project_id}/topics", data=data) - def update_topic(self, project_id="", topic_id="", data=None) -> dict: + def update_topic(self, project_id: str = "", topic_id: str = "", data: Any = None) -> Tuple[int, str]: return self.put(f"/projects/{project_id}/topics/{topic_id}", data=data) - def delete_topic(self, project_id="", topic_id=""): + def delete_topic(self, project_id: str = "", topic_id: str = "") -> Tuple[int, str]: return self.delete(f"/projects/{project_id}/topics/{topic_id}") - def get_snippet(self, project_id="", topic_id="") -> str: + def get_snippet(self, project_id: str = "", topic_id: str = "") -> Tuple[int, str]: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/octet-stream", } - response = requests.get( - f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet", - headers=headers, - ) - # TODO: write to tmpdir - 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 - def update_snippet(self, project_id="", topic_id="", files=None, data=None): + response = requests.get(f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet", headers=headers) + content = response.content.decode("utf-8") + with open(os.path.join(self.filepath, f"{project_id}_{topic_id}_snippet.txt"), "w") as f: + f.write(content) + return response.status_code, content + + def update_snippet(self, project_id: str = "", topic_id: str = "", files: Any = None, data: Any = None) -> int: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/octet-stream", } + response = requests.put( - f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet", - headers=headers, - files=files, + f"{self.baseurl}/projects/{project_id}/topics/{topic_id}/snippet", headers=headers, files=files ) + return response.status_code - def get_files_information(self, project_id="") -> list: + def get_files_information(self, project_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/files_information", { @@ -325,7 +317,7 @@ class BcfClient: }, ) - def get_files(self, project_id="", topic_id="") -> list: + def get_files(self, project_id: str = "", topic_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/files", { @@ -336,32 +328,32 @@ class BcfClient: def update_files( self, - project_id="", - topic_id="", - data=None, - params=None, - ): + project_id: str = "", + topic_id: str = "", + data: Any = None, + params: Any = None, + ) -> Tuple[int, str]: return self.put( f"/projects/{project_id}/topics/{topic_id}/files", data=data, ) - def get_comments(self, project_id="", topic_id="") -> list: + def get_comments(self, project_id: str = "", topic_id: str = "") -> None: pass def create_comments( self, - project_id="", - topic_id="", - data=None, - params=None, - ): + project_id: str = "", + topic_id: str = "", + data: Any = None, + params: Any = None, + ) -> Tuple[int, str]: return self.post( f"/projects/{project_id}/topics/{topic_id}/comments", data=data, ) - def get_comment(self, project_id="", topic_id="", comment_id="") -> dict: + def get_comment(self, project_id: str = "", topic_id: str = "", comment_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}", { @@ -371,22 +363,22 @@ class BcfClient: }, ) - def delete_comment(self, project_id="", topic_id="", comment_id=""): + def delete_comment(self, project_id: str = "", topic_id: str = "", comment_id: str = "") -> Tuple[int, str]: return self.delete(f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}") def update_comment( self, - project_id="", - topic_id="", - comment_id="", - data=None, - ): + project_id: str = "", + topic_id: str = "", + comment_id: str = "", + data: Any = None, + ) -> Tuple[int, str]: return self.put( f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}", data=data, ) - def get_viewpoints(self, project_id="", topic_id="") -> list: + def get_viewpoints(self, project_id: str = "", topic_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints", { @@ -395,13 +387,13 @@ class BcfClient: }, ) - def create_viewpoints(self, project_id="", topic_id="", data=None): + def create_viewpoints(self, project_id: str = "", topic_id: str = "", data: Any = None) -> Tuple[int, str]: return self.post( f"/projects/{project_id}/topics/{topic_id}/viewpoints", data=data, ) - def get_viewpoint(self, project_id="", topic_id="", viewpoint_id="") -> dict: + def get_viewpoint(self, project_id: str = "", topic_id: str = "", viewpoint_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}", { @@ -413,15 +405,15 @@ class BcfClient: def delete_viewpoint( self, - project_id="", - topic_id="", - viewpoint_id="", - ): + project_id: str = "", + topic_id: str = "", + viewpoint_id: str = "", + ) -> Tuple[int, str]: return self.delete( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}", ) - def get_snapshot(self, project_id="", topic_id="", viewpoint_id="") -> str: + def get_snapshot(self, project_id: str = "", topic_id: str = "", viewpoint_id: str = "") -> str: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/snapshot", { @@ -431,7 +423,7 @@ class BcfClient: }, ) - def get_bitmap(self, project_id="", topic_id="", viewpoint_id="", bitmap_id="") -> str: + def get_bitmap(self, project_id: str = "", topic_id: str = "", viewpoint_id: str = "", bitmap_id: str = "") -> str: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/bitmaps/{bitmap_id}", { @@ -442,7 +434,7 @@ class BcfClient: }, ) - def get_selection(self, project_id="", topic_id="", viewpoint_id="") -> dict: + def get_selection(self, project_id: str = "", topic_id: str = "", viewpoint_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/selection", { @@ -452,7 +444,7 @@ class BcfClient: }, ) - def get_coloring(self, project_id="", topic_id="", viewpoint_id="") -> dict: + def get_coloring(self, project_id: str = "", topic_id: str = "", viewpoint_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/coloring", { @@ -462,7 +454,7 @@ class BcfClient: }, ) - def get_visibility(self, project_id="", topic_id="", viewpoint_id="") -> dict: + def get_visibility(self, project_id: str = "", topic_id: str = "", viewpoint_id: str = "") -> dict[str, Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/viewpoints/{viewpoint_id}/visibility", { @@ -472,7 +464,7 @@ class BcfClient: }, ) - def get_related_topics(self, project_id="", topic_id="") -> list: + def get_related_topics(self, project_id: str = "", topic_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/related_topics", { @@ -483,16 +475,16 @@ class BcfClient: def update_related_topics( self, - project_id="", - topic_id="", - data=None, - ): + project_id: str = "", + topic_id: str = "", + data: Any = None, + ) -> Tuple[int, str]: return self.put( f"/projects/{project_id}/topics/{topic_id}/related_topics", data=data, ) - def get_document_references(self, project_id="", topic_id="") -> list: + def get_document_references(self, project_id: str = "", topic_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/document_references", { @@ -503,10 +495,10 @@ class BcfClient: def create_document_reference( self, - project_id="", - topic_id="", - data=None, - ): + project_id: str = "", + topic_id: str = "", + data: Any = None, + ) -> Tuple[int, str]: return self.post( f"/projects/{project_id}/topics/{topic_id}/document_references", data=data, @@ -514,17 +506,17 @@ class BcfClient: def update_document_references( self, - project_id="", - topic_id="", - document_reference_id="", - data=None, - ): + project_id: str = "", + topic_id: str = "", + document_reference_id: str = "", + data: Any = None, + ) -> Tuple[int, str]: return self.put( f"/projects/{project_id}/topics/{topic_id}/document_references/{document_reference_id}", data=data, ) - def get_documents(self, project_id="", topic_id="") -> list: + def get_documents(self, project_id: str = "", topic_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/documents", { @@ -534,40 +526,36 @@ class BcfClient: ) def create_document( - self, - project_id="", - topic_id="", - guid=None, - files=None, - data=None, - ): + self, project_id: str = "", topic_id: str = "", guid: Optional[str] = None, files: Any = None, data: Any = None + ) -> int: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/octet-stream", } + response = requests.post( f"/projects/{project_id}/topics/{topic_id}/documents", data=data, - params={guid}, + params={"guid": guid}, files=files, headers=headers, ) + return response.status_code - def get_document(self, project_id="", topic_id="", document_id="") -> str: + def get_document(self, project_id: str = "", topic_id: str = "", document_id: str = "") -> Tuple[int, str]: headers = { - "Authorization": "Bearer " + self.foundation_client.get_access_token(), + "Authorization": f"Bearer {self.foundation_client.get_access_token()}", "Content-type": "application/octet-stream", } - response = requests.get( - f"{self.baseurl}/projects/{project_id}/topics/documents/{document_id}", - headers=headers, - ) - 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 - def get_topics_events(self, project_id="") -> list: + response = requests.get(f"{self.baseurl}/projects/{project_id}/topics/documents/{document_id}", headers=headers) + content = response.content.decode("utf-8") + with open(os.path.join(self.filepath, f"{project_id}_{topic_id}_{document_id}_document.txt"), "w") as f: + f.write(content) + return response.status_code, content + + def get_topics_events(self, project_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/events", { @@ -575,7 +563,7 @@ class BcfClient: }, ) - def get_topic_events(self, project_id="", topic_id="") -> list: + def get_topic_events(self, project_id: str = "", topic_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/events", { @@ -584,7 +572,7 @@ class BcfClient: }, ) - def get_comments_events(self, project_id="") -> list: + def get_comments_events(self, project_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/comments/events", { @@ -592,7 +580,7 @@ class BcfClient: }, ) - def get_comment_events(self, project_id="", topic_id="", comment_id="") -> list: + def get_comment_events(self, project_id: str = "", topic_id: str = "", comment_id: str = "") -> list[Any]: return self.get( f"/projects/{project_id}/topics/{topic_id}/comments/{comment_id}/events", { diff --git a/src/bcf/src/bcf/v3/bcfxml.py b/src/bcf/src/bcf/v3/bcfxml.py index 0aa5925bdf..a2a81199ec 100644 --- a/src/bcf/src/bcf/v3/bcfxml.py +++ b/src/bcf/src/bcf/v3/bcfxml.py @@ -1,847 +1,291 @@ - -# BCF - BCF Python library -# Copyright (C) 2021 Prabhat Singh -# -# 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 . - -import os +"""BCF XML V3 handlers.""" import uuid -import shutil +import warnings import zipfile -import logging -import tempfile -import bcf.v3.data -from datetime import datetime -from xml.dom import minidom -from xmlschema import XMLSchema -from contextlib import contextmanager -from shutil import copyfile +from pathlib import Path +from typing import Any, Optional, TypeVar -cwd = os.path.dirname(os.path.realpath(__file__)) +import bcf.v3.model as mdl +from bcf.inmemory_zipfile import InMemoryZipFile, ZipFileInterface +from bcf.v3.document import DocumentsHandler +from bcf.v3.topic import TopicHandler +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer - -@contextmanager -def cd(newdir): - prevdir = os.getcwd() - os.chdir(os.path.expanduser(newdir)) - try: - yield - finally: - os.chdir(prevdir) +T = TypeVar("T") class BcfXml: - def __init__(self): - self.filepath = None - self.logger = logging.getLogger("bcfxml") - self.author = "john@doe.com" - self.project = bcf.v3.data.Project() - self.version = "3.0" - self.topics = {} + """BCF XML handler.""" - def new_project(self): - self.project.project_id = str(uuid.uuid4()) - self.project.name = "New Project" - self.topics = {} - if self.filepath: - self.close_project() - self.filepath = tempfile.mkdtemp() - self.edit_project() - self.edit_version() + def __init__( + self, filename: Optional[Path] = None, xml_handler: Optional[AbstractXmlParserSerializer] = None + ) -> None: + self._filename = filename + self._xml_handler = xml_handler or XmlParserSerializer() + self._version: Optional[mdl.Version] = None + self._project_info: Optional[mdl.ProjectInfo] = None + self._extensions: Optional[mdl.Extensions] = None + self._topics: dict[str, TopicHandler] = {} + self._documents: Optional[DocumentsHandler] = None + self._zip_file = self._load_zip_file() - def get_project(self, filepath=None): - if os.path.isfile(os.path.join(self.filepath, "project.bcfp")): - data = self._read_xml("project.bcfp", "project.xsd") - self.project.project_id = data["Project"]["@ProjectId"] - self.project.name = data["Project"].get("Name") + def __enter__(self) -> "BcfXml": + return self + + def __exit__(self, *args: Any) -> None: + self.close() + + def __del__(self) -> None: + self.close() + + def close(self) -> None: + if self._zip_file: + self._zip_file.close() + + def _load_zip_file(self) -> Optional[zipfile.ZipFile]: + return zipfile.ZipFile(self._filename) if self._filename else None + + @property + def version(self) -> mdl.Version: + """Bcf Version.""" + if not self._version: + self._version = ( + self._xml_handler.parse(self._zip_file.read("bcf.version"), mdl.Version) + if self._zip_file + else mdl.Version(version_id="3.0") + ) + return self._version + + @version.setter + def version(self, value: mdl.Version) -> None: + self._version = value + + @property + def project_info(self) -> Optional[mdl.ProjectInfo]: + """BCF project information.""" + if not self._project_info and self._zip_file and zipfile.Path(self._zip_file, "project.bcfp").exists(): + self._project_info = self._xml_handler.parse(self._zip_file.read("project.bcfp"), mdl.ProjectInfo) + return self._project_info + + @project_info.setter + def project_info(self, value: Optional[mdl.ProjectInfo]) -> None: + self._project_info = value + + @property + def project(self) -> Optional[mdl.Project]: + """BCF project.""" + return self.project_info.project if self.project_info else None + + @property + def extensions(self) -> Optional[mdl.Extensions]: + """BCF extensions.""" + if not self._extensions and self._zip_file: + self._extensions = self._xml_handler.parse(self._zip_file.read("extensions.xml"), mdl.Extensions) + return self._extensions + + @extensions.setter + def extensions(self, value: Optional[mdl.Extensions]) -> None: + self._extensions = value + + @property + def topics(self) -> dict[str, TopicHandler]: + """BCF topics.""" + if not self._topics and self._zip_file: + self._load_topics() + return self._topics + + def _load_topics(self) -> None: + for topic_dir in zipfile.Path(self._zip_file).iterdir(): + if not topic_dir.is_dir(): + continue + markup_path = topic_dir.joinpath("markup.bcf") + if not markup_path.exists(): + continue + self._topics[topic_dir.name] = TopicHandler(topic_dir, self._xml_handler) + + @property + def documents(self) -> Optional[DocumentsHandler]: + """Documents stored in the BCF file.""" + if not self._documents and self._zip_file: + self._documents = DocumentsHandler.load(self._zip_file, self._xml_handler) + return self._documents + + @classmethod + def load(cls, filename: Path, xml_handler: Optional[AbstractXmlParserSerializer] = None) -> Optional["BcfXml"]: + """ + Create a BcfXml object from a file. + + Args: + filename: Path to the file. + xml_handler: XML parser and serializer. + + Returns: + A BcfXml object with the file contents. + + Raises: + ValueError: If the file name is null or empty + """ + if not filename: + raise ValueError("filename is required") + xml_handler = xml_handler or XmlParserSerializer() + return cls(xml_handler=xml_handler, filename=filename) + + @classmethod + def create_new( + cls, + project_name: Optional[str] = None, + extensions: Optional[mdl.Extensions] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> "BcfXml": + """ + Create a new BcfXml object. + + Args: + project_name: The name of the project. + extensions: The Extension XML object. Defaults to an empty one. + xml_handler: XML parser and serializer. + + Returns: + A new BcfXml object. + """ + instance = cls(xml_handler=xml_handler or XmlParserSerializer()) + instance.project_info = mdl.ProjectInfo(project=mdl.Project(name=project_name, project_id=str(uuid.uuid4()))) + instance.extensions = extensions or mdl.Extensions() + return instance + + def save(self, filename: Optional[Path] = None, keep_open: bool = False) -> None: + """Save the BCF file to the given filename.""" + if not filename and not self._filename: + raise ValueError("No file name specified, cannot save BCF file.") + if filename: + self._filename = filename + with InMemoryZipFile(self._filename) as bcf_zip: + self._save_project(bcf_zip) + self._save_version(bcf_zip) + self._save_extensions(bcf_zip) + self._save_documents(bcf_zip) + self._save_topics(bcf_zip) + if keep_open: + self._zip_file = self._load_zip_file() + + def _save_project(self, destination_zip: ZipFileInterface) -> None: + self._smart_save_xml(destination_zip, self._project_info, "project.bcfp") + + def _save_version(self, destination_zip: ZipFileInterface) -> None: + if not self._version and self._zip_file: + destination_zip.writestr("bcf.version", self._zip_file.read("bcf.version")) + else: + self._save_xml(destination_zip, "bcf.version", self.version) + + def _save_extensions(self, destination_zip: ZipFileInterface) -> None: + self._smart_save_xml(destination_zip, self._extensions, "extensions.xml") + + def _smart_save_xml(self, destination_zip: ZipFileInterface, item: Any, target: str) -> None: + if item: + self._save_xml(destination_zip, target, item) + elif self._zip_file and zipfile.Path(self._zip_file, target).exists(): + destination_zip.writestr(target, self._zip_file.read(target)) + + def _save_xml(self, destination_zip: ZipFileInterface, inner_file: str, xml_obj: Any) -> None: + destination_zip.writestr(inner_file, self._xml_handler.serialize(xml_obj)) + + def _save_documents(self, bcf_zip: ZipFileInterface) -> None: + if self.documents: + self.documents.save(bcf_zip) + + def _save_topics(self, destination_zip: ZipFileInterface) -> None: + for topic_handler in self.topics.values(): + topic_handler.save(destination_zip) + + def add_topic( + self, title: str, description: str, author: str, topic_type: str = "", topic_status: str = "" + ) -> TopicHandler: + """ + Add a new topic to the BCF. + + Args: + title: The title of the topic. + description: The description of the topic. + author: The author of the topic. + topic_type: The type of the topic. + topic_status: The status of the topic. + + Returns: + The newly created topic wrapped inside a TopicHandler object. + """ + topic_handler = TopicHandler.create_new( + title, + description, + author, + topic_type=topic_type, + topic_status=topic_status, + xml_handler=self._xml_handler, + ) + self.topics[topic_handler.guid] = topic_handler + return topic_handler + + def __eq__(self, other: object) -> bool: + if not isinstance(other, BcfXml): + raise TypeError("Equality needs a BcfXml object.") + return ( + self.version == other.version + and self.project_info == other.project_info + and self.extensions == other.extensions + ) + + # region Deprecated methods + def new_project(self) -> "BcfXml": + """Deprecated method.""" + warnings.warn("new_project is deprecated, use create_new instead.", DeprecationWarning) + return self.create_new() + + def get_project(self, _filepath: Optional[str] = None) -> Optional[mdl.Project]: + """Deprecated method.""" + warnings.warn("get_project is deprecated, use project_info.project instead.", DeprecationWarning) return self.project - def edit_project(self): - self.document = minidom.Document() - root = self._create_element(self.document, "ProjectInfo") - project = self._create_element(root, "Project", {"ProjectId": self.project.project_id}) - if self.project.name: - self._create_element(project, "Name", text=self.project.name) - with open(os.path.join(self.filepath, "project.bcfp"), "wb") as f: - f.write(self.document.toprettyxml(encoding="utf-8")) + def edit_project(self) -> None: + """Deprecated method.""" + warnings.warn("edit_project is deprecated, there's no need to use it.", DeprecationWarning) - def save_project(self, filepath): - with cd(self.filepath): - zip_file = zipfile.ZipFile(filepath, "w", zipfile.ZIP_DEFLATED) - for root, dirs, files in os.walk("./"): - for file in files: - zip_file.write(os.path.join(root, file)) - zip_file.close() + def save_project(self, filepath: Path) -> None: + """Deprecated method.""" + warnings.warn("save_project is deprecated, use save instead.", DeprecationWarning) + self.save(filepath) - def get_version(self): - data = self._read_xml("bcf.version", "version.xsd") - self.version = data["@VersionId"] - return self.version + def get_version(self) -> str: + warnings.warn("get_version is deprecated, use version.version_id instead.", DeprecationWarning) + return self.version.version_id - def edit_version(self): - self.document = minidom.Document() - root = self._create_element(self.document, "Version", {"VersionId": self.version}) - with open(os.path.join(self.filepath, "bcf.version"), "wb") as f: - f.write(self.document.toprettyxml(encoding="utf-8")) + def edit_version(self) -> None: + """Deprecated method.""" + warnings.warn("edit_version is deprecated, there's no need to use it.", DeprecationWarning) - def get_topics(self): - self.topics = {} - topics = [] - subdirs = [] - for (dirpath, dirnames, filenames) in os.walk(self.filepath): - subdirs = dirnames - break - for subdir in subdirs: - try: - uuid.UUID(subdir) - except ValueError: - continue - if not os.path.exists(os.path.join(self.filepath, subdir, "markup.bcf")): - continue - self.topics[subdir] = self.get_topic(subdir) + def get_topics(self) -> dict[str, TopicHandler]: + """Deprecated method.""" + warnings.warn("get_topics is deprecated, use topics instead.", DeprecationWarning) return self.topics - def get_header(self, guid): - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - if "Header" not in data: - return - header = bcf.v3.data.Header() - if data["Header"].get("Files"): - for item in data["Header"]["Files"].get("File", []): - header_file = bcf.v3.data.HeaderFile() - optional_keys = { - "filename": "Filename", - "date": "Date", - "reference": "Reference", - "ifc_project": "@IfcProject", - "ifc_spatial_structure_element": "@IfcSpatialStructureElement", - "is_external": "@IsExternal", - } - for key, value in optional_keys.items(): - if value in item: - setattr(header_file, key, item[value]) - header.files.append(header_file) - self.topics[guid].header = header - return header + def get_topic(self, guid: str) -> TopicHandler: + """Return a topic by its GUID.""" + warnings.warn("get_topic is deprecated, use topics[guid] instead", DeprecationWarning) + return self.topics[guid] - def get_topic(self, guid): - if guid in self.topics: - return self.topics[guid] - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - topic = bcf.v3.data.Topic() - self.topics[guid] = topic + def get_header(self, guid: str) -> Optional[mdl.Header]: + """Return the header of a Topic by its GUID.""" + return self.topics[guid].header - mandatory_keys = { - "guid": "@Guid", - "title": "Title", - "creation_date": "CreationDate", - "creation_author": "CreationAuthor", - "topic_status": "@TopicStatus", - "topic_type": "@TopicType", - } - for key, value in mandatory_keys.items(): - setattr(topic, key, data["Topic"][value]) + def edit_topic(self) -> None: + """Deprecated method.""" + warnings.warn("edit_topic is deprecated, there's no need to use it.", DeprecationWarning) - optional_keys = { - "priority": "Priority", - "index": "Index", - "modified_date": "ModifiedDate", - "modified_author": "ModifiedAuthor", - "due_date": "DueDate", - "assigned_to": "AssignedTo", - "stage": "Stage", - "description": "Description", - "server_assigned_id": "@ServerAssignedId", - } - for key, value in optional_keys.items(): - if value in data["Topic"]: - setattr(topic, key, data["Topic"][value]) + def add_comment(self, _topic: mdl.Topic, _comment: Optional[mdl.Comment] = None) -> None: + """Deprecated method.""" + warnings.warn("add_comment is deprecated, use topics methods instead.", DeprecationWarning) - if data["Topic"].get("ReferenceLinks"): - topic.reference_links.extend(data["Topic"]["ReferenceLinks"].get("ReferenceLink", [])) + def edit_comment(self) -> None: + """Deprecated method.""" + warnings.warn("edit_comment is deprecated, there's no need to use it.", DeprecationWarning) - if data["Topic"].get("Labels"): - topic.labels.extend(data["Topic"]["Labels"].get("Label", [])) - - if "BimSnippet" in data["Topic"]: - bim_snippet = bcf.v3.data.BimSnippet() - keys = { - "snippet_type": "@SnippetType", - "is_external": "@IsExternal", - "reference": "Reference", - "reference_schema": "ReferenceSchema", - } - for key, value in keys.items(): - if value in data["Topic"]["BimSnippet"]: - setattr(bim_snippet, key, data["Topic"]["BimSnippet"][value]) - topic.bim_snippet = bim_snippet - - if data["Topic"].get("DocumentReferences"): - for item in data["Topic"]["DocumentReferences"].get("DocumentReference", []): - document_reference = bcf.v3.data.DocumentReference() - keys = { - "document_guid": "DocumentGuid", - "url": "Url", - "guid": "@Guid", - "description": "Description", - } - for key, value in keys.items(): - if value in item: - setattr(document_reference, key, item[value]) - topic.document_references.append(document_reference) - - if data["Topic"].get("RelatedTopics"): - for item in data["Topic"]["RelatedTopics"].get("RelatedTopic", []): - related_topic = bcf.v3.data.RelatedTopic() - related_topic.guid = item["@Guid"] - topic.related_topics.append(related_topic) - return topic - - def add_topic(self, topic=None): - if topic is None: - topic = bcf.v3.data.Topic() - if not topic.guid: - topic.guid = str(uuid.uuid4()) - if not topic.title: - topic.title = "New Topic" - os.mkdir(os.path.join(self.filepath, topic.guid)) - self.edit_topic(topic) - return topic - - def edit_topic(self, topic): - if not topic.creation_date: - topic.creation_date = datetime.utcnow().isoformat() - topic.creation_author = self.author - else: - topic.modified_date = datetime.utcnow().isoformat() - topic.modified_author = self.author - - self.document = minidom.Document() - root = self._create_element(self.document, "Markup") - if topic.header: - self.write_header(topic.header, root) - - topic_el = self._create_element( - root, - "Topic", - { - "Guid": topic.guid, - "ServerAssignedId": topic.server_assigned_id, - "TopicType": topic.topic_type, - "TopicStatus": topic.topic_status, - }, - ) - if topic.reference_links: - reference_Links_el = self._create_element(topic_el, "ReferenceLinks") - for reference_link in topic.reference_links: - self._create_element(reference_Links_el, "ReferenceLink", text=reference_link) - - text_map = { - "Title": topic.title, - "Priority": topic.priority, - "Index": topic.index, - } - for key, value in text_map.items(): - if value: - self._create_element(topic_el, key, text=value) - if topic.labels: - label_el = self._create_element(topic_el, "Labels") - for label in topic.labels: - self._create_element(label_el, "Label", text=label) - - text_map = { - "CreationDate": topic.creation_date, - "CreationAuthor": topic.creation_author, - "ModifiedDate": topic.modified_date, - "ModifiedAuthor": topic.modified_author, - "DueDate": topic.due_date, - "AssignedTo": topic.assigned_to, - "Stage": topic.stage, - "Description": topic.description, - } - for key, value in text_map.items(): - if value: - self._create_element(topic_el, key, text=value) - - if topic.bim_snippet: - bim_snippet = self._create_element( - topic_el, - "BimSnippet", - { - "SnippetType": topic.bim_snippet.snippet_type, - "IsExternal": topic.bim_snippet.is_external, - }, - ) - self._create_element(bim_snippet, "Reference", text=topic.bim_snippet.reference) - self._create_element( - bim_snippet, - "ReferenceSchema", - text=topic.bim_snippet.reference_schema, - ) - if topic.document_references: - reference_el = self._create_element(topic_el, "DocumentReferences") - self.write_document_references(topic.document_references, reference_el) - if topic.related_topics: - related_topic_el = self._create_element(topic_el, "RelatedTopics") - for related_topic in topic.related_topics: - self._create_element(related_topic_el, "RelatedTopic", {"Guid": related_topic.guid}) - if topic.comments: - comment_el = self._create_element(topic_el, "Comments") - self.write_comments(topic.comments, comment_el) - if topic.viewpoints: - viewpoint_el = self._create_element(topic_el, "Viewpoints") - self.write_viewpoints(topic.viewpoints, viewpoint_el, topic) - with open(os.path.join(self.filepath, topic.guid, "markup.bcf"), "wb") as f: - f.write(self.document.toprettyxml(encoding="utf-8")) - - def write_document_references(self, references, root): - for reference in references: - document_reference_el = self._create_element(root, "DocumentReference", {"Guid": reference.guid}) - if reference.document_guid: - self._create_element(document_reference_el, "DocumentGuid", text=reference.document_guid) - elif reference.url: - self._create_element(document_reference_el, "Url", text=reference.url) - if reference.description: - self._create_element(document_reference_el, "Description", text=reference.description) - - def write_header(self, header, root): - if not header or not header.files: - return - header_el = self._create_element(root, "Header") - files_el = self._create_element(header_el, "Files") - for f in header.files: - file_el = self._create_element( - files_el, - "File", - { - "IfcProject": f.ifc_project, - "IfcSpatialStructureElement": f.ifc_spatial_structure_element, - "IsExternal": f.is_external, - }, - ) - if f.filename: - self._create_element(file_el, "Filename", text=f.filename) - if f.date: - self._create_element(file_el, "Date", text=f.date) - if f.reference: - self._create_element(file_el, "Reference", text=f.reference) - - def write_comments(self, comments, root): - for comment in comments.values(): - comment_el = self._create_element(root, "Comment", {"Guid": comment.guid}) - text_map = { - "Date": comment.date, - "Author": comment.author, - "Comment": comment.comment, - "ModifiedDate": comment.modified_date, - "ModifiedAuthor": comment.modified_author, - } - for key, value in text_map.items(): - if value: - self._create_element(comment_el, key, text=value) - if comment.viewpoint: - self._create_element(comment_el, "Viewpoint", {"Guid": comment.viewpoint.guid}) - - def add_comment(self, topic, comment=None): - if comment is None: - comment = bcf.v3.data.Comment() - if not comment.guid: - comment.guid = str(uuid.uuid4()) - if not comment.comment: - comment.comment = "'Free software' is a matter of liberty, not price. To understand the concept, you should think of 'free' as in 'free speech,' not as in 'free beer'." - topic.comments[comment.guid] = comment - self.edit_comment(comment, topic) - - def edit_comment(self, comment, topic): - if not comment.date: - comment.date = datetime.utcnow().isoformat() - comment.author = self.author - else: - comment.modified_date = datetime.utcnow().isoformat() - comment.modified_author = self.author - self.edit_topic(topic) - - def delete_comment(self, guid, topic): - if guid in topic.comments: - del topic.comments[guid] - self.edit_topic(topic) - - def delete_topic(self, guid): - if guid in self.topics: - del self.topics[guid] - shutil.rmtree(os.path.join(self.filepath, guid)) - - def write_viewpoints(self, viewpoints, root, topic): - for viewpoint in viewpoints.values(): - viewpoint_el = self._create_element(root, "ViewPoint", {"Guid": viewpoint.guid}) - text_map = { - "Viewpoint": viewpoint.viewpoint, - "Snapshot": viewpoint.snapshot, - "Index": viewpoint.index, - } - for key, value in text_map.items(): - if value: - self._create_element(viewpoint_el, key, text=value) - self.write_viewpoint(viewpoint, topic) - - def write_viewpoint(self, viewpoint, topic): - document = minidom.Document() - root = self._create_element(document, "VisualizationInfo", {"Guid": viewpoint.guid}) - self.write_viewpoint_components(viewpoint, root) - self.write_viewpoint_orthogonal_camera(viewpoint, root) - self.write_viewpoint_perspective_camera(viewpoint, root) - self.write_viewpoint_lines(viewpoint, root) - self.write_viewpoint_clipping_planes(viewpoint, root) - self.write_viewpoint_bitmaps(viewpoint, root) - with open(os.path.join(self.filepath, topic.guid, viewpoint.viewpoint), "wb") as f: - f.write(document.toprettyxml(encoding="utf-8")) - - def write_viewpoint_components(self, viewpoint, parent): - if not viewpoint.components: - return - components_el = self._create_element(parent, "Components") - if viewpoint.components.selection: - selection_el = self._create_element(components_el, "Selection") - for selection in viewpoint.components.selection: - self.write_component(selection, selection_el) - if viewpoint.components.visibility: - visibility = self._create_element( - components_el, - "Visibility", - {"DefaultVisibility": viewpoint.components.visibility.default_visibility}, - ) - if viewpoint.components.visibility.view_setup_hints: - view_setup_hints = self._create_element( - visibility, - "ViewSetupHints", - { - "SpacesVisible": viewpoint.components.visibility.view_setup_hints.spaces_visible, - "SpaceBoundariesVisible": viewpoint.components.visibility.view_setup_hints.space_boundaries_visible, - "OpeningsVisible": viewpoint.components.visibility.view_setup_hints.openings_visible, - }, - ) - if viewpoint.components.visibility.exceptions: - exceptions_el = self._create_element(visibility, "Exceptions") - for exception in viewpoint.components.visibility.exceptions: - self.write_component(exception, exceptions_el) - if viewpoint.components.coloring: - coloring_el = self._create_element(components_el, "Coloring") - for color in viewpoint.components.coloring: - color_el = self._create_element(coloring_el, "Color", {"Color": color.color}) - component_el = self._create_element(color_el, "Components") - for component in color.components: - self.write_component(component, component_el) - - def write_viewpoint_orthogonal_camera(self, viewpoint, parent): - if not viewpoint.orthogonal_camera: - return - camera = viewpoint.orthogonal_camera - camera_el = self._create_element(parent, "OrthogonalCamera") - camera_view_point = self._create_element(camera_el, "CameraViewPoint") - self.write_vector(camera_view_point, camera.camera_view_point) - camera_direction = self._create_element(camera_el, "CameraDirection") - self.write_vector(camera_direction, camera.camera_direction) - camera_up_vector = self._create_element(camera_el, "CameraUpVector") - self.write_vector(camera_up_vector, camera.camera_up_vector) - self._create_element(camera_el, "ViewToWorldScale", text=camera.view_to_world_scale) - self._create_element(camera_el, "AspectRatio", text=camera.aspect_ratio) - - def write_viewpoint_perspective_camera(self, viewpoint, parent): - if not viewpoint.perspective_camera: - return - camera = viewpoint.perspective_camera - camera_el = self._create_element(parent, "PerspectiveCamera") - camera_view_point = self._create_element(camera_el, "CameraViewPoint") - self.write_vector(camera_view_point, camera.camera_view_point) - camera_direction = self._create_element(camera_el, "CameraDirection") - self.write_vector(camera_direction, camera.camera_direction) - camera_up_vector = self._create_element(camera_el, "CameraUpVector") - self.write_vector(camera_up_vector, camera.camera_up_vector) - self._create_element(camera_el, "FieldOfView", text=camera.field_of_view) - self._create_element(camera_el, "AspectRatio", text=camera.aspect_ratio) - - def write_viewpoint_lines(self, viewpoint, parent): - if not viewpoint.lines: - return - lines_el = self._create_element(parent, "Lines") - for line in viewpoint.lines: - line_el = self._create_element(lines_el, "Line") - start_point_el = self._create_element(line_el, "StartPoint") - self.write_vector(start_point_el, line.start_point) - end_point_el = self._create_element(line_el, "EndPoint") - self.write_vector(end_point_el, line.end_point) - - def write_viewpoint_clipping_planes(self, viewpoint, parent): - if not viewpoint.clipping_planes: - return - planes_el = self._create_element(parent, "ClippingPlanes") - for plane in viewpoint.clipping_planes: - plane_el = self._create_element(planes_el, "ClippingPlane") - location_el = self._create_element(plane_el, "Location") - self.write_vector(location_el, plane.location) - direction_el = self._create_element(plane_el, "Direction") - self.write_vector(direction_el, plane.direction) - - def write_viewpoint_bitmaps(self, viewpoint, parent): - if not viewpoint.bitmaps: - return - bitmaps_el = self._create_element(parent, "Bitmaps") - for bitmap in viewpoint.bitmaps: - bitmap_el = self._create_element(bitmaps_el, "Bitmap") - - text_map = {"Format": bitmap.bitmap_format, "Reference": bitmap.reference} - for key, value in text_map.items(): - self._create_element(bitmap_el, key, text=value) - - location_el = self._create_element(bitmap_el, "Location") - self.write_vector(location_el, bitmap.location) - normal_el = self._create_element(bitmap_el, "Normal") - self.write_vector(normal_el, bitmap.normal) - up_el = self._create_element(bitmap_el, "Up") - self.write_vector(up_el, bitmap.up) - - self._create_element(bitmap_el, "Height", text=bitmap.height) - - def write_vector(self, parent, from_obj): - self._create_element(parent, "X", text=from_obj.x) - self._create_element(parent, "Y", text=from_obj.y) - self._create_element(parent, "Z", text=from_obj.z) - - def write_component(self, data, parent): - component_el = self._create_element(parent, "Component", {"IfcGuid": data.ifc_guid}) - text_map = { - "OriginatingSystem": data.originating_system, - "AuthoringToolId": data.authoring_tool_id, - } - for key, value in text_map.items(): - if value: - self._create_element(component_el, key, text=value) - - def add_viewpoint(self, topic, viewpoint=None): - if not viewpoint: - viewpoint = bcf.v3.data.Viewpoint() - if not viewpoint.guid: - viewpoint.guid = str(uuid.uuid4()) - if not viewpoint.viewpoint: - viewpoint.viewpoint = f"{viewpoint.guid}.bcfv" - if viewpoint.snapshot: - topic_filepath = os.path.join(self.filepath, topic.guid) - filepath = os.path.join(topic_filepath, viewpoint.snapshot) - if not os.path.exists(filepath): - filename = viewpoint.guid + os.path.splitext(viewpoint.snapshot)[-1] - copyfile(viewpoint.snapshot, os.path.join(topic_filepath, filename)) - viewpoint.snapshot = filename - topic.viewpoints[viewpoint.guid] = viewpoint - self.edit_topic(topic) - - def delete_viewpoint(self, guid, topic): - if guid not in topic.viewpoints: - return - viewpoint = topic.viewpoints[guid] - if viewpoint.snapshot: - filepath = os.path.join(self.filepath, topic.guid, viewpoint.snapshot) - if os.path.exists(filepath): - os.remove(filepath) - if viewpoint.viewpoint: - filepath = os.path.join(self.filepath, topic.guid, viewpoint.viewpoint) - if os.path.exists(filepath): - os.remove(filepath) - for bitmap in viewpoint.bitmaps: - if not bitmap.reference: - continue - filepath = os.path.join(self.filepath, topic.guid, bitmap.reference) - if os.path.exists(filepath): - os.remove(filepath) - del topic.viewpoints[guid] - self.edit_topic(topic) - - def delete_file(self, topic, index): - if not topic.header: - return - f = topic.header.files.pop(index) - filepath = os.path.join(self.filepath, topic.guid, f.reference) - if not f.is_external and os.path.exists(filepath): - os.remove(filepath) - self.edit_topic(topic) - - def delete_bim_snippet(self, topic): - if not topic.bim_snippet: - return - if topic.bim_snippet.reference and not topic.bim_snippet.is_external: - filepath = os.path.join(self.filepath, topic.guid, topic.bim_snippet.reference) - if os.path.exists(filepath): - os.remove(filepath) - topic.bim_snippet = None - self.edit_topic(topic) - - def delete_document_reference(self, topic, index): - document_reference = topic.document_references[index] - if document_reference.referenced_document and not document_reference.is_external: - filepath = os.path.join(self.filepath, topic.guid, document_reference.referenced_document) - if os.path.exists(filepath): - os.remove(filepath) - del topic.document_references[index] - self.edit_topic(topic) - - def add_document_reference(self, topic, document_reference): - if os.path.exists(document_reference.referenced_document): - topic_filepath = os.path.join(self.filepath, topic.guid) - filename = os.path.basename(document_reference.referenced_document) - copyfile( - document_reference.referenced_document, - os.path.join(topic_filepath, filename), - ) - document_reference.referenced_document = filename - document_reference.is_external = False - else: - document_reference.is_external = True - if not document_reference.guid: - document_reference.guid = str(uuid.uuid4()) - topic.document_references.append(document_reference) - self.edit_topic(topic) - - def add_bim_snippet(self, topic, bim_snippet): - if topic.bim_snippet: - self.delete_bim_snippet(topic) - if os.path.exists(bim_snippet.reference): - topic_filepath = os.path.join(self.filepath, topic.guid) - filename = os.path.basename(bim_snippet.reference) - copyfile(bim_snippet.reference, os.path.join(topic_filepath, filename)) - bim_snippet.reference = filename - bim_snippet.is_external = False - else: - bim_snippet.is_external = True - topic.bim_snippet = bim_snippet - self.edit_topic(topic) - - def add_file(self, topic, header_file): - if os.path.exists(header_file.reference): - topic_filepath = os.path.join(self.filepath, topic.guid) - header_file.filename = os.path.basename(header_file.reference) - copyfile( - header_file.reference, - os.path.join(topic_filepath, header_file.filename), - ) - header_file.reference = header_file.filename - header_file.is_external = False - header_file.date = datetime.utcnow().isoformat() - if not topic.header: - topic.header = bcf.v3.data.Header() - topic.header.files.append(header_file) - self.edit_topic(topic) - - def get_comments(self, guid): - comments = {} - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - if "Comments" not in data["Topic"]: - return comments - - for item in data["Topic"]["Comments"].get("Comment", []): - comment = bcf.v3.data.Comment() - mandatory_keys = { - "guid": "@Guid", - "date": "Date", - "author": "Author", - } - for key, value in mandatory_keys.items(): - setattr(comment, key, item[value]) - optional_keys = { - "comment": "Comment", - "modified_date": "ModifiedDate", - "modified_author": "ModifiedAuthor", - } - for key, value in optional_keys.items(): - if value in item: - setattr(comment, key, item[value]) - if "Viewpoint" in item: - viewpoint = bcf.v3.data.Viewpoint() - viewpoint.guid = item["Viewpoint"]["@Guid"] - comment.viewpoint = viewpoint - comments[comment.guid] = comment - self.topics[guid].comments = comments - return comments - - def get_viewpoints(self, guid): - viewpoints = {} - data = self._read_xml(os.path.join(guid, "markup.bcf"), "markup.xsd") - if "Viewpoints" not in data["Topic"]: - return viewpoints - for item in data["Topic"]["Viewpoints"]: - viewpoint = self.get_viewpoint(item, guid) - viewpoints[viewpoint.guid] = viewpoint - self.topics[guid].viewpoints = viewpoints - return viewpoints - - def get_viewpoint(self, data, topic_guid): - viewpoint = bcf.v3.data.Viewpoint() - viewpoint.guid = data["@Guid"] - optional_keys = { - "viewpoint": "Viewpoint", - "snapshot": "Snapshot", - "index": "Index", - } - for key, value in optional_keys.items(): - if value in data: - setattr(viewpoint, key, data[value]) - visinfo = self._read_xml(os.path.join(topic_guid, viewpoint.viewpoint), "visinfo.xsd") - viewpoint.components = self.get_viewpoint_components(visinfo) - viewpoint.orthogonal_camera = self.get_viewpoint_orthogonal_camera(visinfo) - viewpoint.perspective_camera = self.get_viewpoint_perspective_camera(visinfo) - viewpoint.lines = self.get_viewpoint_lines(visinfo) - viewpoint.clipping_planes = self.get_viewpoint_clipping_planes(visinfo) - viewpoint.bitmaps = self.get_viewpoint_bitmaps(visinfo) - return viewpoint - - def get_viewpoint_components(self, visinfo): - if "Components" not in visinfo: - return None - components = bcf.v3.data.Components() - data = visinfo["Components"] - if "Selection" in data and "Component" in data["Selection"]: - for item in data["Selection"].get("Component", []): - components.selection.append(self.get_component(item)) - if "Visibility" in data: - component_visibility = bcf.v3.data.ComponentVisibility() - if "@DefaultVisibility" in data["Visibility"]: - component_visibility.default_visibility = data["Visibility"]["@DefaultVisibility"] - if "Exceptions" in data["Visibility"] and "Component" in data["Visibility"]["Exceptions"]: - for item in data["Visibility"]["Exceptions"]["Component"]: - component_visibility.exceptions.append(self.get_component(item)) - if "ViewSetupHints" in data["Visibility"]: - view_setup_hints = bcf.v3.data.ViewSetupHints() - optional_keys = { - "spaces_visible": "@SpacesVisible", - "space_boundaries_visible": "@SpaceBoundariesVisible", - "openings_visible": "@OpeningsVisible", - } - for key, value in optional_keys.items(): - if value in data["Visibility"]["ViewSetupHints"]: - setattr(view_setup_hints, key, data["Visibility"]["ViewSetupHints"][value]) - component_visibility.view_setup_hints = view_setup_hints - components.visibility = component_visibility - if "Coloring" in data and "Color" in data["Coloring"]: - for item in data["Coloring"]["Color"]: - color = bcf.v3.data.Color() - color.color = item["@Color"] - for item2 in item["Components"]["Component"]: - color.components.append(self.get_component(item2)) - components.coloring.append(color) - return components - - def get_viewpoint_orthogonal_camera(self, visinfo): - if "OrthogonalCamera" not in visinfo: - return None - camera = bcf.v3.data.OrthogonalCamera() - data = visinfo["OrthogonalCamera"] - self.set_vector(camera.camera_view_point, data["CameraViewPoint"]) - self.set_vector(camera.camera_direction, data["CameraDirection"]) - self.set_vector(camera.camera_up_vector, data["CameraUpVector"]) - camera.view_to_world_scale = data["ViewToWorldScale"] - camera.aspect_ratio = data["AspectRatio"] - return camera - - def get_viewpoint_perspective_camera(self, visinfo): - if "PerspectiveCamera" not in visinfo: - return None - camera = bcf.v3.data.PerspectiveCamera() - data = visinfo["PerspectiveCamera"] - self.set_vector(camera.camera_view_point, data["CameraViewPoint"]) - self.set_vector(camera.camera_direction, data["CameraDirection"]) - self.set_vector(camera.camera_up_vector, data["CameraUpVector"]) - camera.field_of_view = data["FieldOfView"] - camera.aspect_ratio = data["AspectRatio"] - return camera - - def get_viewpoint_lines(self, visinfo): - if "Lines" not in visinfo: - return [] - lines = [] - for item in visinfo["Lines"].get("Line", []): - line = bcf.v3.data.Line() - self.set_vector(line.start_point, item["StartPoint"]) - self.set_vector(line.end_point, item["EndPoint"]) - lines.append(line) - return lines - - def get_viewpoint_clipping_planes(self, visinfo): - if "ClippingPlanes" not in visinfo: - return [] - planes = [] - for item in visinfo["ClippingPlanes"]["ClippingPlane"]: - plane = bcf.v3.data.ClippingPlane() - self.set_vector(plane.location, item["Location"]) - self.set_vector(plane.direction, item["Direction"]) - planes.append(plane) - return planes - - def get_viewpoint_bitmaps(self, visinfo): - if "Bitmaps" not in visinfo: - return [] - bitmaps = [] - for item in visinfo["Bitmaps"].get("Bitmap"): - bitmap = bcf.v3.data.Bitmap() - bitmap.reference = item["Reference"] - bitmap.bitmap_format = item["Format"].upper() - self.set_vector(bitmap.location, item["Location"]) - self.set_vector(bitmap.normal, item["Normal"]) - self.set_vector(bitmap.up, item["Up"]) - bitmap.height = item["Height"] - bitmaps.append(bitmap) - return bitmaps - - def set_vector(self, to_obj, from_xml): - to_obj.x = from_xml["X"] - to_obj.y = from_xml["Y"] - to_obj.z = from_xml["Z"] - - def get_component(self, data): - component = bcf.v3.data.Component() - optional_keys = { - "originating_system": "OriginatingSystem", - "authoring_tool_id": "AuthoringToolId", - "ifc_guid": "@IfcGuid", - } - for key, value in optional_keys.items(): - if value in data: - setattr(component, key, data[value]) - return component - - def close_project(self): - shutil.rmtree(self.filepath) - - def _read_xml(self, filename, xsd): - schema = XMLSchema(os.path.join(cwd, "xsd", xsd)) - filepath = os.path.join(self.filepath, filename) - (data, errors) = schema.to_dict(filepath, validation="lax") - for error in errors: - self.logger.error(error) - return data - - def _create_element(self, parent, name, attributes={}, text=None): - element = self.document.createElement(name) - for key, value in attributes.items(): - if isinstance(value, bool): - element.setAttribute(key, str(value).lower()) - elif value: - element.setAttribute(key, value) - if text is not None: - text = self.document.createTextNode(str(text)) - element.appendChild(text) - parent.appendChild(element) - return element - - def __del__(self): - self.close_project() + # TODO: deprecate other methods + # endregion diff --git a/src/bcf/src/bcf/v3/data.py b/src/bcf/src/bcf/v3/data.py deleted file mode 100644 index c98efc42fd..0000000000 --- a/src/bcf/src/bcf/v3/data.py +++ /dev/null @@ -1,200 +0,0 @@ - -# BCF - BCF Python library -# Copyright (C) 2021 Prabhat Singh -# -# 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 . - -class Project: - def __init__(self): - self.project_id = "" - self.name = "" - - -class BimSnippet: - def __init__(self): - self.snippet_type = None - self.is_external = False - self.reference = None - self.reference_schema = None - - -class DocumentReference: - def __init__(self): - self.description = None - self.document_guid = None - self.url = None - self.guid = None - - -class RelatedTopic: - def __init__(self): - self.guid = None - - -class HeaderFile: - def __init__(self): - self.filename = "" - self.date = None - self.reference = "" - self.ifc_project = None - self.ifc_spatial_structure_element = None - self.is_external = True - - -class Header: - def __init__(self): - self.files = [] - - -class Topic: - def __init__(self): - self.reference_links = [] - self.title = "" - self.priority = None - self.index = None # Deprecated, stored, but ignored - self.labels = [] - self.creation_date = None - self.creation_author = None - self.modified_date = None - self.modified_author = None - self.due_date = None - self.assigned_to = None - self.stage = None - self.description = None - self.bim_snippet = None - self.document_references = [] - self.related_topics = [] - self.topic_status = None - self.topic_type = None - self.guid = None - - self.header = None - self.comments = {} - self.viewpoints = {} - self.server_assigned_id = "" - - -class Comment: - def __init__(self): - self.guid = None - self.date = None - self.author = "" - self.comment = "" - self.viewpoint = None - self.modified_date = None - self.modified_author = "" - - -class ViewSetupHints: - def __init__(self): - self.spaces_visible = False - self.space_boundaries_visible = False - self.openings_visible = False - - -class Component: - def __init__(self): - self.originating_system = None - self.authoring_tool_id = None - self.ifc_guid = None - - -class ComponentVisibility: - def __init__(self): - self.exceptions = [] - self.default_visibility = False - self.view_setup_hints = None - - -class Color: - def __init__(self): - self.color = None - self.components = [] - - -class Components: - def __init__(self): - - self.selection = [] - self.visibility = None - self.coloring = [] - - -class Point: - def __init__(self): - self.x = 0 - self.y = 0 - self.z = 0 - - -class Direction(Point): - pass - - -class OrthogonalCamera: - def __init__(self): - self.camera_view_point = Point() - self.camera_direction = Direction() - self.camera_up_vector = Direction() - self.view_to_world_scale = 1.0 - self.aspect_ratio = 1.0 - - -class PerspectiveCamera: - def __init__(self): - self.camera_view_point = Point() - self.camera_direction = Direction() - self.camera_up_vector = Direction() - self.field_of_view = 60.0 - self.aspect_ratio = 1.0 - - -class Line: - def __init__(self): - self.start_point = Point() - self.end_point = Point() - - -class ClippingPlane: - def __init__(self): - self.location = Point() - self.direction = Direction() - - -class Bitmap: - def __init__(self): - self.reference = "" # Only in BCF-XML - self.bitmap_data = None # Only in BCF-API - self.bitmap_format = "PNG" # Enum of png or jpg - self.location = Point() - self.normal = Direction() - self.up = Direction() - self.height = 1.0 - - -class Viewpoint: - def __init__(self): - self.guid = None - self.viewpoint = None - self.snapshot = None - self.index = None - - self.components = None # It's not a list, despite the plural name - self.orthogonal_camera = None - self.perspective_camera = None - self.lines = [] - self.clipping_planes = [] - self.bitmaps = [] diff --git a/src/bcf/src/bcf/v3/document.py b/src/bcf/src/bcf/v3/document.py new file mode 100644 index 0000000000..56a15da42d --- /dev/null +++ b/src/bcf/src/bcf/v3/document.py @@ -0,0 +1,61 @@ +"""BCF XML V3 Documents handler.""" +import zipfile +from typing import Any, Optional + +import bcf.v3.model as mdl +from bcf.inmemory_zipfile import ZipFileInterface +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer + + +class DocumentsHandler: + """BCF documents handler.""" + + def __init__( + self, + definition: mdl.DocumentInfo, + documents: Optional[dict[str, bytes]] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> None: + self.definition = definition + self.documents = documents or {} + self._xml_handler = xml_handler or XmlParserSerializer() + + @classmethod + def load( + cls, + zip_file: zipfile.ZipFile, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> Optional["DocumentsHandler"]: + """ + Loads the documents from the given zip file directory. + + Args: + zip_path: The directory path inside the zip file. + xml_handler: The xml parser/serializer to use. + + Returns: + The documents handler. + """ + xml_handler = xml_handler or XmlParserSerializer() + file_to_open = zipfile.Path(zip_file, "documents.xml") + if not file_to_open.exists(): + return None + definition = xml_handler.parse(file_to_open.read_bytes(), mdl.DocumentInfo) + documents = {} + if def_docs := definition.documents: + for document in def_docs.document: + document_path = zipfile.Path(zip_file, f"documents/{document.guid}") + if document_path.exists(): + documents[document.filename] = document_path.read_bytes() + return cls(definition, documents=documents) + + def save(self, bcf_zip: ZipFileInterface) -> None: + """Save the documents to the zip file.""" + bcf_zip.writestr("documents.xml", self._xml_handler.serialize(self.definition)) + if documents := self.definition.documents: + for doc in documents.document: + if doc.filename in self.documents: + bcf_zip.writestr( + f"documents/{doc.guid}", + self.documents[doc.filename], + ) diff --git a/src/bcf/src/bcf/v3/model/__init__.py b/src/bcf/src/bcf/v3/model/__init__.py new file mode 100644 index 0000000000..ed74e66dcc --- /dev/null +++ b/src/bcf/src/bcf/v3/model/__init__.py @@ -0,0 +1,110 @@ +from bcf.v3.model.documents import Document, DocumentInfo, DocumentInfoDocuments +from bcf.v3.model.extensions import ( + Extensions, + ExtensionsPriorities, + ExtensionsSnippetTypes, + ExtensionsStages, + ExtensionsTopicLabels, + ExtensionsTopicStatuses, + ExtensionsTopicTypes, + ExtensionsUsers, +) +from bcf.v3.model.markup import ( + BimSnippet, + Comment, + CommentViewpoint, + DocumentReference, + File, + Header, + HeaderFiles, + Markup, + Topic, + TopicComments, + TopicDocumentReferences, + TopicLabels, + TopicReferenceLinks, + TopicRelatedTopics, + TopicRelatedTopicsRelatedTopic, + TopicViewpoints, + ViewPoint, +) +from bcf.v3.model.project import Project, ProjectInfo +from bcf.v3.model.version import Version +from bcf.v3.model.visinfo import ( + Bitmap, + BitmapFormat, + ClippingPlane, + Component, + ComponentColoring, + ComponentColoringColor, + ComponentColoringColorComponents, + Components, + ComponentSelection, + ComponentVisibility, + ComponentVisibilityExceptions, + Direction, + Line, + OrthogonalCamera, + PerspectiveCamera, + Point, + ViewSetupHints, + VisualizationInfo, + VisualizationInfoBitmaps, + VisualizationInfoClippingPlanes, + VisualizationInfoLines, +) + +__all__ = [ + "Document", + "DocumentInfo", + "DocumentInfoDocuments", + "Extensions", + "ExtensionsPriorities", + "ExtensionsSnippetTypes", + "ExtensionsStages", + "ExtensionsTopicLabels", + "ExtensionsTopicStatuses", + "ExtensionsTopicTypes", + "ExtensionsUsers", + "BimSnippet", + "Comment", + "CommentViewpoint", + "DocumentReference", + "File", + "Header", + "HeaderFiles", + "Markup", + "Topic", + "TopicComments", + "TopicDocumentReferences", + "TopicLabels", + "TopicReferenceLinks", + "TopicRelatedTopics", + "TopicRelatedTopicsRelatedTopic", + "TopicViewpoints", + "ViewPoint", + "Project", + "ProjectInfo", + "Version", + "Bitmap", + "BitmapFormat", + "ClippingPlane", + "Component", + "ComponentColoring", + "ComponentColoringColor", + "ComponentColoringColorComponents", + "ComponentSelection", + "ComponentVisibility", + "ComponentVisibilityExceptions", + "Components", + "Direction", + "Line", + "OrthogonalCamera", + "PerspectiveCamera", + "Point", + "ViewSetupHints", + "VisualizationInfo", + "VisualizationInfoBitmaps", + "VisualizationInfoClippingPlanes", + "VisualizationInfoLines", +] diff --git a/src/bcf/src/bcf/v3/model/documents.py b/src/bcf/src/bcf/v3/model/documents.py new file mode 100644 index 0000000000..c9a1b43c9c --- /dev/null +++ b/src/bcf/src/bcf/v3/model/documents.py @@ -0,0 +1,61 @@ +from dataclasses import dataclass, field +from typing import List, Optional + + +@dataclass(slots=True, kw_only=True) +class Document: + filename: str = field( + metadata={ + "name": "Filename", + "type": "Element", + "namespace": "", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + description: Optional[str] = field( + default=None, + metadata={ + "name": "Description", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class DocumentInfoDocuments: + class Meta: + global_type = False + + document: List[Document] = field( + default_factory=list, + metadata={ + "name": "Document", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class DocumentInfo: + documents: Optional[DocumentInfoDocuments] = field( + default=None, + metadata={ + "name": "Documents", + "type": "Element", + "namespace": "", + } + ) diff --git a/src/bcf/src/bcf/v3/model/extensions.py b/src/bcf/src/bcf/v3/model/extensions.py new file mode 100644 index 0000000000..cb0af500f6 --- /dev/null +++ b/src/bcf/src/bcf/v3/model/extensions.py @@ -0,0 +1,181 @@ +from dataclasses import dataclass, field +from typing import List, Optional + + +@dataclass(slots=True, kw_only=True) +class ExtensionsPriorities: + class Meta: + global_type = False + + priority: List[str] = field( + default_factory=list, + metadata={ + "name": "Priority", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ExtensionsSnippetTypes: + class Meta: + global_type = False + + snippet_type: List[str] = field( + default_factory=list, + metadata={ + "name": "SnippetType", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ExtensionsStages: + class Meta: + global_type = False + + stage: List[str] = field( + default_factory=list, + metadata={ + "name": "Stage", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ExtensionsTopicLabels: + class Meta: + global_type = False + + topic_label: List[str] = field( + default_factory=list, + metadata={ + "name": "TopicLabel", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ExtensionsTopicStatuses: + class Meta: + global_type = False + + topic_status: List[str] = field( + default_factory=list, + metadata={ + "name": "TopicStatus", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ExtensionsTopicTypes: + class Meta: + global_type = False + + topic_type: List[str] = field( + default_factory=list, + metadata={ + "name": "TopicType", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ExtensionsUsers: + class Meta: + global_type = False + + user: List[str] = field( + default_factory=list, + metadata={ + "name": "User", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Extensions: + topic_types: Optional[ExtensionsTopicTypes] = field( + default=None, + metadata={ + "name": "TopicTypes", + "type": "Element", + "namespace": "", + } + ) + topic_statuses: Optional[ExtensionsTopicStatuses] = field( + default=None, + metadata={ + "name": "TopicStatuses", + "type": "Element", + "namespace": "", + } + ) + priorities: Optional[ExtensionsPriorities] = field( + default=None, + metadata={ + "name": "Priorities", + "type": "Element", + "namespace": "", + } + ) + topic_labels: Optional[ExtensionsTopicLabels] = field( + default=None, + metadata={ + "name": "TopicLabels", + "type": "Element", + "namespace": "", + } + ) + users: Optional[ExtensionsUsers] = field( + default=None, + metadata={ + "name": "Users", + "type": "Element", + "namespace": "", + } + ) + snippet_types: Optional[ExtensionsSnippetTypes] = field( + default=None, + metadata={ + "name": "SnippetTypes", + "type": "Element", + "namespace": "", + } + ) + stages: Optional[ExtensionsStages] = field( + default=None, + metadata={ + "name": "Stages", + "type": "Element", + "namespace": "", + } + ) diff --git a/src/bcf/src/bcf/v3/model/markup.py b/src/bcf/src/bcf/v3/model/markup.py new file mode 100644 index 0000000000..f212b9fc7e --- /dev/null +++ b/src/bcf/src/bcf/v3/model/markup.py @@ -0,0 +1,616 @@ +from dataclasses import dataclass, field +from typing import List, Optional + +from xsdata.models.datatype import XmlDateTime + + +@dataclass(slots=True, kw_only=True) +class BimSnippet: + reference: str = field( + metadata={ + "name": "Reference", + "type": "Element", + "namespace": "", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + reference_schema: str = field( + metadata={ + "name": "ReferenceSchema", + "type": "Element", + "namespace": "", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + snippet_type: str = field( + metadata={ + "name": "SnippetType", + "type": "Attribute", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + is_external: bool = field( + default=False, + metadata={ + "name": "IsExternal", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class CommentViewpoint: + class Meta: + global_type = False + + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class DocumentReference: + document_guid: Optional[str] = field( + default=None, + metadata={ + "name": "DocumentGuid", + "type": "Element", + "namespace": "", + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + url: Optional[str] = field( + default=None, + metadata={ + "name": "Url", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + description: Optional[str] = field( + default=None, + metadata={ + "name": "Description", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class File: + filename: Optional[str] = field( + default=None, + metadata={ + "name": "Filename", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "Date", + "type": "Element", + "namespace": "", + } + ) + reference: Optional[str] = field( + default=None, + metadata={ + "name": "Reference", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + ifc_project: Optional[str] = field( + default=None, + metadata={ + "name": "IfcProject", + "type": "Attribute", + "length": 22, + "pattern": r"[0-9A-Za-z_$]*", + } + ) + ifc_spatial_structure_element: Optional[str] = field( + default=None, + metadata={ + "name": "IfcSpatialStructureElement", + "type": "Attribute", + "length": 22, + "pattern": r"[0-9A-Za-z_$]*", + } + ) + is_external: bool = field( + default=True, + metadata={ + "name": "IsExternal", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicLabels: + class Meta: + global_type = False + + label: List[str] = field( + default_factory=list, + metadata={ + "name": "Label", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicReferenceLinks: + class Meta: + global_type = False + + reference_link: List[str] = field( + default_factory=list, + metadata={ + "name": "ReferenceLink", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicRelatedTopicsRelatedTopic: + class Meta: + global_type = False + + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ViewPoint: + viewpoint: Optional[str] = field( + default=None, + metadata={ + "name": "Viewpoint", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + snapshot: Optional[str] = field( + default=None, + metadata={ + "name": "Snapshot", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + index: Optional[int] = field( + default=None, + metadata={ + "name": "Index", + "type": "Element", + "namespace": "", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Comment: + date: XmlDateTime = field( + metadata={ + "name": "Date", + "type": "Element", + "namespace": "", + "required": True, + } + ) + author: str = field( + metadata={ + "name": "Author", + "type": "Element", + "namespace": "", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + comment: Optional[str] = field( + default=None, + metadata={ + "name": "Comment", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + viewpoint: Optional[CommentViewpoint] = field( + default=None, + metadata={ + "name": "Viewpoint", + "type": "Element", + "namespace": "", + } + ) + modified_date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "ModifiedDate", + "type": "Element", + "namespace": "", + } + ) + modified_author: Optional[str] = field( + default=None, + metadata={ + "name": "ModifiedAuthor", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + + +@dataclass(slots=True, kw_only=True) +class HeaderFiles: + class Meta: + global_type = False + + file: List[File] = field( + default_factory=list, + metadata={ + "name": "File", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicDocumentReferences: + class Meta: + global_type = False + + document_reference: List[DocumentReference] = field( + default_factory=list, + metadata={ + "name": "DocumentReference", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicRelatedTopics: + class Meta: + global_type = False + + related_topic: List[TopicRelatedTopicsRelatedTopic] = field( + default_factory=list, + metadata={ + "name": "RelatedTopic", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicViewpoints: + class Meta: + global_type = False + + view_point: List[ViewPoint] = field( + default_factory=list, + metadata={ + "name": "ViewPoint", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Header: + files: Optional[HeaderFiles] = field( + default=None, + metadata={ + "name": "Files", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class TopicComments: + class Meta: + global_type = False + + comment: List[Comment] = field( + default_factory=list, + metadata={ + "name": "Comment", + "type": "Element", + "namespace": "", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Topic: + reference_links: Optional[TopicReferenceLinks] = field( + default=None, + metadata={ + "name": "ReferenceLinks", + "type": "Element", + "namespace": "", + } + ) + title: str = field( + metadata={ + "name": "Title", + "type": "Element", + "namespace": "", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + priority: Optional[str] = field( + default=None, + metadata={ + "name": "Priority", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + index: Optional[int] = field( + default=None, + metadata={ + "name": "Index", + "type": "Element", + "namespace": "", + } + ) + labels: Optional[TopicLabels] = field( + default=None, + metadata={ + "name": "Labels", + "type": "Element", + "namespace": "", + } + ) + creation_date: XmlDateTime = field( + metadata={ + "name": "CreationDate", + "type": "Element", + "namespace": "", + "required": True, + } + ) + creation_author: str = field( + metadata={ + "name": "CreationAuthor", + "type": "Element", + "namespace": "", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + modified_date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "ModifiedDate", + "type": "Element", + "namespace": "", + } + ) + modified_author: Optional[str] = field( + default=None, + metadata={ + "name": "ModifiedAuthor", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + due_date: Optional[XmlDateTime] = field( + default=None, + metadata={ + "name": "DueDate", + "type": "Element", + "namespace": "", + } + ) + assigned_to: Optional[str] = field( + default=None, + metadata={ + "name": "AssignedTo", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + stage: Optional[str] = field( + default=None, + metadata={ + "name": "Stage", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + description: Optional[str] = field( + default=None, + metadata={ + "name": "Description", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + bim_snippet: Optional[BimSnippet] = field( + default=None, + metadata={ + "name": "BimSnippet", + "type": "Element", + "namespace": "", + } + ) + document_references: Optional[TopicDocumentReferences] = field( + default=None, + metadata={ + "name": "DocumentReferences", + "type": "Element", + "namespace": "", + } + ) + related_topics: Optional[TopicRelatedTopics] = field( + default=None, + metadata={ + "name": "RelatedTopics", + "type": "Element", + "namespace": "", + } + ) + comments: Optional[TopicComments] = field( + default=None, + metadata={ + "name": "Comments", + "type": "Element", + "namespace": "", + } + ) + viewpoints: Optional[TopicViewpoints] = field( + default=None, + metadata={ + "name": "Viewpoints", + "type": "Element", + "namespace": "", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) + server_assigned_id: Optional[str] = field( + default=None, + metadata={ + "name": "ServerAssignedId", + "type": "Attribute", + "min_length": 1, + "white_space": "collapse", + } + ) + topic_type: str = field( + metadata={ + "name": "TopicType", + "type": "Attribute", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + topic_status: str = field( + metadata={ + "name": "TopicStatus", + "type": "Attribute", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Markup: + header: Optional[Header] = field( + default=None, + metadata={ + "name": "Header", + "type": "Element", + "namespace": "", + } + ) + topic: Topic = field( + metadata={ + "name": "Topic", + "type": "Element", + "namespace": "", + "required": True, + } + ) diff --git a/src/bcf/src/bcf/v3/model/project.py b/src/bcf/src/bcf/v3/model/project.py new file mode 100644 index 0000000000..b6962213d6 --- /dev/null +++ b/src/bcf/src/bcf/v3/model/project.py @@ -0,0 +1,37 @@ +from dataclasses import dataclass, field +from typing import Optional + + +@dataclass(slots=True, kw_only=True) +class Project: + name: Optional[str] = field( + default=None, + metadata={ + "name": "Name", + "type": "Element", + "namespace": "", + "min_length": 1, + "white_space": "collapse", + } + ) + project_id: str = field( + metadata={ + "name": "ProjectId", + "type": "Attribute", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ProjectInfo: + project: Project = field( + metadata={ + "name": "Project", + "type": "Element", + "namespace": "", + "required": True, + } + ) diff --git a/src/bcf/src/bcf/v3/model/version.py b/src/bcf/src/bcf/v3/model/version.py new file mode 100644 index 0000000000..f3a44d2ab3 --- /dev/null +++ b/src/bcf/src/bcf/v3/model/version.py @@ -0,0 +1,12 @@ +from dataclasses import dataclass, field + + +@dataclass(slots=True, kw_only=True) +class Version: + version_id: str = field( + metadata={ + "name": "VersionId", + "type": "Attribute", + "required": True, + } + ) diff --git a/src/bcf/src/bcf/v3/model/visinfo.py b/src/bcf/src/bcf/v3/model/visinfo.py new file mode 100644 index 0000000000..fa541945ea --- /dev/null +++ b/src/bcf/src/bcf/v3/model/visinfo.py @@ -0,0 +1,524 @@ +from dataclasses import dataclass, field +from enum import Enum +from typing import List, Optional + + +class BitmapFormat(Enum): + PNG = "png" + JPG = "jpg" + + +@dataclass(slots=True, kw_only=True) +class Component: + originating_system: Optional[str] = field( + default=None, + metadata={ + "name": "OriginatingSystem", + "type": "Element", + "min_length": 1, + "white_space": "collapse", + } + ) + authoring_tool_id: Optional[str] = field( + default=None, + metadata={ + "name": "AuthoringToolId", + "type": "Element", + "min_length": 1, + "white_space": "collapse", + } + ) + ifc_guid: Optional[str] = field( + default=None, + metadata={ + "name": "IfcGuid", + "type": "Attribute", + "length": 22, + "pattern": r"[0-9A-Za-z_$]*", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Direction: + x: float = field( + metadata={ + "name": "X", + "type": "Element", + "required": True, + } + ) + y: float = field( + metadata={ + "name": "Y", + "type": "Element", + "required": True, + } + ) + z: float = field( + metadata={ + "name": "Z", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class Point: + x: float = field( + metadata={ + "name": "X", + "type": "Element", + "required": True, + } + ) + y: float = field( + metadata={ + "name": "Y", + "type": "Element", + "required": True, + } + ) + z: float = field( + metadata={ + "name": "Z", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ViewSetupHints: + spaces_visible: bool = field( + default=False, + metadata={ + "name": "SpacesVisible", + "type": "Attribute", + } + ) + space_boundaries_visible: bool = field( + default=False, + metadata={ + "name": "SpaceBoundariesVisible", + "type": "Attribute", + } + ) + openings_visible: bool = field( + default=False, + metadata={ + "name": "OpeningsVisible", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Bitmap: + format: BitmapFormat = field( + metadata={ + "name": "Format", + "type": "Element", + "required": True, + } + ) + reference: str = field( + metadata={ + "name": "Reference", + "type": "Element", + "required": True, + "min_length": 1, + "white_space": "collapse", + } + ) + location: Point = field( + metadata={ + "name": "Location", + "type": "Element", + "required": True, + } + ) + normal: Direction = field( + metadata={ + "name": "Normal", + "type": "Element", + "required": True, + } + ) + up: Direction = field( + metadata={ + "name": "Up", + "type": "Element", + "required": True, + } + ) + height: float = field( + metadata={ + "name": "Height", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ClippingPlane: + location: Point = field( + metadata={ + "name": "Location", + "type": "Element", + "required": True, + } + ) + direction: Direction = field( + metadata={ + "name": "Direction", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentColoringColorComponents: + class Meta: + global_type = False + + component: List[Component] = field( + default_factory=list, + metadata={ + "name": "Component", + "type": "Element", + "min_occurs": 1, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentSelection: + component: List[Component] = field( + default_factory=list, + metadata={ + "name": "Component", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentVisibilityExceptions: + class Meta: + global_type = False + + component: List[Component] = field( + default_factory=list, + metadata={ + "name": "Component", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Line: + start_point: Point = field( + metadata={ + "name": "StartPoint", + "type": "Element", + "required": True, + } + ) + end_point: Point = field( + metadata={ + "name": "EndPoint", + "type": "Element", + "required": True, + } + ) + + +@dataclass(slots=True, kw_only=True) +class OrthogonalCamera: + """ + Attributes + camera_view_point: + camera_direction: + camera_up_vector: + view_to_world_scale: view's visible vertical size in meters + aspect_ratio: Proportional relationship between the width and + the height of the view (w/h). + """ + camera_view_point: Point = field( + metadata={ + "name": "CameraViewPoint", + "type": "Element", + "required": True, + } + ) + camera_direction: Direction = field( + metadata={ + "name": "CameraDirection", + "type": "Element", + "required": True, + } + ) + camera_up_vector: Direction = field( + metadata={ + "name": "CameraUpVector", + "type": "Element", + "required": True, + } + ) + view_to_world_scale: float = field( + metadata={ + "name": "ViewToWorldScale", + "type": "Element", + "required": True, + } + ) + aspect_ratio: float = field( + metadata={ + "name": "AspectRatio", + "type": "Element", + "required": True, + "min_exclusive": 0.0, + } + ) + + +@dataclass(slots=True, kw_only=True) +class PerspectiveCamera: + """ + Attributes + camera_view_point: + camera_direction: + camera_up_vector: + field_of_view: Vertical field of view, in degrees. It is + currently limited to a value between 45 and 60 degrees. This + limitation will be dropped in the next release and viewers + should be expect values outside this range in current + implementations. + aspect_ratio: Proportional relationship between the width and + the height of the view (w/h). + """ + camera_view_point: Point = field( + metadata={ + "name": "CameraViewPoint", + "type": "Element", + "required": True, + } + ) + camera_direction: Direction = field( + metadata={ + "name": "CameraDirection", + "type": "Element", + "required": True, + } + ) + camera_up_vector: Direction = field( + metadata={ + "name": "CameraUpVector", + "type": "Element", + "required": True, + } + ) + field_of_view: float = field( + metadata={ + "name": "FieldOfView", + "type": "Element", + "required": True, + "min_exclusive": 0.0, + "max_exclusive": 180.0, + } + ) + aspect_ratio: float = field( + metadata={ + "name": "AspectRatio", + "type": "Element", + "required": True, + "min_exclusive": 0.0, + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentColoringColor: + class Meta: + global_type = False + + components: ComponentColoringColorComponents = field( + metadata={ + "name": "Components", + "type": "Element", + "required": True, + } + ) + color: str = field( + metadata={ + "name": "Color", + "type": "Attribute", + "required": True, + "pattern": r"[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentVisibility: + view_setup_hints: Optional[ViewSetupHints] = field( + default=None, + metadata={ + "name": "ViewSetupHints", + "type": "Element", + } + ) + exceptions: Optional[ComponentVisibilityExceptions] = field( + default=None, + metadata={ + "name": "Exceptions", + "type": "Element", + } + ) + default_visibility: bool = field( + default=False, + metadata={ + "name": "DefaultVisibility", + "type": "Attribute", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfoBitmaps: + class Meta: + global_type = False + + bitmap: List[Bitmap] = field( + default_factory=list, + metadata={ + "name": "Bitmap", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfoClippingPlanes: + class Meta: + global_type = False + + clipping_plane: List[ClippingPlane] = field( + default_factory=list, + metadata={ + "name": "ClippingPlane", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfoLines: + class Meta: + global_type = False + + line: List[Line] = field( + default_factory=list, + metadata={ + "name": "Line", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class ComponentColoring: + color: List[ComponentColoringColor] = field( + default_factory=list, + metadata={ + "name": "Color", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class Components: + selection: Optional[ComponentSelection] = field( + default=None, + metadata={ + "name": "Selection", + "type": "Element", + } + ) + visibility: Optional[ComponentVisibility] = field( + default=None, + metadata={ + "name": "Visibility", + "type": "Element", + } + ) + coloring: Optional[ComponentColoring] = field( + default=None, + metadata={ + "name": "Coloring", + "type": "Element", + } + ) + + +@dataclass(slots=True, kw_only=True) +class VisualizationInfo: + """ + VisualizationInfo documentation. + """ + components: Optional[Components] = field( + default=None, + metadata={ + "name": "Components", + "type": "Element", + } + ) + orthogonal_camera: Optional[OrthogonalCamera] = field( + default=None, + metadata={ + "name": "OrthogonalCamera", + "type": "Element", + } + ) + perspective_camera: Optional[PerspectiveCamera] = field( + default=None, + metadata={ + "name": "PerspectiveCamera", + "type": "Element", + } + ) + lines: Optional[VisualizationInfoLines] = field( + default=None, + metadata={ + "name": "Lines", + "type": "Element", + } + ) + clipping_planes: Optional[VisualizationInfoClippingPlanes] = field( + default=None, + metadata={ + "name": "ClippingPlanes", + "type": "Element", + } + ) + bitmaps: Optional[VisualizationInfoBitmaps] = field( + default=None, + metadata={ + "name": "Bitmaps", + "type": "Element", + } + ) + guid: str = field( + metadata={ + "name": "Guid", + "type": "Attribute", + "required": True, + "pattern": r"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}", + } + ) diff --git a/src/bcf/src/bcf/v3/topic.py b/src/bcf/src/bcf/v3/topic.py new file mode 100644 index 0000000000..c3a90f7a1b --- /dev/null +++ b/src/bcf/src/bcf/v3/topic.py @@ -0,0 +1,188 @@ +"""BCF XML V3 Topic handler.""" +import datetime +import uuid +import zipfile +from pathlib import Path +from typing import Any, Optional + +from ifcopenshell import entity_instance +from xsdata.models.datatype import XmlDateTime + +import bcf.v3.model as mdl +from bcf.inmemory_zipfile import ZipFileInterface +from bcf.v3.visinfo import VisualizationInfoHandler +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer + + +class TopicHandler: + """BCF Topic and related objects handler.""" + + def __init__( + self, + topic_dir: Optional[zipfile.Path] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> None: + self._markup: Optional[mdl.Markup] = None + self._viewpoints: dict[str, VisualizationInfoHandler] = {} + self._bim_snippet: Optional[bytes] = None + self._xml_handler = xml_handler or XmlParserSerializer() + self._topic_dir = topic_dir + + @property + def markup(self) -> Optional[mdl.Markup]: + if not self._markup and self._topic_dir: + markup_path = self._topic_dir.joinpath("markup.bcf") + if markup_path.exists(): + self._markup = self._xml_handler.parse(markup_path.read_bytes(), mdl.Markup) + return self._markup + + @markup.setter + def markup(self, value: mdl.Markup) -> None: + self._markup = value + + @property + def topic(self) -> mdl.Topic: + """Return the Topic object.""" + return self.markup.topic + + @property + def guid(self) -> Optional[str]: + """Return the GUID of the topic.""" + if self._markup: + return self.topic.guid + return self._topic_dir.name if self._topic_dir else None + + @property + def header(self) -> Optional[mdl.Header]: + """Return the header of the topic.""" + return self.markup.header + + @property + def comments(self) -> list[mdl.Comment]: + """Return the comments of the topic.""" + return self.topic.comments.comment if self.topic.comments else [] + + @property + def bim_snippet(self) -> Optional[bytes]: + if not self._bim_snippet and self._topic_dir: + self._bim_snippet = self._load_bim_snippet() + return self._bim_snippet + + @bim_snippet.setter + def bim_snippet(self, value: bytes) -> None: + self._bim_snippet = value + + @property + def viewpoints(self) -> Optional[VisualizationInfoHandler]: + if ( + not self._viewpoints + and self._topic_dir + and self.topic.viewpoints + and (viewpoints := self.topic.viewpoints.view_point) + ): + self._viewpoints = VisualizationInfoHandler.from_topic_viewpoints(self._topic_dir, viewpoints) + return self._viewpoints + + def _load_bim_snippet(self) -> Optional[bytes]: + bim_snippet_obj = self.topic.bim_snippet + if bim_snippet_obj and not bim_snippet_obj.is_external and self._topic_dir: + bim_snippet_path = self._topic_dir.joinpath(bim_snippet_obj.reference) + if bim_snippet_path.exists(): + return bim_snippet_path.read_bytes() + return None + + @classmethod + def create_new( + cls, + title: str, + description: str, + author: str, + topic_type: str = "", + topic_status: str = "", + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> "TopicHandler": + """ + Create a new BCF topic. + + Args: + title: The title of the topic. + description: The description of the topic. + author: The author of the topic. + topic_type: The type of the topic. + topic_status: The status of the topic. + xml_handler: The XML parser/serializer to use. + + Returns: + The BCF topic definition. + """ + creation_date = XmlDateTime.from_datetime(datetime.datetime.now()) + guid = str(uuid.uuid4()) + topic = mdl.Topic( + title=title, + description=description, + creation_author=author, + creation_date=creation_date, + guid=guid, + topic_type=topic_type, + topic_status=topic_status, + ) + markup = mdl.Markup(topic=topic) + obj = cls(topic_dir=Path(guid), xml_handler=xml_handler or XmlParserSerializer()) + obj.markup = markup + return obj + + def save(self, destination_zip: ZipFileInterface) -> None: + """ + Save the topic to a BCF zip file. + + Args: + bcf_zip: The BCF zip file to save to. + """ + topic_dir = self.guid + self._save_xml(destination_zip, self._markup, "markup.bcf") + self._save_viewpoints(destination_zip, topic_dir) + self._save_bim_snippet(destination_zip) + + def _save_viewpoints(self, destination_zip, topic_dir) -> None: + if not self.topic.viewpoints or not (viewpoints := self.topic.viewpoints.view_point): + return + for vpt in viewpoints: + if vpt.viewpoint: + self.viewpoints[vpt.viewpoint].save(destination_zip, topic_dir, vpt) + + def _save_xml(self, destination_zip: ZipFileInterface, item: Any, target: str) -> None: + to_write = self._xml_handler.serialize(item) if item else self._topic_dir.joinpath(target).read_bytes() + destination_zip.writestr(f"{self._topic_dir.name}/{target}", to_write) + + def _save_bim_snippet(self, destination_zip: ZipFileInterface) -> None: + snippet = self.topic.bim_snippet + if not snippet or snippet.is_external: + return + ref_filename = Path(snippet.reference).name + if self.bim_snippet: + destination_zip.writestr(f"{self.topic.guid}/{ref_filename}", self.bim_snippet) + + def add_viewpoint(self, element: entity_instance) -> None: + """ + Add a viewpoint tergeting an IFC element to the topic. + + Args: + element: The IFC element. + """ + new_viewpoint = VisualizationInfoHandler.create_new(element, self._xml_handler) + self.add_visinfo_handler(new_viewpoint) + + def add_visinfo_handler(self, new_viewpoint: VisualizationInfoHandler) -> None: + self.viewpoints[new_viewpoint.guid] = new_viewpoint + if self.topic.viewpoints is None: + self.topic.viewpoints = mdl.TopicViewpoints() + self.topic.viewpoints.view_point.append(mdl.ViewPoint(viewpoint=new_viewpoint.guid, guid=new_viewpoint.guid)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, TopicHandler): + raise TypeError("Equality needs a BcfXml object.") + return ( + self.markup == other.markup + and self.viewpoints == other.viewpoints + and self.bim_snippet == other.bim_snippet + ) diff --git a/src/bcf/src/bcf/v3/visinfo.py b/src/bcf/src/bcf/v3/visinfo.py new file mode 100644 index 0000000000..6c1f79de27 --- /dev/null +++ b/src/bcf/src/bcf/v3/visinfo.py @@ -0,0 +1,247 @@ +import uuid +import zipfile +from functools import lru_cache +from typing import Any, Iterable, Optional + +import numpy as np +from ifcopenshell import entity_instance +from ifcopenshell.util import placement +from numpy.typing import NDArray + +import bcf.v3.model as mdl +from bcf.geometry import calc_camera_vectors +from bcf.inmemory_zipfile import ZipFileInterface +from bcf.xml_parser import AbstractXmlParserSerializer, XmlParserSerializer + + +class VisualizationInfoHandler: + """Handle the VisualizationInfo and related objects.""" + + def __init__( + self, + visualization_info: mdl.VisualizationInfo, + snapshot: Optional[bytes] = None, + bitmaps: Optional[dict[str, bytes]] = None, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> None: + self.visualization_info = visualization_info + self.snapshot = snapshot + self.bitmaps = bitmaps or {} + self._xml_handler = xml_handler or XmlParserSerializer() + + @property + def guid(self) -> str: + """Return the GUID of the visualization info.""" + return self.visualization_info.guid + + @classmethod + def from_topic_viewpoints( + cls, + topic_dir: zipfile.Path, + vps: Iterable[mdl.ViewPoint], + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> dict[str, "VisualizationInfoHandler"]: + """Create VisualizationInfoHandler objects of a Topic's ViewPoints.""" + viewpoints = {} + for vpt in vps: + visinfo = cls.load(topic_dir, vpt, xml_handler) + if visinfo and vpt.viewpoint: + viewpoints[vpt.viewpoint] = visinfo + return viewpoints + + @classmethod + def load( + cls, + topic_dir: zipfile.Path, + vpt: mdl.ViewPoint, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> Optional["VisualizationInfoHandler"]: + """ + Load the VisualizationInfo and related objects from a BCF zip file. + + Args: + topic_dir: The directory in the BCF zip file to load from. + vpt: The ViewPoint to load. + xml_handler: The XML handler to use to parse the VisualizationInfo. + + Returns: + The VisualizationInfoHandler object. + """ + visinfo = cls._load_visinfo(topic_dir, vpt.viewpoint, xml_handler) + if not visinfo: + return None + snapshot = cls._load_snapshot(topic_dir, vpt.snapshot) + bitmaps = cls._load_bitmaps(topic_dir, visinfo) + return cls(visinfo, snapshot, bitmaps, xml_handler) + + @staticmethod + def _load_visinfo( + topic_dir: zipfile.Path, + vp_name: Optional[str], + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> Optional[mdl.VisualizationInfo]: + if not vp_name: + return None + vp_path = topic_dir.joinpath(vp_name) + if vp_path.exists(): + xml_handler = xml_handler or XmlParserSerializer() + return xml_handler.parse(vp_path.read_bytes(), mdl.VisualizationInfo) + return None + + @staticmethod + def _load_snapshot(topic_dir: zipfile.Path, vp_snapshot: Optional[str]) -> Optional[bytes]: + if vp_snapshot: + snapshot_path = topic_dir.joinpath(vp_snapshot) + if snapshot_path.exists(): + return snapshot_path.read_bytes() + return None + + @staticmethod + def _load_bitmaps(topic_dir: zipfile.Path, visinfo: Optional[mdl.VisualizationInfo]) -> dict[str, bytes]: + if not visinfo or not (bitmaps := visinfo.bitmaps): + return {} + bitmaps_dict = {} + for bitmap in bitmaps.bitmap: + if not bitmap.reference: + continue + bitmap_path = topic_dir.joinpath(bitmap.reference) + if bitmap_path.exists(): + bitmaps_dict[bitmap.reference] = bitmap_path.read_bytes() + return bitmaps_dict + + def save( + self, + bcf_zip: ZipFileInterface, + topic_dir: str, + vpt: mdl.ViewPoint, + ) -> None: + """ + Save the VisualizationInfo and related objects to a BCF zip file. + + Args: + bcf_zip: The BCF zip file to save to. + topic_dir: The directory in the BCF zip file to save to. + vpt: The ViewPoint to save. + """ + if not (vp_name := vpt.viewpoint): + return + self._save_visinfo(bcf_zip, topic_dir, vp_name) + self._save_snapshot(bcf_zip, topic_dir, vpt.snapshot) + self._save_bitmaps(bcf_zip, topic_dir) + + def _save_snapshot(self, bcf_zip: ZipFileInterface, topic_dir: str, filename: Optional[str]) -> None: + if self.snapshot and filename: + bcf_zip.writestr(f"{topic_dir}/{filename}", self.snapshot) + + def _save_visinfo(self, bcf_zip: ZipFileInterface, topic_dir: str, vp_name: str) -> None: + bcf_zip.writestr( + f"{topic_dir}/{vp_name}", + self._xml_handler.serialize(self.visualization_info), + ) + + def _save_bitmaps(self, bcf_zip: ZipFileInterface, topic_dir: str) -> None: + if not self.bitmaps: + return + if not (bitmaps_defs := self.visualization_info.bitmaps): + return + for bitmap_def in bitmaps_defs.bitmap: + if not (bitmap_name := bitmap_def.reference): + continue + if bitmap_name in self.bitmaps: + bcf_zip.writestr(f"{topic_dir}/{bitmap_name}", self.bitmaps[bitmap_name]) + + @classmethod + def create_new( + cls, + element: entity_instance, + xml_handler: Optional[AbstractXmlParserSerializer] = None, + ) -> "VisualizationInfoHandler": + """ + Create a new VisualizationInfoHandler object from an IFC element. + + Args: + element: The IFC element to point at. + xml_handler: The XML handler to use. + + Returns: + The VisualizationInfoHandler object. + """ + xml_handler = xml_handler or XmlParserSerializer() + return cls(visualization_info=build_viewpoint(element), xml_handler=xml_handler) + + +@lru_cache(maxsize=None) +def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo: + """ + Return a BCF viewpoint of an IFC element. + + This function is cached to speedudp the creation of multiple BCF topics regarding the same element. + + Args: + element: The IFC element to point at. + + Returns: + The BCF viewpoint definition. + """ + elem_placement = placement.get_local_placement(element.ObjectPlacement) + + return mdl.VisualizationInfo( + guid=str(uuid.uuid4()), + components=build_components(element.GlobalId), + perspective_camera=build_camera(elem_placement), + ) + + +def build_components(guid: str) -> mdl.Components: + """ + Return the BCF components from an IFC element GUID. + + Args: + guid: The IFC element GUID. + + Returns: + The BCF components definition. + """ + return mdl.Components( + selection=mdl.ComponentSelection(component=[mdl.Component(ifc_guid=guid)]), + visibility=mdl.ComponentVisibility(default_visibility=True), + ) + + +def build_camera(elem_placement: NDArray[np.float_]) -> mdl.PerspectiveCamera: + """ + Return a BCF camera for an IFC element placement matrix. + + Args: + elem_placement: The IFC element placement as a rototranslation matrix. + + Returns: + The BCF camera definition. + """ + return build_camera_from_vectors(*calc_camera_vectors(elem_placement)) + + +def build_camera_from_vectors( + camera_position: NDArray[np.float_], camera_dir: NDArray[np.float_], camera_up: NDArray[np.float_] +) -> mdl.PerspectiveCamera: + """ + Return a BCF camera for an IFC element placement matrix. + + Args: + camera_position: camera position array + camera_dir: camera direction versor + camera_up_vector: camera up versor + + Returns: + The BCF camera definition. + """ + camera_viewpoint = mdl.Point(x=camera_position[0], y=camera_position[1], z=camera_position[2]) + camera_direction = mdl.Direction(x=camera_dir[0], y=camera_dir[1], z=camera_dir[2]) + camera_up_vector = mdl.Direction(x=camera_up[0], y=camera_up[1], z=camera_up[2]) + return mdl.PerspectiveCamera( + camera_view_point=camera_viewpoint, + camera_direction=camera_direction, + camera_up_vector=camera_up_vector, + aspect_ratio=1.0, + field_of_view=60.0, + ) diff --git a/src/bcf/src/bcf/xml_parser.py b/src/bcf/src/bcf/xml_parser.py new file mode 100644 index 0000000000..9f3878f769 --- /dev/null +++ b/src/bcf/src/bcf/xml_parser.py @@ -0,0 +1,83 @@ +"""XML Parser and Serializer factories.""" +from typing import Optional, Protocol, Type, TypeVar + +from xsdata.formats.dataclass.context import XmlContext +from xsdata.formats.dataclass.parsers import XmlParser +from xsdata.formats.dataclass.serializers import XmlSerializer +from xsdata.formats.dataclass.serializers.config import SerializerConfig + + +def build_xml_parser(context: Optional[XmlContext] = None) -> XmlParser: + """Return a parser for an XML file.""" + parser = XmlParser(context=context or XmlContext()) + parser.register_namespace("xs", "http://www.w3.org/2001/XMLSchema") + return parser + + +def build_serializer(context: Optional[XmlContext] = None) -> XmlSerializer: + """Return a serializer for an XML file.""" + return XmlSerializer( + config=SerializerConfig(pretty_print=True), + context=context or XmlContext(), + ) + + +T = TypeVar("T") + + +class AbstractXmlParserSerializer(Protocol): + """XML Parser and serializer wrapper.""" + + def parse(self, xml: bytes, clazz: Type[T]) -> T: + """ + Parse an XML file to an object. + + Args: + xml: The XML file as bytes. + clazz: The class to parse to. + """ + + def serialize(self, obj: T, ns_map: Optional[dict[str, str]] = None) -> str: + """ + Serialize an object to XML. + + Args: + obj: The object to serialize. + ns_map: The namespace map to use. + + Returns: + The XML as string. + """ + + +class XmlParserSerializer: + """XML Parser and serializer wrapper.""" + + def __init__(self) -> None: + self.context = XmlContext() + self.parser = build_xml_parser(self.context) + self.serializer = build_serializer(self.context) + + def parse(self, xml: bytes, clazz: Type[T]) -> T: + """ + Parse an XML file to an object. + + Args: + xml: The XML file as bytes. + clazz: The class to parse to. + """ + return self.parser.from_bytes(xml, clazz) + + def serialize(self, obj: T, ns_map: Optional[dict[str, str]] = None) -> str: + """ + Serialize an object to XML. + + Args: + obj: The object to serialize. + ns_map: The namespace map to use. + + Returns: + The XML as string. + """ + ns_map = ns_map or {"xs": "http://www.w3.org/2001/XMLSchema"} + return self.serializer.render(obj, ns_map) diff --git a/src/bcf/tests/__init__.py b/src/bcf/tests/__init__.py new file mode 100644 index 0000000000..64bbc124fe --- /dev/null +++ b/src/bcf/tests/__init__.py @@ -0,0 +1 @@ +"""BCF tests.""" diff --git a/src/bcf/tests/conftest.py b/src/bcf/tests/conftest.py new file mode 100644 index 0000000000..ea1b2aee8b --- /dev/null +++ b/src/bcf/tests/conftest.py @@ -0,0 +1,8 @@ +import pytest + +from bcf.xml_parser import XmlParserSerializer + + +@pytest.fixture(scope="session") +def xml_handler() -> XmlParserSerializer: + return XmlParserSerializer() diff --git a/src/bcf/tests/v2/MaximumInformation.bcf b/src/bcf/tests/v2/MaximumInformation.bcf new file mode 100644 index 0000000000000000000000000000000000000000..a05d9efb1980c552a58268347247eeabf7485fc0 GIT binary patch literal 368484 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

IgL@!Fv@>iGw7B7 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

  • 8CO5;k!d0+Wd&oI+OQ2_A};9V1SV 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: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 n)c*;^-}~EtqX tuple[BcfXml, TopicHandler]: + bcf = BcfXml.create_new("Test project", xml_handler=xml_handler) + orig_th = bcf.add_topic("Test topic", "Test message", "Test author", "Test type") + return bcf, orig_th + + +def test_bcf_roundtrip(xml_handler, build_sample) -> None: + """Saving and loading a bcf xml project returns the same objects.""" + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + with BcfXml.load(file_path, xml_handler=xml_handler) as parsed: + assert parsed == bcf + parsed_th = parsed.topics[orig_th.guid] + assert parsed_th == orig_th + + +def test_bcf_edit_saveas(xml_handler, build_sample) -> None: + """Saving and loading a bcf xml project returns the same objects.""" + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + with BcfXml.load(file_path, xml_handler=xml_handler) as parsed: + for th in parsed.topics.values(): + th.topic.title = "New Topic Title" + modified_path = Path(tmp_dir) / "edited.bcf" + parsed.save(modified_path) + with BcfXml.load(modified_path, xml_handler=xml_handler) as modified_parsed: + assert modified_parsed == bcf + parsed_th = modified_parsed.topics[orig_th.guid] + assert parsed_th.markup != orig_th.markup + assert parsed_th.markup == parsed.topics[orig_th.guid].markup + assert parsed_th.viewpoints == orig_th.viewpoints + assert parsed_th.bim_snippet == orig_th.bim_snippet + + +def test_bcf_edit(xml_handler, build_sample) -> None: + """Saving and loading a bcf xml project returns the same objects.""" + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + with BcfXml.load(file_path, xml_handler=xml_handler) as parsed: + for th in parsed.topics.values(): + th.topic.title = "New Topic Title" + parsed.save() + with BcfXml.load(file_path, xml_handler=xml_handler) as modified_parsed: + assert modified_parsed == bcf + assert len(modified_parsed.topics) == 1 + parsed_th = modified_parsed.topics[orig_th.guid] + assert parsed_th.markup != orig_th.markup + assert parsed_th.markup == parsed.topics[orig_th.guid].markup + assert parsed_th.viewpoints == orig_th.viewpoints + assert parsed_th.bim_snippet == orig_th.bim_snippet + + +def test_save_no_filename(build_sample) -> None: + bcf, _ = build_sample + with pytest.raises(ValueError): + bcf.save() + + +def test_load_no_filename() -> None: + with pytest.raises(ValueError): + BcfXml.load("") + + +def test_save_keep_open(build_sample) -> None: + bcf, _ = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path, keep_open=True) + assert bcf._zip_file is not None + bcf._zip_file.close() + + +def test_massive_bcf(xml_handler) -> None: + bcf = BcfXml.create_new("Test project", xml_handler=xml_handler) + for i in range(100): + th = bcf.add_topic(f"Topic {i:04}", f"Message {i:04}", "Test author", "Test type") + vi = mdl.VisualizationInfo( + guid=str(uuid.uuid4()), + components=build_components(str(uuid.uuid4())), + perspective_camera=build_camera_from_vectors([i, 0, 0], [0, 1, 0], [0, 0, 1]), + ) + vh = VisualizationInfoHandler(visualization_info=vi, xml_handler=xml_handler) + th.add_visinfo_handler(vh) + assert len(bcf.topics) == 100 + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + + +def test_equality_with_wrong_object() -> None: + with pytest.raises(TypeError): + build_sample[0] == "Wrong object" + + +def test_topic_equality_with_wrong_object() -> None: + with pytest.raises(TypeError): + build_sample[1] == "Wrong object" diff --git a/src/bcf/tests/v2/test_example_files.py b/src/bcf/tests/v2/test_example_files.py new file mode 100644 index 0000000000..09aa9e4115 --- /dev/null +++ b/src/bcf/tests/v2/test_example_files.py @@ -0,0 +1,365 @@ +import json +import os +import zipfile +from pathlib import Path + +from xsdata.models.datatype import XmlDateTime + +import bcf.v2.model as mdl +from bcf.v2.bcfxml import BcfXml +from bcf.v2.topic import TopicHandler + + +def test_maximum_information() -> None: + """ + All the info in a BCF is parsed correctly. + + Uses sample file from https://github.com/buildingSMART/BCF-XML/ + """ + bcf_path = Path(__file__).parent / "MaximumInformation.bcf" + with BcfXml.load(bcf_path) as bcf: + assert_everything_in_place(bcf) + + +def test_save_maximum_information() -> None: + base_dir = Path(__file__).parent + bcf_path = base_dir / "MaximumInformation.bcf" + target_path = base_dir / "MaximumInformationSaved.bcf" + with BcfXml.load(bcf_path) as bcf: + bcf.save(target_path) + assert target_path.exists() + with BcfXml.load(target_path) as bcf2: + assert_everything_in_place(bcf2) + + expected_files = [ + "bcf.version", + "project.bcfp", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/markup.bcf", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/bitmap.png", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/tux.png", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/JsonElement.json", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/Viewpoint_4ab7514b-b216-4d56-98d2-45cf8500ff5a.bcfv", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/Viewpoint_9a4a1878-ecbd-4916-83a8-dad82e560231.bcfv", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/Viewpoint_fc4019d7-365e-47f3-b6d0-b39fc48f15fc.bcfv", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/Snapshot_4ab7514b-b216-4d56-98d2-45cf8500ff5a.png", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/Snapshot_9a4a1878-ecbd-4916-83a8-dad82e560231.png", + "7ddc3ef0-0ab7-43f1-918a-45e38b42369c/Snapshot_fc4019d7-365e-47f3-b6d0-b39fc48f15fc.png", + "d1068c81-af04-4546-b63c-348810f6c716/markup.bcf", + "extensions.xsd", + "IfcPile_01.ifc", + "markup.xsd", + ] + assert_files_present(target_path, expected_files) + os.unlink(target_path) + + +def assert_everything_in_place(bcf: BcfXml): + assert bcf.version.version_id == "2.1" + assert bcf.project.name == "BCF API Implementation" + assert bcf.project_info.extension_schema == "extensions.xsd" + + assert len(bcf.topics) == 2 + assert_first_topic_handler(bcf.topics["7ddc3ef0-0ab7-43f1-918a-45e38b42369c"]) + second_th = bcf.topics["d1068c81-af04-4546-b63c-348810f6c716"] + assert second_th.topic == mdl.Topic( + title="Referenced topic", + creation_date=XmlDateTime(2017, 5, 22, 7, 51, 0, 42987900), + creation_author="dangl@iabi.eu", + description="This is just an empty topic that acts as a referenced topic.", + guid="d1068c81-af04-4546-b63c-348810f6c716", + ) + + +def assert_first_topic_handler(topic_handler: TopicHandler): + assert topic_handler.guid == "7ddc3ef0-0ab7-43f1-918a-45e38b42369c" + + expected_bs1 = mdl.BimSnippet( + reference="JsonElement.json", reference_schema="http://json-schema.org", snippet_type="JSON" + ) + expected_t1 = mdl.Topic( + reference_link=["https://bim--it.net"], + title="Maximum Content", + priority="High", + index=0, + labels=["Structural", "IT Development"], + creation_date=XmlDateTime(2015, 6, 21, 12, 0, 0), + creation_author="dangl@iabi.eu", + modified_date=XmlDateTime(2015, 6, 21, 14, 22, 47), + modified_author="dangl@iabi.eu", + due_date=XmlDateTime(2016, 10, 2, 14, 22, 47), + assigned_to="linhard@iabi.eu", + stage="Construction Start", + description="This is a topic with all informations present.", + bim_snippet=expected_bs1, + document_reference=[ + mdl.TopicDocumentReference( + referenced_document="https://github.com/BuildingSMART/BCF-XML", + description="GitHub BCF Specification", + is_external=True, + ), + mdl.TopicDocumentReference( + referenced_document="../markup.xsd", + description="Markup.xsd Schema", + is_external=False, + ), + ], + related_topic=[mdl.TopicRelatedTopic(guid="d1068c81-af04-4546-b63c-348810f6c716")], + guid="7ddc3ef0-0ab7-43f1-918a-45e38b42369c", + topic_type="Structural", + topic_status="Open", + ) + assert topic_handler.topic == expected_t1 + expected_h1 = mdl.Header( + file=[ + mdl.HeaderFile( + filename="IfcPile_01.ifc", + date=XmlDateTime(2014, 10, 27, 16, 27, 27), + reference="../IfcPile_01.ifc", + ifc_project="0M6o7Znnv7hxsbWgeu7oQq", + ifc_spatial_structure_element="23B$bNeGHFQuMYJzvUX0FD", + is_external=False, + ) + ] + ) + assert topic_handler.header == expected_h1 + + expected_th1_comments = [ + mdl.Comment( + date=XmlDateTime(2015, 8, 31, 12, 40, 17), + author="dangl@iabi.eu", + comment="This is an unmodified topic at the uppermost hierarchical level.\nAll times in the XML are marked as UTC times.", + guid="07ccdba0-1736-47e1-807d-67dc6f3addaa", + ), + mdl.Comment( + date=XmlDateTime(2015, 8, 31, 14, 0, 1), + author="dangl@iabi.eu", + comment="This comment was a reply to the first comment in BCF v2.0. This is a no longer supported functionality and therefore is to be treated as a regular comment in v2.1.", + guid="a12766c2-61bc-40b4-ab19-e9f45fd0b0bf", + ), + mdl.Comment( + date=XmlDateTime(2015, 8, 31, 13, 7, 11), + author="dangl@iabi.eu", + comment="This comment again is in the highest hierarchy level.\nIt references a viewpoint.", + viewpoint=mdl.CommentViewpoint(guid="4ab7514b-b216-4d56-98d2-45cf8500ff5a"), + guid="c2bb5bb0-773d-45dd-bdaa-19a216439ed3", + ), + mdl.Comment( + date=XmlDateTime(2015, 8, 31, 15, 42, 58), + author="dangl@iabi.eu", + comment="This comment contained some spllng errs.\nHopefully, the modifier did catch them all.", + modified_date=XmlDateTime(2015, 8, 31, 16, 7, 11), + modified_author="dangl@iabi.eu", + guid="0b843a5c-c3bf-41ef-be98-52a9f7bd9790", + ), + ] + assert topic_handler.comments == expected_th1_comments + + expected_th1_viewpoints = [ + mdl.ViewPoint( + viewpoint="Viewpoint_4ab7514b-b216-4d56-98d2-45cf8500ff5a.bcfv", + snapshot="Snapshot_4ab7514b-b216-4d56-98d2-45cf8500ff5a.png", + index=2, + guid="4ab7514b-b216-4d56-98d2-45cf8500ff5a", + ), + mdl.ViewPoint( + viewpoint="Viewpoint_fc4019d7-365e-47f3-b6d0-b39fc48f15fc.bcfv", + snapshot="Snapshot_fc4019d7-365e-47f3-b6d0-b39fc48f15fc.png", + index=0, + guid="fc4019d7-365e-47f3-b6d0-b39fc48f15fc", + ), + mdl.ViewPoint( + viewpoint="Viewpoint_9a4a1878-ecbd-4916-83a8-dad82e560231.bcfv", + snapshot="Snapshot_9a4a1878-ecbd-4916-83a8-dad82e560231.png", + index=1, + guid="9a4a1878-ecbd-4916-83a8-dad82e560231", + ), + ] + + expected_m1 = mdl.Markup( + header=expected_h1, + topic=expected_t1, + comment=expected_th1_comments, + viewpoints=expected_th1_viewpoints, + ) + assert topic_handler.markup == expected_m1 + + assert json.loads(topic_handler.bim_snippet) == {"Material": "Concrete", "Temperatures": ["Cold", "Hot", "Hotter"]} + + assert topic_handler.reference_files["../IfcPile_01.ifc"] is not None + + assert_viewpoints(topic_handler.viewpoints) + + +def assert_viewpoints(viewpoints): + assert len(viewpoints) == 3 + + expected_selection = mdl.ComponentSelection( + component=[ + mdl.Component(ifc_guid="0cSRUx$EX1NRjqiKcYQ$a0"), + mdl.Component(ifc_guid="1jQQiGIAnFzxOUzrdmJYDS"), + mdl.Component(ifc_guid="0fdpeZZEX3FwJ7x0ox5kzF"), + mdl.Component(ifc_guid="23Zwlpd71EyvHlH6OZ77nK"), + mdl.Component(ifc_guid="1OpjQ1Nlv4sQuTxfUC_8zS"), + ] + ) + + expected_exception = mdl.ComponentVisibilityExceptions( + component=[ + mdl.Component(ifc_guid="0Gl71cVurFn8bxAOox6M4X"), + mdl.Component(ifc_guid="23Zwlpd71EyvHlH6OZ77nK"), + mdl.Component(ifc_guid="3DvyPxGIn8qR0KDwbL_9r1"), + mdl.Component(ifc_guid="0fdpeZZEX3FwJ7x0ox5kzF"), + mdl.Component(ifc_guid="1OpjQ1Nlv4sQuTxfUC_8zS"), + ] + ) + + expected_coloring = mdl.ComponentColoring( + color=[ + mdl.ComponentColoringColor( + component=[ + mdl.Component(ifc_guid="0fdpeZZEX3FwJ7x0ox5kzF"), + mdl.Component(ifc_guid="23Zwlpd71EyvHlH6OZ77nK"), + mdl.Component(ifc_guid="1OpjQ1Nlv4sQuTxfUC_8zS"), + mdl.Component(ifc_guid="0cSRUx$EX1NRjqiKcYQ$a0"), + ], + color="3498DB", + ) + ] + ) + + assert_first_viewpoint( + viewpoints["Viewpoint_4ab7514b-b216-4d56-98d2-45cf8500ff5a.bcfv"], + expected_selection, + expected_exception, + expected_coloring, + ) + assert_second_viewpoint( + viewpoints["Viewpoint_fc4019d7-365e-47f3-b6d0-b39fc48f15fc.bcfv"], + expected_selection, + expected_exception, + expected_coloring, + ) + assert_third_viewpoint( + viewpoints["Viewpoint_9a4a1878-ecbd-4916-83a8-dad82e560231.bcfv"], + expected_selection, + expected_exception, + expected_coloring, + ) + + +def assert_first_viewpoint(viewpoint, expected_selection, expected_exception, expected_coloring) -> None: + expected_vp = mdl.VisualizationInfo( + components=mdl.Components( + view_setup_hints=mdl.ViewSetupHints( + spaces_visible=True, + space_boundaries_visible=True, + openings_visible=True, + ), + selection=expected_selection, + visibility=mdl.ComponentVisibility( + exceptions=expected_exception, + default_visibility=True, + ), + coloring=expected_coloring, + ), + perspective_camera=mdl.PerspectiveCamera( + camera_view_point=mdl.Point(x=0.43079984188079834, y=69.52057647705078, z=10.666350364685059), + camera_direction=mdl.Direction(x=0.09159398823976517, y=-0.9375035166740417, z=-0.3357048034667969), + camera_up_vector=mdl.Direction(x=0.01938679628074169, y=-0.3353792130947113, z=0.9418837428092957), + field_of_view=60, + ), + lines=mdl.VisualizationInfoLines( + line=[ + mdl.Line(start_point=mdl.Point(x=0, y=0, z=0), end_point=mdl.Point(x=0, y=0, z=1)), + mdl.Line(start_point=mdl.Point(x=0, y=0, z=1), end_point=mdl.Point(x=0, y=1, z=1)), + mdl.Line(start_point=mdl.Point(x=0, y=1, z=1), end_point=mdl.Point(x=1, y=1, z=1)), + ] + ), + clipping_planes=mdl.VisualizationInfoClippingPlanes( + clipping_plane=[ + mdl.ClippingPlane(location=mdl.Point(x=0, y=0, z=0), direction=mdl.Direction(x=0, y=0, z=1)), + mdl.ClippingPlane(location=mdl.Point(x=0, y=0, z=0), direction=mdl.Direction(x=0, y=1, z=0)), + ] + ), + bitmap=[ + mdl.VisualizationInfoBitmap( + bitmap=mdl.BitmapFormat.PNG, + reference="bitmap.png", + location=mdl.Point(x=10, y=-10, z=7), + normal=mdl.Direction(x=0, y=1, z=0), + up=mdl.Direction(x=0, y=0, z=1), + height=5.0, + ), + mdl.VisualizationInfoBitmap( + bitmap=mdl.BitmapFormat.PNG, + reference="tux.png", + location=mdl.Point(x=20, y=-10, z=7), + normal=mdl.Direction(x=0, y=1, z=0), + up=mdl.Direction(x=0, y=0, z=1), + height=5.0, + ), + ], + guid="8dc86298-9737-40b4-a448-98a9e953293a", + ) + assert viewpoint.visualization_info == expected_vp + assert viewpoint.snapshot is not None + + +def assert_second_viewpoint(viewpoint, expected_selection, expected_exception, expected_coloring) -> None: + expected_vp = mdl.VisualizationInfo( + components=mdl.Components( + view_setup_hints=mdl.ViewSetupHints( + spaces_visible=False, + space_boundaries_visible=False, + openings_visible=False, + ), + selection=expected_selection, + visibility=mdl.ComponentVisibility( + exceptions=expected_exception, + default_visibility=False, + ), + coloring=expected_coloring, + ), + perspective_camera=mdl.PerspectiveCamera( + camera_view_point=mdl.Point(x=-47.18794250488281, y=43.829200744628906, z=10.666350364685059), + camera_direction=mdl.Direction(x=0.6745243072509766, y=-0.6599355936050415, z=-0.33091068267822266), + camera_up_vector=mdl.Direction(x=0.2271970510482788, y=-0.24091780185699463, z=0.9435783624649048), + field_of_view=60, + ), + guid="21dd4807-e9af-439e-a980-04d913a6b1ce", + ) + assert viewpoint.visualization_info == expected_vp + assert viewpoint.snapshot is not None + + +def assert_third_viewpoint(viewpoint, expected_selection, expected_exception, expected_coloring) -> None: + expected_vp = mdl.VisualizationInfo( + components=mdl.Components( + view_setup_hints=mdl.ViewSetupHints( + spaces_visible=False, + space_boundaries_visible=False, + openings_visible=True, + ), + selection=expected_selection, + visibility=mdl.ComponentVisibility( + exceptions=expected_exception, + default_visibility=True, + ), + coloring=expected_coloring, + ), + perspective_camera=mdl.PerspectiveCamera( + camera_view_point=mdl.Point(x=-48.974571228027344, y=-64.20051574707031, z=10.666350364685059), + camera_direction=mdl.Direction(x=0.7232745289802551, y=0.5967116951942444, z=-0.3475759029388428), + camera_up_vector=mdl.Direction(x=0.27662187814712524, y=0.21082592010498047, z=0.937567412853241), + field_of_view=60, + ), + guid="81daa431-bf01-4a49-80a2-1ab07c177717", + ) + assert viewpoint.visualization_info == expected_vp + assert viewpoint.snapshot is not None + + +def assert_files_present(saved_bcf_path, expected_files): + with zipfile.ZipFile(saved_bcf_path) as bcf_zip: + for file_path in expected_files: + assert zipfile.Path(bcf_zip, file_path).exists() diff --git a/src/bcf/tests/v3/Document reference internal.bcf b/src/bcf/tests/v3/Document reference internal.bcf new file mode 100644 index 0000000000000000000000000000000000000000..2f39956c9eaa69b77947016eaab72d6da97ee334 GIT binary patch literal 100614 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 tuple[BcfXml, TopicHandler]: + ext = mdl.Extensions(topic_types=mdl.ExtensionsTopicTypes(topic_type=["Test type"])) + bcf = BcfXml.create_new("Test project", extensions=ext, xml_handler=xml_handler) + orig_th = bcf.add_topic("Test topic", "Test message", "Test author", "Test type") + return bcf, orig_th + + +def test_bcf_roundtrip(xml_handler, build_sample) -> None: + """Saving and loading a bcf xml project returns the same objects.""" + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + with BcfXml.load(file_path, xml_handler=xml_handler) as parsed: + assert parsed == bcf + parsed_th = parsed.topics[orig_th.guid] + assert parsed_th == orig_th + + +def test_bcf_edit_saveas(xml_handler, build_sample) -> None: + """Saving and loading a bcf xml project returns the same objects.""" + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + with BcfXml.load(file_path, xml_handler=xml_handler) as parsed: + for th in parsed.topics.values(): + th.topic.title = "New Topic Title" + modified_path = Path(tmp_dir) / "edited.bcf" + parsed.save(modified_path) + with BcfXml.load(modified_path, xml_handler=xml_handler) as modified_parsed: + assert modified_parsed == bcf + parsed_th = modified_parsed.topics[orig_th.guid] + assert parsed_th.markup != orig_th.markup + assert parsed_th.markup == parsed.topics[orig_th.guid].markup + assert parsed_th.viewpoints == orig_th.viewpoints + assert parsed_th.bim_snippet == orig_th.bim_snippet + + +def test_bcf_edit(xml_handler, build_sample) -> None: + """Saving and loading a bcf xml project returns the same objects.""" + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + with BcfXml.load(file_path, xml_handler=xml_handler) as parsed: + for th in parsed.topics.values(): + th.topic.title = "New Topic Title" + parsed.save() + with BcfXml.load(file_path, xml_handler=xml_handler) as modified_parsed: + assert modified_parsed == bcf + assert len(modified_parsed.topics) == 1 + parsed_th = modified_parsed.topics[orig_th.guid] + assert parsed_th.markup != orig_th.markup + assert parsed_th.markup == parsed.topics[orig_th.guid].markup + assert parsed_th.viewpoints == orig_th.viewpoints + assert parsed_th.bim_snippet == orig_th.bim_snippet + + +def test_save_no_filename(build_sample) -> None: + bcf, _ = build_sample + with pytest.raises(ValueError): + bcf.save() + + +def test_load_no_filename() -> None: + with pytest.raises(ValueError): + BcfXml.load("") + + +def test_save_keep_open(build_sample) -> None: + bcf, orig_th = build_sample + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path, keep_open=True) + assert bcf._zip_file is not None + bcf._zip_file.close() + + +# image = PIL.Image.new('RGB', size=(100, 100)) +# file = BinaryIO() +# image.save(file) + + +def test_massive_bcf(xml_handler) -> None: + ext = mdl.Extensions(topic_types=mdl.ExtensionsTopicTypes(topic_type=["Test type"])) + bcf = BcfXml.create_new("Test project", extensions=ext, xml_handler=xml_handler) + for i in range(100): + th = bcf.add_topic(f"Topic {i:04}", f"Message {i:04}", "Test author", "Test type") + vi = mdl.VisualizationInfo( + guid=str(uuid.uuid4()), + components=build_components(str(uuid.uuid4())), + perspective_camera=build_camera_from_vectors([i, 0, 0], [0, 1, 0], [0, 0, 1]), + ) + vh = VisualizationInfoHandler(visualization_info=vi, xml_handler=xml_handler) + th.add_visinfo_handler(vh) + assert len(bcf.topics) == 100 + with TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / "test.bcf" + bcf.save(file_path) + + +def test_equality_with_wrong_object() -> None: + with pytest.raises(TypeError): + build_sample[0] == "Wrong object" + + +def test_topic_equality_with_wrong_object() -> None: + with pytest.raises(TypeError): + build_sample[1] == "Wrong object" diff --git a/src/bcf/tests/v3/test_example_files.py b/src/bcf/tests/v3/test_example_files.py new file mode 100644 index 0000000000..ec0081a0ea --- /dev/null +++ b/src/bcf/tests/v3/test_example_files.py @@ -0,0 +1,230 @@ +import json +import os +import zipfile +from pathlib import Path + +from xsdata.models.datatype import XmlDateTime + +import bcf.v3.model as mdl +from bcf.v3.bcfxml import BcfXml +from bcf.v3.topic import TopicHandler + + +def test_doc_ref_internal() -> None: + """ + All the info in a BCF is parsed correctly. + + Uses sample file from https://github.com/buildingSMART/BCF-XML/ + """ + bcf_path = Path(__file__).parent / "Document reference internal.bcf" + with BcfXml.load(bcf_path) as bcf: + assert_everything_in_place(bcf) + + +def test_doc_ref_internal_save() -> None: + base_dir = Path(__file__).parent + bcf_path = base_dir / "Document reference internal.bcf" + target_path = base_dir / "Document reference internal Saved.bcf" + with BcfXml.load(bcf_path) as bcf: + bcf.save(target_path) + assert target_path.exists() + with BcfXml.load(target_path) as bcf2: + assert_everything_in_place(bcf2) + assert_files_present(target_path) + os.unlink(target_path) + + +def assert_everything_in_place(bcf: BcfXml): + assert bcf.version.version_id == "3.0" + assert bcf.project.name == "BCF 3.0 test cases" + assert bcf.project.project_id == "de894a86-3a08-4ea0-b2d1-6c222b5602d1" + + assert len(bcf.topics) == 1 + topic_handler = bcf.topics["8ac9822a-761a-4deb-9f39-f61286acbf6a"] + + expected_h1 = mdl.Header( + files=mdl.HeaderFiles( + file=[ + mdl.File( + filename="BCF-ARK", + date=XmlDateTime(2021, 1, 4, 9, 37, 45), + reference="https://bimsync.com/project/f5fbb3c695274d1890036bf64f77eb71/revisions/007afab57f264d2296aae0a452486ae1", + is_external=True, + ), + mdl.File( + filename="BCF-MEP", + date=XmlDateTime(2017, 8, 7, 9, 51, 34), + reference="https://bimsync.com/project/f5fbb3c695274d1890036bf64f77eb71/revisions/a21ed391f9e046a2bb2bc879c48f1d48", + is_external=True, + ), + ] + ) + ) + assert topic_handler.header == expected_h1 + + expected_comments = [ + mdl.Comment( + date=XmlDateTime(2021, 2, 17, 9, 16, 4, 160_000_000), + author="Architect@example.com", + comment="A comment", + viewpoint=mdl.CommentViewpoint(guid="20ad2ff7-ceac-4d4b-b288-ad92a0f65182"), + guid="c045ef04-324d-4c36-9ac8-831f2a15c6d6", + ), + ] + assert topic_handler.comments == expected_comments + + expected_viewpoints = [ + mdl.ViewPoint( + viewpoint="Viewpoint_20ad2ff7-ceac-4d4b-b288-ad92a0f65182.bcfv", + snapshot="Snapshot_20ad2ff7-ceac-4d4b-b288-ad92a0f65182.png", + guid="20ad2ff7-ceac-4d4b-b288-ad92a0f65182", + ), + ] + + expected_topic = mdl.Topic( + reference_links=mdl.TopicReferenceLinks(), + title="Document Reference Internal", + labels=mdl.TopicLabels(), + creation_date=XmlDateTime(2021, 2, 17, 9, 16, 4, 160_000_000), + creation_author="Architect@example.com", + modified_date=XmlDateTime(2021, 2, 17, 9, 16, 4, 160_000_000), + assigned_to="OtherUser@doe.com", + document_references=mdl.TopicDocumentReferences( + document_reference=[ + mdl.DocumentReference( + document_guid="b1d1b7f0-60b9-457d-ad12-16e0fb997bc5", + description="ThisIsADocument.txt", + guid="048e898f-555f-47c3-a273-6c664fb2ef69", + ), + ], + ), + related_topics=mdl.TopicRelatedTopics(), + comments=mdl.TopicComments(comment=expected_comments), + viewpoints=mdl.TopicViewpoints(view_point=expected_viewpoints), + guid="8ac9822a-761a-4deb-9f39-f61286acbf6a", + server_assigned_id="6", + topic_type="ERROR", + topic_status="OPEN", + ) + assert topic_handler.topic == expected_topic + + expected_m1 = mdl.Markup( + header=expected_h1, + topic=expected_topic, + ) + assert topic_handler.markup == expected_m1 + + assert topic_handler.bim_snippet is None + + assert_viewpoints(topic_handler.viewpoints) + + +def assert_viewpoints(viewpoints): + assert len(viewpoints) == 1 + + expected_vp = mdl.VisualizationInfo( + components=mdl.Components( + selection=mdl.ComponentSelection(), + visibility=mdl.ComponentVisibility( + view_setup_hints=mdl.ViewSetupHints( + spaces_visible=False, + space_boundaries_visible=False, + openings_visible=False, + ), + exceptions=mdl.ComponentVisibilityExceptions( + component=[ + mdl.Component(ifc_guid="1m5wAJelDFdhn6qBdOGjos", originating_system="https://bimsync.com"), + mdl.Component(ifc_guid="1bbI761TbBCOoIa5Kt6PXt", originating_system="https://bimsync.com"), + ] + ), + default_visibility=True, + ), + coloring=mdl.ComponentColoring(), + ), + perspective_camera=mdl.PerspectiveCamera( + camera_view_point=mdl.Point(x=23.112083480037754, y=-25.45574897560043, z=18.52519828443092), + camera_direction=mdl.Direction(x=-0.6289237666876837, y=0.5933487270610425, z=-0.5023864884632315), + camera_up_vector=mdl.Direction(x=-0.36542566067664123, y=0.3447553774917179, z=0.8646431727652648), + field_of_view=60, + aspect_ratio=1, + ), + lines=mdl.VisualizationInfoLines(), + clipping_planes=mdl.VisualizationInfoClippingPlanes(), + bitmaps=mdl.VisualizationInfoBitmaps(), + guid="20ad2ff7-ceac-4d4b-b288-ad92a0f65182", + ) + + viewpoint = viewpoints["Viewpoint_20ad2ff7-ceac-4d4b-b288-ad92a0f65182.bcfv"] + assert viewpoint.visualization_info == expected_vp + assert viewpoint.snapshot is not None + + +def assert_second_viewpoint(viewpoint, expected_selection, expected_exception, expected_coloring) -> None: + expected_vp = mdl.VisualizationInfo( + components=mdl.Components( + view_setup_hints=mdl.ViewSetupHints( + spaces_visible=False, + space_boundaries_visible=False, + openings_visible=False, + ), + selection=expected_selection, + visibility=mdl.ComponentVisibility( + exceptions=expected_exception, + default_visibility=False, + ), + coloring=expected_coloring, + ), + perspective_camera=mdl.PerspectiveCamera( + camera_view_point=mdl.Point(x=-47.18794250488281, y=43.829200744628906, z=10.666350364685059), + camera_direction=mdl.Direction(x=0.6745243072509766, y=-0.6599355936050415, z=-0.33091068267822266), + camera_up_vector=mdl.Direction(x=0.2271970510482788, y=-0.24091780185699463, z=0.9435783624649048), + field_of_view=60, + ), + guid="21dd4807-e9af-439e-a980-04d913a6b1ce", + ) + assert viewpoint.visualization_info == expected_vp + assert viewpoint.snapshot is not None + + +def assert_third_viewpoint(viewpoint, expected_selection, expected_exception, expected_coloring) -> None: + expected_vp = mdl.VisualizationInfo( + components=mdl.Components( + view_setup_hints=mdl.ViewSetupHints( + spaces_visible=False, + space_boundaries_visible=False, + openings_visible=True, + ), + selection=expected_selection, + visibility=mdl.ComponentVisibility( + exceptions=expected_exception, + default_visibility=True, + ), + coloring=expected_coloring, + ), + perspective_camera=mdl.PerspectiveCamera( + camera_view_point=mdl.Point(x=-48.974571228027344, y=-64.20051574707031, z=10.666350364685059), + camera_direction=mdl.Direction(x=0.7232745289802551, y=0.5967116951942444, z=-0.3475759029388428), + camera_up_vector=mdl.Direction(x=0.27662187814712524, y=0.21082592010498047, z=0.937567412853241), + field_of_view=60, + ), + guid="81daa431-bf01-4a49-80a2-1ab07c177717", + ) + assert viewpoint.visualization_info == expected_vp + assert viewpoint.snapshot is not None + + +def assert_files_present(saved_bcf_path): + expected_files = [ + "bcf.version", + "project.bcfp", + "documents.xml", + "extensions.xml", + "documents/b1d1b7f0-60b9-457d-ad12-16e0fb997bc5", + "8ac9822a-761a-4deb-9f39-f61286acbf6a/markup.bcf", + "8ac9822a-761a-4deb-9f39-f61286acbf6a/Viewpoint_20ad2ff7-ceac-4d4b-b288-ad92a0f65182.bcfv", + "8ac9822a-761a-4deb-9f39-f61286acbf6a/Snapshot_20ad2ff7-ceac-4d4b-b288-ad92a0f65182.png", + ] + + with zipfile.ZipFile(saved_bcf_path) as bcf_zip: + for file_path in expected_files: + assert zipfile.Path(bcf_zip, file_path).exists()