Compare commits

...

18 Commits

Author SHA1 Message Date
Dion Moult 7845f8e8cd ci: build OCCT shared on Linux so plug-ins share one OCCT instance
`geom.tree().select()` silently returns zero results (or raises SWIG's
"An unknown error occurred") in the Linux release packages, while the same
commit built from source returns correct answers. `select_box()` agrees
between both, and geometry conversion is bit-identical -- only operations
that touch a stored TopoDS_Shape diverge.

Cause is linkage, not code. 8bdaa8c7c narrowed the Rocky builds from
`--shared` to `--ifcopenshell-shared`, which shares IfcOpenShell's own
libraries but leaves every dependency static. OCCT is then compiled
privately into each plug-in that uses it -- 15 of them, verified by their
own copies of the BRepClass3d/BRepExtrema/Standard_Failure strings.

That contradicts what the binaries already declare. tree.h:1748 casts a
`conversion_result_shape*` to `open_cascade_shape*`, moves the
TopoDS_Shape out of it and frees it; `open_cascade_shape` is defined once
in ifcopenshell_geometry_kernel_opencascade.so and left undefined in
ifcopenshell_geometry_tree_opencascade_brep.so for the loader to resolve.
So the two plug-ins are designed to share one OCCT-based type system, yet
static linking gives each its own Standard_Type registry and allocator.
Shapes get read and released by a different OCCT instance than made them.

Add `--opencascade-shared`, mirroring the existing `--ifcopenshell-shared`
precedent, and use it on both Rocky workflows. It cannot be spelled
`--occt-shared`: build-all.py parses any `occt-*` flag as a version
override.

BUILD_STATIC drives three things at once -- dependency link type,
-fvisibility=hidden, and BUILD_SHARED_LIBS -- so making one dependency
shared means overriding all three for it. Visibility is the subtle one:
OCCT's Standard_EXPORT expands to nothing on Unix, so it relies on default
visibility to export its API. Built shared under -fvisibility=hidden it
exports almost nothing and its own libraries cannot resolve against each
other (libTKMath.so fails to find
NCollection_BaseAllocator::CommonBaseAllocator in libTKernel.so). Static
archives are immune, which is why this surfaces only once OCCT goes
shared. Compile OCCT with the pre-visibility flag set instead.

Link the OCCT set with --as-needed. FindOpenCASCADE.cmake's config branch
uses OCCT's *complete* module list, Visualization included, which against a
static OCCT costs nothing -- an unreferenced module contributes no objects.
Against a shared OCCT all 47 become hard DT_NEEDED entries, and libTKV3d
pulls libGL.so.1 + libEGL.so.1, so `import ifcopenshell` fails on any
headless machine with "libEGL.so.1: cannot open shared object file" even
though nothing ever opens a window. Measured through the real find_package
path with the LINK_GROUP workaround composed: 67 DT_NEEDED without the
flag, 3 with it, TKV3d and TKOpenGl gone.

The flag is deliberately left open rather than closed with
-Wl,--no-as-needed. CMake emits the imported targets'
INTERFACE_LINK_LIBRARIES -- where OCCT lists libGL/libEGL -- after that
item, so closing the bracket switches the flag off immediately before the
libraries it exists to exclude. Verified against the shipped artifact:
closed, the kernel plug-in fell from 47 DT_NEEDED libTK entries to 14 and
lost TKV3d, yet still carried a direct libEGL.so.1 and still failed to
import on a headless server; open, the same 14 remain and libGL/libEGL are
gone. None of the 14 retained modules depends on GL.

Put the shared OCCT on LD_LIBRARY_PATH for the build itself. Nothing else
points at it -- IfcOpenShell's libraries get INSTALL_RPATH=$ORIGIN and OCCT
sits in its own dependency prefix -- so the post-build `import ifcopenshell`
check fails the same way. This is build-time only; the shipped packages get
libTK*.so* staged beside the payload with an $ORIGIN RUNPATH instead.

Suffix OCCT's install directory with `-shared` when it applies. Static and
shared installs are not interchangeable, but `build_dependency` skips any
dependency whose install dir already exists and cache_dependencies.py keys
its tarballs purely on that directory name -- so the static
`cache-occt-7.8.1.tar.gz` restored from the build-outputs repo silently
satisfied the build and BUILD_LIBRARY_TYPE was never applied. This is the
same cache stickiness 8bdaa8c7c described, pointing the other way. The
suffix makes the key configuration-aware, so it self-invalidates and the
static tarball stays valid for builds that still want static.

Packaging is the other half, and is why 8bdaa8c7c backed the flag out --
`stage_runtime_payload` only copies from install/ifcopenshell, so OCCT in
install/occt-* was never staged and `--shared` "worked by accident" off
cached static outputs. Stage libTK*.so* alongside, then give every staged
library an $ORIGIN RUNPATH: the core libs currently carry dead
build-machine RPATHs and the plug-ins carry none, resolving only because
the Python wrapper pulls them in by SONAME first. Shared OCCT has no such
first loader, since it is reached through the dlopen'd plug-ins.

The packages shrink: the python zip goes from 109.4 MB to 85.6 MB, because
the duplicated OCCT was 113 MB of the 287 MB unpacked payload (the eight
geometry_writer_ifc* plug-ins alone were 4.6 MB each) against ~67 MB for
one shared copy. Same argument as a91b1da28 ("Reduce Rocky package size")
and 402591e71.

macOS and Windows are affected too but are not fixed here. Their
packaging resolves via @loader_path install names and would need
install_name_tool rewriting, which cannot be verified from Linux; adding
the flag without that would ship a package that fails to load.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 08:19:27 +10:00
Dion Moult 2c1d445d5b ifcviewer-web: mint session model ids when a load is requested
A federated pick could be attributed to the wrong file. The model slot a
host sees — ElementRef::model_index, modelProgress's index — is a rank in
session_model_id order, and on web that id was minted at the END of the
sidecar read chain, after three network round trips. So the ranking was
the order the models' reads happened to finish in, not the order the host
added them. With ~40 similarly-sized models over HTTP, adjacent models
swapped and a click reported its neighbour's file; the host page then
asked for a GUID the file does not contain.

Mint the id at the top of loadSidecarMetadataWeb instead, which runs
synchronously from load_sidecar_from_source_c and therefore in the order
the host asked for its models. A load that fails partway just abandons
its id, and the ranks compact over the surviving models as before.

Positions are still positions, though: if one model fails to load, every
later index shifts down one and a host mapping index into its own list
silently drifts again. So also carry the source id — the handle the host
minted itself when it registered the file — through ElementRef into the
pick payload and getObjects rows, and document it as the way to attribute
an object to a file. ModelGpuData::web_source_id defaults to -1 now, since
0 is a real source id and cannot double as "none".

The test server grows a ?delay=<ms> knob so a test can force the losing
interleaving: georef-a is added first and served slowly, and its objects
must still come back as model 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 11:30:56 +10:00
Dion Moult d86f89090b ifcviewer-web: draw the axis indicator (corner gizmo + orbit pivot)
The desktop viewport draws an RGB triad in the bottom-left corner and a
second one at the orbit target while navigating; the web build drew
neither. Both lived in the Qt-coupled OverlayRenderer, which only
ViewportWindow drives — the web host no-ops the overlay hooks — so the
wasm build had no path to them at all.

Lift them into AxisIndicatorRenderer, a Qt-free renderer in
IfcViewerCore, and drive it from ViewportCore::render for desktop and
web alike. Same move SectionGizmoRenderer already made; the drawing code
is unchanged apart from swapping qDegreesToRadians for CameraMath's kPiF.

Pivot visibility moves to the core with it: it was a QTimer on
ViewportWindow, so the afterglow couldn't follow the gizmo across. It is
now a Stopwatch deadline next to the drawing, with render() requesting
frames until an armed afterglow expires. Hosts keep the same three
triggers (on for orbit/pan drags, off on release, 600 ms on wheel).

