mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-22 13:05:59 +00:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 170ef1b4b7 | |||
| d4a5420851 | |||
| 87bc6bfbab | |||
| a5e94cf0d8 | |||
| 2c1d445d5b | |||
| d86f89090b | |||
| 973f61c6dc | |||
| f47aa4d81a | |||
| fa9a3383aa | |||
| 104591a80b | |||
| 030e6e5bb4 | |||
| a031310a66 | |||
| 436e3f7b2a | |||
| 335d571854 | |||
| f78b380b71 | |||
| 2cebc3f60b | |||
| 0a8159505d | |||
| 301fba5a8b | |||
| ba90cf220d | |||
| 6318892a97 | |||
| 1a6336bd20 | |||
| 511584b36f | |||
| f65de78c46 | |||
| 59b957daff | |||
| 81a0941d5a | |||
| dba735f1ee | |||
| e100cf5a34 | |||
| 665502cbc5 | |||
| 252831d7f0 | |||
| 3a6055a558 | |||
| 7b1b0b986c | |||
| cd34d92fdb | |||
| 1391c7d974 | |||
| 223d6da3b1 | |||
| 171e899eb0 | |||
| e2561ffa3b | |||
| 4b87ab5d0d | |||
| 8cc36f0d4d | |||
| 13cc190849 | |||
| b71354ce19 | |||
| 17042f6f80 | |||
| beb0db89e5 | |||
| 572f718007 | |||
| 6bab0603e6 | |||
| b408e64e5e | |||
| f580f7255f | |||
| b252cd25f8 | |||
| 935562142e | |||
| d1d0fb4636 | |||
| e0b226f4ca | |||
| 79bd3563de | |||
| 4e887e1c59 | |||
| fa9f3b5cb7 | |||
| 77dc679a6e | |||
| ce9e2b94d5 | |||
| 58dcaed89a | |||
| 109bd58384 | |||
| b6dccce12a | |||
| daa7d98b3f | |||
| 321760cea4 | |||
| 7b9615f4e5 | |||
| ff22a9d1f3 | |||
| 055f64fa9b | |||
| 7370d07db1 | |||
| 717d6aa2af | |||
| 69b0409aa0 | |||
| 4095d5c8d6 | |||
| 19a3707f72 | |||
| 262117c4f8 | |||
| 246fa24be0 | |||
| 35d2fb43e2 | |||
| f10f7eba83 | |||
| 785936000a | |||
| 83fc219a8a | |||
| 7a1dcd07c8 | |||
| b63137e859 | |||
| 3d15500976 | |||
| 64aed6a766 | |||
| a08eed7ac9 | |||
| 076f46cfeb | |||
| a353edb9e0 | |||
| 30fb379e32 | |||
| dbea3f0362 | |||
| b5eca83357 | |||
| e5aaf7c602 | |||
| 9e53d0dcc9 | |||
| 17c4d8faff | |||
| c9c7edd4d6 | |||
| 96653029cf | |||
| e9fffc221b | |||
| a441757080 | |||
| c818f48a47 | |||
| 28c9c1d34d | |||
| f05dd4aea5 | |||
| dcfc22e29e | |||
| be3c2ee770 | |||
| fbfa51c451 | |||
| 19f3261dc3 | |||
| 7ed8584edc | |||
| 61f30dd200 | |||
| b706121f53 | |||
| 99a09a2a3c | |||
| 2ba55ba984 | |||
| 616c7a00d5 | |||
| 8c003110fe | |||
| 4e49b640a7 | |||
| c30841aad6 | |||
| 4597929df9 | |||
| 2859c1ef17 | |||
| 7ae6bf4374 | |||
| 02481b3247 | |||
| 2c47c9d4fa | |||
| c2abc3f844 | |||
| 4dcd644a32 | |||
| 6fea72b045 | |||
| 1573730f18 | |||
| 8f4832651a | |||
| af58eaf79f | |||
| 8870ffb018 | |||
| c5ba22451f | |||
| 1a931ddfd9 | |||
| f7876a97ee | |||
| 4d0e5f6aee | |||
| dfc60196ec | |||
| ef4bba8b33 | |||
| 048242783e | |||
| 6f3acc84ee | |||
| e077390e3d | |||
| 80cc603932 |
@@ -1,5 +1,4 @@
|
||||
Checks: 'bugprone-*,cert-*,clang-analyzer-*,readability-*'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: none
|
||||
@@ -0,0 +1,377 @@
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "pytest",
|
||||
# ]
|
||||
# ///
|
||||
|
||||
"""Check (and by default fix) whitespace issues in tracked source files:
|
||||
- stray CR, e.g. 'hello\\rworld' -> 'helloworld'
|
||||
- line ending mismatch, e.g. 'hello\\r\\n' -> 'hello\\n' (or vice versa)
|
||||
- missing newline at end of file
|
||||
- extra newline(s) at end of file
|
||||
- trailing whitespace at end of line
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import BinaryIO, Literal, cast
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class C:
|
||||
RED = "\033[31m"
|
||||
GREEN = "\033[32m"
|
||||
YELLOW = "\033[33m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
|
||||
CR = b"\r"
|
||||
CRLF = b"\r\n"
|
||||
LF = b"\n"
|
||||
|
||||
LineSeparator = Literal[b"\r\n", b"\n"]
|
||||
SYSTEM_LINE_SEPARATOR = cast(LineSeparator, os.linesep.encode())
|
||||
|
||||
|
||||
class Checker:
|
||||
def __init__(self, newline: LineSeparator = SYSTEM_LINE_SEPARATOR) -> None:
|
||||
self.newline = newline
|
||||
self.issues = 0
|
||||
|
||||
def report(self, label: str, issue: str) -> None:
|
||||
self.issues += 1
|
||||
print(f"{label}: {C.RED}{issue}{C.RESET}")
|
||||
|
||||
def check_stray_cr(self, filepath: Path, check: bool) -> None:
|
||||
with filepath.open("r+b") as f:
|
||||
self._check_stray_cr(f, str(filepath), check)
|
||||
|
||||
def _check_stray_cr(self, f: BinaryIO, label: str, check: bool) -> None:
|
||||
# a CR is "stray" if it isn't immediately followed by a LF, i.e. not part of a CRLF pair
|
||||
# CRLF/CR mismatch will be reported separately.
|
||||
stray_cr = re.compile(rb"\r(?!\n)")
|
||||
|
||||
content = f.read()
|
||||
matches = list(stray_cr.finditer(content))
|
||||
if not matches:
|
||||
return
|
||||
|
||||
line_numbers = dict.fromkeys(content.count(b"\n", 0, m.start()) + 1 for m in matches)
|
||||
for line_number in line_numbers:
|
||||
self.report(f"{label}:{line_number}", "stray carriage return")
|
||||
if check:
|
||||
return
|
||||
|
||||
f.seek(0)
|
||||
f.write(stray_cr.sub(b"", content))
|
||||
f.truncate()
|
||||
|
||||
def check_line_endings_mismatch(self, filepath: Path, check: bool) -> None:
|
||||
with filepath.open("r+b") as f:
|
||||
self._check_line_endings_mismatch(f, str(filepath), check)
|
||||
|
||||
def _check_line_endings_mismatch(self, f: BinaryIO, label: str, check: bool) -> None:
|
||||
NEWLINE = self.newline
|
||||
|
||||
def get_line_ending(line: bytes) -> LineSeparator | None:
|
||||
if line.endswith(CRLF):
|
||||
return CRLF
|
||||
if line.endswith(LF):
|
||||
return LF
|
||||
# last line with no trailing newline at all; check_eof_newline handles that
|
||||
return None
|
||||
|
||||
changed = False
|
||||
fixed_lines = []
|
||||
for line_number, line in enumerate(f, start=1):
|
||||
found = get_line_ending(line)
|
||||
if found in (NEWLINE, None):
|
||||
fixed_lines.append(line)
|
||||
continue
|
||||
|
||||
self.report(f"{label}:{line_number}", f"line ending mismatch (expected {NEWLINE!r}, found {found!r})")
|
||||
changed = True
|
||||
content = line[: -len(found)]
|
||||
fixed_lines.append(content + NEWLINE)
|
||||
|
||||
if changed and not check:
|
||||
f.seek(0)
|
||||
f.write(b"".join(fixed_lines))
|
||||
f.truncate()
|
||||
|
||||
def check_eof_newline(self, filepath: Path, check: bool) -> None:
|
||||
with filepath.open("r+b") as f:
|
||||
self._check_eof_newline(f, str(filepath), check)
|
||||
|
||||
def _check_eof_newline(self, f: BinaryIO, label: str, check: bool) -> None:
|
||||
NEWLINE = self.newline
|
||||
NEWLINE_SIZE = len(NEWLINE)
|
||||
|
||||
size = f.seek(0, os.SEEK_END)
|
||||
if size == 0:
|
||||
return
|
||||
|
||||
trailing_newlines = 0
|
||||
while True:
|
||||
pos = f.seek((-trailing_newlines - 1) * NEWLINE_SIZE, os.SEEK_END)
|
||||
if f.read(NEWLINE_SIZE) != NEWLINE:
|
||||
break
|
||||
trailing_newlines += 1
|
||||
if pos == 0:
|
||||
break
|
||||
|
||||
if trailing_newlines == 0:
|
||||
self.report(label, "missing newline at end of file")
|
||||
if check:
|
||||
return
|
||||
f.seek(0, os.SEEK_END)
|
||||
f.write(NEWLINE)
|
||||
elif trailing_newlines > 1:
|
||||
self.report(label, f"{trailing_newlines} trailing newlines at end of file")
|
||||
if check:
|
||||
return
|
||||
f.truncate(size - (trailing_newlines - 1) * NEWLINE_SIZE)
|
||||
|
||||
def check_trailing_whitespaces(self, filepath: Path, check: bool) -> None:
|
||||
with filepath.open("r+b") as f:
|
||||
self._check_trailing_whitespaces(f, str(filepath), check)
|
||||
|
||||
def _check_trailing_whitespaces(self, f: BinaryIO, label: str, check: bool) -> None:
|
||||
NEWLINE = self.newline
|
||||
NEWLINE_SIZE = len(NEWLINE)
|
||||
|
||||
changed = False
|
||||
fixed_lines = []
|
||||
for line_number, line in enumerate(f, start=1):
|
||||
has_newline = line.endswith(NEWLINE)
|
||||
content = line[:-NEWLINE_SIZE] if has_newline else line
|
||||
stripped = content.rstrip()
|
||||
if stripped != content:
|
||||
self.report(f"{label}:{line_number}", "trailing whitespace")
|
||||
changed = True
|
||||
fixed_lines.append(stripped + (NEWLINE if has_newline else b""))
|
||||
|
||||
if changed and not check:
|
||||
f.seek(0)
|
||||
f.write(b"".join(fixed_lines))
|
||||
f.truncate()
|
||||
|
||||
|
||||
CheckMethod = Callable[[Checker, BinaryIO, str, bool], None]
|
||||
|
||||
|
||||
class TestChecker:
|
||||
def _assert_check(
|
||||
self,
|
||||
method: CheckMethod,
|
||||
content: bytes,
|
||||
expected_issues: int,
|
||||
fixed: bytes,
|
||||
check: bool,
|
||||
line_ending: LineSeparator,
|
||||
*,
|
||||
transform: bool = True,
|
||||
) -> None:
|
||||
checker = Checker(line_ending)
|
||||
if line_ending == CRLF and transform:
|
||||
content = content.replace(LF, CRLF)
|
||||
fixed = fixed.replace(LF, CRLF)
|
||||
buffer = io.BytesIO(content)
|
||||
method(checker, buffer, "test", check)
|
||||
assert buffer.getvalue() == (content if check else fixed)
|
||||
assert checker.issues == expected_issues
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("content", "expected_issues", "fixed"),
|
||||
(
|
||||
# OK
|
||||
(b"", 0, b""),
|
||||
(b"hello\n", 0, b"hello\n"),
|
||||
(b"line1\r\nline2\n", 0, b"line1\r\nline2\n"),
|
||||
# ERR
|
||||
(b"hello\rworld\n", 1, b"helloworld\n"),
|
||||
(b"a\rb\rc\n", 1, b"abc\n"),
|
||||
(b"hello\r", 1, b"hello"),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("check", [False, True])
|
||||
def test_check_stray_cr(self, content: bytes, expected_issues: int, fixed: bytes, check: bool) -> None:
|
||||
# Don't parametrize by line endings, since in this case it doesn't matter.
|
||||
self._assert_check(Checker._check_stray_cr, content, expected_issues, fixed, check, LF)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("content", "expected_issues", "fixed", "line_ending"),
|
||||
(
|
||||
# OK
|
||||
(b"", 0, b"", LF),
|
||||
(b"hello\n", 0, b"hello\n", LF),
|
||||
(b"hello\r\n", 0, b"hello\r\n", CRLF),
|
||||
# ERR
|
||||
(b"hello\r\n", 1, b"hello\n", LF),
|
||||
(b"a\nb\r\nc\n", 1, b"a\nb\nc\n", LF),
|
||||
(b"a\r\nb\r\n", 2, b"a\nb\n", LF),
|
||||
(b"hello\n", 1, b"hello\r\n", CRLF),
|
||||
(b"a\r\nb\nc\r\n", 1, b"a\r\nb\r\nc\r\n", CRLF),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("check", [False, True])
|
||||
def test_check_line_endings_mismatch(
|
||||
self, content: bytes, expected_issues: int, fixed: bytes, line_ending: LineSeparator, check: bool
|
||||
) -> None:
|
||||
self._assert_check(
|
||||
Checker._check_line_endings_mismatch, content, expected_issues, fixed, check, line_ending, transform=False
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("content", "expected_issues", "fixed"),
|
||||
(
|
||||
# OK
|
||||
(b"", 0, b""),
|
||||
(b"hello\n", 0, b"hello\n"),
|
||||
# ERR
|
||||
(b"hello", 1, b"hello\n"),
|
||||
(b"hello\n\n\n", 1, b"hello\n"),
|
||||
(b"\n\n\n", 1, b"\n"),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("check", [False, True])
|
||||
@pytest.mark.parametrize("line_ending", [LF, CRLF])
|
||||
def test_check_eof_newline(
|
||||
self, content: bytes, expected_issues: int, fixed: bytes, check: bool, line_ending: LineSeparator
|
||||
) -> None:
|
||||
self._assert_check(Checker._check_eof_newline, content, expected_issues, fixed, check, line_ending)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("content", "expected_issues", "fixed"),
|
||||
(
|
||||
# OK
|
||||
(b"", 0, b""),
|
||||
(b"hello\n", 0, b"hello\n"),
|
||||
(b"hello", 0, b"hello"),
|
||||
# ERR
|
||||
(b" ", 1, b""),
|
||||
(b"hello ", 1, b"hello"),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("check", [False, True])
|
||||
@pytest.mark.parametrize("line_ending", [LF, CRLF])
|
||||
def test_check_trailing_whitespaces(
|
||||
self, content: bytes, expected_issues: int, fixed: bytes, check: bool, line_ending: LineSeparator
|
||||
) -> None:
|
||||
self._assert_check(Checker._check_trailing_whitespaces, content, expected_issues, fixed, check, line_ending)
|
||||
|
||||
@staticmethod
|
||||
def run_tests(extra_args: list[str] | None = None) -> None:
|
||||
pytest.main([__file__, *(extra_args or [])])
|
||||
|
||||
|
||||
def existing_path(value: str) -> Path:
|
||||
path = Path(value)
|
||||
if not path.exists():
|
||||
raise argparse.ArgumentTypeError(f"path not found: {value}")
|
||||
return path
|
||||
|
||||
|
||||
# Python files are covered by `black`.
|
||||
PATTERNS = (
|
||||
"*.cpp",
|
||||
"*.h",
|
||||
"*.i",
|
||||
)
|
||||
|
||||
REPO_ROOT = Path(subprocess.check_output(["git", "rev-parse", "--show-toplevel"], text=True).strip())
|
||||
|
||||
# Generated files; formatted by the express codegen, not by this script.
|
||||
IGNORED_DIRS = (REPO_ROOT / "src/ifcparse/schemas",)
|
||||
|
||||
|
||||
def get_tracked_files(root: Path | None = None) -> list[Path]:
|
||||
output = subprocess.check_output(
|
||||
["git", "ls-files", "--others", "--cached", "--exclude-standard", *PATTERNS],
|
||||
cwd=root,
|
||||
text=True,
|
||||
)
|
||||
base = root if root is not None else Path()
|
||||
filepaths = []
|
||||
for line in output.splitlines():
|
||||
filepath = base / line
|
||||
if not any(filepath.resolve().is_relative_to(d) for d in IGNORED_DIRS):
|
||||
filepaths.append(filepath)
|
||||
return filepaths
|
||||
|
||||
|
||||
def main() -> int:
|
||||
# anything after "--" is forwarded to pytest, e.g. `--test -- --capture=no`
|
||||
argv = sys.argv[1:]
|
||||
if "--" in argv:
|
||||
split = argv.index("--")
|
||||
argv, extra_args = argv[:split], argv[split + 1 :]
|
||||
else:
|
||||
extra_args = []
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=__doc__,
|
||||
)
|
||||
parser.add_argument("paths", type=existing_path, nargs="*", help="files or directories to check")
|
||||
parser.add_argument(
|
||||
"--check",
|
||||
action="store_true",
|
||||
help="only check for whitespace issues without applying fixes",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--test",
|
||||
action="store_true",
|
||||
help="run self-tests",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
action="store_true",
|
||||
help="print each checked path",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.test:
|
||||
TestChecker.run_tests(extra_args)
|
||||
return 0
|
||||
|
||||
if args.paths:
|
||||
filepaths: list[Path] = []
|
||||
for path in args.paths:
|
||||
filepaths.extend(get_tracked_files(path) if path.is_dir() else [path])
|
||||
else:
|
||||
filepaths = get_tracked_files()
|
||||
|
||||
# dict.fromkeys() dedupes while preserving order, unlike set().
|
||||
filepaths = list(dict.fromkeys(filepaths))
|
||||
|
||||
checker = Checker()
|
||||
for filepath in filepaths:
|
||||
if args.verbose:
|
||||
print(f"checking {filepath}")
|
||||
checker.check_stray_cr(filepath, args.check)
|
||||
checker.check_line_endings_mismatch(filepath, args.check)
|
||||
checker.check_eof_newline(filepath, args.check)
|
||||
checker.check_trailing_whitespaces(filepath, args.check)
|
||||
print(f"{len(filepaths)} file(s) checked.")
|
||||
if not checker.issues:
|
||||
color = C.GREEN
|
||||
elif args.check:
|
||||
color = C.RED
|
||||
else:
|
||||
color = C.YELLOW
|
||||
outcome = "found" if args.check else "found and fixed"
|
||||
print(f"{color}{checker.issues} issue(s) {outcome}.{C.RESET}")
|
||||
|
||||
return 1 if args.check and checker.issues else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
working-directory: src/bonsaiviewer-autodesk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
|
||||
@@ -35,6 +35,9 @@ jobs:
|
||||
lfs: true
|
||||
token: ${{ secrets.BUILD_REPO_TOKEN }}
|
||||
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
|
||||
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
brew update
|
||||
@@ -61,7 +64,7 @@ jobs:
|
||||
- name: Unpack Dependencies
|
||||
run: |
|
||||
cd build
|
||||
python ../nix/cache_dependencies.py unpack
|
||||
uv run ../nix/cache_dependencies.py unpack
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||
@@ -102,7 +105,7 @@ jobs:
|
||||
# INSTALL_RPATH to "@loader_path" on Apple.
|
||||
CXXFLAGS="-O3" CFLAGS="-O3 ${DARWIN_C_SOURCE}" ADD_COMMIT_SHA=1 BUILD_CFG=Release \
|
||||
BUILD_BONSAIVIEWER=ON QT_DIR="${QT_DIR}" \
|
||||
python3 ./nix/build-all.py -v --diskcleanup --ifcopenshell-shared ${MAC_INTEL} \
|
||||
uv run ./nix/build-all.py -v --diskcleanup --ifcopenshell-shared ${MAC_INTEL} \
|
||||
| tee build.log
|
||||
|
||||
- name: Upload Build Logs
|
||||
@@ -119,7 +122,7 @@ jobs:
|
||||
- name: Pack Dependencies
|
||||
run: |
|
||||
cd build
|
||||
python ../nix/cache_dependencies.py pack
|
||||
uv run ../nix/cache_dependencies.py pack
|
||||
|
||||
- name: Commit and Push Changes to Build Repository
|
||||
run: |
|
||||
@@ -136,7 +139,7 @@ jobs:
|
||||
# packaging/build.py stages the connector binary + connector.json
|
||||
# into dist/autodesk/; the .app loop below copies that folder into
|
||||
# the bundle. Same on-disk shape as the Linux and Windows builds.
|
||||
python3 src/bonsaiviewer-autodesk/packaging/build.py
|
||||
uv run src/bonsaiviewer-autodesk/packaging/build.py
|
||||
autodesk_connector_dir="$PWD/src/bonsaiviewer-autodesk/dist/autodesk"
|
||||
test -d "$autodesk_connector_dir"
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ jobs:
|
||||
python-version: '3.11'
|
||||
- name: Get current version
|
||||
id: version
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
run: echo "version=$(sed -E 's/[[:alpha:]]+[0-9]+$//' VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Compile
|
||||
run: |
|
||||
cd src/bonsai && make dist PLATFORM=${{ matrix.config.short_name }} PYVERSION=${{ matrix.pyver }}
|
||||
|
||||
@@ -27,7 +27,9 @@ jobs:
|
||||
|
||||
- name: Get current version
|
||||
id: version
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
# Strip any trailing prerelease label and number; the dated alpha
|
||||
# suffix is added below.
|
||||
run: echo "version=$(sed -E 's/[[:alpha:]]+[0-9]+$//' VERSION)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get current date
|
||||
id: date
|
||||
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
python-version: '3.11'
|
||||
- name: Get current version
|
||||
id: version
|
||||
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
|
||||
run: echo "version=$(sed -E 's/[[:alpha:]]+[0-9]+$//' VERSION)" >> $GITHUB_OUTPUT
|
||||
- name: Get current date
|
||||
id: date
|
||||
run: echo "date=$(date +'%y%m%d')" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -7,7 +7,7 @@ on:
|
||||
- src/ifctester/**
|
||||
|
||||
jobs:
|
||||
publish_website:
|
||||
publish_ifctester_org:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
@@ -43,6 +43,7 @@ jobs:
|
||||
sudo apt update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
cmake \
|
||||
bison \
|
||||
gcc \
|
||||
g++ \
|
||||
libboost-date-time-dev \
|
||||
@@ -61,13 +62,23 @@ jobs:
|
||||
libocct-ocaf-dev \
|
||||
libocct-visualization-dev \
|
||||
libpcre3-dev \
|
||||
libpcre2-dev \
|
||||
libtbb-dev \
|
||||
libxml2-dev \
|
||||
libxi-dev \
|
||||
occt-misc \
|
||||
tcl-dev \
|
||||
tk-dev \
|
||||
swig
|
||||
tk-dev
|
||||
|
||||
- name: Build SWIG
|
||||
# IfcOpenShell requires SWIG 4.1+, ubuntu-22.04 ships 4.0.2.
|
||||
run: |
|
||||
sudo apt-get remove --purge -y swig swig4.0
|
||||
git clone https://github.com/swig/swig --branch v4.2.1 --depth 1
|
||||
cmake -S swig -B swig/build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build swig/build -j "$(nproc)"
|
||||
sudo cmake --install swig/build
|
||||
swig -version
|
||||
|
||||
- name: Configure minimal IfcOpenShell
|
||||
run: |
|
||||
|
||||
@@ -121,7 +121,7 @@ jobs:
|
||||
cd OpenCOLLADA
|
||||
git checkout v1.6.68
|
||||
patch -p1 --batch --forward -i ../nix/patches/opencollada/pr622_and_disable_subdirs.patch
|
||||
patch -p1 --batch --forward -i ../nix/patches/opencollada/allow_static_libraries_config_on_unix.patch
|
||||
patch -p1 --batch --forward -i ../nix/patches/opencollada/config_select_libs_by_use_shared.patch
|
||||
mkdir build && cd build
|
||||
cmake .. \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
name: Publish C++ API documentation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v0.9.0
|
||||
paths:
|
||||
- '.github/workflows/publish-cpp-api-docs.yml'
|
||||
- 'docs/cpp-api/**'
|
||||
- 'src/ifcgeom/**'
|
||||
- 'src/ifcparse/**'
|
||||
- 'src/serializers/**'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: publish-cpp-api-docs
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
if: github.repository == 'IfcOpenShell/IfcOpenShell'
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Checkout IfcOpenShell
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install documentation dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install --yes doxygen graphviz
|
||||
python -m pip install --requirement docs/cpp-api/requirements.txt
|
||||
|
||||
- name: Build C++ API documentation
|
||||
working-directory: docs/cpp-api
|
||||
run: |
|
||||
export PROJECT_NUMBER="$(git rev-parse --short HEAD)"
|
||||
python -m sphinx -M html . output -W --keep-going
|
||||
|
||||
- name: Checkout documentation repository
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
repository: IfcOpenShell/cpp_docs
|
||||
ref: master
|
||||
path: published-docs
|
||||
token: ${{ secrets.BUILD_REPO_TOKEN }}
|
||||
|
||||
- name: Replace published documentation
|
||||
run: |
|
||||
publish_tree="${RUNNER_TEMP}/published-docs-tree"
|
||||
mkdir -p "${publish_tree}/v0.9.0-latest"
|
||||
|
||||
rsync --archive docs/cpp-api/output/html/ "${publish_tree}/v0.9.0-latest/"
|
||||
touch "${publish_tree}/.nojekyll"
|
||||
|
||||
if [[ -f published-docs/CNAME ]]; then
|
||||
cp published-docs/CNAME "${publish_tree}/CNAME"
|
||||
fi
|
||||
|
||||
rsync --archive --delete --exclude='.git/' "${publish_tree}/" published-docs/
|
||||
|
||||
- name: Commit and push if changed
|
||||
working-directory: published-docs
|
||||
env:
|
||||
SOURCE_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
git config user.name 'IfcOpenBot'
|
||||
git config user.email 'IfcOpenBot@users.noreply.github.com'
|
||||
|
||||
git add --all
|
||||
if git diff --cached --quiet; then
|
||||
echo "No changes to commit"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
git commit -m "Update C++ API docs from ${SOURCE_SHA:0:7}"
|
||||
git push origin master
|
||||
+7
-3
@@ -111,10 +111,11 @@ src/ifcopenshell-python/ifcopenshell/_ifcopenshell_wrapper*.so
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell_wrapper.py
|
||||
|
||||
# plugins
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell.document.*.so
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell.geometry.*.so
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell.parse.schema*.so
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell_document_*.so
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell_geometry_*.so
|
||||
src/ifcopenshell-python/ifcopenshell/ifcopenshell_parse_schema*.so
|
||||
src/ifcopenshell-python/ifcopenshell/libifcopenshell.geometry.so
|
||||
src/ifcopenshell-python/ifcopenshell/libifcopenshell.geometry.writer.so
|
||||
src/ifcopenshell-python/ifcopenshell/libifcopenshell.parse.so
|
||||
src/ifcopenshell-python/ifcopenshell/libifcopenshell.plugin.so
|
||||
|
||||
@@ -125,6 +126,9 @@ src/ifcopenshell-python/ifcopenshell/libifcopenshell.plugin.so
|
||||
.clangd
|
||||
# clangd cache
|
||||
.cache
|
||||
# Useful for symlinking json compilation database from cmake,
|
||||
# allowing clang commands without `-p path/to/build`.
|
||||
/compile_commands.json
|
||||
|
||||
# Brickschema
|
||||
src/bonsai/bonsai/bim/schema/Brick.ttl
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
[submodule "src/ifcopenshell-python/test/Sample-BIM-Files"]
|
||||
path = src/ifcopenshell-python/test/Sample-BIM-Files
|
||||
url = https://github.com/IfcOpenShell/ids-test-files
|
||||
[submodule "docs/cpp-api/assets/doxygen-awesome-css"]
|
||||
path = docs/cpp-api/assets/doxygen-awesome-css
|
||||
url = https://github.com/jothepro/doxygen-awesome-css.git
|
||||
[submodule "src/ifcopenshell-python/ifcopenshell/simple_spf"]
|
||||
path = src/ifcopenshell-python/ifcopenshell/simple_spf
|
||||
url = https://github.com/IfcOpenShell/step-file-parser
|
||||
|
||||
+19
-14
@@ -36,6 +36,14 @@ file(READ "../VERSION" "RELEASE_VERSION_")
|
||||
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
||||
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
||||
|
||||
# CMake's project(VERSION) only accepts numeric components. Keep the complete
|
||||
# release identifier for build information, but use its numeric release part
|
||||
# for PROJECT_VERSION, SOVERSION, and generated CMake package metadata.
|
||||
string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" PROJECT_VERSION_NUMERIC "${RELEASE_VERSION}")
|
||||
if(NOT PROJECT_VERSION_NUMERIC)
|
||||
message(FATAL_ERROR "VERSION must start with a numeric major.minor.patch version: '${RELEASE_VERSION}'")
|
||||
endif()
|
||||
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
|
||||
if(POLICY CMP0141) # 3.25+
|
||||
@@ -55,9 +63,15 @@ endif()
|
||||
# Include utility macros and functions
|
||||
include(utilities.cmake)
|
||||
|
||||
# use extra version to make pre-release using eg semver
|
||||
# Use a SemVer-compatible spelling for CPack artifact names. A trailing
|
||||
# alphabetic label and number is separated from the numeric version by a
|
||||
# hyphen: for example, 0.9.0alpha0 becomes 0.9.0-alpha0.
|
||||
if(NOT DEFINED EXTRA_VERSION)
|
||||
set(EXTRA_VERSION "-alpha.3")
|
||||
if(RELEASE_VERSION MATCHES "^[0-9]+\\.[0-9]+\\.[0-9]+([A-Za-z]+)([0-9]+)$")
|
||||
set(EXTRA_VERSION "-${CMAKE_MATCH_1}${CMAKE_MATCH_2}")
|
||||
else()
|
||||
set(EXTRA_VERSION "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF)
|
||||
@@ -119,7 +133,7 @@ option(WITH_ZSTD "Use Zstd compression in RocksDB writes" OFF)
|
||||
option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF)
|
||||
option(USE_DEBUG_PYTHON "Use debug binaries when building Debug IfcPython on Windows." OFF)
|
||||
option(ADD_COMMIT_SHA "Add commit sha and branch in version number, requires git" OFF)
|
||||
option(VERSION_OVERRIDE "Override the version defined in buildinfo.cpp with the file VERSION in the repository root" OFF)
|
||||
option(VERSION_OVERRIDE "Use VERSION as the branch label when commit information is embedded" OFF)
|
||||
|
||||
set(
|
||||
PYTHON_MODULE_INSTALL_DIR
|
||||
@@ -127,15 +141,7 @@ set(
|
||||
"Directory to install IfcPython package to. By default package is installed in found Python's site-packages."
|
||||
)
|
||||
|
||||
if (VERSION_OVERRIDE)
|
||||
file(READ "../VERSION" "RELEASE_VERSION_")
|
||||
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
||||
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
||||
else()
|
||||
set(RELEASE_VERSION "0.8.0")
|
||||
endif()
|
||||
|
||||
project(IfcOpenShell VERSION ${RELEASE_VERSION})
|
||||
project(IfcOpenShell VERSION ${PROJECT_VERSION_NUMERIC})
|
||||
|
||||
# Make sure CMake modules in this project are found first
|
||||
list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
|
||||
@@ -693,8 +699,7 @@ endif()
|
||||
|
||||
# Documentation
|
||||
if(BUILD_DOCUMENTATION)
|
||||
set(CMAKE_MODULE_PATH "../docs/cmake")
|
||||
add_subdirectory(../docs docs)
|
||||
add_subdirectory(../docs/cpp-api docs/cpp-api)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
|
||||
@@ -52,6 +52,7 @@ macro(SET_INSTALL_SELF_RPATH _target)
|
||||
endmacro()
|
||||
|
||||
function(ifcopenshell_plugin_target TARGET)
|
||||
# Plug-ins are loaded by exact filename and should not receive a platform library prefix.
|
||||
set_target_properties(${TARGET} PROPERTIES PREFIX "")
|
||||
if((NOT WIN32) AND BUILD_SHARED_LIBS AND NOT WASM_BUILD AND NOT CREATE_BUNDLE AND NOT CMAKE_INSTALL_RPATH AND COMMAND SET_INSTALL_SELF_RPATH)
|
||||
SET_INSTALL_SELF_RPATH(${TARGET})
|
||||
|
||||
+13
-33
@@ -1,35 +1,15 @@
|
||||
#Look for an executable called sphinx-build
|
||||
find_program(SPHINX_EXECUTABLE NAMES sphinx-build DOC "Path to sphinx-build executable")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
#Handle standard arguments to find_package like REQUIRED and QUIET
|
||||
find_package_handle_standard_args(Sphinx "Failed to find sphinx-build executable" SPHINX_EXECUTABLE)
|
||||
|
||||
find_package(Doxygen REQUIRED)
|
||||
#find_package(Sphinx REQUIRED)
|
||||
find_program(
|
||||
SPHINX_EXECUTABLE
|
||||
NAMES sphinx-build
|
||||
REQUIRED
|
||||
DOC "Path to the sphinx-build executable"
|
||||
)
|
||||
|
||||
set(SPHINX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(SPHINX_BUILD ${CMAKE_CURRENT_BINARY_DIR}/docs/sphinx)
|
||||
|
||||
message(STATUS "SPHINX BUILD ${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
file(MAKE_DIRECTORY ./output/doxygen)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
add_custom_target(
|
||||
Sphinx
|
||||
ALL
|
||||
COMMAND ${SPHINX_EXECUTABLE} -v -T -b html ${SPHINX_SOURCE} ${CMAKE_CURRENT_SOURCE_DIR}/output
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/output
|
||||
COMMENT "Generating documentation with Sphinx"
|
||||
)
|
||||
|
||||
# add_custom_target(ifcopenshell_python_docs ALL
|
||||
# COMMAND make html
|
||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcblenderexport/docs
|
||||
# OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/../src/ifcblenderexport/docs
|
||||
# COMMENT "Generating documentation with Sphinx")
|
||||
else(DOXYGEN_FOUND)
|
||||
message("Doxygen need to be installed to generate the doxygen documentation")
|
||||
endif(DOXYGEN_FOUND)
|
||||
add_custom_target(
|
||||
cpp_api_docs
|
||||
COMMAND ${SPHINX_EXECUTABLE} -M html . output -W --keep-going
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Generating the IfcOpenShell C++ API documentation"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
+63
-22
@@ -68,7 +68,7 @@ PROJECT_LOGO =
|
||||
# entered, it will be relative to the location where doxygen was started. If
|
||||
# left blank the current directory will be used.
|
||||
|
||||
OUTPUT_DIRECTORY = ./output
|
||||
OUTPUT_DIRECTORY = ./output/doxygen
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
|
||||
# sub-directories (in 2 levels) under the output directory of each output format
|
||||
@@ -852,7 +852,7 @@ WARNINGS = YES
|
||||
# will automatically be disabled.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
|
||||
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
|
||||
# potential errors in the documentation, such as documenting some parameters in
|
||||
@@ -901,7 +901,7 @@ WARN_IF_UNDOC_ENUM_VAL = NO
|
||||
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_AS_ERROR = FAIL_ON_WARNINGS
|
||||
|
||||
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
|
||||
# can produce. The string should contain the $file, $line, and $text tags, which
|
||||
@@ -944,7 +944,6 @@ WARN_LOGFILE =
|
||||
# Note: If this tag is empty the current directory is searched.
|
||||
|
||||
INPUT = ../../src/ifcgeom \
|
||||
../../src/ifcgeom_schema_agnostic \
|
||||
../../src/ifcparse \
|
||||
../../src/serializers \
|
||||
|
||||
@@ -1001,7 +1000,7 @@ RECURSIVE = YES
|
||||
# Note that relative paths are relative to the directory from which doxygen is
|
||||
# run.
|
||||
|
||||
EXCLUDE =
|
||||
EXCLUDE = ../../src/ifcparse/schemas
|
||||
|
||||
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
|
||||
# directories that are symbolic links (a Unix file system feature) are excluded
|
||||
@@ -1025,7 +1024,33 @@ EXCLUDE_PATTERNS =
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXCLUDE_SYMBOLS = "ifcopenshell::geom::opaque_number::*" \
|
||||
ifcopenshell::entity::attribute_by_name_cmp \
|
||||
ifcopenshell::impl::rocks_db_file_storage::rocksdb_types_iterator \
|
||||
ifcopenshell::impl::in_memory_file_storage::type_iterator \
|
||||
"util::string_buffer::*_item" \
|
||||
util::string_buffer::item \
|
||||
ifcopenshell::geom::layer_filter::wildcards_match \
|
||||
ifcopenshell::paged_file_impl::entry \
|
||||
ifcopenshell::token \
|
||||
attribute_value::pointer_type \
|
||||
INCLUDE_PARENT_PARENT_DIR \
|
||||
POSTFIX_SCHEMA_ \
|
||||
POSTFIX_SCHEMA__ \
|
||||
STRINGIFY_ \
|
||||
MAKE_INIT_FN_ \
|
||||
MAKE_INIT_FN__ \
|
||||
key_from_string \
|
||||
add_ \
|
||||
subtract_ \
|
||||
multiply_ \
|
||||
divide_ \
|
||||
equals_ \
|
||||
less_than_ \
|
||||
negate_ \
|
||||
ifcopenshell::geom::utils::create_cube \
|
||||
ifcopenshell::geom::utils::create_polyhedron \
|
||||
ifcopenshell::geom::utils::create_nef_polyhedron
|
||||
|
||||
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
|
||||
# that contain example code fragments that are included (see the \include
|
||||
@@ -1236,7 +1261,7 @@ IGNORE_PREFIX =
|
||||
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
|
||||
# The default value is: YES.
|
||||
|
||||
GENERATE_HTML = YES
|
||||
GENERATE_HTML = NO
|
||||
|
||||
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
|
||||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
|
||||
@@ -1311,7 +1336,7 @@ HTML_STYLESHEET =
|
||||
# documentation.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_EXTRA_STYLESHEET = assets/doxygen-awesome-css/doxygen-awesome.css
|
||||
HTML_EXTRA_STYLESHEET =
|
||||
|
||||
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
|
||||
# other source files which should be copied to the HTML output directory. Note
|
||||
@@ -2166,7 +2191,7 @@ MAN_LINKS = NO
|
||||
# captures the structure of the code including all documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_XML = NO
|
||||
GENERATE_XML = YES
|
||||
|
||||
# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
|
||||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
|
||||
@@ -2303,7 +2328,7 @@ ENABLE_PREPROCESSING = YES
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
MACRO_EXPANSION = YES
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
|
||||
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||
@@ -2311,7 +2336,7 @@ MACRO_EXPANSION = NO
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
|
||||
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
|
||||
# INCLUDE_PATH will be searched if a #include is found.
|
||||
@@ -2344,7 +2369,17 @@ INCLUDE_FILE_PATTERNS =
|
||||
# recursively expanded use the := operator instead of the = operator.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
PREDEFINED =
|
||||
PREDEFINED = IFC_PARSE_API= \
|
||||
IFC_SCHEMA_API= \
|
||||
IFC_GEOM_API= \
|
||||
IFC_GEOMLIBRARY_API= \
|
||||
IFC_GEOMSERIALIZATION_API= \
|
||||
SERIALIZERS_API= \
|
||||
"POSTFIX_SCHEMA(name)=name##_Schema" \
|
||||
"Handle(name):=opencascade::handle<name>" \
|
||||
kernel_=kernel \
|
||||
Simplekernel_=Simplekernel \
|
||||
inline=
|
||||
|
||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||
# tag can be used to specify a list of macro names that should be expanded. The
|
||||
@@ -2353,7 +2388,22 @@ PREDEFINED =
|
||||
# definition found in the source code.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
EXPAND_AS_DEFINED =
|
||||
EXPAND_AS_DEFINED = kernel_ \
|
||||
cgal_shape \
|
||||
cgal_kernel \
|
||||
cgal_placement \
|
||||
cgal_point \
|
||||
cgal_direction \
|
||||
cgal_vector \
|
||||
cgal_plane \
|
||||
cgal_curve \
|
||||
cgal_wire \
|
||||
cgal_face \
|
||||
cgal_polyhedron \
|
||||
cgal_vertex_descriptor \
|
||||
cgal_face_descriptor \
|
||||
create_cube \
|
||||
create_polyhedron
|
||||
|
||||
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
|
||||
# remove all references to function-like macros that are alone on a line, have
|
||||
@@ -2731,15 +2781,6 @@ DOT_GRAPH_MAX_NODES = 50
|
||||
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
|
||||
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
|
||||
# files in one run (i.e. multiple -o and -T options on the command line). This
|
||||
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
|
||||
# this, this feature is disabled by default.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_MULTI_TARGETS = NO
|
||||
|
||||
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
|
||||
# explaining the meaning of the various boxes and arrows in the dot generated
|
||||
# graphs.
|
||||
|
||||
+41
-18
@@ -1,33 +1,56 @@
|
||||
# IfcOpenShell C++ API documentation
|
||||
|
||||
This folder contains the setup to build the IfcOpenShell C++ API documentation from the source code.
|
||||
This directory contains the Sphinx, Doxygen, Breathe, and Exhale configuration
|
||||
for the IfcOpenShell C++ API reference. During a Sphinx build, Exhale runs
|
||||
Doxygen, Breathe consumes the generated XML, and Exhale creates the API pages.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10 or newer
|
||||
- [Doxygen](https://www.doxygen.nl/)
|
||||
- [Graphviz](https://graphviz.org/)
|
||||
|
||||
Install the Python dependencies from this directory:
|
||||
|
||||
```shell
|
||||
python -m pip install -r requirements.txt
|
||||
```
|
||||
|
||||
Both `doxygen` and `dot` must be available on `PATH`. For the standard Windows
|
||||
install locations, this can be done for the current PowerShell session with:
|
||||
|
||||
```powershell
|
||||
$env:Path = "C:\Program Files\doxygen\bin;C:\Program Files\Graphviz\bin;$env:Path"
|
||||
```
|
||||
|
||||
## Generating the documentation
|
||||
|
||||
> Prerequisites:
|
||||
>
|
||||
> Make sure to have [Doxygen](https://www.doxygen.nl) and [Graphviz](https://graphviz.org) installed into your `$PATH` variable.
|
||||
>
|
||||
> The documentation also use the [doxygen-awesome](https://jothepro.github.io/doxygen-awesome-css) theme as a git submodule.
|
||||
|
||||
Build with the command (from within the `/docs/cpp-api` folder):
|
||||
From this directory, run:
|
||||
|
||||
```shell
|
||||
$ doxygen
|
||||
python -m sphinx -M html . output -W --keep-going
|
||||
```
|
||||
|
||||
To include the current git commit hash into the build documentation, use the following command:
|
||||
To include the current Git commit in Doxygen's project metadata, set
|
||||
`PROJECT_NUMBER` before building. For example, in PowerShell:
|
||||
|
||||
```powershell
|
||||
$env:PROJECT_NUMBER = git rev-parse --short HEAD
|
||||
python -m sphinx -M html . output -W --keep-going
|
||||
```
|
||||
|
||||
Or in a POSIX shell:
|
||||
|
||||
```shell
|
||||
$ PROJECT_NUMBER=$(git rev-parse --short HEAD) doxygen
|
||||
PROJECT_NUMBER=$(git rev-parse --short HEAD) python -m sphinx -M html . output -W --keep-going
|
||||
```
|
||||
|
||||
This will extract the current commit hash in short version and sets the propper ENV variable used by doxygen.
|
||||
Alternatively, configure the main CMake project with
|
||||
`-DBUILD_DOCUMENTATION=ON` and build the `cpp_api_docs` target.
|
||||
|
||||
The generation of the documentation might take a while depending on your systems hardware, as it is configured to generate the Class graphs using .
|
||||
The generated documentation is written to `output/html/index.html`. The
|
||||
generated Doxygen XML and Exhale sources are kept under `output/` as build
|
||||
artifacts.
|
||||
|
||||
The resulting documentation is located unter `/cpp-api/output/html` and can be directly accessed with your browser:
|
||||
|
||||
```shell
|
||||
$ open ./output/html/index.html
|
||||
```
|
||||
The generated headers under `src/ifcparse/schemas` are intentionally excluded
|
||||
from this documentation build.
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from shutil import rmtree
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx90Warning
|
||||
|
||||
warnings.filterwarnings("ignore", category=RemovedInSphinx90Warning, module=r"exhale\.configs")
|
||||
|
||||
generated_directories = (
|
||||
Path(__file__).parent / "output" / "api",
|
||||
Path(__file__).parent / "output" / "doxygen",
|
||||
)
|
||||
for generated_directory in generated_directories:
|
||||
if generated_directory.is_dir():
|
||||
rmtree(generated_directory)
|
||||
|
||||
project = "IfcOpenShell"
|
||||
copyright = "2020, IfcOpenShell"
|
||||
|
||||
extensions = [
|
||||
"breathe",
|
||||
"exhale",
|
||||
]
|
||||
|
||||
primary_domain = "cpp"
|
||||
highlight_language = "cpp"
|
||||
html_theme = "alabaster"
|
||||
|
||||
breathe_projects = {
|
||||
"IfcOpenShell": "./output/doxygen/xml",
|
||||
}
|
||||
breathe_default_project = "IfcOpenShell"
|
||||
|
||||
exhale_args = {
|
||||
"containmentFolder": "./output/api",
|
||||
"rootFileName": "library_root.rst",
|
||||
"rootFileTitle": "IfcOpenShell C++ API",
|
||||
"doxygenStripFromPath": "../..",
|
||||
"createTreeView": False,
|
||||
"exhaleExecutesDoxygen": True,
|
||||
"exhaleUseDoxyfile": True,
|
||||
}
|
||||
|
||||
cpp_id_attributes = [
|
||||
"IFC_PARSE_API",
|
||||
"IFC_SCHEMA_API",
|
||||
"IFC_GEOM_API",
|
||||
"IFC_GEOMLIBRARY_API",
|
||||
"IFC_GEOMSERIALIZATION_API",
|
||||
"SERIALIZERS_API",
|
||||
]
|
||||
|
||||
exclude_patterns = [
|
||||
"output/doctrees",
|
||||
"output/doxygen",
|
||||
"output/html",
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
.. This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
IfcOpenShell C++ API
|
||||
====================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
output/api/library_root
|
||||
@@ -0,0 +1,5 @@
|
||||
# This file was generated with the assistance of an AI coding tool.
|
||||
|
||||
Sphinx==8.1.3
|
||||
breathe==4.36.0
|
||||
exhale==0.3.7
|
||||
+54
-37
@@ -1,5 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "typing_extensions",
|
||||
# ]
|
||||
# ///
|
||||
###############################################################################
|
||||
# #
|
||||
@@ -32,6 +35,7 @@ Example usage:
|
||||
Available arguments:
|
||||
``-py-313`` - build for specific Python version
|
||||
(building for all supported Python version by default).
|
||||
``-occt-xxx`` - use a specific OCCT version (e.g. ``-occt-7.8.1``) instead of the default
|
||||
``-wasm`` - compile for wasm
|
||||
``-without-xxx`` - do not build dependency ``xxx`` (e.g. ``--without-swig``)
|
||||
``-mac-cross-compile-intel`` - cross compile for Intel Mac on Apple Silicon host
|
||||
@@ -39,6 +43,8 @@ Available arguments:
|
||||
``-ifcopenshell-shared`` - build only IfcOpenShell's own libraries as shared
|
||||
(dependencies stay static). Redundant if ``-shared`` is also passed.
|
||||
``-diskcleanup`` - clean up build directories after finishing building dependencies
|
||||
``-build-examples`` - build IfcOpenShell examples
|
||||
``-lto`` - enable link-time optimization (adds ``-flto`` to compiler flags)
|
||||
``-v`` - enable verbose logs
|
||||
|
||||
|
||||
@@ -131,6 +137,8 @@ from pathlib import Path
|
||||
from typing import Literal
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
from typing_extensions import assert_never
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.INFO)
|
||||
ch = logging.StreamHandler()
|
||||
@@ -217,6 +225,11 @@ def cecho(message, color=NO_COLOR):
|
||||
|
||||
|
||||
# Flags.
|
||||
BUILD_EXAMPLES = "build-examples" in flags
|
||||
DISK_CLEANUP = "diskcleanup" in flags
|
||||
LTO = "lto" in flags
|
||||
VERBOSE = "v" in flags
|
||||
|
||||
APPLE = platform.system() == "Darwin"
|
||||
MAC_CROSS_COMPILE_INTEL = "mac-cross-compile-intel" in flags
|
||||
assert platform.system() == "Darwin" or not MAC_CROSS_COMPILE_INTEL
|
||||
@@ -372,7 +385,7 @@ def gather_dependencies(dep: str) -> Generator[str]:
|
||||
yield x
|
||||
|
||||
|
||||
if "v" in flags:
|
||||
if VERBOSE:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
|
||||
ch.setFormatter(formatter)
|
||||
@@ -432,7 +445,6 @@ if WASM:
|
||||
SKIP_TARGETS_FOR_WASM = {
|
||||
"rocksdb",
|
||||
"opencollada",
|
||||
"swig",
|
||||
"pcre",
|
||||
"IfcGeom",
|
||||
"IfcConvert",
|
||||
@@ -454,12 +466,8 @@ bison = "bison"
|
||||
|
||||
missing_commands: list[str] = []
|
||||
required_commands = [git, bunzip2, tar, cc, cplusplus, autoconf, automake, make, "patch", "cmake", yacc, xz, bison]
|
||||
if "wasm" in flags:
|
||||
# Skip swig build for WASM.
|
||||
required_commands.append("swig")
|
||||
if WASM:
|
||||
required_commands.append("pyodide")
|
||||
required_commands.remove(yacc)
|
||||
required_commands.remove(bison)
|
||||
if platform.system() == "Linux" and "BonsaiViewer" in targets:
|
||||
required_commands.append("patchelf")
|
||||
|
||||
@@ -576,7 +584,7 @@ def run_autoconf(dependency_name: str, configure_args: list[str], cwd: str) -> N
|
||||
prefix = os.path.realpath(f"{DEPS_DIR}/install/{dependency_name}")
|
||||
|
||||
wasm = []
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
wasm.append("emconfigure")
|
||||
|
||||
run(
|
||||
@@ -584,7 +592,7 @@ def run_autoconf(dependency_name: str, configure_args: list[str], cwd: str) -> N
|
||||
*wasm,
|
||||
"/bin/sh",
|
||||
"../configure",
|
||||
*(["--host=wasm32"] if "wasm" in flags and not any(s.startswith("--host") for s in configure_args) else []),
|
||||
*(["--host=wasm32"] if WASM and not any(s.startswith("--host") for s in configure_args) else []),
|
||||
*configure_args,
|
||||
f"--prefix={prefix}",
|
||||
],
|
||||
@@ -592,18 +600,20 @@ def run_autoconf(dependency_name: str, configure_args: list[str], cwd: str) -> N
|
||||
)
|
||||
|
||||
|
||||
def run_cmake(arg1, cmake_args: list[str], cmake_dir: str | None = None, cwd: str | None = None):
|
||||
def run_cmake(
|
||||
name, cmake_args: list[str], cmake_dir: str | None = None, cwd: str | None = None, native: bool = False
|
||||
) -> None:
|
||||
if cmake_dir is None:
|
||||
P = ".."
|
||||
else:
|
||||
P = cmake_dir
|
||||
|
||||
wasm = []
|
||||
if "wasm" in flags:
|
||||
if WASM and not native:
|
||||
wasm.append("emcmake")
|
||||
|
||||
cmake_flags: list[str] = []
|
||||
if not WASM or not WASM_CMAKE_IS_USING_INIT_VARS:
|
||||
if not native and (not WASM or not WASM_CMAKE_IS_USING_INIT_VARS):
|
||||
# For WASM we provide flags using just environment variables.
|
||||
# If we provide them using cmake vars, it will override emscripten toolchain flags.
|
||||
# Unsure if we need this in general even for non-WASM builds.
|
||||
@@ -619,6 +629,10 @@ def run_cmake(arg1, cmake_args: list[str], cmake_dir: str | None = None, cwd: st
|
||||
f"-DBUILD_SHARED_LIBS={OFF_ON[not BUILD_STATIC]}",
|
||||
)
|
||||
|
||||
if WASM and native:
|
||||
# Override emscripten cmake toolchain coming from environment variable.
|
||||
cmake_flags.append("-DCMAKE_TOOLCHAIN_FILE=")
|
||||
|
||||
run(
|
||||
[
|
||||
*wasm,
|
||||
@@ -627,7 +641,7 @@ def run_cmake(arg1, cmake_args: list[str], cmake_dir: str | None = None, cwd: st
|
||||
*cmake_flags,
|
||||
*cmake_args,
|
||||
f"-DCMAKE_BUILD_TYPE={BUILD_CFG}",
|
||||
f"-DCMAKE_SHARED_LINKER_FLAGS={os.environ['LDFLAGS']}",
|
||||
*([] if native else [f"-DCMAKE_SHARED_LINKER_FLAGS={os.environ['LDFLAGS']}"]),
|
||||
],
|
||||
cwd=cwd,
|
||||
)
|
||||
@@ -675,7 +689,7 @@ def build_dependency(
|
||||
additional_files: dict[str, str] | None = None,
|
||||
no_append_name=False,
|
||||
cmake_dir=None,
|
||||
**kwargs,
|
||||
cmake_native: bool = False,
|
||||
) -> None:
|
||||
"""Handles building of dependencies with different tools (which are
|
||||
distinguished with the `mode` argument. `build_tool_args` is expected to be
|
||||
@@ -684,7 +698,8 @@ def build_dependency(
|
||||
|
||||
:param pre_compile_subs: A sequence of ``(fn, before, after)``
|
||||
:param additional_files: Mapping path->url.
|
||||
:param kwargs: Additional ``mode`` related kwargs.
|
||||
:param cmake_native: For ``mode="cmake"``, force a native (host) build
|
||||
even when building for WASM. Needed for build-time tools like swig.
|
||||
"""
|
||||
check_dir = os.path.join(DEPS_DIR, "install", name)
|
||||
if os.path.exists(check_dir):
|
||||
@@ -720,7 +735,7 @@ def build_dependency(
|
||||
logger.info(f"\rChecking {name}... ")
|
||||
git_clone_or_pull_repository(download_url, target_dir=os.path.join(build_dir, download_name), revision=revision)
|
||||
else:
|
||||
raise ValueError(f"download tool '{download_tool}' is not supported")
|
||||
assert_never(download_tool)
|
||||
download_dir = os.path.join(build_dir, download_name)
|
||||
|
||||
if os.path.isdir(download_dir):
|
||||
@@ -781,9 +796,9 @@ def build_dependency(
|
||||
if mode == "autoconf":
|
||||
run_autoconf(name, build_tool_args, cwd=extract_build_dir)
|
||||
elif mode == "cmake":
|
||||
run_cmake(name, build_tool_args, cwd=extract_build_dir)
|
||||
run_cmake(name, build_tool_args, cwd=extract_build_dir, native=cmake_native)
|
||||
else:
|
||||
raise ValueError()
|
||||
assert_never(mode)
|
||||
for fn, before, after in pre_compile_subs:
|
||||
with open(os.path.join(extract_dir, fn), "r") as f:
|
||||
s = f.read()
|
||||
@@ -799,14 +814,14 @@ def build_dependency(
|
||||
logger.info(f"\rConfiguring {name}...")
|
||||
run([bash, "./bootstrap.sh"], cwd=extract_dir)
|
||||
logger.info(f"\rBuilding {name}... ")
|
||||
run(["./b2", f"-j{IFCOS_NUM_BUILD_PROCS}"] + build_tool_args, cwd=extract_dir, can_fail="wasm" in flags)
|
||||
run(["./b2", f"-j{IFCOS_NUM_BUILD_PROCS}"] + build_tool_args, cwd=extract_dir, can_fail=WASM)
|
||||
logger.info(f"\rInstalling {name}... ")
|
||||
shutil.copytree(
|
||||
os.path.join(extract_dir, "boost"), os.path.join(DEPS_DIR, "install", f"boost-{BOOST_VERSION}", "boost")
|
||||
)
|
||||
logger.info(f"\rInstalled {name} \n")
|
||||
|
||||
if "diskcleanup" in flags:
|
||||
if DISK_CLEANUP:
|
||||
shutil.rmtree(build_dir, ignore_errors=True)
|
||||
|
||||
|
||||
@@ -912,7 +927,7 @@ ADDITIONAL_ARGS_STR = " ".join(ADDITIONAL_ARGS)
|
||||
|
||||
CXXFLAGS_MINIMAL = f"{CXXFLAGS} {PIC} {ADDITIONAL_ARGS_STR}"
|
||||
CFLAGS_MINIMAL = f"{CFLAGS} {PIC} {ADDITIONAL_ARGS_STR}"
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
# WASM `SIDE_MODULE_` are absorbed by `emcmake` automatically.
|
||||
CXXFLAGS = CXXFLAGS_MINIMAL
|
||||
CFLAGS = CFLAGS_MINIMAL
|
||||
@@ -933,7 +948,7 @@ else:
|
||||
CFLAGS = CFLAGS_MINIMAL
|
||||
LDFLAGS = f"{LDFLAGS} {ADDITIONAL_ARGS_STR}"
|
||||
|
||||
if "lto" in flags:
|
||||
if LTO:
|
||||
for f in compiler_flags:
|
||||
locals()[f] += f" -flto={IFCOS_NUM_BUILD_PROCS}"
|
||||
|
||||
@@ -1010,6 +1025,7 @@ if "swig" in targets:
|
||||
download_name="swig",
|
||||
download_tool=download_tool_git,
|
||||
revision=f"v{SWIG_VERSION}",
|
||||
cmake_native=WASM,
|
||||
)
|
||||
|
||||
if USE_OCCT and "occ" in targets:
|
||||
@@ -1020,13 +1036,13 @@ if USE_OCCT and "occ" in targets:
|
||||
|
||||
# Skip ExpToCasExe as we don't need it and it requires additional dependencies.
|
||||
# Before 7.7.2 ExpToCasExe is part of DataExchange, DETools doesn't exist yet.
|
||||
# Since we do need DataExchange (used for IgesSerializer), we use a patch to skip only ExpToCasExe.
|
||||
# Since we do need DataExchange (used for iges_serializer), we use a patch to skip only ExpToCasExe.
|
||||
if "7.7.2" > OCCT_VERSION >= "7.7":
|
||||
patches.append("./patches/occt/no_ExpToCasExe.patch")
|
||||
elif OCCT_VERSION >= "7.7.2":
|
||||
occt_args.append("-DBUILD_MODULE_DETools=OFF")
|
||||
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
patches.append("./patches/occt/no_em_js.patch")
|
||||
|
||||
build_dependency(
|
||||
@@ -1110,7 +1126,7 @@ if "libxml2" in targets:
|
||||
"--without-iconv",
|
||||
"--without-lzma",
|
||||
]
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
build_tool_args.append("--without-threads")
|
||||
build_dependency(
|
||||
f"libxml2-{LIBXML2_VERSION}",
|
||||
@@ -1132,7 +1148,7 @@ if "OpenCOLLADA" in targets:
|
||||
# whether shared libs were actually built. We make it follow `USE_SHARED` instead.
|
||||
patches.append("./patches/opencollada/config_select_libs_by_use_shared.patch")
|
||||
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
# This is necessary for the WASM build, because recent versions of
|
||||
# clang don't have the tr1:: namespace anymore. However, it breaks
|
||||
# some versions of gcc (9.4.0 at least) due to specializing std::hash
|
||||
@@ -1162,7 +1178,7 @@ if "OpenCOLLADA" in targets:
|
||||
revision=OPENCOLLADA_VERSION,
|
||||
)
|
||||
|
||||
if "python" in targets and not USE_CURRENT_PYTHON_VERSION and "wasm" not in flags:
|
||||
if "python" in targets and not USE_CURRENT_PYTHON_VERSION and not WASM:
|
||||
# Python should not be built with -fvisibility=hidden, from experience that introduces segfaults
|
||||
OLD_CPP_FLAGS = os.environ["CPPFLAGS"]
|
||||
OLD_CXX_FLAGS = os.environ["CXXFLAGS"]
|
||||
@@ -1223,7 +1239,7 @@ if "python" in targets and not USE_CURRENT_PYTHON_VERSION and "wasm" not in flag
|
||||
if "boost" in targets:
|
||||
str_concat = lambda prefix: lambda postfix: "" if postfix.strip() == "" else "=".join((prefix, postfix.strip()))
|
||||
toolset = []
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
toolset.append("toolset=emscripten")
|
||||
build_dependency(
|
||||
f"boost-{BOOST_VERSION}",
|
||||
@@ -1251,7 +1267,7 @@ if "boost" in targets:
|
||||
# patch="./patches/boost/boostorg_regex_62.patch",
|
||||
download_name=f"boost-{BOOST_VERSION}-b2-nodocs.tar.gz",
|
||||
)
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
# only supported on nix for now
|
||||
run(
|
||||
("find", ".", "-name", "*.bc", "-exec", "bash", "-c", "emar q ${1%.bc}.a $1", "bash", "{}", ";"),
|
||||
@@ -1293,9 +1309,7 @@ if "cgal" in targets:
|
||||
name=f"gmp-{GMP_VERSION}",
|
||||
mode="autoconf",
|
||||
build_tool_args=[ENABLE_FLAG, DISABLE_FLAG, "--with-pic", *gmp_args],
|
||||
pre_compile_subs=(
|
||||
[("build/config.h", "HAVE_OBSTACK_VPRINTF 1", "HAVE_OBSTACK_VPRINTF 0")] if "wasm" in flags else []
|
||||
),
|
||||
pre_compile_subs=([("build/config.h", "HAVE_OBSTACK_VPRINTF 1", "HAVE_OBSTACK_VPRINTF 0")] if WASM else []),
|
||||
patch=gmp_patches,
|
||||
# Sometimes ftp.gnu.org is very slow, use ftpmirror.gnu.org as a workaround.
|
||||
download_url="https://ftpmirror.gnu.org/gnu/gmp/",
|
||||
@@ -1427,7 +1441,7 @@ os.makedirs(ifcos_build_dir, exist_ok=True)
|
||||
|
||||
cmake_args = [
|
||||
"-DUSE_MMAP=OFF",
|
||||
"-DBUILD_EXAMPLES=OFF",
|
||||
f"-DBUILD_EXAMPLES={OFF_ON[BUILD_EXAMPLES]}",
|
||||
"-DBUILD_SHARED_LIBS=" + OFF_ON[not IFCOPENSHELL_STATIC],
|
||||
"-DGLTF_SUPPORT=ON",
|
||||
"-DBoost_NO_BOOST_CMAKE=On",
|
||||
@@ -1457,7 +1471,7 @@ def get_cmake_args_prefix_path(additional_paths: Sequence[str] = ()) -> list[str
|
||||
return [f"-DCMAKE_PREFIX_PATH={prefix_path}"]
|
||||
|
||||
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
# Boost is built by the build script so should not be found
|
||||
# inside of the sysroot set by the emscriptem toolchain
|
||||
cmake_args.append("-DWASM_BUILD=On")
|
||||
@@ -1523,7 +1537,10 @@ if "rocksdb" in targets:
|
||||
)
|
||||
|
||||
if "swig" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/swig-{SWIG_VERSION}")
|
||||
# `cmake_args_prefix_path` won't work on wasm
|
||||
# because `find_program` in emscripten toolchain don't use `find_root_path`.
|
||||
# As a workaround we provide executable path directly on all platforms.
|
||||
cmake_args.append(f"-DSWIG_EXECUTABLE={DEPS_DIR}/install/swig-{SWIG_VERSION}/bin/swig")
|
||||
|
||||
if os.environ.get("QT_DIR"):
|
||||
cmake_args_prefix_path.append(os.environ["QT_DIR"])
|
||||
@@ -1635,7 +1652,7 @@ if "IfcOpenShell-Python" in targets:
|
||||
if platform.system() != "Darwin":
|
||||
if BUILD_CFG == "Release":
|
||||
for so in glob.glob(os.path.join(module_dir, "*.so")):
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
run(["wasm-strip", so, "-k", "dylink.0"])
|
||||
elif os.path.basename(so).startswith("_ifcopenshell_wrapper"):
|
||||
# TODO: This symbol name depends on the Python version?
|
||||
@@ -1645,7 +1662,7 @@ if "IfcOpenShell-Python" in targets:
|
||||
|
||||
return module_dir
|
||||
|
||||
if "wasm" in flags:
|
||||
if WASM:
|
||||
compile_python_wrapper(
|
||||
run(["pyodide", "config", "get", "python_version"]),
|
||||
run(["pyodide", "config", "get", "python_include_dir"]),
|
||||
|
||||
+5
-2
@@ -28,8 +28,11 @@ since it's pure cmake without any additional moving parts.
|
||||
- clone IfcOpenShell repo next to it to `IfcOpenShell` folder
|
||||
- run `python nix/build-all.py -wasm -py-313` in `IfcOpenShell`
|
||||
- it will produce Python package in `IfcOpenShell/ifcopenshell`
|
||||
- run `pyodide build`
|
||||
- it will produce a wheel in `IfcOpenShell/dist`
|
||||
- run `python pyodide/build-all-pack-wheel-local.py`, it will
|
||||
- clean up previous wheels
|
||||
- run `pyodide build`
|
||||
- prepare standalone and modular wheels
|
||||
- produce final wheels in `IfcOpenShell/dist` and `IfcOpenshell/dist-modular`
|
||||
- testing:
|
||||
- ensure you're in pyodide environment
|
||||
- `cd IfcOpenshell/pyodide`
|
||||
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Intended to be run after nix/build-all.py has finished the wasm build."""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_repo_root() -> Path:
|
||||
output = subprocess.check_output(["git", "rev-parse", "--show-toplevel"], text=True)
|
||||
return Path(output.strip())
|
||||
|
||||
|
||||
def run(cmd: list[str], **kwargs) -> None:
|
||||
print("$", " ".join(cmd))
|
||||
subprocess.check_call(cmd, **kwargs)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
repo_root = get_repo_root()
|
||||
|
||||
shutil.rmtree(repo_root / "dist", ignore_errors=True)
|
||||
shutil.rmtree(repo_root / "dist_modular", ignore_errors=True)
|
||||
run(["pyodide", "build"], cwd=repo_root)
|
||||
shutil.rmtree(repo_root / "ifcopenshell", ignore_errors=True)
|
||||
(repo_root / "setup.py").unlink(missing_ok=True)
|
||||
run(["git", "restore", "pyproject.toml"], cwd=repo_root)
|
||||
|
||||
wheel = next((repo_root / "dist").glob("ifcopenshell-*.whl"))
|
||||
|
||||
run(["uv", "run", "pyodide/order_pyodide_wheel_shared_objects.py", str(wheel)], cwd=repo_root)
|
||||
run(
|
||||
["uv", "run", "pyodide/split_pyodide_ifcopenshell_wheel.py", str(wheel), "dist-modular/"],
|
||||
cwd=repo_root,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,10 +1,8 @@
|
||||
#!/usr/bin/bash
|
||||
set -ex
|
||||
|
||||
PYODIDE_VERSION=0.29.3
|
||||
PYODIDE_BUILD_VERSION=0.33.0
|
||||
PYODIDE_XBUILDENV_ROOT="${HOME}/.cache/.pyodide-xbuildenv-${PYODIDE_BUILD_VERSION}"
|
||||
PYODIDE_XBUILDENV="${PYODIDE_XBUILDENV_ROOT}/${PYODIDE_VERSION}"
|
||||
PYODIDE_VERSION=0.29.4
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
|
||||
# Script is assuming that it will be possible to execute it multiple times
|
||||
# therefore we're clearing venv each time and ignoring existing 'emsdk' folder.
|
||||
@@ -16,12 +14,14 @@ source .venv/bin/activate
|
||||
|
||||
# Install pyodide cross build environment.
|
||||
# Instructions: https://pyodide.org/en/stable/development/building-packages.html
|
||||
uv pip install "pyodide-build==${PYODIDE_BUILD_VERSION}"
|
||||
uv pip install -r "${SCRIPT_DIR}/requirements.txt"
|
||||
# `uv run` is required, so xbuildenv would skip using `pip`.
|
||||
uv run pyodide xbuildenv install "${PYODIDE_VERSION}"
|
||||
uv run pyodide xbuildenv install-emscripten
|
||||
|
||||
EMSDK_ROOT="${PYODIDE_XBUILDENV}/emsdk"
|
||||
# Cache path includes a hash segment that varies by pyodide-build version,
|
||||
# so query it instead of constructing it manually.
|
||||
EMSDK_ROOT=$(uv run pyodide config get emsdk_dir)
|
||||
[ -f "${EMSDK_ROOT}/emsdk_env.sh" ] && source "${EMSDK_ROOT}/emsdk_env.sh"
|
||||
[ -f "${EMSDK_ROOT}/../../emsdk_env.sh" ] && source "${EMSDK_ROOT}/../../emsdk_env.sh"
|
||||
which emcc
|
||||
@@ -29,8 +29,10 @@ emcc --version
|
||||
|
||||
mkdir -p packages/ifcopenshell
|
||||
VERSION=`cat IfcOpenShell/VERSION`
|
||||
# Normalize to the canonical PEP 440 form (e.g. 0.9.0alpha0 -> 0.9.0a0).
|
||||
VERSION=`python3 -c "from packaging.version import Version; print(Version('$VERSION'))"`
|
||||
cp IfcOpenShell/pyodide/meta.yaml packages/ifcopenshell
|
||||
sed -i s/0.8.0/$VERSION/g packages/ifcopenshell/meta.yaml
|
||||
sed -i s/9.9.9/$VERSION/g packages/ifcopenshell/meta.yaml
|
||||
|
||||
# Use custom build ifcopenshell directory in build-all to make caching simpler
|
||||
# Otherwise pyodide build path typically includes package version, so cached cmake configs might break.
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
package:
|
||||
name: ifcopenshell
|
||||
version: 0.8.0
|
||||
# Placeholder, replaced by build_pyodide.sh with the actual version from VERSION file.
|
||||
version: 9.9.9
|
||||
|
||||
source:
|
||||
# meta.yaml is placed as `packages/ifcopenshell/meta.yaml`.
|
||||
|
||||
@@ -34,10 +34,10 @@ SCHEMA_ORDER = {
|
||||
}
|
||||
|
||||
MAIN_SHARED_OBJECT_RE = re.compile(r"^_ifcopenshell_wrapper(?:\.|$)")
|
||||
SCHEMA_PLUGIN_RE = re.compile(r"^ifcopenshell\.parse\.schema\.([^.]+)\.so$")
|
||||
MAPPING_PLUGIN_RE = re.compile(r"^ifcopenshell\.geometry\.mapping\.([^.]+)\.so$")
|
||||
DOCUMENT_PLUGIN_RE = re.compile(r"^ifcopenshell\.document\.[^.]+\.([^.]+)\.so$")
|
||||
GEOMETRY_SERIALIZATION_PLUGIN_RE = re.compile(r"^ifcopenshell\.geometry\.serialization\.([^.]+)\.so$")
|
||||
SCHEMA_PLUGIN_RE = re.compile(r"^ifcopenshell_parse_schema_(.+)\.so$")
|
||||
MAPPING_PLUGIN_RE = re.compile(r"^ifcopenshell_geometry_mapping_(.+)\.so$")
|
||||
DOCUMENT_PLUGIN_RE = re.compile(r"^ifcopenshell_document_[a-z0-9]+(?:_(.+))?\.so$")
|
||||
GEOMETRY_SERIALIZATION_PLUGIN_RE = re.compile(r"^ifcopenshell_geometry_writer_(.+)\.so$")
|
||||
|
||||
|
||||
def schema_key(schema: str) -> tuple[int, str]:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pyodide-build==0.39.0
|
||||
+33
-15
@@ -6,11 +6,6 @@ version = "0.0.0"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
include = '''
|
||||
src/.*.pyi?$
|
||||
|nix/.*.pyi?$
|
||||
|pyodide/.*.pyi?$
|
||||
'''
|
||||
extend-exclude = '''
|
||||
src/ifcopenshell-python/ifcopenshell/express/rules/*
|
||||
|src/ifcopenshell-python/ifcopenshell/express/express_parser.py
|
||||
@@ -19,6 +14,15 @@ extend-exclude = '''
|
||||
|src/ifc2ca/templates/*
|
||||
|src/svgfill
|
||||
|src/exterior-shell-extractor
|
||||
|choco/bonsai/tools/enable_blenderbim_addon.py
|
||||
|choco/bonsai/tools/disable_blenderbim_addon.py
|
||||
|docs/conf.py
|
||||
|docs/generate_docs.py
|
||||
|aws/lambda/example_handler/__init__.py
|
||||
|conda/update_version_init.py
|
||||
|test/bpy.py
|
||||
|test/tests.py
|
||||
|test/run.py
|
||||
'''
|
||||
|
||||
[tool.pyright]
|
||||
@@ -63,20 +67,30 @@ select = [
|
||||
#
|
||||
"FA", # future annotations
|
||||
"UP", # pyupgrade
|
||||
"RUF015", # next() > list_comprehension[0]
|
||||
"RUF022", # sort __all__
|
||||
"unnecessary-iterable-allocation-for-first-element",
|
||||
"unsorted-dunder-all",
|
||||
"I", # import sorting
|
||||
"unused-noqa",
|
||||
"rule-codes-in-selectors",
|
||||
"noqa-comments",
|
||||
"rule-codes-in-suppression-comments",
|
||||
# General util rules.
|
||||
"invalid-rule-code",
|
||||
"redirected-noqa",
|
||||
"invalid-pyproject-toml",
|
||||
"invalid-suppression-comment",
|
||||
]
|
||||
ignore = [
|
||||
"FA100", # Conflicts with Blender using annotations for props definitions.
|
||||
# Conflicts with Blender using annotations for props definitions.
|
||||
"future-rewritable-type-annotation",
|
||||
# Maybe will enable later:
|
||||
"UP007", # Union[X,Y] to X | Y
|
||||
"UP045", # Optional to X | None
|
||||
"UP015", # Unnecessary mode argument
|
||||
"UP028", # yield for -> yield from
|
||||
"UP030", # implicit references for positional format fields
|
||||
"UP031", # Replace % with .format
|
||||
"UP032", # Replace .format with f-string
|
||||
"non-pep604-annotation-union", # Union[X,Y] to X | Y
|
||||
"non-pep604-annotation-optional", # Optional to X | None
|
||||
"redundant-open-modes", # Unnecessary mode argument
|
||||
"yield-in-for-loop", # yield for -> yield from
|
||||
"format-literals", # implicit references for positional format fields
|
||||
"printf-string-formatting", # Replace % with .format
|
||||
"f-string", # Replace .format with f-string
|
||||
]
|
||||
|
||||
[tool.ty.rules]
|
||||
@@ -102,7 +116,9 @@ invalid-assignment = "ignore"
|
||||
invalid-parameter-default = "ignore"
|
||||
missing-override-decorator = "ignore"
|
||||
invalid-yield = "ignore"
|
||||
unsound-yield = "ignore"
|
||||
invalid-return-type = "ignore"
|
||||
unsound-return-statement = "ignore"
|
||||
non-callable-init-subclass = "ignore"
|
||||
not-iterable = "ignore"
|
||||
possibly-missing-attribute = "ignore"
|
||||
@@ -171,6 +187,8 @@ dev-setup.help = "Install repo packages in editable mode"
|
||||
|
||||
ruff = "ruff check"
|
||||
|
||||
check-whitespace = "uv run .github/scripts/check-whitespace.py"
|
||||
|
||||
black = "black ."
|
||||
|
||||
ty.sequence = ["ty-bonsai", "ty-ios"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
black==26.3.1
|
||||
ruff==0.16.0
|
||||
poethepoet
|
||||
ty==0.0.63
|
||||
ty==0.0.72
|
||||
gersemi==0.28.0
|
||||
|
||||
@@ -10,7 +10,7 @@ name = "bcf-client"
|
||||
# author = "IfcOpenShell"
|
||||
description = "BCF-XML file handler."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.8"
|
||||
requires-python = ">=3.10"
|
||||
keywords = ["IFC", "BCF", "BIM"]
|
||||
dependencies = [
|
||||
"xsdata>=24.4",
|
||||
@@ -65,6 +65,6 @@ commands = pytest --cov --cov-report=term tests
|
||||
|
||||
[tool.ruff]
|
||||
extend = "../../pyproject.toml"
|
||||
lint.select = [
|
||||
"F401", # unused imports
|
||||
lint.extend-select = [
|
||||
"unused-import", # unused imports
|
||||
]
|
||||
|
||||
+13
-11
@@ -42,10 +42,12 @@ endif
|
||||
|
||||
IS_STABLE:=FALSE
|
||||
VERSION:=$(shell cat ../../VERSION)
|
||||
VERSION_MAJOR:=$(shell cat '../../VERSION' | cut -d '.' -f 1)
|
||||
VERSION_MINOR:=$(shell cat '../../VERSION' | cut -d '.' -f 2)
|
||||
VERSION_PATCH:=$(shell cat '../../VERSION' | cut -d '.' -f 3)
|
||||
VERSION_BASE:=$(shell sed -E 's/[[:alpha:]]+[0-9]+$$//' ../../VERSION)
|
||||
VERSION_PYTHON:=$(shell sed 's/alpha/a/' ../../VERSION)
|
||||
VERSION_SEMVER:=$(shell sed -E 's/([[:alpha:]]+)([0-9]+)$$/-\\1\\2/' ../../VERSION)
|
||||
VERSION_DATE:=$(shell date '+%y%m%d')
|
||||
VERSION_DAILY:=$(VERSION_BASE)a$(VERSION_DATE)
|
||||
VERSION_SEMVER_DAILY:=$(VERSION_BASE)-alpha$(VERSION_DATE)
|
||||
LAST_COMMIT_HASH:=$(shell git rev-parse HEAD)
|
||||
LAST_COMMIT_DATE:=$(shell git show -s --format=%cI)
|
||||
LAST_GIT_BRANCH:=$(shell git rev-parse --abbrev-ref HEAD)
|
||||
@@ -260,14 +262,14 @@ endif
|
||||
|
||||
cp pyproject.toml build/
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) "s/0.0.0/$(VERSION)/" build/bonsai/blender_manifest.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/pyproject.toml
|
||||
$(SED) "s/0.0.0/$(VERSION_SEMVER)/" build/bonsai/blender_manifest.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_PYTHON)"/' build/pyproject.toml
|
||||
else
|
||||
$(SED) "s/0.0.0/$(VERSION)-alpha$(VERSION_DATE)/" build/bonsai/blender_manifest.toml
|
||||
$(SED) "s/0.0.0/$(VERSION_SEMVER_DAILY)/" build/bonsai/blender_manifest.toml
|
||||
$(SED) "s/8888888/$(LAST_COMMIT_HASH)/" build/bonsai/__init__.py
|
||||
$(SED) "s/9999999/$(LAST_COMMIT_DATE)/" build/bonsai/__init__.py
|
||||
$(SED) "s/7777777/$(LAST_GIT_BRANCH)/" build/bonsai/__init__.py
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)-alpha$(VERSION_DATE)"/' build/pyproject.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_DAILY)"/' build/pyproject.toml
|
||||
endif
|
||||
|
||||
# Blender 5.1+ requires Python 3.13.
|
||||
@@ -279,9 +281,9 @@ endif
|
||||
|
||||
# Provides bonsai Add-on functionality
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/pyproject.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_PYTHON)"/' build/pyproject.toml
|
||||
else
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)a$(VERSION_DATE)"/' build/pyproject.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_DAILY)"/' build/pyproject.toml
|
||||
endif
|
||||
cd build && . env/$(VENV_ACTIVATE) && $(PYTHON) -m build
|
||||
cp build/dist/*.whl build/wheels/
|
||||
@@ -315,9 +317,9 @@ endif
|
||||
rm -rf build/bonsai/libs/
|
||||
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
cd build && zip -r bonsai_$(PYVERSION)-$(VERSION)-$(BLENDER_PLATFORM).zip ./bonsai
|
||||
cd build && zip -r bonsai_$(PYVERSION)-$(VERSION_SEMVER)-$(BLENDER_PLATFORM).zip ./bonsai
|
||||
else
|
||||
cd build && zip -r bonsai_$(PYVERSION)-$(VERSION)-alpha$(VERSION_DATE)-$(BLENDER_PLATFORM).zip ./bonsai
|
||||
cd build && zip -r bonsai_$(PYVERSION)-$(VERSION_SEMVER_DAILY)-$(BLENDER_PLATFORM).zip ./bonsai
|
||||
endif
|
||||
|
||||
mv build/bonsai*.zip dist/
|
||||
|
||||
@@ -185,13 +185,10 @@ class IfcStore:
|
||||
os.makedirs(os.path.dirname(cache_path), exist_ok=True)
|
||||
IfcStore.cache_path = cache_path
|
||||
cache_path = Path(IfcStore.cache_path)
|
||||
cache_settings = ifcopenshell.geom.settings()
|
||||
serializer_settings = ifcopenshell.geom.serializer_settings()
|
||||
settings = ifcopenshell.geom.settings()
|
||||
cache_preexists = cache_path.exists()
|
||||
try:
|
||||
IfcStore.cache = ifcopenshell.geom.serializers.hdf5(
|
||||
IfcStore.cache_path, cache_settings, serializer_settings
|
||||
)
|
||||
IfcStore.cache = ifcopenshell.geom.serializers.hdf5(IfcStore.cache_path, settings)
|
||||
if cache_preexists:
|
||||
print(f"Successfully loaded existing cache: {cache_path.name}.")
|
||||
else:
|
||||
@@ -206,9 +203,7 @@ class IfcStore:
|
||||
|
||||
os.remove(IfcStore.cache_path)
|
||||
try:
|
||||
IfcStore.cache = ifcopenshell.geom.serializers.hdf5(
|
||||
IfcStore.cache_path, cache_settings, serializer_settings
|
||||
)
|
||||
IfcStore.cache = ifcopenshell.geom.serializers.hdf5(IfcStore.cache_path, settings)
|
||||
print("New cache was created.")
|
||||
except Exception as e:
|
||||
print(f"Failed to create a cache: {str(e)}.")
|
||||
|
||||
@@ -740,7 +740,7 @@ class IfcImporter:
|
||||
self.update_progress((percent_average / 100 * progress_range) + start_progress)
|
||||
shape = iterator.get()
|
||||
if shape:
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
assert isinstance(shape, W.triangulation_element)
|
||||
product = self.file.by_id(shape.id)
|
||||
self.create_product(product, shape)
|
||||
results.add(product)
|
||||
@@ -1079,9 +1079,9 @@ class IfcImporter:
|
||||
def create_curve(
|
||||
self,
|
||||
element: ifcopenshell.entity_instance,
|
||||
shape: Union[W.Triangulation, W.TriangulationElement],
|
||||
shape: Union[W.triangulation, W.triangulation_element],
|
||||
) -> bpy.types.Curve:
|
||||
if isinstance(shape, W.TriangulationElement):
|
||||
if isinstance(shape, W.triangulation_element):
|
||||
geometry = shape.geometry
|
||||
else:
|
||||
geometry = shape
|
||||
@@ -1112,11 +1112,11 @@ class IfcImporter:
|
||||
def create_mesh(
|
||||
self,
|
||||
element: ifcopenshell.entity_instance,
|
||||
shape: Union[W.Triangulation, W.TriangulationElement],
|
||||
shape: Union[W.triangulation, W.triangulation_element],
|
||||
cartesian_point_offset: Union[npt.NDArray[np.float64], Literal[False]] = None,
|
||||
) -> Union[bpy.types.Mesh, None]:
|
||||
try:
|
||||
if isinstance(shape, W.TriangulationElement):
|
||||
if isinstance(shape, W.triangulation_element):
|
||||
# shape is ShapeElementType
|
||||
geometry = shape.geometry
|
||||
else:
|
||||
|
||||
@@ -678,7 +678,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
# Identify all potential building elements
|
||||
# TODO: don't select everything, use AABB culling in Blender
|
||||
building_elements = (
|
||||
building_elements = list(
|
||||
tool.Ifc.get().by_type("IfcWall")
|
||||
+ tool.Ifc.get().by_type("IfcSlab")
|
||||
+ tool.Ifc.get().by_type("IfcVirtualElement")
|
||||
@@ -708,7 +708,7 @@ class AddBoundary(bpy.types.Operator, tool.Ifc.Operator):
|
||||
while True:
|
||||
tree.add_element(iterator.get_native())
|
||||
shape = iterator.get()
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
assert isinstance(shape, W.triangulation_element)
|
||||
shapes[shape.id] = {
|
||||
"verts": ifcopenshell.util.shape.get_vertices(shape.geometry),
|
||||
"faces": ifcopenshell.util.shape.get_faces(shape.geometry),
|
||||
|
||||
@@ -348,10 +348,7 @@ class AddClassificationReference(bpy.types.Operator, tool.Ifc.Operator):
|
||||
|
||||
def _execute(self, context):
|
||||
if self.obj_type == "Object":
|
||||
if context.selected_objects:
|
||||
objects = [o.name for o in context.selected_objects]
|
||||
else:
|
||||
objects = [context.active_object.name]
|
||||
objects = [o.name for o in tool.Blender.get_selected_objects()]
|
||||
else:
|
||||
objects = [self.obj]
|
||||
props = tool.Classification.get_classification_props()
|
||||
|
||||
@@ -516,7 +516,7 @@ def _world_segment_to_screen_pixels(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class BIM_GT_box_face_quad(bpy.types.Gizmo): # noqa: N801 — Blender bl_idname convention
|
||||
class BIM_GT_box_face_quad(bpy.types.Gizmo):
|
||||
"""Near-invisible face-quad click target with drag-to-resize modal.
|
||||
|
||||
Geometry: a unit quad in the local XY plane at z=0. The adapter
|
||||
@@ -620,7 +620,7 @@ class BIM_GT_box_face_quad(bpy.types.Gizmo): # noqa: N801 — Blender bl_idname
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class BIM_GT_box_face_outline(bpy.types.Gizmo): # noqa: N801 — Blender bl_idname convention
|
||||
class BIM_GT_box_face_outline(bpy.types.Gizmo):
|
||||
"""Thin non-interactive colored edge outline for one face.
|
||||
|
||||
Drawn as 4 line segments in the face plane. The layout helper
|
||||
|
||||
@@ -160,7 +160,7 @@ def _make_face_set_cb(gz: Any, group: Any, axis: int, is_max: bool):
|
||||
return setter
|
||||
|
||||
|
||||
class OBJECT_GGT_bim_clip_box(bpy.types.GizmoGroup): # noqa: N801 — Blender bl_idname convention
|
||||
class OBJECT_GGT_bim_clip_box(bpy.types.GizmoGroup):
|
||||
"""Face-quad resize handles on the active clip box.
|
||||
|
||||
Renders six near-invisible click-target quads and six colored edge
|
||||
|
||||
@@ -987,7 +987,7 @@ class ExportCostSchedulesToPDF(bpy.types.Operator, ExportHelper):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
try:
|
||||
import typst # noqa: F401
|
||||
import typst # ruff: ignore[unused-import]
|
||||
|
||||
return True
|
||||
except ModuleNotFoundError:
|
||||
|
||||
@@ -313,7 +313,7 @@ class CreateAllShapes(bpy.types.Operator):
|
||||
failures.append(element)
|
||||
print("***** FAILURE *****")
|
||||
if shape:
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
assert isinstance(shape, W.triangulation_element)
|
||||
geom = shape.geometry
|
||||
print(
|
||||
f"Success {time.time() - start:.3f}s "
|
||||
|
||||
@@ -28,7 +28,7 @@ operators via ``target_set_operator``; drag handles inherit modal state
|
||||
from ``GizmoMovable``.
|
||||
"""
|
||||
|
||||
__all__ = [ # noqa: RUF022 (unsorted `__all__`)
|
||||
__all__ = [ # ruff: ignore[unsorted-dunder-all]
|
||||
"GizmoColor",
|
||||
"GizmoAxis",
|
||||
"TextAlignment",
|
||||
@@ -5660,7 +5660,7 @@ class BaseParametricGizmoGroup:
|
||||
"""
|
||||
return 0.0
|
||||
|
||||
def _update_view_dependent_dimensions(self, context: bpy.types.Context, mw: Matrix, props) -> None: # noqa: ARG002
|
||||
def _update_view_dependent_dimensions(self, context: bpy.types.Context, mw: Matrix, props) -> None:
|
||||
"""Update overall_width, overall_height, and lining_offset based on view direction.
|
||||
|
||||
This base implementation handles the common pattern for door/window gizmos.
|
||||
@@ -5837,7 +5837,7 @@ class BaseParametricGizmoGroup:
|
||||
self.update_dimension_gizmos(mw, props)
|
||||
self._refresh_element_specific(context, mw, props)
|
||||
|
||||
def _refresh_element_specific(self, context: bpy.types.Context, mw: "Matrix", props) -> None: # noqa: ARG002
|
||||
def _refresh_element_specific(self, context: bpy.types.Context, mw: "Matrix", props) -> None:
|
||||
"""Override for element-specific refresh logic.
|
||||
|
||||
Called from both refresh() (on state change) and draw_prepare() (per frame),
|
||||
@@ -6344,7 +6344,7 @@ class BaseParametricGizmoGroup:
|
||||
"""
|
||||
return (0.0, 0.0)
|
||||
|
||||
def get_icon_y_offset(self, context: bpy.types.Context, mw: Matrix) -> float: # noqa: ARG002
|
||||
def get_icon_y_offset(self, context: bpy.types.Context, mw: Matrix) -> float:
|
||||
"""Get Y offset for icons based on view direction.
|
||||
|
||||
Uses get_icon_y_extent() to determine how far to offset icons based on
|
||||
@@ -6546,9 +6546,7 @@ class BaseParametricGizmoGroup:
|
||||
|
||||
self._refresh_element_specific(context, mw, props)
|
||||
|
||||
def _update_dimension_gizmo_positions(
|
||||
self, context: bpy.types.Context, mw: "Matrix", props # noqa: ARG002
|
||||
) -> None:
|
||||
def _update_dimension_gizmo_positions(self, context: bpy.types.Context, mw: "Matrix", props) -> None:
|
||||
"""Update dimension gizmo positions based on view direction.
|
||||
|
||||
Override this method in subclasses to implement view-dependent
|
||||
|
||||
@@ -1406,31 +1406,28 @@ class CreateDrawing(bpy.types.Operator):
|
||||
# Backwards compatibility with older ifcopenshell builds that don't expose these keys.
|
||||
pass
|
||||
self.svg_buffer = ifcopenshell.geom.serializers.buffer()
|
||||
self.serialiser_settings = ifcopenshell.geom.serializer_settings()
|
||||
self.serialiser_settings.set("svg-without-storeys", True)
|
||||
self.serialiser_settings.set("svg-write-poly", True)
|
||||
self.serialiser_settings.set("svg-poly", True)
|
||||
self.svg_settings.set("svg-without-storeys", True)
|
||||
self.svg_settings.set("svg-write-poly", True)
|
||||
self.svg_settings.set("svg-poly", True)
|
||||
# Objects with more than these edges are rendered as wireframe instead of HLR for optimisation
|
||||
self.serialiser_settings.set("profile-threshold", 10000)
|
||||
self.serialiser_settings.set("svg-xmlns", True)
|
||||
self.serialiser_settings.set("svg-project", True)
|
||||
self.serialiser_settings.set("auto-elevation", False)
|
||||
self.serialiser_settings.set("auto-section", False)
|
||||
self.serialiser_settings.set("print-space-names", False)
|
||||
self.serialiser_settings.set("print-space-areas", False)
|
||||
self.serialiser_settings.set("door-arcs", False)
|
||||
self.serialiser_settings.set("svg-no-css", True)
|
||||
self.serialiser_settings.set("elevation-ref-guid", self.camera_element.GlobalId)
|
||||
self.serialiser_settings.set("scale", str(self.scale))
|
||||
self.serialiser_settings.set("svg-subtract-before", "always")
|
||||
self.serialiser_settings.set("svg-prefilter", True) # See #3359
|
||||
self.serialiser_settings.set("svg-unify-inputs", True)
|
||||
self.serialiser_settings.set("svg-segment-projection", True)
|
||||
self.svg_settings.set("profile-threshold", 10000)
|
||||
self.svg_settings.set("svg-xmlns", True)
|
||||
self.svg_settings.set("svg-project", True)
|
||||
self.svg_settings.set("auto-elevation", False)
|
||||
self.svg_settings.set("auto-section", False)
|
||||
self.svg_settings.set("print-space-names", False)
|
||||
self.svg_settings.set("print-space-areas", False)
|
||||
self.svg_settings.set("door-arcs", False)
|
||||
self.svg_settings.set("svg-no-css", True)
|
||||
self.svg_settings.set("elevation-ref-guid", self.camera_element.GlobalId)
|
||||
self.svg_settings.set("scale", str(self.scale))
|
||||
self.svg_settings.set("svg-subtract-before", "always")
|
||||
self.svg_settings.set("svg-prefilter", True) # See #3359
|
||||
self.svg_settings.set("svg-unify-inputs", True)
|
||||
self.svg_settings.set("svg-segment-projection", True)
|
||||
if target_view == "REFLECTED_PLAN_VIEW":
|
||||
self.serialiser_settings.set("svg-mirror-y", True)
|
||||
self.serialiser = ifcopenshell.geom.serializers.svg(
|
||||
self.svg_buffer, self.svg_settings, self.serialiser_settings
|
||||
)
|
||||
self.svg_settings.set("svg-mirror-y", True)
|
||||
self.serialiser = ifcopenshell.geom.serializers.svg(self.svg_buffer, self.svg_settings)
|
||||
# tree = ifcopenshell.geom.tree()
|
||||
# This instructs the tree to explode BReps into faces and return
|
||||
# the style of the face when running tree.select_ray()
|
||||
|
||||
@@ -72,11 +72,10 @@ class ExportOBJ(bpy.types.Operator):
|
||||
# Conversion from IFC to OBJ
|
||||
# Settings for obj
|
||||
settings = ifcopenshell.geom.settings()
|
||||
serializer_settings = ifcopenshell.geom.serializer_settings()
|
||||
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.SURFACES_AND_SOLIDS)
|
||||
settings.set("apply-default-materials", True)
|
||||
serializer_settings.set("use-element-guids", True)
|
||||
settings.set("use-element-guids", True)
|
||||
settings.set("use-world-coords", True)
|
||||
|
||||
ifc_file: ifcopenshell.file
|
||||
@@ -90,7 +89,7 @@ class ExportOBJ(bpy.types.Operator):
|
||||
obj_file_path = os.path.join(output_dir, "model.obj")
|
||||
mtl_file_path = os.path.join(output_dir, "model.mtl")
|
||||
|
||||
serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings, serializer_settings)
|
||||
serialiser = ifcopenshell.geom.serializers.obj(obj_file_path, mtl_file_path, settings)
|
||||
serialiser.setFile(ifc_file)
|
||||
serialiser.setUnitNameAndMagnitude("METER", 1.0)
|
||||
serialiser.writeHeader()
|
||||
@@ -107,7 +106,7 @@ class ExportOBJ(bpy.types.Operator):
|
||||
if iterator.initialize():
|
||||
while True:
|
||||
shape = iterator.get()
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
assert isinstance(shape, W.triangulation_element)
|
||||
materials = shape.geometry.materials
|
||||
|
||||
for material in materials:
|
||||
|
||||
@@ -430,7 +430,7 @@ class SverchokData:
|
||||
@classmethod
|
||||
def has_sverchok(cls) -> bool:
|
||||
try:
|
||||
import sverchok # noqa: F401
|
||||
import sverchok # ruff: ignore[unused-import]
|
||||
|
||||
return True
|
||||
except ModuleNotFoundError:
|
||||
|
||||
@@ -560,7 +560,7 @@ class AddDoor(bpy.types.Operator, tool.Ifc.Operator):
|
||||
)
|
||||
update_door_modifier_representation(obj)
|
||||
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]:
|
||||
for obj in tool.Blender.get_selected_objects():
|
||||
if not tool.Blender.Modifier.is_eligible_for_door_modifier(obj):
|
||||
continue
|
||||
@@ -638,7 +638,7 @@ class RemoveDoor(bpy.types.Operator, tool.Ifc.Operator):
|
||||
pset = tool.Pset.get_element_pset(element, "BBIM_Door")
|
||||
ifcopenshell.api.pset.remove_pset(tool.Ifc.get(), product=element, pset=pset)
|
||||
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]:
|
||||
for obj in tool.Blender.get_selected_objects():
|
||||
self.remove_door_on_object(obj)
|
||||
return {"FINISHED"}
|
||||
@@ -683,7 +683,7 @@ class ToggleDoorSwing(bpy.types.Operator, tool.Ifc.Operator):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]:
|
||||
obj = tool.Blender.get_active_object()
|
||||
if not obj:
|
||||
return {"CANCELLED"}
|
||||
@@ -909,9 +909,7 @@ class GizmoDoorEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
setattr(self, f"gizmo_swing_arc_{cfg.name}", main)
|
||||
setattr(self, f"gizmo_swing_arc_{cfg.name}_flip", flip)
|
||||
|
||||
def _refresh_element_specific(
|
||||
self, context: bpy.types.Context, mw: Matrix, props: "BIMDoorProperties" # noqa: ARG002
|
||||
) -> None:
|
||||
def _refresh_element_specific(self, context: bpy.types.Context, mw: Matrix, props: "BIMDoorProperties") -> None:
|
||||
"""Update door-specific swing arc gizmos."""
|
||||
self.update_swing_gizmos(mw, props)
|
||||
|
||||
|
||||
@@ -765,7 +765,7 @@ class GizmoRoofEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
def is_element_type(cls, element: ifcopenshell.entity_instance) -> bool:
|
||||
return tool.Parametric.is_roof(element)
|
||||
|
||||
def _update_dimension_gizmo_positions(self, context: bpy.types.Context, mw, props) -> None: # noqa: ARG002
|
||||
def _update_dimension_gizmo_positions(self, context: bpy.types.Context, mw, props) -> None:
|
||||
"""Anchor every dimension gizmo at the object origin. Each gizmo's
|
||||
declared axis (height/slope along +Z, thickness along -Z) separates
|
||||
them in 3D so they don't visually collide despite sharing a
|
||||
@@ -776,7 +776,7 @@ class GizmoRoofEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
self.set_dimension_gizmo_position("angle", mw, origin, (0, 0, 1))
|
||||
self.set_dimension_gizmo_position("roof_thickness", mw, origin, (0, 0, -1))
|
||||
|
||||
def get_element_height(self, props) -> float: # noqa: ARG002
|
||||
def get_element_height(self, props) -> float:
|
||||
"""Object-local Z of the mesh's topmost vertex, so the pen / validate /
|
||||
cancel / cycle row anchors visibly above sloped or stepped roof
|
||||
bodies rather than at the parametric ``props.height`` which may not
|
||||
|
||||
@@ -405,7 +405,7 @@ class SetStairTreads(bpy.types.Operator):
|
||||
bl_label = "Set Number of Treads"
|
||||
bl_options = {"REGISTER", "UNDO", "INTERNAL"}
|
||||
|
||||
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: # noqa: ARG002
|
||||
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]:
|
||||
obj = context.active_object
|
||||
if not obj:
|
||||
return {"CANCELLED"}
|
||||
@@ -658,9 +658,7 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
self.tread_count_label_gizmo.alpha = 0.8
|
||||
self.tread_count_label_gizmo.target_set_operator("bim.input_stair_treads")
|
||||
|
||||
def _refresh_element_specific(
|
||||
self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties" # noqa: ARG002
|
||||
) -> None:
|
||||
def _refresh_element_specific(self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties") -> None:
|
||||
"""Update stair-specific lock and tread count gizmos. Lock positioning is
|
||||
handled per-frame in the dimension-positioning hook."""
|
||||
self.update_lock_gizmo(props)
|
||||
@@ -707,7 +705,7 @@ class GizmoStairEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
self.update_gizmo_visibility(self.tread_count_label_gizmo, props.is_editing)
|
||||
|
||||
def _update_dimension_gizmo_positions(
|
||||
self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties" # noqa: ARG002
|
||||
self, context: bpy.types.Context, mw: Matrix, props: "BIMStairProperties"
|
||||
) -> None:
|
||||
"""Update dimension gizmo positions based on camera view direction."""
|
||||
viewing_from_negative_y, viewing_from_negative_x = self._frame_view_dir
|
||||
|
||||
@@ -2174,7 +2174,7 @@ class GizmoWallEdition(bpy.types.GizmoGroup, gizmo.BaseParametricGizmoGroup):
|
||||
return (far, near)
|
||||
|
||||
def _update_dimension_gizmo_positions(
|
||||
self, context: bpy.types.Context, mw: Matrix, props: "BIMWallProperties" # noqa: ARG002
|
||||
self, context: bpy.types.Context, mw: Matrix, props: "BIMWallProperties"
|
||||
) -> None:
|
||||
"""Re-position length / height / height_end dimensions to the camera-facing
|
||||
Y-side of the wall every frame. Mirrors the door & stair pattern: when the
|
||||
@@ -2530,7 +2530,7 @@ def _perpendicular_wall_params(
|
||||
return clamped_x, abs(cursor_local_y), side_sign
|
||||
|
||||
|
||||
def _commit_pending_wall_edits_for_selection(context: bpy.types.Context) -> None: # noqa: ARG001
|
||||
def _commit_pending_wall_edits_for_selection(context: bpy.types.Context) -> None:
|
||||
"""Thin wall-scoped alias for ``tool.Parametric.commit_pending_edits_for_selection``.
|
||||
|
||||
Encapsulates the ``names=("wall",)`` filter so the registry name is
|
||||
|
||||
@@ -538,7 +538,7 @@ class RemoveWindow(bpy.types.Operator, tool.Ifc.Operator):
|
||||
bl_label = "Remove Window"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]: # noqa: ARG002
|
||||
def _execute(self, context: bpy.types.Context) -> set[str]:
|
||||
obj = context.active_object
|
||||
assert obj
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
|
||||
@@ -2442,7 +2442,7 @@ class LoadLinkedProject(bpy.types.Operator, ImportHelper):
|
||||
if iterator.initialize():
|
||||
while True: # Main loop.
|
||||
shape = iterator.get()
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
assert isinstance(shape, W.triangulation_element)
|
||||
results.add(self.file.by_id(shape.id))
|
||||
geometry = shape.geometry
|
||||
|
||||
@@ -2518,7 +2518,7 @@ class LoadLinkedProject(bpy.types.Operator, ImportHelper):
|
||||
print("Finished", time.time() - start)
|
||||
return {"FINISHED"}
|
||||
|
||||
def process_occurrence(self, shape: W.TriangulationElement) -> None:
|
||||
def process_occurrence(self, shape: W.triangulation_element) -> None:
|
||||
element = self.file.by_id(shape.id)
|
||||
|
||||
mat = ifcopenshell.util.shape.get_shape_matrix(shape)
|
||||
|
||||
@@ -558,7 +558,7 @@ class IntegerInputDialogMixin:
|
||||
return None
|
||||
return props
|
||||
|
||||
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]: # noqa: ARG002
|
||||
def invoke(self, context: bpy.types.Context, event: bpy.types.Event) -> set[str]:
|
||||
props = self._resolve_props(context)
|
||||
if props is None:
|
||||
return {"CANCELLED"}
|
||||
|
||||
@@ -142,8 +142,35 @@ def assign_material(
|
||||
else:
|
||||
element_material_type = material_type
|
||||
|
||||
ifc.run("material.assign_material", products=[element], type=element_material_type, material=material)
|
||||
assigned_material = material_tool.get_material(element)
|
||||
# TODO: this whole dance is a stopgap and wants rewriting.
|
||||
#
|
||||
# material.assign_material creates material sets with no items in them,
|
||||
# ignoring the material it was handed -- an IfcMaterialLayerSet with no
|
||||
# MaterialLayers is not valid IFC, since the list is mandatory and
|
||||
# [1:?]. So we repair it below, after the fact. Worse, the API rejects a
|
||||
# plain IfcMaterial outright when asked for a usage, which is exactly
|
||||
# what the Object Materials dropdown gives us, so we cannot even pass it
|
||||
# on and have to let the API invent an empty set and then fill it in.
|
||||
#
|
||||
# The fix is for assign_material to build the set around the material it
|
||||
# is given, rather than leaving an invalid one behind for its callers to
|
||||
# patch up. That is a wider change than it looks: add_material_set has
|
||||
# the same behaviour, and the create-empty-then-add-items idiom is
|
||||
# spread through the API's own docstrings, examples and tests. Until
|
||||
# that is untangled, keep the repair here where it is at least visible.
|
||||
|
||||
# Only a usage refuses a plain IfcMaterial; every other type still wants
|
||||
# it, and IfcMaterial and IfcMaterialList cannot be created without it.
|
||||
pass_material = material_tool.is_a_material_set(material) or not element_material_type.endswith("Usage")
|
||||
ifc.run(
|
||||
"material.assign_material",
|
||||
products=[element],
|
||||
type=element_material_type,
|
||||
material=material if pass_material else None,
|
||||
)
|
||||
# A usage points at the set rather than being one, and it is the set
|
||||
# that needs an item adding to it below.
|
||||
assigned_material = material_tool.get_material(element, should_skip_usage=True)
|
||||
assert assigned_material # Type checker.
|
||||
|
||||
if material_tool.is_a_material_set(material):
|
||||
|
||||
@@ -651,7 +651,7 @@ class Material:
|
||||
def get_default_material(cls): pass
|
||||
def get_elements_by_material(cls, material): pass
|
||||
def get_material_attributes(cls): pass
|
||||
def get_material(cls, element, should_inherit: bool = False): pass
|
||||
def get_material(cls, element, should_inherit: bool = False, should_skip_usage: bool = False): pass
|
||||
def get_object_ui_active_material(cls): pass
|
||||
def get_object_ui_material_type(cls): pass
|
||||
def get_style(cls, material): pass
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# along with Bonsai. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Ignore unused imports.
|
||||
# ruff: noqa: F401
|
||||
# ruff: file-ignore[unused-import]
|
||||
|
||||
from bonsai.tool.aggregate import Aggregate
|
||||
from bonsai.tool.array import Array
|
||||
|
||||
@@ -25,6 +25,7 @@ import importlib
|
||||
import math
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -1756,6 +1757,7 @@ class Blender(bonsai.core.tool.Blender):
|
||||
repo_path = repo.working_tree_dir
|
||||
assert repo_path
|
||||
version_ = (Path(repo_path) / "VERSION").read_text().strip()
|
||||
version_ = re.sub(r"[A-Za-z]+\d+$", "", version_)
|
||||
commit_date = bonsai.get_last_commit_date()
|
||||
assert commit_date
|
||||
commit_date = datetime.fromisoformat(commit_date)
|
||||
|
||||
@@ -1187,7 +1187,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
if iterator and iterator.initialize():
|
||||
while True:
|
||||
shape = iterator.get()
|
||||
assert isinstance(shape, W.TriangulationElement)
|
||||
assert isinstance(shape, W.triangulation_element)
|
||||
element = tool.Ifc.get().by_id(shape.id)
|
||||
if obj := tool.Ifc.get_object(element):
|
||||
# It's possible that there will be multiple shapes for the same context,
|
||||
@@ -2179,7 +2179,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
item = tool.Ifc.get().by_id(props.ifc_definition_id)
|
||||
allowed_attributes = [
|
||||
a.name()
|
||||
for a in item.declaration().as_entity.all_attributes()
|
||||
for a in item.declaration.as_entity().all_attributes()
|
||||
if a.type_of_attribute()._is("IfcLengthMeasure")
|
||||
]
|
||||
|
||||
|
||||
@@ -872,7 +872,7 @@ class Loader(bonsai.core.tool.Loader):
|
||||
cls,
|
||||
element: ifcopenshell.entity_instance,
|
||||
representation: ifcopenshell.entity_instance,
|
||||
shape: W.TriangulationElement,
|
||||
shape: W.triangulation_element,
|
||||
) -> bpy.types.Camera:
|
||||
"""Create camera data.
|
||||
|
||||
@@ -1026,7 +1026,7 @@ class Loader(bonsai.core.tool.Loader):
|
||||
@classmethod
|
||||
def convert_geometry_to_mesh(
|
||||
cls,
|
||||
geometry: W.Triangulation,
|
||||
geometry: W.triangulation,
|
||||
mesh: bpy.types.Mesh,
|
||||
verts: Optional[npt.NDArray[np.float64]] = None,
|
||||
*,
|
||||
|
||||
@@ -220,9 +220,14 @@ class Material(bonsai.core.tool.Material):
|
||||
|
||||
@classmethod
|
||||
def get_material(
|
||||
cls, element: ifcopenshell.entity_instance, should_inherit: bool = False
|
||||
cls,
|
||||
element: ifcopenshell.entity_instance,
|
||||
should_inherit: bool = False,
|
||||
should_skip_usage: bool = False,
|
||||
) -> Union[ifcopenshell.entity_instance, None]:
|
||||
return ifcopenshell.util.element.get_material(element, should_inherit=should_inherit)
|
||||
return ifcopenshell.util.element.get_material(
|
||||
element, should_inherit=should_inherit, should_skip_usage=should_skip_usage
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def is_a_material_set(cls, material: ifcopenshell.entity_instance) -> bool:
|
||||
|
||||
@@ -2459,7 +2459,7 @@ class Model(bonsai.core.tool.Model):
|
||||
polygons = {}
|
||||
for curve in curves:
|
||||
geometry = ifcopenshell.geom.create_shape(settings, curve)
|
||||
assert isinstance(geometry, W.Triangulation)
|
||||
assert isinstance(geometry, W.triangulation)
|
||||
v = ifcopenshell.util.shape.get_vertices(geometry, is_2d=True)
|
||||
v = np.round(v, 4) # Round to nearest 0.1mm, otherwise things like circles don't polygonise reliably
|
||||
edges = ifcopenshell.util.shape.get_edges(geometry)
|
||||
|
||||
@@ -53,7 +53,7 @@ class Profile(bonsai.core.tool.Profile):
|
||||
settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS)
|
||||
shape = ifcopenshell.geom.create_shape(settings, profile)
|
||||
|
||||
assert isinstance(shape, W.Triangulation)
|
||||
assert isinstance(shape, W.triangulation)
|
||||
verts = ifcopenshell.util.shape.get_vertices(shape)
|
||||
if verts.size == 0:
|
||||
raise RuntimeError(f"Profile shape has no vertices, it probably is invalid: '{profile}'.")
|
||||
|
||||
@@ -76,6 +76,10 @@ Release
|
||||
Notes:
|
||||
|
||||
- Typically all packages are released at once using the same version schema
|
||||
- ``VERSION`` uses Python/PEP 440-compatible spelling. For example, an alpha
|
||||
release may be ``0.9.0alpha0`` (canonicalized to ``0.9.0a0``); build scripts
|
||||
derive numeric-only and SemVer forms such as ``0.9.0`` and
|
||||
``0.9.0-alpha0`` where required.
|
||||
- The ``README.md`` badges can serve as a visual reference for what versions have been released
|
||||
- Corrective Release (if needed after a standard release):
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ exclude = ["test*"]
|
||||
[tool.ruff]
|
||||
extend = "../../pyproject.toml"
|
||||
lint.extend-select = [
|
||||
"F401", # unused imports
|
||||
"unused-import", # unused imports
|
||||
]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
|
||||
@@ -42,6 +42,7 @@ markers =
|
||||
type
|
||||
unit
|
||||
void
|
||||
wall
|
||||
web
|
||||
|
||||
# Provide plugins explicitly, so it will be possible run tests with PYTEST_DISABLE_PLUGIN_AUTOLOAD.
|
||||
|
||||
@@ -45,10 +45,10 @@ for dep in dependencies:
|
||||
subprocess.check_call(command + [dep])
|
||||
|
||||
try:
|
||||
import pygments # noqa: F401
|
||||
import pytest # noqa: F401
|
||||
import pytest_bdd # noqa: F401
|
||||
import pytest_blender # noqa: F401
|
||||
import pygments # ruff: ignore[unused-import]
|
||||
import pytest # ruff: ignore[unused-import]
|
||||
import pytest_bdd # ruff: ignore[unused-import]
|
||||
import pytest_blender # ruff: ignore[unused-import]
|
||||
|
||||
print("Test dependency installation was successful!")
|
||||
except Exception as e:
|
||||
|
||||
@@ -163,32 +163,29 @@ class Drawer:
|
||||
|
||||
# self.svg_settings.set_deflection_tolerance(0.0001)
|
||||
self.svg_buffer = ifcopenshell.geom.serializers.buffer()
|
||||
self.serialiser_settings = ifcopenshell.geom.serializer_settings()
|
||||
self.serialiser_settings.set("svg-without-storeys", True)
|
||||
self.serialiser_settings.set("svg-write-poly", True)
|
||||
self.serialiser_settings.set("svg-poly", True)
|
||||
self.svg_settings.set("svg-without-storeys", True)
|
||||
self.svg_settings.set("svg-write-poly", True)
|
||||
self.svg_settings.set("svg-poly", True)
|
||||
# Objects with more than these edges are rendered as wireframe instead of HLR for optimisation
|
||||
self.serialiser_settings.set("profile-threshold", 10000)
|
||||
self.serialiser_settings.set("svg-xmlns", True)
|
||||
self.serialiser_settings.set("svg-project", True)
|
||||
self.serialiser_settings.set("auto-elevation", False)
|
||||
self.serialiser_settings.set("auto-section", False)
|
||||
self.serialiser_settings.set("print-space-names", False)
|
||||
self.serialiser_settings.set("print-space-areas", False)
|
||||
self.serialiser_settings.set("door-arcs", False)
|
||||
self.serialiser_settings.set("svg-no-css", True)
|
||||
self.serialiser_settings.set("elevation-ref-guid", self.camera_element.GlobalId)
|
||||
self.serialiser_settings.set("scale", "1/50")
|
||||
self.serialiser_settings.set("svg-subtract-before", "always")
|
||||
self.serialiser_settings.set("svg-prefilter", True) # See #3359
|
||||
# self.serialiser_settings.set("svg-prefilter", False) # See #3359
|
||||
self.serialiser_settings.set("svg-unify-inputs", True)
|
||||
self.serialiser_settings.set("svg-segment-projection", True)
|
||||
self.svg_settings.set("profile-threshold", 10000)
|
||||
self.svg_settings.set("svg-xmlns", True)
|
||||
self.svg_settings.set("svg-project", True)
|
||||
self.svg_settings.set("auto-elevation", False)
|
||||
self.svg_settings.set("auto-section", False)
|
||||
self.svg_settings.set("print-space-names", False)
|
||||
self.svg_settings.set("print-space-areas", False)
|
||||
self.svg_settings.set("door-arcs", False)
|
||||
self.svg_settings.set("svg-no-css", True)
|
||||
self.svg_settings.set("elevation-ref-guid", self.camera_element.GlobalId)
|
||||
self.svg_settings.set("scale", "1/50")
|
||||
self.svg_settings.set("svg-subtract-before", "always")
|
||||
self.svg_settings.set("svg-prefilter", True) # See #3359
|
||||
# self.svg_settings.set("svg-prefilter", False) # See #3359
|
||||
self.svg_settings.set("svg-unify-inputs", True)
|
||||
self.svg_settings.set("svg-segment-projection", True)
|
||||
if target_view == "REFLECTED_PLAN_VIEW":
|
||||
self.serialiser_settings.set("svg-mirror-y", True)
|
||||
self.serialiser = ifcopenshell.geom.serializers.svg(
|
||||
self.svg_buffer, self.svg_settings, self.serialiser_settings
|
||||
)
|
||||
self.svg_settings.set("svg-mirror-y", True)
|
||||
self.serialiser = ifcopenshell.geom.serializers.svg(self.svg_buffer, self.svg_settings)
|
||||
self.serialiser.setFile(ifc)
|
||||
|
||||
|
||||
|
||||
@@ -72,12 +72,12 @@ Scenario: Add classification reference - object
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
When I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')"
|
||||
When I press "bim.add_classification_reference(reference={reference}, obj='IfcWall/Cube', obj_type='Object')"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Change classification level
|
||||
@@ -88,8 +88,8 @@ Scenario: Change classification level
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
@@ -104,8 +104,8 @@ Scenario: Disable editing classification references
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
When I press "bim.disable_editing_classification_references"
|
||||
@@ -119,12 +119,12 @@ Scenario: Enable editing classification reference
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWall/Cube', obj_type='Object')"
|
||||
And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
When I press "bim.enable_editing_classification_reference(reference={reference})"
|
||||
Then nothing happens
|
||||
@@ -137,12 +137,12 @@ Scenario: Disable editing classification reference
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWall/Cube', obj_type='Object')"
|
||||
And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.enable_editing_classification_reference(reference={reference})"
|
||||
When I press "bim.disable_editing_classification_reference"
|
||||
@@ -156,15 +156,15 @@ Scenario: Remove classification reference - object
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWall/Cube', obj_type='Object')"
|
||||
And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.enable_editing_classification_reference(reference={reference})"
|
||||
When I press "bim.remove_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')"
|
||||
When I press "bim.remove_classification_reference(reference={reference}, obj='IfcWall/Cube', obj_type='Object')"
|
||||
Then nothing happens
|
||||
|
||||
Scenario: Edit classification reference
|
||||
@@ -175,12 +175,12 @@ Scenario: Edit classification reference
|
||||
And I press "bim.add_classification"
|
||||
And I add a cube
|
||||
And the object "Cube" is selected
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I set "scene.BIMRootProperties.ifc_product" to "IfcElement"
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.change_classification_level(parent_id={classification})"
|
||||
And the variable "reference" is "{classification_ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWallType/Cube', obj_type='Object')"
|
||||
And I press "bim.add_classification_reference(reference={reference}, obj='IfcWall/Cube', obj_type='Object')"
|
||||
And the variable "reference" is "{ifc}.by_type('IfcClassificationReference')[0].id()"
|
||||
And I press "bim.enable_editing_classification_reference(reference={reference})"
|
||||
When I press "bim.edit_classification_reference"
|
||||
|
||||
@@ -185,6 +185,7 @@ Scenario: Update representation - updating a layered extrusion
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -213,6 +214,7 @@ Scenario: Update representation - updating a profiled extrusion
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -416,6 +418,7 @@ Scenario: Override duplicate move - copying a layered extrusion
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -447,6 +450,7 @@ Scenario: Override duplicate move - copying a profiled extrusion
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
|
||||
@@ -121,6 +121,7 @@ Scenario: Assign material - material layer set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
When I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
Then the object "IfcWallType/Empty" does not have the material "Default"
|
||||
@@ -134,6 +135,7 @@ Scenario: Unassign material - material layer set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
When I press "bim.unassign_material"
|
||||
@@ -155,6 +157,7 @@ Scenario: Unassign material - removing inherited material
|
||||
And I press "bim.assign_class"
|
||||
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
|
||||
@@ -181,6 +184,7 @@ Scenario: Enable editing assigned material - material layer set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
When I press "bim.enable_editing_assigned_material"
|
||||
@@ -200,6 +204,7 @@ Scenario: Disable editing assigned material - material layer set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -220,6 +225,7 @@ Scenario: Edit assigned material - material layer set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -235,6 +241,7 @@ Scenario: Assign material - material profile set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
When I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
Then the object "IfcWallType/Empty" does not have the material "Default"
|
||||
@@ -248,6 +255,7 @@ Scenario: Unassign material - material profile set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
When I press "bim.unassign_material"
|
||||
@@ -267,6 +275,7 @@ Scenario: Enable editing assigned material - material profile set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
When I press "bim.enable_editing_assigned_material"
|
||||
@@ -286,6 +295,7 @@ Scenario: Disable editing assigned material - material profile set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -306,6 +316,7 @@ Scenario: Edit assigned material - material profile set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -454,6 +465,7 @@ Scenario: Add material set layer
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
@@ -477,6 +489,7 @@ Scenario: Remove material set layer
|
||||
And I press "bim.assign_class"
|
||||
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
|
||||
|
||||
@@ -314,6 +314,12 @@ Scenario: Load project elements - auto offset of cartesian points
|
||||
Then the object "IfcBuildingElementProxy/NAME" is at "0,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations - disabled false origin mode
|
||||
# D, G and J have their geometry far from their placement, so each is
|
||||
# shifted onto one of its own verts to keep its precision. Which vert that
|
||||
# is comes from the geometry kernel and has changed before, so these assert
|
||||
# that the origin is on a vert rather than which one, and name verts rather
|
||||
# than origins. In automatic mode the model origin is picked the same way
|
||||
# and everything moves with it, so there they are relative to it.
|
||||
Given an empty Blender session
|
||||
And I press "bim.load_project(filepath='{cwd}/test/files/geolocation.ifc', is_advanced=True)"
|
||||
When I set "scene.BIMProjectProperties.false_origin_mode" to "DISABLED"
|
||||
@@ -326,13 +332,19 @@ Scenario: Load project elements - all georeferencing coordinate situations - dis
|
||||
And the object "IfcActuator/A" is at "7,3,0"
|
||||
And the object "IfcActuator/B" is at "6,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "13,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "13,4,-1" at map coordinates "13000,4000,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "15,2,1" at map coordinates "15000,2000,1000"
|
||||
And the object "IfcActuator/E" is at "6,3,0"
|
||||
And the object "IfcActuator/F" is at "3,3,0"
|
||||
And the object "IfcActuator/G" is at "15,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "15,6,-1" at map coordinates "15000,6000,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "17,4,1" at map coordinates "17000,4000,1000"
|
||||
And the object "IfcActuator/H" is at "9,2,0"
|
||||
And the object "IfcActuator/I" is at "3,3,0"
|
||||
And the object "IfcActuator/J" is at "11,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "11,3,-1" at map coordinates "11000,3000,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "13,1,1" at map coordinates "13000,1000,1000"
|
||||
And the object "IfcActuator/K" is at "10,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations - automatic false origin mode
|
||||
@@ -342,24 +354,27 @@ Scenario: Load project elements - all georeferencing coordinate situations - aut
|
||||
When I set "scene.BIMProjectProperties.distance_limit" to "5"
|
||||
And I press "bim.load_project_elements"
|
||||
Then "scene.BIMGeoreferenceProperties.has_blender_offset" is "True"
|
||||
And "scene.BIMGeoreferenceProperties.model_origin" is "13000.0,4000.0,-1000.0"
|
||||
And "scene.BIMGeoreferenceProperties.blender_offset_x" is "13000.0"
|
||||
And "scene.BIMGeoreferenceProperties.blender_offset_y" is "4000.0"
|
||||
And "scene.BIMGeoreferenceProperties.blender_offset_z" is "-1000.0"
|
||||
And the model origin is on an object vertex
|
||||
And the object "IfcSite/My Site" is at "0,0,0"
|
||||
And the object "IfcBuilding/My Building" is at "0,0,0"
|
||||
And the object "IfcBuildingStorey/My Storey" is at "0,0,0"
|
||||
And the object "IfcActuator/A" is at "-6,-1,1"
|
||||
And the object "IfcActuator/B" is at "-7,-3,1"
|
||||
And the object "IfcActuator/A" is at "7,3,0" relative to the model origin at map coordinates "7000,3000,0"
|
||||
And the object "IfcActuator/B" is at "6,1,0" relative to the model origin at map coordinates "6000,1000,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "0,0,0"
|
||||
And the object "IfcActuator/E" is at "-7,-1,1"
|
||||
And the object "IfcActuator/F" is at "-10,-1,1"
|
||||
And the object "IfcActuator/G" is at "2,2,0"
|
||||
And the object "IfcActuator/H" is at "-4,-2,1"
|
||||
And the object "IfcActuator/I" is at "-10,-1,1"
|
||||
And the object "IfcActuator/J" is at "-2,-1,0"
|
||||
And the object "IfcActuator/K" is at "-3,-4,1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "13,4,-1" relative to the model origin at map coordinates "13000,4000,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "15,2,1" relative to the model origin at map coordinates "15000,2000,1000"
|
||||
And the object "IfcActuator/E" is at "6,3,0" relative to the model origin at map coordinates "6000,3000,0"
|
||||
And the object "IfcActuator/F" is at "3,3,0" relative to the model origin at map coordinates "3000,3000,0"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "15,6,-1" relative to the model origin at map coordinates "15000,6000,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "17,4,1" relative to the model origin at map coordinates "17000,4000,1000"
|
||||
And the object "IfcActuator/H" is at "9,2,0" relative to the model origin at map coordinates "9000,2000,0"
|
||||
And the object "IfcActuator/I" is at "3,3,0" relative to the model origin at map coordinates "3000,3000,0"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "11,3,-1" relative to the model origin at map coordinates "11000,3000,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "13,1,1" relative to the model origin at map coordinates "13000,1000,1000"
|
||||
And the object "IfcActuator/K" is at "10,0,0" relative to the model origin at map coordinates "10000,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations - manual false origin mode
|
||||
Given an empty Blender session
|
||||
@@ -379,23 +394,20 @@ Scenario: Load project elements - all georeferencing coordinate situations - man
|
||||
And the object "IfcActuator/A" is at "-3,3,0"
|
||||
And the object "IfcActuator/B" is at "-4,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "3,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "3,4,-1" at map coordinates "13000,4000,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "5,2,1" at map coordinates "15000,2000,1000"
|
||||
And the object "IfcActuator/E" is at "-4,3,0"
|
||||
And the object "IfcActuator/F" is at "-7,3,0"
|
||||
And the object "IfcActuator/G" is at "5,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "5,6,-1" at map coordinates "15000,6000,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "7,4,1" at map coordinates "17000,4000,1000"
|
||||
And the object "IfcActuator/H" is at "-1,2,0"
|
||||
And the object "IfcActuator/I" is at "-7,3,0"
|
||||
And the object "IfcActuator/J" is at "1,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "1,3,-1" at map coordinates "11000,3000,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "3,1,1" at map coordinates "13000,1000,1000"
|
||||
And the object "IfcActuator/K" is at "0,0,0"
|
||||
And the object "IfcActuator/D" has a cartesian point offset of "31,4,-1"
|
||||
And the object "IfcActuator/G" has a cartesian point offset of "-25,6,-1"
|
||||
And the object "IfcActuator/J" has a cartesian point offset of "11,3,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "3,2,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "5,2,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "5,4,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "7,4,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "1,1,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "3,1,-1"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with an offset site - disabled false origin mode
|
||||
Given an empty Blender session
|
||||
@@ -410,13 +422,19 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "5.985,14.71,0"
|
||||
And the object "IfcActuator/B" is at "5.5367,12.519,0"
|
||||
And the object "IfcActuator/C" is at "0,10,0"
|
||||
And the object "IfcActuator/D" is at "11.522,17.228,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "11.5218,17.2284,-1" at map coordinates "11521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "13.9712,15.8141,1" at map coordinates "13971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "5.0191,14.451,0"
|
||||
And the object "IfcActuator/F" is at "2.1213,13.674,0"
|
||||
And the object "IfcActuator/G" is at "12.936,19.678,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "12.936,19.6778,-1" at map coordinates "12935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "15.3855,18.2636,1" at map coordinates "15385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "8.1757,14.261,0"
|
||||
And the object "IfcActuator/I" is at "2.1213,13.674,0"
|
||||
And the object "IfcActuator/J" is at "9.8487,15.745,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "9.8487,15.7448,-1" at map coordinates "9848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "12.2982,14.3306,1" at map coordinates "12298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "9.6593,12.588,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with an offset site - automatic false origin mode
|
||||
@@ -436,13 +454,19 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "7,3,0"
|
||||
And the object "IfcActuator/B" is at "6,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "13,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "13,4,-1" at map coordinates "11521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "15,2,1" at map coordinates "13971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "6,3,0"
|
||||
And the object "IfcActuator/F" is at "3,3,0"
|
||||
And the object "IfcActuator/G" is at "15,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "15,6,-1" at map coordinates "12935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "17,4,1" at map coordinates "15385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "9,2,0"
|
||||
And the object "IfcActuator/I" is at "3,3,0"
|
||||
And the object "IfcActuator/J" is at "11,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "11,3,-1" at map coordinates "9848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "13,1,1" at map coordinates "12298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "10,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with an offset site - manual false origin mode
|
||||
@@ -463,23 +487,20 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "5.985,4.71,0"
|
||||
And the object "IfcActuator/B" is at "5.5367,2.519,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "11.522,7.228,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "11.5218,7.2284,-1" at map coordinates "11521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "13.9712,5.8141,1" at map coordinates "13971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "5.0191,4.451,0"
|
||||
And the object "IfcActuator/F" is at "2.1213,3.674,0"
|
||||
And the object "IfcActuator/G" is at "12.936,9.678,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "12.936,9.6778,-1" at map coordinates "12935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "15.3855,8.2636,1" at map coordinates "15385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "8.1757,4.261,0"
|
||||
And the object "IfcActuator/I" is at "2.1213,3.674,0"
|
||||
And the object "IfcActuator/J" is at "9.8487,5.745,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "9.8487,5.7448,-1" at map coordinates "9848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "12.2982,4.3306,1" at map coordinates "12298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "9.6593,2.588,0"
|
||||
And the object "IfcActuator/D" has a cartesian point offset of "31,4,-1"
|
||||
And the object "IfcActuator/G" has a cartesian point offset of "-25,6,-1"
|
||||
And the object "IfcActuator/J" has a cartesian point offset of "11,3,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "12.039,5.296,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "13.971,5.814,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "13.454,7.746,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "15.385,8.264,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "10.366,3.813,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "12.298,4.331,-1"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with an offset site - manual false origin mode - with custom project north
|
||||
Given an empty Blender session
|
||||
@@ -500,13 +521,19 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "7,3,0"
|
||||
And the object "IfcActuator/B" is at "6,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "13,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "13,4,-1" at map coordinates "11521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "15,2,1" at map coordinates "13971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "6,3,0"
|
||||
And the object "IfcActuator/F" is at "3,3,0"
|
||||
And the object "IfcActuator/G" is at "15,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "15,6,-1" at map coordinates "12935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "17,4,1" at map coordinates "15385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "9,2,0"
|
||||
And the object "IfcActuator/I" is at "3,3,0"
|
||||
And the object "IfcActuator/J" is at "11,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "11,3,-1" at map coordinates "9848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "13,1,1" at map coordinates "12298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "10,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with a map conversion - disabled false origin mode (this should be identical to the situation with no map conversion)
|
||||
@@ -522,13 +549,19 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "7,3,0"
|
||||
And the object "IfcActuator/B" is at "6,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "13,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "13,4,-1" at map coordinates "28000,4000,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "15,2,1" at map coordinates "30000,2000,1000"
|
||||
And the object "IfcActuator/E" is at "6,3,0"
|
||||
And the object "IfcActuator/F" is at "3,3,0"
|
||||
And the object "IfcActuator/G" is at "15,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "15,6,-1" at map coordinates "30000,6000,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "17,4,1" at map coordinates "32000,4000,1000"
|
||||
And the object "IfcActuator/H" is at "9,2,0"
|
||||
And the object "IfcActuator/I" is at "3,3,0"
|
||||
And the object "IfcActuator/J" is at "11,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "11,3,-1" at map coordinates "26000,3000,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "13,1,1" at map coordinates "28000,1000,1000"
|
||||
And the object "IfcActuator/K" is at "10,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with a map conversion - automatic false origin mode (this should affect the Blender eastings and northings, which is now different to the Blender offset XYZ, but is otherwise identical to the non-map conversion variant)
|
||||
@@ -538,24 +571,27 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
When I set "scene.BIMProjectProperties.distance_limit" to "5"
|
||||
And I press "bim.load_project_elements"
|
||||
Then "scene.BIMGeoreferenceProperties.has_blender_offset" is "True"
|
||||
And "scene.BIMGeoreferenceProperties.model_origin" is "28000.0,4000.0,-1000.0"
|
||||
And "scene.BIMGeoreferenceProperties.blender_offset_x" is "13000.0"
|
||||
And "scene.BIMGeoreferenceProperties.blender_offset_y" is "4000.0"
|
||||
And "scene.BIMGeoreferenceProperties.blender_offset_z" is "-1000.0"
|
||||
And the model origin is on an object vertex
|
||||
And the object "IfcSite/My Site" is at "0,0,0"
|
||||
And the object "IfcBuilding/My Building" is at "0,0,0"
|
||||
And the object "IfcBuildingStorey/My Storey" is at "0,0,0"
|
||||
And the object "IfcActuator/A" is at "-6,-1,1"
|
||||
And the object "IfcActuator/B" is at "-7,-3,1"
|
||||
And the object "IfcActuator/A" is at "22,3,0" relative to the model origin at map coordinates "22000,3000,0"
|
||||
And the object "IfcActuator/B" is at "21,1,0" relative to the model origin at map coordinates "21000,1000,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "0,0,0"
|
||||
And the object "IfcActuator/E" is at "-7,-1,1"
|
||||
And the object "IfcActuator/F" is at "-10,-1,1"
|
||||
And the object "IfcActuator/G" is at "2,2,0"
|
||||
And the object "IfcActuator/H" is at "-4,-2,1"
|
||||
And the object "IfcActuator/I" is at "-10,-1,1"
|
||||
And the object "IfcActuator/J" is at "-2,-1,0"
|
||||
And the object "IfcActuator/K" is at "-3,-4,1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "28,4,-1" relative to the model origin at map coordinates "28000,4000,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "30,2,1" relative to the model origin at map coordinates "30000,2000,1000"
|
||||
And the object "IfcActuator/E" is at "21,3,0" relative to the model origin at map coordinates "21000,3000,0"
|
||||
And the object "IfcActuator/F" is at "18,3,0" relative to the model origin at map coordinates "18000,3000,0"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "30,6,-1" relative to the model origin at map coordinates "30000,6000,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "32,4,1" relative to the model origin at map coordinates "32000,4000,1000"
|
||||
And the object "IfcActuator/H" is at "24,2,0" relative to the model origin at map coordinates "24000,2000,0"
|
||||
And the object "IfcActuator/I" is at "18,3,0" relative to the model origin at map coordinates "18000,3000,0"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "26,3,-1" relative to the model origin at map coordinates "26000,3000,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "28,1,1" relative to the model origin at map coordinates "28000,1000,1000"
|
||||
And the object "IfcActuator/K" is at "25,0,0" relative to the model origin at map coordinates "25000,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with a map conversion - manual false origin mode (this should affect the Blender eastings and northings, which is now different to the Blender offset XYZ, but is otherwise identical to the non-map conversion variant)
|
||||
Given an empty Blender session
|
||||
@@ -575,23 +611,20 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "-3,3,0"
|
||||
And the object "IfcActuator/B" is at "-4,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "3,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "3,4,-1" at map coordinates "28000,4000,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "5,2,1" at map coordinates "30000,2000,1000"
|
||||
And the object "IfcActuator/E" is at "-4,3,0"
|
||||
And the object "IfcActuator/F" is at "-7,3,0"
|
||||
And the object "IfcActuator/G" is at "5,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "5,6,-1" at map coordinates "30000,6000,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "7,4,1" at map coordinates "32000,4000,1000"
|
||||
And the object "IfcActuator/H" is at "-1,2,0"
|
||||
And the object "IfcActuator/I" is at "-7,3,0"
|
||||
And the object "IfcActuator/J" is at "1,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "1,3,-1" at map coordinates "26000,3000,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "3,1,1" at map coordinates "28000,1000,1000"
|
||||
And the object "IfcActuator/K" is at "0,0,0"
|
||||
And the object "IfcActuator/D" has a cartesian point offset of "31,4,-1"
|
||||
And the object "IfcActuator/G" has a cartesian point offset of "-25,6,-1"
|
||||
And the object "IfcActuator/J" has a cartesian point offset of "11,3,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "3,2,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "5,2,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "5,4,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "7,4,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "1,1,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "3,1,-1"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with map conversion and an offset site - disabled false origin mode
|
||||
Given an empty Blender session
|
||||
@@ -606,13 +639,19 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "5.985,14.71,0"
|
||||
And the object "IfcActuator/B" is at "5.5367,12.519,0"
|
||||
And the object "IfcActuator/C" is at "0,10,0"
|
||||
And the object "IfcActuator/D" is at "11.522,17.228,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "11.5218,17.2284,-1" at map coordinates "26521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "13.9712,15.8141,1" at map coordinates "28971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "5.0191,14.451,0"
|
||||
And the object "IfcActuator/F" is at "2.1213,13.674,0"
|
||||
And the object "IfcActuator/G" is at "12.936,19.678,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "12.936,19.6778,-1" at map coordinates "27935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "15.3855,18.2636,1" at map coordinates "30385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "8.1757,14.261,0"
|
||||
And the object "IfcActuator/I" is at "2.1213,13.674,0"
|
||||
And the object "IfcActuator/J" is at "9.8487,15.745,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "9.8487,15.7448,-1" at map coordinates "24848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "12.2982,14.3306,1" at map coordinates "27298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "9.6593,12.588,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with map conversion and an offset site - automatic false origin mode
|
||||
@@ -632,13 +671,19 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "7,3,0"
|
||||
And the object "IfcActuator/B" is at "6,1,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "13,4,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "13,4,-1" at map coordinates "26521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "15,2,1" at map coordinates "28971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "6,3,0"
|
||||
And the object "IfcActuator/F" is at "3,3,0"
|
||||
And the object "IfcActuator/G" is at "15,6,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "15,6,-1" at map coordinates "27935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "17,4,1" at map coordinates "30385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "9,2,0"
|
||||
And the object "IfcActuator/I" is at "3,3,0"
|
||||
And the object "IfcActuator/J" is at "11,3,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "11,3,-1" at map coordinates "24848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "13,1,1" at map coordinates "27298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "10,0,0"
|
||||
|
||||
Scenario: Load project elements - all georeferencing coordinate situations with map conversion and an offset site - manual false origin mode
|
||||
@@ -659,23 +704,20 @@ Scenario: Load project elements - all georeferencing coordinate situations with
|
||||
And the object "IfcActuator/A" is at "5.985,4.71,0"
|
||||
And the object "IfcActuator/B" is at "5.5367,2.519,0"
|
||||
And the object "IfcActuator/C" is at "0,0,0"
|
||||
And the object "IfcActuator/D" is at "11.522,7.228,-1"
|
||||
And the object "IfcActuator/D" has its origin on a vertex
|
||||
And the object "IfcActuator/D" has a vert at "11.5218,7.2284,-1" at map coordinates "26521.758,17228.35,-1000"
|
||||
And the object "IfcActuator/D" has a vert at "13.9712,5.8141,1" at map coordinates "28971.246,15814.136,1000"
|
||||
And the object "IfcActuator/E" is at "5.0191,4.451,0"
|
||||
And the object "IfcActuator/F" is at "2.1213,3.674,0"
|
||||
And the object "IfcActuator/G" is at "12.936,9.678,-1"
|
||||
And the object "IfcActuator/G" has its origin on a vertex
|
||||
And the object "IfcActuator/G" has a vert at "12.936,9.6778,-1" at map coordinates "27935.975,19677.841,-1000"
|
||||
And the object "IfcActuator/G" has a vert at "15.3855,8.2636,1" at map coordinates "30385.465,18263.627,1000"
|
||||
And the object "IfcActuator/H" is at "8.1757,4.261,0"
|
||||
And the object "IfcActuator/I" is at "2.1213,3.674,0"
|
||||
And the object "IfcActuator/J" is at "9.8487,5.745,-1"
|
||||
And the object "IfcActuator/J" has its origin on a vertex
|
||||
And the object "IfcActuator/J" has a vert at "9.8487,5.7448,-1" at map coordinates "24848.726,15744.786,-1000"
|
||||
And the object "IfcActuator/J" has a vert at "12.2982,4.3306,1" at map coordinates "27298.216,14330.573,1000"
|
||||
And the object "IfcActuator/K" is at "9.6593,2.588,0"
|
||||
And the object "IfcActuator/D" has a cartesian point offset of "31,4,-1"
|
||||
And the object "IfcActuator/G" has a cartesian point offset of "-25,6,-1"
|
||||
And the object "IfcActuator/J" has a cartesian point offset of "11,3,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "12.039,5.296,-1"
|
||||
And the object "IfcActuator/D" has a vertex at "13.971,5.814,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "13.454,7.746,-1"
|
||||
And the object "IfcActuator/G" has a vertex at "15.385,8.264,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "10.366,3.813,-1"
|
||||
And the object "IfcActuator/J" has a vertex at "12.298,4.331,-1"
|
||||
|
||||
Scenario: Link IFC - from an empty IFC project
|
||||
Given an empty IFC project
|
||||
|
||||
@@ -81,6 +81,7 @@ Scenario: Assign type - assign to a type with a material layer set, which automa
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
|
||||
@@ -102,6 +103,7 @@ Scenario: Assign type - assign to a type with a material layer set, which automa
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
|
||||
@@ -125,6 +127,7 @@ Scenario: Assign type - assign to a different type with a LAYER2 material layer
|
||||
And I press "bim.assign_class"
|
||||
And the variable "type" is "{ifc}.by_type('IfcWallType')[-1].id()"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
|
||||
And I press "bim.assign_material"
|
||||
And I add an empty
|
||||
@@ -180,6 +183,7 @@ Scenario: Assign type - assign to a type with a material profile set
|
||||
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
|
||||
And I press "bim.assign_class"
|
||||
And I press "bim.add_material()"
|
||||
And the object "IfcWallType/Empty" is selected
|
||||
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
|
||||
And I press "bim.assign_material"
|
||||
And I press "bim.enable_editing_assigned_material"
|
||||
|
||||
@@ -45,14 +45,14 @@ def test_text_formatter_defaults_to_none():
|
||||
|
||||
|
||||
def test_text_formatter_field_stores_callable():
|
||||
formatter = lambda props, value: f"{value:.2f}m" # noqa: E731
|
||||
formatter = lambda props, value: f"{value:.2f}m"
|
||||
config = DimensionGizmoConfig(attr_name="length", axis=(1, 0, 0), text_formatter=formatter)
|
||||
assert config.text_formatter is not None
|
||||
assert callable(config.text_formatter)
|
||||
|
||||
|
||||
def test_text_formatter_receives_props_and_value():
|
||||
formatter = lambda props, value: f"{props.label}={value}" # noqa: E731
|
||||
formatter = lambda props, value: f"{props.label}={value}"
|
||||
config = DimensionGizmoConfig(attr_name="length", axis=(1, 0, 0), text_formatter=formatter)
|
||||
props = SimpleNamespace(label="L")
|
||||
assert config.text_formatter(props, 3.14) == "L=3.14"
|
||||
|
||||
@@ -104,7 +104,7 @@ class TestParametricGizmoPollsHideDuringTransformModal:
|
||||
continue
|
||||
try:
|
||||
result = poll(bpy.context)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc:
|
||||
offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}"))
|
||||
continue
|
||||
if result:
|
||||
|
||||
@@ -98,7 +98,7 @@ class TestWallGizmoGroupsHideDuringPreview:
|
||||
continue
|
||||
try:
|
||||
result = poll(bpy.context)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc:
|
||||
offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}"))
|
||||
continue
|
||||
if result:
|
||||
|
||||
@@ -119,7 +119,7 @@ class TestWallGizmoGroupsHideOnArrayChildSelection:
|
||||
for name, cls in groups:
|
||||
try:
|
||||
result = cls.poll(bpy.context)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc:
|
||||
offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}"))
|
||||
continue
|
||||
if result:
|
||||
@@ -159,7 +159,7 @@ class TestWallOperatorsRejectArrayChildSelection:
|
||||
for name, cls in ops:
|
||||
try:
|
||||
result = cls.poll(bpy.context)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
except Exception as exc:
|
||||
offenders.append((name, f"poll raised: {type(exc).__name__}: {exc}"))
|
||||
continue
|
||||
if result:
|
||||
|
||||
@@ -36,6 +36,7 @@ import bpy
|
||||
import ifcopenshell
|
||||
import ifcopenshell.util.element
|
||||
import ifcopenshell.util.representation
|
||||
import ifcopenshell.util.unit
|
||||
import numpy as np
|
||||
import pytest
|
||||
from mathutils import Vector
|
||||
@@ -1000,6 +1001,7 @@ def i_click_button_and_expect_error_error_msg(button, error_msg):
|
||||
|
||||
@given(parsers.parse('I evaluate expression "{expression}"'))
|
||||
@when(parsers.parse('I evaluate expression "{expression}"'))
|
||||
@then(parsers.parse('I evaluate expression "{expression}"'))
|
||||
def i_evaluate_expression(expression):
|
||||
expression = replace_variables(expression)
|
||||
exec(expression)
|
||||
@@ -1680,6 +1682,111 @@ def the_object_name_has_a_vertex_at_location(name, location):
|
||||
assert is_pass, f"No verts found at {location}: {verts}"
|
||||
|
||||
|
||||
def get_model_origin() -> Vector:
|
||||
"""Where the model was shifted to, in Blender units.
|
||||
|
||||
Geometry far from the origin is moved next to it so it keeps its precision,
|
||||
and the shift is recorded as the model origin. Which vert of which object it
|
||||
lands on is not something to depend on, so anything measured from it stays
|
||||
put even when that choice changes.
|
||||
"""
|
||||
props = bpy.context.scene.BIMGeoreferenceProperties
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(an_ifc_file_exists())
|
||||
return Vector([float(co) for co in props.model_origin.split(",")]) * unit_scale
|
||||
|
||||
|
||||
def get_world_verts(obj: bpy.types.Object) -> list[Vector]:
|
||||
mesh = obj.data
|
||||
assert isinstance(mesh, bpy.types.Mesh) and len(mesh.vertices), f"Object {obj.name} has no mesh"
|
||||
return [obj.matrix_world @ v.co for v in mesh.vertices]
|
||||
|
||||
|
||||
def assert_vert_at_map_coordinates(obj: bpy.types.Object, vert: Vector, coordinates: str) -> None:
|
||||
# Same conversion as the georeferencing calculator, which works in project
|
||||
# units rather than Blender ones.
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(an_ifc_file_exists())
|
||||
enh = Vector(tool.Georeference.xyz2enh(tuple(co / unit_scale for co in vert)))
|
||||
expected = Vector([float(co) for co in coordinates.split(",")])
|
||||
assert (enh - expected).length < 0.05, f"Vert {vert} is at map coordinates {enh[:]} instead of {coordinates}"
|
||||
|
||||
|
||||
@then(
|
||||
parsers.parse(
|
||||
'the object "{name}" is at "{location}" relative to the model origin at map coordinates "{coordinates}"'
|
||||
)
|
||||
)
|
||||
def the_object_name_is_at_location_relative_to_the_model_origin_at_map_coordinates(name, location, coordinates):
|
||||
"""For objects with no geometry to name a vert on.
|
||||
|
||||
The Blender location is only meaningful next to the origin everything was
|
||||
shifted by, since the two move together, but the map coordinates hold still
|
||||
either way.
|
||||
"""
|
||||
obj = the_object_name_exists(name)
|
||||
obj_location = obj.location + get_model_origin()
|
||||
assert (
|
||||
obj_location - Vector([float(co) for co in location.split(",")])
|
||||
).length < 0.05, f"Object is at {obj_location} relative to the model origin instead of {location}"
|
||||
assert_vert_at_map_coordinates(obj, obj.matrix_world.translation, coordinates)
|
||||
|
||||
|
||||
@then(parsers.parse('the object "{name}" has a vert at "{location}" at map coordinates "{coordinates}"'))
|
||||
def the_object_name_has_a_vert_at_location_at_map_coordinates(name, location, coordinates):
|
||||
"""Check where a vert sits in Blender and where it is in the world.
|
||||
|
||||
Both matter: the Blender location is what the user sees, and checking only
|
||||
the map coordinates would pass just as happily if the georeferencing maths
|
||||
or the offsets it reads were wrong, since the same maths produces both.
|
||||
"""
|
||||
obj = the_object_name_exists(name)
|
||||
target = Vector([float(co) for co in location.split(",")])
|
||||
verts = get_world_verts(obj)
|
||||
vert = next((v for v in verts if (v - target).length < 0.001), None)
|
||||
assert vert is not None, f"No vert found at {location}: {verts}"
|
||||
assert_vert_at_map_coordinates(obj, vert, coordinates)
|
||||
|
||||
|
||||
@then(
|
||||
parsers.parse(
|
||||
'the object "{name}" has a vert at "{location}" relative to the model origin at map coordinates "{coordinates}"'
|
||||
)
|
||||
)
|
||||
def the_object_name_has_a_vert_at_location_relative_to_the_model_origin_at_map_coordinates(name, location, coordinates):
|
||||
"""As above, for when the whole model has been shifted onto the origin.
|
||||
|
||||
Blender locations are then only meaningful relative to that origin, since
|
||||
everything moves together with it.
|
||||
"""
|
||||
obj = the_object_name_exists(name)
|
||||
target = Vector([float(co) for co in location.split(",")]) - get_model_origin()
|
||||
verts = get_world_verts(obj)
|
||||
vert = next((v for v in verts if (v - target).length < 0.001), None)
|
||||
assert vert is not None, f"No vert found at {location} relative to the model origin: {verts}"
|
||||
assert_vert_at_map_coordinates(obj, vert, coordinates)
|
||||
|
||||
|
||||
@then(parsers.parse('the object "{name}" has its origin on a vertex'))
|
||||
def the_object_name_has_its_origin_on_a_vertex(name):
|
||||
"""Far away geometry is shifted onto one of its own verts, which keeps the
|
||||
origin on the geometry and the local coordinates small enough to keep their
|
||||
precision. Which vert that is does not matter."""
|
||||
obj = the_object_name_exists(name)
|
||||
mesh = obj.data
|
||||
assert isinstance(mesh, bpy.types.Mesh) and len(mesh.vertices), f"Object {obj.name} has no mesh"
|
||||
nearest = min(v.co.length for v in mesh.vertices)
|
||||
assert nearest < 0.001, f"Object origin is {nearest} away from its nearest vert"
|
||||
|
||||
|
||||
@then("the model origin is on an object vertex")
|
||||
def the_model_origin_is_on_an_object_vertex():
|
||||
for obj in bpy.data.objects:
|
||||
if not isinstance(obj.data, bpy.types.Mesh):
|
||||
continue
|
||||
if any(v.length < 0.001 for v in get_world_verts(obj)):
|
||||
return
|
||||
assert False, "No object has a vert at the model origin"
|
||||
|
||||
|
||||
@then(parsers.parse('the object "{name}" has no scale'))
|
||||
def the_object_name_has_no_scale(name):
|
||||
assert the_object_name_exists(name).scale == Vector(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[tool.ruff]
|
||||
extend = "../pyproject.toml"
|
||||
lint.ignore = [
|
||||
"F401", # unused imports
|
||||
"unused-import", # unused imports
|
||||
]
|
||||
|
||||
@@ -168,7 +168,7 @@ ifcopenshell_deploy_qt_runtime(BonsaiViewer)
|
||||
# them explicitly. (In a static build these are absent from lib/
|
||||
# and the glob just no-ops, so this rule is safe in both modes.)
|
||||
#
|
||||
# 2. Plug-ins (ifcopenshell.*.dylib, no `lib` prefix) — dlopen-only
|
||||
# 2. Plug-ins (ifcopenshell_*.dylib, no `lib` prefix) — dlopen-only
|
||||
# deps the plug-in loader resolves at runtime. macdeployqt has
|
||||
# no way to know about these.
|
||||
#
|
||||
@@ -177,7 +177,7 @@ ifcopenshell_deploy_qt_runtime(BonsaiViewer)
|
||||
# inside the bundle), so plug-ins and core libs both find each other
|
||||
# on the first probe.
|
||||
#
|
||||
# The geometry-writer filter drops ifcopenshell.geometry.writer.*.dylib
|
||||
# The geometry-writer filter drops ifcopenshell_geometry_writer_*.dylib
|
||||
# (the per-schema OBJ / glTF / DAE / STP / IGS / SVG / TTL export
|
||||
# converters — heavy, viewer-irrelevant). Mirrors the Rocky workflow's
|
||||
# filter in `stage_runtime_payload` (see 27249770e).
|
||||
@@ -195,7 +195,7 @@ if(APPLE)
|
||||
install(CODE [[
|
||||
set(_fw "${CMAKE_INSTALL_PREFIX}/BonsaiViewer.app/Contents/Frameworks")
|
||||
file(GLOB _ifc_dylibs "${CMAKE_INSTALL_PREFIX}/lib/*.dylib")
|
||||
list(FILTER _ifc_dylibs EXCLUDE REGEX "ifcopenshell\\.geometry\\.writer\\.")
|
||||
list(FILTER _ifc_dylibs EXCLUDE REGEX "ifcopenshell_geometry_writer_")
|
||||
if(_ifc_dylibs)
|
||||
message(STATUS "Staging IfcOpenShell dylibs (linked core + plug-ins) into BonsaiViewer.app/Contents/Frameworks")
|
||||
file(COPY ${_ifc_dylibs} DESTINATION "${_fw}")
|
||||
|
||||
@@ -70,7 +70,7 @@ std::optional<BasicElementInfo> ElementRegistry::findBasicElementInfo(uint32_t o
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::optional<express::Base> ElementRegistry::findEntity(uint32_t object_id) const {
|
||||
std::optional<express::base> ElementRegistry::findEntity(uint32_t object_id) const {
|
||||
if (!loader_) return std::nullopt;
|
||||
|
||||
auto info = findBasicElementInfo(object_id);
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
void removeModel(uint32_t session_model_id);
|
||||
std::vector<BasicElementInfo> basicElementInfoForModel(uint32_t session_model_id) const;
|
||||
std::optional<BasicElementInfo> findBasicElementInfo(uint32_t object_id) const;
|
||||
std::optional<express::Base> findEntity(uint32_t object_id) const;
|
||||
std::optional<express::base> findEntity(uint32_t object_id) const;
|
||||
|
||||
private:
|
||||
void onSidecarElementsReady(uint32_t session_model_id,
|
||||
|
||||
@@ -44,7 +44,7 @@ Main components
|
||||
code.
|
||||
|
||||
``GeometryStreamer``
|
||||
Runs ``IfcGeom::Iterator`` on a worker thread for raw IFC loads. It emits a
|
||||
Runs ``ifcopenshell::geom::iterator`` on a worker thread for raw IFC loads. It emits a
|
||||
``StreamedMesh`` once for each unique representation mesh and a
|
||||
``StreamedInstance`` for each placed occurrence.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "../../../ifcviewer/SceneLoader.h"
|
||||
#include "../../../ifcviewer/SidecarBuilder.h"
|
||||
#include "../../../ifcviewer/ViewportWindow.h"
|
||||
#include "../../../ifcgeom/Serializer.h"
|
||||
#include "../../../ifcgeom/serializer.h"
|
||||
#include "../../../serializers/document_serializer_plugin.h"
|
||||
|
||||
#include <QDebug>
|
||||
@@ -685,7 +685,7 @@ void convertIfcToDatabase(SessionState& session, QWidget& host) {
|
||||
throw ifcopenshell::exception("RDB serializer does not support streaming from an input filename");
|
||||
}
|
||||
|
||||
boost::shared_ptr<Serializer> serializer = registry.create("rdb", context);
|
||||
std::shared_ptr<ifcopenshell::geom::serializer> serializer = registry.create("rdb", context);
|
||||
serializer->finalize();
|
||||
} catch (const std::exception& e) {
|
||||
*error_message = QString::fromUtf8(e.what());
|
||||
@@ -791,7 +791,7 @@ void exportGeometryDatabase(SessionState& session, QWidget& host) {
|
||||
throw ifcopenshell::exception("RDB serializer does not support streaming from an input filename");
|
||||
}
|
||||
|
||||
boost::shared_ptr<Serializer> serializer = registry.create("rdb", context);
|
||||
std::shared_ptr<ifcopenshell::geom::serializer> serializer = registry.create("rdb", context);
|
||||
serializer->finalize();
|
||||
serializer.reset();
|
||||
|
||||
|
||||
@@ -75,16 +75,16 @@ QString formatCachedUnitScale(double meters_per_unit) {
|
||||
return QString("Cached scale: 1 unit = %1 m").arg(formatNumber(meters_per_unit));
|
||||
}
|
||||
|
||||
std::string enumString(const attribute_value& av) {
|
||||
std::string enumString(const ifcopenshell::attribute_value& av) {
|
||||
if (av.isNull()) return {};
|
||||
if (av.type() != ifcopenshell::Argument_ENUMERATION) return {};
|
||||
enumeration_reference enumeration = av;
|
||||
ifcopenshell::enumeration_reference enumeration = av;
|
||||
return std::string(enumeration.value() ? enumeration.value() : "");
|
||||
}
|
||||
|
||||
QString formatNamedUnit(const express::Base& unit) {
|
||||
QString formatNamedUnit(const express::base& unit) {
|
||||
if (!unit) return "—";
|
||||
auto entity = unit.as<express::Entity>();
|
||||
auto entity = unit.as<express::entity>();
|
||||
if (unit.declaration().is("IfcSIUnit")) {
|
||||
const std::string prefix = enumString(entity.get("Prefix"));
|
||||
const std::string name = enumString(entity.get("Name"));
|
||||
|
||||
@@ -109,7 +109,7 @@ void PropertiesPanelView::refresh(uint32_t object_id) {
|
||||
state.entity = {"No item selected", ""};
|
||||
|
||||
auto entity = registry ? registry->findEntity(object_id)
|
||||
: std::optional<express::Base>{};
|
||||
: std::optional<express::base>{};
|
||||
if (entity) {
|
||||
state.entity.entity_class = QString::fromStdString(entity->declaration().name());
|
||||
if (auto predefined_type = get_predefined_type(*entity)) {
|
||||
@@ -121,16 +121,16 @@ void PropertiesPanelView::refresh(uint32_t object_id) {
|
||||
}
|
||||
// Relationships: the construction type and the spatial container, shown
|
||||
// by name (falling back to the entity class when unnamed).
|
||||
auto display_name = [](const express::Base& related) -> QString {
|
||||
auto display_name = [](const express::base& related) -> QString {
|
||||
if (auto name = get_string_attribute(related, "Name"); name && !name->empty()) {
|
||||
return QString::fromStdString(*name);
|
||||
}
|
||||
return QString::fromStdString(related.declaration().name());
|
||||
};
|
||||
if (express::Base type = get_type(*entity)) {
|
||||
if (express::base type = get_type(*entity)) {
|
||||
state.relationships.append({"Type", display_name(type)});
|
||||
}
|
||||
if (express::Base container = get_container(*entity)) {
|
||||
if (express::base container = get_container(*entity)) {
|
||||
state.relationships.append({"Container", display_name(container)});
|
||||
}
|
||||
// Property sets (Pset_*) and quantity sets (Qto_* / BaseQuantities),
|
||||
|
||||
@@ -60,7 +60,7 @@ TreeNode* findNodeRecursive(QList<TreeNode>& nodes, const NodePath& path, int de
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ItemKind kindOf(const express::Base& element) {
|
||||
ItemKind kindOf(const express::base& element) {
|
||||
const auto& declaration = element.declaration();
|
||||
if (declaration.is("IfcSite")) return ItemKind::Site;
|
||||
if (declaration.is("IfcBuilding")) return ItemKind::Building;
|
||||
@@ -68,14 +68,14 @@ ItemKind kindOf(const express::Base& element) {
|
||||
return ItemKind::Space; // IfcSpace, IfcSpatialZone, …
|
||||
}
|
||||
|
||||
QString displayName(const express::Base& element) {
|
||||
QString displayName(const express::base& element) {
|
||||
if (auto name = get_string_attribute(element, "Name"); name && !name->empty()) {
|
||||
return QString::fromStdString(*name);
|
||||
}
|
||||
return QString::fromStdString(element.declaration().name());
|
||||
}
|
||||
|
||||
TreeNode buildNode(const express::Base& element) {
|
||||
TreeNode buildNode(const express::base& element) {
|
||||
TreeNode node;
|
||||
node.name = displayName(element);
|
||||
node.kind = kindOf(element);
|
||||
|
||||
@@ -46,6 +46,6 @@ py-modules = ["bsdd","bsdd_json","type_hints"]
|
||||
|
||||
[tool.ruff]
|
||||
extend = "../../pyproject.toml"
|
||||
lint.select = [
|
||||
"F401", # unused imports
|
||||
lint.extend-select = [
|
||||
"unused-import", # unused imports
|
||||
]
|
||||
|
||||
+9
-6
@@ -3,7 +3,10 @@ IS_STABLE:=FALSE
|
||||
PYTHON:=python3
|
||||
PIP:=pip3
|
||||
VERSION:=$(shell cat ../../VERSION)
|
||||
VERSION_BASE:=$(shell sed -E 's/[[:alpha:]]+[0-9]+$$//' ../../VERSION)
|
||||
VERSION_PYTHON:=$(shell sed 's/alpha/a/' ../../VERSION)
|
||||
VERSION_DATE:=$(shell date '+%y%m%d')
|
||||
VERSION_DAILY:=$(VERSION_BASE)a$(VERSION_DATE)
|
||||
SED:=sed -i
|
||||
VENV_BIN:=bin
|
||||
|
||||
@@ -30,18 +33,18 @@ dist:
|
||||
cp pyproject.toml build/
|
||||
if [ -f README.md ]; then cp README.md build/; fi
|
||||
ifeq ($(IS_STABLE), TRUE)
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/pyproject.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_PYTHON)"/' build/pyproject.toml
|
||||
ifdef IS_MODULE
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/$(PACKAGE_NAME)
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_PYTHON)"/' build/$(PACKAGE_NAME)
|
||||
else
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)"/' build/$(PACKAGE_NAME)/__init__.py
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_PYTHON)"/' build/$(PACKAGE_NAME)/__init__.py
|
||||
endif
|
||||
else
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)a$(VERSION_DATE)"/' build/pyproject.toml
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_DAILY)"/' build/pyproject.toml
|
||||
ifdef IS_MODULE
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)-alpha$(VERSION_DATE)"/' build/$(PACKAGE_NAME)
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_DAILY)"/' build/$(PACKAGE_NAME)
|
||||
else
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION)-alpha$(VERSION_DATE)"/' build/$(PACKAGE_NAME)/__init__.py
|
||||
$(SED) 's/version = "0.0.0"/version = "$(VERSION_DAILY)"/' build/$(PACKAGE_NAME)/__init__.py
|
||||
endif
|
||||
endif
|
||||
cd build && $(PYTHON) -m venv env && . env/$(VENV_ACTIVATE) && $(PIP) install build
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
#include "plugin/plugin.h"
|
||||
|
||||
#include "../ifcgeom/Serialization/Serialization.h"
|
||||
#include "../ifcgeom/serialization/serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
@@ -76,12 +76,12 @@ int main() {
|
||||
// By adding a building, a hierarchy has been automatically created that consists of the following
|
||||
// structure: IfcProject > IfcSite > IfcBuilding
|
||||
|
||||
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
|
||||
// Lateron changing the name of the IfcProject can be done by obtaining a reference to the
|
||||
// project, which has been created automatically.
|
||||
file.getSingle<IfcSchema::IfcProject>().setName("IfcAdvancedHouse"s);
|
||||
|
||||
// To demonstrate the ability to serialize arbitrary opencascade solids a building envelope is
|
||||
// constructed by applying boolean operations. Naturally, in IFC, building elements should be
|
||||
// constructed by applying boolean operations. Naturally, in IFC, building elements should be
|
||||
// modeled separately, with rich parametric and relational semantics. Creating geometry in this
|
||||
// way does not preserve any history and is merely a demonstration of technical capabilities.
|
||||
TopoDS_Shape outer = BRepPrimAPI_MakeBox(gp_Pnt(-5000., -180., -2000.), gp_Pnt(5000., 5180., 3000.)).Shape();
|
||||
@@ -101,8 +101,8 @@ int main() {
|
||||
// IfcFacetedBRep. If it would not be a polyhedron, serialise() can only be successful when linked
|
||||
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
|
||||
// return `0` otherwise.
|
||||
auto building_shape = IfcGeom::serialise(file, building_shell, false).as<IfcSchema::IfcProductDefinitionShape>();
|
||||
|
||||
auto building_shape = ifcopenshell::geom::serialise(file, building_shell, false).as<IfcSchema::IfcProductDefinitionShape>();
|
||||
|
||||
file.add_entity(building_shape);
|
||||
auto building_representations = building_shape.Representations();
|
||||
building_representations.front().setContextOfItems(file.getRepresentationContext("model"));
|
||||
@@ -117,12 +117,12 @@ int main() {
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
|
||||
auto ground_representation = IfcGeom::serialise(file, shape, true);
|
||||
auto ground_representation = ifcopenshell::geom::serialise(file, shape, true);
|
||||
if (!ground_representation) {
|
||||
ground_representation = IfcGeom::tesselate(file, shape, 100.);
|
||||
ground_representation = ifcopenshell::geom::tesselate(file, shape, 100.);
|
||||
}
|
||||
file.getSingle<IfcSchema::IfcSite>().setRepresentation(ground_representation.as<IfcSchema::IfcProductDefinitionShape>());
|
||||
|
||||
|
||||
auto ground_reps = file.getSingle<IfcSchema::IfcSite>().Representation().Representations();
|
||||
for (auto& rep : ground_reps) {
|
||||
rep.setContextOfItems(file.getRepresentationContext("Model"));
|
||||
@@ -131,13 +131,13 @@ int main() {
|
||||
setSurfaceColour(file, ground_representation.as<IfcSchema::IfcProductDefinitionShape>(), 0.15, 0.25, 0.05);
|
||||
|
||||
/*
|
||||
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
|
||||
// BRepBuilderAPI_NurbsConvert can be used to serialize such surfaces as nurbs surfaces.
|
||||
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
|
||||
// BRepBuilderAPI_NurbsConvert can be used to serialize such surfaces as nurbs surfaces.
|
||||
TopoDS_Shape sphere = BRepPrimAPI_MakeSphere(gp_Pnt(), 1000.).Shape();
|
||||
IfcSchema::IfcProductDefinitionShape* sphere_representation = IfcGeom::serialise(sphere, true);
|
||||
auto sphere_representation = ifcopenshell::geom::serialise(file, sphere, true);
|
||||
if (S(IfcSchema::Identifier) == "IFC4") {
|
||||
sphere = BRepBuilderAPI_NurbsConvert(sphere, true).Shape();
|
||||
sphere_representation = IfcGeom::serialise(sphere, true);
|
||||
sphere_representation = ifcopenshell::geom::serialise(file, sphere, true);
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -175,10 +175,10 @@ void createGroundShape(TopoDS_Shape& shape) {
|
||||
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
|
||||
TColStd_Array1OfReal knots(0, 1);
|
||||
knots(0) = 0;
|
||||
knots(1) = 1;
|
||||
knots(1) = 1;
|
||||
TColStd_Array1OfInteger mult(0, 1);
|
||||
mult(0) = 5;
|
||||
mult(1) = 5;
|
||||
mult(1) = 5;
|
||||
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
|
||||
@@ -70,7 +70,7 @@ Schema::IfcProject setup_project(hierarchy_helper<Schema>& file) {
|
||||
dimensions.setThermodynamicTemperatureExponent(0);
|
||||
dimensions.setAmountOfSubstanceExponent(0);
|
||||
dimensions.setLuminousIntensityExponent(0);
|
||||
|
||||
|
||||
auto conversion_factor = file.create<Schema::IfcMeasureWithUnit>();
|
||||
auto length = file.create<Schema::IfcLengthMeasure>();
|
||||
length.set_attribute_value(0, 304.80);
|
||||
@@ -82,7 +82,7 @@ Schema::IfcProject setup_project(hierarchy_helper<Schema>& file) {
|
||||
conversion_based_unit.setUnitType(Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT);
|
||||
conversion_based_unit.setName("FEET");
|
||||
conversion_based_unit.setConversionFactor(conversion_factor);
|
||||
|
||||
|
||||
units.erase(std::remove(units.begin(), units.end(), unit)); // remove the millimeter unit
|
||||
units.push_back(conversion_based_unit); // add the feet unit
|
||||
units_in_context.setUnits(units); // update the UnitsInContext
|
||||
@@ -386,7 +386,7 @@ int main() {
|
||||
nests_horizontal_segments.setName("Nests horizontal alignment segments with horizontal alignment");
|
||||
nests_horizontal_segments.setRelatingObject(horizontal_alignment);
|
||||
nests_horizontal_segments.setRelatedObjects(horizontal_segments);
|
||||
|
||||
|
||||
//
|
||||
// Create plan view footprint model representation for the horizontal alignment
|
||||
//
|
||||
@@ -403,7 +403,7 @@ int main() {
|
||||
footprint_shape_representation.setRepresentationType("Curve2D");
|
||||
// the composite curve is a representation item
|
||||
footprint_shape_representation.setItems({composite_curve});
|
||||
|
||||
|
||||
//
|
||||
// Define vertical profile segments
|
||||
//
|
||||
@@ -539,7 +539,7 @@ int main() {
|
||||
nests_alignment_layouts.setName("Nest horizontal and vertical alignment layouts with the alignment");
|
||||
nests_alignment_layouts.setRelatingObject(alignment);
|
||||
nests_alignment_layouts.setRelatedObjects({horizontal_alignment, vertical_profile});
|
||||
|
||||
|
||||
// Define the relationship with the project
|
||||
|
||||
// IFC 4.1.4.1.1 "Every IfcAlignment must be related to IfcProject using the IfcRelAggregates relationship"
|
||||
@@ -550,7 +550,7 @@ int main() {
|
||||
aggregate_alignments_with_project.setName("Alignments in project");
|
||||
aggregate_alignments_with_project.setRelatingObject(project);
|
||||
aggregate_alignments_with_project.setRelatedObjects({alignment});
|
||||
|
||||
|
||||
// Define the spatial structure of the alignment with respect to the site
|
||||
|
||||
// IFC 4.1.5.1 alignment is referenced in spatial structure of an IfcSpatialElement. In this case IfcSite is the highest level IfcSpatialElement
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
#include "plugin/plugin.h"
|
||||
|
||||
#include "../ifcgeom/Serialization/Serialization.h"
|
||||
#include "../ifcgeom/serialization/serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
// Some convenience typedefs and definitions.
|
||||
// Some convenience typedefs and definitions.
|
||||
typedef ifcopenshell::global_id guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
#ifdef SCHEMA_HAS_IfcPresentationStyleAssignment
|
||||
@@ -295,13 +295,13 @@ int main() {
|
||||
west_void.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
west_void.setRelatingBuildingElement(west_wall);
|
||||
west_void.setRelatedOpeningElement(west_opening_copy);
|
||||
|
||||
// Up until now we have only used simple extrusions for the creation of the geometry. For the
|
||||
// ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. The surface
|
||||
|
||||
// Up until now we have only used simple extrusions for the creation of the geometry. For the
|
||||
// ground mesh of the IfcSite we will use a Nurbs surface created in Open Cascade. The surface
|
||||
// will be tessellated using the deflection specified.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
auto ground_representation = IfcGeom::tesselate(file, shape, 100.).as<IfcSchema::IfcProductDefinitionShape>();
|
||||
auto ground_representation = ifcopenshell::geom::tesselate(file, shape, 100.).as<IfcSchema::IfcProductDefinitionShape>();
|
||||
file.getSingle<IfcSchema::IfcSite>().setRepresentation(ground_representation);
|
||||
|
||||
GProp_GProps prop;
|
||||
@@ -325,7 +325,7 @@ int main() {
|
||||
site_prop.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
site_prop.setRelatedObjects({file.getSingle<IfcSchema::IfcSite>()});
|
||||
site_prop.setRelatingPropertyDefinition(pset);
|
||||
|
||||
|
||||
auto ground_reps = file.getSingle<IfcSchema::IfcSite>().Representation().Representations();
|
||||
for (auto& rep : ground_reps) {
|
||||
rep.setContextOfItems(file.getRepresentationContext("Model"));
|
||||
@@ -334,11 +334,11 @@ int main() {
|
||||
setSurfaceColour(file,ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
// According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
|
||||
// assigned. Note that this material definition is independent of the surface styles we have
|
||||
// been assigning to the walls already. The surface styles determine the colour in the
|
||||
// assigned. Note that this material definition is independent of the surface styles we have
|
||||
// been assigning to the walls already. The surface styles determine the colour in the
|
||||
// '3D viewport' of most applications.
|
||||
// Some BIM authoring applications, such as Autodesk Revit, ignore the geometrical representation
|
||||
// by and large and construct native walls using the layer thickness and reference line offset
|
||||
// by and large and construct native walls using the layer thickness and reference line offset
|
||||
// provided here.
|
||||
auto material = file.create<IfcSchema::IfcMaterial>();
|
||||
material.setName("Brick");
|
||||
@@ -422,7 +422,7 @@ int main() {
|
||||
#endif
|
||||
|
||||
door.setRepresentation(file.addBox(80, 80, 2120, IfcSchema::IfcAxis2Placement2D{}, file.addPlacement3d(460, 0, 0)));
|
||||
|
||||
|
||||
auto door_representations = door.Representation().Representations();
|
||||
IfcSchema::IfcShapeRepresentation door_body;
|
||||
for (auto& rep : door_representations) {
|
||||
@@ -465,9 +465,9 @@ int main() {
|
||||
#endif
|
||||
|
||||
// Surface styles are assigned to representation items, hence there is no real limitation to
|
||||
// assign different colours within the same representation. However, some viewers have
|
||||
// difficulties rendering products with representation items with different surface styles.
|
||||
// Therefore we will construct the window as a decomposition of beams and a plate, in which
|
||||
// assign different colours within the same representation. However, some viewers have
|
||||
// difficulties rendering products with representation items with different surface styles.
|
||||
// Therefore we will construct the window as a decomposition of beams and a plate, in which
|
||||
// only the plate will have a transparent material assigned.
|
||||
|
||||
// The window frame will consists of four separate beams.
|
||||
@@ -476,7 +476,7 @@ int main() {
|
||||
// match the bounding box of the representation. Furthermore, the window placement needs
|
||||
// to align with the lowerleft corner of the constituent parts.
|
||||
std::vector<IfcSchema::IfcShapeRepresentation> frame_representations;
|
||||
|
||||
|
||||
auto horizontal_bar = file.addEmptyRepresentation();
|
||||
auto vertical_bar = file.addEmptyRepresentation();
|
||||
file.addBox(horizontal_bar, 1860, 90, 90);
|
||||
@@ -498,7 +498,7 @@ int main() {
|
||||
// Because of the duplication the iterator is incremented twice
|
||||
}
|
||||
|
||||
// This window will be placed at five locations within the building. A list of placements is
|
||||
// This window will be placed at five locations within the building. A list of placements is
|
||||
// created and is iterated over to create all window instances.
|
||||
std::vector<IfcSchema::IfcLocalPlacement> window_placements;
|
||||
window_placements.push_back(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400));
|
||||
@@ -506,7 +506,7 @@ int main() {
|
||||
window_placements.push_back(file.addLocalPlacement(storey_placement, -430-930, -45, 400));
|
||||
window_placements.push_back(file.addLocalPlacement(storey_placement, 3000-930, -45, 400));
|
||||
window_placements.push_back(file.addLocalPlacement(storey_placement, -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
|
||||
|
||||
|
||||
for (auto& place : window_placements) {
|
||||
|
||||
// Create the window at the current location
|
||||
@@ -520,7 +520,7 @@ int main() {
|
||||
window.setPredefinedType(IfcSchema::IfcWindowTypeEnum::IfcWindowType_WINDOW);
|
||||
window.setPartitioningType(IfcSchema::IfcWindowTypePartitioningEnum::IfcWindowTypePartitioning_SINGLE_PANEL);
|
||||
#endif
|
||||
file.addBuildingProduct(window);
|
||||
file.addBuildingProduct(window);
|
||||
|
||||
// Initialize a list of parts for the window to be composed of
|
||||
std::vector<IfcSchema::IfcObjectDefinition> window_parts;
|
||||
@@ -532,7 +532,7 @@ int main() {
|
||||
frame_placements.push_back(file.addLocalPlacement(storey_placement, 930, 45, 1510));
|
||||
frame_placements.push_back(file.addLocalPlacement(storey_placement, -885+930, 45, 90));
|
||||
frame_placements.push_back(file.addLocalPlacement(storey_placement, 885+930, 45, 90));
|
||||
|
||||
|
||||
// Now iterate over the placements and representations of the beam and add them to list of parts
|
||||
std::vector<IfcSchema::IfcLocalPlacement>::const_iterator frame_placement;
|
||||
std::vector<IfcSchema::IfcShapeRepresentation>::const_iterator frame_representation;
|
||||
@@ -565,7 +565,7 @@ int main() {
|
||||
window_parts.push_back(glass_part);
|
||||
file.relatePlacements(window, glass_part);
|
||||
setSurfaceColour(file, glass_part.Representation(), 0.6, 0.7, 0.75, 0.1);
|
||||
|
||||
|
||||
// Now create a decomposition relation between the window and the parts. Most viewers and authoring
|
||||
// tools will consider the window a single entity that can be selected as a whole.
|
||||
{
|
||||
@@ -612,10 +612,10 @@ void createGroundShape(TopoDS_Shape& shape) {
|
||||
cv.SetValue(4, 4, gp_Pnt( 10000, 10000, -8130));
|
||||
TColStd_Array1OfReal knots(0, 1);
|
||||
knots(0) = 0;
|
||||
knots(1) = 1;
|
||||
knots(1) = 1;
|
||||
TColStd_Array1OfInteger mult(0, 1);
|
||||
mult(0) = 5;
|
||||
mult(1) = 5;
|
||||
mult(1) = 5;
|
||||
Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(cv, knots, knots, mult, mult, 4, 4);
|
||||
#if OCC_VERSION_HEX < 0x60502
|
||||
shape = BRepBuilderAPI_MakeFace(surf);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
@@ -70,10 +70,10 @@ typedef IfcSchema::IfcBuildingElement element_t;
|
||||
typedef IfcSchema::IfcBuiltElement element_t;
|
||||
#endif
|
||||
|
||||
std::string format_string(const attribute_value& argument) {
|
||||
std::string format_string(const ifcopenshell::attribute_value& argument) {
|
||||
// Argument is a runtime tagged variant for the various data types in a IFC model,
|
||||
// in this particular case we only care about flattening it to a string.
|
||||
// @todo mostly duplicated from XmlSerializer.cpp
|
||||
// @todo mostly duplicated from xml_serializer.cpp
|
||||
if (argument.isNull()) {
|
||||
return "-";
|
||||
}
|
||||
@@ -151,7 +151,7 @@ void process_pset(element_properties& props, const T& inst) {
|
||||
|
||||
template <typename Schema>
|
||||
void get_psets_s(element_properties& props, const typename Schema::IfcObjectDefinition& inst) {
|
||||
// Extracts the property definitions for an IFC instance.
|
||||
// Extracts the property definitions for an IFC instance.
|
||||
if (auto tyob = inst.template as<typename Schema::IfcTypeObject>()) {
|
||||
if (tyob.HasPropertySets()) {
|
||||
auto defs = *tyob.HasPropertySets();
|
||||
@@ -194,7 +194,7 @@ void get_psets_s(element_properties& props, const typename Schema::IfcObjectDefi
|
||||
}
|
||||
}
|
||||
|
||||
element_properties get_psets(const express::Base& inst) {
|
||||
element_properties get_psets(const express::base& inst) {
|
||||
element_properties props;
|
||||
if (auto object_definition = inst.as<IfcSchema::IfcObjectDefinition>()) {
|
||||
get_psets_s<IfcSchema>(props, object_definition);
|
||||
@@ -213,7 +213,7 @@ int main(int argc, char** argv) {
|
||||
#endif
|
||||
|
||||
// Redirect the output (both progress and log) to stdout
|
||||
::logger::root().set_output(&std::cout, &std::cout);
|
||||
ifcopenshell::logger::root().set_output(&std::cout, &std::cout);
|
||||
|
||||
// Parse the IFC file provided in argv[1]
|
||||
ifcopenshell::file file(argv[1]);
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
ISO-10303-21;
|
||||
HEADER;
|
||||
FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1');
|
||||
FILE_NAME('IfcParseExamples_test.ifc','2025-12-12T13:49:19+05:00',(''),(''),'IfcOpenShell 0.0.0','Bonsai 0.8.5-alpha251212-a47cbc3','Nobody');
|
||||
FILE_SCHEMA(('IFC2X3'));
|
||||
ENDSEC;
|
||||
DATA;
|
||||
#1=IFCPERSON('HSeldon','Seldon','Hari',$,$,$,$,$);
|
||||
#2=IFCORGANIZATION('APTR','Aperture Science',$,$,$);
|
||||
#3=IFCPERSONANDORGANIZATION(#1,#2,$);
|
||||
#4=IFCACTORROLE(.USERDEFINED.,'CONTRIBUTOR',$);
|
||||
#5=IFCORGANIZATION('IfcOpenShell','IfcOpenShell','IfcOpenShell is an open source software library that helps users and software developers to work with IFC data.',(#4),(#6));
|
||||
#6=IFCTELECOMADDRESS(.USERDEFINED.,$,'WEBPAGE',$,$,$,$,'https://ifcopenshell.org');
|
||||
#7=IFCAPPLICATION(#5,'0.8.5','Bonsai','Bonsai-0.8.5');
|
||||
#8=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1765520605,#3,#7,1765520605);
|
||||
#9=IFCPROJECT('3GSSvm5SP5U96O5iar8uYb',#8,'My Project',$,$,$,$,(#22,#34),#17);
|
||||
#10=IFCSIUNIT(*,.LENGTHUNIT.,$,.METRE.);
|
||||
#11=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
|
||||
#12=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.);
|
||||
#13=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
|
||||
#14=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
|
||||
#15=IFCMEASUREWITHUNIT(IFCREAL(0.0174532925199433),#14);
|
||||
#16=IFCCONVERSIONBASEDUNIT(#13,.PLANEANGLEUNIT.,'degree',#15);
|
||||
#17=IFCUNITASSIGNMENT((#12,#10,#16,#11));
|
||||
#18=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#19=IFCDIRECTION((0.,0.,1.));
|
||||
#20=IFCDIRECTION((1.,0.,0.));
|
||||
#21=IFCAXIS2PLACEMENT3D(#18,#19,#20);
|
||||
#22=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#21,$);
|
||||
#23=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#22,$,.MODEL_VIEW.,$);
|
||||
#24=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#22,$,.GRAPH_VIEW.,$);
|
||||
#25=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#22,$,.MODEL_VIEW.,$);
|
||||
#26=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#22,$,.SECTION_VIEW.,$);
|
||||
#27=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#22,$,.ELEVATION_VIEW.,$);
|
||||
#28=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#22,$,.MODEL_VIEW.,$);
|
||||
#29=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#22,$,.PLAN_VIEW.,$);
|
||||
#30=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Profile','Model',*,*,*,*,#22,$,.ELEVATION_VIEW.,$);
|
||||
#31=IFCCARTESIANPOINT((0.,0.));
|
||||
#32=IFCDIRECTION((1.,0.));
|
||||
#33=IFCAXIS2PLACEMENT2D(#31,#32);
|
||||
#34=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#33,$);
|
||||
#35=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Plan',*,*,*,*,#34,$,.GRAPH_VIEW.,$);
|
||||
#36=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Plan',*,*,*,*,#34,$,.PLAN_VIEW.,$);
|
||||
#37=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#34,$,.PLAN_VIEW.,$);
|
||||
#38=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#34,$,.REFLECTED_PLAN_VIEW.,$);
|
||||
#39=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765520605,#3,#7,1765520605);
|
||||
#40=IFCSITE('2Ys4j4OOf3x9UYeALDJ_g3',#39,'My Site',$,$,#66,$,$,.ELEMENT.,$,$,$,$,$);
|
||||
#46=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765520605,#3,#7,1765520605);
|
||||
#47=IFCBUILDING('3e580MQFTCD9tCSaZWRPi9',#46,'My Building',$,$,#73,$,$,.ELEMENT.,$,$,$);
|
||||
#53=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765520605,#3,#7,1765520605);
|
||||
#54=IFCBUILDINGSTOREY('3XFkAr6KbAsP5wR3gxi3my',#53,'My Storey',$,$,#80,$,$,.ELEMENT.,$);
|
||||
#60=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1765520605,#3,#7,1765520605);
|
||||
#61=IFCRELAGGREGATES('2OWfFyDQn0qP0Vd6NWGX7k',#60,$,$,#9,(#40));
|
||||
#62=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#63=IFCDIRECTION((0.,0.,1.));
|
||||
#64=IFCDIRECTION((1.,0.,0.));
|
||||
#65=IFCAXIS2PLACEMENT3D(#62,#63,#64);
|
||||
#66=IFCLOCALPLACEMENT($,#65);
|
||||
#67=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1765520605,#3,#7,1765520605);
|
||||
#68=IFCRELAGGREGATES('3_X_vfPpXDaO3NODBJgmSp',#67,$,$,#40,(#47));
|
||||
#69=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#70=IFCDIRECTION((0.,0.,1.));
|
||||
#71=IFCDIRECTION((1.,0.,0.));
|
||||
#72=IFCAXIS2PLACEMENT3D(#69,#70,#71);
|
||||
#73=IFCLOCALPLACEMENT(#66,#72);
|
||||
#74=IFCOWNERHISTORY(#3,#7,.READWRITE.,.ADDED.,1765520605,#3,#7,1765520605);
|
||||
#75=IFCRELAGGREGATES('3ScF98CZD3pAa0SW$mhBHF',#74,$,$,#47,(#54));
|
||||
#76=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#77=IFCDIRECTION((0.,0.,1.));
|
||||
#78=IFCDIRECTION((1.,0.,0.));
|
||||
#79=IFCAXIS2PLACEMENT3D(#76,#77,#78);
|
||||
#80=IFCLOCALPLACEMENT(#73,#79);
|
||||
#110=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765529359,#3,#7,1765520632);
|
||||
#111=IFCWALL('1lfiJzSCH1a8vjDuSLL4Ii',#110,'Cube',$,$,#203,$,$);
|
||||
#112=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765520818,#3,#7,1765520632);
|
||||
#113=IFCRELCONTAINEDINSPATIALSTRUCTURE('2Gqx6vP7jB4x_h65Tawn0f',#112,$,$,(#111,#182,#150),#54);
|
||||
#149=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765529359,#3,#7,1765520810);
|
||||
#150=IFCWINDOW('1eE0btB_54tBL59wLXKO1B',#149,'Cube',$,$,#208,$,$,$,$);
|
||||
#181=IFCOWNERHISTORY(#3,#7,.READWRITE.,.MODIFIED.,1765529359,#3,#7,1765520818);
|
||||
#182=IFCBUILDINGELEMENTPART('0fmaoBJgz0kPBavO$EJkPn',#181,'Cube',$,$,#198,$,$);
|
||||
#194=IFCCARTESIANPOINT((-3.82147288322449,-0.987768530845642,1.78445267677307));
|
||||
#195=IFCDIRECTION((0.,0.,1.));
|
||||
#196=IFCDIRECTION((1.,0.,0.));
|
||||
#197=IFCAXIS2PLACEMENT3D(#194,#195,#196);
|
||||
#198=IFCLOCALPLACEMENT(#80,#197);
|
||||
#199=IFCCARTESIANPOINT((0.,0.,0.));
|
||||
#200=IFCDIRECTION((0.,0.,1.));
|
||||
#201=IFCDIRECTION((1.,0.,0.));
|
||||
#202=IFCAXIS2PLACEMENT3D(#199,#200,#201);
|
||||
#203=IFCLOCALPLACEMENT(#80,#202);
|
||||
#204=IFCCARTESIANPOINT((0.,4.25822639465332,0.));
|
||||
#205=IFCDIRECTION((0.,0.,1.));
|
||||
#206=IFCDIRECTION((1.,0.,0.));
|
||||
#207=IFCAXIS2PLACEMENT3D(#204,#205,#206);
|
||||
#208=IFCLOCALPLACEMENT(#80,#207);
|
||||
ENDSEC;
|
||||
END-ISO-10303-21;
|
||||
@@ -1,147 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates various representations from *
|
||||
* IfcArbitraryOpenProfileDefs and its subclass IfcCenterLineProfileDef *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc4
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
static int i = 0;
|
||||
|
||||
void create_product_from_item(hierarchy_helper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("product"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 120 * i++));
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.add_entity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(set);
|
||||
}
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), s, items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
void create_surfaces_from_profile(hierarchy_helper& file, IfcSchema::IfcProfileDef* profile) {
|
||||
IfcSchema::IfcSurfaceOfLinearExtrusion* extrusion = new IfcSchema::IfcSurfaceOfLinearExtrusion(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
|
||||
file.add_entity(extrusion);
|
||||
|
||||
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
|
||||
IfcSchema::IfcSurfaceOfRevolution* revolution = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), ax1);
|
||||
file.add_entity(ax1);
|
||||
file.add_entity(revolution);
|
||||
|
||||
create_product_from_item(file, extrusion, "GeometricSet");
|
||||
create_product_from_item(file, revolution, "GeometricSet");
|
||||
}
|
||||
|
||||
void create_solids_from_profile(hierarchy_helper& file, IfcSchema::IfcProfileDef* profile) {
|
||||
IfcSchema::IfcExtrudedAreaSolid* extrusion = new IfcSchema::IfcExtrudedAreaSolid(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
|
||||
file.add_entity(extrusion);
|
||||
|
||||
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
|
||||
IfcSchema::IfcRevolvedAreaSolid* revolution1 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 360.);
|
||||
IfcSchema::IfcRevolvedAreaSolid* revolution2 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 90.);
|
||||
file.add_entity(ax1);
|
||||
file.add_entity(revolution1);
|
||||
file.add_entity(revolution2);
|
||||
|
||||
create_product_from_item(file, extrusion, "SweptSolid");
|
||||
create_product_from_item(file, revolution1, "SweptSolid");
|
||||
create_product_from_item(file, revolution2, "SweptSolid");
|
||||
}
|
||||
|
||||
void create_products_from_curve(hierarchy_helper& file, IfcSchema::IfcBoundedCurve* curve) {
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* open = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, null, curve);
|
||||
IfcSchema::IfcCenterLineProfileDef* center_line = new IfcSchema::IfcCenterLineProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, curve, 10.);
|
||||
file.add_entity(open);
|
||||
file.add_entity(center_line);
|
||||
|
||||
create_surfaces_from_profile(file, open);
|
||||
create_solids_from_profile(file, center_line);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list());
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords1, coords1+2)));
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
|
||||
file.addEntities(points->generalize());
|
||||
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(points);
|
||||
file.add_entity(poly);
|
||||
|
||||
create_products_from_curve(file, poly);
|
||||
|
||||
IfcSchema::IfcEllipse* ellipse = new IfcSchema::IfcEllipse(file.addPlacement2d(), 50., 25.);
|
||||
file.add_entity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcSchema::IfcParameterValue( 0.));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(180.));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.add_entity(trim);
|
||||
|
||||
create_products_from_curve(file, trim);
|
||||
|
||||
file.getSingle<Ifc2x3::IfcProject>()->setName("IfcArbitraryOpenProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates extrusions of parameterized profiles. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
#ifdef SCHEMA_IfcIShapeProfileDef_HAS_FlangeEdgeRadius
|
||||
#define IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS , null, null
|
||||
#else
|
||||
#define IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcLShapeProfileDef_HAS_CentreOfGravityInX
|
||||
#define IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS , null, null
|
||||
#else
|
||||
#define IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcTShapeProfileDef_HAS_CentreOfGravityInY
|
||||
#define IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS , null
|
||||
#else
|
||||
#define IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcCShapeProfileDef_HAS_CentreOfGravityInX
|
||||
#define IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS , null
|
||||
#else
|
||||
#define IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {100.0, 0.0};
|
||||
double coords2[] = {200.0, 0.0};
|
||||
double coords3[] = {300.0, 0.0};
|
||||
|
||||
IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list());
|
||||
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform1 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), null);
|
||||
IfcSchema::IfcCartesianTransformationOperator2D* transform2 = new IfcSchema::IfcCartesianTransformationOperator2D(file.addDoublet<IfcSchema::IfcDirection>(0, -1), file.addDoublet<IfcSchema::IfcDirection>(1, 0), file.addDoublet<IfcSchema::IfcCartesianPoint>(40, 0), 0.3);
|
||||
|
||||
IfcSchema::IfcProfileDef* p1 = new IfcSchema::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(), 25.0, 50.0, 5.0, 5.0, 2.0 IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS);
|
||||
|
||||
IfcSchema::IfcProfileDef* p2 = new IfcSchema::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(), 50.0, 25.0, 5.0, 1.0, 2.0, 2.0 IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS);
|
||||
|
||||
IfcSchema::IfcProfileDef* p3 = new IfcSchema::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(), 50.0, 40.0, 10.0, 10.0, 3.0, 2.0, 1.0, 2.0, 2.0 IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS);
|
||||
|
||||
IfcSchema::IfcProfileDef* p4 = new IfcSchema::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(80.), 50.0, 25.0, 5.0, 10.0, 2.0 IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS);
|
||||
|
||||
file.add_entity(p2);
|
||||
file.add_entity(p3);
|
||||
|
||||
file.add_entity(transform1);
|
||||
file.add_entity(transform2);
|
||||
|
||||
IfcSchema::IfcDerivedProfileDef* p5 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p2, transform1, null);
|
||||
IfcSchema::IfcDerivedProfileDef* p6 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p3, transform2, null);
|
||||
|
||||
profiles->push(p1);
|
||||
profiles->push(p5);
|
||||
profiles->push(p6);
|
||||
profiles->push(p4);
|
||||
|
||||
file.addEntities(profiles->generalize());
|
||||
|
||||
IfcSchema::IfcCompositeProfileDef* composite = new IfcSchema::IfcCompositeProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, S("IFC"), profiles, null);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("profile"), null, null, 0, 0, null, null);
|
||||
|
||||
file.addBuildingProduct(product);
|
||||
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(composite,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.add_entity(composite);
|
||||
file.add_entity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcCompositeProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates a Constructive Solid Geometry example *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
class Node {
|
||||
private:
|
||||
typedef enum {
|
||||
OP_ADD, OP_SUBTRACT, OP_INTERSECT, OP_TERMINAL
|
||||
} Op;
|
||||
typedef enum {
|
||||
PRIM_BOX, PRIM_CONE, PRIM_CYLINDER, PRIM_PYRAMID, PRIM_SPHERE
|
||||
} Prim;
|
||||
|
||||
double x,y,z, zx,zy,zz, xx,xy,xz, a,b,c;
|
||||
const Node *left, *right;
|
||||
|
||||
Op op;
|
||||
Prim prim;
|
||||
|
||||
Node& operate(Op op, const Node& p) {
|
||||
left = new Node(*this);
|
||||
right = new Node(p);
|
||||
this->op = op;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Node(Prim p, double la, double lb=0., double lc=0.)
|
||||
: prim(p), op(OP_TERMINAL),
|
||||
x(0.), y(0.), z(0.),
|
||||
zx(0.), zy(0.), zz(1.),
|
||||
xx(1.), xy(0.), xz(0.),
|
||||
a(la), b(lb), c(lc) {}
|
||||
public:
|
||||
static Node Sphere(double r) {
|
||||
return Node(PRIM_SPHERE, r);
|
||||
}
|
||||
static Node Box(double dx, double dy, double dz) {
|
||||
return Node(PRIM_BOX, dx, dy, dz);
|
||||
}
|
||||
static Node Pyramid(double dx, double dy, double dz) {
|
||||
return Node(PRIM_PYRAMID, dx, dy, dz);
|
||||
}
|
||||
static Node Cylinder(double r, double h) {
|
||||
return Node(PRIM_CYLINDER, r, h);
|
||||
}
|
||||
static Node Cone(double r, double h) {
|
||||
return Node(PRIM_CONE, r, h);
|
||||
}
|
||||
|
||||
Node& move(
|
||||
double px = 0., double py = 0., double pz = 0.,
|
||||
double zx = 0., double zy = 0., double zz = 1.,
|
||||
double xx = 1., double xy = 0., double xz = 0.)
|
||||
{
|
||||
this->x = px; this->y = py; this->z = pz;
|
||||
this->zx = zx; this->zy = zy; this->zz = zz;
|
||||
this->xx = xx; this->xy = xy; this->xz = xz;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Node& add(const Node& p) {
|
||||
return operate(OP_ADD, p);
|
||||
}
|
||||
Node& subtract(const Node& p) {
|
||||
return operate(OP_SUBTRACT, p);
|
||||
}
|
||||
Node& intersect(const Node& p) {
|
||||
return operate(OP_INTERSECT, p);
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationItem* serialize(hierarchy_helper& file) const {
|
||||
IfcSchema::IfcRepresentationItem* my;
|
||||
if (op == OP_TERMINAL) {
|
||||
IfcSchema::IfcAxis2Placement3D* place = file.addPlacement3d(x,y,z,zx,zy,zz,xx,xy,xz);
|
||||
if (prim == PRIM_SPHERE) {
|
||||
my = new IfcSchema::IfcSphere(place, a);
|
||||
} else if (prim == PRIM_BOX) {
|
||||
my = new IfcSchema::IfcBlock(place, a, b, c);
|
||||
} else if (prim == PRIM_PYRAMID) {
|
||||
my = new IfcSchema::IfcRectangularPyramid(place, a, b, c);
|
||||
} else if (prim == PRIM_CYLINDER) {
|
||||
my = new IfcSchema::IfcRightCircularCylinder(place, b, a);
|
||||
} else if (prim == PRIM_CONE) {
|
||||
my = new IfcSchema::IfcRightCircularCone(place, b, a);
|
||||
}
|
||||
} else {
|
||||
IfcSchema::IfcBooleanOperator::IfcBooleanOperator o;
|
||||
if (op == OP_ADD) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION;
|
||||
} else if (op == OP_SUBTRACT) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE;
|
||||
} else if (op == OP_INTERSECT) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION;
|
||||
}
|
||||
my = new IfcSchema::IfcBooleanResult(o, left->serialize(file), right->serialize(file));
|
||||
}
|
||||
file.add_entity(my);
|
||||
return my;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "IfcCsgPrimitive.ifc";
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
|
||||
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
|
||||
).add(
|
||||
Node::Pyramid(8000.,6000.,3000.).move(0,0,3000.).add(
|
||||
Node::Cylinder(1000.,4000.).move(4000.,1000.,4000., 0.,1.,0.)
|
||||
).subtract(
|
||||
Node::Pyramid(7600.,5600.,2800.).move(200.,200.,3000.)
|
||||
).subtract(
|
||||
Node::Cylinder(900.,4000.).move(4000.,1000.,4000., 0.,1.,0.).intersect(
|
||||
Node::Box(2000.,4000.,1000.).move(3000.,1000.,4000.)
|
||||
)
|
||||
)
|
||||
).serialize(file);
|
||||
|
||||
const double x = 1000.; const double y = -4000.;
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg2 = Node::Sphere(5000.).move(x,y,-4500.).intersect(
|
||||
Node::Box(6000., 6000., 6000.).move(x-3000., y-3000., 0.)
|
||||
).add(
|
||||
Node::Cone(500., 3000.).move(x,y).add(
|
||||
Node::Cone(1500., 1000.).move(x,y, 900.).add(
|
||||
Node::Cone(1100., 1000.).move(x,y, 1800.).add(
|
||||
Node::Cone(750., 600.).move(x,y, 2700.)
|
||||
)))).serialize(file);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("IfcCsgPrimitive"), null, null, 0, 0, null, null);
|
||||
|
||||
file.addBuildingProduct(product);
|
||||
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(csg1);
|
||||
items->push(csg2);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("CSG"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcCompositeProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates profiles of trimmed ellipses. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcSegment
|
||||
typedef IfcSchema::IfcSegment curve_segment_tt;
|
||||
#else
|
||||
typedef IfcSchema::IfcCompositeCurveSegment curve_segment_tt;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
double r1;
|
||||
double r2;
|
||||
double t1;
|
||||
double t2;
|
||||
} EllipsePie;
|
||||
|
||||
static int i = 0;
|
||||
|
||||
void create_testcase_for(hierarchy_helper& file, const EllipsePie& pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference pref) {
|
||||
const double deg = 1. / 180. * 3.141592653;
|
||||
double flt1[] = {0. , 0. };
|
||||
double flt2[] = {pie.r1 * cos(pie.t1*deg), pie.r2 * sin(pie.t1*deg)};
|
||||
double flt3[] = {pie.r1 * cos(pie.t2*deg), pie.r2 * sin(pie.t2*deg)};
|
||||
|
||||
std::vector<double> coords1(flt1, flt1 + 2);
|
||||
std::vector<double> coords2(flt2, flt2 + 2);
|
||||
std::vector<double> coords3(flt3, flt3 + 2);
|
||||
|
||||
IfcSchema::IfcCartesianPoint* p1 = new IfcSchema::IfcCartesianPoint(coords1);
|
||||
IfcSchema::IfcCartesianPoint* p2 = new IfcSchema::IfcCartesianPoint(coords2);
|
||||
IfcSchema::IfcCartesianPoint* p3 = new IfcSchema::IfcCartesianPoint(coords3);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list());
|
||||
points->push(p3);
|
||||
points->push(p1);
|
||||
points->push(p2);
|
||||
file.addEntities(points->generalize());
|
||||
|
||||
|
||||
IfcSchema::IfcEllipse* ellipse = new IfcSchema::IfcEllipse(file.addPlacement2d(), pie.r1, pie.r2);
|
||||
file.addEntity(ellipse);
|
||||
aggregate_of_instance::ptr trim1(new aggregate_of_instance);
|
||||
aggregate_of_instance::ptr trim2(new aggregate_of_instance);
|
||||
if (pref == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
trim1->push(new IfcSchema::IfcParameterValue(pie.t1));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(pie.t2));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
}
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1->as<IfcSchema::IfcTrimmingSelect>(), trim2->as<IfcSchema::IfcTrimmingSelect>(), true, pref);
|
||||
file.addEntity(trim);
|
||||
|
||||
curve_segment_tt::list::ptr segments(new curve_segment_tt::list());
|
||||
IfcSchema::IfcCompositeCurveSegment* s2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
IfcSchema::IfcCompositeCurveSegment* s1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly);
|
||||
segments->push(s1);
|
||||
|
||||
segments->push(s2);
|
||||
file.addEntities(segments->generalize());
|
||||
|
||||
IfcSchema::IfcCompositeCurve* ccurve = new IfcSchema::IfcCompositeCurve(segments, false);
|
||||
IfcSchema::IfcArbitraryClosedProfileDef* profile = new IfcSchema::IfcArbitraryClosedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, ccurve);
|
||||
file.addEntity(ccurve);
|
||||
file.addEntity(profile);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("profile"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 200 * i++));
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.add_entity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::string filename = "ellipse_pies.ifc";
|
||||
hierarchy_helper file;
|
||||
{ EllipsePie pie = {80., 50., 0., 150.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {80, 50., 30., 300.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {80, 50., 300., 30.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50., 80., 0., 150.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50, 80., 30., 300.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50, 80., 300., 30.};
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates various forms of IfcFace *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
static int x = 0;
|
||||
|
||||
void create_testcase(hierarchy_helper& file, IfcSchema::IfcFace* face, const std::string& name) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
faces->push(face);
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, name, null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 1000 * x++, 0));
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(model);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
hierarchy_helper file;
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "circle");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* outer_bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +300, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-300, +300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceBound* inner_bound1 = new IfcSchema::IfcFaceBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points3 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, +300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+300, -300, 0));
|
||||
points3->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -300, 0));
|
||||
IfcSchema::IfcPolyLoop* loop3 = new IfcSchema::IfcPolyLoop(points3);
|
||||
IfcSchema::IfcFaceBound* inner_bound2 = new IfcSchema::IfcFaceBound(loop3, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(inner_bound1);
|
||||
bounds->push(outer_bound);
|
||||
bounds->push(inner_bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "polyloop with holes");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-100, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound1 = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2 (new IfcSchema::IfcCartesianPoint::list);
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points2->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+100, -400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop2 = new IfcSchema::IfcPolyLoop(points2);
|
||||
IfcSchema::IfcFaceOuterBound* bound2 = new IfcSchema::IfcFaceOuterBound(loop2, false);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound1);
|
||||
bounds->push(bound2);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "multiple outer boundaries (invalid)");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 1e-6));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, -400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, +400, 0));
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, +400, 0));
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFace(bounds);
|
||||
create_testcase(file, face, "imprecise polyloop");
|
||||
}
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint* point1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(+400, 0., 0.);
|
||||
IfcSchema::IfcCartesianPoint* point2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, 0., 0.);
|
||||
IfcSchema::IfcVertexPoint* vertex1 = new IfcSchema::IfcVertexPoint(point1);
|
||||
IfcSchema::IfcVertexPoint* vertex2 = new IfcSchema::IfcVertexPoint(point2);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(file.addPlacement2d(), 400.);
|
||||
IfcSchema::IfcEdgeCurve* edge1 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, circle, true);
|
||||
IfcSchema::IfcEdgeCurve* edge2 = new IfcSchema::IfcEdgeCurve(vertex2, vertex1, circle, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge1 = new IfcSchema::IfcOrientedEdge(edge1, true);
|
||||
IfcSchema::IfcOrientedEdge* oriented_edge2 = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
edges->push(oriented_edge1);
|
||||
edges->push(oriented_edge2);
|
||||
IfcSchema::IfcEdgeLoop* loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds (new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim1(new IfcSchema::IfcCartesianPoint::list);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
|
||||
trim1->push(point1);
|
||||
trim2->push(point2);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
|
||||
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
|
||||
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
|
||||
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
|
||||
create_testcase(file, face, "face surface");
|
||||
}
|
||||
const std::string filename = "faces.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example of curve rebar. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
const static double PI = boost::math::constants::pi<double>();
|
||||
|
||||
typedef std::string S;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcSegment
|
||||
typedef IfcSchema::IfcSegment curve_segment_t;
|
||||
#else
|
||||
typedef IfcSchema::IfcCompositeCurveSegment curve_segment_t;
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcReinforcingBar_HAS_PredefinedType
|
||||
#define IFC_REINFORCING_BAR_TYPE IfcSchema::IfcReinforcingBarTypeEnum::IfcReinforcingBarType_LIGATURE
|
||||
#else
|
||||
#define IFC_REINFORCING_BAR_TYPE IfcSchema::IfcReinforcingBarRoleEnum::IfcReinforcingBarRole_LIGATURE
|
||||
#endif
|
||||
|
||||
void create_curve_rebar(hierarchy_helper<IfcSchema>& file)
|
||||
{
|
||||
int dia = 24;
|
||||
int R = 3 * dia;
|
||||
int length = 12 * dia;
|
||||
|
||||
double crossSectionarea = M_PI * (dia / 2) * 2;
|
||||
IfcSchema::IfcReinforcingBar* rebar = new IfcSchema::IfcReinforcingBar(
|
||||
guid(), 0, S("test"), null,
|
||||
null, 0, 0,
|
||||
null, S("SR24"), //SteelGrade
|
||||
dia, //diameter
|
||||
crossSectionarea, //crossSectionarea = math.pi*(12.0/2)**2
|
||||
0,
|
||||
IFC_REINFORCING_BAR_TYPE,
|
||||
IfcSchema::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurfaceEnum::IfcReinforcingBarSurface_PLAIN //PLAIN or TEXTURED
|
||||
);
|
||||
|
||||
file.addBuildingProduct(rebar);
|
||||
rebar->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
curve_segment_t::list::ptr segments(new curve_segment_t::list());
|
||||
|
||||
IfcSchema::IfcCartesianPoint* p1 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 1000.);
|
||||
IfcSchema::IfcCartesianPoint* p2 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, 0, 0);
|
||||
IfcSchema::IfcCartesianPoint* p3 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, 0);
|
||||
IfcSchema::IfcCartesianPoint* p4 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R, -R);
|
||||
IfcSchema::IfcCartesianPoint* p5 = file.addTriplet<IfcSchema::IfcCartesianPoint>(0, R + length, -R);
|
||||
|
||||
/*first segment - line */
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points1(new IfcSchema::IfcCartesianPoint::list());
|
||||
points1->push(p1);
|
||||
points1->push(p2);
|
||||
file.addEntities(points1->generalize());
|
||||
IfcSchema::IfcPolyline* poly1 = new IfcSchema::IfcPolyline(points1);
|
||||
file.add_entity(poly1);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly1);
|
||||
file.add_entity(segment1);
|
||||
segments->push(segment1);
|
||||
|
||||
/*second segment - arc */
|
||||
IfcSchema::IfcAxis2Placement3D* axis1 = new IfcSchema::IfcAxis2Placement3D(p3, file.addTriplet<IfcSchema::IfcDirection>(1, 0, 0), file.addTriplet<IfcSchema::IfcDirection>(0, 1, 0));
|
||||
file.add_entity(axis1);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(axis1, R);
|
||||
file.add_entity(circle);
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
|
||||
trim1->push(new IfcSchema::IfcParameterValue(180));
|
||||
trim1->push(p2);
|
||||
|
||||
trim2->push(new IfcSchema::IfcParameterValue(270));
|
||||
trim2->push(p4);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1, trim2, false, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.add_entity(trimmed_curve);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, false, trimmed_curve);
|
||||
file.add_entity(segment2);
|
||||
segments->push(segment2);
|
||||
|
||||
/*third segment - line */
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points2(new IfcSchema::IfcCartesianPoint::list());
|
||||
points2->push(p4);
|
||||
points2->push(p5);
|
||||
file.addEntities(points2->generalize());
|
||||
IfcSchema::IfcPolyline* poly2 = new IfcSchema::IfcPolyline(points2);
|
||||
file.add_entity(poly2);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment3 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly2);
|
||||
file.add_entity(segment3);
|
||||
segments->push(segment3);
|
||||
|
||||
IfcSchema::IfcCompositeCurve* curve = new IfcSchema::IfcCompositeCurve(segments, false);
|
||||
file.add_entity(curve);
|
||||
|
||||
IfcSchema::IfcSweptDiskSolid* solid = new IfcSchema::IfcSweptDiskSolid(curve, dia / 2, null, 0, 1);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("AdvancedSweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.add_entity(shape);
|
||||
|
||||
rebar->setRepresentation(shape);
|
||||
|
||||
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
|
||||
rebar->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 0, 0));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name("ifc_curve_rebar.ifc");
|
||||
create_curve_rebar(file);
|
||||
std::ofstream f("ifc_curve_rebar.ifc");
|
||||
f << file;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the Lesser GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* Lesser GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the Lesser GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
/********************************************************************************
|
||||
* *
|
||||
* Example that generates extrusions of parameterized profiles. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "ifcparse/macros.h"
|
||||
|
||||
#ifndef IfcSchema
|
||||
#define IfcSchema Ifc2x3
|
||||
#endif
|
||||
|
||||
#include INCLUDE_SCHEMA(ifcparse/schemas, IfcSchema)
|
||||
#include INCLUDE_SCHEMA_DEFINITIONS(ifcparse/schemas, IfcSchema)
|
||||
|
||||
#include "ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
#ifdef SCHEMA_IfcUShapeProfileDef_HAS_CentreOfGravityInX
|
||||
#define IFC_U_SHAPE_PROFILE_DEF_EXTRA_ARGS , null
|
||||
#else
|
||||
#define IFC_U_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcTShapeProfileDef_HAS_CentreOfGravityInY
|
||||
#define IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS , null
|
||||
#else
|
||||
#define IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcIShapeProfileDef_HAS_FlangeEdgeRadius
|
||||
#define IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS , null, null
|
||||
#else
|
||||
#define IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcAsymmetricIShapeProfileDef_HAS_BottomFlangeSlope
|
||||
#define IFC_ASYMMETRIC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS , null, null, null
|
||||
#else
|
||||
#define IFC_ASYMMETRIC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcLShapeProfileDef_HAS_CentreOfGravityInX
|
||||
#define IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS , null, null
|
||||
#else
|
||||
#define IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
#ifdef SCHEMA_IfcCShapeProfileDef_HAS_CentreOfGravityInX
|
||||
#define IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS , null
|
||||
#else
|
||||
#define IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS
|
||||
#endif
|
||||
|
||||
void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
IfcSchema::IfcProfileDef* profile = *profiles->begin();
|
||||
const std::string profile_type = IfcSchema::Type::ToString(profile->type());
|
||||
const std::string filename = profile_type + ".ifc";
|
||||
|
||||
hierarchy_helper file;
|
||||
file.filename(filename);
|
||||
|
||||
int i = 0;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
|
||||
IfcSchema::IfcProfileDef* profile = *it;
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("profile"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName(profile_type);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 100. * i));
|
||||
|
||||
if (profile->is(IfcSchema::Type::IfcParameterizedProfileDef)) {
|
||||
((IfcSchema::IfcParameterizedProfileDef*) profile)->setPosition(file.addPlacement2d());
|
||||
}
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.add_entity(profile);
|
||||
file.add_entity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
|
||||
items->push(solid);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null IFC_U_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0, null IFC_U_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, 4.0 IFC_U_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 1.0, 3.0, 6.0 IFC_U_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null, null IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0, 2.0, null, null IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, 2.0, 2.0 IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 3.0, 2.0, 1.0, 2.0, 2.0 IFC_T_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 15.0));
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 15.0, 25.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, null IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0 IFC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcAsymmetricIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0, 20.0, 10.0, 5.0, null IFC_ASYMMETRIC_I_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, null IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 2.0, null IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, 2.0 IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 1.0, 2.0, 2.0 IFC_L_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, null IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
profiles->push(new IfcSchema::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, 2.0 IFC_C_SHAPE_PROFILE_DEF_EXTRA_ARGS));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcCircleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0));
|
||||
profiles->push(new Ifc2x3::IfcCircleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 5.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0));
|
||||
profiles->push(new Ifc2x3::IfcRoundedRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0));
|
||||
profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null));
|
||||
profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 4.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 30.0, 25.0, 0.0));
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 60.0, 25.0, -20.0));
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 10.0, 25.0, 30.0));
|
||||
create_testcase_for(profiles); }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user