The web demo shell's log overlay sat exactly on top of the corner gizmo,
so it shifts right of the 110 px box.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 11:16:41 +10:00
Andrej730 973f61c6dc express.h: remove non-snake case aliases (schemas are regenerated now) 2026-08-19 20:17:51 +05:00
Andrej730 f47aa4d81a Manually update other schemas 2026-08-19 20:17:51 +05:00
Andrej730 fa9a3383aa Use snake case in cpp consistently 2026-08-19 20:17:51 +05:00
Andrej730 104591a80b Normalize whitespaces in the codebase 2026-08-19 20:17:50 +05:00
Andrej730 030e6e5bb4 Regen cpp schemas 2026-08-19 20:17:50 +05:00
Andrej730 a031310a66 express/run.bat: rewrite in Python 2026-08-19 20:17:50 +05:00
Andrej730 436e3f7b2a Header_section_schema-definitions.h: use IFC_SCHEMA_API 2026-08-19 20:17:50 +05:00
Andrej730 335d571854 gltf_serializer: refactor proj code into a separate call 2026-08-19 20:17:49 +05:00
Andrej730 f78b380b71 express/mapping: fix breaking generation after f23db9440f
It was failing to map `int64_t` to `Argument_INT` enum.
2026-08-19 19:38:30 +05:00
Andrej730 2cebc3f60b typing 2026-08-19 19:38:30 +05:00
Andrej730 0a8159505d pyproject: black to format all files by default 2026-08-19 19:38:30 +05:00
Andrej730 301fba5a8b Bump ty to 0.0.72 2026-08-19 19:38:30 +05:00
Andrej730 ba90cf220d black, ruff 2026-08-19 19:38:29 +05:00
Andrej730 6318892a97 Script to check whitespace issues in the codebase 2026-08-19 19:33:08 +05:00
Dion Moult 1a6336bd20 Output test audits to sqlite 2026-08-18 13:50:14 +10:00
197 changed files with 45669 additions and 44685 deletions
+377
View File
@@ -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())
+24 -1
View File
@@ -80,7 +80,7 @@ jobs:
set -o pipefail
CXXFLAGS="-O3" CFLAGS="-O3" ADD_COMMIT_SHA=1 BUILD_CFG=Release BUILD_BONSAIVIEWER=ON \
uv run --with aqtinstall ./nix/build-all.py \
-v --diskcleanup --ifcopenshell-shared 2>&1 \
-v --diskcleanup --ifcopenshell-shared --opencascade-shared 2>&1 \
| tee build.log
- name: Upload Build Logs
@@ -147,6 +147,22 @@ jobs:
done
}
# Copy the shared OCCT from the dependency prefix to the provided `$1`.
# OCCT is built shared (`--opencascade-shared`) so that the opencascade kernel
# and tree plug-ins share a single OCCT instance: `open_cascade_shape` objects
# are created by the kernel plug-in and then have their `TopoDS_Shape` moved out
# and freed by a tree plug-in. A private static OCCT per plug-in gives each its
# own Standard_Type registry and allocator, which silently corrupts those shapes.
# These libs live under `install/occt-*` rather than `install/ifcopenshell`,
# so `stage_runtime_payload` does not pick them up on its own.
stage_occt_runtime_payload() {
dest="$1"
for occt_lib_dir in "$(dirname "$install_root")"/occt-*/lib "$(dirname "$install_root")"/occt-*/lib64; do
[ -d "$occt_lib_dir" ] || continue
find "$occt_lib_dir" -maxdepth 1 \( -type f -o -type l \) -name "libTK*.so*" -exec cp -P {} "$dest/" \;
done
}
# Copy all libs from `install/ifcopenshell` to the provided `$1`.
# Set `$2` to `0` to skip including geometry writers.
stage_runtime_payload() {
@@ -163,7 +179,14 @@ jobs:
find "$runtime_dir" \( -type f -o -type l \) \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
done
)
stage_occt_runtime_payload "$dest"
ensure_soname_links "$dest"
# The core libs ship with dead build-machine RPATHs and the plug-ins have
# none; today they resolve only because the Python wrapper ($ORIGIN) pulls
# them in by SONAME before any plug-in is dlopen'd. Shared OCCT has no such
# first loader -- it is reached through the plug-ins -- so give every staged
# library an $ORIGIN of its own.
find "$dest" -maxdepth 1 -type f -name "*.so*" -exec patchelf --set-rpath '$ORIGIN' {} \;
}
# Copy all libs from `QT_DIR` to the provided `$2`.
+24 -1
View File
@@ -92,7 +92,7 @@ jobs:
set -o pipefail
CXXFLAGS="-O3" CFLAGS="-O3" ADD_COMMIT_SHA=1 BUILD_CFG=Release BUILD_BONSAIVIEWER=ON \
uv run --with aqtinstall ./nix/build-all.py \
-v --diskcleanup --ifcopenshell-shared 2>&1 \
-v --diskcleanup --ifcopenshell-shared --opencascade-shared 2>&1 \
| tee build.log
- name: Upload Build Logs
@@ -156,6 +156,22 @@ jobs:
done
}
# Copy the shared OCCT from the dependency prefix to the provided `$1`.
# OCCT is built shared (`--opencascade-shared`) so that the opencascade kernel
# and tree plug-ins share a single OCCT instance: `open_cascade_shape` objects
# are created by the kernel plug-in and then have their `TopoDS_Shape` moved out
# and freed by a tree plug-in. A private static OCCT per plug-in gives each its
# own Standard_Type registry and allocator, which silently corrupts those shapes.
# These libs live under `install/occt-*` rather than `install/ifcopenshell`,
# so `stage_runtime_payload` does not pick them up on its own.
stage_occt_runtime_payload() {
dest="$1"
for occt_lib_dir in "$(dirname "$install_root")"/occt-*/lib "$(dirname "$install_root")"/occt-*/lib64; do
[ -d "$occt_lib_dir" ] || continue
find "$occt_lib_dir" -maxdepth 1 \( -type f -o -type l \) -name "libTK*.so*" -exec cp -P {} "$dest/" \;
done
}
stage_runtime_payload() {
dest="$1"
include_geometry_writers="${2:-1}"
@@ -170,7 +186,14 @@ jobs:
find "$runtime_dir" \( -type f -o -type l \) \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
done
)
stage_occt_runtime_payload "$dest"
ensure_soname_links "$dest"
# The core libs ship with dead build-machine RPATHs and the plug-ins have
# none; today they resolve only because the Python wrapper ($ORIGIN) pulls
# them in by SONAME before any plug-in is dlopen'd. Shared OCCT has no such
# first loader -- it is reached through the plug-ins -- so give every staged
# library an $ORIGIN of its own.
find "$dest" -maxdepth 1 -type f -name "*.so*" -exec patchelf --set-rpath '$ORIGIN' {} \;
}
stage_qt_runtime_payload() {
+35
View File
@@ -54,6 +54,41 @@ if(NOT OCC_INCLUDE_DIR AND NOT OCC_LIBRARY_DIR)
set(OpenCASCADE_LIBRARIES "$<LINK_GROUP:RESCAN,${OpenCASCADE_LIBRARIES}>")
endif()
if(UNIX AND NOT APPLE)
# Record only the OCCT modules whose symbols are actually referenced.
#
# OpenCASCADE_LIBRARIES is OCCT's *complete* module list, Visualization
# included -- TKV3d, TKOpenGl, TKService. Against a static OCCT that
# costs nothing, because an unreferenced module contributes no objects.
# Against a shared OCCT every entry becomes a hard DT_NEEDED, and
# libTKV3d pulls libGL.so.1 + libEGL.so.1, so `import ifcopenshell`
# dies on any headless machine with
# ImportError: libEGL.so.1: cannot open shared object file
# even though IfcOpenShell never opens a window. Measured on a full
# 67-module link: 67 DT_NEEDED entries without the flag, 3 with it,
# and TKV3d/TKOpenGl gone in the second case.
#
# Goes before the LINK_GROUP above rather than inside it, and is a
# no-op for a static OCCT (--as-needed only governs shared libraries),
# so this is safe for both link types.
#
# Deliberately NOT closed with -Wl,--no-as-needed. CMake emits the
# imported targets' INTERFACE_LINK_LIBRARIES -- which is where OCCT
# lists libGL/libEGL -- *after* this item, so a closing bracket
# switches the flag back off just before the libraries it was added to
# exclude. Measured: with the bracket closed the plug-ins dropped from
# 47 DT_NEEDED libTK entries to 14 and lost TKV3d, yet still carried a
# direct libEGL.so.1 and failed to import on a headless server; with it
# left open the same 14 remain and libGL/libEGL are gone.
#
# The cost is that --as-needed stays in effect for whatever follows on
# the link line. That is the default on Debian/Ubuntu so it is
# well-trodden, but it does mean a library needed only for
# static-initialiser side effects could be dropped -- the thing to
# suspect first if a serialiser stops registering itself.
set(OpenCASCADE_LIBRARIES "-Wl,--as-needed" "${OpenCASCADE_LIBRARIES}")
endif()
if(OpenCASCADE_VERSION VERSION_LESS "7.9.0" AND WIN32)
# Bug in OCCT cmake configs < 7.9.0 - missing linked library.
list(APPEND OpenCASCADE_LIBRARIES WSOCK32.lib)
+61 -4
View File
@@ -42,6 +42,13 @@ Available arguments:
``-shared`` - build shared libraries. By default will build static.
``-ifcopenshell-shared`` - build only IfcOpenShell's own libraries as shared
(dependencies stay static). Redundant if ``-shared`` is also passed.
``-opencascade-shared`` - build OCCT as shared libraries (other dependencies stay
static). Redundant if ``-shared`` is also passed. Required whenever more than one
plug-in uses OCCT: `open_cascade_shape` instances are created by the opencascade
kernel plug-in and consumed by the opencascade tree plug-ins, which move a
`TopoDS_Shape` out of them and free them. A private static OCCT per plug-in gives
each one its own `Standard_Type` registry and allocator, so those shapes are read
and released by a different OCCT instance than the one that made them.
``-diskcleanup`` - clean up build directories after finishing building dependencies
``-build-examples`` - build IfcOpenShell examples
``-lto`` - enable link-time optimization (adds ``-flto`` to compiler flags)
@@ -410,6 +417,8 @@ BUILD_STATIC = "shared" not in flags
"""Whether dependencies are built static."""
IFCOPENSHELL_STATIC = BUILD_STATIC and "ifcopenshell-shared" not in flags
"""Whether IfcOpenShell's own libraries are built static."""
OCCT_STATIC = BUILD_STATIC and "opencascade-shared" not in flags
"""Whether OCCT is built static. See ``-opencascade-shared``."""
ENABLE_FLAG = "--enable-static" if BUILD_STATIC else "--enable-shared"
DISABLE_FLAG = "--disable-shared" if BUILD_STATIC else "--disable-static"
LINK_TYPE = "static" if BUILD_STATIC else "shared"
@@ -423,6 +432,32 @@ if any(f.startswith("py-") for f in flags):
if any(f.startswith("occt-") for f in flags):
OCCT_VERSION = next(f.split("-", 1)[1] for f in flags if f.startswith("occt-"))
# Static and shared OCCT installs are not interchangeable, so they must not share
# a directory: `build_dependency` skips a dependency whose install dir already
# exists, and cache_dependencies.py keys its tarballs purely on that directory
# name. Without the suffix a cached static OCCT silently satisfies a shared build
# (and vice versa) and the requested link type is never applied.
OCCT_DIR_NAME = f"occt-{OCCT_VERSION}" + ("" if OCCT_STATIC else "-shared")
if not OCCT_STATIC:
# A shared OCCT has to be resolvable at run time by everything this script
# executes out of the install tree -- most visibly the post-build
# `import ifcopenshell` sanity check, which otherwise dies with
# "libTKernel.so.7.8: cannot open shared object file". Nothing points there:
# IfcOpenShell's libraries get INSTALL_RPATH=$ORIGIN (see SET_INSTALL_SELF_RPATH
# in cmake/utilities.cmake) and OCCT lives in its own dependency prefix.
#
# This is a build-time concern only. The shipped packages do not rely on it:
# the workflows stage libTK*.so* next to the payload and patchelf an $ORIGIN
# RUNPATH onto every staged library.
_occt_lib_dirs = [
os.path.join(DEPS_DIR, "install", OCCT_DIR_NAME, libdir)
for libdir in ("lib", "lib64")
]
os.environ["LD_LIBRARY_PATH"] = os.pathsep.join(
[*_occt_lib_dirs, os.environ.get("LD_LIBRARY_PATH", "")]
).rstrip(os.pathsep)
if explicit_targets:
targets = {dep for target in explicit_targets for dep in gather_dependencies(target)}
else:
@@ -1045,12 +1080,34 @@ if USE_OCCT and "occ" in targets:
if WASM:
patches.append("./patches/occt/no_em_js.patch")
if not OCCT_STATIC:
# BUILD_STATIC drives three things at once: the dependency link type,
# -fvisibility=hidden, and BUILD_SHARED_LIBS. Building only OCCT shared
# means overriding all three for it, not just the link type.
#
# Visibility matters most. OCCT's Standard_EXPORT expands to nothing on
# Unix (Standard_Macro.hxx), so it relies on default visibility to export
# its API. Built shared under -fvisibility=hidden it exports almost
# nothing and its libraries fail to resolve against each other -- e.g.
# libTKMath.so cannot find NCollection_BaseAllocator::CommonBaseAllocator
# in libTKernel.so. Static archives are immune, which is why this only
# appears once OCCT goes shared. CXXFLAGS_MINIMAL is the pre-visibility
# flag set, so this restores default visibility without dropping -O3/-fPIC.
#
# These come after the generic flags in the cmake command line, and the
# last -D for a given variable wins.
occt_args.append(f"-DCMAKE_CXX_FLAGS={CXXFLAGS_MINIMAL}")
occt_args.append(f"-DCMAKE_C_FLAGS={CFLAGS_MINIMAL}")
# Suppresses the generic -DBUILD_SHARED_LIBS=OFF that BUILD_STATIC would
# otherwise add, which contradicts BUILD_LIBRARY_TYPE=Shared.
occt_args.append("-DBUILD_SHARED_LIBS=ON")
build_dependency(
name=f"occt-{OCCT_VERSION}",
name=OCCT_DIR_NAME,
mode="cmake",
build_tool_args=[
f"-DINSTALL_DIR={DEPS_DIR}/install/occt-{OCCT_VERSION}",
f"-DBUILD_LIBRARY_TYPE={LINK_TYPE_UCFIRST}",
f"-DINSTALL_DIR={DEPS_DIR}/install/{OCCT_DIR_NAME}",
f"-DBUILD_LIBRARY_TYPE={'Static' if OCCT_STATIC else 'Shared'}",
f"-DBUILD_MODULE_Draw=0",
f"-DBUILD_RELEASE_DISABLE_EXCEPTIONS=Off",
# Disable xlib explicitly, as it tries to use it on Desktop Ubuntu, adding unnecessary dependency.
@@ -1487,7 +1544,7 @@ if "cgal" in targets:
cmake_args.append(f"-DCGAL_WITH_GMPXX=Off")
if "occ" in targets and USE_OCCT:
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/occt-{OCCT_VERSION}")
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/{OCCT_DIR_NAME}")
elif "occ" in targets:
# We don't support find_package for OCE.
+1
View File
@@ -1,5 +1,6 @@
#!/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
+13 -5
View File
@@ -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]
@@ -112,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"
@@ -181,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 -1
View File
@@ -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
+6 -6
View File
@@ -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();
@@ -102,7 +102,7 @@ int main() {
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
// return `0` otherwise.
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"));
@@ -122,7 +122,7 @@ int main() {
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"));
@@ -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);
+6 -6
View File
@@ -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
+20 -20
View File
@@ -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,9 +295,9 @@ 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);
@@ -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);
+2 -2
View File
@@ -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
@@ -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();
+28 -28
View File
@@ -336,7 +336,7 @@ int main(int argc, char** argv) {
std::string exterior_only_algo;
ifcopenshell::geom::settings settings;
po::options_description geom_options("Geometry options");
geom_options.add_options()
("kernel", po::value<std::string>(&geometry_kernel)->default_value(default_kernel),
@@ -389,7 +389,7 @@ int main(int argc, char** argv) {
("model", "Specifies whether to include surfaces and solids in the output result. "
"Typically these are representations of type Body or Facetation. ")
;
settings.define_options(geom_options);
std::string bounds;
@@ -466,7 +466,7 @@ int main(int argc, char** argv) {
num_threads = std::thread::hardware_concurrency();
logger.notice("SYS", 7, "Using " + std::to_string(num_threads) + " threads");
}
if (vmap.count("log-format") == 1) {
boost::to_lower(log_format);
if (log_format == "plain") {
@@ -479,7 +479,7 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
}
if (!filter_filename.empty()) {
size_t num_filters = read_filters_from_file(ifcopenshell::path::to_utf8(filter_filename), include_filter, include_traverse_filter, exclude_filter, exclude_traverse_filter);
if (num_filters) {
@@ -524,10 +524,10 @@ int main(int argc, char** argv) {
// If no output filename is specified a Wavefront OBJ file will be output
// to maintain backwards compatibility with the obsolete IfcObj executable.
const path_t output_filename = vmap.count("output-file") == 1
const path_t output_filename = vmap.count("output-file") == 1
? vmap["output-file"].as<path_t>()
: change_extension(input_filename, ifcopenshell::path::from_utf8(DEFAULT_EXTENSION));
if (output_filename.size() < 5) {
cerr_ << "[error] Invalid or unsupported output file '" << output_filename << "' given" << std::endl;
print_usage();
@@ -572,13 +572,13 @@ int main(int argc, char** argv) {
}
path_t output_temp_filename = output_filename + ifcopenshell::path::from_utf8(TEMP_FILE_EXTENSION);
std::vector<path_t> tokens;
split(tokens, output_filename, boost::is_any_of("."));
std::vector<path_t>::iterator tok_iter;
path_t ext = *(tokens.end() - 1);
path_t dot;
dot = '.';
dot = '.';
path_t output_extension = dot + ext;
boost::to_lower(output_extension);
@@ -785,7 +785,7 @@ int main(int argc, char** argv) {
time_t start,end;
time(&start);
// @nb last argument true -> bypass_properties which are not read by any of the geometry serializers
// Document serializers and IFC are already special-cased above
// SVG requires properties for IfcAnnotation/DRAWING properties
@@ -839,12 +839,12 @@ int main(int argc, char** argv) {
settings.get<ifcopenshell::geom::settings::ModelOffset>().value = offset;
}
if (is_tesselated && (center_model || center_model_geometry)) {
std::vector<double> offset(3);
ifcopenshell::geom::iterator tmp_context_iterator(ifcopenshell::geom::kernels::construct(ifc_file, geometry_kernel, settings, logger), settings, ifc_file, filter_funcs, num_threads, logger);
time_t bounds_start, bounds_end;
time(&bounds_start);
if (!quiet) logger.status("Computing bounds...");
@@ -860,7 +860,7 @@ int main(int argc, char** argv) {
return EXIT_FAILURE;
}
}
tmp_context_iterator.compute_bounds(center_model_geometry);
time(&bounds_end);
@@ -919,19 +919,19 @@ int main(int argc, char** argv) {
}
// The functions ifcopenshell::geom::iterator::get() and ifcopenshell::geom::iterator::next()
// wrap an iterator of all geometrical products in the Ifc file.
// wrap an iterator of all geometrical products in the Ifc file.
// ifcopenshell::geom::iterator::get() returns an ifcopenshell::geom::triangulation_element or
// -native_element pointer, based on current settings. (see iterator.h
// for definition) ifcopenshell::geom::iterator::next() is used to poll whether more
// geometrical entities are available. None of these functions throw
// exceptions, neither for parsing errors or geometrical errors. Upon
// calling next() the entity to be returned has already been processed, a
// non-null return value guarantees that a successfully processed product is
// available.
// geometrical entities are available. None of these functions throw
// exceptions, neither for parsing errors or geometrical errors. Upon
// calling next() the entity to be returned has already been processed, a
// non-null return value guarantees that a successfully processed product is
// available.
size_t num_created = 0;
while (true) {
auto geom_object = context_iterator->get();
if (is_tesselated)
@@ -967,7 +967,7 @@ int main(int argc, char** argv) {
if (!context_iterator->next()) {
break;
}
}
}
if (!no_progress && quiet) {
for (; old_progress < 100; ++old_progress) {
cout_ << ".";
@@ -1086,7 +1086,7 @@ bool init_input_file(const std::string& filename, ifcopenshell::file*& ifc_file,
ifc_file->bypass_type("IfcProfileProperties");
ifc_file->bypass_type("IfcPhysicalQuantity");
}
#ifdef USE_MMAP
if (mmap) {
ifc_file->initialize(filename, mmap);
@@ -1382,20 +1382,20 @@ void fix_quantities(ifcopenshell::file& f, bool no_progress, bool quiet, bool st
auto person = latebound_access::create(f, "IfcPerson");
latebound_access::set(person, "FamilyName", std::string("IfcOpenShell"));
latebound_access::set(person, "GivenName", std::string("IfcOpenShell"));
auto org = latebound_access::create(f, "IfcOrganization");
latebound_access::set(org, "Name", std::string("IfcOpenShell"));
auto pando = latebound_access::create(f, "IfcPersonAndOrganization");
latebound_access::set(pando, "ThePerson", person);
latebound_access::set(pando, "TheOrganization", org);
auto application = latebound_access::create(f, "IfcApplication");
latebound_access::set(application, "ApplicationDeveloper", org);
latebound_access::set(application, "Version", std::string(IFCOPENSHELL_VERSION));
latebound_access::set(application, "ApplicationFullName", std::string("IfcConvert"));
latebound_access::set(application, "ApplicationIdentifier", std::string("IfcConvert") + IFCOPENSHELL_VERSION);
auto ownerhist = latebound_access::create(f, "IfcOwnerHistory");
latebound_access::set(ownerhist, "OwningUser", pando);
latebound_access::set(ownerhist, "OwningApplication", application);
@@ -1440,7 +1440,7 @@ void fix_quantities(ifcopenshell::file& f, bool no_progress, bool quiet, bool st
latebound_access::set(quantity_area, "AreaValue", a);
quantities.push_back(quantity_area);
}
if (geom_object->geometry().calculate_volume(a)) {
auto quantity_volume = latebound_access::create(f, "IfcQuantityVolume");
latebound_access::set(quantity_volume, "Name", std::string("Volume"));
@@ -1461,13 +1461,13 @@ void fix_quantities(ifcopenshell::file& f, bool no_progress, bool quiet, bool st
std::vector<express::base> quantities_2;
for (auto& part : geom_object->geometry()) {
for (auto& part : geom_object->geometry()) {
auto quantity_count = latebound_access::create(f, "IfcQuantityCount");
latebound_access::set(quantity_count, "Name", std::string("Surface Genus"));
latebound_access::set(quantity_count, "Description", '#' + boost::lexical_cast<std::string>(part.ItemId()));
latebound_access::set(quantity_count, "CountValue", (int64_t) part.shape()->surface_genus());
quantities_2.push_back(quantity_count);
quantities_2.push_back(quantity_count);
}
latebound_access::set(quantity_complex, "HasQuantities", quantities_2);
@@ -41,7 +41,7 @@ void fix_storeycontainment(ifcopenshell::file& f, bool no_progress, bool quiet,
elem_to_storey[*it] = storey;
}
}
});
});
auto storeys = f.instances_by_type("IfcBuildingStorey");
std::vector<const ifcopenshell::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
@@ -98,7 +98,7 @@ void fix_storeycontainment(ifcopenshell::file& f, bool no_progress, bool quiet,
std::wcout << "---" << std::endl;
}
*/
if (!context_iterator.initialize()) {
return;
}
@@ -22,7 +22,7 @@ void fix_wallconnectivity(ifcopenshell::file& f, bool no_progress, bool quiet, b
settings.get<ifcopenshell::geom::settings::DisableOpeningSubtractions>().value = true;
settings.get<ifcopenshell::geom::settings::OutputDimensionality>().value = ifcopenshell::geom::settings::CURVES;
ifcopenshell::geom::converter c(ifcopenshell::geom::kernels::construct(&f, "cgal", settings, logger), &f, settings, logger);
auto rels = f.instances_by_type("IfcRelConnectsPathElements");
@@ -54,7 +54,7 @@ void fix_wallconnectivity(ifcopenshell::file& f, bool no_progress, bool quiet, b
if (!a_is_relating) {
std::swap(a_type, b_type);
}
}
}
#if 0
auto a_poly = ifcopenshell::geom::utils::create_polyhedron(a.handle()->second);
@@ -123,7 +123,7 @@ void fix_wallconnectivity(ifcopenshell::file& f, bool no_progress, bool quiet, b
} else {
auto p0 = boost::get<taxonomy::point3::ptr>(first_vertex);
auto p1 = boost::get<taxonomy::point3::ptr>(last_vertex);
auto v0 = taxonomy::cast<taxonomy::geom_item>(item)->matrix->ccomponents() * p0->ccomponents().homogeneous();
auto v1 = taxonomy::cast<taxonomy::geom_item>(item)->matrix->ccomponents() * p1->ccomponents().homogeneous();
@@ -142,7 +142,7 @@ void fix_wallconnectivity(ifcopenshell::file& f, bool no_progress, bool quiet, b
auto pit = std::minmax_element(parameters.begin(), parameters.end());
return std::make_pair(len, std::make_pair(CGAL::to_double(*pit.first), CGAL::to_double(*pit.second)));
}
}
}
const auto& nan = std::numeric_limits<double>::quiet_NaN();
return std::make_pair(nan, std::make_pair(nan, nan));
+2 -2
View File
@@ -37,7 +37,7 @@ inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance = AL
return fabs(a - b) < tolerance;
}
namespace ifcopenshell {
namespace ifcopenshell {
#if defined(_MSC_VER)
#pragma warning(push)
@@ -70,7 +70,7 @@ namespace ifcopenshell {
public:
bool propagate_exceptions = false;
bool partial_success_is_success = true;
abstract_kernel(const std::string& geometry_library, const ifcopenshell::geom::settings& settings, ifcopenshell::logger& logger = ifcopenshell::logger::root())
: geometry_library_(geometry_library)
, settings_(settings)
+2 -2
View File
@@ -44,7 +44,7 @@ namespace geom {
/// should return true if the geometry for the product is wanted to be included in the output.
/// http://www.boost.org/doc/libs/1_62_0/doc/html/function/tutorial.html
typedef std::function<bool(const express::base&)> filter_function;
class IFC_GEOM_API abstract_mapping {
protected:
ifcopenshell::geom::settings settings_;
@@ -106,7 +106,7 @@ namespace geom {
IFC_GEOM_API mapping_factory_implementation& mapping_implementations();
}
}
}
+6 -6
View File
@@ -510,20 +510,20 @@ namespace ifcopenshell::geom {
virtual void triangulate(ifcopenshell::geom::settings settings, const ifcopenshell::geom::taxonomy::matrix4& place, triangulation* t, int item_id, int surface_style_id, ifcopenshell::logger& logger = ifcopenshell::logger::root()) const = 0;
ifcopenshell::geom::triangulation* triangulate(const ifcopenshell::geom::settings& settings, ifcopenshell::logger& logger = ifcopenshell::logger::root()) const;
virtual void serialize(const ifcopenshell::geom::taxonomy::matrix4& place, std::string&) const = 0;
virtual int surface_genus() const = 0;
virtual bool is_manifold() const = 0;
virtual int num_vertices() const = 0;
virtual int num_edges() const = 0;
virtual int num_faces() const = 0;
// @todo choose one prototype
virtual double bounding_box(void*&) const = 0;
// @todo this must be something with a virtual dtor so that we can delete it.
virtual std::pair<opaque_coordinate<3>, opaque_coordinate<3>> bounding_box() const = 0;
virtual void set_box(void* b) = 0;
virtual opaque_number length() = 0;
virtual opaque_number area() = 0;
virtual opaque_number volume() = 0;
@@ -550,11 +550,11 @@ namespace ifcopenshell::geom {
virtual std::size_t map(opaque_coordinate<4>& from, opaque_coordinate<4>& to) = 0;
virtual std::size_t map(const std::vector<opaque_coordinate<4>>& from, const std::vector<opaque_coordinate<4>>& to) = 0;
virtual conversion_result_shape* moved(ifcopenshell::geom::taxonomy::matrix4::ptr) const = 0;
virtual bool surface_area_along_direction(double tol, const ifcopenshell::geom::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const = 0;
virtual ~conversion_result_shape() {}
};
class IFC_GEOM_API conversion_result {
+1 -1
View File
@@ -498,7 +498,7 @@ namespace ifcopenshell {
static constexpr const char* const description = "Slight variation of --model-offset where large offsets are applied by negating existing large offsets to retain maximum precision. Requires --no-parallel-mapping.";
};
}
namespace impl {
template <typename T>
struct readable_name {
+3 -3
View File
@@ -19,7 +19,7 @@ ifcopenshell::geom::converter::~converter() {
ifcopenshell::geom::native_element* ifcopenshell::geom::converter::create_brep_for_representation_and_product(taxonomy::ptr representation_node, const express::base product_, const taxonomy::matrix4::ptr& place_) {
auto product = product_.as<express::entity>();
std::stringstream representation_id_builder;
auto place = place_;
@@ -32,7 +32,7 @@ ifcopenshell::geom::native_element* ifcopenshell::geom::converter::create_brep_f
if (!kernel_->convert(representation_node, shapes)) {
return 0;
}
if (settings_.get<ifcopenshell::geom::settings::ApplyLayerSets>().get()) {
ifcopenshell::geom::layerset_information layerinfo;
std::vector<ifcopenshell::geom::endpoint_connection> neighbours;
@@ -55,7 +55,7 @@ ifcopenshell::geom::native_element* ifcopenshell::geom::converter::create_brep_f
/*
if (util::flatten_shape_list(shapes, merge, false, getValue(GV_PRECISION))) {
if (util::count(merge, TopAbs_FACE) > 0) {
if (convert_layerset(product, layers, styles, thickness)) {
IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
+1 -1
View File
@@ -27,7 +27,7 @@ namespace ifcopenshell { namespace geom {
ifcopenshell::geom::kernels::abstract_kernel* kernel() { return &*kernel_; }
converter(std::unique_ptr<ifcopenshell::geom::kernels::abstract_kernel>&& geometry_library, ifcopenshell::file* file, ifcopenshell::geom::settings& settings, ifcopenshell::logger& logger = ifcopenshell::logger::root());
~converter();
ifcopenshell::geom::abstract_mapping* mapping() const { return mapping_; }
+2 -2
View File
@@ -53,7 +53,7 @@ namespace ifcopenshell::geom {
}
}
const ifcopenshell::geom::taxonomy::matrix4::ptr& data() const {
if (matrix_orig_units_) {
if (matrix_orig_units_) {
return matrix_orig_units_;
}
if (matrix_) {
@@ -131,7 +131,7 @@ namespace ifcopenshell::geom {
const std::string& guid, const std::string& context, const ifcopenshell::geom::taxonomy::matrix4::ptr& trsf, const express::entity& product)
: _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf)
, product_(product)
{
{
std::ostringstream oss;
if (type == "IfcProject") {
+1 -1
View File
@@ -1,2 +1,2 @@
// A purposely empty file so that the unrolled loop
// can overflow into an existing empty include file.
// can overflow into an existing empty include file.
+1 -1
View File
@@ -135,7 +135,7 @@ struct cant_fn_evaluator : public fn_evaluator {
auto g = gradient_evaluator_.evaluate(u);
auto c = cant_evaluator_.evaluate(u);
// curvature is stored in row 3 - capture it and remove it from the xy and uz matrices
// so the matrix operations (ie multiplication) works correctly
auto gradient_curvature = g.row(3);
+2 -2
View File
@@ -13,8 +13,8 @@ IFC_GEOM_API std::vector<double> helmert_curve_point(double A0, double A1, doubl
/// This is intended to be used from python side. Polylines are mapped to a loop, but when
/// representing an alignment they need to be a function_item so the can be evaluated by function_item_evaluator.
/// On the C++ side, the dcast operator take care of this, but dcast is not accessible on the python side.
/// @param loop
/// @return
/// @param loop
/// @return
inline taxonomy::function_item::ptr convert_loop_to_function_item(taxonomy::loop::ptr loop) {
return ifcopenshell::geom::taxonomy::dcast<taxonomy::function_item>(loop);
}
+4 -4
View File
@@ -78,7 +78,7 @@ taxonomy::loft::ptr ifcopenshell::geom::make_loft(const ifcopenshell::geom::sett
while (dist_along > *(profile_index + 1)) {
profile_index++;
if (profile_index == longitudes.end()) {
// @todo handle this?
// @todo handle this?
}
}
@@ -158,7 +158,7 @@ taxonomy::loft::ptr ifcopenshell::geom::make_loft(const ifcopenshell::geom::sett
}
interpolated->matrix->components() = lerp(m4a, m4b, relative_dist_along);
}
auto interpolated_offset = lerp(offset_a, offset_b, relative_dist_along);
if (rotation_a == rotation_b && rotation_a) {
// @todo we don't support an overridden rotation on only one of the placements
@@ -215,7 +215,7 @@ taxonomy::loft::ptr ifcopenshell::geom::make_loft(const ifcopenshell::geom::sett
std::vector<taxonomy::point3::ptr> points;
std::vector<std::set<std::string>> tags;
std::vector<std::string>::const_iterator tag_it;
if (!loop->closed.value_or(false)) {
points = {std::get<taxonomy::point3::ptr>(loop->children[0]->start)};
if (input_tags) {
@@ -352,7 +352,7 @@ taxonomy::loft::ptr ifcopenshell::geom::make_loft(const ifcopenshell::geom::sett
for (auto& x : tags_for_this_point_on_subsequent_profile) {
points.push_back(taxonomy::make<taxonomy::point3>(p3));
common_tags_vec.push_back(x);
}
}
}
} else {
for (auto tmp__ : boost::combine(w1_points, w2_points)) {
+1 -1
View File
@@ -9,7 +9,7 @@
namespace ifcopenshell {
namespace geom {
struct IFC_GEOM_API cross_section {
double dist_along;
taxonomy::geom_item::ptr section_geometry;
+4 -4
View File
@@ -624,7 +624,7 @@ std::unique_ptr<ifcopenshell::geom::element> ifcopenshell::geom::iterator::get()
hasParent = false;
}
}
// Add the previously found parent to the vector
hasParent = hasParent && parent_object->parent_id() != -1;
}
@@ -688,13 +688,13 @@ express::base ifcopenshell::geom::iterator::create() {
}
ifcopenshell::geom::taxonomy::direction3::ptr ifcopenshell::geom::iterator::remove_offset_() {
using namespace ifcopenshell::geom::taxonomy;
if (!settings_.get<ifcopenshell::geom::settings::MaxOffset>().has()) {
return nullptr;
}
if (!settings_.get<ifcopenshell::geom::settings::NoParallelMapping>().get()) {
throw std::runtime_error("remove_offset() can only be called with defer-processing-first-element and no-parallel-mapping settings");
}
+2 -2
View File
@@ -128,7 +128,7 @@ namespace ifcopenshell::geom {
bool task_result_ptr_initialized = false;
bool task_result_ptr_exhausted = false;
size_t async_elements_returned_ = 0;
ifcopenshell::geom::settings settings_;
ifcopenshell::file* ifc_file;
std::vector<ifcopenshell::geom::filter_function> filters_;
@@ -138,7 +138,7 @@ namespace ifcopenshell::geom {
// When single-threaded
ifcopenshell::geom::converter* converter_;
// When multi-threaded
std::vector<ifcopenshell::geom::converter*> kernel_pool;
std::vector<std::unique_ptr<ifcopenshell::logger>> worker_loggers_;
@@ -296,7 +296,7 @@ ifcopenshell::geom::cgal_shape::cgal_shape(const cgal_polyhedron& shape, bool co
};
std::vector<CGAL::Point_2<kernel_>> ps;
for (auto& he1 : CGAL::halfedges_around_face(face->halfedge(), poly)) {
const auto& source = he1->vertex()->point();
ps.push_back(transform_point(source));
@@ -345,7 +345,7 @@ void ifcopenshell::geom::cgal_shape::to_poly() const {
CGAL::Polygon_mesh_processing::orient_to_bound_a_volume(poly);
}
shape_ = poly;
// nef_->convert_to_polyhedron(*shape_);
}
}
@@ -384,7 +384,7 @@ void ifcopenshell::geom::cgal_shape::triangulate(ifcopenshell::geom::settings se
}
const bool setting_use_original_edges = settings.get<ifcopenshell::geom::settings::CgalEmitOriginalEdges>().get();
std::set<std::set<kernel_::Point_3>> original_edges;
if (setting_use_original_edges) {
for (auto it = shape_to_use->edges_begin(); it != shape_to_use->edges_end(); ++it) {
@@ -457,7 +457,7 @@ void ifcopenshell::geom::cgal_shape::triangulate(ifcopenshell::geom::settings se
// std::map<cgal_vertex_descriptor, kernel_::Vector_3> vertex_normals;
// boost::associative_property_map<std::map<cgal_vertex_descriptor, kernel_::Vector_3>> vertex_normals_map(vertex_normals);
// triangulate the shape and compute the normals
std::map<facet_const_handle, kernel_::Vector_3> face_normals;
boost::associative_property_map<std::map<facet_const_handle, kernel_::Vector_3>> face_normals_map(face_normals);
@@ -556,7 +556,7 @@ void ifcopenshell::geom::cgal_shape::triangulate(ifcopenshell::geom::settings se
is_face_boundary[i] = setting_use_original_edges
? original_edges.find({ current_halfedge->vertex()->point(), current_halfedge->prev()->vertex()->point() }) != original_edges.end()
: facet_to_component[face] != facet_to_component[current_halfedge->opposite()->face()];
++i;
++num_vertices;
++current_halfedge;
@@ -764,7 +764,7 @@ opaque_coordinate<3> ifcopenshell::geom::cgal_shape::position()
for (auto it = shp.points_begin(); it != shp.points_end(); ++it) {
for (int i = 0; i < 3; ++i) {
p[i] += it->cartesian(i);
}
}
}
kernel_::FT N(static_cast<double>(std::distance(shp.points_begin(), shp.points_end())));
for (int i = 0; i < 3; ++i) {
+9 -9
View File
@@ -84,7 +84,7 @@ CGAL::Polyhedron_3<kernel_> ifcopenshell::geom::utils::create_polyhedron(std::li
// fresult.close();
return CGAL::Polyhedron_3<kernel_>();
}
// std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl;
return polyhedron;
@@ -223,7 +223,7 @@ bool cgal_kernel::convert(const taxonomy::shell::ptr l, cgal_polyhedron& shape)
} else {
logger().message(ifcopenshell::logger::LOG_ERROR, "Failed to convert face:", f->instance);
return false;
}
}
}
// std::cout << "Face in ConnectedFaceSet: " << std::endl;
@@ -673,9 +673,9 @@ namespace {
namespace {
void face_to_poly_with_holes(const cgal_face& face, CGAL::Polygon_with_holes_2<kernel_>& pwh, CGAL::Aff_transformation_3<kernel_>& place) {
// static
// static
kernel_::Vector_3 Z(0, 0, 1);
// static
// static
kernel_::Vector_3 X(1, 0, 0);
auto refz = newell(face.outer);
@@ -912,7 +912,7 @@ bool ifcopenshell::geom::kernels::cgal_kernel::convert_openings(const express::b
#else
CGAL::Nef_nary_union_3<CGAL::Nef_polyhedron_3<kernel_>> second_operand_collector;
size_t second_operand_collector_size = 0;
std::list<std::pair<express::base, std::list<cgal_polyhedron>>> operands;
std::list<express::base> second_operand_instances;
@@ -1483,7 +1483,7 @@ bool cgal_kernel::preprocess_boolean_operand(const express::base& log_reference,
for (auto& nef : first_operands_nef) {
// @todo eliminate this copy (= to remove const)
auto nef_copy = nef;
auto tree = build_halfspace_tree_decomposed(nef_copy, planes_fixed);
auto tree = build_halfspace_tree_decomposed(nef_copy, planes_fixed);
}
{
// @nb we snap internally as well...
@@ -1551,7 +1551,7 @@ bool cgal_kernel::preprocess_boolean_operand(const express::base& log_reference,
}
}
/*
{
@@ -2026,7 +2026,7 @@ bool cgal_kernel::convert_impl(const taxonomy::boolean_result::ptr br, std::vect
if (!convert(face, fs) || fs.size() != 1) {
return false;
}
auto& w = fs.front().outer;
CGAL::Polygon_2<kernel_> ps;
for (auto& wire_point : w) {
@@ -2037,7 +2037,7 @@ bool cgal_kernel::convert_impl(const taxonomy::boolean_result::ptr br, std::vect
continue;
}
// static
// static
auto z = taxonomy::make<taxonomy::direction3>(0, 0, 1);
cgal_polyhedron poly;
process_extrusion(fs.front(), z, 200, poly);
+1 -1
View File
@@ -74,7 +74,7 @@ namespace ifcopenshell {
class IFC_GEOMLIBRARY_API cgal_kernel : public abstract_kernel {
private:
#ifndef IFOPSH_SIMPLE_KERNEL
enum boolean_operand_preprocess {
enum boolean_operand_preprocess {
PP_MINKOWSKY_DILATE,
PP_SNAP_POINTS_TO_FIRST_OPERAND,
PP_SNAP_PLANES_TO_FIRST_OPERAND,
@@ -95,7 +95,7 @@ std::string dump_facet(typename CGAL::Nef_polyhedron_3<Kernel>::Halffacet_const_
const auto& p = h->plane();
oss << "Facet plane=" << p << std::endl;
auto fc = h->facet_cycles_begin();
auto se = shalfedge_const_handle(fc);
CGAL_assertion(se != 0);
@@ -187,7 +187,7 @@ plane_map<Kernel> snap_halfspaces(const std::list<CGAL::Plane_3<Kernel>>& planes
fuzzy_sphere fs(query, search_radius, 0.);
// std::cout << "q " << query << std::endl;
std::list<point_d> results_pos, results_neg;
kdtree.search(std::back_inserter(results_pos), fs);
@@ -801,7 +801,7 @@ void bfs(graph<Kernel>& g, size_t start_vertex, Fn& fn) {
for (boost::tie(ei, ei_end) = boost::out_edges(cur, g); ei != ei_end; ++ei) {
auto s = boost::source(*ei, g);
auto t = boost::target(*ei, g);
// @todo is this necessary?
if (cur == t) {
std::swap(s, t);
@@ -863,10 +863,10 @@ std::unique_ptr<halfspace_tree<TreeKernel>> build_halfspace_tree(graph<Kernel>&
int largest_component_idx = -1;
int num_components = 0;
// @nb we don't just randomly start from an arbitrary seed, but we sort planes by d / | abc |
// for (size_t i = 0; i < boost::num_vertices(sub_graph_0); ++i) {
std::vector<size_t> sorted_verts;
for (size_t i = 0; i < boost::num_vertices(sub_graph_0); ++i) {
sorted_verts.push_back(i);
@@ -1232,7 +1232,7 @@ std::unique_ptr<halfspace_tree<TreeKernel>> build_halfspace_tree_decomposed(cons
// directly, so for now we need to isolate the individual volumes.
CGAL::Polyhedron_3<Kernel> P;
poly.convert_inner_shell_to_polyhedron(ci->shells_begin(), P);
CGAL::Nef_polyhedron_3<Kernel> Pnef(P);
CGAL::Nef_polyhedron_3<Kernel> Pnef(P);
for (auto it = Pnef.halffacets_begin(); it != Pnef.halffacets_end(); ++it) {
if (it->incident_volume()->mark()) {
@@ -1315,7 +1315,7 @@ size_t edge_contract(graph<Kernel>& G) {
bool exists = boost::edge(srcid, tt, G).second;
if (!exists) {
boost::add_edge(srcid, tt, G);
}
}
}
}
++n;
@@ -19,7 +19,7 @@ struct IFC_GEOMLIBRARY_API manifold_part {
auto copy = s;
copy.CalculateNormals(3);
mesh = copy.GetMeshGL64();
solid = s;
solid = s;
}
manifold_part(const manifold::MeshGL64& s) : mesh(s) {}
@@ -114,10 +114,10 @@ namespace {
mesh_type build() const {
mesh_type mesh;
mesh.numProp = 3;
std::vector<size_t> vertex_use_count(vertices.size(), 0);
std::vector<Eigen::Vector3d> vertex_normals(vertices.size(), Eigen::Vector3d::Zero());
for (size_t i = 0; i < tri_verts.size(); i += 3) {
for (size_t j = 0; j < 3; ++j) {
vertex_use_count[tri_verts[i + j]]++;
@@ -1242,13 +1242,13 @@ namespace {
}
std::optional<part> part_from_halfspace_solid(halfspace_build_state& state, const taxonomy::solid::ptr& solid, const taxonomy::face::ptr& face,const manifold::Box& reference_box, double precision, double dilation) {
auto plane = taxonomy::cast<taxonomy::plane>(face->basis);
// @todo verify order
const auto transform = matrix_or_identity(solid->matrix) * matrix_or_identity(plane->matrix);
const auto extrusion_dir = matrix_or_identity(solid->matrix).col(2).head<3>().eval();
Eigen::Vector3d x = transform.col(0).head<3>();
Eigen::Vector3d y = transform.col(1).head<3>();
Eigen::Vector3d normal = transform.col(2).head<3>();
@@ -1281,7 +1281,7 @@ namespace {
const auto delta = corner - origin;
const auto u = delta.dot(x);
const auto v = delta.dot(y);
u_min = std::min(u_min, u);
u_max = std::max(u_max, u);
v_min = std::min(v_min, v);
@@ -58,7 +58,7 @@ double ifcopenshell::geom::util::min_edge_length(const TopoDS_Shape & a) {
TopExp_Explorer exp(a, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
const TopoDS_Edge& e = TopoDS::Edge(exp.Current());
TopoDS_Vertex v0, v1;
TopExp::Vertices(e, v0, v1);
if (!v0.IsNull() && !v1.IsNull() && v0.IsSame(v1)) {
+10 -10
View File
@@ -43,8 +43,8 @@ bool is_intersect_ray_box(const struct ray *ray, const struct box *box) {
// https://github.com/NVIDIA-Omniverse/PhysX/blob/main/physx/source/geomutils/src/intersection/GuIntersectionRayTriangle.h
// With minor modifications to use gp_Vec type.
// More reading: https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2,
bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2,
double& at, double& au, double& av,
bool cull, float enlarge) {
// Find vectors for two edges sharing vert0
@@ -147,7 +147,7 @@ void edgeEdgeDist(gp_Vec& x, gp_Vec& y, // closest points
const double Denom = ADotA*BDotB - ADotB*ADotB;
double t; // We will clamp result so t is on the segment (p, a)
if(Denom!=0.0)
if(Denom!=0.0)
t = ios_clamp((ADotT*BDotB - BDotT*ADotB) / Denom, 0.0, 1.0);
else
t = 0.0;
@@ -268,7 +268,7 @@ double distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<
if(Tp[2]>Tp[index]) index = 2;
}
if(index >= 0)
if(index >= 0)
{
shown_disjoint = true;
@@ -297,7 +297,7 @@ double distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<
gp_Vec Tn = Tv[0].Crossed(Tv[1]);
double Tnl = Tn.Dot(Tn);
if(Tnl>1e-15f)
{
const std::array<double, 3> Sp = {(q[0] - p[0]).Dot(Tn),
@@ -317,7 +317,7 @@ double distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array<
}
if(index >= 0)
{
{
shown_disjoint = true;
const gp_Vec& pIndex = p[index];
@@ -525,11 +525,11 @@ bool trianglesIntersectCoplanar(const gp_Vec& p1_n, const gp_Vec& a1, const gp_V
const double third = (1.0 / 3.0);
//A bit of the computations done inside the following functions could be shared but it's kept simple since the
//A bit of the computations done inside the following functions could be shared but it's kept simple since the
//difference is not very big and the coplanar case is not expected to be the most common case
if (linesIntersect(a1, b1, a2, b2, x, y) || linesIntersect(a1, b1, b2, c2, x, y) || linesIntersect(a1, b1, c2, a2, x, y) ||
linesIntersect(b1, c1, a2, b2, x, y) || linesIntersect(b1, c1, b2, c2, x, y) || linesIntersect(b1, c1, c2, a2, x, y) ||
linesIntersect(c1, a1, a2, b2, x, y) || linesIntersect(c1, a1, b2, c2, x, y) || linesIntersect(c1, a1, c2, a2, x, y) ||
linesIntersect(c1, a1, a2, b2, x, y) || linesIntersect(c1, a1, b2, c2, x, y) || linesIntersect(c1, a1, c2, a2, x, y) ||
pointInTriangle(a1, b1, c1, third * (a2 + b2 + c2), x, y) || pointInTriangle(a2, b2, c2, third * (a1 + b1 + c1), x, y))
return true;
@@ -557,7 +557,7 @@ bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, co
if ((p1ToA > 0) == (p1ToB > 0) && (p1ToA > 0) == (p1ToC > 0))
return false; //All points of triangle 2 on same side of triangle 1 -> no intersection
gp_Dir p2_n((b2 - a2).Crossed(c2 - a2).Normalized());
double p2_d = -a2.Dot(p2_n);
// const PxPlane p2(a2, b2, c2);
@@ -566,7 +566,7 @@ bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, co
const double p2ToC = c1.Dot(p2_n) + p2_d;
if ((p2ToA > 0) == (p2ToB > 0) && (p2ToA > 0) == (p2ToC > 0))
return false; //All points of triangle 1 on same side of triangle 2 -> no intersection
return false; //All points of triangle 1 on same side of triangle 2 -> no intersection
gp_Vec intersectionDirection = p1_n.Crossed(p2_n);
const double l2 = intersectionDirection.SquareMagnitude();
@@ -20,7 +20,7 @@ struct IFC_GEOMLIBRARY_API box {
IFC_GEOMLIBRARY_API bool is_intersect_ray_box(const struct ray *ray, const struct box *box);
IFC_GEOMLIBRARY_API bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir,
const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2,
const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2,
double& at, double& au, double& av,
bool cull, float enlarge=0.0f);
@@ -35,7 +35,7 @@ bool open_cascade_kernel::convert(const taxonomy::extrusion::ptr extrusion, Topo
if (face.ShapeType() == TopAbs_COMPOUND) {
// For compounds (most likely the result of a IfcCompositeProfileDef)
// For compounds (most likely the result of a IfcCompositeProfileDef)
// create a compound solid shape.
TopExp_Explorer exp(face, TopAbs_FACE);
+1 -1
View File
@@ -247,7 +247,7 @@ namespace {
auto crv = get_curve(e->basis);
result = Handle(Geom_Surface)(new Geom_SurfaceOfRevolution(
crv, ax
crv, ax
));
result->Transform(tr);
@@ -70,7 +70,7 @@ namespace ifcopenshell::geom {
std::pair<wire_it, wire_it> inner_wires() const {
return { wires_.begin() + 1, wires_.end() };
}
};
};
}
}
+5 -5
View File
@@ -163,7 +163,7 @@ bool open_cascade_kernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape&
return false;
}
}
NCollection_List<TopoDS_Shape> faces;
TopoDS_Compound comp;
BRep_Builder BB;
@@ -330,7 +330,7 @@ bool open_cascade_kernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape&
std::array<std::vector<std::vector<std::set<std::string>>>::const_iterator, 2> tag_pairs = {
all_tags.begin() + std::distance(shps.begin(), it),
all_tags.begin() + std::distance(shps.begin(), jt)};
for (size_t i = 0; i < 2; ++i) {
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> ancestors;
const auto& wire = wp[i];
@@ -357,7 +357,7 @@ bool open_cascade_kernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape&
for (NCollection_List<TopoDS_Shape>::Iterator edge_it(incidentEdges); edge_it.More(); edge_it.Next()) {
const TopoDS_Edge& e = TopoDS::Edge(edge_it.Value());
TopoDS_Vertex ev0, ev1;
TopExp::Vertices(e, ev0, ev1);
@@ -405,11 +405,11 @@ bool open_cascade_kernel::convert(const taxonomy::loft::ptr loft, TopoDS_Shape&
++d;
} else {
throw std::runtime_error("Unable to construct surface");
}
}
}
continue;
}
}
for (auto& wp : ws) {
BRepTools_WireExplorer a(wp[0]);
+1 -1
View File
@@ -204,7 +204,7 @@ namespace {
BRep_Tool::Pnt(v1).DumpJson(oss);
auto osss = oss.str();
std::wcout << osss.c_str() << std::endl;
#endif
#endif
BRep_Builder B;
TopoDS_Wire W;
@@ -75,7 +75,7 @@ void ifcopenshell::geom::open_cascade_shape::triangulate(ifcopenshell::geom::set
// A 3x3 matrix to rotate the vertex normals
std::optional<gp_Mat> rotation_matrix;
if (place.components_) {
const auto& m = *place.components_;
rotation_matrix.emplace(
@@ -84,7 +84,7 @@ void ifcopenshell::geom::open_cascade_shape::triangulate(ifcopenshell::geom::set
m(2, 0), m(2, 1), m(2, 2)
);
}
// When welding vertices, vertex coords will be shared among faces so we need to per-shape set
// to keep track of which edges were already emitted.
std::set<std::pair<int, int>> emitted_edges;
@@ -119,9 +119,9 @@ void ifcopenshell::geom::open_cascade_shape::triangulate(ifcopenshell::geom::set
for (exp.Init(shape_, TopAbs_FACE); exp.More(); exp.Next(), ++num_faces) {
TopoDS_Face face = TopoDS::Face(exp.Current());
size_t num_bounds = 0;
size_t num_bounds = 0;
for (TopoDS_Iterator it(face); it.More(); it.Next(), ++num_bounds) {}
const bool is_planar = BRep_Tool::Surface(face) && BRep_Tool::Surface(face)->DynamicType() == STANDARD_TYPE(Geom_Plane);
const bool has_inner_bounds = num_bounds > 1;
@@ -314,7 +314,7 @@ void ifcopenshell::geom::open_cascade_shape::triangulate(ifcopenshell::geom::set
} else {
p = tessellater.Value(i).XYZ();
}
auto p_local = p;
taxonomy_transform(place.components_, p);
@@ -582,7 +582,7 @@ conversion_result_shape* ifcopenshell::geom::open_cascade_shape::concat(conversi
{
TopoDS_Compound compound;
BRep_Builder builder;
auto& left = shape_;
auto& right = ((ifcopenshell::geom::open_cascade_shape*)other)->shape_;
@@ -594,7 +594,7 @@ conversion_result_shape* ifcopenshell::geom::open_cascade_shape::concat(conversi
builder.MakeCompound(compound);
builder.Add(compound, left);
}
builder.Add(compound, right);
return new open_cascade_shape(std::move(compound));
@@ -84,7 +84,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_openings(const express::ba
// opening_trsf = relative;
std::vector<ifcopenshell::geom::conversion_result> opening_shapes;
// @todo
abstract_kernel::convert(op.first, opening_shapes);
@@ -309,13 +309,13 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// IfcSchema::IfcRelVoidsElement::list::ptr ifcopenshell::geom::Kernel::find_openings(IfcSchema::IfcProduct* product) {
// std::vector<IfcSchema::IfcRelVoidsElement*> rs;
//
//
// if (product->declaration().is(IfcSchema::IfcElement::Class()) && !product->declaration().is(IfcSchema::IfcOpeningElement::Class())) {
// IfcSchema::IfcElement* element = (IfcSchema::IfcElement*)product;
// auto rels = element->HasOpenings();
// rs.insert(rs.end(), rels->begin(), rels->end());
// }
//
//
// // Is the IfcElement a decomposition of an IfcElement with any IfcOpeningElements?
// IfcSchema::IfcObjectDefinition* obdef = product->as<IfcSchema::IfcObjectDefinition>();
// for (;;) {
@@ -327,10 +327,10 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// auto rels = element->HasOpenings();
// rs.insert(rs.end(), rels->begin(), rels->end());
// }
//
//
// obdef = rel_obdef;
// }
//
//
// // Filter openings in Reference view, solely marked as Reference.
// IfcSchema::IfcRelVoidsElement::list::ptr openings(new IfcSchema::IfcRelVoidsElement::list);
// std::for_each(rs.begin(), rs.end(), [&openings](IfcSchema::IfcRelVoidsElement* rel) {
@@ -341,17 +341,17 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// });
//
//
// return openings;
// }
//
//
// const IfcSchema::IfcMaterial* ifcopenshell::geom::Kernel::get_single_material_association(const IfcSchema::IfcProduct* product) {
// IfcSchema::IfcMaterial* single_material = 0;
// IfcSchema::IfcRelAssociatesMaterial::list::ptr associated_materials = product->HasAssociations()->as<IfcSchema::IfcRelAssociatesMaterial>();
// if (associated_materials->size() == 1) {
// IfcSchema::IfcMaterialSelect* associated_material = (*associated_materials->begin())->RelatingMaterial();
// single_material = associated_material->as<IfcSchema::IfcMaterial>();
//
//
// // NB: IfcMaterialLayerSets are also considered, regardless of --enable-layerset-slicing. Picking
// // the first material (in accordance with other viewers) when layerset-slicing is disabled.
// if (!single_material && associated_material->as<IfcSchema::IfcMaterialLayerSetUsage>()) {
@@ -366,21 +366,21 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// return single_material;
// }
//
//
// ifcopenshell::geom::native_element* ifcopenshell::geom::Kernel::create_brep_for_representation_and_product(
// const IteratorSettings& settings, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product)
// {
// std::stringstream representation_id_builder;
//
//
// representation_id_builder << representation->data().id();
//
//
// ifcopenshell::geom::native* shape;
// std::vector<ifcopenshell::geom::conversion_result> shapes, shapes2;
//
//
// if (!convert_shapes(representation, shapes)) {
// return 0;
// }
//
//
// if (settings.get(IteratorSettings::APPLY_LAYERSETS)) {
// TopoDS_Shape merge;
// if (util::flatten_shape_list(shapes, merge, false, getValue(GV_PRECISION))) {
@@ -390,7 +390,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// std::vector< std::vector<Handle_Geom_Surface> > folded_layers;
// std::vector<std::shared_ptr<const SurfaceStyle>> styles;
// if (convert_layerset(product, layers, styles, thickness)) {
//
//
// IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations();
// for (IfcSchema::IfcRelAssociates::list::it it = associations->begin(); it != associations->end(); ++it) {
// IfcSchema::IfcRelAssociatesMaterial* associates_material = (**it).as<IfcSchema::IfcRelAssociatesMaterial>();
@@ -400,7 +400,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// break;
// }
// }
//
//
// if (styles.size() > 1) {
// // If there's only a single layer there is no need to manipulate geometries.
// bool success = true;
@@ -415,7 +415,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// success = true;
// }
// }
//
//
// if (!success) {
// ifcopenshell::logger::root().error("Failed processing layerset");
// }
@@ -424,9 +424,9 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// bool material_style_applied = false;
//
//
// const IfcSchema::IfcMaterial* single_material = get_single_material_association(product);
// if (single_material) {
// auto s = get_style(single_material);
@@ -448,11 +448,11 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// ifcopenshell::logger::root().warning("No material and surface styles for:", product);
// }
// }
//
//
// if (material_style_applied) {
// representation_id_builder << "-material-" << single_material->data().id();
// }
//
//
// if (settings.force_space_transparency() >= 0. && product->declaration().is("IfcSpace")) {
// for (auto& s : shapes) {
// if (s.hasStyle()) {
@@ -464,7 +464,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// int parent_id = -1;
// try {
// express::entity* parent_object = get_decomposing_entity(product);
@@ -474,10 +474,10 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// } catch (const std::exception& e) {
// ifcopenshell::logger::root().error(e);
// }
//
//
// const std::string name = product->Name().value_or("");
// const std::string guid = product->GlobalId();
//
//
// gp_Trsf trsf;
// try {
// if (product->ObjectPlacement()) {
@@ -488,20 +488,20 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// } catch (...) {
// ifcopenshell::logger::root().error("Failed to construct placement");
// }
//
//
// // Does the IfcElement have any IfcOpenings?
// // Note that openings for IfcOpeningElements are not processed
// IfcSchema::IfcRelVoidsElement::list::ptr openings = find_openings(product);
//
//
// const std::string product_type = product->declaration().name();
// ElementSettings element_settings(settings, getValue(GV_LENGTH_UNIT), product_type);
//
//
// if (!settings.get(ifcopenshell::geom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) {
// representation_id_builder << "-openings";
// for (IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++it) {
// representation_id_builder << "-" << (*it)->data().id();
// }
//
//
// std::vector<ifcopenshell::geom::conversion_result> opened_shapes;
// bool caught_error = false;
// try {
@@ -512,11 +512,11 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// } catch (...) {
// ifcopenshell::logger::root().message(ifcopenshell::logger::LOG_ERROR, "error processing openings for:", product);
// }
//
//
// if (caught_error && opened_shapes.size() < shapes.size()) {
// opened_shapes = shapes;
// }
//
//
// if (settings.get(IteratorSettings::USE_WORLD_COORDS)) {
// for (std::vector<ifcopenshell::geom::conversion_result>::iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++it) {
// it->prepend(trsf);
@@ -535,14 +535,14 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// } else {
// shape = new ifcopenshell::geom::native(element_settings, representation_id_builder.str(), shapes);
// }
//
//
// std::string context_string = "";
// if (representation->RepresentationIdentifier()) {
// context_string = *representation->RepresentationIdentifier();
// } else if (representation->ContextOfItems()->ContextType()) {
// context_string = *representation->ContextOfItems()->ContextType();
// }
//
//
// auto elem = new native_element(
// product->data().id(),
// parent_id,
@@ -554,7 +554,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// std::shared_ptr<ifcopenshell::geom::native>(shape),
// product
// );
//
//
// if (settings.get(IteratorSettings::VALIDATE_QUANTITIES)) {
// auto rels = product->IsDefinedBy();
// for (auto& rel : *rels) {
@@ -623,10 +623,10 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// return elem;
// }
//
//
// IfcSchema::IfcRepresentation* ifcopenshell::geom::Kernel::representation_mapped_to(const IfcSchema::IfcRepresentation* representation) {
// IfcSchema::IfcRepresentation* representation_mapped_to = 0;
// try {
@@ -651,36 +651,36 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// return representation_mapped_to;
// }
//
//
// IfcSchema::IfcProduct::list::ptr ifcopenshell::geom::Kernel::products_represented_by(const IfcSchema::IfcRepresentation* representation) {
// IfcSchema::IfcProduct::list::ptr products(new IfcSchema::IfcProduct::list);
//
//
// IfcSchema::IfcProductRepresentation::list::ptr prodreps = representation->OfProductRepresentation();
//
//
// for (IfcSchema::IfcProductRepresentation::list::it it = prodreps->begin(); it != prodreps->end(); ++it) {
// // http://buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcrepresentationresource/lexical/ifcproductrepresentation.htm
// // IFC2x Edition 3 NOTE Users should not instantiate the entity IfcProductRepresentation from IFC2x Edition 3 onwards.
// // It will be changed into an ABSTRACT supertype in future releases of IFC.
//
//
// // IfcProductRepresentation also lacks the INVERSE relation to IfcProduct
// // Let's find the IfcProducts that reference the IfcProductRepresentation anyway
// products->push((*it)->data().get_inverse((&IfcSchema::IfcProduct::Class()), -1)->as<IfcSchema::IfcProduct>());
// }
//
//
// IfcSchema::IfcRepresentationMap::list::ptr maps = representation->RepresentationMap();
//
//
// if (products->size() && maps->size()) {
// ifcopenshell::logger::root().warning("Representation used by IfcRepresentationMap and IfcProductDefinitionShape", representation);
// }
//
//
// if (prodreps->size() > 1) {
// ifcopenshell::logger::root().warning("Multiple IfcProductDefinitionShapes for representation", representation);
// }
//
//
// if (maps->size() > 1) {
// ifcopenshell::logger::root().warning("Multiple IfcRepresentationMaps for representation", representation);
// }
//
//
// if (maps->size() == 1) {
// IfcSchema::IfcRepresentationMap* map = *maps->begin();
// if (is_identity_transform(map->MappingOrigin())) {
@@ -688,11 +688,11 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// for (IfcSchema::IfcMappedItem::list::it it = items->begin(); it != items->end(); ++it) {
// IfcSchema::IfcMappedptr item = *it;
// if (item->StyledByItem()->size() != 0) continue;
//
//
// if (!is_identity_transform(item->MappingTarget())) {
// continue;
// }
//
//
// IfcSchema::IfcRepresentation::list::ptr reps = item->data().get_inverse((&IfcSchema::IfcRepresentation::Class()), -1)->as<IfcSchema::IfcRepresentation>();
// for (IfcSchema::IfcRepresentation::list::it jt = reps->begin(); jt != reps->end(); ++jt) {
// IfcSchema::IfcRepresentation* rep = *jt;
@@ -706,10 +706,10 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// return products;
// }
//
//
// ifcopenshell::geom::native_element* ifcopenshell::geom::Kernel::create_brep_for_processed_representation(
// const IteratorSettings& /*settings*/, IfcSchema::IfcRepresentation* representation, IfcSchema::IfcProduct* product,
// ifcopenshell::geom::native_element* brep)
@@ -723,10 +723,10 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// } catch (const std::exception& e) {
// ifcopenshell::logger::root().error(e);
// }
//
//
// const std::string name = product->Name().value_or("");
// const std::string guid = product->GlobalId();
//
//
// gp_Trsf trsf;
// try {
// if (product->ObjectPlacement()) {
@@ -737,16 +737,16 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// } catch (...) {
// ifcopenshell::logger::root().error("Failed to construct placement");
// }
//
//
// std::string context_string = "";
// if (representation->RepresentationIdentifier()) {
// context_string = *representation->RepresentationIdentifier();
// } else if (representation->ContextOfItems()->ContextType()) {
// context_string = *representation->ContextOfItems()->ContextType();
// }
//
//
// const std::string product_type = product->declaration().name();
//
//
// return new native_element(
// product->data().id(),
// parent_id,
@@ -759,24 +759,24 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// product
// );
// }
//
//
// bool ifcopenshell::geom::Kernel::convert_layerset(const IfcSchema::IfcProduct* product, std::vector<Handle_Geom_Surface>& surfaces, std::vector<std::shared_ptr<const SurfaceStyle>>& styles, std::vector<double>& thicknesses) {
//
//
// }
//
//
// bool ifcopenshell::geom::Kernel::find_wall_end_points(const IfcSchema::IfcWall* wall, gp_Pnt& start, gp_Pnt& end) {
// IfcSchema::IfcRepresentation* axis_representation = find_representation(wall, "Axis");
// if (!axis_representation) {
// return false;
// }
//
//
// std::vector<conversion_result> items;
// {
// Kernel temp = *this;
// temp.setValue(GV_DIMENSIONALITY, -1.);
// temp.convert_shapes(axis_representation, items);
// }
//
//
// TopoDS_Vertex a, b;
// for (std::vector<conversion_result>::const_iterator it = items.begin(); it != items.end(); ++it) {
// TopExp_Explorer exp(it->shape(), TopAbs_VERTEX);
@@ -787,36 +787,36 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// if (a.IsNull() || b.IsNull()) {
// return false;
// }
//
//
// start = BRep_Tool::Pnt(a);
// end = BRep_Tool::Pnt(b);
//
//
// return true;
// }
//
//
// bool ifcopenshell::geom::Kernel::fold_layers(const IfcSchema::IfcWall* wall, const std::vector<conversion_result>& items, const std::vector<Handle_Geom_Surface>& surfaces, const std::vector<double>& thicknesses, std::vector< std::vector<Handle_Geom_Surface> >& result) {
// /*
// * @todo isn't it easier to do this based on the non-folded surfaces of
// * the connected walls and fold both pairs of layersets simultaneously?
// */
//
//
// bool folds_made = false;
//
//
// IfcSchema::IfcRelConnectsPathElements::list::ptr connections(new IfcSchema::IfcRelConnectsPathElements::list);
// connections->push(wall->ConnectedFrom()->as<IfcSchema::IfcRelConnectsPathElements>());
// connections->push(wall->ConnectedTo()->as<IfcSchema::IfcRelConnectsPathElements>());
//
//
// typedef std::vector<Handle_Geom_Surface> surfaces_t;
// typedef std::pair<Handle_Geom_Surface, Handle_Geom_Curve> curve_on_surface;
// typedef std::vector<curve_on_surface> curves_on_surfaces_t;
// typedef std::vector< std::pair< std::pair<IfcSchema::IfcConnectionTypeEnum::Value, IfcSchema::IfcConnectionTypeEnum::Value>, const IfcSchema::IfcProduct*> > endpoint_connections_t;
// typedef std::vector< std::vector<Handle_Geom_Surface> > result_t;
// endpoint_connections_t endpoint_connections;
//
//
// // Find the semantic connections to other wall elements when they are not connected 'AT_PATH' because
// // in that latter case no folds need to be made.
// for (IfcSchema::IfcRelConnectsPathElements::list::it it = connections->begin(); it != connections->end(); ++it) {
@@ -838,18 +838,18 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// if (endpoint_connections.size() == 0) {
// return false;
// }
//
//
// // Count how many connections are made AT_START and AT_END respectively
// int connection_type_count[2] = { 0,0 };
// for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) {
// const int idx = it->first.first == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART;
// connection_type_count[idx] ++;
// }
//
//
// gp_Trsf local;
// if (wall->ObjectPlacement()) {
// if (!convert(wall->ObjectPlacement(), local)) {
@@ -857,7 +857,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// local.Invert();
//
//
// {
// // Copy the unfolded surfaces
// result.resize(surfaces.size());
@@ -867,25 +867,25 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// result_it->push_back(*input_it);
// }
// }
//
//
// const double total_thickness = std::accumulate(thicknesses.begin(), thicknesses.end(), 0.);
//
//
// gp_Pnt own_axis_start, own_axis_end;
// find_wall_end_points(wall, own_axis_start, own_axis_end);
//
//
// // Sometimes duplicate IfcRelConnectsPathElements exist. These are detected
// // and the counts of connections are decremented accordingly.
// for (int idx = 0; idx < 2; ++idx) {
// if (connection_type_count[idx] <= 1) {
// continue;
// }
//
//
// /*
// IfcSchema::IfcConnectionTypeEnum::Value connection_type = idx == 1
// ? IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
// : IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATEND;
// */
//
//
// std::set<const IfcSchema::IfcProduct*> others;
// endpoint_connections_t::iterator it = endpoint_connections.begin();
// while (it != endpoint_connections.end()) {
@@ -899,38 +899,38 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// // Check whether the end points are of the wall are really ~1 LayerThickness away from each other
// /*
// for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) {
// IfcSchema::IfcConnectionTypeEnum::Value own_type = it->first.first;
// IfcSchema::IfcConnectionTypeEnum::Value other_type = it->first.second;
//
//
// gp_Pnt other_axis_start, other_axis_end;
// find_wall_end_points(it->second->as<IfcSchema::IfcWall>(), other_axis_start, other_axis_end);
//
//
// gp_Trsf other;
// if (!convert(it->second->ObjectPlacement(), other)) {
// continue;
// }
//
//
// other.Transforms(other_axis_start.ChangeCoord());
// local.Transforms(other_axis_start.ChangeCoord());
// other.Transforms(other_axis_end.ChangeCoord());
// local.Transforms(other_axis_end.ChangeCoord());
//
//
// const gp_Pnt& a = own_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
// ? own_axis_start
// : own_axis_end;
//
//
// const gp_Pnt& b = other_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART
// ? other_axis_start
// : other_axis_end;
//
//
// const double d = a.Distance(b);
// }
// */
//
//
// const double length_required = endpoint_connections.size() * total_thickness;
// // @todo this is not precisely the distance in case of curved walls. Also, it's safer
// // to first reproject the body onto the axis to get the precise curve parametrization
@@ -940,20 +940,20 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// ifcopenshell::logger::root().warning("The wall axis is not long enough to accommodate the fold points");
// return false;
// }
//
//
// for (endpoint_connections_t::const_iterator it = endpoint_connections.begin(); it != endpoint_connections.end(); ++it) {
// IfcSchema::IfcConnectionTypeEnum::Value connection_type = it->first.first;
//
//
// // If more than one wall connects to this start/end -point assume layers do not need to be folded
// const int idx = connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATSTART;
// if (connection_type_count[idx] > 1) continue;
//
//
// // Pick the corresponding point from the axis
// const gp_Pnt& own_end_point = connection_type == IfcSchema::IfcConnectionTypeEnum::IfcConnectionType_ATEND
// ? own_axis_end
// : own_axis_start;
// const IfcSchema::IfcProduct* other_wall = it->second;
//
//
// gp_Trsf other;
// if (other_wall->ObjectPlacement()) {
// if (!convert(other_wall->ObjectPlacement(), other)) {
@@ -961,32 +961,32 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// continue;
// }
// }
//
//
// IfcSchema::IfcRepresentation* axis_representation = find_representation(other_wall, "Axis");
//
//
// if (!axis_representation) {
// ifcopenshell::logger::root().warning("Joined wall has no axis representation", other_wall);
// continue;
// }
//
//
// std::vector<conversion_result> axis_items;
// {
// Kernel temp = *this;
// temp.setValue(GV_DIMENSIONALITY, -1.);
// temp.convert_shapes(axis_representation, axis_items);
// }
//
//
// TopoDS_Shape axis_shape;
// util::flatten_shape_list(axis_items, axis_shape, false, getValue(GV_PRECISION));
//
//
// // local and other are IfcLocalPlacements and therefore have a unit
// // scale factor that can be applied by means of TopoDS_Shape::Move()
// axis_shape.Move(other);
// axis_shape.Move(local);
//
//
// TopoDS_Shape body_shape;
// util::flatten_shape_list(items, body_shape, false, getValue(GV_PRECISION));
//
//
// // Create a single paremetric range over a single curve
// // that represents the entire 1d domain of the other wall
// // Sometimes there are multiple edges in the Axis shape
@@ -998,19 +998,19 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// if (!exp.More()) {
// return false;
// }
//
//
// TopoDS_Edge axis_edge = TopoDS::Edge(exp.Current());
// other_axis_curve = BRep_Tool::Curve(axis_edge, axis_u1, axis_u2);
//
//
// gp_Pnt other_a_1, other_a_2;
// other_axis_curve->D0(axis_u1, other_a_1);
// other_axis_curve->D0(axis_u2, other_a_2);
//
//
// if (axis_u2 < axis_u1) {
// std::swap(axis_u1, axis_u2);
// }
// exp.Next();
//
//
// for (; exp.More(); exp.Next()) {
// TopoDS_Edge axis_edge2 = TopoDS::Edge(exp.Current());
// TopExp_Explorer exp2(axis_edge2, TopAbs_VERTEX);
@@ -1025,22 +1025,22 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// double layer_offset = 0;
//
//
// std::vector<double>::const_iterator thickness = thicknesses.begin();
// result_t::iterator result_vector = result.begin() + 1;
//
//
// // nb The first layer is never folded, because it corresponds
// // to one of the longitudinal faces of the wall. Hence the +1
// for (surfaces_t::const_iterator jt = surfaces.begin() + 1; jt != surfaces.end() - 1; ++jt, ++result_vector) {
// layer_offset += *thickness++;
//
//
// bool found_intersection = false, parallel = false;
// std::optional<gp_Pnt> point_outside_param_range;
//
//
// const Handle_Geom_Surface& surface = *jt;
//
//
// // Find the intersection point between the layerset surface
// // and the other axis curve. If it's within the parametric
// // range of the other wall it means the walls are connected
@@ -1048,16 +1048,16 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// GeomAPI_IntCS intersections(other_axis_curve, surface);
// if (intersections.IsDone() && intersections.NbPoints() == 1) {
// const gp_Pnt& p = intersections.Point(1);
//
//
// double u, v, w;
// intersections.Parameters(1, u, v, w);
//
//
// gp_Pnt Pc, Ps;
// gp_Vec Vc, Vs1, Vs2;
// other_axis_curve->D1(w, Pc, Vc);
// surface->D1(u, v, Ps, Vs1, Vs2);
// Vs1.Cross(Vs2);
//
//
// if (Vs1.IsNormal(Vc, 1.e-5)) {
// ifcopenshell::logger::root().warning("Connected walls are parallel");
// parallel = true;
@@ -1069,9 +1069,9 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// break;
// }
// }
//
//
// if (!parallel && !found_intersection && point_outside_param_range) {
//
//
// /*
// Is there a bug in Open Cascade related to the intersection
// of offset surfaces constructed from linear extrusions?
@@ -1083,13 +1083,13 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// Handle_Geom_Surface yz2 = new Geom_OffsetSurface(yz, 1.);
// intersect(xy, yz2);
// */
//
//
// Handle_Geom_Surface plane = new Geom_Plane(*point_outside_param_range, gp::DZ());
//
//
// // vertical edges at wall end point face.
// curves_on_surfaces_t layer_ends;
// util::intersect(surface, body_shape, layer_ends);
//
//
// Handle_Geom_Curve layer_body_intersection;
// Handle_Geom_Surface body_surface;
// double mind = std::numeric_limits<double>::infinity();
@@ -1111,9 +1111,9 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// if (d < total_thickness * 3 && d < mind) {
// GeomAdaptor_Curve GAC(other_axis_curve);
// GeomAdaptor_Surface GAS(kt->first);
//
//
// Extrema_ExtCS x(GAC, GAS, getValue(GV_PRECISION), getValue(GV_PRECISION));
//
//
// if (x.IsParallel()) {
// body_surface = kt->first;
// layer_body_intersection = kt->second;
@@ -1122,16 +1122,16 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// if (body_surface.IsNull()) {
// continue;
// }
//
//
// // Intersect vertical edge with ground plane for point.
// GeomAPI_IntCS intersection2(layer_body_intersection, plane);
// if (intersection2.IsDone() && intersection2.NbPoints() == 1) {
// const gp_Pnt& layer_end_point = intersection2.Point(1);
//
//
// // Intersect layerset surface with ground plane
// GeomAPI_IntSS intersection3(surface, plane, 1.e-7);
// if (intersection3.IsDone() && intersection3.NbLines() == 1) {
@@ -1140,14 +1140,14 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// ShapeAnalysis_Curve sac;
// gp_Pnt layer_end_point_projected; double layer_end_point_param;
// sac.Project(layer_line, layer_end_point, 1e-3, layer_end_point_projected, layer_end_point_param, false);
//
//
// // Move point inwards by distance from other layerset
// GCPnts_AbscissaPoint dst(layer_line_adaptor, layer_offset, layer_end_point_param);
// if (dst.IsDone()) {
// // Convert parameter to point
// gp_Pnt layer_fold_point;
// layer_line->D0(dst.Parameter(), layer_fold_point);
//
//
// GeomAPI_IntSS intersection4(body_surface, plane, 1.e-7);
// if (intersection4.IsDone() && intersection4.NbLines() == 1) {
// Handle_Geom_Curve body_trim_curve = intersection4.Line(1);
@@ -1155,7 +1155,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// gp_Pnt layer_fold_point_projected; double layer_fold_point_param;
// sac2.Project(body_trim_curve, layer_fold_point, 1.e-7, layer_fold_point_projected, layer_fold_point_param, false);
// Handle_Geom_Curve fold_curve = new Geom_OffsetCurve(body_trim_curve->Reversed(), layer_fold_point_projected.Distance(layer_fold_point), gp::DZ());
//
//
// Handle_Geom_Surface fold_surface = new Geom_SurfaceOfLinearExtrusion(fold_curve, gp::DZ());
// result_vector->push_back(fold_surface);
// folds_made = true;
@@ -1163,15 +1163,15 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// }
// }
//
//
// }
//
//
// }
// }
//
//
// return folds_made;
// }
//
//
// IfcSchema::IfcRepresentation* ifcopenshell::geom::Kernel::find_representation(const IfcSchema::IfcProduct* product, const std::string& identifier) {
// if (!product->Representation()) return 0;
// IfcSchema::IfcProductRepresentation* prod_rep = product->Representation();
@@ -1183,12 +1183,12 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// return 0;
// }
//
//
// const IfcSchema::IfcRepresentationptr ifcopenshell::geom::Kernel::find_item_carrying_style(const IfcSchema::IfcRepresentationptr item) {
// if (item->StyledByItem()->size()) {
// return item;
// }
//
//
// while (item->declaration().is(IfcSchema::IfcBooleanResult::Class())) {
// // All instantiations of IfcBooleanOperand (type of FirstOperand) are subtypes of
// // IfcGeometricRepresentationItem
@@ -1197,24 +1197,24 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// return item;
// }
// }
//
//
// // TODO: Ideally this would be done for other entities (such as IfcCsgSolid) as well.
// // But neither are these very prevalent, nor does the current IfcOpenShell style
// // mechanism enable to conveniently style subshapes, which would be necessary for
// // distinctly styled union operands.
//
//
// return item;
// }
//
//
// bool ifcopenshell::geom::Kernel::is_identity_transform(ifcopenshell::IfcBaseInterface* l) {
// IfcSchema::IfcAxis2Placement2D* ax2d;
// IfcSchema::IfcAxis2Placement3D* ax3d;
//
//
// IfcSchema::IfcCartesianTransformationOperator2D* op2d;
// IfcSchema::IfcCartesianTransformationOperator3D* op3d;
// IfcSchema::IfcCartesianTransformationOperator2DnonUniform* op2dnonu;
// IfcSchema::IfcCartesianTransformationOperator3DnonUniform* op3dnonu;
//
//
// if ((op2dnonu = l->as<IfcSchema::IfcCartesianTransformationOperator2DnonUniform>()) != 0) {
// gp_GTrsf2d gtrsf2d;
// convert(op2dnonu, gtrsf2d);
@@ -1243,18 +1243,18 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// throw ifcopenshell::exception("Invalid valuation for IfcAxis2Placement / IfcCartesianTransformationOperator");
// }
// }
//
//
// void ifcopenshell::geom::Kernel::set_conversion_placement_rel_to_type(const ifcopenshell::declaration* type) {
// placement_rel_to_type_ = type;
// }
//
//
// void ifcopenshell::geom::Kernel::set_conversion_placement_rel_to_instance(const express::entity* instance) {
// placement_rel_to_instance_ = instance;
// }
//
//
//
//
// namespace {
//
//
// bool process_colour(IfcSchema::IfcColourRgb* colour, double* rgb) {
// if (colour != 0) {
// rgb[0] = colour->Red();
@@ -1263,7 +1263,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// return colour != 0;
// }
//
//
// bool process_colour(IfcSchema::IfcNormalisedRatioMeasure* factor, double* rgb) {
// if (factor != 0) {
// const double f = *factor;
@@ -1271,7 +1271,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// return factor != 0;
// }
//
//
// bool process_colour(IfcSchema::IfcColourOrFactor* colour_or_factor, double* rgb) {
// if (colour_or_factor == 0) {
// return false;
@@ -1283,11 +1283,11 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// return false;
// }
// }
//
//
// }
//
//
// #define Kernel POSTFIX_SCHEMA(Kernel)
//
//
// std::shared_ptr<const ifcopenshell::geom::SurfaceStyle> ifcopenshell::geom::Kernel::internalize_surface_style(const std::pair<express::base, express::base>& shading_styles) {
// if (shading_styles.second == 0) {
// return 0;
@@ -1297,22 +1297,22 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// if (it != style_cache.end()) {
// return it->second;
// }
//
//
//
//
// IfcSchema::IfcSurfaceStyle* style = shading_styles.first->as<IfcSchema::IfcSurfaceStyle>();
// IfcSchema::IfcSurfaceStyleShading* shading = shading_styles.second->as<IfcSchema::IfcSurfaceStyleShading>();
//
//
// std::shared_ptr<SurfaceStyle> surface_style_ptr;
//
//
// if (style->Name()) {
// surface_style_ptr.reset(new SurfaceStyle(surface_style_id, *style->Name()));
// } else {
// surface_style_ptr.reset(new SurfaceStyle(surface_style_id));
// }
//
//
// std::shared_ptr<const SurfaceStyle> surface_style_ptr_const = std::const_pointer_cast<const SurfaceStyle>(surface_style_ptr);
// SurfaceStyle& surface_style = *surface_style_ptr;
//
//
// double rgb[3];
// if (process_colour(shading->SurfaceColour(), rgb)) {
// surface_style.Diffuse().reset(SurfaceStyle::ColorComponent(rgb[0], rgb[1], rgb[2]));
@@ -1353,11 +1353,11 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// }
// return style_cache[surface_style_id] = surface_style_ptr_const;
// }
//
//
// std::shared_ptr<const ifcopenshell::geom::SurfaceStyle> ifcopenshell::geom::Kernel::get_style(const IfcSchema::IfcRepresentationptr item) {
// return internalize_surface_style(get_surface_style<IfcSchema::IfcSurfaceStyleShading>(item));
// }
//
//
// std::shared_ptr<const ifcopenshell::geom::SurfaceStyle> ifcopenshell::geom::Kernel::get_style(const IfcSchema::IfcMaterial* material) {
// IfcSchema::IfcMaterialDefinitionRepresentation::list::ptr defs = material->HasRepresentation();
// for (IfcSchema::IfcMaterialDefinitionRepresentation::list::it jt = defs->begin(); jt != defs->end(); ++jt) {
@@ -1376,14 +1376,14 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// auto material_style = std::make_shared<ifcopenshell::geom::SurfaceStyle>(material->data().id(), material->Name());
// return style_cache[material->data().id()] = material_style;
// }
//
//
// void ifcopenshell::geom::Kernel::apply_layerset(std::vector<ifcopenshell::geom::conversion_result>& r, const ifcopenshell::geom::layerset_information& info) {
// convert(info.layers);
//
//
// if (info.layers.empty()) {
// return;
// }
//
//
// if (axis_curve->DynamicType() == STANDARD_TYPE(Geom_Line)) {
// Handle_Geom_Line axis_line = Handle_Geom_Line::DownCast(axis_curve);
// // @todo note that this creates an offset into the wrong order, the cross product arguments should be
@@ -1397,7 +1397,7 @@ bool ifcopenshell::geom::open_cascade_kernel::convert_impl(const taxonomy::revol
// ifcopenshell::logger::root().message(ifcopenshell::logger::LOG_ERROR, "Unsupported underlying curve of Axis representation:", product);
// return false;
// }
//
//
// std::vector<ifcopenshell::geom::conversion_result> r2;
// if (ifcopenshell::geom::util::apply_layerset(r, const std::vector<ifcopenshell::geom::taxonomy::style>&, std::vector<conversion_result>& r2, double tol)) {
// std::swap(r, r2)
@@ -90,7 +90,7 @@ private:
std::map<std::pair<int, int>, TopoDS_Edge> edges_;
double eps_;
bool non_manifold_;
void loop_(const ifcopenshell::geom::taxonomy::loop::ptr ps, const std::function<void(int, int, bool)>& callback);
public:
faceset_helper(open_cascade_kernel* kernel, const ifcopenshell::geom::taxonomy::shell::ptr l);
@@ -99,7 +99,7 @@ private:
bool non_manifold() const { return non_manifold_; }
bool& non_manifold() { return non_manifold_; }
double epsilon() const { return eps_; }
bool edge(int A, int B, TopoDS_Edge& e);
bool wire(const ifcopenshell::geom::taxonomy::loop::ptr loop, TopoDS_Wire& wire);
+2 -2
View File
@@ -64,8 +64,8 @@ bool open_cascade_kernel::convert(const taxonomy::solid::ptr solid, TopoDS_Shape
result = halfspace;
return true;
} else if (solid->children.size() == 1
&& solid->children[0]->children.size() == 1
} else if (solid->children.size() == 1
&& solid->children[0]->children.size() == 1
&& solid->children[0]->children[0]->basis
&& solid->children[0]->children[0]->basis->kind() == taxonomy::SPHERE)
{
@@ -126,7 +126,7 @@ bool open_cascade_kernel::convert(const taxonomy::sweep_along_curve::ptr scs, To
}
}
}
// Build the wire from curve, which is the directrix offset toward the origin
// when applied_temporary_offset is set. Using scs->curve here left the wire
// far from the origin yet still translated the result back by +mean, which
@@ -155,11 +155,11 @@ bool open_cascade_kernel::convert(const taxonomy::sweep_along_curve::ptr scs, To
} else {
return false;
}
Handle(Geom_Surface) surface;
if (scs->surface) {
surface = convert_surface(scs->surface);
}
}
gp_Trsf directrix;
TopoDS_Wire wire = std::get<TopoDS_Wire>(w);
+18 -18
View File
@@ -201,12 +201,12 @@ namespace ifcopenshell::geom {
box.corners[1][1] = static_cast<float>(max_point[1] + 1e-5);
box.corners[1][2] = static_cast<float>(max_point[2] + 1e-5);
/*
std::cout << "Ray "
std::cout << "Ray "
<< v_ray.origin[0] << " "
<< v_ray.origin[1] << " "
<< v_ray.origin[2] << " "
<< std::endl;
std::cout << "Box "
std::cout << "Box "
<< min_point[0] << " "
<< min_point[1] << " "
<< min_point[2] << " "
@@ -864,7 +864,7 @@ namespace ifcopenshell::geom {
if (dss.Value() <= extend) {
distances_.push_back(dss.Value());
protrusion_distances_.push_back(max_distance_inside(B, A));
}
}
return dss.Value() <= extend;
}
} else {
@@ -925,8 +925,8 @@ namespace ifcopenshell::geom {
// Gap is assumed to be positive throughout the codebase,
// but at least for IsOut() in the selector a negative
// Gap should work as well.
b.SetGap(b.GetGap() + extend);
b.SetGap(b.GetGap() + extend);
return select_box(b, completely_within);
}
@@ -956,7 +956,7 @@ namespace ifcopenshell::geom {
double gap = B.GetGap();
gp_Pnt p1(x1 - gap, y1 - gap, z1 - gap);
gp_Pnt p2(x2 + gap, y2 + gap, z2 + gap);
if (!b.IsOut(p1) && !b.IsOut(p2)) {
ts_filtered.push_back(*it);
}
@@ -1389,7 +1389,7 @@ namespace ifcopenshell::geom {
if (extend > 0.0) {
BRepExtrema_DistShapeShape dss(v, B);
if (dss.Perform() && dss.NbSolution() >= 1 && dss.Value() <= extend) {
distances_.push_back(dss.Value());
distances_.push_back(dss.Value());
protrusion_distances_.push_back(max_distance_inside(B, v));
ts_filtered.push_back(*it);
@@ -1416,9 +1416,9 @@ namespace ifcopenshell::geom {
spatial_tree tree_;
shape_map shapes_;
std::map<T, Bnd_Box> aabbs_;
std::map<T, Bnd_OBB> obbs_;
std::map<T, double> max_protrusions_;
std::map<T, opencascade::handle<BVH_Tree<double, 3, BVH_BinaryTree>>> bvhs_;
std::map<T, Bnd_OBB> obbs_;
std::map<T, double> max_protrusions_;
std::map<T, opencascade::handle<BVH_Tree<double, 3, BVH_BinaryTree>>> bvhs_;
std::unordered_map<T, bool> is_manifold_;
std::unordered_map<T, std::vector<std::array<int, 3>>> tris_;
std::unordered_map<T, std::vector<gp_Pnt>> verts_;
@@ -1433,7 +1433,7 @@ namespace ifcopenshell::geom {
std::map<std::string, std::vector<int>> local_faces_;
std::map<std::string, std::vector<ifcopenshell::geom::taxonomy::style::ptr>> local_materials_;
std::map<std::string, std::vector<int>> local_material_ids_;
bool enable_face_styles_ = false;
class selector : public spatial_tree::Selector
@@ -1480,7 +1480,7 @@ namespace ifcopenshell::geom {
opencascade_tree(ifcopenshell::geom::iterator& it) {
add_file(it);
}
}
void add_file(ifcopenshell::file& f, ifcopenshell::geom::settings settings) {
ifcopenshell::geom::settings settings_ = settings;
@@ -1509,7 +1509,7 @@ namespace ifcopenshell::geom {
result.reserve(flat_list.size());
for (size_t i = 0; i < flat_list.size(); i += 3) {
vin <<
vin <<
flat_list[i],
flat_list[i + 1],
flat_list[i + 2];
@@ -1576,7 +1576,7 @@ namespace ifcopenshell::geom {
vs_transformed.push_back(p.Transformed(tr));
aabb.Add(vs_transformed.back());
}
std::unordered_map<std::tuple<int, int, int>, std::vector<size_t>, boost::hash<std::tuple<int, int, int>>> quantized_normal_counts;
std::vector<double> tri_areas;
@@ -1631,7 +1631,7 @@ namespace ifcopenshell::geom {
gp_Ax3 ax3;
gp_Trsf trsf2;
for (size_t attempt = 0; attempt < 2; ++attempt) {
if (candidates.empty() || attempt == 1) {
@@ -1673,7 +1673,7 @@ namespace ifcopenshell::geom {
obb.SetZComponent(ax3.Direction(), halfsize.Z());
obb.SetCenter(cent.Transformed(trsf2.Inverted()));
}
const auto& t = elem->product();
const auto& matrix = elem->transformation().data();
const std::vector<double>& elem_verts_local = elem->geometry().verts();
@@ -1744,7 +1744,7 @@ namespace ifcopenshell::geom {
obbs_[t] = obb;
max_protrusions_[t] = std::min(std::min(obb.XHSize(), obb.YHSize()), obb.ZHSize()) * 2;
}
void add_element(ifcopenshell::geom::native_element* elem) {
if (!elem) {
return;
@@ -1753,7 +1753,7 @@ namespace ifcopenshell::geom {
auto compound_generic = (ifcopenshell::geom::open_cascade_shape*)elem->geometry().as_compound();
TopoDS_Shape compound(std::move(compound_generic->shape()));
delete compound_generic;
const auto& m = elem->transformation().data()->ccomponents();
gp_Trsf tr;
tr.SetValues(
@@ -381,7 +381,7 @@ namespace {
bool ifcopenshell::geom::util::wire_intersections(const TopoDS_Wire& wire, NCollection_List<TopoDS_Shape>& wires, const wire_tolerance_settings& settings) {
double eps = get_wire_intersection_tolerance(settings, wire);
double eps_real = settings.precision;
if (!wire.Closed()) {
wires.Append(wire);
return false;
@@ -576,7 +576,7 @@ void ifcopenshell::geom::util::select_largest(const NCollection_List<TopoDS_Shap
BRepBndLib::AddClose(it.Value(), bb);
double xyz_min[3], xyz_max[3];
bb.Get(xyz_min[0], xyz_min[1], xyz_min[2], xyz_max[0], xyz_max[1], xyz_max[2]);
// @todo hard coded precision.
// @todo this is a really strange measure for wire size. Why not use newell's
// method to project to plane and then calculate size of the 2d bbox?
@@ -45,7 +45,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef& i
}
}
}
return face;
} else {
return nullptr;
+1 -1
View File
@@ -35,7 +35,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcAxis1Placement& inst) {
taxonomy::direction3::ptr v = taxonomy::cast<taxonomy::direction3>(map(inst.Axis()));
axis = *v->components_;
}
// @todo not sure what to do with ref, we're probably never reading it,
// because we just created an Axis1 again from it in the kernel, but
// to this constructor we need to supply something valid.
@@ -27,12 +27,12 @@ using namespace ifcopenshell::geom;
#ifdef SCHEMA_HAS_IfcBSplineCurveWithKnots
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcBSplineCurveWithKnots& inst) {
auto bc = taxonomy::make<taxonomy::bspline_curve>();
const std::vector<IfcSchema::IfcCartesianPoint> cps = inst.ControlPointsList();
std::vector<taxonomy::point3::ptr> points;
std::transform(cps.begin(), cps.end(), std::back_inserter(points), [this](const IfcSchema::IfcCartesianPoint& cp) { return taxonomy::cast<taxonomy::point3>(map(cp)); });
bc->control_points = points;
auto knot_multiplicities = inst.KnotMultiplicities();
bc->multiplicities.assign(knot_multiplicities.begin(), knot_multiplicities.end());
bc->knots = inst.Knots();
@@ -73,7 +73,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCenterLineProfileDef&) {
mw.Add(BRepBuilderAPI_MakeEdge(c1a, c2a));
mw.Add(BRepBuilderAPI_MakeEdge(c2));
mw.Add(BRepBuilderAPI_MakeEdge(c2b, c1b));
face = BRepBuilderAPI_MakeFace(mw.Wire());
} else {
BRepOffsetAPI_MakeOffset offset(BRepBuilderAPI_MakeFace(gp_Pln(gp::Origin(), gp::DZ())));
+1 -1
View File
@@ -23,7 +23,7 @@ using namespace ifcopenshell::geom;
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCircle& inst) {
const double r = inst.Radius() * length_unit_;
if (r < settings_.get<settings::Precision>().get()) {
if (r < settings_.get<settings::Precision>().get()) {
logger_.message(ifcopenshell::logger::LOG_ERROR, "GEO", 237, "Radius not greater than zero for:", inst);
return nullptr;
}
+1 -1
View File
@@ -31,7 +31,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve& inst) {
#else
std::vector<IfcSchema::IfcCompositeCurveSegment> segments = inst.Segments();
#endif
for (auto& segment : segments) {
if (segment.as<IfcSchema::IfcCompositeCurveSegment>() && segment.as<IfcSchema::IfcCompositeCurveSegment>().ParentCurve().as<IfcSchema::IfcLine>()) {
logger_.notice("GEO", 238, "Infinite IfcLine used as ParentCurve of segment, treating as a segment", segment);
+1 -1
View File
@@ -25,7 +25,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCurveBoundedPlane& inst) {
taxonomy::plane::ptr pl = taxonomy::cast<taxonomy::plane>(map(inst.BasisSurface()));
auto f = taxonomy::make<taxonomy::face>();
f->children.push_back(taxonomy::cast<taxonomy::loop>(map(inst.OuterBoundary())));
std::vector<IfcSchema::IfcCurve> boundaries = inst.InnerBoundaries();
for (auto& b : boundaries) {
+10 -10
View File
@@ -133,7 +133,7 @@ struct spiral_parent_curve : public parent_curve_function {
// this is the piecewise curve segment function for horizontal and vertical
struct curve_segment_function {
curve_segment_function(const Eigen::Matrix4d& curve_segment_placement, const Eigen::Matrix4d& parent_curve_normalization, std::shared_ptr<parent_curve_function> parent_curve_fn) :
curve_segment_function(const Eigen::Matrix4d& curve_segment_placement, const Eigen::Matrix4d& parent_curve_normalization, std::shared_ptr<parent_curve_function> parent_curve_fn) :
curve_segment_placement_(curve_segment_placement),
parent_curve_normalization_(parent_curve_normalization),
parent_curve_fn_(parent_curve_fn) {
@@ -153,7 +153,7 @@ struct curve_segment_function {
// this is the piecewise curve segment function for cant
struct cant_curve_segment_function {
cant_curve_segment_function(const Eigen::Matrix4d& curve_segment_placement, const Eigen::Matrix4d& parent_curve_start_point, std::shared_ptr<parent_curve_function> parent_curve_fn) :
cant_curve_segment_function(const Eigen::Matrix4d& curve_segment_placement, const Eigen::Matrix4d& parent_curve_start_point, std::shared_ptr<parent_curve_function> parent_curve_fn) :
curve_segment_placement_(curve_segment_placement),
parent_curve_start_point_(parent_curve_start_point),
parent_curve_fn_(parent_curve_fn) {
@@ -354,7 +354,7 @@ class curve_segment_evaluator {
} else {
// The parent curve function returns the 4x4 matrix for the parent curve.
// Normalize the parent curve so that the trim start point and tangent direction at the start point
// are aligned with the origin. This is accomplished with a normalization matrix that subtracts the
// are aligned with the origin. This is accomplished with a normalization matrix that subtracts the
// incremental parent curve start point and applies a rotation. Apply the incremental
// translation and rotation to the curve_segment_placement to get the curve_segment_point
@@ -623,7 +623,7 @@ class curve_segment_evaluator {
} else if (segment_type_ == ST_CANT) {
std::optional<std::function<double(double)>> super, slope;
std::tie(super, slope) = get_superelevation_functions();
auto cant = [constant_term, cosine_term, L](double t) -> double {
auto a0 = constant_term.has_value() ? 1 / constant_term.value() : 0.0;
auto a1 = (1 / cosine_term) * cos(PI * t / L);
@@ -690,7 +690,7 @@ class curve_segment_evaluator {
} else if (segment_type_ == ST_CANT) {
std::optional<std::function<double(double)>> super, slope;
std::tie(super, slope) = get_superelevation_functions();
auto cant = [constant_term, linear_term, sine_term, L](double t) -> double {
auto a0 = constant_term.has_value() ? 1 / constant_term.value() : 0.0;
auto a1 = linear_term.has_value() ? (linear_term.value()/fabs(linear_term.value())) * pow(1 / linear_term.value(), 2.0) * t : 0.0;
@@ -825,7 +825,7 @@ class curve_segment_evaluator {
#else
A3 = c.QubicTerm();
#endif
if (segment_type_ == ST_CANT) {
polynomial_cant_spiral(A0, A1, A2, A3, A4, A5, A6, A7);
} else {
@@ -983,7 +983,7 @@ class curve_segment_evaluator {
[](double /*u*/) -> Eigen::Matrix4d { return Eigen::Matrix4d::Identity(); });
}
}
void operator()(const IfcSchema::IfcLine& l) {
projected_length_ = length_;
@@ -995,8 +995,8 @@ class curve_segment_evaluator {
// 8.9.3.30 IfcDirection https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/lexical/IfcDirection.htm
// "The IfcDirection does not imply a vector length, and the direction ratios does not have to be normalized."
//
// Therefore, the direction ratios need to be normalized to compute points on the line.
//
// Therefore, the direction ratios need to be normalized to compute points on the line.
//
// Magnitude is not used because it relates to the parameterization of the line, which isn't currently done for IfcCurveSegment
// @todo - parameterization was recently added so Magnitude needs to be taking into consideration
auto dr = l.Dir().Orientation().DirectionRatios();
@@ -1030,7 +1030,7 @@ class curve_segment_evaluator {
auto pcDZy = curve_segment_placement_ ? (*curve_segment_placement_)(1, 2) : 0.;
auto pcDZz = curve_segment_placement_ ? (*curve_segment_placement_)(2, 2) : 1.;
parent_curve_fn_ = std::make_shared<line_parent_curve>(
[segment_type = segment_type_,pcX, pcY, pcDXx, pcDXy, pcDZy, pcDZz, convert_u](double u)->Eigen::Matrix4d {
u = convert_u(u);
@@ -56,7 +56,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolidTapered& in
if (has_position) {
matrix = taxonomy::cast<taxonomy::matrix4>(map(inst.Position()));
}
loft->matrix = matrix;
return loft;
+2 -2
View File
@@ -24,7 +24,7 @@ using namespace ifcopenshell::geom;
#ifdef SCHEMA_HAS_IfcIndexedPolyCurve
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcIndexedPolyCurve& inst) {
auto point_list = inst.Points();
std::vector< std::vector<double> > coordinates;
if (point_list.as<IfcSchema::IfcCartesianPointList2D>()) {
@@ -100,7 +100,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcIndexedPolyCurve& inst) {
previous = current;
}
}
return loop;
}
+1 -1
View File
@@ -32,7 +32,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcLShapeProfileDef& inst) {
const double x = inst.Width().value_or(inst.Depth()) / 2.0f * length_unit_;
const double d = inst.Thickness() * length_unit_;
const double slope = inst.LegSlope().value_or(0.) * angle_unit_;
double f1 = 0.0f;
double f2 = 0.0f;
if (doFillet) {
@@ -84,11 +84,11 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances& inst
double pz = first_offset_value.OffsetVertical().value_or(0.0);
py *= length_unit_;
pz *= length_unit_;
auto fn = [py, pz](double /*u*/) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = py;
m.col(3)(2) = pz;
auto fn = [py, pz](double /*u*/) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = py;
m.col(3)(2) = pz;
return m; };
offset_spans.emplace_back(taxonomy::make<taxonomy::functor_item>(first_distance, fn));
}
@@ -146,7 +146,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances& inst
zn = zn_at_end;
}
auto fn = [yp, yn, zp, zn, l](double u) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = (l == 0.0 ? yp : (yp + (yn - yp) * u / l));
@@ -171,10 +171,10 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOffsetCurveByDistances& inst
py *= length_unit_;
pz *= length_unit_;
double l = basis_curve_length - last_distance;
auto fn = [py, pz](double /*u*/) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = py;
m.col(3)(2) = pz;
auto fn = [py, pz](double /*u*/) -> Eigen::Matrix4d {
Eigen::Matrix4d m = Eigen::Matrix4d::Identity();
m.col(3)(1) = py;
m.col(3)(2) = pz;
return m; };
offset_spans.emplace_back(taxonomy::make<taxonomy::functor_item>(l, fn));
@@ -87,7 +87,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcOpenCrossProfileDef& inst) {
auto r = taxonomy::loop::ptr((taxonomy::loop*)mapped->clone_());
r->closed = false;
return r;
}*/
}*/
mapped->closed = false;
mapped->tags = tags;
+1 -1
View File
@@ -24,5 +24,5 @@ using namespace ifcopenshell::geom;
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPlane& inst) {
auto p = taxonomy::make<taxonomy::plane>();
p->matrix = taxonomy::cast<taxonomy::matrix4>(map(inst.Position()));
return p;
return p;
}
@@ -45,7 +45,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPointByDistanceExpression& i
if (inst.OffsetLateral().has_value()) {
auto offset_lateral = inst.OffsetLateral().value() * length_unit_;
auto y = Eigen::Vector3d(m.col(1)(0), m.col(1)(1), m.col(1)(2));
auto y = Eigen::Vector3d(m.col(1)(0), m.col(1)(1), m.col(1)(2));
o += offset_lateral * y;
}
+1 -1
View File
@@ -50,7 +50,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolyLoop& inst) {
int count = polygon.size();
if (original_count - count != 0) {
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
logger_.message(ifcopenshell::logger::LOG_WARNING, "GEO", 280, ss.str(), inst);
}
+1 -1
View File
@@ -61,7 +61,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolygonalFaceSet& inst) {
for (auto& f : polygonal_faces) {
auto fa = taxonomy::make<taxonomy::face>();
shell->children.push_back(fa);
{
auto loop = taxonomy::make<taxonomy::loop>();
fa->children = { loop };
+2 -2
View File
@@ -44,7 +44,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcProduct& inst) {
}
if (openings->size() && !settings_.get(IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && use_body) {
Eigen::Matrix4d ci;
if (c->matrix.components_) {
ci = c->matrix.components_->inverse();
@@ -69,7 +69,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcProduct& inst) {
c->children = { child };
} else {
delete c;
return nullptr;
return nullptr;
}
}
@@ -33,7 +33,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRectangleHollowProfileDef& i
const double r1 = fr1 ? (*inst.OuterFilletRadius()) * length_unit_ : 0.;
const double r2 = fr2 ? (*inst.InnerFilletRadius()) * length_unit_ : 0.;
const double tol = settings_.get<settings::Precision>().get();
if (x < tol || y < tol) {
@@ -42,7 +42,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRectangleProfileDef& inst) {
if (has_position) {
m4 = taxonomy::cast<taxonomy::matrix4>(map(inst.Position()));
}
return profile_helper(m4, {
{{-x,-y}},
{{x,-y}},
+1 -1
View File
@@ -27,7 +27,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRevolvedAreaSolid& inst) {
const double ang = inst.Angle() * angle_unit_;
taxonomy::cast<taxonomy::face>(map(inst.SweptArea()));
std::optional<double> angle;
taxonomy::matrix4::ptr matrix;
@@ -32,7 +32,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRightCircularCylinder&) {
BRepPrimAPI_MakeCylinder builder(r, h);
gp_Trsf trsf;
ifcopenshell::geom::Kernel::convert(inst.Position(),trsf);
// IfcCsgPrimitive3D.Position has unit scale factor
shape = builder.Solid().Moved(trsf);
@@ -38,7 +38,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal& in
return nullptr;
}
{
{
auto css = inst.CrossSections();
auto csps = inst.CrossSectionPositions();
std::vector<taxonomy::face::ptr> faces;
@@ -47,7 +47,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal& in
// reference frame along a certain curve location (b) the longitude.
// The longitudes determine the range of the sweep and the offsets are interpolated in between
// sweep segments.
// sweep segments.
std::vector<Eigen::Vector3d> profile_offsets;
std::vector<std::optional<Eigen::Matrix3d>> profile_rotations;
std::vector<double> longitudes;
+2 -2
View File
@@ -39,7 +39,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSurface& inst) {
}
{
{
auto css = inst.CrossSections();
auto csps = inst.CrossSectionPositions();
std::vector<taxonomy::geom_item::ptr> faces;
@@ -48,7 +48,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSurface& inst) {
// reference frame along a certain curve location (b) the longitude.
// The longitudes determine the range of the sweep and the offsets are interpolated in between
// sweep segments.
// sweep segments.
std::vector<Eigen::Vector3d> profile_offsets;
std::vector<std::optional<Eigen::Matrix3d>> profile_rotations;
std::vector<double> longitudes;
@@ -28,7 +28,7 @@ using namespace ifcopenshell::geom;
taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSegmentedReferenceCurve& inst) {
if (!inst.BaseCurve().as<IfcSchema::IfcGradientCurve>())
logger_.warning("GEO", 291, "Expected IfcSegmentedReferenceCurve.BaseCurve to be IfcGradient", inst); // CT 4.1.7.1.1.3
auto segments = inst.Segments();
taxonomy::piecewise_function::span_list spans;
+6 -6
View File
@@ -97,9 +97,9 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSweptDiskSolid& inst) {
return taxonomy::make<taxonomy::sweep_along_curve>(taxonomy::make<taxonomy::matrix4>(), f, nullptr, loop);
/*
TopoDS_Wire wire, section1, section2;
bool hasInnerRadius = !!inst.InnerRadius();
@@ -107,7 +107,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSweptDiskSolid& inst) {
if (!convert_wire(inst.Directrix(), wire)) {
return false;
}
if (util::count(wire, TopAbs_EDGE) == 1 && sp && ep) {
@@ -119,7 +119,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSweptDiskSolid& inst) {
double a, b;
auto crv = BRep_Tool::Curve(e, a, b);
if ((crv->DynamicType() == STANDARD_TYPE(Geom_Circle)) ||
(crv->DynamicType() == STANDARD_TYPE(Geom_Ellipse)))
(crv->DynamicType() == STANDARD_TYPE(Geom_Ellipse)))
{
BRepBuilderAPI_MakeEdge me(crv, *sp, *ep);
if (me.IsDone()) {
@@ -227,7 +227,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSweptDiskSolid& inst) {
j += 1;
} else {
ifcopenshell::logger::root().error("Unexpected amount of fillet edges generated");
}
}
} else {
ifcopenshell::logger::root().error("Unable to build fillet, probably edge too short");
}
@@ -258,7 +258,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSweptDiskSolid& inst) {
// NB: Note that StartParam and EndParam param are ignored and the assumption is
// made that the parametric range over which to be swept matches the IfcCurve in
// its entirety.
util::process_sweep(wire, inst.Radius() * length_unit_, shape);
if (shape.IsNull()) {
+1 -1
View File
@@ -43,7 +43,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTShapeProfileDef& inst) {
logger_.message(ifcopenshell::logger::LOG_NOTICE, "GEO", 296, "Skipping zero sized profile:", inst);
return nullptr;
}
double dy1 = 0.0f;
double dy2 = 0.0f;
double dx1 = 0.0f;
+4 -4
View File
@@ -29,21 +29,21 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTrimmedCurve& inst) {
auto basis_curve = inst.BasisCurve();
bool isConic = basis_curve.declaration().is(IfcSchema::IfcConic::Class());
double parameterFactor = isConic ? angle_unit_ : length_unit_;
auto tc = taxonomy::make<taxonomy::edge>();
tc->basis = map(inst.BasisCurve());
bool trim_cartesian = inst.MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
auto trims1 = inst.Trim1();
auto trims2 = inst.Trim2();
// reversed orientation handling happens in geometry kernel
unsigned sense_agreement = 0;
double flts[2];
taxonomy::point3::ptr pnts[2];
bool has_flts[2] = {false,false};
bool has_pnts[2] = {false,false};
tc->curve_sense = inst.SenseAgreement();
for (auto it = trims1.begin(); it != trims1.end(); it ++) {
+1 -1
View File
@@ -33,7 +33,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcUShapeProfileDef& inst) {
const double d1 = inst.WebThickness() * length_unit_;
const double d2 = inst.FlangeThickness() * length_unit_;
const double slope = inst.FlangeSlope().value_or(0.) * angle_unit_;
double dy1 = 0.0f;
double dy2 = 0.0f;
double f1 = 0.0f;
+1 -1
View File
@@ -31,7 +31,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcZShapeProfileDef& inst) {
bool doFillet = !!inst.FilletRadius();
bool doEdgeFillet = !!inst.EdgeRadius();
double f1 = 0.;
double f2 = 0.;
+8 -8
View File
@@ -69,7 +69,7 @@ std::vector<IfcSchema::IfcProduct> mapping::products_represented_by(const IfcSch
auto invs = prodrep.file()->get_inverse(prodrep.id(), &IfcSchema::IfcProduct::Class(), -1);
for (auto& inv : invs) {
products.push_back(inv.as<IfcSchema::IfcProduct>());
}
}
}
if (only_direct) {
@@ -169,7 +169,7 @@ bool mapping::reuse_ok_(const std::vector<IfcSchema::IfcProduct>& products) {
std::vector<express::base> mapping::find_openings(const express::base& inst) {
std::vector<express::base> openings;
if (auto rep = inst.as<IfcSchema::IfcRepresentation>()) {
// @todo this is essentially only for hybrid kernel trying to guess
// when not to use a simple kernel.
@@ -246,11 +246,11 @@ void mapping::get_representations(std::vector<geometry_conversion_task>& tasks,
int task_index = 0;
std::set<IfcSchema::IfcProduct> products_seen;
for (auto representation : representations) {
IfcSchema::IfcRepresentationMap rmap;
std::vector<IfcSchema::IfcProduct> ifcproducts = filter_products(products_represented_by(representation, rmap, false), filters);
if (ifcproducts.empty()) {
continue;
}
@@ -838,7 +838,7 @@ express::base mapping::get_decomposing_entity(const express::base& inst, bool in
for (auto it = parents.begin(); it != parents.end(); ++it) {
IfcSchema::IfcRelDecomposes decompose = (*it).as<IfcSchema::IfcRelDecomposes>();
express::base ifc_objectdef;
ifc_objectdef = get_RelatingObject(decompose);
if (!ifc_objectdef || product == ifc_objectdef) continue;
@@ -871,7 +871,7 @@ void mapping::initialize_units_() {
length_unit_ = 1.;
angle_unit_ = -1.;
length_unit_name_ = "METER";
#ifdef SCHEMA_HAS_IfcContext
auto projects = file_->instances_by_type<IfcSchema::IfcContext>();
#else
@@ -1133,7 +1133,7 @@ bool mapping::get_layerset_information(const express::base& p, layerset_informat
std::vector<IfcSchema::IfcExtrudedAreaSolid> extrusions;
for (auto& r : resources) {
if (auto ex = r.as<IfcSchema::IfcExtrudedAreaSolid>()) {
extrusions.push_back(ex);
extrusions.push_back(ex);
}
}
@@ -1209,7 +1209,7 @@ bool mapping::get_layerset_information(const express::base& p, layerset_informat
}
return true;
}
+3 -3
View File
@@ -16,7 +16,7 @@
namespace ifcopenshell {
namespace geom {
class POSTFIX_SCHEMA(mapping) : public abstract_mapping {
private:
ifcopenshell::file* file_;
@@ -30,7 +30,7 @@ namespace geom {
const express::base placement_rel_to_instance_;
Eigen::Matrix4d offset_and_rotation_ = Eigen::Matrix4d::Identity();
void initialize_units_();
void addRepresentationsFromContextIds(std::vector<IfcSchema::IfcRepresentation>&);
void addRepresentationsFromPriorities(std::vector<IfcSchema::IfcRepresentation>&);
@@ -136,7 +136,7 @@ namespace geom {
template <>
struct element_type<taxonomy::solid> {
typedef taxonomy::shell type;
};
};
template <typename U = taxonomy::collection, typename T>
typename U::ptr map_to_collection(POSTFIX_SCHEMA(mapping)* m, const T& ts) {
+1 -1
View File
@@ -182,4 +182,4 @@ BIND(IfcSurfaceStyle); // -> style
#ifdef SCHEMA_HAS_IfcCurveSegment
BIND(IfcCurveSegment);
#endif
#endif
+3 -3
View File
@@ -7,8 +7,8 @@ taxonomy::loop::ptr ifcopenshell::geom::fillet_loop(taxonomy::loop::ptr loop, do
const auto child_count = static_cast<int>(loop->children.size());
for (int b = 0; b < child_count; ++b) {
int c = (b + child_count - 1) % child_count;
pps[b] = {
std::get<taxonomy::point3::ptr>(loop->children[c]->start)->ccomponents(),
pps[b] = {
std::get<taxonomy::point3::ptr>(loop->children[c]->start)->ccomponents(),
radius, loop->children[c], loop->children[b]
};
}
@@ -227,7 +227,7 @@ std::pair<std::vector<taxonomy::point3::ptr>, std::vector<std::set<std::string>>
if (equal) {
// do not remove the first or last point to
// maintain connectivity with other wires
/*
// Only removing direct equality so does not impact connectivity
if ((closed && j == 0) || (!closed && j == (n - 1))) {
+1 -1
View File
@@ -121,7 +121,7 @@ ifcopenshell::geom::triangulation::triangulation(const native& shape_model)
, weld_offset_(0)
{
for (std::vector<ifcopenshell::geom::conversion_result>::const_iterator iit = shape_model.begin(); iit != shape_model.end(); ++iit) {
// Don't weld vertices that belong to different items to prevent non-manifold situations.
resetWelds();
+1 -1
View File
@@ -108,7 +108,7 @@ namespace ifcopenshell::geom {
std::vector<int> faces_;
std::vector<std::vector<int>> polyhedral_faces_without_holes_;
std::vector<std::vector<std::vector<int>>> polyhedral_faces_with_holes_;
std::vector<int> edges_;
std::vector<double> normals_;
std::vector<double> uvs_;
@@ -162,7 +162,7 @@ int convert_to_ifc(ifcopenshell::file& f, const opencascade::handle<Geom_Curve>&
el.setSemiAxis1(ellipse->MajorRadius());
el.setSemiAxis2(ellipse->MinorRadius());
curve = el;
return 1;
}
#ifdef SCHEMA_HAS_IfcRationalBSplineSurfaceWithKnots
@@ -461,11 +461,11 @@ int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Edge& e, IfcSchema::IfcEd
IfcSchema::IfcEdge edge2 = f.create<IfcSchema::IfcEdge>();
edge2.setEdgeStart(vertex1);
edge2.setEdgeEnd(vertex2);
auto ori = f.create<IfcSchema::IfcOrientedEdge>();
ori.setEdgeElement(edge2);
ori.setOrientation(true);
edge = ori;
return 1;
} else {
+1 -1
View File
@@ -620,7 +620,7 @@ typedef item const* ptr;
struct equal_functor {
bool operator()(taxonomy::item::ptr const& a,
taxonomy::item::ptr const& b) const
taxonomy::item::ptr const& b) const
{
if (a == b) {
return true;
+10 -10
View File
@@ -106,7 +106,7 @@ std::string format_json(const double& d) {
template <>
std::string format_json(const gp_Dir& d) {
std::stringstream ss;
ss << std::setprecision(std::numeric_limits<double>::digits10)
ss << std::setprecision(std::numeric_limits<double>::digits10)
<< "[" << d.X() << "," << d.Y() << "," << d.Z() << "]";
return ss.str();
}
@@ -311,7 +311,7 @@ protected:
m(3,0), m(3,1), m(3,2), m(3,3)
};
swrite(s, std::string((char*)matrix_array, 16 * sizeof(double)));
// The first bit of the string is always the instance name of the representation.
const std::string& representation_id = geom->geometry().id();
const int integer_representation_id = atoi(representation_id.c_str());
@@ -326,13 +326,13 @@ protected:
indices.reserve(faces.size());
for (std::vector<int>::const_iterator it = faces.begin(); it != faces.end(); ++it) {
indices.push_back(*it);
}
}
swrite_array<int32_t>(s, indices);
if (append_line_data) {
std::vector<int32_t> lines;
std::set<int32_t> faces_set (indices.begin(), indices.end());
const std::vector<int>& edges = geom->geometry().edges();
for ( std::vector<int>::const_iterator it = edges.begin(); it != edges.end(); ) {
const int32_t i1 = *(it++);
@@ -349,7 +349,7 @@ protected:
swrite_array<int32_t>(s, lines);
}
}
{
{
// We remove the blanks here from the material array. I.e. materials without a diffuse color
std::vector<boost::optional<std::array<float, 4> > > diffuse_color_array;
for (auto it = geom->geometry().materials().begin(); it != geom->geometry().materials().end(); ++it) {
@@ -369,7 +369,7 @@ protected:
std::map<int, int> orig_to_condensed_index_map;
std::vector<float> diffuse_color_array_condensed;
int new_index = 0;
for (size_t orig = 0; orig < diffuse_color_array.size(); ++orig) {
auto& material = diffuse_color_array[orig];
@@ -470,13 +470,13 @@ private:
const ifcopenshell::geom::native_element* elem_;
public:
QuantityWriter_v0(const ifcopenshell::geom::native_element* elem) :
elem_(elem)
elem_(elem)
{
put_json(TOTAL_SURFACE_AREA, 0.);
put_json(TOTAL_SHAPE_VOLUME, 0.);
if (elem_->type() == "IfcSpace") {
put_json(WALKABLE_SURFACE_AREA, 0.);
}
}
}
};
@@ -548,7 +548,7 @@ public:
};
int main () {
// Redirect stdout to this stream, so that involuntary
// Redirect stdout to this stream, so that involuntary
// writes to stdout do not interfere with our protocol.
std::ostringstream oss;
stdout_redir = oss.rdbuf();
@@ -672,7 +672,7 @@ int main () {
}
}
default:
exit_code = 1;
exit_code = 1;
break;
}
break;
+3 -3
View File
@@ -276,7 +276,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
const int v1 = o->geometry().faces()[3*i+0];
const int v2 = o->geometry().faces()[3*i+1];
const int v3 = o->geometry().faces()[3*i+2];
const edge_t e1((std::min)(v1, v2), (std::max)(v1, v2));
const edge_t e2((std::min)(v2, v3), (std::max)(v2, v3));
const edge_t e3((std::min)(v3, v1), (std::max)(v3, v1));
@@ -294,7 +294,7 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
}
tri->mesh.faces[i].setMatID(mtlid);
}
tri->mesh.buildNormals();
// Either use this or undefine the FACESETS_AS_COMPOUND option in IfcGeom.h to have
// properly oriented normals. Using only the line below will result in a consistent
@@ -322,6 +322,6 @@ int IFCImp::DoImport(const TCHAR *name, ImpInterface *impitfc, Interface *itfc,
} while (iterator.next());
itfc->ProgressEnd();
return true;
}
+1 -1
View File
@@ -24,7 +24,7 @@
extern ClassDesc* GetIFCImpDesc();
class IFCImp : public SceneImport
class IFCImp : public SceneImport
{
public:
int ExtCount(); // = 1
@@ -66,6 +66,12 @@ Alternatively, you can use Python:
report.report()
report.to_file("report.json")
# Or to a SQLite database. Unlike JSON, entities are stored once and
# referenced by ID, so this stays small on large models and can be queried
# instead of parsed. Recommended for anything but small audits. Results are
# written directly to the file, so there is no report() step.
reporter.Sqlite(specs).to_file("report.db")
# Or to ODS spreadsheet
report = reporter.Ods(specs)
report.report()
@@ -47,6 +47,7 @@ def _create_layout(file: ifcopenshell.file, alignment: entity_instance, points:
start_dist_along = 0.0
gradient = None
dir = None
for p1, p2 in zip(points, points[1:]):
x1, y1, z1 = p1.Coordinates
x2, y2, z2 = p2.Coordinates
@@ -86,6 +87,7 @@ def _create_layout(file: ifcopenshell.file, alignment: entity_instance, points:
start_dist_along += length
# zero length segment
assert dir is not None
hsegment = file.createIfcAlignmentSegment(
ifcopenshell.guid.new(),
DesignParameters=file.createIfcAlignmentHorizontalSegment(
@@ -258,5 +258,5 @@ if __name__ == "__main__":
for output in sys.argv[2:]:
mdl = importlib.import_module(output)
mdl.Generator(m).emit()
sys.stdout.write(m.schema.name)
print(m.schema.name)
""" % ("\n ".join(statements)))
@@ -1,16 +0,0 @@
import sys, fileinput
if sys.platform == "win32" and not hasattr(sys.stdout, "buffer"):
import os, msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
files = sys.argv[1:]
if files[0] == "-o":
b = open(files[1], "wb")
files = files[2:]
else:
b = getattr(sys.stdout, "buffer", sys.stdout)
for line in fileinput.input(files=files, mode="rb"):
b.write(line)
@@ -486,5 +486,4 @@ if __name__ == "__main__":
for output in sys.argv[2:]:
mdl = importlib.import_module(output)
mdl.Generator(m).emit()
sys.stdout.write(m.schema.name)
@@ -19,9 +19,14 @@
from __future__ import annotations
import sys
import nodes
import templates
import schema
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from . import nodes, schema, templates
else:
import nodes
import schema
import templates
class Mapping:
@@ -36,6 +41,15 @@ class Mapping:
"binary": "boost::dynamic_bitset<>",
}
cpp_to_argument_types = {
"boolean": "BOOL",
"logical": "LOGICAL",
"integer": "INT",
"real": "DOUBLE",
"number": "DOUBLE",
"string": "STRING",
}
supported_argument_types = set(
[
"INT",
@@ -117,8 +131,8 @@ class Mapping:
else:
return "Type::%s" % type
def make_argument_type(self, attr):
def _make_argument_type(type):
def make_argument_type(self, attr: nodes.Node | str) -> str:
def _make_argument_type(type: nodes.Node | str) -> str:
if isinstance(type, nodes.SimpleType):
type = type.type
if self.schema.is_entity(type) or isinstance(type, nodes.SelectType):
@@ -134,8 +148,8 @@ class Mapping:
if ty == "UNKNOWN":
return "UNKNOWN"
return "AGGREGATE_OF_" + ty
elif str(type) in self.express_to_cpp_typemapping:
return self.express_to_cpp_typemapping.get(str(type), type).split("::")[-1].upper()
elif (ty := self.cpp_to_argument_types.get(str(type))) is not None:
return ty
elif self.schema.is_type(type):
return _make_argument_type(self.schema.types[type].type)
else:
@@ -253,10 +267,10 @@ class Mapping:
derived = set(self.derived_in_supertype(t))
attrs = enumerate(self.arguments(t))
def include(attr):
def include(attr: nodes.Node) -> bool:
not_derived = include_derived or (attr.name not in derived)
supported = self.make_argument_type(attr) != "ifcopenshell::Argument_UNKNOWN"
return not_derived and supported
return bool(not_derived and supported)
return [
{
@@ -1,199 +0,0 @@
@ECHO OFF
:: python bootstrap.py express.bnf > express_parser.py
IF EXIST IFC2X3_TC1.exp (
python express_parser.py IFC2X3_TC1.exp header implementation schema_class definitions
IF EXIST Ifc2x3-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3.cpp txt/header_ifc2x3.txt Ifc2x3.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3.h txt/header_ifc2x3.txt Ifc2x3.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3-schema.cpp txt/header_ifc2x3.txt Ifc2x3-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3-definitions.h txt/header_ifc2x3.txt Ifc2x3-definitions.h
) ELSE (
:: v0.5.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3.cpp txt/header_ifc2x3.txt txt/ifndef_ifc4.txt Ifc2x3.cpp txt/endif.txt
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3.h txt/header_ifc2x3.txt Ifc2x3.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3enum.h txt/header_ifc2x3.txt Ifc2x3enum.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3-latebound.cpp txt/header_ifc2x3.txt txt/ifndef_ifc4.txt Ifc2x3-latebound.cpp txt/endif.txt
python cat.py -o ..\..\..\ifcparse\schemas\Ifc2x3-latebound.h txt/header_ifc2x3.txt Ifc2x3-latebound.h
)
del *.cpp *.h
)
IF EXIST IFC4_ADD2TC1.exp (
python express_parser.py IFC4_ADD2TC1.exp header implementation schema_class definitions
IF EXIST Ifc4-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4.cpp txt/header_ifc4.txt Ifc4.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4.h txt/header_ifc4.txt Ifc4.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4-schema.cpp txt/header_ifc4.txt Ifc4-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4-definitions.h txt/header_ifc4.txt Ifc4-definitions.h
) ELSE (
:: v0.5.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4.cpp txt/header_ifc4.txt txt/ifdef_ifc4.txt Ifc4.cpp txt/endif.txt
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4.h txt/header_ifc4.txt Ifc4.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4enum.h txt/header_ifc4.txt Ifc4enum.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4-latebound.cpp txt/header_ifc4.txt txt/ifdef_ifc4.txt Ifc4-latebound.cpp txt/endif.txt
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4-latebound.h txt/header_ifc4.txt Ifc4-latebound.h
)
del *.cpp *.h
)
IF EXIST IFC4x1.exp (
python express_parser.py IFC4x1.exp header implementation schema_class definitions
IF EXIST Ifc4x1-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x1.cpp txt/header_ifc4x1.txt Ifc4x1.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x1.h txt/header_ifc4x1.txt Ifc4x1.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x1-schema.cpp txt/header_ifc4x1.txt Ifc4x1-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x1-definitions.h txt/header_ifc4x1.txt Ifc4x1-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4x2.exp (
python express_parser.py IFC4x2.exp header implementation schema_class definitions
IF EXIST Ifc4x2-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x2.cpp txt/header_ifc4x2.txt Ifc4x2.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x2.h txt/header_ifc4x2.txt Ifc4x2.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x2-schema.cpp txt/header_ifc4x2.txt Ifc4x2-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x2-definitions.h txt/header_ifc4x2.txt Ifc4x2-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4x3_RC1.exp (
python express_parser.py IFC4x3_RC1.exp header implementation schema_class definitions
IF EXIST Ifc4x3_rc1-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc1.cpp txt/header_ifc4x3_rc1.txt Ifc4x3_rc1.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc1.h txt/header_ifc4x3_rc1.txt Ifc4x3_rc1.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc1-schema.cpp txt/header_ifc4x3_rc1.txt Ifc4x3_rc1-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc1-definitions.h txt/header_ifc4x3_rc1.txt Ifc4x3_rc1-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4x3_RC2.exp (
python express_parser.py IFC4x3_RC2.exp header implementation schema_class definitions
IF EXIST Ifc4x3_rc2-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc2.cpp txt/header_ifc4x3_rc2.txt Ifc4x3_rc2.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc2.h txt/header_ifc4x3_rc2.txt Ifc4x3_rc2.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc2-schema.cpp txt/header_ifc4x3_rc2.txt Ifc4x3_rc2-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc2-definitions.h txt/header_ifc4x3_rc2.txt Ifc4x3_rc2-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4x3_RC3.exp (
python express_parser.py IFC4x3_RC3.exp header implementation schema_class definitions
IF EXIST Ifc4x3_rc3-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc3.cpp txt/header_ifc4x3_rc2.txt Ifc4x3_rc3.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc3.h txt/header_ifc4x3_rc2.txt Ifc4x3_rc3.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc3-schema.cpp txt/header_ifc4x3_rc2.txt Ifc4x3_rc3-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc3-definitions.h txt/header_ifc4x3_rc2.txt Ifc4x3_rc3-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4x3_RC4.exp (
python express_parser.py IFC4x3_RC4.exp header implementation schema_class definitions
IF EXIST Ifc4x3_rc4-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc4.cpp txt/header_ifc4x3_rc2.txt Ifc4x3_rc4.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc4.h txt/header_ifc4x3_rc2.txt Ifc4x3_rc4.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc4-schema.cpp txt/header_ifc4x3_rc2.txt Ifc4x3_rc4-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_rc4-definitions.h txt/header_ifc4x3_rc2.txt Ifc4x3_rc4-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4X3.exp (
python express_parser.py IFC4X3.exp header implementation schema_class definitions
IF EXIST Ifc4x3-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3.cpp txt/header_ifc4x3_rc2.txt Ifc4x3.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3.h txt/header_ifc4x3_rc2.txt Ifc4x3.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3-schema.cpp txt/header_ifc4x3_rc2.txt Ifc4x3-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3-definitions.h txt/header_ifc4x3_rc2.txt Ifc4x3-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4X3_TC1.exp (
python express_parser.py IFC4X3_TC1.exp header implementation schema_class definitions
IF EXIST Ifc4x3_tc1-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_tc1.cpp txt/header_ifc4x3_tc1.txt Ifc4x3_tc1.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_tc1.h txt/header_ifc4x3_tc1.txt Ifc4x3_tc1.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_tc1-schema.cpp txt/header_ifc4x3_tc1.txt Ifc4x3_tc1-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_tc1-definitions.h txt/header_ifc4x3_tc1.txt Ifc4x3_tc1-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4X3_ADD1.exp (
python express_parser.py IFC4X3_ADD1.exp header implementation schema_class definitions
IF EXIST Ifc4x3_add1-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add1.cpp txt/header_ifc4x3_add1.txt Ifc4x3_add1.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add1.h txt/header_ifc4x3_add1.txt Ifc4x3_add1.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add1-schema.cpp txt/header_ifc4x3_add1.txt Ifc4x3_add1-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add1-definitions.h txt/header_ifc4x3_add1.txt Ifc4x3_add1-definitions.h
)
del *.cpp *.h
)
IF EXIST IFC4X3_ADD2.exp (
python express_parser.py IFC4X3_ADD2.exp header implementation schema_class definitions
IF EXIST Ifc4x3_add2-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add2.cpp txt/header_ifc4x3_add2.txt Ifc4x3_add2.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add2.h txt/header_ifc4x3_add2.txt Ifc4x3_add2.h
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add2-schema.cpp txt/header_ifc4x3_add2.txt Ifc4x3_add2-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Ifc4x3_add2-definitions.h txt/header_ifc4x3_add2.txt Ifc4x3_add2-definitions.h
)
del *.cpp *.h
)
IF EXIST header_schema.exp (
python express_parser.py header_schema.exp header implementation schema_class definitions
IF EXIST Header_section_schema-schema.cpp (
:: v0.6.0
python cat.py -o ..\..\..\ifcparse\schemas\Header_section_schema.cpp Header_section_schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Header_section_schema.h Header_section_schema.h
python cat.py -o ..\..\..\ifcparse\schemas\Header_section_schema-schema.cpp Header_section_schema-schema.cpp
python cat.py -o ..\..\..\ifcparse\schemas\Header_section_schema-definitions.h Header_section_schema-definitions.h
)
del *.cpp *.h
)
@@ -1,25 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file has been generated from IFC2X3_TC1.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/
@@ -1,25 +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/>. *
* *
********************************************************************************/
/********************************************************************************
* *
* This file has been generated from IFC4.exp. Do not make modifications *
* but instead modify the python script that has been used to generate this. *
* *
********************************************************************************/

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