mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-24 13:56:50 +00:00
Compare commits
249 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f2f1954f3 | |||
| b4323ba67a | |||
| b79070456f | |||
| 5cd4dbf603 | |||
| 2c18aebdcc | |||
| cb0a70ac7e | |||
| cf3f3c2c00 | |||
| 7029feca0a | |||
| f75526e6c3 | |||
| 6d4fe17975 | |||
| c1b4b5c1d0 | |||
| 994fa4bc03 | |||
| 3e066443be | |||
| d475553cd0 | |||
| 65e40b9923 | |||
| 29fdf629f9 | |||
| d9eb67b7a8 | |||
| bae1eddda9 | |||
| ad62dd6d91 | |||
| d565dc3ff3 | |||
| a340e6cf9a | |||
| 359693c562 | |||
| 016c278748 | |||
| f2b655fcf6 | |||
| 0bb6df6a6b | |||
| f07afda09c | |||
| 5b2721c1c4 | |||
| 0d5fa0c20c | |||
| 802ddf8ff9 | |||
| e20cea221b | |||
| ae66550cae | |||
| 5ccb655e10 | |||
| 278c1e5068 | |||
| 095e4a1677 | |||
| de5eb9641f | |||
| 4597be7fda | |||
| ca2e866c45 | |||
| e84767c22b | |||
| f7add7f412 | |||
| 8ffdb8f0b9 | |||
| e0e143bab5 | |||
| 8f3eaa35d7 | |||
| 81b1efdfd6 | |||
| 4a9af13626 | |||
| e9d577890e | |||
| 7f29850022 | |||
| 92c3b4c308 | |||
| 600d3a3460 | |||
| bea4e38e65 | |||
| 5386c9ec69 | |||
| ecf0a5a4e1 | |||
| 540f3acf52 | |||
| b3d29c4081 | |||
| 0d3849737c | |||
| a2db0a68a4 | |||
| 3e2869b6aa | |||
| db1a2705a3 | |||
| e7787b6aad | |||
| 6f0327d4b5 | |||
| 6341d7dd31 | |||
| 51971dd493 | |||
| 309e20009c | |||
| a06e5ecdf5 | |||
| 1ca2e12f92 | |||
| b9e5739088 | |||
| 30cdffc27a | |||
| 3607fbb762 | |||
| b73cdd1a0e | |||
| e21bd1ac96 | |||
| 633c613da2 | |||
| 8282f691e8 | |||
| 7bc64bef1a | |||
| 81a7c5b50e | |||
| 8f7c8dc1d2 | |||
| eea2398e07 | |||
| 35be7f4190 | |||
| 4f929e90a7 | |||
| f898089b27 | |||
| 4e4553201b | |||
| 29f5132510 | |||
| ae938d425b | |||
| 5161b0a3f8 | |||
| 3015f758ba | |||
| dbe68b48f2 | |||
| 094d96c735 | |||
| ed6e8d831e | |||
| 930678e3d2 | |||
| 4e3cc63de1 | |||
| 7b64dd338b | |||
| 71612e0780 | |||
| 9aae8f0329 | |||
| 175efcfffe | |||
| 643a2e1c1f | |||
| 3c5c8e44cb | |||
| fc89ffeb19 | |||
| 4bedb40d8a | |||
| a34c36d22e | |||
| e5ed7b53d4 | |||
| 069ef20c46 | |||
| 0b122ae1f5 | |||
| a0cc4b874b | |||
| 2f88778c9f | |||
| 0a752e09eb | |||
| 03662d2016 | |||
| 99f409280a | |||
| 0c9d3ea6d7 | |||
| 37fa4e9076 | |||
| 1ec273f508 | |||
| 574bcfa6c5 | |||
| 09ffdd2028 | |||
| d0c5bd5e85 | |||
| c03a7fe117 | |||
| 8596d53a4a | |||
| c78e16eafb | |||
| 68fea7bd45 | |||
| 90366f8236 | |||
| d3c21d7a81 | |||
| cd77c557e9 | |||
| 3110c98429 | |||
| 0e2a62d3b7 | |||
| f532624dc1 | |||
| f0e3056d0a | |||
| 298eca0ab6 | |||
| 1f17d73f3e | |||
| ababb49ae7 | |||
| 07a5c59359 | |||
| 8c8ef5c32b | |||
| 36fa53122a | |||
| 1dace18d26 | |||
| 5b4c1089cf | |||
| 83a3131276 | |||
| 6f6bebf387 | |||
| bfac12dbe7 | |||
| d33055bb72 | |||
| d08a4e0706 | |||
| 06eca938d7 | |||
| 543d9f8588 | |||
| b40e4378b3 | |||
| 1089de14f0 | |||
| 1b35533917 | |||
| c42a7f32d0 | |||
| 14e9846e35 | |||
| 37c6aea092 | |||
| 9b13dc8dd6 | |||
| 89c66f62bf | |||
| 18363c0d19 | |||
| 782aa4f88f | |||
| 13c71d7a8a | |||
| cb7e7331e6 | |||
| 4850e2a07c | |||
| fd980abcc2 | |||
| b022ca7e70 | |||
| 325db2e57f | |||
| 046ceb452a | |||
| 9e19735275 | |||
| 6ee05b646b | |||
| e62921171c | |||
| 6c47123781 | |||
| d448fa95e3 | |||
| 57de09d236 | |||
| a25f522cc3 | |||
| e067c2b834 | |||
| e2905d6f0e | |||
| ead061a98a | |||
| fae85e63cc | |||
| bccea6d932 | |||
| 1cc93784cd | |||
| f1e93581ec | |||
| 91ae631c7d | |||
| b599ee1040 | |||
| d2cc66fdf0 | |||
| 3824e7b449 | |||
| aa10784154 | |||
| 2018bcb3c1 | |||
| 11006f0ef5 | |||
| a44f72287b | |||
| c6849073d9 | |||
| b2fc0c00cc | |||
| 2d5883f966 | |||
| 4621fc9269 | |||
| 1840e3d1a8 | |||
| becd38c77d | |||
| 7d6c6bd523 | |||
| a425bb6da0 | |||
| a19d398c78 | |||
| f616c4049c | |||
| 20ccf2b455 | |||
| a07f56db6f | |||
| 724cdb446e | |||
| 95b3f7dac4 | |||
| 603cedc487 | |||
| fe6e9d86ae | |||
| 8e42f35db3 | |||
| 9d69a712ac | |||
| dc127471c5 | |||
| 95a094d596 | |||
| 4ec643d4e1 | |||
| c089c11cd6 | |||
| 8afba9a665 | |||
| 5c4046e054 | |||
| d82e1da907 | |||
| 8c2e1226c9 | |||
| ed8821486d | |||
| 742bfac144 | |||
| 1f4c4204d0 | |||
| 43f78605f2 | |||
| 6cd1375cf9 | |||
| 2d1250c18f | |||
| bee61cba11 | |||
| 33f072e0a7 | |||
| 490fa92dc0 | |||
| cf3393b6a0 | |||
| fbbc92c5d7 | |||
| 574827016a | |||
| 18c9140700 | |||
| 9e165319e6 | |||
| 64bf807baa | |||
| 136befde86 | |||
| 1a4d750ecd | |||
| 0a5dd78774 | |||
| 94427ebcb3 | |||
| 9147938c36 | |||
| ffcc02fb99 | |||
| e4e4f31d20 | |||
| 2dd002bcd8 | |||
| 7e5248da29 | |||
| 07a01bcf54 | |||
| 0a9e29ce45 | |||
| 0604db06e9 | |||
| 991556fbe3 | |||
| b66b04b001 | |||
| 5c9213426f | |||
| 69a4ad35a1 | |||
| 7f4d9e31c3 | |||
| ae79996eb6 | |||
| f5b2358c2e | |||
| f9c791de1b | |||
| 5b85a2c38b | |||
| bc46a8f85b | |||
| c57209fbce | |||
| 088a6b7204 | |||
| f2f4d626a5 | |||
| 572a5655cf | |||
| ccd91c0ff0 | |||
| a1d2c902f3 | |||
| 3ae361bb3b | |||
| 2d7521ed88 | |||
| 7098beb819 | |||
| f09ca658f1 |
@@ -110,7 +110,20 @@ jobs:
|
||||
run: |
|
||||
VERSION=v`cat VERSION`
|
||||
cd ./build/`uname`/*/10.15/install/ifcopenshell
|
||||
mkdir ~/output
|
||||
mkdir -p ~/output
|
||||
install_root="$PWD"
|
||||
|
||||
stage_runtime_payload() {
|
||||
dest="$1"
|
||||
while IFS= read -r runtime_file; do
|
||||
cp -L "$runtime_file" "$dest/"
|
||||
done < <(
|
||||
for runtime_dir in "$install_root/bin" "$install_root/lib" "$install_root/lib64"; do
|
||||
[ -d "$runtime_dir" ] || continue
|
||||
find "$runtime_dir" -type f \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
ls -d python-* | while read py_version; do
|
||||
postfix=`echo ${py_version: -1} | sed s/[0-9]//`
|
||||
@@ -125,18 +138,25 @@ jobs:
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip ifcopenshell/*
|
||||
stage_runtime_payload ifcopenshell
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip ifcopenshell
|
||||
mv *.zip ~/output
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
cd bin
|
||||
rm *.zip || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip $exe
|
||||
rm -f "$install_root"/bin/*.zip
|
||||
find "$install_root/bin" -maxdepth 1 -type f -perm /111 ! -name "*.zip" ! -name "*.so" ! -name "*.so.*" ! -name "*.dylib" ! -name "*.dll" | while read exe_path; do
|
||||
exe=`basename "$exe_path"`
|
||||
package_dir="$install_root/.package-${exe}"
|
||||
rm -rf "$package_dir"
|
||||
mkdir -p "$package_dir"
|
||||
cp "$exe_path" "$package_dir/"
|
||||
stage_runtime_payload "$package_dir"
|
||||
pushd "$package_dir" > /dev/null
|
||||
zip -qq -r "$HOME/output/${exe}-${VERSION}-${GITHUB_SHA:0:7}-macos${{ matrix.oldarch }}64.zip" .
|
||||
popd > /dev/null
|
||||
rm -rf "$package_dir"
|
||||
done
|
||||
mv *.zip ~/output
|
||||
cd ..
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
||||
@@ -86,7 +86,20 @@ jobs:
|
||||
run: |
|
||||
VERSION=v`cat VERSION`
|
||||
cd ./build/`uname`/*/install/ifcopenshell
|
||||
mkdir ~/output
|
||||
mkdir -p ~/output
|
||||
install_root="$PWD"
|
||||
|
||||
stage_runtime_payload() {
|
||||
dest="$1"
|
||||
while IFS= read -r runtime_file; do
|
||||
cp -L "$runtime_file" "$dest/"
|
||||
done < <(
|
||||
for runtime_dir in "$install_root/bin" "$install_root/lib" "$install_root/lib64"; do
|
||||
[ -d "$runtime_dir" ] || continue
|
||||
find "$runtime_dir" -type f \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
ls -d python-* | while read py_version; do
|
||||
postfix=`echo ${py_version: -1} | sed s/[0-9]//`
|
||||
@@ -101,18 +114,24 @@ jobs:
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip ifcopenshell/*
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip ifcopenshell
|
||||
mv *.zip ~/output
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
cd bin
|
||||
rm *.zip || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip $exe
|
||||
rm -f "$install_root"/bin/*.zip
|
||||
find "$install_root/bin" -maxdepth 1 -type f -perm /111 ! -name "*.zip" ! -name "*.so" ! -name "*.so.*" ! -name "*.dylib" ! -name "*.dll" | while read exe_path; do
|
||||
exe=`basename "$exe_path"`
|
||||
package_dir="$install_root/.package-${exe}"
|
||||
rm -rf "$package_dir"
|
||||
mkdir -p "$package_dir"
|
||||
cp "$exe_path" "$package_dir/"
|
||||
stage_runtime_payload "$package_dir"
|
||||
pushd "$package_dir" > /dev/null
|
||||
zip -qq -r "$HOME/output/${exe}-${VERSION}-${GITHUB_SHA:0:7}-linux64.zip" .
|
||||
popd > /dev/null
|
||||
rm -rf "$package_dir"
|
||||
done
|
||||
mv *.zip ~/output
|
||||
cd ..
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
||||
@@ -86,7 +86,20 @@ jobs:
|
||||
run: |
|
||||
VERSION=v`cat VERSION`
|
||||
cd ./build/`uname`/*/install/ifcopenshell
|
||||
mkdir ~/output
|
||||
mkdir -p ~/output
|
||||
install_root="$PWD"
|
||||
|
||||
stage_runtime_payload() {
|
||||
dest="$1"
|
||||
while IFS= read -r runtime_file; do
|
||||
cp -L "$runtime_file" "$dest/"
|
||||
done < <(
|
||||
for runtime_dir in "$install_root/bin" "$install_root/lib" "$install_root/lib64"; do
|
||||
[ -d "$runtime_dir" ] || continue
|
||||
find "$runtime_dir" -type f \( -name "*.so" -o -name "*.so.*" -o -name "*.dylib" -o -name "*.dll" \)
|
||||
done
|
||||
)
|
||||
}
|
||||
|
||||
ls -d python-* | while read py_version; do
|
||||
postfix=`echo ${py_version: -1} | sed s/[0-9]//`
|
||||
@@ -101,18 +114,25 @@ jobs:
|
||||
fi
|
||||
[ -d ifcopenshell/__pycache__ ] && rm -rf ifcopenshell/__pycache__
|
||||
find ifcopenshell -name "*.pyc" -delete
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip ifcopenshell/*
|
||||
stage_runtime_payload ifcopenshell
|
||||
zip -r -qq ifcopenshell-${py_version_major}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip ifcopenshell
|
||||
mv *.zip ~/output
|
||||
popd > /dev/null
|
||||
done
|
||||
|
||||
cd bin
|
||||
rm *.zip || true
|
||||
ls | while read exe; do
|
||||
zip -qq -r ${exe}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip $exe
|
||||
rm -f "$install_root"/bin/*.zip
|
||||
find "$install_root/bin" -maxdepth 1 -type f -perm /111 ! -name "*.zip" ! -name "*.so" ! -name "*.so.*" ! -name "*.dylib" ! -name "*.dll" | while read exe_path; do
|
||||
exe=`basename "$exe_path"`
|
||||
package_dir="$install_root/.package-${exe}"
|
||||
rm -rf "$package_dir"
|
||||
mkdir -p "$package_dir"
|
||||
cp "$exe_path" "$package_dir/"
|
||||
stage_runtime_payload "$package_dir"
|
||||
pushd "$package_dir" > /dev/null
|
||||
zip -qq -r "$HOME/output/${exe}-${VERSION}-${GITHUB_SHA:0:7}-linuxarm64.zip" .
|
||||
popd > /dev/null
|
||||
rm -rf "$package_dir"
|
||||
done
|
||||
mv *.zip ~/output
|
||||
cd ..
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v6
|
||||
|
||||
@@ -68,6 +68,64 @@ jobs:
|
||||
cd win
|
||||
python build-all-win.py
|
||||
|
||||
- name: Repack .zip Archives With Runtime Plugins
|
||||
shell: powershell
|
||||
run: |
|
||||
$version = (Get-Content VERSION | Select-Object -First 1).Trim()
|
||||
$sha = $env:GITHUB_SHA.Substring(0, 7)
|
||||
$outputDir = Join-Path $env:USERPROFILE "output"
|
||||
$installDir = Get-ChildItem -Path . -Directory | Where-Object { $_.Name -like "_installed*" } | Select-Object -First 1
|
||||
if (-not $installDir) {
|
||||
throw "Install directory not found."
|
||||
}
|
||||
|
||||
$runtimeFiles = @()
|
||||
foreach ($runtimeDir in @((Join-Path $installDir.FullName "bin"), (Join-Path $installDir.FullName "lib"))) {
|
||||
if (Test-Path $runtimeDir) {
|
||||
$runtimeFiles += Get-ChildItem -Path $runtimeDir -Recurse -File | Where-Object { $_.Extension -ieq ".dll" }
|
||||
}
|
||||
}
|
||||
$runtimeFiles = $runtimeFiles | Sort-Object FullName -Unique
|
||||
|
||||
Get-ChildItem -Path $outputDir -Filter *.zip -ErrorAction SilentlyContinue | Remove-Item -Force
|
||||
|
||||
$binDir = Join-Path $installDir.FullName "bin"
|
||||
foreach ($exe in Get-ChildItem -Path $binDir -File -Filter *.exe) {
|
||||
$stageDir = Join-Path $env:RUNNER_TEMP ("package-" + $exe.BaseName)
|
||||
Remove-Item -Path $stageDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Path $stageDir | Out-Null
|
||||
Copy-Item -Path $exe.FullName -Destination $stageDir
|
||||
foreach ($runtimeFile in $runtimeFiles) {
|
||||
Copy-Item -Path $runtimeFile.FullName -Destination $stageDir -Force
|
||||
}
|
||||
$zipPath = Join-Path $outputDir ("{0}-v{1}-{2}-win64.zip" -f $exe.BaseName, $version, $sha)
|
||||
Compress-Archive -Path (Join-Path $stageDir '*') -DestinationPath $zipPath -Force
|
||||
}
|
||||
|
||||
$depsRoot = Join-Path (Get-Location) "_deps"
|
||||
if (Test-Path $depsRoot) {
|
||||
foreach ($pythonRoot in Get-ChildItem -Path $depsRoot -Directory | Where-Object { $_.Name -like "python.*" }) {
|
||||
$pythonVersion = $pythonRoot.Name.Substring("python.".Length)
|
||||
$pythonVersionMajorMinor = ($pythonVersion.Split(".")[0..1] -join "")
|
||||
$sitePackages = Join-Path $pythonRoot.FullName "tools\\Lib\\site-packages"
|
||||
$packagePath = Join-Path $sitePackages "ifcopenshell"
|
||||
if (!(Test-Path $packagePath)) {
|
||||
continue
|
||||
}
|
||||
Get-ChildItem -Path $packagePath -Recurse -Filter *.pyc -ErrorAction SilentlyContinue | Remove-Item -Force
|
||||
foreach ($runtimeFile in $runtimeFiles) {
|
||||
Copy-Item -Path $runtimeFile.FullName -Destination $packagePath -Force
|
||||
}
|
||||
$zipPath = Join-Path $outputDir ("ifcopenshell-python-{0}-v{1}-{2}-win64.zip" -f $pythonVersionMajorMinor, $version, $sha)
|
||||
Push-Location $sitePackages
|
||||
try {
|
||||
Compress-Archive -Path "ifcopenshell" -DestinationPath $zipPath -Force
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- name: Pack Dependencies
|
||||
run: |
|
||||
cd ${{ matrix.deps_dir }}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
mkdir -p build && cd build
|
||||
|
||||
cmake ../cmake \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DPython_EXECUTABLE=/home/dion/Projects/env/bin/python3.11 \
|
||||
-DPython_INCLUDE_DIR=/usr/include/python3.11 \
|
||||
-DBUILD_IFCPYTHON=ON \
|
||||
-DBUILD_IFCGEOM=ON \
|
||||
-DBUILD_CONVERT=ON \
|
||||
-DBUILD_GEOMSERVER=OFF \
|
||||
-DBUILD_EXAMPLES=OFF \
|
||||
-DWITH_OPENCASCADE=ON \
|
||||
-DWITH_CGAL=ON \
|
||||
-DWITH_MANIFOLD=ON \
|
||||
-DHDF5_SUPPORT=OFF \
|
||||
-DGLTF_SUPPORT=ON \
|
||||
-DIFCXML_SUPPORT=OFF \
|
||||
-DCOLLADA_SUPPORT=OFF \
|
||||
-DSCHEMA_VERSIONS="2x3;4;4x3_add2" \
|
||||
-DOCC_INCLUDE_DIR=/usr/include/opencascade \
|
||||
-DOCC_LIBRARY_DIR=/usr/lib64/opencascade
|
||||
|
||||
ninja
|
||||
|
||||
cp ifcwrap/_ifcopenshell_wrapper*.so ifcwrap/ifcopenshell_wrapper.py \
|
||||
../src/ifcopenshell-python/ifcopenshell/
|
||||
+204
-204
@@ -18,28 +18,19 @@
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
if(NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
if (NOT DEFINED CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
if(CMAKE_CXX_STANDARD LESS 17)
|
||||
if (CMAKE_CXX_STANDARD LESS 17)
|
||||
message(FATAL_ERROR "C++17 or newer is required.")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON) # not necessary, but encouraged
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
if(VERSION_OVERRIDE)
|
||||
file(READ "../VERSION" "RELEASE_VERSION_")
|
||||
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
||||
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
||||
else()
|
||||
set(RELEASE_VERSION "0.8.0")
|
||||
endif()
|
||||
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
|
||||
if(POLICY CMP0141) # 3.25+
|
||||
# Has to be set before `project` to take effect.
|
||||
cmake_policy(SET CMP0141 NEW) # Support for `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`.
|
||||
cmake_policy(SET CMP0141 NEW) # Support for `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`.
|
||||
endif()
|
||||
if(POLICY CMP0144) # 3.27
|
||||
cmake_policy(SET CMP0144 NEW) # find_package() uses upper-case <PACKAGENAME>_ROOT variables.
|
||||
@@ -48,8 +39,6 @@ if(POLICY CMP0167) # 3.30
|
||||
cmake_policy(SET CMP0167 OLD)
|
||||
endif()
|
||||
|
||||
project(IfcOpenShell VERSION ${RELEASE_VERSION})
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
@@ -65,64 +54,59 @@ endif()
|
||||
option(MINIMAL_BUILD "The build is to make a minimal version of IFC converter from OCCT into IFC." OFF)
|
||||
option(WASM_BUILD "Build a WebAssembly binary." OFF)
|
||||
|
||||
option(
|
||||
ENABLE_BUILD_OPTIMIZATIONS
|
||||
"Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds."
|
||||
OFF
|
||||
)
|
||||
option(BUILD_SHARED_LIBS "Build IfcParse and IfcGeom as shared libs (SO/DLL)." OFF)
|
||||
option(ENABLE_BUILD_OPTIMIZATIONS "Enable certain compiler and linker optimizations on RelWithDebInfo and Release builds." OFF)
|
||||
option(BUILD_SHARED_LIBS "Build IfcOpenShell as shared libraries (required)." ON)
|
||||
option(MSVC_PARALLEL_BUILD "Multi-threaded compilation in Microsoft Visual Studio (/MP)" OFF)
|
||||
option(USE_VLD "Use Visual Leak Detector for debugging memory leaks, MSVC-only." OFF)
|
||||
option(USE_MMAP "Adds a command line options to parse IFC files from memory mapped files using Boost.Iostreams" OFF)
|
||||
option(NO_WARN "Disable all warnings" OFF)
|
||||
option(CREATE_BUNDLE "Copy .so files and don't create RPATHS or SOVERSION symlinks" )
|
||||
|
||||
option(BUILD_IFCGEOM "Build IfcGeom." ON)
|
||||
option(BUILD_IFCPYTHON "Build IfcPython." ON)
|
||||
option(BUILD_IFCPARSE_EXPERIMENTAL_WRAPPER "Build the experimental Clang-generated ifcparse Python wrapper." OFF)
|
||||
option(BUILD_CONVERT "Build IfcConvert executable." ON)
|
||||
option(BUILD_DOCUMENTATION "Build IfcOpenShell Documentation." OFF)
|
||||
option(BUILD_EXAMPLES "Build example applications." OFF)
|
||||
option(BUILD_EXAMPLES "Build example applications." ON)
|
||||
option(BUILD_GEOMSERVER "Build IfcGeomServer executable (Open CASCADE is required)." ON)
|
||||
option(BUILD_IFCMAX "Build IfcMax, a 3ds Max plug-in, Windows-only." OFF)
|
||||
option(BUILD_QTVIEWER "Build IfcOpenShell Qt GUI Viewer" OFF) # QtViewer requires Qt6
|
||||
option(BUILD_IFCVIEWER "Build IfcViewer, a high-performance IFC viewer" OFF) # Requires Qt6 + OpenGL 4.5
|
||||
option(BUILD_IFCVIEWER_TESTS "Build unit tests for IfcViewer (fetches Catch2 v3)" OFF)
|
||||
option(BUILD_PACKAGE "" OFF)
|
||||
# Most users probably need just common schemas,
|
||||
# but we're keeping it `OFF` by default to avoid disruption
|
||||
# (e.g. all Python distribution would need to adapt this option to be set).
|
||||
option(
|
||||
BUILD_ONLY_COMMON_SCHEMAS
|
||||
"Build only common IFC schemas (2x3, 4, 4x3_add2). By default all schemas will be built."
|
||||
OFF
|
||||
)
|
||||
option(SCHEMA_VERSIONS "Explicitly specify schemas to build." "")
|
||||
|
||||
option(WITH_OPENCASCADE "Enable geometry interpretation using Open CASCADE" ON)
|
||||
option(WITH_CGAL "Enable geometry interpretation using CGAL" ON)
|
||||
option(WITH_MANIFOLD "Enable geometry interpretation using Manifold" OFF)
|
||||
option(COLLADA_SUPPORT "Build IfcConvert with COLLADA support (requires OpenCOLLADA)." ON)
|
||||
option(GLTF_SUPPORT "Build IfcConvert with glTF support (requires json.hpp)." OFF)
|
||||
option(HDF5_SUPPORT "Enable HDF5 support (requires HDF5, zlib)" ON)
|
||||
option(WITH_PROJ "Enable output of Earth-Centered Earth-Fixed glTF output using the PROJ library" OFF)
|
||||
option(IFCXML_SUPPORT "Build IfcParse with ifcXML support (requires libxml2)." ON)
|
||||
option(USD_SUPPORT "Build IfcConvert with USD support (requires pixar's USD library)." OFF)
|
||||
option(WITH_RELATIONSHIP_VALIDATION "Build IfcConvert with option to validate geometrical relationships." OFF)
|
||||
option(WITH_ROCKSDB "Support a RocksDB key-value store as a file backend in IfcOpenShell" OFF)
|
||||
option(WITH_ZSTD "Use Zstd compression in RocksDB writes" OFF)
|
||||
|
||||
option(USERSPACE_PYTHON_PREFIX "Installs IfcPython for the current user only instead of system-wide." OFF)
|
||||
option(USE_DEBUG_PYTHON "Use debug binaries when building Debug IfcPython on Windows." OFF)
|
||||
option(ADD_COMMIT_SHA "Add commit sha and branch in version number, requires git" OFF)
|
||||
option(
|
||||
VERSION_OVERRIDE
|
||||
"Override the version defined in buildinfo.cpp with the file VERSION in the repository root"
|
||||
OFF
|
||||
)
|
||||
option(USE_CCACHE "Enable use of ccache if it's available from PATH." ON)
|
||||
option(VERSION_OVERRIDE "Override the version defined in buildinfo.cpp with the file VERSION in the repository root" OFF)
|
||||
|
||||
set(PYTHON_MODULE_INSTALL_DIR
|
||||
""
|
||||
CACHE PATH
|
||||
set(
|
||||
PYTHON_MODULE_INSTALL_DIR
|
||||
"" CACHE PATH
|
||||
"Directory to install IfcPython package to. By default package is installed in found Python's site-packages."
|
||||
)
|
||||
|
||||
if (VERSION_OVERRIDE)
|
||||
file(READ "../VERSION" "RELEASE_VERSION_")
|
||||
string(STRIP "${RELEASE_VERSION_}" RELEASE_VERSION)
|
||||
message(STATUS "Detected version '${RELEASE_VERSION}'")
|
||||
else()
|
||||
set(RELEASE_VERSION "0.8.0")
|
||||
endif()
|
||||
|
||||
project(IfcOpenShell VERSION ${RELEASE_VERSION})
|
||||
|
||||
# Make sure CMake modules in this project are found first
|
||||
list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
|
||||
|
||||
@@ -134,17 +118,20 @@ if(MINIMAL_BUILD)
|
||||
set(COLLADA_SUPPORT OFF)
|
||||
set(GLTF_SUPPORT OFF)
|
||||
set(HDF5_SUPPORT OFF)
|
||||
set(IFCXML_SUPPORT OFF)
|
||||
set(USD_SUPPORT OFF)
|
||||
endif()
|
||||
|
||||
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND (NOT BUILD_IFCGEOM))
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
message(FATAL_ERROR "BUILD_SHARED_LIBS=OFF is not supported. Configure with -DBUILD_SHARED_LIBS=ON.")
|
||||
endif()
|
||||
|
||||
if((BUILD_CONVERT OR BUILD_GEOMSERVER OR BUILD_IFCPYTHON) AND(NOT BUILD_IFCGEOM))
|
||||
message(STATUS "'IfcGeom' is required with current outputs")
|
||||
set(BUILD_IFCGEOM ON)
|
||||
endif()
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(USE_CCACHE AND CCACHE_FOUND)
|
||||
if(CCACHE_FOUND)
|
||||
message(STATUS "`ccache` is found, using it as a compiler launcher.")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
|
||||
if(MSVC)
|
||||
@@ -153,15 +140,17 @@ if(USE_CCACHE AND CCACHE_FOUND)
|
||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
|
||||
# Not needed for Ninja.
|
||||
if(CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||
file(COPY_FILE ${CCACHE_FOUND} ${CMAKE_BINARY_DIR}/cl.exe ONLY_IF_DIFFERENT)
|
||||
set(CMAKE_VS_GLOBALS "CLToolExe=cl.exe" "CLToolPath=${CMAKE_BINARY_DIR}" "UseMultiToolTask=true")
|
||||
file(COPY_FILE
|
||||
${CCACHE_FOUND} ${CMAKE_BINARY_DIR}/cl.exe
|
||||
ONLY_IF_DIFFERENT)
|
||||
set(CMAKE_VS_GLOBALS
|
||||
"CLToolExe=cl.exe"
|
||||
"CLToolPath=${CMAKE_BINARY_DIR}"
|
||||
"UseMultiToolTask=true"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
mark_as_advanced(CCACHE_FOUND)
|
||||
|
||||
# Variable to accumulate swig definitions from various submodules.
|
||||
set(SWIG_DEFINES "")
|
||||
|
||||
if(MSVC AND MSVC_PARALLEL_BUILD)
|
||||
add_definitions("/MP")
|
||||
@@ -177,28 +166,23 @@ endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(IFCOPENSHELL_EXPORT_TARGETS "${PROJECT_NAME}Targets")
|
||||
|
||||
# On Windows Release and Debug binaries are not compatible.
|
||||
# So we add a postfix to avoid issues and allow release and debug installations to coexist.
|
||||
if(WIN32)
|
||||
set(CMAKE_DEBUG_POSTFIX "_d")
|
||||
if(NOT INCLUDEDIR)
|
||||
set(INCLUDEDIR include)
|
||||
endif()
|
||||
if(NOT IS_ABSOLUTE ${INCLUDEDIR})
|
||||
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
endif()
|
||||
message(STATUS "INCLUDEDIR: ${INCLUDEDIR}")
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_definitions(-DIFC_SHARED_BUILD)
|
||||
if(MSVC)
|
||||
message(
|
||||
WARNING
|
||||
"Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed."
|
||||
)
|
||||
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
if(MSVC)
|
||||
message(WARNING "Building DLLs against the static VC run-time. This is not recommended if the DLLs are to be redistributed.")
|
||||
# C4521: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
||||
# There will be couple hundreds of these so suppress them away, https://msdn.microsoft.com/en-us/library/esew7y1w.aspx
|
||||
add_definitions(-wd4251)
|
||||
endif()
|
||||
|
||||
UNIFY_ENVVARS_AND_CACHE(BOOST_ROOT)
|
||||
UNIFY_ENVVARS_AND_CACHE(BOOST_LIBRARYDIR)
|
||||
|
||||
if(NOT MINIMAL_BUILD)
|
||||
UNIFY_ENVVARS_AND_CACHE(PYTHON_INCLUDE_DIR)
|
||||
@@ -214,71 +198,75 @@ foreach(option_flag IN LISTS option_flags)
|
||||
convert_env_var_to_bool("${option_flag}")
|
||||
endforeach()
|
||||
|
||||
if(WITH_CGAL)
|
||||
find_package(CGAL REQUIRED)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_CGAL)
|
||||
list(APPEND GEOMETRY_KERNELS cgal)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM AND WITH_OPENCASCADE)
|
||||
find_package(OpenCASCADE REQUIRED)
|
||||
add_definitions(-DIFOPSH_WITH_OPENCASCADE)
|
||||
# Map OpenCASCADE_LIBRARIES variable from OpenCASCADEConfig.cmake to OpenCASCADE_LIBRARIES used by kernel generic cmake file
|
||||
set(OpenCASCADE_LIBRARIES ${OpenCASCADE_LIBRARIES})
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_OPENCASCADE)
|
||||
list(APPEND GEOMETRY_KERNELS opencascade)
|
||||
endif()
|
||||
|
||||
set(GLTF_LIBRARIES "")
|
||||
message(STATUS "BUILD_IFCGEOM WITH_MANIFOLD: ${BUILD_IFCGEOM} ${WITH_MANIFOLD}")
|
||||
|
||||
if(BUILD_IFCGEOM AND WITH_MANIFOLD)
|
||||
find_package(manifold CONFIG REQUIRED)
|
||||
if(TARGET manifold::manifold)
|
||||
set(MANIFOLD_LIBRARIES manifold::manifold)
|
||||
elseif(TARGET manifold)
|
||||
set(MANIFOLD_LIBRARIES manifold)
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to determine manifold target")
|
||||
endif()
|
||||
list(APPEND GEOMETRY_KERNELS manifold)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
list(APPEND GEOMETRY_KERNELS passthrough)
|
||||
endif()
|
||||
|
||||
if(GLTF_SUPPORT)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
set(GLTF_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
add_definitions(-DWITH_GLTF)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_GLTF)
|
||||
endif()
|
||||
|
||||
# Add USD support to serializers
|
||||
set(USD_LIBRARIES "")
|
||||
if(USD_SUPPORT)
|
||||
find_package(USD REQUIRED)
|
||||
set(USD_LIBRARIES pxr::USD)
|
||||
endif(USD_SUPPORT)
|
||||
|
||||
set(ROCKSDB_LIBRARIES "")
|
||||
if(WITH_ROCKSDB)
|
||||
if (WITH_ROCKSDB)
|
||||
# Temporaily mess with CMAKE_FIND_PACKAGE_PREFER_CONFIG to help RocksDB
|
||||
# find it's zstd dependency on Windows.
|
||||
# Only do it on Windows, otherwise it might create problems as
|
||||
# findzstd and zstd-config target names do not match.
|
||||
# https://github.com/facebook/rocksdb/pull/13975
|
||||
if(WIN32)
|
||||
set(TEMP CMAKE_FIND_PACKAGE_PREFER_CONFIG)
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE)
|
||||
endif()
|
||||
find_package(RocksDB CONFIG REQUIRED)
|
||||
mark_as_advanced(RocksDB_DIR)
|
||||
if(WIN32)
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ${TEMP})
|
||||
endif()
|
||||
|
||||
message(STATUS "RocksDB: found at '${RocksDB_DIR}'.")
|
||||
add_library(IFCOPENSHELL_RocksDB INTERFACE)
|
||||
set(ROCKSDB_LIBRARIES "IFCOPENSHELL_RocksDB")
|
||||
target_compile_definitions(IFCOPENSHELL_RocksDB INTERFACE IFOPSH_WITH_ROCKSDB)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_ROCKSDB)
|
||||
# Shared binaries for `rocksdb` only support limited API (only `c.h`), but we use `db.h` API.
|
||||
# So rocksdb supported only as a static library.
|
||||
# See https://github.com/facebook/rocksdb/issues/981.
|
||||
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb)
|
||||
|
||||
if(WITH_ZSTD)
|
||||
if (WITH_ZSTD)
|
||||
# @todo do we actually need the zstd include dir or rather just pass
|
||||
# the libzstd.a along with the rocksdb library when needed and feature
|
||||
# detect based on rocksdb API?
|
||||
find_package(zstd CONFIG REQUIRED)
|
||||
mark_as_advanced(zstd_DIR)
|
||||
message(STATUS "zstd: found at '${zstd_DIR}'.")
|
||||
target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE zstd::libzstd_static)
|
||||
endif()
|
||||
|
||||
install(TARGETS IFCOPENSHELL_RocksDB EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
endif()
|
||||
|
||||
# Find Boost: On win32 the (hardcoded) default is to use static libraries and
|
||||
# runtime, when doing running conda-build we pick what conda prepared for us.
|
||||
if(WIN32 AND NOT DEFINED ENV{CONDA_BUILD})
|
||||
if(WIN32 AND("$ENV{CONDA_BUILD}" STREQUAL ""))
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
@@ -309,14 +297,8 @@ if(WASM_BUILD)
|
||||
else()
|
||||
# @todo review this, shouldn't this be all possible header-only now?
|
||||
# ... or rewritten using C++17 features?
|
||||
set(BOOST_COMPONENTS
|
||||
system
|
||||
program_options
|
||||
regex
|
||||
thread
|
||||
date_time
|
||||
iostreams
|
||||
)
|
||||
# set(BOOST_COMPONENTS system program_options regex thread date_time iostreams)
|
||||
set(BOOST_COMPONENTS program_options regex thread date_time iostreams)
|
||||
endif()
|
||||
|
||||
if(USE_MMAP)
|
||||
@@ -326,17 +308,6 @@ if(USE_MMAP)
|
||||
else()
|
||||
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} iostreams)
|
||||
endif()
|
||||
|
||||
add_definitions(-DUSE_MMAP)
|
||||
endif()
|
||||
|
||||
# Handle CGAL after Boost settings are set, since CGAL will use them too.
|
||||
# Do `find_package(Boost)` only after this, to make sure `FindBoost` finds correct components.
|
||||
# Otherwise it will find components needed for CGAL and we might some libraries.
|
||||
if(WITH_CGAL)
|
||||
find_package(CGAL REQUIRED)
|
||||
set(CGAL_LIBRARIES IFCOPENSHELL_CGAL)
|
||||
list(APPEND GEOMETRY_KERNELS cgal)
|
||||
endif()
|
||||
|
||||
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
@@ -345,15 +316,10 @@ message(STATUS "Boost libraries found in ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
if(COLLADA_SUPPORT)
|
||||
find_package(OpenCOLLADA REQUIRED)
|
||||
add_definitions(-DWITH_OPENCOLLADA)
|
||||
endif()
|
||||
|
||||
if(HDF5_SUPPORT)
|
||||
find_package(HDF5 REQUIRED COMPONENTS C CXX)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} hdf5::hdf5_cpp)
|
||||
|
||||
add_definitions(-DWITH_HDF5)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_HDF5)
|
||||
endif(HDF5_SUPPORT)
|
||||
|
||||
if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
@@ -368,20 +334,12 @@ if(ENABLE_BUILD_OPTIMIZATIONS)
|
||||
|
||||
# Linker
|
||||
# /OPT:REF enables also /OPT:ICF and disables INCREMENTAL
|
||||
set(LINKER_FLAGS_RELEASE "/LTCG /OPT:REF")
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(LINKER_FLAGS_RELWITHDEBINFO "/DEBUG /OPT:NOICF")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELWITHDEBINFO}"
|
||||
)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELWITHDEBINFO}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELEASE}")
|
||||
set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${LINKER_FLAGS_RELWITHDEBINFO}"
|
||||
)
|
||||
# /OPT:NOICF is recommended when /DEBUG is used (http://msdn.microsoft.com/en-us/library/xe4t6fc1.aspx)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:NOICF")
|
||||
else()
|
||||
# GCC-like: Release should use O3 but RelWithDebInfo 02 so enforce 03. Anything other useful that could be added here?
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
@@ -430,7 +388,7 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
# Enforce standards-conformance on VS > 2015, older Boost versions fail to compile with this
|
||||
if(MSVC_VERSION GREATER 1900 AND (Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
if(MSVC_VERSION GREATER 1900 AND(Boost_MAJOR_VERSION GREATER 1 OR Boost_MINOR_VERSION GREATER 66))
|
||||
add_definitions(-permissive-)
|
||||
endif()
|
||||
|
||||
@@ -449,11 +407,11 @@ if(MSVC)
|
||||
# endforeach()
|
||||
# endif()
|
||||
|
||||
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||
# See #5158.
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.40)
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
endif()
|
||||
add_definitions(-D_ENABLE_EXTENDED_ALIGNED_STORAGE)
|
||||
# See #5158.
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.40)
|
||||
add_definitions(-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-Wall -Wextra)
|
||||
|
||||
@@ -463,10 +421,7 @@ else()
|
||||
add_definitions(-Wno-maybe-uninitialized)
|
||||
endif()
|
||||
|
||||
if(
|
||||
CMAKE_CXX_COMPILER_ID MATCHES "GNU"
|
||||
AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0)
|
||||
)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 9.0))
|
||||
# OpenCascade spews a lot of deprecated-copy warnings
|
||||
add_definitions(-Wno-deprecated-copy)
|
||||
endif()
|
||||
@@ -477,45 +432,35 @@ else()
|
||||
endif()
|
||||
endif(MSVC)
|
||||
|
||||
include_directories(${OPENCOLLADA_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR})
|
||||
include_directories(${INCLUDE_DIRECTORIES}
|
||||
${Boost_INCLUDE_DIRS} ${HDF5_INCLUDE_DIR}
|
||||
${CGAL_INCLUDE_DIR} ${GMP_INCLUDE_DIR} ${MPFR_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
if(NOT SCHEMA_VERSIONS)
|
||||
# `WASM_BUILD` - super arbitrarily try to keep size down at least a little bit
|
||||
if(BUILD_ONLY_COMMON_SCHEMAS OR WASM_BUILD)
|
||||
if(WASM_BUILD)
|
||||
# super arbitrarily try to keep size down at least a little bit
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x3_add2")
|
||||
else()
|
||||
set(SCHEMA_VERSIONS
|
||||
"2x3"
|
||||
"4"
|
||||
"4x1"
|
||||
"4x2"
|
||||
"4x3"
|
||||
"4x3_tc1"
|
||||
"4x3_add1"
|
||||
"4x3_add2"
|
||||
)
|
||||
set(SCHEMA_VERSIONS "2x3" "4" "4x1" "4x2" "4x3" "4x3_tc1" "4x3_add1" "4x3_add2")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "IFC SCHEMA_VERSIONS that will be used for the build: ${SCHEMA_VERSIONS}.")
|
||||
|
||||
set(SCHEMA_DEFINITIONS "")
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
list(APPEND SCHEMA_DEFINITIONS "-DHAS_SCHEMA_${schema}")
|
||||
add_definitions(-DHAS_SCHEMA_${schema})
|
||||
endforeach()
|
||||
|
||||
string(REPLACE ";" ")(" schema_version_seq "(${SCHEMA_VERSIONS})")
|
||||
list(APPEND SCHEMA_DEFINITIONS "-DSCHEMA_SEQ=${schema_version_seq}")
|
||||
add_definitions(-DSCHEMA_SEQ=${schema_version_seq})
|
||||
|
||||
if(COMPILE_SCHEMA)
|
||||
# @todo, this appears to be untested at the moment
|
||||
find_package(PythonInterp)
|
||||
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed."
|
||||
)
|
||||
message(FATAL_ERROR "A Python interpreter is necessary when COMPILE_SCHEMA is enabled. Disable COMPILE_SCHEMA or fix Python paths to proceed.")
|
||||
endif()
|
||||
|
||||
set(IFC_RELEASE_NOT_USED ${SCHEMA_VERSIONS})
|
||||
@@ -535,10 +480,7 @@ if(COMPILE_SCHEMA)
|
||||
|
||||
if("${PYPARSING_FOUND}" STREQUAL "-1")
|
||||
message(STATUS "Installing pyparsing")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing
|
||||
RESULT_VARIABLE SUCCESS
|
||||
)
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if(NOT "${SUCCESS}" STREQUAL "0")
|
||||
execute_process(COMMAND pip "install" --user pyparsing RESULT_VARIABLE SUCCESS)
|
||||
@@ -553,23 +495,19 @@ if(COMPILE_SCHEMA)
|
||||
|
||||
# Bootstrap the parser
|
||||
message(STATUS "Compiling schema, this will take a while...")
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} bootstrap.py express.bnf
|
||||
WORKING_DIRECTORY ../src/ifcexpressparser
|
||||
OUTPUT_FILE express_parser.py
|
||||
RESULT_VARIABLE SUCCESS
|
||||
)
|
||||
RESULT_VARIABLE SUCCESS)
|
||||
|
||||
if(NOT "${SUCCESS}" STREQUAL "0")
|
||||
message(FATAL_ERROR "Failed to bootstrap parser. Make sure pyparsing is installed")
|
||||
endif()
|
||||
|
||||
# Generate code
|
||||
execute_process(
|
||||
COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
execute_process(COMMAND ${PYTHON_EXECUTABLE} ../ifcexpressparser/express_parser.py ../../${COMPILE_SCHEMA}
|
||||
WORKING_DIRECTORY ../src/ifcparse
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME
|
||||
)
|
||||
OUTPUT_VARIABLE COMPILED_SCHEMA_NAME)
|
||||
|
||||
# Prevent the schema that had just been compiled from being excluded
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
@@ -584,16 +522,39 @@ if(NOT Boost_VERSION LESS 105800)
|
||||
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
|
||||
endif()
|
||||
|
||||
add_subdirectory(../src/plugin plugin)
|
||||
|
||||
add_subdirectory(../src/ifcparse ifcparse)
|
||||
set(IFCOPENSHELL_LIBRARIES IfcParse)
|
||||
|
||||
if(BUILD_IFCPARSE_EXPERIMENTAL_WRAPPER)
|
||||
add_subdirectory(../src/wrappergen wrappergen)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
# CGAL::CGAL target already has dependencies resolved.
|
||||
if(WITH_CGAL AND CGAL_DIR)
|
||||
set(CGAL_LIBRARIES CGAL::CGAL)
|
||||
message(STATUS "Using found CGAL package at '${CGAL_DIR}'")
|
||||
elseif(WITH_CGAL AND NOT CGAL_DIR)
|
||||
find_library(libGMP NAMES gmp mpir PATHS ${GMP_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
find_library(libMPFR NAMES mpfr PATHS ${MPFR_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||
if(NOT libGMP)
|
||||
message(FATAL_ERROR "Unable to find GMP library files, aborting")
|
||||
endif()
|
||||
if(NOT libMPFR)
|
||||
message(FATAL_ERROR "Unable to find MPFR library files, aborting")
|
||||
endif()
|
||||
|
||||
list(APPEND CGAL_LIBRARIES "${libMPFR}")
|
||||
list(APPEND CGAL_LIBRARIES "${libGMP}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(../src/ifcgeom ifcgeom)
|
||||
endif(BUILD_IFCGEOM)
|
||||
|
||||
if(BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||
add_subdirectory(../src/serializers serializers)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} ${SERIALIZER_SCHEMA_LIBRARIES})
|
||||
endif(BUILD_CONVERT OR BUILD_IFCPYTHON)
|
||||
|
||||
if(BUILD_CONVERT)
|
||||
@@ -613,8 +574,8 @@ if(ADD_COMMIT_SHA)
|
||||
endif()
|
||||
|
||||
if(GIT_FOUND)
|
||||
if(VERSION_OVERRIDE)
|
||||
set(git_branch ${RELEASE_VERSION})
|
||||
if (VERSION_OVERRIDE)
|
||||
set (git_branch ${RELEASE_VERSION})
|
||||
else()
|
||||
message("git found: ${GIT_EXECUTABLE} with version ${GIT_VERSION_STRING}")
|
||||
execute_process(
|
||||
@@ -626,8 +587,8 @@ if(ADD_COMMIT_SHA)
|
||||
string(REPLACE "\n" ";" git_branch_list "${git_branches}")
|
||||
|
||||
foreach(git_branch_candidate IN ITEMS ${git_branch_list})
|
||||
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
|
||||
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
|
||||
string(REPLACE "*" "" git_branch_candidate_temp "${git_branch_candidate}")
|
||||
string(STRIP "${git_branch_candidate_temp}" git_branch_candidate_2)
|
||||
if(NOT git_branch_candidate_2 MATCHES "^HEAD$")
|
||||
string(REPLACE "/" ";" git_branch_candidate_2_list "${git_branch_candidate_2}")
|
||||
list(GET git_branch_candidate_2_list -1 git_branch)
|
||||
@@ -645,13 +606,13 @@ if(ADD_COMMIT_SHA)
|
||||
message(STATUS "IfcOpenShell branch: \"${git_branch}\"")
|
||||
message(STATUS "IfcOpenShell commit: \"${git_sha}\"")
|
||||
|
||||
if("${git_branch}" STREQUAL "" OR "${git_sha}" STREQUAL "")
|
||||
if ("${git_branch}" STREQUAL "" OR "${git_sha}" STREQUAL "")
|
||||
message(FATAL_ERROR "Unable to determine commit sha and/or branch")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(
|
||||
IfcParse
|
||||
PRIVATE -DIFCOPENSHELL_BRANCH=${git_branch} -DIFCOPENSHELL_COMMIT=${git_sha}
|
||||
target_compile_definitions(IfcParse PRIVATE
|
||||
-DIFCOPENSHELL_BRANCH=${git_branch}
|
||||
-DIFCOPENSHELL_COMMIT=${git_sha}
|
||||
)
|
||||
endif()
|
||||
endif(ADD_COMMIT_SHA)
|
||||
@@ -669,10 +630,6 @@ if(BUILD_DOCUMENTATION)
|
||||
add_subdirectory(../docs docs)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCPYTHON)
|
||||
add_subdirectory(../src/ifcwrap ifcwrap)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(../src/examples examples)
|
||||
endif()
|
||||
@@ -685,32 +642,82 @@ if(BUILD_IFCPYTHON AND WITH_CGAL)
|
||||
add_subdirectory(../src/svgfill svgfill)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCPYTHON)
|
||||
add_subdirectory(../src/ifcwrap ifcwrap)
|
||||
endif()
|
||||
|
||||
if(BUILD_QTVIEWER)
|
||||
add_subdirectory(../src/qtviewer qtviewer)
|
||||
endif()
|
||||
|
||||
if(BUILD_IFCGEOM)
|
||||
# install(FILES ${IFCGEOM_H_FILES}
|
||||
# DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
# )
|
||||
|
||||
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
)
|
||||
|
||||
file(GLOB SERIALIZATION_H_FILES ../src/ifcgeom/serialization/*.h)
|
||||
install(FILES ${SERIALIZATION_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/serialization
|
||||
)
|
||||
|
||||
foreach(kernel ${GEOMETRY_KERNELS})
|
||||
file(GLOB IFCGEOM_H_FILES ../src/ifcgeom/kernels/${kernel}/*.h)
|
||||
install(FILES ${IFCGEOM_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/kernels/${kernel}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
install(TARGETS ${IFCGEOM_SCHEMA_LIBRARIES} ${kernel_libraries} IfcGeom)
|
||||
endif(BUILD_IFCGEOM)
|
||||
if(BUILD_IFCVIEWER)
|
||||
if(BUILD_IFCVIEWER_TESTS)
|
||||
# Catch2 v3 — fetched on demand. Test option is OFF by default so the
|
||||
# default build remains offline-capable.
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||
GIT_TAG v3.5.4
|
||||
GIT_SHALLOW TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
add_subdirectory(../src/ifcviewer ifcviewer)
|
||||
add_subdirectory(../src/ifcviewer-minimal ifcviewer-minimal)
|
||||
add_subdirectory(../src/ifcviewer-full ifcviewer-full)
|
||||
endif()
|
||||
|
||||
# Cmake uninstall target
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE
|
||||
@ONLY
|
||||
)
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
# Packaging
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "/\\\\.git" "/build/" "/.pytest_cache/" "/__pycache__/")
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES
|
||||
"/\\\\.git"
|
||||
"/build/"
|
||||
"/.pytest_cache/"
|
||||
"/__pycache__/"
|
||||
)
|
||||
set(CPACK_SOURCE_INSTALLED_DIRECTORIES "${CMAKE_SOURCE_DIR}/..;/")
|
||||
set(CPACK_PACKAGE_NAME
|
||||
"${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}"
|
||||
)
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}${EXTRA_VERSION}")
|
||||
set(CPACK_PACKAGE_FILE_NAME
|
||||
"${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}"
|
||||
)
|
||||
SET(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${EXTRA_VERSION}-${CMAKE_SYSTEM_NAME}")
|
||||
set(CPACK_PACKAGE_DIRECTORY "${PROJECT_BINARY_DIR}/assets")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IfcOpenShell")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "IfcOpenShell.")
|
||||
@@ -723,7 +730,6 @@ set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
|
||||
set(CPACK_GENERATOR "TGZ;DEB")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ")
|
||||
|
||||
set(BOOST_DEPS "")
|
||||
foreach(COMPONENT IN ITEMS ${BOOST_COMPONENTS})
|
||||
string(REPLACE "_" "-" COMP ${COMPONENT})
|
||||
set(BOOST_DEPS "${BOOST_DEPS}, libboost-${COMP}-dev")
|
||||
@@ -731,19 +737,13 @@ endforeach(COMPONENT)
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_CONTACT}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS
|
||||
"python3, libxml2, libocct-foundation-dev, libocct-modeling-algorithms-dev, libocct-modeling-data-dev, libocct-ocaf-dev, libocct-visualization-dev, libocct-data-exchange-dev, libhdf5-serial-dev, libpython3-dev, python3-pytest ${BOOST_DEPS}"
|
||||
)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "python3, libxml2, libocct-foundation-dev, libocct-modeling-algorithms-dev, libocct-modeling-data-dev, libocct-ocaf-dev, libocct-visualization-dev, libocct-data-exchange-dev, libhdf5-serial-dev, libpython3-dev, python3-pytest ${BOOST_DEPS}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION_SUMMARY "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION "science")
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION
|
||||
"${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}"
|
||||
)
|
||||
set(CPACK_DEBIAN_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}${EXTRA_VERSION}")
|
||||
set(CPACK_DEBIAN_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
# set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/debian/postinst")
|
||||
|
||||
include(CPack)
|
||||
|
||||
include(package_export.cmake)
|
||||
|
||||
@@ -139,7 +139,8 @@ if(NOT OpenCOLLADA_DIR)
|
||||
endif()
|
||||
endif(NOT OpenCOLLADA_DIR)
|
||||
|
||||
if(OPENCOLLADA_FOUND)
|
||||
add_definitions(-DWITH_OPENCOLLADA)
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_OPENCOLLADA)
|
||||
if(OPENCOLLADA_FOUND AND NOT TARGET OpenCOLLADA::OpenCOLLADA)
|
||||
add_library(OpenCOLLADA::OpenCOLLADA INTERFACE IMPORTED)
|
||||
target_include_directories(OpenCOLLADA::OpenCOLLADA INTERFACE ${OPENCOLLADA_INCLUDE_DIRS})
|
||||
target_link_libraries(OpenCOLLADA::OpenCOLLADA INTERFACE ${OPENCOLLADA_LIBRARIES})
|
||||
endif()
|
||||
|
||||
+12
-6
@@ -6,7 +6,7 @@
|
||||
# Input variables could also be provided as environment variables.
|
||||
#
|
||||
# Output targets:
|
||||
# - `PROJ::proj`
|
||||
# - `proj::proj`
|
||||
#
|
||||
|
||||
# To avoid cyclic calls to this file
|
||||
@@ -34,10 +34,12 @@ if((NOT PROJ_INCLUDE_DIR AND NOT PROJ_LIBRARIES))
|
||||
message(FATAL_ERROR "Unable to find PROJ libraries in: ${PROJ_LIBRARY_DIR}")
|
||||
endif()
|
||||
|
||||
add_library(PROJ::proj INTERFACE IMPORTED)
|
||||
target_include_directories(PROJ::proj INTERFACE "${PROJ_INCLUDE_DIR}")
|
||||
target_link_libraries(PROJ::proj INTERFACE ${PROJ_LIBRARIES})
|
||||
target_link_directories(PROJ::proj INTERFACE "${PROJ_LIBRARY}")
|
||||
if(NOT TARGET proj::proj)
|
||||
add_library(proj::proj INTERFACE IMPORTED)
|
||||
target_include_directories(proj::proj INTERFACE "${PROJ_INCLUDE_DIR}")
|
||||
target_link_libraries(proj::proj INTERFACE ${PROJ_LIBRARIES})
|
||||
target_link_directories(proj::proj INTERFACE "${PROJ_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
find_library(PROJ_LIBRARY NAMES proj PATHS ${PROJ_LIBRARY_DIR})
|
||||
@@ -50,7 +52,11 @@ else()
|
||||
|
||||
set(PROJ_INCLUDE_DIR ${PROJ_INCLUDE_DIR} CACHE FILEPATH "PROJ header files")
|
||||
message(STATUS "Looking for PROJ include files in: ${PROJ_INCLUDE_DIR}")
|
||||
include_directories(${PROJ_INCLUDE_DIR})
|
||||
if(NOT TARGET proj::proj)
|
||||
add_library(proj::proj INTERFACE IMPORTED)
|
||||
target_include_directories(proj::proj INTERFACE "${PROJ_INCLUDE_DIR}")
|
||||
target_link_libraries(proj::proj INTERFACE ${PROJ_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
|
||||
|
||||
@@ -64,7 +64,6 @@ set(USD_LIBRARIES
|
||||
find_library(USD_LIBRARY NAMES ${USD_LIBRARIES} PATHS ${USD_LIBRARY_DIR})
|
||||
if(USD_LIBRARY)
|
||||
message(STATUS "USD libraries ${USD_LIBRARIES} found in: ${USD_LIBRARY_DIR}")
|
||||
link_directories(${USD_LIBRARY_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "Unable to find USD libraries in: ${USD_LIBRARY_DIR}")
|
||||
endif()
|
||||
@@ -82,5 +81,3 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(pxr::USD INTERFACE PXR_STATIC WITH_USD)
|
||||
|
||||
set(SWIG_DEFINES ${SWIG_DEFINES} -DWITH_USD)
|
||||
|
||||
@@ -37,7 +37,6 @@ cmake -G "Ninja" ^
|
||||
-D GLTF_SUPPORT:BOOL=ON ^
|
||||
-D BUILD_CONVERT:BOOL=ON ^
|
||||
-D BUILD_IFCMAX:BOOL=OFF ^
|
||||
-D IFCXML_SUPPORT:BOOL=ON ^
|
||||
-D Boost_LIBRARY_DIR:FILEPATH="%LIBRARY_PREFIX%\lib" ^
|
||||
-D Boost_INCLUDE_DIR:FILEPATH="%LIBRARY_PREFIX%\include" ^
|
||||
-D Boost_USE_STATIC_LIBS:BOOL=OFF ^
|
||||
|
||||
@@ -34,7 +34,6 @@ cmake ${CMAKE_ARGS} -G Ninja \
|
||||
-DEIGEN_DIR:FILEPATH=$PREFIX/include/eigen3 \
|
||||
-DCOLLADA_SUPPORT:BOOL=OFF \
|
||||
-DBUILD_EXAMPLES:BOOL=OFF \
|
||||
-DIFCXML_SUPPORT:BOOL=ON \
|
||||
-DGLTF_SUPPORT:BOOL=ON \
|
||||
-DBUILD_CONVERT:BOOL=ON \
|
||||
-DBUILD_IFCPYTHON:BOOL=ON \
|
||||
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
# Build fix: remove `boost_system` from CMake components
|
||||
|
||||
`Boost.System` became header-only in Boost 1.69. Boost 1.90.0 no longer ships a compiled library or CMake config for it, so `find_package(Boost REQUIRED COMPONENTS system ...)` fails.
|
||||
|
||||
## Fix
|
||||
|
||||
`cmake/CMakeLists.txt`:
|
||||
|
||||
```diff
|
||||
- set(BOOST_COMPONENTS system program_options regex thread date_time iostreams)
|
||||
+ set(BOOST_COMPONENTS program_options regex thread date_time iostreams)
|
||||
```
|
||||
|
||||
The headers are still available; no linking is needed.
|
||||
|
||||
# Build fix: add `template` keyword for dependent template member calls
|
||||
|
||||
Calling a template member function through a dependent expression (e.g. `storage->has_attribute_value<T>(...)` where `storage`'s type depends on a template parameter) requires the `template` keyword to disambiguate from a less-than comparison.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
src/ifcparse/IfcParse.cpp:1856:67: error: expected primary-expression before '>' token
|
||||
1856 | if (storage->has_attribute_value<express::Base>(attr_index)) {
|
||||
| ^
|
||||
```
|
||||
|
||||
Six identical errors at lines 1856, 1865, 1896, 1905, 1934, 1943.
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcparse/IfcParse.cpp`:
|
||||
|
||||
```diff
|
||||
-storage->has_attribute_value<express::Base>(attr_index)
|
||||
+storage->template has_attribute_value<express::Base>(attr_index)
|
||||
|
||||
-storage->has_attribute_value<Blank>(attr_index)
|
||||
+storage->template has_attribute_value<Blank>(attr_index)
|
||||
```
|
||||
|
||||
Applied at all six call sites in `in_memory_file_storage::read_from_stream`.
|
||||
|
||||
# Linker fix: missing explicit template instantiations for `InstanceStreamer`
|
||||
|
||||
`InstanceStreamer` is a class template with methods defined in `IfcParse.cpp`, not the header. Without explicit instantiations, the linker can't find the symbols when the SWIG wrapper loads.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ImportError: undefined symbol: _ZN8IfcParse16InstanceStreamerINS_10FileReaderINS_14FullBufferImplEEEEC1EPS3_PNS_7IfcFileE
|
||||
(IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(FileReader<FullBufferImpl>*, IfcFile*))
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
Cannot use `template class InstanceStreamer<...>` because some constructors have `static_assert` guards that reject certain reader types. Instead, instantiate each member function individually per reader type, only including the constructors valid for that type.
|
||||
|
||||
`src/ifcparse/IfcParse.cpp` (after the last `InstanceStreamer` method definition):
|
||||
|
||||
```cpp
|
||||
// FullBufferImpl
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(IfcParse::IfcFile*);
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(const std::string&, bool, IfcParse::IfcFile*);
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(void*, int, IfcParse::IfcFile*);
|
||||
template IfcParse::InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(FileReader<FullBufferImpl>*, IfcParse::IfcFile*);
|
||||
// ... plus ensure_header, initialize_header, hasSemicolon, semicolonCount,
|
||||
// pushPage, bypassTypes, readInstance
|
||||
|
||||
// PushedSequentialImpl — same pattern, different valid constructors
|
||||
|
||||
// MMapFileReader (ifdef USE_MMAP) — same pattern
|
||||
```
|
||||
|
||||
# Linker fix: `FullBufferImpl` missing buffer constructor
|
||||
|
||||
SWIG's `stream_from_string` calls `InstanceStreamer<FileReader<FullBufferImpl>>(void*, int, IfcFile*)`, but the `(void*, int)` constructor previously hit a `static_assert` for `FullBufferImpl` — it only allowed `PushedSequentialImpl`.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ImportError: undefined symbol: _ZN8IfcParse16InstanceStreamerINS_10FileReaderINS_14FullBufferImplEEEEC1EPviPNS_7IfcFileE
|
||||
(InstanceStreamer<FileReader<FullBufferImpl>>::InstanceStreamer(void*, int, IfcFile*))
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
Three changes to make `FullBufferImpl` support buffer-based and default construction:
|
||||
|
||||
`src/ifcparse/FileReader.h` — add buffer constructor to `FullBufferImpl`:
|
||||
|
||||
```diff
|
||||
class IFC_PARSE_API FullBufferImpl {
|
||||
public:
|
||||
explicit FullBufferImpl(const std::string& fn);
|
||||
+ FullBufferImpl(void* data, size_t length);
|
||||
```
|
||||
|
||||
`src/ifcparse/FileReader.h` — add `FileReader(void*, size_t)` forwarding constructor:
|
||||
|
||||
```diff
|
||||
+ FileReader(void* data, size_t length)
|
||||
+ : cursor_(0) {
|
||||
+ if constexpr (std::is_same_v<Impl, FullBufferImpl>) {
|
||||
+ impl_ = std::make_shared<Impl>(data, length);
|
||||
+ } else {
|
||||
+ static_assert(...);
|
||||
+ }
|
||||
+ }
|
||||
```
|
||||
|
||||
`src/ifcparse/FileReader.cpp` — implement the constructor:
|
||||
|
||||
```cpp
|
||||
FullBufferImpl::FullBufferImpl(void* data, size_t length)
|
||||
: buf_(static_cast<char*>(data), static_cast<char*>(data) + length)
|
||||
, size_(length) {
|
||||
}
|
||||
```
|
||||
|
||||
`src/ifcparse/IfcParse.cpp` — extend the two `InstanceStreamer` constructors to accept `FullBufferImpl`:
|
||||
|
||||
```diff
|
||||
// InstanceStreamer(IfcFile*):
|
||||
+ } else if constexpr (std::is_same_v<Reader, FileReader<FullBufferImpl>>) {
|
||||
+ owned_stream_ = std::make_unique<Reader>(nullptr, (size_t)0);
|
||||
|
||||
// InstanceStreamer(void*, int, IfcFile*):
|
||||
+ } else if constexpr (std::is_same_v<Reader, FileReader<FullBufferImpl>>) {
|
||||
+ owned_stream_ = std::make_unique<Reader>(data, (size_t)length);
|
||||
```
|
||||
|
||||
# Runtime fix: segfault in `parse_context::push()` due to vector reallocation
|
||||
|
||||
`parse_context_pool` stores nodes in a `std::vector<parse_context>`. During parsing, `load()` takes a `parse_context&` parameter and calls `context.push()`, which calls `pool_->make()`. If the pool's vector reallocates (via `emplace_back`), all existing references into the vector — including the `context` reference held by the caller — become dangling. Subsequent access through the dangling reference causes a segfault.
|
||||
|
||||
Triggered by larger IFC files (e.g. `ISSUE_159_kleine_Wohnung_R22.ifc`, 9.5 MB) that cause enough pool growth to trigger reallocation.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
Thread 1 received signal SIGSEGV, Segmentation fault.
|
||||
0x... in IfcParse::parse_context::push()
|
||||
#1 in_memory_file_storage::load(...) // context& is dangling after reallocation
|
||||
#2 in_memory_file_storage::load(...) // parent call
|
||||
#3 InstanceStreamer::readInstance()
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcparse/storage.h` — change the pool container from `std::vector` to `std::deque`, which does not invalidate references on `push_back`/`emplace_back`:
|
||||
|
||||
```diff
|
||||
+#include <deque>
|
||||
|
||||
struct parse_context_pool {
|
||||
- std::vector<parse_context> nodes_;
|
||||
+ std::deque<parse_context> nodes_;
|
||||
```
|
||||
|
||||
# Runtime fix: `express::Base` comparison operators throw on null/expired instances
|
||||
|
||||
`express::Base::operator<` and `operator==` called `data()`, which throws `std::runtime_error("Trying to access deleted instance reference")` when the internal `weak_ptr` is expired. A default-constructed `express::Base` (the value-type equivalent of a null pointer) always has an expired `weak_ptr`.
|
||||
|
||||
## Why this model triggers it
|
||||
|
||||
The bug requires two conditions to coincide:
|
||||
|
||||
1. A representation is shared by **more than one product** (via `IfcRepresentationMap` / `IfcMappedItem`).
|
||||
2. At least one of those products has **no material association**, so `get_single_material_association()` returns `express::Base{}` (the null equivalent).
|
||||
|
||||
In `advanced_model.ifc`, Body representations like `#449` (Body/Brep) have a single `IfcRepresentationMap` (`#453`) with 13 `IfcMappedItem` usages, meaning 13 products share the geometry. Some of those products (e.g. `IfcFlowTerminal` instances) have no `IfcRelAssociatesMaterial`, so `get_single_material_association` returns `express::Base{}`.
|
||||
|
||||
Smaller or simpler models don't hit this because either:
|
||||
- Every representation maps to only 1 product → `reuse_ok_` short-circuits at `products.size() == 1` before reaching the material check.
|
||||
- Every product has a material association → no null `express::Base` is ever inserted into the set.
|
||||
|
||||
## Exact call sequence
|
||||
|
||||
```
|
||||
Iterator::initialize()
|
||||
try {
|
||||
mapping::get_representations(reps, filters_)
|
||||
addRepresentationsFromDefaultContexts(representations)
|
||||
→ collects reps from subcontexts in order:
|
||||
Axis (#115): 143 reps
|
||||
Body (#117): 7550 reps
|
||||
FootPrint (#119): 12 reps
|
||||
|
||||
for (auto representation : representations):
|
||||
|
||||
── Axis reps (indices 0–142) ──────────────────────────
|
||||
products_represented_by(rep, rmap)
|
||||
→ OfProductRepresentation: 1 product each
|
||||
filter_products(products, filters) → 1 product
|
||||
reuse_ok_(ifcproducts)
|
||||
→ products.size() == 1 → return true ← SHORT-CIRCUIT, no material check
|
||||
representation_mapped_to(rep) → null (no MappedItem)
|
||||
→ task created. 143 tasks accumulated.
|
||||
|
||||
── First Body rep #449 (Body/Brep) ────────────────────
|
||||
products_represented_by(#449, rmap)
|
||||
→ OfProductRepresentation: empty
|
||||
→ RepresentationMap: 1 map (#453)
|
||||
→ MapUsage: 13 MappedItems → traces through to 13 IfcProducts
|
||||
filter_products(products, filters) → 13 products
|
||||
reuse_ok_(ifcproducts) ← CRASH HERE
|
||||
→ products.size() == 1? NO (13 products)
|
||||
→ for each product:
|
||||
find_openings(product) → OK
|
||||
get_single_material_association(product)
|
||||
→ some products have no IfcRelAssociatesMaterial
|
||||
→ returns express::Base{} (expired weak_ptr)
|
||||
associated_single_materials.insert(result)
|
||||
→ std::set::insert calls operator<
|
||||
→ operator< calls data()
|
||||
→ data() calls data_.lock() → expired → THROWS
|
||||
"Trying to access deleted instance reference"
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e) ← exception caught here, get_representations aborted
|
||||
}
|
||||
|
||||
→ reps contains only the 143 Axis tasks created before the throw
|
||||
→ all 143 Axis reps have Curve2D geometry → map(representation) returns null
|
||||
→ no valid elements produced → initialize() returns false
|
||||
```
|
||||
|
||||
In the old pointer-based code, `reuse_ok_` used `std::set<const IfcUtil::IfcBaseEntity*>` and `get_single_material_association` returned `nullptr`. Inserting `nullptr` into a `std::set<T*>` is a plain pointer comparison — no dereference, no throw. The refactoring to `std::set<express::Base>` changed the comparison from pointer comparison to `express::Base::operator<`, which unconditionally dereferences through `data()`.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
[Error] Trying to access deleted instance reference
|
||||
[Notice] Created 143 tasks for 143 products ← only Axis reps; all Body reps lost
|
||||
initialize() returned: False
|
||||
```
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcparse/express.h` — use `weak_ptr::lock().get()` instead of `data()` so that expired pointers compare as `nullptr` (matching old raw-pointer semantics):
|
||||
|
||||
```diff
|
||||
bool operator<(const Base& other) const {
|
||||
- return data() < other.data();
|
||||
+ auto a = data_.lock();
|
||||
+ auto b = other.data_.lock();
|
||||
+ return a.get() < b.get();
|
||||
}
|
||||
|
||||
bool operator==(const Base& other) const {
|
||||
- return data() == other.data();
|
||||
+ auto a = data_.lock();
|
||||
+ auto b = other.data_.lock();
|
||||
+ return a.get() == b.get();
|
||||
}
|
||||
```
|
||||
|
||||
# Runtime fix: `entity_instance` missing `get_inverse` due to SWIG `%rename` collision
|
||||
|
||||
Accessing inverse attributes (e.g. `element.IsDecomposedBy`) on any entity raises `AttributeError: entity instance of type 'IFC2X3.IfcProject' has no attribute 'get_inverse'`.
|
||||
|
||||
## Why
|
||||
|
||||
`entity_instance_mixin.__getattr__` (line 106 of `entity_instance.py`) calls `self.get_inverse(name)` when it detects an inverse attribute. Since the mixin inherits into the SWIG-generated `entity_instance` class (via the `object = custom_base` hack in `IfcParseWrapper.i:936`), `self.get_inverse` must resolve to a method on the SWIG class.
|
||||
|
||||
However, `IfcParseWrapper.i:70` has a global rename:
|
||||
|
||||
```
|
||||
%rename("get_inverses_by_declaration") get_inverse;
|
||||
```
|
||||
|
||||
This was intended for `ifcopenshell::file::get_inverse` (which takes an entity + declaration and returns instances by reference), but SWIG `%rename` is global — it also renames the `%extend express::Base` method `get_inverse(const std::string& a)` at line 551. So the Python-side `entity_instance` class exposes the method as `get_inverses_by_declaration`, not `get_inverse`.
|
||||
|
||||
The old code (`v0.8.0`) didn't hit this because `__getattr__` called `self.wrapped_data.get_inverse(name)` on an inner `ifcopenshell_wrapper.entity_instance` object — but in that old layout, the inner object was constructed differently and the rename didn't apply the same way (or the method had a different path). In the new mixin approach, `self` **is** the SWIG object, so the rename is directly visible.
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcwrap/IfcParseWrapper.i` — override the global rename specifically for `express::Base::get_inverse`, restoring the original name on entity instances:
|
||||
|
||||
```diff
|
||||
+%rename("get_inverse") express::Base::get_inverse;
|
||||
%rename("get_inverses_by_declaration") get_inverse;
|
||||
```
|
||||
|
||||
Add this line **before** the global rename (or anywhere before the `%extend express::Base` block). This scoped rename takes precedence for `express::Base`, so:
|
||||
- `entity_instance.get_inverse(name)` works as the mixin expects
|
||||
- `file.get_inverses_by_declaration(...)` keeps its intended name
|
||||
|
||||
## Python-side workaround
|
||||
|
||||
`entity_instance.py:106` — call the method by its SWIG-renamed name:
|
||||
|
||||
```diff
|
||||
- vs = self.get_inverse(name)
|
||||
+ vs = self.get_inverses_by_declaration(name)
|
||||
```
|
||||
|
||||
# Runtime fix: `entity_instance` class no longer importable from `entity_instance` module
|
||||
|
||||
The class rename from `entity_instance` to `entity_instance_mixin` broke external code that does `from ifcopenshell.entity_instance import entity_instance`.
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ImportError: cannot import name 'entity_instance' from 'ifcopenshell.entity_instance'
|
||||
```
|
||||
|
||||
Triggered at import time via `ifcopenshell.util.pset` (and likely other modules).
|
||||
|
||||
## Fix
|
||||
|
||||
`src/ifcopenshell-python/ifcopenshell/entity_instance.py` — add a backwards-compatible alias at the bottom of the module:
|
||||
|
||||
```python
|
||||
entity_instance = entity_instance_mixin
|
||||
```
|
||||
+83
-48
@@ -162,6 +162,8 @@ USD_VERSION = "23.05"
|
||||
TBB_VERSION = "2021.9.0"
|
||||
ROCKSDB_VERSION = "9.11.2"
|
||||
ZSTD_VERSION = "1.5.7"
|
||||
MANIFOLD_VERSION = "3.2.1"
|
||||
|
||||
# binaries
|
||||
cp = "cp"
|
||||
bash = "bash"
|
||||
@@ -330,7 +332,7 @@ cecho(""" - IFC Schemas to compile. If not provided, fallback to default provide
|
||||
|
||||
dependency_tree: "dict[str, tuple[str, ...]]" = {
|
||||
"IfcParse": ("boost", "libxml2", "hdf5", "rocksdb"),
|
||||
"IfcGeom": ("IfcParse", "occ", "json", "cgal", "eigen", "OpenCOLLADA"),
|
||||
"IfcGeom": ("IfcParse", "occ", "manifold", "json", "cgal", "eigen", "OpenCOLLADA"),
|
||||
"IfcConvert": ("IfcGeom",),
|
||||
"OpenCOLLADA": ("libxml2", "pcre"),
|
||||
"IfcGeomServer": ("IfcGeom",),
|
||||
@@ -347,6 +349,7 @@ dependency_tree: "dict[str, tuple[str, ...]]" = {
|
||||
"eigen": (),
|
||||
"rocksdb": ("zstd",),
|
||||
"zstd": (),
|
||||
"manifold": (),
|
||||
# 'usd': ('boost', 'oneTBB')
|
||||
}
|
||||
|
||||
@@ -583,6 +586,11 @@ def run_cmake(arg1, cmake_args: "list[str]", cmake_dir: Union[str, None] = None,
|
||||
]
|
||||
)
|
||||
|
||||
if not any("BUILD_SHARED_LIBS" in f for f in cmake_args):
|
||||
cmake_flags.append(
|
||||
f"-DBUILD_SHARED_LIBS={OFF_ON[not BUILD_STATIC]}",
|
||||
)
|
||||
|
||||
run(
|
||||
[
|
||||
*wasm,
|
||||
@@ -591,7 +599,6 @@ def run_cmake(arg1, cmake_args: "list[str]", cmake_dir: Union[str, None] = None,
|
||||
*cmake_flags,
|
||||
*cmake_args,
|
||||
f"-DCMAKE_BUILD_TYPE={BUILD_CFG}",
|
||||
f"-DBUILD_SHARED_LIBS={OFF_ON[not BUILD_STATIC]}",
|
||||
f"-DCMAKE_SHARED_LINKER_FLAGS={os.environ['LDFLAGS']}",
|
||||
],
|
||||
cwd=cwd,
|
||||
@@ -994,6 +1001,29 @@ elif "occ" in targets:
|
||||
download_name=f"OCE-{OCE_VERSION}.tar.gz",
|
||||
)
|
||||
|
||||
if "manifold" in targets:
|
||||
dependency_name = f"manifold-{MANIFOLD_VERSION}"
|
||||
build_dependency(
|
||||
name=dependency_name,
|
||||
mode="cmake",
|
||||
build_tool_args=[
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/{dependency_name}",
|
||||
"-DMANIFOLD_PAR=OFF",
|
||||
"-DMANIFOLD_CROSS_SECTION=OFF",
|
||||
"-DMANIFOLD_PYBIND=OFF",
|
||||
"-DMANIFOLD_JSBIND=OFF",
|
||||
"-DMANIFOLD_CBIND=OFF",
|
||||
"-DMANIFOLD_TEST=OFF",
|
||||
"-DMANIFOLD_EXPORT=OFF",
|
||||
"-DMANIFOLD_DOWNLOADS=OFF",
|
||||
*MAC_CROSS_COMPILE_INTEL_ARGS,
|
||||
],
|
||||
download_url="https://github.com/elalish/manifold.git",
|
||||
download_name="manifold",
|
||||
download_tool=download_tool_git,
|
||||
revision=f"v{MANIFOLD_VERSION}",
|
||||
)
|
||||
|
||||
if "libxml2" in targets:
|
||||
OLD_CC = ""
|
||||
if MAC_CROSS_COMPILE_INTEL:
|
||||
@@ -1304,16 +1334,17 @@ if os.environ.get("NO_CLEAN", "").lower() not in {"1", "on", "true"}:
|
||||
if os.path.exists(IFCOS_DIR):
|
||||
shutil.rmtree(IFCOS_DIR)
|
||||
os.makedirs(IFCOS_DIR, exist_ok=True)
|
||||
executables_dir = os.path.join(IFCOS_DIR, "executables")
|
||||
os.makedirs(executables_dir, exist_ok=True)
|
||||
ifcos_build_dir = os.path.join(IFCOS_DIR, "build")
|
||||
os.makedirs(ifcos_build_dir, exist_ok=True)
|
||||
|
||||
|
||||
cmake_args = [
|
||||
"-DUSE_MMAP=OFF",
|
||||
"-DBUILD_EXAMPLES=OFF",
|
||||
"-DBUILD_SHARED_LIBS=" + OFF_ON[not BUILD_STATIC],
|
||||
"-DBUILD_SHARED_LIBS=ON",
|
||||
"-DGLTF_SUPPORT=ON",
|
||||
"-DBoost_NO_BOOST_CMAKE=On",
|
||||
"-DCREATE_BUNDLE=On",
|
||||
"-DADD_COMMIT_SHA=" + ("On" if ADD_COMMIT_SHA else "Off"),
|
||||
"-DVERSION_OVERRIDE=" + ("On" if ADD_COMMIT_SHA else "Off"),
|
||||
*MAC_CROSS_COMPILE_INTEL_ARGS,
|
||||
@@ -1363,6 +1394,10 @@ elif "occ" in targets:
|
||||
occ_library_dir = f"{DEPS_DIR}/install/oce-{OCE_VERSION}/lib"
|
||||
cmake_args.extend(["-DOCC_INCLUDE_DIR=" + occ_include_dir, "-DOCC_LIBRARY_DIR=" + occ_library_dir])
|
||||
|
||||
if "manifold" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/manifold-{MANIFOLD_VERSION}")
|
||||
cmake_args.append("-DWITH_MANIFOLD=On")
|
||||
|
||||
if "OpenCOLLADA" in targets:
|
||||
# pcre is a dependency of OpenCOLLADA, but since we `find_package`,
|
||||
# we don't need to add it explicitly here as cmake will find it from the config.
|
||||
@@ -1408,40 +1443,33 @@ if "rocksdb" in targets:
|
||||
if "swig" in targets:
|
||||
cmake_args_prefix_path.append(f"{DEPS_DIR}/install/swig-{SWIG_VERSION}")
|
||||
|
||||
ifcos_build_args = [
|
||||
f"-DBUILD_IFCGEOM={OFF_ON['IfcGeom' in targets]}",
|
||||
f"-DBUILD_GEOMSERVER={OFF_ON['IfcGeomServer' in targets]}",
|
||||
f"-DBUILD_CONVERT={OFF_ON['IfcConvert' in targets]}",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell",
|
||||
]
|
||||
|
||||
if not WASM and (not explicit_targets or {"IfcGeom", "IfcConvert", "IfcGeomServer"} & set(explicit_targets)):
|
||||
logger.info("\rConfiguring executables...")
|
||||
|
||||
exec_args = [
|
||||
f"-DBUILD_IFCGEOM={OFF_ON['IfcGeom' in targets]}",
|
||||
f"-DBUILD_GEOMSERVER={OFF_ON['IfcGeomServer' in targets]}",
|
||||
f"-DBUILD_CONVERT={OFF_ON['IfcConvert' in targets]}",
|
||||
*ifcos_build_args,
|
||||
f"-DBUILD_IFCPYTHON=OFF",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell",
|
||||
]
|
||||
|
||||
run_cmake("", exec_args + cmake_args + get_cmake_args_prefix_path(), cmake_dir=CMAKE_DIR, cwd=executables_dir)
|
||||
run_cmake("", exec_args + cmake_args + get_cmake_args_prefix_path(), cmake_dir=CMAKE_DIR, cwd=ifcos_build_dir)
|
||||
|
||||
logger.info("\rBuilding executables... ")
|
||||
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "VERBOSE=1"], cwd=executables_dir)
|
||||
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=executables_dir)
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "VERBOSE=1"], cwd=ifcos_build_dir)
|
||||
run([make, "install/strip" if BUILD_CFG == "Release" else "install"], cwd=ifcos_build_dir)
|
||||
|
||||
if "IfcOpenShell-Python" in targets:
|
||||
# On OSX the actual Python library is not linked against.
|
||||
ADDITIONAL_ARGS = ""
|
||||
wrapper_ldflags = ""
|
||||
if platform.system() == "Darwin":
|
||||
ADDITIONAL_ARGS = "-Wl,-undefined,dynamic_lookup"
|
||||
|
||||
# NOTE: We don't use `CXXFLAGS` for wrappers, so wrapper is compiled with different flags
|
||||
# (e.g. ` -fdata-sections` is missing, which is set by default for executables)
|
||||
# So cache doesn't match and running build-all.py builds most of ifcopenshell libraries twice.
|
||||
os.environ["CPPFLAGS"] = f"{CXXFLAGS_MINIMAL} {ADDITIONAL_ARGS}"
|
||||
os.environ["CXXFLAGS"] = f"{CXXFLAGS_MINIMAL} {ADDITIONAL_ARGS}"
|
||||
os.environ["CFLAGS"] = f"{CFLAGS_MINIMAL} {ADDITIONAL_ARGS}"
|
||||
os.environ["LDFLAGS"] = f"{LDFLAGS} {ADDITIONAL_ARGS}"
|
||||
|
||||
python_dir = os.path.join(IFCOS_DIR, "pythonwrapper")
|
||||
os.makedirs(python_dir, exist_ok=True)
|
||||
# On OSX the actual Python library is not linked against.
|
||||
wrapper_ldflags = "-Wl,-undefined,dynamic_lookup"
|
||||
|
||||
def compile_python_wrapper(
|
||||
python_version: str,
|
||||
@@ -1456,10 +1484,6 @@ if "IfcOpenShell-Python" in targets:
|
||||
|
||||
logger.info(f"\rConfiguring python {python_version} wrapper...")
|
||||
|
||||
cache_path = os.path.join(python_dir, "CMakeCache.txt")
|
||||
if os.path.exists(cache_path):
|
||||
os.remove(cache_path)
|
||||
|
||||
if python_path:
|
||||
# We couldn't just prefix PATH and have to provide all variables explicitly,
|
||||
# see ifcwrap/cmake for the details.
|
||||
@@ -1473,27 +1497,38 @@ if "IfcOpenShell-Python" in targets:
|
||||
)
|
||||
|
||||
assert python_include
|
||||
run_cmake(
|
||||
"",
|
||||
cmake_args
|
||||
+ get_cmake_args_prefix_path()
|
||||
+ [
|
||||
*([f"-DPYTHON_EXECUTABLE={python_executable}"] if python_executable else []),
|
||||
# Needed because pyodide is expecting setup.py to be in the root.
|
||||
*([f"-DPYTHON_MODULE_INSTALL_DIR={REPO_PATH}"] * WASM),
|
||||
f"-DPYTHON_INCLUDE_DIR={python_include}",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell/tmp",
|
||||
"-DUSERSPACE_PYTHON_PREFIX="
|
||||
+ ["Off", "On"][os.environ.get("PYTHON_USER_SITE", "").lower() in {"1", "on", "true"}],
|
||||
],
|
||||
cmake_dir=CMAKE_DIR,
|
||||
cwd=python_dir,
|
||||
)
|
||||
old_ldflags = os.environ["LDFLAGS"]
|
||||
if wrapper_ldflags:
|
||||
os.environ["LDFLAGS"] = f"{old_ldflags} {wrapper_ldflags}"
|
||||
|
||||
try:
|
||||
run_cmake(
|
||||
"",
|
||||
ifcos_build_args
|
||||
+ [
|
||||
"-DBUILD_IFCPYTHON=ON",
|
||||
]
|
||||
+ cmake_args
|
||||
+ get_cmake_args_prefix_path()
|
||||
+ [
|
||||
*([f"-DPYTHON_EXECUTABLE={python_executable}"] if python_executable else []),
|
||||
# Needed because pyodide is expecting setup.py to be in the root.
|
||||
*([f"-DPYTHON_MODULE_INSTALL_DIR={REPO_PATH}"] * WASM),
|
||||
f"-DPYTHON_INCLUDE_DIR={python_include}",
|
||||
f"-DCMAKE_INSTALL_PREFIX={DEPS_DIR}/install/ifcopenshell/tmp",
|
||||
"-DUSERSPACE_PYTHON_PREFIX="
|
||||
+ ["Off", "On"][os.environ.get("PYTHON_USER_SITE", "").lower() in {"1", "on", "true"}],
|
||||
],
|
||||
cmake_dir=CMAKE_DIR,
|
||||
cwd=ifcos_build_dir,
|
||||
)
|
||||
finally:
|
||||
os.environ["LDFLAGS"] = old_ldflags
|
||||
|
||||
logger.info(f"\rBuilding python {python_version} wrapper... ")
|
||||
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "ifcopenshell_wrapper", "VERBOSE=1"], cwd=python_dir)
|
||||
run([make, "install/local"], cwd=os.path.join(python_dir, "ifcwrap"))
|
||||
run([make, f"-j{IFCOS_NUM_BUILD_PROCS}", "ifcopenshell_wrapper", "VERBOSE=1"], cwd=ifcos_build_dir)
|
||||
run([make, "install/local"], cwd=os.path.join(ifcos_build_dir, "ifcwrap"))
|
||||
|
||||
if python_executable:
|
||||
run([python_executable, "-m", "ensurepip"])
|
||||
|
||||
@@ -316,7 +316,7 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
Returns:
|
||||
The BCF viewpoint definition.
|
||||
"""
|
||||
ifc_file = element.wrapped_data.file
|
||||
ifc_file = element.file
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
elem_placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
elem_placement[:3, 3] *= unit_scale
|
||||
|
||||
@@ -316,7 +316,7 @@ def build_viewpoint(element: entity_instance) -> mdl.VisualizationInfo:
|
||||
Returns:
|
||||
The BCF viewpoint definition.
|
||||
"""
|
||||
ifc_file = element.wrapped_data.file
|
||||
ifc_file = element.file
|
||||
unit_scale = ifcopenshell.util.unit.calculate_unit_scale(ifc_file)
|
||||
elem_placement = ifcopenshell.util.placement.get_local_placement(element.ObjectPlacement)
|
||||
elem_placement[:3, 3] *= unit_scale
|
||||
|
||||
@@ -187,7 +187,7 @@ def import_attributes(
|
||||
info = {a.name(): None for a in attributes}
|
||||
info["type"] = element
|
||||
else:
|
||||
assert (entity := element.wrapped_data.declaration().as_entity())
|
||||
assert (entity := element.declaration().as_entity())
|
||||
attributes = entity.all_attributes()
|
||||
info = element.get_info()
|
||||
for attribute in attributes:
|
||||
|
||||
@@ -206,7 +206,7 @@ class CostSchedulesData:
|
||||
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
|
||||
if quantity.is_a("IfcPhysicalSimpleQuantity"):
|
||||
measure_class = (
|
||||
quantity.wrapped_data.declaration()
|
||||
quantity.declaration()
|
||||
.as_entity()
|
||||
.attribute_by_index(3)
|
||||
.type_of_attribute()
|
||||
|
||||
@@ -90,7 +90,7 @@ class PrintIfcFile(bpy.types.Operator):
|
||||
return tool.Ifc.get()
|
||||
|
||||
def execute(self, context):
|
||||
print(tool.Ifc.get().wrapped_data.to_string())
|
||||
print(tool.Ifc.get().to_string())
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
|
||||
@@ -790,7 +790,7 @@ def lock_error_message(name: str) -> str:
|
||||
|
||||
|
||||
def calc_delete_is_batch(ifc_file: ifcopenshell.file, context: bpy.types.Context) -> bool:
|
||||
total_elements = len(tool.Ifc.get().wrapped_data.entity_names())
|
||||
total_elements = len(tool.Ifc.get().entity_names())
|
||||
total_polygons = sum([len(o.data.polygons) for o in context.selected_objects if o.type == "MESH"])
|
||||
# These numbers are a bit arbitrary, but basically batching is only
|
||||
# really necessary on large models and large geometry removals.
|
||||
|
||||
@@ -95,7 +95,7 @@ class ColourByPropertyData:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return default
|
||||
keys = [a.name() for a in element.wrapped_data.declaration().as_entity().all_attributes()]
|
||||
keys = [a.name() for a in element.declaration().as_entity().all_attributes()]
|
||||
psets = ifcopenshell.util.element.get_psets(element)
|
||||
for pset, properties in psets.items():
|
||||
if pset.endswith("Common"):
|
||||
@@ -126,7 +126,7 @@ class SelectSimilarData:
|
||||
element = tool.Ifc.get_entity(obj)
|
||||
if not element:
|
||||
return []
|
||||
keys = [a.name() for a in element.wrapped_data.declaration().as_entity().all_attributes()]
|
||||
keys = [a.name() for a in element.declaration().as_entity().all_attributes()]
|
||||
psets = ifcopenshell.util.element.get_psets(element, psets_only=True)
|
||||
for pset, properties in psets.items():
|
||||
if pset.endswith("Common"):
|
||||
|
||||
@@ -1809,7 +1809,7 @@ class Geometry(bonsai.core.tool.Geometry):
|
||||
item = tool.Ifc.get().by_id(props.ifc_definition_id)
|
||||
allowed_attributes = [
|
||||
a.name()
|
||||
for a in item.wrapped_data.declaration().as_entity().all_attributes()
|
||||
for a in item.declaration().as_entity().all_attributes()
|
||||
if a.type_of_attribute()._is("IfcLengthMeasure")
|
||||
]
|
||||
|
||||
|
||||
@@ -39,12 +39,11 @@
|
||||
#include <Standard_Version.hxx>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/macros.h"
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcBaseClass.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
#include "ifcgeom/Serialization/Serialization.h"
|
||||
#include "../ifcgeom/Serialization/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
@@ -57,18 +56,18 @@ void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// The hierarchy_helper is a subclass of the regular file that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname("IfcAdvancedHouse.ifc");
|
||||
hierarchy_helper<IfcSchema> file;
|
||||
file.header().file_name().setname("IfcAdvancedHouse.ifc");
|
||||
|
||||
IfcSchema::IfcBuilding* building = file.addBuilding();
|
||||
auto building = file.addBuilding();
|
||||
// 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
|
||||
// project, which has been created automatically.
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcAdvancedHouse"s);
|
||||
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
|
||||
@@ -91,13 +90,13 @@ int main() {
|
||||
// IfcFacetedBRep. If it would not be a polyhedron, serialise() can only be successful when linked
|
||||
// to the IFC4 model and with `advanced` set to `true` which introduces IfcAdvancedFace. It would
|
||||
// return `0` otherwise.
|
||||
IfcSchema::IfcProductDefinitionShape* building_shape = IfcGeom::serialise(STRINGIFY(IfcSchema), building_shell, false)->as<IfcSchema::IfcProductDefinitionShape>();
|
||||
auto building_shape = IfcGeom::serialise(file, building_shell, false).as<IfcSchema::IfcProductDefinitionShape>();
|
||||
|
||||
file.addEntity(building_shape);
|
||||
IfcSchema::IfcRepresentation* rep = *building_shape->Representations()->begin();
|
||||
file.add_entity(building_shape);
|
||||
auto rep = building_shape.Representations().begin();
|
||||
rep->setContextOfItems(file.getRepresentationContext("model"));
|
||||
|
||||
building->setRepresentation(building_shape);
|
||||
building.setRepresentation(building_shape);
|
||||
|
||||
// A pale white colour is assigned to the building.
|
||||
setSurfaceColour(file, building_shape, 0.75, 0.73, 0.68);
|
||||
@@ -107,18 +106,18 @@ int main() {
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
|
||||
auto ground_representation = IfcGeom::serialise(STRINGIFY(IfcSchema), shape, true);
|
||||
auto ground_representation = IfcGeom::serialise(file, shape, true);
|
||||
if (!ground_representation) {
|
||||
ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.);
|
||||
ground_representation = IfcGeom::tesselate(file, shape, 100.);
|
||||
}
|
||||
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation->as<IfcSchema::IfcProductDefinitionShape>());
|
||||
file.getSingle<IfcSchema::IfcSite>().setRepresentation(ground_representation.as<IfcSchema::IfcProductDefinitionShape>());
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
|
||||
auto ground_reps = file.getSingle<IfcSchema::IfcSite>().Representation().Representations();
|
||||
for (auto& rep : ground_reps) {
|
||||
rep.setContextOfItems(file.getRepresentationContext("Model"));
|
||||
}
|
||||
file.addEntity(ground_representation);
|
||||
setSurfaceColour(file, ground_representation->as<IfcSchema::IfcProductDefinitionShape>(), 0.15, 0.25, 0.05);
|
||||
file.add_entity(ground_representation);
|
||||
setSurfaceColour(file, ground_representation.as<IfcSchema::IfcProductDefinitionShape>(), 0.15, 0.25, 0.05);
|
||||
|
||||
/*
|
||||
// Note that IFC lacks elementary surfaces that STEP does have, such as spherical_surface.
|
||||
|
||||
+299
-210
@@ -30,8 +30,8 @@
|
||||
// Disable warnings coming from IfcOpenShell
|
||||
#pragma warning(disable : 4018 4267 4250 4984 4985)
|
||||
|
||||
#include "ifcparse/Ifc4x3_add2.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/Ifc4x3_add2.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <fstream>
|
||||
@@ -43,37 +43,49 @@ double to_radian(double deg) { return PI * deg / 180; }
|
||||
|
||||
// performs basic project setup including created the IfcProject object
|
||||
// and initializing the project units to FEET
|
||||
Schema::IfcProject* setup_project(IfcHierarchyHelper<Schema>& file) {
|
||||
Schema::IfcProject setup_project(hierarchy_helper<Schema>& file) {
|
||||
std::vector<std::string> file_description;
|
||||
file_description.push_back("ViewDefinition[Alignment-basedReferenceView]");
|
||||
file.header().file_description()->setdescription(file_description);
|
||||
file.header().file_description().setdescription(file_description);
|
||||
|
||||
auto project = file.addProject();
|
||||
project->setName(std::string("FHWA Bridge Geometry Manual Example Alignment"));
|
||||
project->setDescription(std::string("C++ Example"));
|
||||
project.setName("FHWA Bridge Geometry Manual Example Alignment");
|
||||
project.setDescription("C++ Example");
|
||||
|
||||
// set up project units for feet
|
||||
// the call to file.addProject() sets up length units as millimeter.
|
||||
auto units_in_context = project->UnitsInContext();
|
||||
auto units = units_in_context->Units();
|
||||
auto begin = units->begin();
|
||||
auto units_in_context = project.UnitsInContext();
|
||||
auto units = units_in_context.Units();
|
||||
auto begin = units.begin();
|
||||
auto iter = begin;
|
||||
auto end = units->end();
|
||||
auto end = units.end();
|
||||
for (; iter != end; iter++) {
|
||||
auto unit = *iter;
|
||||
if (unit->as<Schema::IfcSIUnit>() && unit->as<Schema::IfcSIUnit>()->UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) {
|
||||
auto dimensions = new Schema::IfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0);
|
||||
file.addEntity(dimensions);
|
||||
auto& unit = *iter;
|
||||
if (unit.as<Schema::IfcSIUnit>() && unit.as<Schema::IfcSIUnit>().UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) {
|
||||
auto dimensions = file.create<Schema::IfcDimensionalExponents>();
|
||||
dimensions.setLengthExponent(1);
|
||||
dimensions.setMassExponent(0);
|
||||
dimensions.setTimeExponent(0);
|
||||
dimensions.setElectricCurrentExponent(0);
|
||||
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);
|
||||
conversion_factor.setValueComponent(length);
|
||||
conversion_factor.setUnitComponent(unit);
|
||||
|
||||
auto conversion_factor = new Schema::IfcMeasureWithUnit(new Schema::IfcLengthMeasure(304.80), unit->as<Schema::IfcSIUnit>());
|
||||
file.addEntity(conversion_factor);
|
||||
|
||||
auto conversion_based_unit = new Schema::IfcConversionBasedUnit(dimensions, Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT, "FEET", conversion_factor);
|
||||
file.addEntity(conversion_based_unit);
|
||||
|
||||
units->remove(unit); // remove the millimeter unit
|
||||
units->push(conversion_based_unit); // add the feet unit
|
||||
units_in_context->setUnits(units); // update the UnitsInContext
|
||||
auto conversion_based_unit = file.create<Schema::IfcConversionBasedUnit>();
|
||||
conversion_based_unit.setDimensions(dimensions);
|
||||
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
|
||||
|
||||
break; // Done!, the length unit was found, so break out of the loop
|
||||
}
|
||||
@@ -83,135 +95,198 @@ Schema::IfcProject* setup_project(IfcHierarchyHelper<Schema>& file) {
|
||||
}
|
||||
|
||||
// creates geometry and business logic segments for horizontal alignment tangent runs
|
||||
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_tangent(typename Schema::IfcCartesianPoint* p, double dir, double length) {
|
||||
std::pair<typename Schema::IfcCurveSegment, typename Schema::IfcAlignmentSegment> create_tangent(hierarchy_helper<Schema>& file, const typename Schema::IfcCartesianPoint& p, double dir, double length) {
|
||||
// geometry
|
||||
auto parent_curve = new Schema::IfcLine(
|
||||
new Schema::IfcCartesianPoint(std::vector<double>({0, 0})),
|
||||
new Schema::IfcVector(new Schema::IfcDirection(std::vector<double>{1.0, 0.0}), 1.0));
|
||||
auto parent_curve = file.create<Schema::IfcLine>();
|
||||
parent_curve.setPnt(file.addDoublet<Schema::IfcCartesianPoint>(0.0, 0.0));
|
||||
auto vec = file.create<Schema::IfcVector>();
|
||||
vec.setOrientation(file.addDoublet<Schema::IfcDirection>(1.0, 0.0));
|
||||
vec.setMagnitude(1.0);
|
||||
parent_curve.setDir(vec);
|
||||
|
||||
auto curve_segment = new Schema::IfcCurveSegment(
|
||||
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
|
||||
new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{cos(dir), sin(dir)})),
|
||||
new Schema::IfcLengthMeasure(0.0), // start
|
||||
new Schema::IfcLengthMeasure(length),
|
||||
parent_curve);
|
||||
auto place = file.create<Schema::IfcAxis2Placement2D>();
|
||||
place.setLocation(p);
|
||||
place.setRefDirection(file.addDoublet<Schema::IfcDirection>(cos(dir), sin(dir)));
|
||||
|
||||
auto curve_segment = file.create<Schema::IfcCurveSegment>();
|
||||
curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT);
|
||||
curve_segment.setPlacement(place);
|
||||
curve_segment.setSegmentStart(file.addValue<Schema::IfcLengthMeasure>(0.0));
|
||||
curve_segment.setSegmentLength(file.addValue<Schema::IfcLengthMeasure>(length));
|
||||
curve_segment.setParentCurve(parent_curve);
|
||||
|
||||
// business logic
|
||||
auto design_parameters = new Schema::IfcAlignmentHorizontalSegment(
|
||||
boost::none, boost::none, p, dir, 0.0, 0.0, length, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE);
|
||||
auto design_parameters = file.create<Schema::IfcAlignmentHorizontalSegment>();
|
||||
design_parameters.setStartPoint(p);
|
||||
design_parameters.setStartDirection(dir);
|
||||
design_parameters.setStartRadiusOfCurvature(0.0);
|
||||
design_parameters.setEndRadiusOfCurvature(0.0);
|
||||
design_parameters.setSegmentLength(length);
|
||||
design_parameters.setPredefinedType(Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_LINE);
|
||||
|
||||
auto alignment_segment = new Schema::IfcAlignmentSegment(
|
||||
IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters);
|
||||
auto alignment_segment = file.create<Schema::IfcAlignmentSegment>();
|
||||
alignment_segment.setGlobalId(ifcopenshell::global_id());
|
||||
alignment_segment.setDesignParameters(design_parameters);
|
||||
|
||||
return {curve_segment, alignment_segment};
|
||||
}
|
||||
|
||||
// creates geometry and business logic segments for horizontal alignment horizonal curves
|
||||
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_hcurve(typename Schema::IfcCartesianPoint* pc, double dir, double radius, double lc) {
|
||||
std::pair<typename Schema::IfcCurveSegment, typename Schema::IfcAlignmentSegment> create_hcurve(hierarchy_helper<Schema>& file, const typename Schema::IfcCartesianPoint& pc, double dir, double radius, double lc) {
|
||||
// geometry
|
||||
double sign = radius / fabs(radius);
|
||||
auto parent_curve = new Schema::IfcCircle(
|
||||
new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector<double>({0, 0})), new Schema::IfcDirection(std::vector<double>{1, 0})),
|
||||
fabs(radius));
|
||||
auto place = file.create<Schema::IfcAxis2Placement2D>();
|
||||
place.setLocation(file.addDoublet<Schema::IfcCartesianPoint>(0.0, 0.0));
|
||||
place.setRefDirection(file.addDoublet<Schema::IfcDirection>(1.0, 0.0));
|
||||
auto parent_curve = file.create<Schema::IfcCircle>();
|
||||
parent_curve.setPosition(place);
|
||||
parent_curve.setRadius(fabs(radius));
|
||||
|
||||
auto curve_segment = new Schema::IfcCurveSegment(
|
||||
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
|
||||
new Schema::IfcAxis2Placement2D(pc, new Schema::IfcDirection(std::vector<double>{cos(dir), sin(dir)})),
|
||||
new Schema::IfcLengthMeasure(0.0),
|
||||
new Schema::IfcLengthMeasure(sign * lc),
|
||||
parent_curve);
|
||||
auto place2 = file.create<Schema::IfcAxis2Placement2D>();
|
||||
place2.setLocation(pc);
|
||||
place2.setRefDirection(file.addDoublet<Schema::IfcDirection>(cos(dir), sin(dir)));
|
||||
|
||||
auto curve_segment = file.create<Schema::IfcCurveSegment>();
|
||||
curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT);
|
||||
curve_segment.setPlacement(place2);
|
||||
curve_segment.setSegmentStart(file.addValue<Schema::IfcLengthMeasure>(0.0));
|
||||
curve_segment.setSegmentLength(file.addValue<Schema::IfcLengthMeasure>(sign * lc));
|
||||
curve_segment.setParentCurve(parent_curve);
|
||||
|
||||
// business logic
|
||||
auto design_parameters = new Schema::IfcAlignmentHorizontalSegment(boost::none, boost::none, pc, dir, radius, radius, lc, boost::none, Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_CIRCULARARC);
|
||||
auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters);
|
||||
auto design_parameters = file.create<Schema::IfcAlignmentHorizontalSegment>();
|
||||
design_parameters.setStartPoint(pc);
|
||||
design_parameters.setStartDirection(dir);
|
||||
design_parameters.setStartRadiusOfCurvature(radius);
|
||||
design_parameters.setEndRadiusOfCurvature(radius);
|
||||
design_parameters.setSegmentLength(lc);
|
||||
design_parameters.setPredefinedType(Schema::IfcAlignmentHorizontalSegmentTypeEnum::IfcAlignmentHorizontalSegmentType_CIRCULARARC);
|
||||
|
||||
auto alignment_segment = file.create<Schema::IfcAlignmentSegment>();
|
||||
alignment_segment.setGlobalId(ifcopenshell::global_id());
|
||||
alignment_segment.setDesignParameters(design_parameters);
|
||||
|
||||
return {curve_segment, alignment_segment};
|
||||
}
|
||||
|
||||
// creates geometry and business logic segments for vertical profile gradient runs
|
||||
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_gradient(typename Schema::IfcCartesianPoint* p, double slope, double length) {
|
||||
std::pair<typename Schema::IfcCurveSegment, typename Schema::IfcAlignmentSegment> create_gradient(hierarchy_helper<Schema>& file, const typename Schema::IfcCartesianPoint& p, double slope, double length) {
|
||||
// geometry
|
||||
auto parent_curve = new Schema::IfcLine(
|
||||
new Schema::IfcCartesianPoint(std::vector<double>({0, 0})),
|
||||
new Schema::IfcVector(new Schema::IfcDirection(std::vector<double>{1, 0}), 1.0));
|
||||
auto parent_curve = file.create<Schema::IfcLine>();
|
||||
parent_curve.setPnt(file.addDoublet<Schema::IfcCartesianPoint>(0.0, 0.0));
|
||||
auto vec = file.create<Schema::IfcVector>();
|
||||
vec.setOrientation(file.addDoublet<Schema::IfcDirection>(1.0, 0.0));
|
||||
vec.setMagnitude(1.0);
|
||||
parent_curve.setDir(vec);
|
||||
|
||||
auto curve_segment = new Schema::IfcCurveSegment(
|
||||
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
|
||||
new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{sqrt(1 - slope * slope), slope})),
|
||||
new Schema::IfcLengthMeasure(0.0), // start
|
||||
new Schema::IfcLengthMeasure(length),
|
||||
parent_curve);
|
||||
auto place2 = file.create<Schema::IfcAxis2Placement2D>();
|
||||
place2.setLocation(p);
|
||||
place2.setRefDirection(file.addDoublet<Schema::IfcDirection>(sqrt(1 - slope * slope), slope));
|
||||
|
||||
auto curve_segment = file.create<Schema::IfcCurveSegment>();
|
||||
curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT);
|
||||
curve_segment.setPlacement(place2);
|
||||
curve_segment.setSegmentStart(file.addValue<Schema::IfcLengthMeasure>(0.0));
|
||||
curve_segment.setSegmentLength(file.addValue<Schema::IfcLengthMeasure>(length));
|
||||
curve_segment.setParentCurve(parent_curve);
|
||||
|
||||
// business logic
|
||||
auto design_parameters = new Schema::IfcAlignmentVerticalSegment(boost::none, boost::none, p->Coordinates()[0], length, p->Coordinates()[1], slope, slope, boost::none, Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_CONSTANTGRADIENT);
|
||||
auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters);
|
||||
auto design_parameters = file.create<Schema::IfcAlignmentVerticalSegment>();
|
||||
design_parameters.setStartDistAlong(p.Coordinates()[0]);
|
||||
design_parameters.setHorizontalLength(length);
|
||||
design_parameters.setStartHeight(p.Coordinates()[1]);
|
||||
design_parameters.setStartGradient(slope);
|
||||
design_parameters.setEndGradient(slope);
|
||||
design_parameters.setPredefinedType(Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_CONSTANTGRADIENT);
|
||||
|
||||
auto alignment_segment = file.create<Schema::IfcAlignmentSegment>();
|
||||
alignment_segment.setGlobalId(ifcopenshell::global_id());
|
||||
alignment_segment.setDesignParameters(design_parameters);
|
||||
|
||||
return {curve_segment, alignment_segment};
|
||||
}
|
||||
|
||||
// creates geometry and business logic segments for vertical profile parabolic vertical curves
|
||||
std::pair<typename Schema::IfcCurveSegment*, typename Schema::IfcAlignmentSegment*> create_vcurve(typename Schema::IfcCartesianPoint* p, double start_slope, double end_slope, double length) {
|
||||
std::pair<typename Schema::IfcCurveSegment, typename Schema::IfcAlignmentSegment> create_vcurve(hierarchy_helper<Schema>& file, const typename Schema::IfcCartesianPoint& p, double start_slope, double end_slope, double length) {
|
||||
// geometry
|
||||
double A = p->Coordinates()[1];
|
||||
double A = p.Coordinates()[1];
|
||||
double B = start_slope;
|
||||
double C = (end_slope - start_slope) / (2 * length);
|
||||
|
||||
auto parent_curve = new Schema::IfcPolynomialCurve(
|
||||
new Schema::IfcAxis2Placement2D(new Schema::IfcCartesianPoint(std::vector<double>{0.0, 0.0}), new Schema::IfcDirection(std::vector<double>{1.0, 0.0})),
|
||||
std::vector<double>{0.0, 1.0},
|
||||
std::vector<double>{A, B, C},
|
||||
boost::none);
|
||||
auto place = file.create<Schema::IfcAxis2Placement2D>();
|
||||
place.setLocation(file.addDoublet<Schema::IfcCartesianPoint>(0.0, 0.0));
|
||||
place.setRefDirection(file.addDoublet<Schema::IfcDirection>(1.0, 0.0));
|
||||
|
||||
auto curve_segment = new Schema::IfcCurveSegment(
|
||||
Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT,
|
||||
new Schema::IfcAxis2Placement2D(p, new Schema::IfcDirection(std::vector<double>{sqrt(1 - start_slope * start_slope), start_slope})),
|
||||
new Schema::IfcLengthMeasure(0.0),
|
||||
new Schema::IfcLengthMeasure(length),
|
||||
parent_curve);
|
||||
auto parent_curve = file.create<Schema::IfcPolynomialCurve>();
|
||||
parent_curve.setPosition(place);
|
||||
parent_curve.setCoefficientsX(std::vector<double>{0.0, 1.0});
|
||||
parent_curve.setCoefficientsY(std::vector<double>{A, B, C});
|
||||
|
||||
auto place2 = file.create<Schema::IfcAxis2Placement2D>();
|
||||
place2.setLocation(p);
|
||||
place2.setRefDirection(file.addDoublet<Schema::IfcDirection>(sqrt(1 - start_slope * start_slope), start_slope));
|
||||
|
||||
auto curve_segment = file.create<Schema::IfcCurveSegment>();
|
||||
curve_segment.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT);
|
||||
curve_segment.setPlacement(place2);
|
||||
curve_segment.setSegmentStart(file.addValue<Schema::IfcLengthMeasure>(0.0));
|
||||
curve_segment.setSegmentLength(file.addValue<Schema::IfcLengthMeasure>(length));
|
||||
curve_segment.setParentCurve(parent_curve);
|
||||
|
||||
// business logic
|
||||
double k = (end_slope - start_slope) / length;
|
||||
auto design_parameters = new Schema::IfcAlignmentVerticalSegment(boost::none, boost::none, p->Coordinates()[0], length, p->Coordinates()[1], start_slope, end_slope, 1 / k, Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_PARABOLICARC);
|
||||
auto alignment_segment = new Schema::IfcAlignmentSegment(IfcParse::IfcGlobalId(), nullptr, boost::none, boost::none, boost::none, nullptr, nullptr, design_parameters);
|
||||
|
||||
auto design_parameters = file.create<Schema::IfcAlignmentVerticalSegment>();
|
||||
design_parameters.setStartDistAlong(p.Coordinates()[0]);
|
||||
design_parameters.setHorizontalLength(length);
|
||||
design_parameters.setStartHeight(p.Coordinates()[1]);
|
||||
design_parameters.setStartGradient(start_slope);
|
||||
design_parameters.setEndGradient(end_slope);
|
||||
design_parameters.setRadiusOfCurvature(1 / k);
|
||||
design_parameters.setPredefinedType(Schema::IfcAlignmentVerticalSegmentTypeEnum::IfcAlignmentVerticalSegmentType_PARABOLICARC);
|
||||
|
||||
auto alignment_segment = file.create<Schema::IfcAlignmentSegment>();
|
||||
alignment_segment.setGlobalId(ifcopenshell::global_id());
|
||||
alignment_segment.setDesignParameters(design_parameters);
|
||||
|
||||
return {curve_segment, alignment_segment};
|
||||
}
|
||||
|
||||
// creates representations for each IfcAlignmentSegment per CT 4.1.7.1.1.4
|
||||
// https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Product_Shape/Product_Geometric_Representation/Alignment_Geometry/Alignment_Geometry_-_Segments/content.html
|
||||
void create_segment_representations(IfcHierarchyHelper<Schema>& file, Schema::IfcLocalPlacement* global_placement, Schema::IfcGeometricRepresentationSubContext* segment_axis_subcontext, typename aggregate_of<typename Schema::IfcSegment>::ptr curve_segments, typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr segments) {
|
||||
auto cs_iter = curve_segments->begin();
|
||||
auto s_iter = segments->begin();
|
||||
for (; cs_iter != curve_segments->end(); cs_iter++, s_iter++) {
|
||||
auto curve_segment = *cs_iter;
|
||||
auto alignment_segment = (*s_iter)->as<Schema::IfcAlignmentSegment>();
|
||||
void create_segment_representations(hierarchy_helper<Schema>& file, const Schema::IfcLocalPlacement& global_placement, const Schema::IfcGeometricRepresentationSubContext& segment_axis_subcontext, std::vector<Schema::IfcSegment>& curve_segments, std::vector<Schema::IfcObjectDefinition>& segments) {
|
||||
auto cs_iter = curve_segments.begin();
|
||||
auto s_iter = segments.begin();
|
||||
for (; cs_iter != curve_segments.end(); cs_iter++, s_iter++) {
|
||||
auto& curve_segment = *cs_iter;
|
||||
auto alignment_segment = (*s_iter).as<Schema::IfcAlignmentSegment>();
|
||||
|
||||
typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
|
||||
representation_items->push(curve_segment);
|
||||
auto axis_representation = file.create<Schema::IfcShapeRepresentation>();
|
||||
axis_representation.setContextOfItems(segment_axis_subcontext);
|
||||
axis_representation.setRepresentationIdentifier("Axis");
|
||||
axis_representation.setRepresentationType("Segment");
|
||||
axis_representation.setItems({curve_segment});
|
||||
|
||||
auto axis_representation = new Schema::IfcShapeRepresentation(segment_axis_subcontext, std::string("Axis"), std::string("Segment"), representation_items);
|
||||
file.addEntity(axis_representation);
|
||||
auto product = file.create<Schema::IfcProductDefinitionShape>();
|
||||
product.setRepresentations({axis_representation});
|
||||
|
||||
typename aggregate_of<typename Schema::IfcRepresentation>::ptr representations(new aggregate_of<typename Schema::IfcRepresentation>());
|
||||
representations->push(axis_representation);
|
||||
|
||||
auto product = new Schema::IfcProductDefinitionShape(boost::none, boost::none, representations);
|
||||
file.addEntity(product);
|
||||
|
||||
alignment_segment->setObjectPlacement(global_placement);
|
||||
alignment_segment->setRepresentation(product);
|
||||
alignment_segment.setObjectPlacement(global_placement);
|
||||
alignment_segment.setRepresentation(product);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
IfcHierarchyHelper<Schema> file;
|
||||
hierarchy_helper<Schema> file;
|
||||
|
||||
auto project = setup_project(file);
|
||||
|
||||
auto geometric_representation_context = file.getRepresentationContext(std::string("Model")); // creates the representation context if it doesn't already exist
|
||||
|
||||
auto axis_model_representation_subcontext = new Schema::IfcGeometricRepresentationSubContext(std::string("Axis"), std::string("Model"), geometric_representation_context, boost::none, Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_MODEL_VIEW, boost::none);
|
||||
file.addEntity(axis_model_representation_subcontext);
|
||||
auto axis_model_representation_subcontext = file.create<Schema::IfcGeometricRepresentationSubContext>();
|
||||
axis_model_representation_subcontext.setContextIdentifier("Axis");
|
||||
axis_model_representation_subcontext.setContextType("Model");
|
||||
axis_model_representation_subcontext.setParentContext(geometric_representation_context);
|
||||
axis_model_representation_subcontext.setTargetView(Schema::IfcGeometricProjectionEnum::IfcGeometricProjection_MODEL_VIEW);
|
||||
|
||||
auto global_placement = file.addLocalPlacement();
|
||||
|
||||
@@ -251,86 +326,91 @@ int main() {
|
||||
double angle_4 = to_radian(289.0395);
|
||||
|
||||
// create containers to store the curve segments
|
||||
typename aggregate_of<typename Schema::IfcSegment>::ptr horizontal_curve_segments(new aggregate_of<typename Schema::IfcSegment>()); // geometry
|
||||
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr horizontal_segments(new aggregate_of<typename Schema::IfcObjectDefinition>()); // business logic
|
||||
std::vector<Schema::IfcSegment> horizontal_curve_segments; // geometry
|
||||
std::vector<Schema::IfcObjectDefinition> horizontal_segments; // business logic
|
||||
|
||||
//
|
||||
// Build the horizontal alignment segments
|
||||
//
|
||||
|
||||
// POB to PC1
|
||||
auto curve_segment_1 = create_tangent(pob, angle_1, run_1);
|
||||
horizontal_curve_segments->push(curve_segment_1.first);
|
||||
horizontal_segments->push(curve_segment_1.second);
|
||||
auto curve_segment_1 = create_tangent(file, pob, angle_1, run_1);
|
||||
horizontal_curve_segments.push_back(curve_segment_1.first);
|
||||
horizontal_segments.push_back(curve_segment_1.second);
|
||||
|
||||
// Curve 1
|
||||
auto curve_segment_2 = create_hcurve(pc1, angle_1, rc_1, lc_1);
|
||||
horizontal_curve_segments->push(curve_segment_2.first);
|
||||
horizontal_segments->push(curve_segment_2.second);
|
||||
auto curve_segment_2 = create_hcurve(file, pc1, angle_1, rc_1, lc_1);
|
||||
horizontal_curve_segments.push_back(curve_segment_2.first);
|
||||
horizontal_segments.push_back(curve_segment_2.second);
|
||||
|
||||
// PT1 to PC2
|
||||
auto curve_segment_3 = create_tangent(pt1, angle_2, run_2);
|
||||
horizontal_curve_segments->push(curve_segment_3.first);
|
||||
horizontal_segments->push(curve_segment_3.second);
|
||||
auto curve_segment_3 = create_tangent(file, pt1, angle_2, run_2);
|
||||
horizontal_curve_segments.push_back(curve_segment_3.first);
|
||||
horizontal_segments.push_back(curve_segment_3.second);
|
||||
|
||||
// Curve 2
|
||||
auto curve_segment_4 = create_hcurve(pc2, angle_2, rc_2, lc_2);
|
||||
horizontal_curve_segments->push(curve_segment_4.first);
|
||||
horizontal_segments->push(curve_segment_4.second);
|
||||
auto curve_segment_4 = create_hcurve(file, pc2, angle_2, rc_2, lc_2);
|
||||
horizontal_curve_segments.push_back(curve_segment_4.first);
|
||||
horizontal_segments.push_back(curve_segment_4.second);
|
||||
|
||||
// PT2 to PC3
|
||||
auto curve_segment_5 = create_tangent(pt2, angle_3, run_3);
|
||||
horizontal_curve_segments->push(curve_segment_5.first);
|
||||
horizontal_segments->push(curve_segment_5.second);
|
||||
auto curve_segment_5 = create_tangent(file, pt2, angle_3, run_3);
|
||||
horizontal_curve_segments.push_back(curve_segment_5.first);
|
||||
horizontal_segments.push_back(curve_segment_5.second);
|
||||
|
||||
// Curve 3
|
||||
auto curve_segment_6 = create_hcurve(pc3, angle_3, rc_3, lc_3);
|
||||
horizontal_curve_segments->push(curve_segment_6.first);
|
||||
horizontal_segments->push(curve_segment_6.second);
|
||||
auto curve_segment_6 = create_hcurve(file, pc3, angle_3, rc_3, lc_3);
|
||||
horizontal_curve_segments.push_back(curve_segment_6.first);
|
||||
horizontal_segments.push_back(curve_segment_6.second);
|
||||
|
||||
// PT3 to POE
|
||||
auto curve_segment_7 = create_tangent(pt3, angle_4, run_4);
|
||||
horizontal_curve_segments->push(curve_segment_7.first);
|
||||
horizontal_segments->push(curve_segment_7.second);
|
||||
auto curve_segment_7 = create_tangent(file, pt3, angle_4, run_4);
|
||||
horizontal_curve_segments.push_back(curve_segment_7.first);
|
||||
horizontal_segments.push_back(curve_segment_7.second);
|
||||
|
||||
// Zero-length terminator segment
|
||||
auto terminator_segment = create_tangent(poe, angle_4, 0.0);
|
||||
terminator_segment.first->setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS);
|
||||
horizontal_curve_segments->push(terminator_segment.first);
|
||||
horizontal_segments->push(terminator_segment.second);
|
||||
auto terminator_segment = create_tangent(file, poe, angle_4, 0.0);
|
||||
terminator_segment.first.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS);
|
||||
horizontal_curve_segments.push_back(terminator_segment.first);
|
||||
horizontal_segments.push_back(terminator_segment.second);
|
||||
|
||||
//
|
||||
// Create the horizontal alignment (IfcAlignmentHorizontal) and nest alignment segments
|
||||
//
|
||||
auto horizontal_alignment = new Schema::IfcAlignmentHorizontal(IfcParse::IfcGlobalId(), nullptr, std::string("Horizontal Alignment"), boost::none, boost::none, nullptr, nullptr);
|
||||
file.addEntity(horizontal_alignment);
|
||||
|
||||
auto nests_horizontal_segments = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, boost::none, std::string("Nests horizontal alignment segments with horizontal alignment"), horizontal_alignment, horizontal_segments);
|
||||
file.addEntity(nests_horizontal_segments);
|
||||
auto horizontal_alignment = file.create<Schema::IfcAlignmentHorizontal>();
|
||||
horizontal_alignment.setGlobalId(ifcopenshell::global_id());
|
||||
horizontal_alignment.setName("Example Alignment");
|
||||
|
||||
auto nests_horizontal_segments = file.create<Schema::IfcRelNests>();
|
||||
nests_horizontal_segments.setGlobalId(ifcopenshell::global_id());
|
||||
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
|
||||
//
|
||||
|
||||
// start by defining a composite curve composed of the horizonal curve segments
|
||||
auto composite_curve = new Schema::IfcCompositeCurve(horizontal_curve_segments, false /*not self-intersecting*/);
|
||||
file.addEntity(composite_curve);
|
||||
|
||||
// the composite curve is a representation item
|
||||
typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr alignment_representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
|
||||
alignment_representation_items->push(composite_curve);
|
||||
auto composite_curve = file.create<Schema::IfcCompositeCurve>();
|
||||
composite_curve.setSegments(horizontal_curve_segments);
|
||||
composite_curve.setSelfIntersect(false);
|
||||
|
||||
// create the footprint representation
|
||||
auto footprint_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("FootPrint"), std::string("Curve2D"), alignment_representation_items);
|
||||
file.addEntity(footprint_shape_representation);
|
||||
|
||||
auto footprint_shape_representation = file.create<Schema::IfcShapeRepresentation>();
|
||||
footprint_shape_representation.setContextOfItems(axis_model_representation_subcontext);
|
||||
footprint_shape_representation.setRepresentationIdentifier("Footprint");
|
||||
footprint_shape_representation.setRepresentationType("Curve2D");
|
||||
// the composite curve is a representation item
|
||||
footprint_shape_representation.setItems({composite_curve});
|
||||
|
||||
//
|
||||
// Define vertical profile segments
|
||||
//
|
||||
|
||||
// create containers to store the curve segments
|
||||
typename aggregate_of<typename Schema::IfcSegment>::ptr vertical_curve_segments(new aggregate_of<typename Schema::IfcSegment>()); // geometry
|
||||
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr vertical_segments(new aggregate_of<typename Schema::IfcObjectDefinition>()); // business logic
|
||||
std::vector<Schema::IfcSegment> vertical_curve_segments; // geometry
|
||||
std::vector<Schema::IfcObjectDefinition> vertical_segments; // business logic
|
||||
|
||||
// define key profile points
|
||||
auto vpob = file.addDoublet<Schema::IfcCartesianPoint>(0.0, 100.0); // beginning
|
||||
@@ -349,80 +429,86 @@ int main() {
|
||||
//
|
||||
|
||||
// Grade start to VPC1
|
||||
auto vertical_profile_segment_1 = create_gradient(vpob, 1.75 / 100, 1200);
|
||||
vertical_curve_segments->push(vertical_profile_segment_1.first);
|
||||
vertical_segments->push(vertical_profile_segment_1.second);
|
||||
auto vertical_profile_segment_1 = create_gradient(file, vpob, 1.75 / 100, 1200);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_1.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_1.second);
|
||||
|
||||
// Vertical Curve 1
|
||||
auto vertical_profile_segment_2 = create_vcurve(vpc1, 1.75 / 100, -1.0 / 100, 1600);
|
||||
vertical_curve_segments->push(vertical_profile_segment_2.first);
|
||||
vertical_segments->push(vertical_profile_segment_2.second);
|
||||
auto vertical_profile_segment_2 = create_vcurve(file, vpc1, 1.75 / 100, -1.0 / 100, 1600);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_2.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_2.second);
|
||||
|
||||
// Grade VPT1 to VPC2
|
||||
auto vertical_profile_segment_3 = create_gradient(vpt1, -1.0 / 100, 1600);
|
||||
vertical_curve_segments->push(vertical_profile_segment_3.first);
|
||||
vertical_segments->push(vertical_profile_segment_3.second);
|
||||
auto vertical_profile_segment_3 = create_gradient(file, vpt1, -1.0 / 100, 1600);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_3.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_3.second);
|
||||
|
||||
// Vertical Curve 2
|
||||
auto vertical_profile_segment_4 = create_vcurve(vpc2, -1.0 / 100, 2.0 / 100, 1200);
|
||||
vertical_curve_segments->push(vertical_profile_segment_4.first);
|
||||
vertical_segments->push(vertical_profile_segment_4.second);
|
||||
auto vertical_profile_segment_4 = create_vcurve(file, vpc2, -1.0 / 100, 2.0 / 100, 1200);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_4.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_4.second);
|
||||
|
||||
// Grade PVT2 to VPC3
|
||||
auto vertical_profile_segment_5 = create_gradient(vpt2, 2.0 / 100, 800);
|
||||
vertical_curve_segments->push(vertical_profile_segment_5.first);
|
||||
vertical_segments->push(vertical_profile_segment_5.second);
|
||||
auto vertical_profile_segment_5 = create_gradient(file, vpt2, 2.0 / 100, 800);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_5.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_5.second);
|
||||
|
||||
// Vertical Curve 3
|
||||
auto vertical_profile_segment_6 = create_vcurve(vpc3, 2.0 / 100, -2.0 / 100, 2000);
|
||||
vertical_curve_segments->push(vertical_profile_segment_6.first);
|
||||
vertical_segments->push(vertical_profile_segment_6.second);
|
||||
auto vertical_profile_segment_6 = create_vcurve(file, vpc3, 2.0 / 100, -2.0 / 100, 2000);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_6.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_6.second);
|
||||
|
||||
// Grade PVT3 to VPC4
|
||||
auto vertical_profile_segment_7 = create_gradient(vpt3, -2.0 / 100, 1000);
|
||||
vertical_curve_segments->push(vertical_profile_segment_7.first);
|
||||
vertical_segments->push(vertical_profile_segment_7.second);
|
||||
auto vertical_profile_segment_7 = create_gradient(file, vpt3, -2.0 / 100, 1000);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_7.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_7.second);
|
||||
|
||||
// Vertical Curve 4
|
||||
auto vertical_profile_segment_8 = create_vcurve(vpc4, -2.0 / 100, -0.5 / 100, 800);
|
||||
vertical_curve_segments->push(vertical_profile_segment_8.first);
|
||||
vertical_segments->push(vertical_profile_segment_8.second);
|
||||
auto vertical_profile_segment_8 = create_vcurve(file, vpc4, -2.0 / 100, -0.5 / 100, 800);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_8.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_8.second);
|
||||
|
||||
// Grade VPT4 to End
|
||||
auto vertical_profile_segment_9 = create_gradient(vpt4, -0.5 / 100, 2600);
|
||||
vertical_curve_segments->push(vertical_profile_segment_9.first);
|
||||
vertical_segments->push(vertical_profile_segment_9.second);
|
||||
auto vertical_profile_segment_9 = create_gradient(file, vpt4, -0.5 / 100, 2600);
|
||||
vertical_curve_segments.push_back(vertical_profile_segment_9.first);
|
||||
vertical_segments.push_back(vertical_profile_segment_9.second);
|
||||
|
||||
// Zero-length terminator
|
||||
auto vertical_terminator_segment = create_gradient(vpoe, -0.5 / 100, 0.0);
|
||||
vertical_terminator_segment.first->setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS);
|
||||
vertical_curve_segments->push(vertical_terminator_segment.first);
|
||||
vertical_segments->push(vertical_terminator_segment.second);
|
||||
auto vertical_terminator_segment = create_gradient(file, vpoe, -0.5 / 100, 0.0);
|
||||
vertical_terminator_segment.first.setTransition(Schema::IfcTransitionCode::IfcTransitionCode_DISCONTINUOUS);
|
||||
vertical_curve_segments.push_back(vertical_terminator_segment.first);
|
||||
vertical_segments.push_back(vertical_terminator_segment.second);
|
||||
|
||||
//
|
||||
// Create the vertical alignment (IfcAlignmentVertical) and nest alignment segments
|
||||
//
|
||||
auto vertical_profile = new Schema::IfcAlignmentVertical(IfcParse::IfcGlobalId(), nullptr, std::string("Vertical Alignment"), boost::none, boost::none, nullptr, nullptr);
|
||||
file.addEntity(vertical_profile);
|
||||
auto vertical_profile = file.create<Schema::IfcAlignmentVertical>();
|
||||
vertical_profile.setGlobalId(ifcopenshell::global_id());
|
||||
vertical_profile.setName("Example Vertical Profile");
|
||||
|
||||
auto nests_vertical_segments = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, boost::none, std::string("Nests vertical alignment segments with vertical alignment"), vertical_profile, vertical_segments);
|
||||
file.addEntity(nests_vertical_segments);
|
||||
auto nests_vertical_segments = file.create<Schema::IfcRelNests>();
|
||||
nests_vertical_segments.setGlobalId(ifcopenshell::global_id());
|
||||
nests_vertical_segments.setName("Nests vertical alignment segments with vertical profile");
|
||||
nests_vertical_segments.setRelatingObject(vertical_profile);
|
||||
nests_vertical_segments.setRelatedObjects(vertical_segments);
|
||||
|
||||
//
|
||||
// Create profile view axis model representation for the vertical profile
|
||||
//
|
||||
|
||||
// start by defining a gradient curve composed of the vertical curve segments and associated with the horizontal composite curve
|
||||
auto gradient_curve = new Schema::IfcGradientCurve(vertical_curve_segments, false, composite_curve, nullptr);
|
||||
file.addEntity(gradient_curve);
|
||||
|
||||
// the gradient curve is a representation item
|
||||
typename aggregate_of<typename Schema::IfcRepresentationItem>::ptr profile_representation_items(new aggregate_of<typename Schema::IfcRepresentationItem>());
|
||||
profile_representation_items->push(gradient_curve);
|
||||
auto gradient_curve = file.create<Schema::IfcGradientCurve>();
|
||||
gradient_curve.setSegments(vertical_curve_segments);
|
||||
gradient_curve.setSelfIntersect(false);
|
||||
gradient_curve.setBaseCurve(composite_curve);
|
||||
|
||||
// create the axis representation
|
||||
auto axis3d_shape_representation = new Schema::IfcShapeRepresentation(axis_model_representation_subcontext, std::string("Axis"), std::string("Curve3D"), profile_representation_items);
|
||||
file.addEntity(axis3d_shape_representation);
|
||||
auto axis3d_shape_representation = file.create<Schema::IfcShapeRepresentation>();
|
||||
axis3d_shape_representation.setContextOfItems(axis_model_representation_subcontext);
|
||||
axis3d_shape_representation.setRepresentationIdentifier("Axis");
|
||||
axis3d_shape_representation.setRepresentationType("Curve3D");
|
||||
// the gradient curve is a representation item
|
||||
axis3d_shape_representation.setItems({gradient_curve});
|
||||
|
||||
// create axis representations for each segment
|
||||
create_segment_representations(file, global_placement, axis_model_representation_subcontext, horizontal_curve_segments, horizontal_segments);
|
||||
@@ -432,38 +518,39 @@ int main() {
|
||||
// Create the IfcAlignment
|
||||
//
|
||||
|
||||
// the alignment has two representations, a plan view footprint and a 3d curve
|
||||
typename aggregate_of<typename Schema::IfcRepresentation>::ptr alignment_representations(new aggregate_of<typename Schema::IfcRepresentation>());
|
||||
alignment_representations->push(footprint_shape_representation); // 2D footprint
|
||||
alignment_representations->push(axis3d_shape_representation); // 3D curve
|
||||
|
||||
// create the alignment product definition
|
||||
auto alignment_product = new Schema::IfcProductDefinitionShape(std::string("Alignment Product Definition Shape"), boost::none, alignment_representations);
|
||||
auto alignment_product = file.create<Schema::IfcProductDefinitionShape>();
|
||||
alignment_product.setName("Alignment Product Definition Shape");
|
||||
// the alignment has two representations, a plan view footprint and a 3d curve
|
||||
alignment_product.setRepresentations({footprint_shape_representation, axis3d_shape_representation});
|
||||
|
||||
// create the alignment
|
||||
auto alignment = new Schema::IfcAlignment(IfcParse::IfcGlobalId(), nullptr, std::string("Example Alignment"), boost::none, boost::none, global_placement, alignment_product, boost::none);
|
||||
file.addEntity(alignment);
|
||||
auto alignment = file.create<Schema::IfcAlignment>();
|
||||
alignment.setGlobalId(ifcopenshell::global_id());
|
||||
alignment.setName("Example Alignment");
|
||||
alignment.setObjectPlacement(global_placement);
|
||||
alignment.setRepresentation(alignment_product);
|
||||
|
||||
// Nest the IfcAlignmentHorizontal and IfcAlignmentVertical with the IfcAlignment to complete the business logic
|
||||
// 4.1.4.4.1 Alignments nest horizontal and vertical layouts
|
||||
// https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Object_Composition/Nesting/Alignment_Layouts/content.html
|
||||
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr alignment_layout_list(new aggregate_of<typename Schema::IfcObjectDefinition>());
|
||||
alignment_layout_list->push(horizontal_alignment);
|
||||
alignment_layout_list->push(vertical_profile);
|
||||
|
||||
auto nests_alignment_layouts = new Schema::IfcRelNests(IfcParse::IfcGlobalId(), nullptr, std::string("Nest horizontal and vertical alignment layouts with the alignment"), boost::none, alignment, alignment_layout_list);
|
||||
file.addEntity(nests_alignment_layouts);
|
||||
|
||||
auto nests_alignment_layouts = file.create<Schema::IfcRelNests>();
|
||||
nests_alignment_layouts.setGlobalId(ifcopenshell::global_id());
|
||||
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"
|
||||
// https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Object_Composition/Aggregation/Alignment_Aggregation_To_Project/content.html
|
||||
// IfcProject <-> IfcRelAggregates <-> IfcAlignment
|
||||
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr list_of_alignments_in_project(new aggregate_of<typename Schema::IfcObjectDefinition>());
|
||||
list_of_alignments_in_project->push(alignment);
|
||||
auto aggregate_alignments_with_project = new Schema::IfcRelAggregates(IfcParse::IfcGlobalId(), nullptr, std::string("Alignments in project"), boost::none, project, list_of_alignments_in_project);
|
||||
file.addEntity(aggregate_alignments_with_project);
|
||||
|
||||
auto aggregate_alignments_with_project = file.create<Schema::IfcRelAggregates>();
|
||||
aggregate_alignments_with_project.setGlobalId(ifcopenshell::global_id());
|
||||
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
|
||||
@@ -471,24 +558,26 @@ int main() {
|
||||
// IfcSite <-> IfcRelReferencedInSpatialStructure <-> IfcAlignment
|
||||
// This means IfcAlignment is not part of the IfcSite (it is not an aggregate component) but instead IfcAlignment is used within
|
||||
// the IfcSite by reference. This implies an IfcAlignment can traverse many IfcSite instances within an IfcProject
|
||||
typename Schema::IfcSpatialReferenceSelect::list::ptr list_alignments_referenced_in_site(new Schema::IfcSpatialReferenceSelect::list);
|
||||
list_alignments_referenced_in_site->push(alignment);
|
||||
std::vector<Schema::IfcSpatialReferenceSelect> list_alignments_referenced_in_site{alignment};
|
||||
|
||||
// this alignment traverse 3 bridge sites.
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
std::ostringstream os;
|
||||
os << "Site of Bridge " << i;
|
||||
auto site = file.addSite(project, nullptr);
|
||||
site->setName(os.str());
|
||||
auto site = file.addSite(project);
|
||||
site.setName(os.str());
|
||||
|
||||
std::ostringstream description;
|
||||
description << "Alignments referenced into the spatial structure of Bridge Site " << i;
|
||||
|
||||
auto rel_referenced_in_spatial_structure = new Schema::IfcRelReferencedInSpatialStructure(IfcParse::IfcGlobalId(), nullptr, boost::none, description.str(), list_alignments_referenced_in_site, site);
|
||||
file.addEntity(rel_referenced_in_spatial_structure);
|
||||
auto rel_referenced_in_spatial_structure = file.create<Schema::IfcRelReferencedInSpatialStructure>();
|
||||
rel_referenced_in_spatial_structure.setGlobalId(ifcopenshell::global_id());
|
||||
rel_referenced_in_spatial_structure.setDescription(description.str());
|
||||
rel_referenced_in_spatial_structure.setRelatedElements(list_alignments_referenced_in_site);
|
||||
rel_referenced_in_spatial_structure.setRelatingStructure(site);
|
||||
}
|
||||
|
||||
// That's it - save the model to a file
|
||||
std::ofstream ofs("IfcAlignment.ifc");
|
||||
std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example.ifc");
|
||||
ofs << file;
|
||||
}
|
||||
|
||||
+374
-324
@@ -36,12 +36,11 @@
|
||||
#include <Precision.hxx>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/macros.h"
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcBaseClass.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
#include "ifcgeom/Serialization/Serialization.h"
|
||||
#include "../ifcgeom/Serialization/Serialization.h"
|
||||
|
||||
#if USE_VLD
|
||||
#include <vld.h>
|
||||
@@ -50,7 +49,7 @@
|
||||
using namespace std::string_literals;
|
||||
|
||||
// Some convenience typedefs and definitions.
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
typedef std::pair<double, double> XY;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
@@ -59,235 +58,276 @@ void createGroundShape(TopoDS_Shape& shape);
|
||||
|
||||
int main() {
|
||||
|
||||
// The IfcHierarchyHelper is a subclass of the regular IfcFile that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname("IfcOpenHouse.ifc");
|
||||
// The hierarchy_helper is a subclass of the regular file that provides several
|
||||
// convenience functions for working with geometry in IFC files.
|
||||
hierarchy_helper<IfcSchema> file;
|
||||
file.header().file_name().setname("IfcOpenHouse.ifc");
|
||||
|
||||
// Start by adding a wall to the file, initially leaving most attributes blank.
|
||||
IfcSchema::IfcWallStandardCase* south_wall = new IfcSchema::IfcWallStandardCase(
|
||||
guid(), // GlobalId
|
||||
0, // OwnerHistory
|
||||
"South wall"s, // Name
|
||||
null, // Description
|
||||
null, // ObjectType
|
||||
0, // ObjectPlacement
|
||||
0, // Representation
|
||||
null // Tag
|
||||
// Start by adding a wall to the file, initially leaving most attributes blank.
|
||||
auto south_wall = file.create<IfcSchema::IfcWallStandardCase>();
|
||||
south_wall.setGlobalId(guid());
|
||||
south_wall.setName("South wall");
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
south_wall.setPredefinedType(IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD);
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(south_wall);
|
||||
file.addBuildingProduct(south_wall);
|
||||
|
||||
// By adding a wall, a hierarchy has been automatically created that consists of the following
|
||||
// structure: IfcProject > IfcSite > IfcBuilding > IfcBuildingStorey > IfcWall
|
||||
// By adding a wall, a hierarchy has been automatically created that consists of the following
|
||||
// structure: IfcProject > IfcSite > IfcBuilding > IfcBuildingStorey > IfcWall
|
||||
|
||||
// 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("IfcOpenHouse"s);
|
||||
// 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("IfcOpenHouse"s);
|
||||
|
||||
// An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
|
||||
south_wall->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
// An IfcOwnerHistory has been initialized as well, which should be assigned to the wall.
|
||||
south_wall.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
|
||||
// The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting
|
||||
// product definition will consist of both a body representation as well as an axis representation
|
||||
// that runs over the centerline of the box in the X-axis.
|
||||
IfcSchema::IfcProductDefinitionShape* south_wall_shape = file.addAxisBox(10000, 360, 3000);
|
||||
// The wall will be shaped as a box, with the dimensions specified in millimeters. The resulting
|
||||
// product definition will consist of both a body representation as well as an axis representation
|
||||
// that runs over the centerline of the box in the X-axis.
|
||||
auto south_wall_shape = file.addAxisBox(10000, 360, 3000);
|
||||
|
||||
// Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy
|
||||
// of placements for the products
|
||||
IfcSchema::IfcObjectPlacement* storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>()->ObjectPlacement();
|
||||
// Obtain a reference to the placement of the IfcBuildingStorey in order to create a hierarchy
|
||||
// of placements for the products
|
||||
auto storey_placement = file.getSingle<IfcSchema::IfcBuildingStorey>().ObjectPlacement();
|
||||
|
||||
// The shape has to be assigned to the representation of the wall and is placed at the origin
|
||||
// of the coordinate system.
|
||||
south_wall->setRepresentation(south_wall_shape);
|
||||
south_wall->setObjectPlacement(file.addLocalPlacement(storey_placement));
|
||||
// The shape has to be assigned to the representation of the wall and is placed at the origin
|
||||
// of the coordinate system.
|
||||
south_wall.setRepresentation(south_wall_shape);
|
||||
south_wall.setObjectPlacement(file.addLocalPlacement(storey_placement));
|
||||
|
||||
// A pale white colour is assigned to the wall.
|
||||
IfcSchema::IfcPresentationStyleAssignment* wall_colour = setSurfaceColour(file, south_wall_shape, 0.75, 0.73, 0.68);
|
||||
// A pale white colour is assigned to the wall.
|
||||
auto wall_colour = setSurfaceColour(file, south_wall_shape, 0.75, 0.73, 0.68);
|
||||
|
||||
// Now create a footing for the wall to rest on.
|
||||
IfcSchema::IfcFooting* footing = new IfcSchema::IfcFooting(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
"Footing"s, null, null, 0, 0, null, IfcSchema::IfcFootingTypeEnum::IfcFootingType_STRIP_FOOTING);
|
||||
// Now create a footing for the wall to rest on.
|
||||
auto footing = file.create<IfcSchema::IfcFooting>();
|
||||
footing.setGlobalId(guid());
|
||||
footing.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
footing.setName("Footing");
|
||||
footing.setPredefinedType(IfcSchema::IfcFootingTypeEnum::IfcFootingType_STRIP_FOOTING);
|
||||
|
||||
file.addBuildingProduct(footing);
|
||||
file.addBuildingProduct(footing);
|
||||
|
||||
// The footing will span the entire floor plan of our building. The IfcRepresentationContext is
|
||||
// something that has been created automatically as well, but representations could have been
|
||||
// assigned to a specific context, for example to add a two dimensional plan representation as well.
|
||||
footing->setRepresentation(file.addBox(10100, 5460, 2000));
|
||||
footing->setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000));
|
||||
// The footing will have a dark gray colour
|
||||
IfcSchema::IfcPresentationStyleAssignment* footing_colour = setSurfaceColour(file,footing->Representation(), 0.26, 0.22, 0.18);
|
||||
// The footing will span the entire floor plan of our building. The IfcRepresentationContext is
|
||||
// something that has been created automatically as well, but representations could have been
|
||||
// assigned to a specific context, for example to add a two dimensional plan representation as well.
|
||||
footing.setRepresentation(file.addBox(10100, 5460, 2000));
|
||||
footing.setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 2500, -2000));
|
||||
// The footing will have a dark gray colour
|
||||
auto footing_colour = setSurfaceColour(file, footing.Representation(), 0.26, 0.22, 0.18);
|
||||
|
||||
// IFC has two ways to apply boolean operations to geometry. IfcBooleanResults are commonly used
|
||||
// to clip geometry to a surface, for example to a slanted roof. For openings that are filled
|
||||
// with another element, for example a door or a window, an IfcOpeningElement is used instead.
|
||||
// IFC has two ways to apply boolean operations to geometry. IfcBooleanResults are commonly used
|
||||
// to clip geometry to a surface, for example to a slanted roof. For openings that are filled
|
||||
// with another element, for example a door or a window, an IfcOpeningElement is used instead.
|
||||
|
||||
// An opening element is created with rectangular geometry:
|
||||
IfcSchema::IfcOpeningElement* west_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(south_wall->ObjectPlacement(), -2500, 0, 400),
|
||||
file.addBox(6000, 3630, 1600), null
|
||||
// An opening element is created with rectangular geometry:
|
||||
auto west_opening = file.create<IfcSchema::IfcOpeningElement>();
|
||||
west_opening.setGlobalId(guid());
|
||||
west_opening.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
west_opening.setObjectPlacement(file.addLocalPlacement(south_wall.ObjectPlacement(), -2500, 0, 400));
|
||||
west_opening.setRepresentation(file.addBox(6000, 3630, 1600));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
west_opening.setPredefinedType(IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING);
|
||||
#endif
|
||||
);
|
||||
file.addEntity(west_opening);
|
||||
|
||||
// Relate the opening element to the wall.
|
||||
IfcSchema::IfcRelVoidsElement* void_element = new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, south_wall, west_opening);
|
||||
file.addEntity(void_element);
|
||||
// Relate the opening element to the wall.
|
||||
auto void_element = file.create<IfcSchema::IfcRelVoidsElement>();
|
||||
void_element.setGlobalId(guid());
|
||||
void_element.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
void_element.setRelatingBuildingElement(south_wall);
|
||||
void_element.setRelatedOpeningElement(west_opening);
|
||||
|
||||
// Now create an additional opening
|
||||
IfcSchema::IfcOpeningElement* south_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 3000, 0, 400),
|
||||
file.addBox(1860, 3000, 1600), null
|
||||
// Now create an additional opening
|
||||
auto south_opening = file.create<IfcSchema::IfcOpeningElement>();
|
||||
south_opening.setGlobalId(guid());
|
||||
south_opening.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
south_opening.setObjectPlacement(file.addLocalPlacement(storey_placement, 3000, 0, 400));
|
||||
south_opening.setRepresentation(file.addBox(1860, 3000, 1600));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
south_opening.setPredefinedType(IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING);
|
||||
#endif
|
||||
);
|
||||
file.addEntity(south_opening);
|
||||
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, south_wall, south_opening));
|
||||
|
||||
// Create a roof element that will consist of two slabs:
|
||||
IfcSchema::IfcRoof* roof = new IfcSchema::IfcRoof(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), "Roof"s, null, null,
|
||||
file.addLocalPlacement(storey_placement), 0, null, IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
|
||||
|
||||
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
|
||||
IfcSchema::IfcShapeRepresentation* roof_rep = file.addEmptyRepresentation();
|
||||
file.addBox(roof_rep, 10200, 360, sqrt(2.0*2900*2900), 0, file.addPlacement3d(0, 0, 0, 0, 1, 0),
|
||||
file.addTriplet<IfcSchema::IfcDirection>(0, -sqrt(0.5), sqrt(0.5)));
|
||||
// Relate the opening element to the wall.
|
||||
auto void_element2 = file.create<IfcSchema::IfcRelVoidsElement>();
|
||||
void_element2.setGlobalId(guid());
|
||||
void_element2.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
void_element2.setRelatingBuildingElement(south_wall);
|
||||
void_element2.setRelatedOpeningElement(south_opening);
|
||||
|
||||
// CV-2x3-144: Roofs are aggregates and shall have at least one contained element and no own geometry
|
||||
IfcSchema::IfcSlab* south_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), "South roof"s,
|
||||
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
|
||||
// The geometry is instantiated by using IfcMappedItems. This way geometry definitions can
|
||||
// be reused while maintaining the cardinality constraint that the ShapeOfProduct relation
|
||||
// imposes on the IfcProductDefinitionShape. Note that this constrained is lifted in IFC4.
|
||||
south_roof_part->setRepresentation(file.addMappedItem(roof_rep));
|
||||
south_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, -400, 2700));
|
||||
|
||||
// The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
|
||||
// the local placement the roof is rotated 180 degrees around the Z-axis
|
||||
IfcSchema::IfcSlab* north_roof_part = new IfcSchema::IfcSlab(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), "North roof"s,
|
||||
null, null, 0, 0, null, IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
north_roof_part->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
north_roof_part->setRepresentation(file.addMappedItem(roof_rep));
|
||||
north_roof_part->setObjectPlacement(file.addLocalPlacement(roof->ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0));
|
||||
|
||||
IfcSchema::IfcObjectDefinition::list::ptr roof_parts(new IfcSchema::IfcObjectDefinition::list);
|
||||
roof_parts->push(south_roof_part);
|
||||
roof_parts->push(north_roof_part);
|
||||
IfcSchema::IfcRelDecomposes* roof_decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, roof, roof_parts);
|
||||
file.addEntity(roof_decomposition);
|
||||
|
||||
file.addBuildingProduct(south_roof_part);
|
||||
file.addBuildingProduct(north_roof_part);
|
||||
file.addBuildingProduct(roof);
|
||||
|
||||
setSurfaceColour(file, roof_rep, 0.24, 0.08, 0.04);
|
||||
|
||||
// Copy the south wall to the north
|
||||
IfcSchema::IfcWallStandardCase* north_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), "North wall"s,
|
||||
null, null, file.addLocalPlacement(storey_placement, 0, 5000, 0), file.addAxisBox(10000, 360, 3000), null
|
||||
// Create a roof element that will consist of two slabs:
|
||||
auto roof = file.create<IfcSchema::IfcRoof>();
|
||||
roof.setGlobalId(guid());
|
||||
roof.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
roof.setName("Roof");
|
||||
roof.setObjectPlacement(file.addLocalPlacement(storey_placement));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(north_wall);
|
||||
setSurfaceColour(file,north_wall->Representation(), wall_colour);
|
||||
roof.setPredefinedType(IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
|
||||
#else
|
||||
roof.setShapeType(IfcSchema::IfcRoofTypeEnum::IfcRoofType_GABLE_ROOF);
|
||||
#endif
|
||||
|
||||
// Two identical representations are created for the two remaining walls. Mapped items
|
||||
// are not used, because it is not allowed by the standard for wall body representations.
|
||||
// MappedItems are not allowed for Axis representations as per CV-2x3-161
|
||||
IfcSchema::IfcProductDefinitionShape* clipped_wall_body_reps[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
IfcSchema::IfcShapeRepresentation* body = file.addEmptyRepresentation();
|
||||
file.addBox(body, 5000, 360, 6000);
|
||||
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
setSurfaceColour(file, body, wall_colour);
|
||||
// The roof geometry is slanted 45 degrees by specifying a direction for the box extrusion
|
||||
auto roof_rep = file.addEmptyRepresentation();
|
||||
file.addBox(roof_rep, 10200, 360, sqrt(2.0 * 2900 * 2900), IfcSchema::IfcAxis2Placement2D{}, file.addPlacement3d(0, 0, 0, 0, 1, 0), file.addTriplet<IfcSchema::IfcDirection>(0, -sqrt(0.5), sqrt(0.5)));
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* axis = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(axis, 5000);
|
||||
// CV-2x3-144: Roofs are aggregates and shall have at least one contained element and no own geometry
|
||||
auto south_roof_part = file.create<IfcSchema::IfcSlab>();
|
||||
south_roof_part.setGlobalId(guid());
|
||||
south_roof_part.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
south_roof_part.setName("South roof");
|
||||
south_roof_part.setPredefinedType(IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(body);
|
||||
reps->push(axis);
|
||||
clipped_wall_body_reps[i] = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
}
|
||||
// The geometry is instantiated by using IfcMappedItems. This way geometry definitions can
|
||||
// be reused while maintaining the cardinality constraint that the ShapeOfProduct relation
|
||||
// imposes on the IfcProductDefinitionShape. Note that this constrained is lifted in IFC4.
|
||||
south_roof_part.setRepresentation(file.addMappedItem(roof_rep));
|
||||
south_roof_part.setObjectPlacement(file.addLocalPlacement(roof.ObjectPlacement(), 0, -400, 2700));
|
||||
|
||||
// Now create a wall on the east of the building, again starting with just a box shape
|
||||
IfcSchema::IfcWallStandardCase* east_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
"East wall"s, null, null, file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0), clipped_wall_body_reps[0], null
|
||||
// The same roof geometry is re-used on the north side of the roof, by inverting the X-axis of
|
||||
// the local placement the roof is rotated 180 degrees around the Z-axis
|
||||
auto north_roof_part = file.create<IfcSchema::IfcSlab>();
|
||||
north_roof_part.setGlobalId(guid());
|
||||
north_roof_part.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
north_roof_part.setName("North roof");
|
||||
north_roof_part.setPredefinedType(IfcSchema::IfcSlabTypeEnum::IfcSlabType_ROOF);
|
||||
|
||||
north_roof_part.setRepresentation(file.addMappedItem(roof_rep));
|
||||
north_roof_part.setObjectPlacement(file.addLocalPlacement(roof.ObjectPlacement(), 0, 5400, 2700, 0, 0, 1, -1, 0, 0));
|
||||
|
||||
{
|
||||
auto rel = file.create<IfcSchema::IfcRelAggregates>();
|
||||
rel.setGlobalId(guid());
|
||||
rel.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
rel.setRelatingObject(roof);
|
||||
rel.setRelatedObjects({south_roof_part, north_roof_part});
|
||||
}
|
||||
|
||||
file.addBuildingProduct(south_roof_part);
|
||||
file.addBuildingProduct(north_roof_part);
|
||||
file.addBuildingProduct(roof);
|
||||
|
||||
setSurfaceColour(file, roof_rep, 0.24, 0.08, 0.04);
|
||||
|
||||
// Copy the south wall to the north
|
||||
auto north_wall = file.create<IfcSchema::IfcWallStandardCase>();
|
||||
north_wall.setGlobalId(guid());
|
||||
north_wall.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
north_wall.setName("North wall");
|
||||
north_wall.setObjectPlacement(file.addLocalPlacement(storey_placement, 0, 5000, 0));
|
||||
north_wall.setRepresentation(file.addAxisBox(10000, 360, 3000));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(east_wall);
|
||||
north_wall.setPredefinedType(IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD);
|
||||
#endif
|
||||
|
||||
// The east wall is copied to the west location of the house
|
||||
IfcSchema::IfcWallStandardCase* west_wall = new IfcSchema::IfcWallStandardCase(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
"West wall"s, null, null, file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0), clipped_wall_body_reps[1], null
|
||||
file.addBuildingProduct(north_wall);
|
||||
setSurfaceColour(file, north_wall.Representation(), wall_colour);
|
||||
|
||||
// Two identical representations are created for the two remaining walls. Mapped items
|
||||
// are not used, because it is not allowed by the standard for wall body representations.
|
||||
// MappedItems are not allowed for Axis representations as per CV-2x3-161
|
||||
IfcSchema::IfcProductDefinitionShape clipped_wall_body_reps[2];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
auto body = file.addEmptyRepresentation();
|
||||
file.addBox(body, 5000, 360, 6000);
|
||||
// The wall geometry is clipped using two IfcHalfSpaceSolids, created from an
|
||||
// 'axis 3d placement' that specifies the plane against which the geometry is clipped.
|
||||
file.clipRepresentation(body, file.addPlacement3d(-2500, 0, 3000, -1, 0, 1), false);
|
||||
file.clipRepresentation(body, file.addPlacement3d(2500, 0, 3000, 1, 0, 1), false);
|
||||
setSurfaceColour(file, body, wall_colour);
|
||||
|
||||
auto axis = file.addEmptyRepresentation("Axis", "Curve2D");
|
||||
file.addAxis(axis, 5000);
|
||||
|
||||
clipped_wall_body_reps[i] = file.create<IfcSchema::IfcProductDefinitionShape>();
|
||||
clipped_wall_body_reps[i].setRepresentations({body, axis});
|
||||
}
|
||||
|
||||
// Now create a wall on the east of the building, again starting with just a box shape
|
||||
auto east_wall = file.create<IfcSchema::IfcWallStandardCase>();
|
||||
east_wall.setGlobalId(guid());
|
||||
east_wall.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
east_wall.setName("East wall");
|
||||
east_wall.setObjectPlacement(file.addLocalPlacement(storey_placement, 4820, 2500, 0, 0, 0, 1, 0, 1, 0));
|
||||
east_wall.setRepresentation(clipped_wall_body_reps[0]);
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD
|
||||
#endif
|
||||
);
|
||||
file.addBuildingProduct(west_wall);
|
||||
east_wall.setPredefinedType(IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD);
|
||||
#endif
|
||||
|
||||
// The west wall is assigned an opening element we created for the south wall, opening elements are
|
||||
// not shared across building elements, even if they share the same representation. Hence, the east
|
||||
// wall will not feature this opening.
|
||||
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
|
||||
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
|
||||
file.addBuildingProduct(east_wall);
|
||||
|
||||
// Not all viewers support opening elements with mapped representations, hence an exact copy of the
|
||||
// same subtraction box is instantiated for the otherwise identical opening element.
|
||||
IfcSchema::IfcOpeningElement* west_opening_copy = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(west_wall->ObjectPlacement(), 2500, -2500+4820, 400, 0, 0, 1, 0, 1, 0),
|
||||
file.addBox(6000, 3630, 1600), null
|
||||
// The east wall is copied to the west location of the house
|
||||
auto west_wall = file.create<IfcSchema::IfcWallStandardCase>();
|
||||
west_wall.setGlobalId(guid());
|
||||
west_wall.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
west_wall.setName("West wall");
|
||||
west_wall.setObjectPlacement(file.addLocalPlacement(storey_placement, -4820, 2500, 0, 0, 0, 1, 0, -1, 0));
|
||||
west_wall.setRepresentation(clipped_wall_body_reps[1]);
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
file.addEntity(west_opening_copy);
|
||||
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, west_wall, west_opening_copy));
|
||||
|
||||
west_wall.setPredefinedType(IfcSchema::IfcWallTypeEnum::IfcWallType_STANDARD);
|
||||
#endif
|
||||
|
||||
file.addBuildingProduct(west_wall);
|
||||
|
||||
// The west wall is assigned an opening element we created for the south wall, opening elements are
|
||||
// not shared across building elements, even if they share the same representation. Hence, the east
|
||||
// wall will not feature this opening.
|
||||
// NB: an Opening Element can only be used to create a single void within a single Element, as per:
|
||||
// http://www.buildingsmart-tech.org/ifc/IFC2x3/TC1/html/ifcproductextension/lexical/ifcfeatureelementsubtraction.htm
|
||||
|
||||
// Not all viewers support opening elements with mapped representations, hence an exact copy of the
|
||||
// same subtraction box is instantiated for the otherwise identical opening element.
|
||||
auto west_opening_copy = file.create<IfcSchema::IfcOpeningElement>();
|
||||
west_opening_copy.setGlobalId(guid());
|
||||
west_opening_copy.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
west_opening_copy.setObjectPlacement(file.addLocalPlacement(west_wall.ObjectPlacement(), 2500, -2500 + 4820, 400, 0, 0, 1, 0, 1, 0));
|
||||
west_opening_copy.setRepresentation(file.addBox(6000, 3630, 1600));
|
||||
#ifdef USE_IFC4
|
||||
west_opening_copy.setPredefinedType(IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING);
|
||||
#endif
|
||||
|
||||
{
|
||||
auto rel = file.create<IfcSchema::IfcRelVoidsElement>();
|
||||
rel.setGlobalId(guid());
|
||||
rel.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
rel.setRelatingBuildingElement(west_wall);
|
||||
rel.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
|
||||
// will be tessellated using the deflection specified.
|
||||
TopoDS_Shape shape;
|
||||
createGroundShape(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* ground_representation = IfcGeom::tesselate(STRINGIFY(IfcSchema), shape, 100.)->as<IfcSchema::IfcProductDefinitionShape>();
|
||||
file.getSingle<IfcSchema::IfcSite>()->setRepresentation(ground_representation);
|
||||
auto ground_representation = IfcGeom::tesselate(file, shape, 100.).as<IfcSchema::IfcProductDefinitionShape>();
|
||||
file.getSingle<IfcSchema::IfcSite>().setRepresentation(ground_representation);
|
||||
|
||||
GProp_GProps prop;
|
||||
BRepGProp::SurfaceProperties(shape, prop);
|
||||
const double site_area = prop.Mass() / 1000 / 1000;
|
||||
|
||||
IfcSchema::IfcProperty::list::ptr properties(new IfcSchema::IfcProperty::list);
|
||||
properties->push(new IfcSchema::IfcPropertySingleValue("TotalArea", null, new IfcSchema::IfcAreaMeasure(site_area), 0));
|
||||
IfcSchema::IfcPropertySet* pset = new IfcSchema::IfcPropertySet(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), "Pset_SiteCommon"s, null, properties);
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcObjectDefinition::list::ptr related_objs(new IfcSchema::IfcObjectDefinition::list);
|
||||
#else
|
||||
IfcSchema::IfcObject::list::ptr related_objs(new IfcSchema::IfcObject::list);
|
||||
#endif
|
||||
related_objs->push(file.getSingle<IfcSchema::IfcSite>());
|
||||
IfcSchema::IfcRelDefinesByProperties* site_prop = new IfcSchema::IfcRelDefinesByProperties(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, related_objs, pset);
|
||||
file.addEntity(site_prop);
|
||||
auto total_area = file.create<IfcSchema::IfcPropertySingleValue>();
|
||||
total_area.setName("TotalArea");
|
||||
auto area = file.create<IfcSchema::IfcAreaMeasure>();
|
||||
area.set_attribute_value(0, site_area);
|
||||
total_area.setNominalValue(area);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr ground_reps = file.getSingle<IfcSchema::IfcSite>()->Representation()->Representations();
|
||||
for (IfcSchema::IfcRepresentation::list::it it = ground_reps->begin(); it != ground_reps->end(); ++it) {
|
||||
(*it)->setContextOfItems(file.getRepresentationContext("Model"));
|
||||
auto pset = file.create<IfcSchema::IfcPropertySet>();
|
||||
pset.setGlobalId(guid());
|
||||
pset.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
pset.setName("Pset_SiteCommon");
|
||||
pset.setHasProperties({total_area});
|
||||
|
||||
auto site_prop = file.create<IfcSchema::IfcRelDefinesByProperties>();
|
||||
site_prop.setGlobalId(guid());
|
||||
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"));
|
||||
}
|
||||
file.addEntity(ground_representation);
|
||||
file.add_entity(ground_representation);
|
||||
setSurfaceColour(file,ground_representation, 0.15, 0.25, 0.05);
|
||||
|
||||
// According to the Ifc2x3 schema an IfcWallStandardCase needs to have an IfcMaterialLayerSet
|
||||
@@ -297,58 +337,28 @@ int main() {
|
||||
// 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
|
||||
// provided here.
|
||||
#ifdef USE_IFC4
|
||||
IfcSchema::IfcMaterial* material = new IfcSchema::IfcMaterial("Brick", null, null);
|
||||
#else
|
||||
IfcSchema::IfcMaterial* material = new IfcSchema::IfcMaterial("Brick");
|
||||
#endif
|
||||
IfcSchema::IfcMaterialLayer* layer = new IfcSchema::IfcMaterialLayer(
|
||||
material,
|
||||
360,
|
||||
null
|
||||
#ifdef USE_IFC4
|
||||
, null
|
||||
, null
|
||||
, null
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
IfcSchema::IfcMaterialLayer::list::ptr layers (new aggregate_of<IfcSchema::IfcMaterialLayer>());
|
||||
layers->push(layer);
|
||||
IfcSchema::IfcMaterialLayerSet* layer_set = new IfcSchema::IfcMaterialLayerSet(
|
||||
layers,
|
||||
"Wall"s
|
||||
#ifdef USE_IFC4
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
IfcSchema::IfcMaterialLayerSetUsage* layer_usage = new IfcSchema::IfcMaterialLayerSetUsage(
|
||||
layer_set,
|
||||
IfcSchema::IfcLayerSetDirectionEnum::IfcLayerSetDirection_AXIS2,
|
||||
IfcSchema::IfcDirectionSenseEnum::IfcDirectionSense_POSITIVE,
|
||||
-180
|
||||
#ifdef USE_IFC4
|
||||
, null
|
||||
#endif
|
||||
);
|
||||
auto material = file.create<IfcSchema::IfcMaterial>();
|
||||
material.setName("Brick");
|
||||
|
||||
IfcSchema::IfcRelAssociatesMaterial* associates_material = new IfcSchema::IfcRelAssociatesMaterial(
|
||||
guid(),
|
||||
file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null,
|
||||
null,
|
||||
#ifdef USE_IFC4
|
||||
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcDefinitionSelect>(),
|
||||
#else
|
||||
file.instances_by_type<IfcSchema::IfcWallStandardCase>()->as<IfcSchema::IfcRoot>(),
|
||||
#endif
|
||||
layer_usage);
|
||||
auto layer = file.create<IfcSchema::IfcMaterialLayer>();
|
||||
layer.setMaterial(material);
|
||||
layer.setLayerThickness(360);
|
||||
|
||||
file.addEntity(material);
|
||||
file.addEntity(layer);
|
||||
file.addEntity(layer_set);
|
||||
file.addEntity(layer_usage);
|
||||
file.addEntity(associates_material);
|
||||
auto layer_set = file.create<IfcSchema::IfcMaterialLayerSet>();
|
||||
layer_set.setMaterialLayers({layer});
|
||||
layer_set.setLayerSetName("Wall");
|
||||
|
||||
auto layer_usage = file.create<IfcSchema::IfcMaterialLayerSetUsage>();
|
||||
layer_usage.setForLayerSet(layer_set);
|
||||
layer_usage.setDirectionSense(IfcSchema::IfcDirectionSenseEnum::IfcDirectionSense_POSITIVE);
|
||||
layer_usage.setLayerSetDirection(IfcSchema::IfcLayerSetDirectionEnum::IfcLayerSetDirection_AXIS1);
|
||||
layer_usage.setOffsetFromReferenceLine(-180);
|
||||
|
||||
auto associates_material = file.create<IfcSchema::IfcRelAssociatesMaterial>();
|
||||
associates_material.setGlobalId(guid());
|
||||
associates_material.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
associates_material.setRelatedObjects({south_wall, north_wall, east_wall, west_wall});
|
||||
associates_material.setRelatingMaterial(layer_usage);
|
||||
|
||||
// In addition, another common way to represent geometry in IFC files is to use extrusions of
|
||||
// planar areas bounded by a polygon.
|
||||
@@ -359,55 +369,88 @@ int main() {
|
||||
stair_points.push_back(XY(500, 200));
|
||||
stair_points.push_back(XY(500, 400));
|
||||
stair_points.push_back(XY( 0, 400));
|
||||
IfcSchema::IfcStairFlight* stair = new IfcSchema::IfcStairFlight(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 5050, 1000, 0, 0, 1, 0, 1, 0, 0),
|
||||
file.addExtrudedPolyline(stair_points, 1200), null, 2, 2, 0.2, 0.25
|
||||
auto stair = file.create<IfcSchema::IfcStairFlight>();
|
||||
stair.setGlobalId(guid());
|
||||
stair.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
stair.setObjectPlacement(file.addLocalPlacement(storey_placement, 5050, 1000, 0, 0, 1, 0, 1, 0, 0));
|
||||
stair.setRepresentation(file.addExtrudedPolyline(stair_points, 1200));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcStairFlightTypeEnum::IfcStairFlightType_STRAIGHT
|
||||
stair.setNumberOfRisers(2);
|
||||
#else
|
||||
stair.setNumberOfRiser(2);
|
||||
#endif
|
||||
stair.setNumberOfTreads(2);
|
||||
stair.setRiserHeight(0.2);
|
||||
stair.setTreadLength(0.25);
|
||||
#ifdef USE_IFC4
|
||||
stair.setPredefinedType(IfcSchema::IfcStairFlightTypeEnum::IfcStairFlightType_STRAIGHT);
|
||||
#endif
|
||||
);
|
||||
|
||||
file.addBuildingProduct(stair);
|
||||
setSurfaceColour(file, stair->Representation(), footing_colour);
|
||||
setSurfaceColour(file, stair.Representation(), footing_colour);
|
||||
|
||||
IfcSchema::IfcOpeningElement* door_opening = new IfcSchema::IfcOpeningElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, file.addLocalPlacement(storey_placement, 5000-180, 2500-900, 0), file.addBox(1000, 1000, 2200), null
|
||||
auto door_opening = file.create<IfcSchema::IfcOpeningElement>();
|
||||
door_opening.setGlobalId(guid());
|
||||
door_opening.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
door_opening.setObjectPlacement(file.addLocalPlacement(storey_placement, 5000 - 180, 2500 - 900, 0));
|
||||
door_opening.setRepresentation(file.addBox(1000, 1000, 2200));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING
|
||||
#endif
|
||||
);
|
||||
file.addEntity(door_opening);
|
||||
file.addEntity(new IfcSchema::IfcRelVoidsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, east_wall, door_opening));
|
||||
door_opening.setPredefinedType(IfcSchema::IfcOpeningElementTypeEnum::IfcOpeningElementType_OPENING);
|
||||
#endif
|
||||
|
||||
auto rel3 = file.create<IfcSchema::IfcRelVoidsElement>();
|
||||
rel3.setGlobalId(guid());
|
||||
rel3.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
rel3.setRelatingBuildingElement(east_wall);
|
||||
rel3.setRelatedOpeningElement(door_opening);
|
||||
|
||||
// A single shape representation can contain multiple representiation items. This way a product
|
||||
// can be a composition of multiple solids. The following door will be composed of four boxes
|
||||
// which constitute the door and its frame.
|
||||
IfcSchema::IfcDoor* door = new IfcSchema::IfcDoor(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, null,
|
||||
file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0), 0, null, 2200, 1000
|
||||
auto door = file.create<IfcSchema::IfcDoor>();
|
||||
door.setGlobalId(guid());
|
||||
door.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
door.setObjectPlacement(file.addLocalPlacement(storey_placement, 4800, 1600, 0, 0, 0, 1, 0, 1, 0));
|
||||
door.setOverallWidth(1000);
|
||||
door.setOverallHeight(2200);
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR
|
||||
, IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT
|
||||
, null
|
||||
door.setPredefinedType(IfcSchema::IfcDoorTypeEnum::IfcDoorType_DOOR);
|
||||
door.setOperationType(IfcSchema::IfcDoorTypeOperationEnum::IfcDoorTypeOperation_SINGLE_SWING_LEFT);
|
||||
#endif
|
||||
);
|
||||
door->setRepresentation(file.addBox(80, 80, 2120, 0, file.addPlacement3d(460, 0, 0)));
|
||||
IfcSchema::IfcRepresentation::list::ptr door_representations = door->Representation()->Representations();
|
||||
IfcSchema::IfcShapeRepresentation* door_body = 0;
|
||||
for (IfcSchema::IfcRepresentation::list::it i = door_representations->begin(); i != door_representations->end(); ++i) {
|
||||
IfcSchema::IfcRepresentation* rep = *i;
|
||||
if (rep->declaration().is(IfcSchema::IfcShapeRepresentation::Class()) && rep->RepresentationIdentifier().get_value_or("") == "Body") {
|
||||
door_body = (IfcSchema::IfcShapeRepresentation*) rep;
|
||||
|
||||
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) {
|
||||
if (rep.declaration().is(IfcSchema::IfcShapeRepresentation::Class()) && rep.RepresentationIdentifier().value_or("") == "Body") {
|
||||
door_body = rep.as<IfcSchema::IfcShapeRepresentation>();
|
||||
}
|
||||
}
|
||||
file.addBox(door_body, 80, 80, 2120, 0, file.addPlacement3d(-460, 0, 0));
|
||||
file.addBox(door_body, 1000, 80, 80, 0, file.addPlacement3d( 0, 0, 2120));
|
||||
|
||||
file.addBox(door_body, 80, 80, 2120, IfcSchema::IfcAxis2Placement2D{}, file.addPlacement3d(-460, 0, 0));
|
||||
file.addBox(door_body, 1000, 80, 80, IfcSchema::IfcAxis2Placement2D{}, file.addPlacement3d( 0, 0, 2120));
|
||||
file.addBox(door_body, 860, 30, 2120);
|
||||
file.addBuildingProduct(door);
|
||||
setSurfaceColour(file, door->Representation(), 0.9, 0.9, 0.9);
|
||||
file.addEntity(new IfcSchema::IfcRelFillsElement(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null, null, door_opening, door));
|
||||
|
||||
IfcSchema::IfcDoorStyle* door_style = new IfcSchema::IfcDoorStyle(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), "Door type"s, null, null, null, null, null,
|
||||
IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT, IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD, false, false);
|
||||
setSurfaceColour(file, door.Representation(), 0.9, 0.9, 0.9);
|
||||
{
|
||||
auto rel = file.create<IfcSchema::IfcRelFillsElement>();
|
||||
rel.setGlobalId(guid());
|
||||
rel.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
rel.setRelatingOpeningElement(door_opening);
|
||||
rel.setRelatedBuildingElement(door);
|
||||
}
|
||||
|
||||
auto door_style = file.create<IfcSchema::IfcDoorStyle>();
|
||||
door_style.setGlobalId(guid());
|
||||
door_style.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
door_style.setName("Door type");
|
||||
door_style.setOperationType(IfcSchema::IfcDoorStyleOperationEnum::IfcDoorStyleOperation_SINGLE_SWING_LEFT);
|
||||
door_style.setConstructionType(IfcSchema::IfcDoorStyleConstructionEnum::IfcDoorStyleConstruction_WOOD);
|
||||
door_style.setParameterTakesPrecedence(false);
|
||||
door_style.setSizeable(false);
|
||||
|
||||
// NOTE: typing by IfcDoorStyle will cause validation errors in IFC4+ but it's allowed for backwards compatibility
|
||||
// better to use IfcDoorType in the actual use case
|
||||
file.addRelatedObject<IfcSchema::IfcRelDefinesByType>(door_style, door);
|
||||
@@ -423,23 +466,23 @@ int main() {
|
||||
// Therefore the OverallWidth and OverallHeight of the window attributes will need to
|
||||
// match the bounding box of the representation. Furthermore, the window placement needs
|
||||
// to align with the lowerleft corner of the constituent parts.
|
||||
IfcSchema::IfcShapeRepresentation::list::ptr frame_representations(new IfcSchema::IfcShapeRepresentation::list);
|
||||
std::vector<IfcSchema::IfcShapeRepresentation> frame_representations;
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* horizontal_bar = file.addEmptyRepresentation();
|
||||
IfcSchema::IfcShapeRepresentation* vertical_bar = file.addEmptyRepresentation();
|
||||
auto horizontal_bar = file.addEmptyRepresentation();
|
||||
auto vertical_bar = file.addEmptyRepresentation();
|
||||
file.addBox(horizontal_bar, 1860, 90, 90);
|
||||
file.addBox(vertical_bar, 90, 90, 1420);
|
||||
|
||||
frame_representations->push(horizontal_bar);
|
||||
frame_representations->push(horizontal_bar); // Add another reference to the horizontal bar created above
|
||||
frame_representations->push(vertical_bar);
|
||||
frame_representations->push(vertical_bar); // Add another reference to the vertical bar created above
|
||||
frame_representations.push_back(horizontal_bar);
|
||||
frame_representations.push_back(horizontal_bar); // Add another reference to the horizontal bar created above
|
||||
frame_representations.push_back(vertical_bar);
|
||||
frame_representations.push_back(vertical_bar); // Add another reference to the vertical bar created above
|
||||
|
||||
// The beams all have the same surface style assigned
|
||||
IfcSchema::IfcPresentationStyleAssignment* frame_style = 0;
|
||||
for (IfcSchema::IfcShapeRepresentation::list::it i = frame_representations->begin(); i != frame_representations->end(); i += 2) {
|
||||
IfcSchema::IfcPresentationStyleAssignment frame_style;
|
||||
for (auto i = frame_representations.begin(); i != frame_representations.end(); i += 2) {
|
||||
if (frame_style) {
|
||||
setSurfaceColour(file,*i, frame_style);
|
||||
setSurfaceColour(file, *i, frame_style);
|
||||
} else {
|
||||
frame_style = setSurfaceColour(file,*i, 0.5, 0.4, 0.3);
|
||||
}
|
||||
@@ -448,73 +491,80 @@ int main() {
|
||||
|
||||
// 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.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr window_placements (new IfcSchema::IfcLocalPlacement::list);
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -1770-430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -430-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, 3000-930, -45, 400));
|
||||
window_placements->push(file.addLocalPlacement(storey_placement, -4855+45, 885-930, 400, 0, 0, 1, 0, 1, 0));
|
||||
std::vector<IfcSchema::IfcLocalPlacement> window_placements;
|
||||
window_placements.push_back(file.addLocalPlacement(storey_placement, 2*-1770-430-930, -45, 400));
|
||||
window_placements.push_back(file.addLocalPlacement(storey_placement, -1770-430-930, -45, 400));
|
||||
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 (IfcSchema::IfcLocalPlacement::list::it it = window_placements->begin(); it != window_placements->end(); ++it) {
|
||||
|
||||
// Create the window at the current location
|
||||
IfcSchema::IfcLocalPlacement* place = *it;
|
||||
IfcSchema::IfcWindow* window = new IfcSchema::IfcWindow(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, place, 0, null, 1600, 1860
|
||||
for (auto& place : window_placements) {
|
||||
auto window = file.create<IfcSchema::IfcWindow>();
|
||||
window.setGlobalId(guid());
|
||||
window.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
window.setObjectPlacement(place);
|
||||
window.setOverallWidth(1860);
|
||||
window.setOverallHeight(1600);
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcWindowTypeEnum::IfcWindowType_WINDOW
|
||||
, IfcSchema::IfcWindowTypePartitioningEnum::IfcWindowTypePartitioning_SINGLE_PANEL
|
||||
, null
|
||||
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
|
||||
IfcSchema::IfcObjectDefinition::list::ptr window_parts(new aggregate_of<IfcSchema::IfcObjectDefinition>());
|
||||
std::vector<IfcSchema::IfcObjectDefinition> window_parts;
|
||||
|
||||
// The placements for the beams are not shared across the different windows because every
|
||||
// beam is placed relative to its parent window entity.
|
||||
IfcSchema::IfcLocalPlacement::list::ptr frame_placements (new aggregate_of<IfcSchema::IfcLocalPlacement>());
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930,45));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 930, 45, 1510));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, -885+930, 45, 90));
|
||||
frame_placements->push(file.addLocalPlacement(storey_placement, 885+930, 45, 90));
|
||||
std::vector<IfcSchema::IfcLocalPlacement> frame_placements;
|
||||
frame_placements.push_back(file.addLocalPlacement(storey_placement, 930,45));
|
||||
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
|
||||
IfcSchema::IfcLocalPlacement::list::it frame_placement;
|
||||
IfcSchema::IfcShapeRepresentation::list::it frame_representation;
|
||||
for (frame_placement = frame_placements->begin(), frame_representation = frame_representations->begin();
|
||||
frame_placement != frame_placements->end() && frame_representation != frame_representations->end();
|
||||
std::vector<IfcSchema::IfcLocalPlacement>::const_iterator frame_placement;
|
||||
std::vector<IfcSchema::IfcShapeRepresentation>::const_iterator frame_representation;
|
||||
for (frame_placement = frame_placements.begin(), frame_representation = frame_representations.begin();
|
||||
frame_placement != frame_placements.end() && frame_representation != frame_representations.end();
|
||||
++frame_placement, ++frame_representation)
|
||||
{
|
||||
IfcSchema::IfcMember* frame_part = new IfcSchema::IfcMember(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, null, *frame_placement, file.addMappedItem(*frame_representation), null
|
||||
auto frame_part = file.create<IfcSchema::IfcMember>();
|
||||
frame_part.setGlobalId(guid());
|
||||
frame_part.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
frame_part.setObjectPlacement(*frame_placement);
|
||||
frame_part.setRepresentation(file.addMappedItem(*frame_representation));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcMemberTypeEnum::IfcMemberType_MULLION
|
||||
frame_part.setPredefinedType(IfcSchema::IfcMemberTypeEnum::IfcMemberType_MULLION);
|
||||
#endif
|
||||
);
|
||||
file.addEntity(frame_part);
|
||||
window_parts->push(frame_part);
|
||||
window_parts.push_back(frame_part);
|
||||
file.relatePlacements(window, frame_part);
|
||||
}
|
||||
|
||||
// Add the glass plate to the list of parts
|
||||
IfcSchema::IfcPlate* glass_part = new IfcSchema::IfcPlate(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(), null,
|
||||
null, null, file.addLocalPlacement(storey_placement, 930, 45, 90), file.addBox(1680, 10, 1420), null
|
||||
auto glass_part = file.create<IfcSchema::IfcPlate>();
|
||||
glass_part.setGlobalId(guid());
|
||||
glass_part.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
glass_part.setObjectPlacement(file.addLocalPlacement(storey_placement, 930, 45, 90));
|
||||
glass_part.setRepresentation(file.addBox(1860, 10, 1420));
|
||||
#ifdef USE_IFC4
|
||||
, IfcSchema::IfcPlateTypeEnum::IfcPlateType_SHEET
|
||||
glass_part.setPredefinedType(IfcSchema::IfcPlateTypeEnum::IfcPlateType_SHEET);
|
||||
#endif
|
||||
);
|
||||
file.addEntity(glass_part);
|
||||
window_parts->push(glass_part);
|
||||
|
||||
window_parts.push_back(glass_part);
|
||||
file.relatePlacements(window, glass_part);
|
||||
setSurfaceColour(file,glass_part->Representation(), 0.6, 0.7, 0.75, 0.1);
|
||||
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.
|
||||
IfcSchema::IfcRelDecomposes* decomposition = new IfcSchema::IfcRelAggregates(guid(), file.getSingle<IfcSchema::IfcOwnerHistory>(),
|
||||
null, null, window, window_parts);
|
||||
file.addEntity(decomposition);
|
||||
{
|
||||
|
||||
auto rel = file.create<IfcSchema::IfcRelAggregates>();
|
||||
rel.setGlobalId(guid());
|
||||
rel.setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
rel.setRelatingObject(window);
|
||||
rel.setRelatedObjects(window_parts);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally create a file stream for our output and write the IFC file to it.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -20,9 +20,9 @@
|
||||
// TODO: Multiple schemas
|
||||
#define IfcSchema Ifc2x3
|
||||
|
||||
#include "ifcparse/IfcFile.h"
|
||||
#include "ifcparse/IfcLogger.h"
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "../ifcparse/file.h"
|
||||
#include "../ifcparse/logger.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
@@ -47,7 +47,7 @@ static_assert(false, "A boost preprocessor sequence of schema identifiers is nee
|
||||
// for and then overflow into an existing empty include file.
|
||||
|
||||
#define INCLUDE_SCHEMA(n) \
|
||||
BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(SCHEMA_SEQ), n), BOOST_PP_STRINGIZE(../ifcparse/BOOST_PP_CAT(Ifc,BOOST_PP_SEQ_ELEM(BOOST_PP_MIN(n, BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_POP_BACK(SCHEMA_SEQ))),SCHEMA_SEQ)).h), "../ifcgeom/empty.h")
|
||||
BOOST_PP_IIF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(SCHEMA_SEQ), n), BOOST_PP_STRINGIZE(../ifcparse/schemas/BOOST_PP_CAT(Ifc,BOOST_PP_SEQ_ELEM(BOOST_PP_MIN(n, BOOST_PP_SEQ_SIZE(BOOST_PP_SEQ_POP_BACK(SCHEMA_SEQ))),SCHEMA_SEQ)).h), "../ifcgeom/empty.h")
|
||||
|
||||
#include INCLUDE_SCHEMA(0)
|
||||
#include INCLUDE_SCHEMA(1)
|
||||
@@ -80,7 +80,7 @@ struct is_ifc4_or_higher<T, std::void_t<decltype(T::IfcMaterialDefinition)>> : s
|
||||
|
||||
typedef std::map<std::string, std::map<std::string, std::string>> element_properties;
|
||||
|
||||
std::string format_string(const AttributeValue& argument) {
|
||||
std::string format_string(const attribute_value& argument) {
|
||||
// Argument is a runtime tagged variant for the various data types in a IFC model,
|
||||
// in this particular case we only care about flattening it to a string.
|
||||
// @todo mostly duplicated from XmlSerializer.cpp
|
||||
@@ -89,21 +89,21 @@ std::string format_string(const AttributeValue& argument) {
|
||||
}
|
||||
auto argument_type = argument.type();
|
||||
switch (argument_type) {
|
||||
case IfcUtil::Argument_BOOL: {
|
||||
case ifcopenshell::Argument_BOOL: {
|
||||
const bool b = argument;
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
case IfcUtil::Argument_DOUBLE: {
|
||||
case ifcopenshell::Argument_DOUBLE: {
|
||||
const double d = argument;
|
||||
std::stringstream stream;
|
||||
stream << std::setprecision(std::numeric_limits< double >::max_digits10) << d;
|
||||
return stream.str();
|
||||
break; }
|
||||
case IfcUtil::Argument_STRING:
|
||||
case IfcUtil::Argument_ENUMERATION: {
|
||||
case ifcopenshell::Argument_STRING:
|
||||
case ifcopenshell::Argument_ENUMERATION: {
|
||||
return static_cast<std::string>(argument);
|
||||
break; }
|
||||
case IfcUtil::Argument_INT: {
|
||||
case ifcopenshell::Argument_INT: {
|
||||
const int v = argument;
|
||||
std::stringstream stream;
|
||||
stream << v;
|
||||
@@ -114,44 +114,42 @@ std::string format_string(const AttributeValue& argument) {
|
||||
}
|
||||
|
||||
template <typename Schema, typename T>
|
||||
void process_pset(element_properties& props, const T* inst) {
|
||||
void process_pset(element_properties& props, const T& inst) {
|
||||
// Process an individual Property or Quantity set.
|
||||
if (auto pset = inst->template as<typename Schema::IfcPropertySet>()) {
|
||||
if (!pset->Name()) {
|
||||
if (auto pset = inst.template as<typename Schema::IfcPropertySet>()) {
|
||||
if (!pset.Name()) {
|
||||
return;
|
||||
}
|
||||
auto ps = pset->HasProperties();
|
||||
for (auto it = ps->begin(); it != ps->end(); ++it) {
|
||||
auto& p = *it;
|
||||
if (auto singleval = p->template as<typename Schema::IfcPropertySingleValue>()) {
|
||||
auto ps = pset.HasProperties();
|
||||
for (auto& p : ps) {
|
||||
if (auto singleval = p.template as<typename Schema::IfcPropertySingleValue>()) {
|
||||
std::string propname, propvalue;
|
||||
if constexpr (is_ifc4_or_higher<Schema>::value) {
|
||||
if (!singleval->Name()) {
|
||||
if (!singleval.Name()) {
|
||||
continue;
|
||||
}
|
||||
propname = *singleval->Name();
|
||||
propname = *singleval.Name();
|
||||
}
|
||||
if constexpr (!is_ifc4_or_higher<Schema>::value) {
|
||||
propname = singleval->Name();
|
||||
propname = singleval.Name();
|
||||
}
|
||||
if (!singleval->NominalValue()) {
|
||||
if (!singleval.NominalValue()) {
|
||||
propvalue = "-";
|
||||
} else {
|
||||
props[*pset->Name()][propname] = format_string(singleval->NominalValue()->template as<IfcUtil::IfcBaseClass>()->get_attribute_value(0));
|
||||
props[*pset.Name()][propname] = format_string(singleval.NominalValue().concrete().get_attribute_value(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto qset = inst->template as<typename Schema::IfcElementQuantity>()) {
|
||||
if (!qset->Name()) {
|
||||
if (auto qset = inst.template as<typename Schema::IfcElementQuantity>()) {
|
||||
if (!qset.Name()) {
|
||||
return;
|
||||
}
|
||||
auto qs = qset->Quantities();
|
||||
for (auto it = qs->begin(); it != qs->end(); ++it) {
|
||||
auto& q = *it;
|
||||
if (q->template as<typename Schema::IfcPhysicalSimpleQuantity>() && q->get_attribute_value(3).type() == IfcUtil::Argument_DOUBLE) {
|
||||
double v = q->get_attribute_value(3);
|
||||
props[*qset->Name()][q->Name()] = std::to_string(v);
|
||||
auto qs = qset.Quantities();
|
||||
for (auto& q : qs) {
|
||||
if (q.template as<typename Schema::IfcPhysicalSimpleQuantity>() && q.get_attribute_value(3).type() == ifcopenshell::Argument_DOUBLE) {
|
||||
double v = q.get_attribute_value(3);
|
||||
props[*qset.Name()][q.Name()] = std::to_string(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,49 +161,44 @@ void process_pset(element_properties& props, const T* inst) {
|
||||
}
|
||||
|
||||
template <typename Schema>
|
||||
void get_psets_s(element_properties& props, const typename Schema::IfcObjectDefinition* inst) {
|
||||
void get_psets_s(element_properties& props, const typename Schema::IfcObjectDefinition& inst) {
|
||||
// Extracts the property definitions for an IFC instance.
|
||||
if (auto tyob = inst->template as<typename Schema::IfcTypeObject>()) {
|
||||
if (tyob->HasPropertySets()) {
|
||||
auto defs = *tyob->HasPropertySets();
|
||||
for (auto it = defs->begin(); it != defs->end(); ++it) {
|
||||
auto& def = *it;
|
||||
if (auto tyob = inst.template as<typename Schema::IfcTypeObject>()) {
|
||||
if (tyob.HasPropertySets()) {
|
||||
auto defs = *tyob.HasPropertySets();
|
||||
for (auto& def : defs) {
|
||||
process_pset<Schema>(props, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
if constexpr (is_ifc4_or_higher<Schema>::value) {
|
||||
if (auto mdef = inst->template as<typename Schema::IfcMaterialDefinition>()) {
|
||||
auto defs = mdef->HasProperties();
|
||||
for (auto it = defs->begin(); it != defs->end(); ++it) {
|
||||
auto& def = *it;
|
||||
if (auto mdef = inst.template as<typename Schema::IfcMaterialDefinition>()) {
|
||||
auto defs = mdef.HasProperties();
|
||||
for (auto& def : defs) {
|
||||
process_pset<Schema>(props, def);
|
||||
}
|
||||
}
|
||||
if (auto pdef = inst->template as<typename Schema::IfcProfileDef>()) {
|
||||
if (auto pdef = inst.template as<typename Schema::IfcProfileDef>()) {
|
||||
auto defs = pdef->HasProperties();
|
||||
for (auto it = defs->begin(); it != defs->end(); ++it) {
|
||||
auto& def = *it;
|
||||
for (auto& def : defs) {
|
||||
process_pset<Schema>(props, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (auto ob = inst->template as<typename Schema::IfcObject>()) {
|
||||
if (auto ob = inst.template as<typename Schema::IfcObject>()) {
|
||||
if constexpr (is_ifc4_or_higher<Schema>::value) {
|
||||
auto rels = ob->IsTypedBy();
|
||||
for (auto it = rels->begin(); it != rels->end(); ++it) {
|
||||
auto& rel = *it;
|
||||
auto rels = ob.IsTypedBy();
|
||||
for (auto& rel : rels) {
|
||||
get_psets_s<Schema>(props, rel->RelatingType());
|
||||
}
|
||||
}
|
||||
{
|
||||
auto rels = ob->IsDefinedBy();
|
||||
for (auto it = rels->begin(); it != rels->end(); ++it) {
|
||||
auto& rel = *it;
|
||||
if (auto bytype = rel->template as<typename Schema::IfcRelDefinesByType>()) {
|
||||
get_psets_s<Schema>(props, bytype->RelatingType());
|
||||
} else if (auto byprops = rel->template as<typename Schema::IfcRelDefinesByProperties>()) {
|
||||
process_pset<Schema>(props, byprops->RelatingPropertyDefinition());
|
||||
auto rels = ob.IsDefinedBy();
|
||||
for (auto& rel : rels) {
|
||||
if (auto bytype = rel.template as<typename Schema::IfcRelDefinesByType>()) {
|
||||
get_psets_s<Schema>(props, bytype.RelatingType());
|
||||
} else if (auto byprops = rel.template as<typename Schema::IfcRelDefinesByProperties>()) {
|
||||
process_pset<Schema>(props, byprops.RelatingPropertyDefinition());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,10 +213,10 @@ void get_psets_s(element_properties& props, const typename Schema::IfcObjectDefi
|
||||
#define GENERATE_LITERAL_STRING(elem) "Ifc" # elem
|
||||
|
||||
#define TEST_AND_DISPATCH(r, data, elem) \
|
||||
if (strcasecmp(schema_name, GENERATE_LITERAL_STRING(elem)) == 0) { get_psets_s<EXPAND_AND_CONCATENATE(elem)>(props, inst->as<EXPAND_AND_CONCATENATE(elem)::IfcObjectDefinition>()); }
|
||||
if (strcasecmp(schema_name, GENERATE_LITERAL_STRING(elem)) == 0) { get_psets_s<EXPAND_AND_CONCATENATE(elem)>(props, inst.as<EXPAND_AND_CONCATENATE(elem)::IfcObjectDefinition>()); }
|
||||
|
||||
void get_psets(element_properties& props, const IfcUtil::IfcBaseClass* inst) {
|
||||
auto schema_name = inst->declaration().schema()->name().c_str();
|
||||
void get_psets(element_properties& props, const express::Base& inst) {
|
||||
auto schema_name = inst.declaration().schema()->name().c_str();
|
||||
BOOST_PP_SEQ_FOR_EACH(TEST_AND_DISPATCH, , SCHEMA_SEQ)
|
||||
}
|
||||
|
||||
@@ -234,10 +227,10 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
// Redirect the output (both progress and log) to stdout
|
||||
Logger::SetOutput(&std::cout, &std::cout);
|
||||
logger::set_output(&std::cout, &std::cout);
|
||||
|
||||
// Parse the IFC file provided in argv[1]
|
||||
IfcParse::IfcFile file(argv[1]);
|
||||
ifcopenshell::file file(argv[1]);
|
||||
if (!file.good()) {
|
||||
std::cout << "Unable to parse .ifc file" << std::endl;
|
||||
return 1;
|
||||
@@ -259,19 +252,17 @@ int main(int argc, char** argv) {
|
||||
// we need to cast them to IfcWindows. Since these properties
|
||||
// are optional we need to make sure the properties are
|
||||
// defined for the window in question before accessing them.
|
||||
IfcSchema::IfcBuildingElement::list::ptr elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
|
||||
auto elements = file.instances_by_type<IfcSchema::IfcBuildingElement>();
|
||||
|
||||
std::cout << "Found " << elements->size() << " elements in " << argv[1] << ":" << std::endl;
|
||||
std::cout << "Found " << elements.size() << " elements in " << argv[1] << ":" << std::endl;
|
||||
|
||||
for (auto it = elements->begin(); it != elements->end(); ++it) {
|
||||
const auto* element = *it;
|
||||
element->toString(std::cout);
|
||||
for (auto& element : elements) {
|
||||
element.to_string(std::cout);
|
||||
std::cout << std::endl;
|
||||
|
||||
const IfcSchema::IfcWindow* window;
|
||||
if ((window = element->as<IfcSchema::IfcWindow>()) != 0) {
|
||||
if (window->OverallWidth() && window->OverallHeight()) {
|
||||
const double area = *window->OverallWidth() * *window->OverallHeight();
|
||||
if (auto window = element.as<IfcSchema::IfcWindow>()) {
|
||||
if (window.OverallWidth() && window.OverallHeight()) {
|
||||
const double area = *window.OverallWidth() * *window.OverallHeight();
|
||||
std::cout << "The area of this window is " << area << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
// Disable warnings coming from IfcOpenShell
|
||||
#pragma warning(disable : 4018 4267 4250 4984 4985)
|
||||
|
||||
#include "ifcparse/Ifc4x3_add2.h"
|
||||
#include "ifcparse/IfcAlignmentHelper.h"
|
||||
#include "../ifcparse/Ifc4x3_add2.h"
|
||||
#include "../ifcparse/alignment_helper.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@@ -39,37 +39,49 @@
|
||||
|
||||
// performs basic project setup including created the IfcProject object
|
||||
// and initializing the project units to FEET
|
||||
Schema::IfcProject* setup_project(IfcHierarchyHelper<Schema>& file) {
|
||||
Schema::IfcProject setup_project(hierarchy_helper<Schema>& file) {
|
||||
std::vector<std::string> file_description;
|
||||
file_description.push_back("ViewDefinition[Alignment-basedReferenceView]");
|
||||
file.header().file_description()->setdescription(file_description);
|
||||
file.header().file_description().setdescription(file_description);
|
||||
|
||||
auto project = file.addProject();
|
||||
project->setName(std::string("FHWA Bridge Geometry Manual Example Alignment"));
|
||||
project->setDescription(std::string("C++ Example - Simplified"));
|
||||
project.setName(std::string("FHWA Bridge Geometry Manual Example Alignment"));
|
||||
project.setDescription(std::string("C++ Example - Simplified"));
|
||||
|
||||
// set up project units for feet
|
||||
// the call to file.addProject() sets up length units as millimeter.
|
||||
auto units_in_context = project->UnitsInContext();
|
||||
auto units = units_in_context->Units();
|
||||
auto begin = units->begin();
|
||||
auto units_in_context = project.UnitsInContext();
|
||||
auto units = units_in_context.Units();
|
||||
auto begin = units.begin();
|
||||
auto iter = begin;
|
||||
auto end = units->end();
|
||||
auto end = units.end();
|
||||
for (; iter != end; iter++) {
|
||||
auto unit = *iter;
|
||||
if (unit->as<Schema::IfcSIUnit>() && unit->as<Schema::IfcSIUnit>()->UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) {
|
||||
auto dimensions = new Schema::IfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0);
|
||||
file.addEntity(dimensions);
|
||||
if (unit.as<Schema::IfcSIUnit>() && unit.as<Schema::IfcSIUnit>().UnitType() == Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT) {
|
||||
auto dimensions = file.create<Schema::IfcDimensionalExponents>();
|
||||
dimensions.setLengthExponent(1);
|
||||
dimensions.setMassExponent(0);
|
||||
dimensions.setTimeExponent(0);
|
||||
dimensions.setElectricCurrentExponent(0);
|
||||
dimensions.setThermodynamicTemperatureExponent(0);
|
||||
dimensions.setAmountOfSubstanceExponent(0);
|
||||
dimensions.setLuminousIntensityExponent(0);
|
||||
|
||||
auto conversion_factor = new Schema::IfcMeasureWithUnit(new Schema::IfcLengthMeasure(304.80), unit->as<Schema::IfcSIUnit>());
|
||||
file.addEntity(conversion_factor);
|
||||
auto conversion_factor = file.create<Schema::IfcMeasureWithUnit>();
|
||||
auto length = file.create<Schema::IfcLengthMeasure>();
|
||||
length.set_attribute_value(0, 304.80);
|
||||
conversion_factor.setValueComponent(length);
|
||||
conversion_factor.setUnitComponent(unit);
|
||||
|
||||
auto conversion_based_unit = new Schema::IfcConversionBasedUnit(dimensions, Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT, "FEET", conversion_factor);
|
||||
file.addEntity(conversion_based_unit);
|
||||
auto conversion_based_unit = file.create<Schema::IfcConversionBasedUnit>();
|
||||
conversion_based_unit.setDimensions(dimensions);
|
||||
conversion_based_unit.setUnitType(Schema::IfcUnitEnum::IfcUnit_LENGTHUNIT);
|
||||
conversion_based_unit.setName("FEET");
|
||||
conversion_based_unit.setConversionFactor(conversion_factor);
|
||||
|
||||
units->remove(unit); // remove the millimeter unit
|
||||
units->push(conversion_based_unit); // add the feet unit
|
||||
units_in_context->setUnits(units); // update the UnitsInContext
|
||||
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
|
||||
|
||||
break; // Done!, the length unit was found, so break out of the loop
|
||||
}
|
||||
@@ -79,7 +91,7 @@ Schema::IfcProject* setup_project(IfcHierarchyHelper<Schema>& file) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
IfcHierarchyHelper<Schema> file;
|
||||
hierarchy_helper<Schema> file;
|
||||
|
||||
auto project = setup_project(file);
|
||||
|
||||
@@ -129,10 +141,11 @@ int main() {
|
||||
// IFC 4.1.4.1.1 "Every IfcAlignment must be related to IfcProject using the IfcRelAggregates relationship"
|
||||
// https://standards.buildingsmart.org/IFC/RELEASE/IFC4_3/HTML/concepts/Object_Composition/Aggregation/Alignment_Aggregation_To_Project/content.html
|
||||
// IfcProject <-> IfcRelAggregates <-> IfcAlignment
|
||||
typename aggregate_of<typename Schema::IfcObjectDefinition>::ptr list_of_alignments_in_project(new aggregate_of<typename Schema::IfcObjectDefinition>());
|
||||
list_of_alignments_in_project->push(alignment);
|
||||
auto aggregate_alignments_with_project = new Schema::IfcRelAggregates(IfcParse::IfcGlobalId(), nullptr, std::string("Alignments in project"), boost::none, project, list_of_alignments_in_project);
|
||||
file.addEntity(aggregate_alignments_with_project);
|
||||
auto aggregate_alignments_with_project = file.create<Schema::IfcRelAggregates>();
|
||||
aggregate_alignments_with_project.setGlobalId(ifcopenshell::global_id());
|
||||
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
|
||||
|
||||
@@ -141,24 +154,24 @@ int main() {
|
||||
// IfcSite <-> IfcRelReferencedInSpatialStructure <-> IfcAlignment
|
||||
// This means IfcAlignment is not part of the IfcSite (it is not an aggregate component) but instead IfcAlignment is used within
|
||||
// the IfcSite by reference. This implies an IfcAlignment can traverse many IfcSite instances within an IfcProject
|
||||
typename Schema::IfcSpatialReferenceSelect::list::ptr list_alignments_referenced_in_site(new Schema::IfcSpatialReferenceSelect::list);
|
||||
list_alignments_referenced_in_site->push(alignment);
|
||||
|
||||
// Complete the model by creating sites for the 3 bridges
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
std::ostringstream os;
|
||||
os << "Site of Bridge " << i;
|
||||
auto site = file.addSite(project, nullptr);
|
||||
site->setName(os.str());
|
||||
auto site = file.addSite(project);
|
||||
site.setName(os.str());
|
||||
|
||||
std::ostringstream description;
|
||||
description << "Alignments referenced into the spatial structure of Bridge Site " << i;
|
||||
|
||||
auto rel_referenced_in_spatial_structure = new Schema::IfcRelReferencedInSpatialStructure(IfcParse::IfcGlobalId(), nullptr, boost::none, description.str(), list_alignments_referenced_in_site, site);
|
||||
file.addEntity(rel_referenced_in_spatial_structure);
|
||||
auto rel_referenced_in_spatial_structure = file.create<Schema::IfcRelReferencedInSpatialStructure>();
|
||||
rel_referenced_in_spatial_structure.setGlobalId(ifcopenshell::global_id());
|
||||
rel_referenced_in_spatial_structure.setDescription(description.str());
|
||||
rel_referenced_in_spatial_structure.setRelatedElements(std::vector<Schema::IfcSpatialReferenceSelect>{alignment});
|
||||
rel_referenced_in_spatial_structure.setRelatingStructure(site);
|
||||
}
|
||||
|
||||
// That's it - save the model to a file
|
||||
std::ofstream ofs("IfcSimplifiedAlignment.ifc");
|
||||
std::ofstream ofs("FHWA_Bridge_Geometry_Alignment_Example_Simplified.ifc");
|
||||
ofs << file;
|
||||
}
|
||||
|
||||
@@ -28,16 +28,15 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc4
|
||||
#include "ifcparse/Ifc4.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
static int i = 0;
|
||||
|
||||
void create_product_from_item(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
void create_product_from_item(hierarchy_helper& file, IfcSchema::IfcRepresentationItem* item, const std::string& s) {
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("product"), null, null, 0, 0, null, null);
|
||||
file.addBuildingProduct(product);
|
||||
@@ -50,8 +49,8 @@ void create_product_from_item(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::If
|
||||
items->push(item);
|
||||
|
||||
if (s == "GeometricSet") {
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->as<IfcSchema::IfcGeometricSetSelect>());
|
||||
file.addEntity(set);
|
||||
IfcSchema::IfcGeometricSet* set = new IfcSchema::IfcGeometricSet(items->generalize());
|
||||
file.add_entity(set);
|
||||
items = IfcSchema::IfcRepresentationItem::list::ptr(new IfcSchema::IfcRepresentationItem::list());
|
||||
items->push(set);
|
||||
}
|
||||
@@ -61,55 +60,55 @@ void create_product_from_item(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::If
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
void create_surfaces_from_profile(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::IfcProfileDef* profile) {
|
||||
void create_surfaces_from_profile(hierarchy_helper& file, IfcSchema::IfcProfileDef* profile) {
|
||||
IfcSchema::IfcSurfaceOfLinearExtrusion* extrusion = new IfcSchema::IfcSurfaceOfLinearExtrusion(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
|
||||
file.addEntity(extrusion);
|
||||
file.add_entity(extrusion);
|
||||
|
||||
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
|
||||
IfcSchema::IfcSurfaceOfRevolution* revolution = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), ax1);
|
||||
file.addEntity(ax1);
|
||||
file.addEntity(revolution);
|
||||
file.add_entity(ax1);
|
||||
file.add_entity(revolution);
|
||||
|
||||
create_product_from_item(file, extrusion, "GeometricSet");
|
||||
create_product_from_item(file, revolution, "GeometricSet");
|
||||
}
|
||||
|
||||
void create_solids_from_profile(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::IfcProfileDef* profile) {
|
||||
void create_solids_from_profile(hierarchy_helper& file, IfcSchema::IfcProfileDef* profile) {
|
||||
IfcSchema::IfcExtrudedAreaSolid* extrusion = new IfcSchema::IfcExtrudedAreaSolid(profile, file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 100.);
|
||||
file.addEntity(extrusion);
|
||||
file.add_entity(extrusion);
|
||||
|
||||
IfcSchema::IfcAxis1Placement* ax1 = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0,100,0), file.addTriplet<IfcSchema::IfcDirection>(1,0,0));
|
||||
IfcSchema::IfcRevolvedAreaSolid* revolution1 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 360.);
|
||||
IfcSchema::IfcRevolvedAreaSolid* revolution2 = new IfcSchema::IfcRevolvedAreaSolid(profile, file.addPlacement3d(), ax1, 90.);
|
||||
file.addEntity(ax1);
|
||||
file.addEntity(revolution1);
|
||||
file.addEntity(revolution2);
|
||||
file.add_entity(ax1);
|
||||
file.add_entity(revolution1);
|
||||
file.add_entity(revolution2);
|
||||
|
||||
create_product_from_item(file, extrusion, "SweptSolid");
|
||||
create_product_from_item(file, revolution1, "SweptSolid");
|
||||
create_product_from_item(file, revolution2, "SweptSolid");
|
||||
}
|
||||
|
||||
void create_products_from_curve(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::IfcBoundedCurve* curve) {
|
||||
void create_products_from_curve(hierarchy_helper& file, IfcSchema::IfcBoundedCurve* curve) {
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* open = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, null, curve);
|
||||
IfcSchema::IfcCenterLineProfileDef* center_line = new IfcSchema::IfcCenterLineProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, curve, 10.);
|
||||
file.addEntity(open);
|
||||
file.addEntity(center_line);
|
||||
file.add_entity(open);
|
||||
file.add_entity(center_line);
|
||||
|
||||
create_surfaces_from_profile(file, open);
|
||||
create_solids_from_profile(file, center_line);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "arbitrary_open_profile_def.ifc";
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname(filename);
|
||||
const char filename[] = "IfcArbitraryOpenProfileDef.ifc";
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {-50.0, 0.0};
|
||||
double coords2[] = { 50.0, 0.0};
|
||||
@@ -118,24 +117,23 @@ int main(int argc, char** argv) {
|
||||
points->push(new IfcSchema::IfcCartesianPoint(std::vector<double>(coords2, coords2+2)));
|
||||
file.addEntities(points->generalize());
|
||||
IfcSchema::IfcPolyline* poly = new IfcSchema::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
file.add_entity(poly);
|
||||
|
||||
create_products_from_curve(file, poly);
|
||||
|
||||
IfcSchema::IfcEllipse* ellipse = new IfcSchema::IfcEllipse(file.addPlacement2d(), 50., 25.);
|
||||
file.addEntity(ellipse);
|
||||
aggregate_of_instance::ptr trim1(new aggregate_of_instance);
|
||||
aggregate_of_instance::ptr trim2(new aggregate_of_instance);
|
||||
file.add_entity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
trim1->push(new IfcSchema::IfcParameterValue( 0.));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(180.));
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1->as<IfcSchema::IfcTrimmingSelect>(), trim2->as<IfcSchema::IfcTrimmingSelect>(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trim);
|
||||
IfcSchema::IfcTrimmedCurve* trim = new IfcSchema::IfcTrimmedCurve(ellipse, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.add_entity(trim);
|
||||
|
||||
create_products_from_curve(file, trim);
|
||||
|
||||
using namespace std::string_literals;
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("arbitrary_open_profile_def"s);
|
||||
file.getSingle<Ifc2x3::IfcProject>()->setName("IfcArbitraryOpenProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,18 +27,18 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "composite_profile_def.ifc";
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname(filename);
|
||||
const char filename[] = "IfcCompositeProfileDef.ifc";
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
double coords1[] = {100.0, 0.0};
|
||||
double coords2[] = {200.0, 0.0};
|
||||
@@ -65,11 +65,11 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, file.addPlacement2d(80.), 50.0, 25.0, 5.0, 10.0, 2.0, null);
|
||||
|
||||
file.addEntity(p2);
|
||||
file.addEntity(p3);
|
||||
file.add_entity(p2);
|
||||
file.add_entity(p3);
|
||||
|
||||
file.addEntity(transform1);
|
||||
file.addEntity(transform2);
|
||||
file.add_entity(transform1);
|
||||
file.add_entity(transform2);
|
||||
|
||||
IfcSchema::IfcDerivedProfileDef* p5 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p2, transform1, null);
|
||||
IfcSchema::IfcDerivedProfileDef* p6 = new IfcSchema::IfcDerivedProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA, null, p3, transform2, null);
|
||||
@@ -95,8 +95,8 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(composite,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(composite);
|
||||
file.addEntity(solid);
|
||||
file.add_entity(composite);
|
||||
file.add_entity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
@@ -107,13 +107,12 @@ int main(int argc, char** argv) {
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
using namespace std::string_literals;
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("composite_profile_def"s);
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcCompositeProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
class Node {
|
||||
@@ -101,7 +101,7 @@ public:
|
||||
return operate(OP_INTERSECT, p);
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentationItem* serialize(IfcHierarchyHelper<IfcSchema>& file) const {
|
||||
IfcSchema::IfcRepresentationItem* serialize(hierarchy_helper& file) const {
|
||||
IfcSchema::IfcRepresentationItem* my;
|
||||
if (op == OP_TERMINAL) {
|
||||
IfcSchema::IfcAxis2Placement3D* place = file.addPlacement3d(x,y,z,zx,zy,zz,xx,xy,xz);
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
my = new IfcSchema::IfcRightCircularCone(place, b, a);
|
||||
}
|
||||
} else {
|
||||
IfcSchema::IfcBooleanOperator o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION;
|
||||
IfcSchema::IfcBooleanOperator::IfcBooleanOperator o;
|
||||
if (op == OP_ADD) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION;
|
||||
} else if (op == OP_SUBTRACT) {
|
||||
@@ -125,17 +125,17 @@ public:
|
||||
} else if (op == OP_INTERSECT) {
|
||||
o = IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION;
|
||||
}
|
||||
my = new IfcSchema::IfcBooleanResult(o, left->serialize(file)->as<IfcSchema::IfcBooleanOperand>(), right->serialize(file)->as<IfcSchema::IfcBooleanOperand>());
|
||||
my = new IfcSchema::IfcBooleanResult(o, left->serialize(file), right->serialize(file));
|
||||
}
|
||||
file.addEntity(my);
|
||||
file.add_entity(my);
|
||||
return my;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char filename[] = "csg_primitive.ifc";
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname(filename);
|
||||
const char filename[] = "IfcCsgPrimitive.ifc";
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name(filename);
|
||||
|
||||
IfcSchema::IfcRepresentationItem* csg1 = Node::Box(8000.,6000.,3000.).subtract(
|
||||
Node::Box(7600.,5600.,2800.).move(200.,200.,200.)
|
||||
@@ -181,13 +181,12 @@ int main(int argc, char** argv) {
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
|
||||
using namespace std::string_literals;
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("csg_primitive"s);
|
||||
file.getSingle<IfcSchema::IfcProject>()->setName("IfcCompositeProfileDef");
|
||||
|
||||
std::ofstream f(filename);
|
||||
f << file;
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
typedef struct {
|
||||
@@ -44,7 +44,7 @@ typedef struct {
|
||||
|
||||
static int i = 0;
|
||||
|
||||
void create_testcase_for(IfcHierarchyHelper<IfcSchema>& file, const EllipsePie& pie, IfcSchema::IfcTrimmingPreference pref) {
|
||||
void create_testcase_for(hierarchy_helper& file, const EllipsePie& pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference pref) {
|
||||
const double deg = 1. / 180. * 3.141592653;
|
||||
double flt1[] = {0. , 0. };
|
||||
double flt2[] = {pie.r1 * cos(pie.t1*deg), pie.r2 * sin(pie.t1*deg)};
|
||||
@@ -66,24 +66,24 @@ void create_testcase_for(IfcHierarchyHelper<IfcSchema>& file, const EllipsePie&
|
||||
|
||||
|
||||
Ifc2x3::IfcEllipse* ellipse = new Ifc2x3::IfcEllipse(file.addPlacement2d(), pie.r1, pie.r2);
|
||||
file.addEntity(ellipse);
|
||||
aggregate_of_instance::ptr trim1(new aggregate_of_instance);
|
||||
aggregate_of_instance::ptr trim2(new aggregate_of_instance);
|
||||
if (pref == IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
file.add_entity(ellipse);
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
if (pref == Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER) {
|
||||
trim1->push(new Ifc2x3::IfcParameterValue(pie.t1));
|
||||
trim2->push(new Ifc2x3::IfcParameterValue(pie.t2));
|
||||
} else {
|
||||
trim1->push(p2);
|
||||
trim2->push(p3);
|
||||
}
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1->as<IfcSchema::IfcTrimmingSelect>(), trim2->as<IfcSchema::IfcTrimmingSelect>(), true, pref);
|
||||
file.addEntity(trim);
|
||||
Ifc2x3::IfcTrimmedCurve* trim = new Ifc2x3::IfcTrimmedCurve(ellipse, trim1, trim2, true, pref);
|
||||
file.add_entity(trim);
|
||||
|
||||
Ifc2x3::IfcCompositeCurveSegment::list::ptr segments(new Ifc2x3::IfcCompositeCurveSegment::list());
|
||||
Ifc2x3::IfcCompositeCurveSegment* s2 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, trim);
|
||||
|
||||
Ifc2x3::IfcPolyline* poly = new Ifc2x3::IfcPolyline(points);
|
||||
file.addEntity(poly);
|
||||
file.add_entity(poly);
|
||||
Ifc2x3::IfcCompositeCurveSegment* s1 = new Ifc2x3::IfcCompositeCurveSegment(Ifc2x3::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly);
|
||||
segments->push(s1);
|
||||
|
||||
@@ -92,8 +92,8 @@ void create_testcase_for(IfcHierarchyHelper<IfcSchema>& file, const EllipsePie&
|
||||
|
||||
Ifc2x3::IfcCompositeCurve* ccurve = new Ifc2x3::IfcCompositeCurve(segments, false);
|
||||
Ifc2x3::IfcArbitraryClosedProfileDef* profile = new Ifc2x3::IfcArbitraryClosedProfileDef(Ifc2x3::IfcProfileTypeEnum::IfcProfileType_AREA, null, ccurve);
|
||||
file.addEntity(ccurve);
|
||||
file.addEntity(profile);
|
||||
file.add_entity(ccurve);
|
||||
file.add_entity(profile);
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("profile"), null, null, 0, 0, null, null);
|
||||
@@ -105,7 +105,7 @@ void create_testcase_for(IfcHierarchyHelper<IfcSchema>& file, const EllipsePie&
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(solid);
|
||||
file.add_entity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list());
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list());
|
||||
@@ -116,33 +116,33 @@ void create_testcase_for(IfcHierarchyHelper<IfcSchema>& file, const EllipsePie&
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::string filename = "ellipse_pies.ifc";
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
hierarchy_helper file;
|
||||
{ EllipsePie pie = {80., 50., 0., 150.};
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {80, 50., 30., 300.};
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {80, 50., 300., 30.};
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50., 80., 0., 150.};
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50, 80., 30., 300.};
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
{ EllipsePie pie = {50, 80., 300., 30.};
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
create_testcase_for(file, pie, Ifc2x3::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);}
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
|
||||
+14
-15
@@ -22,19 +22,18 @@
|
||||
* Example that generates various forms of IfcFace *
|
||||
* *
|
||||
********************************************************************************/
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
static int x = 0;
|
||||
|
||||
void create_testcase(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::IfcFace* face, const std::string& name) {
|
||||
void create_testcase(hierarchy_helper& file, IfcSchema::IfcFace* face, const std::string& name) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
faces->push(face);
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
@@ -58,14 +57,14 @@ void create_testcase(IfcHierarchyHelper<IfcSchema>& file, IfcSchema::IfcFace* fa
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
hierarchy_helper file;
|
||||
{
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points (new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(file.addTriplet<IfcSchema::IfcCartesianPoint>(-400, -400, 0));
|
||||
@@ -193,7 +192,7 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr trim2(new IfcSchema::IfcCartesianPoint::list);
|
||||
trim1->push(point1);
|
||||
trim2->push(point2);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize()->as<IfcSchema::IfcTrimmingSelect>(), trim2->generalize()->as<IfcSchema::IfcTrimmingSelect>(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1->generalize(), trim2->generalize(), true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_CARTESIAN);
|
||||
IfcSchema::IfcArbitraryOpenProfileDef* profile = new IfcSchema::IfcArbitraryOpenProfileDef(IfcSchema::IfcProfileTypeEnum::IfcProfileType_CURVE, boost::none, trimmed_curve);
|
||||
IfcSchema::IfcAxis1Placement* place = new IfcSchema::IfcAxis1Placement(file.addTriplet<IfcSchema::IfcCartesianPoint>(0., 0., 0.), file.addTriplet<IfcSchema::IfcDirection>(1., 0., 0.));
|
||||
IfcSchema::IfcSurfaceOfRevolution* surface = new IfcSchema::IfcSurfaceOfRevolution(profile, file.addPlacement3d(), place);
|
||||
@@ -201,8 +200,8 @@ int main(int argc, char** argv) {
|
||||
IfcSchema::IfcFace* face = new IfcSchema::IfcFaceSurface(bounds, surface, true);
|
||||
create_testcase(file, face, "face surface");
|
||||
}
|
||||
const char filename[] = "faces.ifc";
|
||||
file.header().file_name()->setname(filename);
|
||||
std::ofstream f(filename);
|
||||
const std::string filename = "faces.ifc";
|
||||
file.header().file_name().name(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,24 +27,22 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
const static double PI = boost::math::constants::pi<double>();
|
||||
#include "ifcparse\Ifc2x3.h"
|
||||
#include "ifcparse\IfcUtil.h"
|
||||
#include "ifcparse\hierarchy_helper.h"
|
||||
#include "ifcgeom\IfcGeom.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
boost::none_t const null = boost::none;
|
||||
|
||||
void create_curve_rebar(IfcHierarchyHelper<IfcSchema>& file)
|
||||
void create_curve_rebar(hierarchy_helper& file)
|
||||
{
|
||||
int dia = 24;
|
||||
int R = 3 * dia;
|
||||
int length = 12 * dia;
|
||||
|
||||
double crossSectionarea = PI * dia * dia / 4;
|
||||
double crossSectionarea = M_PI * (dia / 2) * 2;
|
||||
IfcSchema::IfcReinforcingBar* rebar = new IfcSchema::IfcReinforcingBar(
|
||||
guid(), 0, S("test"), null,
|
||||
null, 0, 0,
|
||||
@@ -73,32 +71,31 @@ void create_curve_rebar(IfcHierarchyHelper<IfcSchema>& file)
|
||||
points1->push(p2);
|
||||
file.addEntities(points1->generalize());
|
||||
IfcSchema::IfcPolyline* poly1 = new IfcSchema::IfcPolyline(points1);
|
||||
file.addEntity(poly1);
|
||||
file.add_entity(poly1);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment1 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly1);
|
||||
file.addEntity(segment1);
|
||||
file.add_entity(segment1);
|
||||
segments->push(segment1);
|
||||
|
||||
/*second segment - arc */
|
||||
IfcSchema::IfcAxis2Placement3D* axis1 = new IfcSchema::IfcAxis2Placement3D(p3, file.addTriplet<IfcSchema::IfcDirection>(1, 0, 0), file.addTriplet<IfcSchema::IfcDirection>(0, 1, 0));
|
||||
file.addEntity(axis1);
|
||||
file.add_entity(axis1);
|
||||
IfcSchema::IfcCircle* circle = new IfcSchema::IfcCircle(axis1, R);
|
||||
file.addEntity(circle);
|
||||
file.add_entity(circle);
|
||||
|
||||
IfcEntityList::ptr trim1(new IfcEntityList);
|
||||
IfcEntityList::ptr trim2(new IfcEntityList);
|
||||
|
||||
IfcSchema::IfcTrimmingSelect::list::ptr trim1(new IfcSchema::IfcTrimmingSelect::list);
|
||||
IfcSchema::IfcTrimmingSelect::list::ptr trim2(new IfcSchema::IfcTrimmingSelect::list);
|
||||
|
||||
trim1->push(new IfcSchema::IfcParameterValue(180));
|
||||
trim1->push(p2);
|
||||
|
||||
trim2->push(new IfcSchema::IfcParameterValue(270));
|
||||
trim2->push(p4);
|
||||
|
||||
IfcSchema::IfcTrimmedCurve* trimmed_curve = new IfcSchema::IfcTrimmedCurve(circle, trim1, trim2, false, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
file.addEntity(trimmed_curve);
|
||||
file.add_entity(trimmed_curve);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment2 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTSAMEGRADIENT, false, trimmed_curve);
|
||||
file.addEntity(segment2);
|
||||
file.add_entity(segment2);
|
||||
segments->push(segment2);
|
||||
|
||||
/*third segment - line */
|
||||
@@ -107,14 +104,14 @@ void create_curve_rebar(IfcHierarchyHelper<IfcSchema>& file)
|
||||
points2->push(p5);
|
||||
file.addEntities(points2->generalize());
|
||||
IfcSchema::IfcPolyline* poly2 = new IfcSchema::IfcPolyline(points2);
|
||||
file.addEntity(poly2);
|
||||
file.add_entity(poly2);
|
||||
|
||||
IfcSchema::IfcCompositeCurveSegment* segment3 = new IfcSchema::IfcCompositeCurveSegment(IfcSchema::IfcTransitionCode::IfcTransitionCode_CONTINUOUS, true, poly2);
|
||||
file.addEntity(segment3);
|
||||
file.add_entity(segment3);
|
||||
segments->push(segment3);
|
||||
|
||||
IfcSchema::IfcCompositeCurve* curve = new IfcSchema::IfcCompositeCurve(segments, false);
|
||||
file.addEntity(curve);
|
||||
file.add_entity(curve);
|
||||
|
||||
IfcSchema::IfcSweptDiskSolid* solid = new IfcSchema::IfcSweptDiskSolid(curve, dia / 2, null, 0, 1);
|
||||
|
||||
@@ -126,7 +123,7 @@ void create_curve_rebar(IfcHierarchyHelper<IfcSchema>& file)
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(shape);
|
||||
file.add_entity(shape);
|
||||
|
||||
rebar->setRepresentation(shape);
|
||||
|
||||
@@ -136,8 +133,8 @@ void create_curve_rebar(IfcHierarchyHelper<IfcSchema>& file)
|
||||
|
||||
int main()
|
||||
{
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname("ifc_curve_rebar.ifc");
|
||||
hierarchy_helper file;
|
||||
file.header().file_name().name("ifc_curve_rebar.ifc");
|
||||
create_curve_rebar(file);
|
||||
std::ofstream f("ifc_curve_rebar.ifc");
|
||||
f << file;
|
||||
|
||||
+44
-45
@@ -27,21 +27,21 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define IfcSchema Ifc2x3
|
||||
#include "ifcparse/Ifc2x3.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc2x3.h"
|
||||
#include "../ifcparse/IfcUtil.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef IfcWrite::IfcGuidHelper guid;
|
||||
boost::none_t const null = (static_cast<boost::none_t>(0));
|
||||
|
||||
void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
IfcSchema::IfcProfileDef* profile = *profiles->begin();
|
||||
const std::string& profile_type = profile->declaration().name();
|
||||
const std::string profile_type = IfcSchema::Type::ToString(profile->type());
|
||||
const std::string filename = profile_type + ".ifc";
|
||||
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
file.header().file_name()->setname(filename);
|
||||
hierarchy_helper file;
|
||||
file.filename(filename);
|
||||
|
||||
int i = 0;
|
||||
for (IfcSchema::IfcProfileDef::list::it it = profiles->begin(); it != profiles->end(); ++it, ++i) {
|
||||
@@ -54,15 +54,15 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement(0, 100. * i));
|
||||
|
||||
if (profile->declaration().is(IfcSchema::IfcParameterizedProfileDef::Class())) {
|
||||
if (profile->is(IfcSchema::Type::IfcParameterizedProfileDef)) {
|
||||
((IfcSchema::IfcParameterizedProfileDef*) profile)->setPosition(file.addPlacement2d());
|
||||
}
|
||||
|
||||
IfcSchema::IfcExtrudedAreaSolid* solid = new IfcSchema::IfcExtrudedAreaSolid(profile,
|
||||
file.addPlacement3d(), file.addTriplet<IfcSchema::IfcDirection>(0, 0, 1), 20.0);
|
||||
|
||||
file.addEntity(profile);
|
||||
file.addEntity(solid);
|
||||
file.add_entity(profile);
|
||||
file.add_entity(solid);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
@@ -72,9 +72,9 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
file.getSingle<IfcSchema::IfcRepresentationContext>(), S("Body"), S("SweptSolid"), items);
|
||||
reps->push(rep);
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(null, null, reps);
|
||||
file.addEntity(rep);
|
||||
file.addEntity(shape);
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(0, 0, reps);
|
||||
file.add_entity(rep);
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
}
|
||||
@@ -84,123 +84,122 @@ void create_testcase_for(IfcSchema::IfcProfileDef::list::ptr profiles) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcSchema::get_schema(); // Ensure schema is initialized
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null));
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0, null, null));
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, 4.0, null));
|
||||
profiles->push(new IfcSchema::IfcUShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcUShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 1.0, 3.0, 6.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, null, null, null));
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0, 2.0, null, null, null));
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null, null, 2.0, 2.0, null));
|
||||
profiles->push(new IfcSchema::IfcTShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 3.0, 2.0, 1.0, 2.0, 2.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcZShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, null, null));
|
||||
profiles->push(new IfcSchema::IfcZShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcZShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 5.0, 2.0, 2.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcEllipseProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 15.0));
|
||||
profiles->push(new IfcSchema::IfcEllipseProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcEllipseProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 15.0, 25.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcIShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, null));
|
||||
profiles->push(new IfcSchema::IfcIShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0));
|
||||
profiles->push(new IfcSchema::IfcAsymmetricIShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcAsymmetricIShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 50.0, 5.0, 5.0, 2.0, 20.0, 10.0, 5.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, null, null, null));
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 2.0, null, null, null));
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null, 2.0, null, null));
|
||||
profiles->push(new IfcSchema::IfcLShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcLShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 1.0, 2.0, 2.0, null, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcCShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, null, null));
|
||||
profiles->push(new IfcSchema::IfcCShapeProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcCShapeProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 10.0, 2.0, null));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcCircleProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcCircleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0));
|
||||
profiles->push(new IfcSchema::IfcCircleHollowProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcCircleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 25.0, 5.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcRectangleProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0));
|
||||
profiles->push(new IfcSchema::IfcRoundedRectangleProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcRoundedRectangleProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0));
|
||||
profiles->push(new IfcSchema::IfcRectangleHollowProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, null, null));
|
||||
profiles->push(new IfcSchema::IfcRectangleHollowProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcRectangleHollowProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 25.0, 5.0, 2.0, 4.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
{ IfcSchema::IfcProfileDef::list::ptr profiles (new IfcSchema::IfcProfileDef::list);
|
||||
profiles->push(new IfcSchema::IfcTrapeziumProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 30.0, 25.0, 0.0));
|
||||
profiles->push(new IfcSchema::IfcTrapeziumProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 60.0, 25.0, -20.0));
|
||||
profiles->push(new IfcSchema::IfcTrapeziumProfileDef(
|
||||
profiles->push(new Ifc2x3::IfcTrapeziumProfileDef(
|
||||
IfcSchema::IfcProfileTypeEnum::IfcProfileType_AREA,
|
||||
null, 0, 50.0, 10.0, 25.0, 30.0));
|
||||
create_testcase_for(profiles); }
|
||||
|
||||
@@ -23,19 +23,15 @@
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
#define IfcSchema Ifc4
|
||||
#include "ifcparse/Ifc4.h"
|
||||
#include "ifcparse/IfcHierarchyHelper.h"
|
||||
#include "../ifcparse/schemas/Ifc4.h"
|
||||
#include "../ifcparse/hierarchy_helper.h"
|
||||
|
||||
#include "suzanne_geometry.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
typedef std::string S;
|
||||
typedef IfcParse::IfcGlobalId guid;
|
||||
boost::none_t const null = boost::none;
|
||||
typedef ifcopenshell::global_id guid;
|
||||
|
||||
template <typename T>
|
||||
std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned size) {
|
||||
@@ -54,36 +50,31 @@ std::vector< std::vector<T> > create_vector_from_array(const T* arr, unsigned si
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
IfcHierarchyHelper<IfcSchema> file;
|
||||
hierarchy_helper<Ifc4> file;
|
||||
|
||||
IfcSchema::IfcBuildingElementProxy* product = new IfcSchema::IfcBuildingElementProxy(
|
||||
guid(), 0, S("Blender's Suzanne"), null, null, 0, 0, null, null);
|
||||
Ifc4::IfcBuildingElementProxy product = file.create<Ifc4::IfcBuildingElementProxy>().initialize(
|
||||
guid(), std::nullopt, S("Blender's Suzanne"), std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt);
|
||||
file.addBuildingProduct(product);
|
||||
product->setOwnerHistory(file.getSingle<IfcSchema::IfcOwnerHistory>());
|
||||
product.setOwnerHistory(file.getSingle<Ifc4::IfcOwnerHistory>());
|
||||
|
||||
product->setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps (new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items (new IfcSchema::IfcRepresentationItem::list);
|
||||
product.setObjectPlacement(file.addLocalPlacement());
|
||||
|
||||
std::vector< std::vector< double > > vertices_vector = create_vector_from_array(vertices, sizeof(vertices) / sizeof(vertices[0]));
|
||||
std::vector< std::vector< int > > indices_vector = create_vector_from_array(indices, sizeof(indices) / sizeof(indices[0]));
|
||||
|
||||
IfcSchema::IfcCartesianPointList3D* coordinates = new IfcSchema::IfcCartesianPointList3D(vertices_vector);
|
||||
IfcSchema::IfcTriangulatedFaceSet* faceset = new IfcSchema::IfcTriangulatedFaceSet(coordinates, null, null, indices_vector, null);
|
||||
Ifc4::IfcCartesianPointList3D coordinates = file.create<Ifc4::IfcCartesianPointList3D>().initialize(vertices_vector);
|
||||
Ifc4::IfcTriangulatedFaceSet faceset = file.create<Ifc4::IfcTriangulatedFaceSet>().initialize(coordinates, std::nullopt, std::nullopt, indices_vector, std::nullopt);
|
||||
|
||||
items->push(faceset);
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
file.getRepresentationContext("Model"), S("Body"), S("SurfaceModel"), items);
|
||||
reps->push(rep);
|
||||
Ifc4::IfcShapeRepresentation rep = file.create<Ifc4::IfcShapeRepresentation>().initialize(
|
||||
file.getRepresentationContext("Model"), "Body", "SurfaceModel", {faceset});
|
||||
|
||||
IfcSchema::IfcProductDefinitionShape* shape = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
file.addEntity(shape);
|
||||
Ifc4::IfcProductDefinitionShape shape = file.create<Ifc4::IfcProductDefinitionShape>().initialize(std::nullopt, std::nullopt, {rep});
|
||||
file.add_entity(shape);
|
||||
|
||||
product->setRepresentation(shape);
|
||||
product.setRepresentation(shape);
|
||||
|
||||
const std::string filename = "triangulated_faceset.ifc";
|
||||
file.header().file_name()->setname(filename);
|
||||
std::ofstream f(filename);
|
||||
const std::string filename = "tesselated_faceset.ifc";
|
||||
file.header().file_name().setname(filename);
|
||||
std::ofstream f(filename.c_str());
|
||||
f << file;
|
||||
}
|
||||
|
||||
@@ -457,7 +457,7 @@ class context:
|
||||
|
||||
for f in self.fs:
|
||||
if kwargs.keys() == {'include'}:
|
||||
kwargs2 = {'include': [e for e in kwargs['include'] if e.wrapped_data.file == f]}
|
||||
kwargs2 = {'include': [e for e in kwargs['include'] if e.file == f]}
|
||||
else:
|
||||
kwargs2 = kwargs
|
||||
it = ifcopenshell.geom.iterator(s, f, geometry_library="cgal", **kwargs2)
|
||||
|
||||
@@ -168,7 +168,7 @@ class ifc5D2json:
|
||||
data["UnitSymbol"] = ifcopenshell.util.unit.get_unit_symbol(unit)
|
||||
if quantity.is_a("IfcPhysicalSimpleQuantity"):
|
||||
measure_class = (
|
||||
quantity.wrapped_data.declaration()
|
||||
quantity.declaration()
|
||||
.as_entity()
|
||||
.attribute_by_index(3)
|
||||
.type_of_attribute()
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
# IfcConvert
|
||||
if(WITH_RELATIONSHIP_VALIDATION)
|
||||
file(GLOB IFCCONVERT_CPP_FILES *.cpp)
|
||||
file(GLOB IFCCONVERT_H_FILES *.h)
|
||||
else()
|
||||
file(GLOB IFCCONVERT_CPP_FILES IfcConvert.cpp)
|
||||
file(GLOB IFCCONVERT_H_FILES)
|
||||
endif()
|
||||
set(IFCCONVERT_FILES ${IFCCONVERT_CPP_FILES} ${IFCCONVERT_H_FILES})
|
||||
add_executable(IfcConvert ${IFCCONVERT_FILES})
|
||||
add_executable(IfcConvert IfcConvert.cpp)
|
||||
|
||||
target_link_libraries(
|
||||
IfcConvert
|
||||
PRIVATE
|
||||
IfcGeom
|
||||
IfcParse
|
||||
Serializers
|
||||
${kernel_libraries}
|
||||
${OpenCASCADE_LIBRARIES}
|
||||
${Boost_LIBRARIES}
|
||||
${HDF5_LIBRARIES}
|
||||
${USD_LIBRARIES}
|
||||
${CGAL_LIBRARIES}
|
||||
${GLTF_LIBRARIES}
|
||||
target_link_libraries(IfcConvert PRIVATE IfcGeom IfcParse ${Boost_LIBRARIES})
|
||||
if(kernel_libraries OR mapping_libraries OR geometry_serializer_libraries OR document_serializer_libraries)
|
||||
add_dependencies(IfcConvert ${kernel_libraries} ${mapping_libraries} ${geometry_serializer_libraries} ${document_serializer_libraries})
|
||||
endif()
|
||||
|
||||
set(_plugin_targets
|
||||
${kernel_libraries}
|
||||
${mapping_libraries}
|
||||
${geometry_serializer_libraries}
|
||||
${document_serializer_libraries}
|
||||
)
|
||||
|
||||
install(TARGETS IfcConvert EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
set(_plugin_paths "")
|
||||
foreach(t IN LISTS _plugin_targets)
|
||||
string(APPEND _plugin_paths ";$<TARGET_FILE_DIR:${t}>")
|
||||
endforeach()
|
||||
|
||||
set_target_properties(IfcConvert PROPERTIES
|
||||
VS_DEBUGGER_ENVIRONMENT
|
||||
"PATH=%PATH%;$<JOIN:$<TARGET_RUNTIME_DLL_DIRS:IfcConvert>,;>;${_plugin_paths}"
|
||||
)
|
||||
|
||||
install(TARGETS IfcConvert)
|
||||
|
||||
+359
-530
File diff suppressed because it is too large
Load Diff
@@ -18,29 +18,29 @@ typedef CGAL::AABB_traits<Kernel_, Primitive> Traits;
|
||||
typedef CGAL::AABB_tree<Traits> Tree;
|
||||
typedef Tree::Point_and_primitive_id Point_and_primitive_id;
|
||||
|
||||
void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
void fix_spaceboundaries(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
intersection_validator v(f, { "IfcWall", "IfcSpace", "IfcSlab", "IfcCovering" }, 1.e-5, no_progress, quiet, stderr_progress);
|
||||
|
||||
auto rels = f.instances_by_type("IfcRelSpaceBoundary");
|
||||
|
||||
std::map<std::pair<const IfcUtil::IfcBaseClass*, const IfcUtil::IfcBaseClass*>, const IfcUtil::IfcBaseClass*> rel_by_space_elem;
|
||||
std::map<std::pair<const ifcopenshell::IfcBaseClass*, const ifcopenshell::IfcBaseClass*>, const ifcopenshell::IfcBaseClass*> rel_by_space_elem;
|
||||
|
||||
|
||||
if (rels) {
|
||||
std::for_each(rels->begin(), rels->end(), [&rel_by_space_elem](const IfcUtil::IfcBaseClass* rel) {
|
||||
auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingSpace");
|
||||
std::for_each(rels->begin(), rels->end(), [&rel_by_space_elem](const ifcopenshell::IfcBaseClass* rel) {
|
||||
auto x = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingSpace");
|
||||
try {
|
||||
auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedBuildingElement");
|
||||
auto y = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatedBuildingElement");
|
||||
rel_by_space_elem.insert({ { x,y }, rel });
|
||||
} catch (IfcParse::IfcException&) {
|
||||
} catch (ifcopenshell::exception&) {
|
||||
// RelatedBuildingElement can be NULL
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::set<const IfcUtil::IfcBaseClass*> rels_encounted;
|
||||
std::set<const ifcopenshell::IfcBaseClass*> rels_encounted;
|
||||
|
||||
IfcParse::IfcFile f2("boundaries-triangulated.ifc");
|
||||
ifcopenshell::file f2("boundaries-triangulated.ifc");
|
||||
if (!f2.good()) {
|
||||
return;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
std::map<std::set<std::string>, std::vector<Kernel_::Point_3>> elem_to_space_boundary_coords;
|
||||
|
||||
for (auto& i : *f2.instances_by_type("IfcProduct")) {
|
||||
auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value<std::string>("Name");
|
||||
auto n = ((ifcopenshell::IfcBaseEntity*)i)->get_value<std::string>("Name");
|
||||
auto g1 = n.substr(0, 22);
|
||||
auto g2 = n.substr(23);
|
||||
auto item = c.mapping()->map(i);
|
||||
@@ -83,7 +83,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
|
||||
v([&rel_by_space_elem, &elem_to_space_boundary_coords, &guid_pairs_visited](const intersection_validator::Box& a, const intersection_validator::Box& b) {
|
||||
std::ostringstream ss;
|
||||
// ss << id_map[a.id()]->first->data().toString() << "x" << id_map[b.id()]->first->data().toString() << std::endl;
|
||||
// ss << id_map[a.id()]->first->data().to_string() << "x" << id_map[b.id()]->first->data().to_string() << std::endl;
|
||||
// auto x = id_map[a.id()]->second * id_map[b.id()]->second;
|
||||
|
||||
auto A = a.handle()->first;
|
||||
@@ -103,7 +103,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
return;
|
||||
}
|
||||
|
||||
ss << a.handle()->first->data().toString() << "x" << a.handle()->first->data().toString() << std::endl;
|
||||
ss << a.handle()->first->data().to_string() << "x" << a.handle()->first->data().to_string() << std::endl;
|
||||
auto x = a.handle()->second * b.handle()->second;
|
||||
|
||||
if (x.is_empty()) {
|
||||
@@ -128,7 +128,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
auto itelem = elem_to_space_boundary_coords.find({ Aguid, Bguid });
|
||||
|
||||
if (itelem == elem_to_space_boundary_coords.end()) {
|
||||
Logger::Error("Missing space boundary relationship " + Aguid + " " + Bguid);
|
||||
logger::error("Missing space boundary relationship " + Aguid + " " + Bguid);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
bool valid = *std::max_element(distances.begin(), distances.end()) < 0.4;
|
||||
|
||||
if (!valid) {
|
||||
Logger::Error("Wrong connection geometry " + Aguid + " " + Bguid);
|
||||
logger::error("Wrong connection geometry " + Aguid + " " + Bguid);
|
||||
}
|
||||
|
||||
/*{
|
||||
@@ -174,11 +174,11 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo
|
||||
};
|
||||
|
||||
for (auto& i : *f2.instances_by_type("IfcProduct")) {
|
||||
auto n = ((IfcUtil::IfcBaseEntity*)i)->get_value<std::string>("Name");
|
||||
auto n = ((ifcopenshell::IfcBaseEntity*)i)->get_value<std::string>("Name");
|
||||
auto g1 = n.substr(0, 22);
|
||||
auto g2 = n.substr(23);
|
||||
if (is_wall_space_or_slab(g1) && is_wall_space_or_slab(g2) && guid_pairs_visited.find({ g1, g2 }) == guid_pairs_visited.end()) {
|
||||
Logger::Error("Space boundary for non-bounding geometry " + g1 + " " + g2);
|
||||
logger::error("Space boundary for non-bounding geometry " + g1 + " " + g2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
void fix_storeycontainment(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
ifcopenshell::geometry::Settings settings;
|
||||
|
||||
settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = false;
|
||||
@@ -25,16 +25,16 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
|
||||
IfcGeom::Iterator context_iterator("cgal", settings, &f, no_openings_and_spaces, 1);
|
||||
|
||||
auto get_elevation = [](const IfcUtil::IfcBaseClass* a) {
|
||||
return ((const IfcUtil::IfcBaseEntity*)a)->get_value<double>("Elevation", 0.);
|
||||
auto get_elevation = [](const ifcopenshell::IfcBaseClass* a) {
|
||||
return ((const ifcopenshell::IfcBaseEntity*)a)->get_value<double>("Elevation", 0.);
|
||||
};
|
||||
|
||||
// latebound inverse attribute lookup not working
|
||||
auto rels = f.instances_by_type("IfcRelContainedInSpatialStructure");
|
||||
std::map<const IfcUtil::IfcBaseClass*, const IfcUtil::IfcBaseClass*> elem_to_storey;
|
||||
std::for_each(rels->begin(), rels->end(), [&elem_to_storey](IfcUtil::IfcBaseClass* r) {
|
||||
auto elems = ((IfcUtil::IfcBaseEntity*)r)->get_value<aggregate_of_instance::ptr>("RelatedElements");
|
||||
auto storey = ((IfcUtil::IfcBaseEntity*)r)->get_value<IfcUtil::IfcBaseClass*>("RelatingStructure");
|
||||
std::map<const ifcopenshell::IfcBaseClass*, const ifcopenshell::IfcBaseClass*> elem_to_storey;
|
||||
std::for_each(rels->begin(), rels->end(), [&elem_to_storey](ifcopenshell::IfcBaseClass* r) {
|
||||
auto elems = ((ifcopenshell::IfcBaseEntity*)r)->get_value<aggregate_of_instance::ptr>("RelatedElements");
|
||||
auto storey = ((ifcopenshell::IfcBaseEntity*)r)->get_value<ifcopenshell::IfcBaseClass*>("RelatingStructure");
|
||||
|
||||
if (storey->declaration().name() == "IfcBuildingStorey") {
|
||||
for (auto it = elems->begin(); it != elems->end(); ++it) {
|
||||
@@ -44,15 +44,15 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
});
|
||||
|
||||
auto storeys = f.instances_by_type("IfcBuildingStorey");
|
||||
std::vector<const IfcUtil::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
|
||||
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](const IfcUtil::IfcBaseClass* a, const IfcUtil::IfcBaseClass* b) {
|
||||
std::vector<const ifcopenshell::IfcBaseClass*> storeys_sorted(storeys->begin(), storeys->end());
|
||||
std::sort(storeys_sorted.begin(), storeys_sorted.end(), [&get_elevation](const ifcopenshell::IfcBaseClass* a, const ifcopenshell::IfcBaseClass* b) {
|
||||
return get_elevation(a) < get_elevation(b);
|
||||
});
|
||||
|
||||
/*
|
||||
std::wcout << "Storeys ";
|
||||
for (auto& s : storeys_sorted) {
|
||||
auto n = ((IfcUtil::IfcBaseEntity*)s)->get_value<std::string>("Name");
|
||||
auto n = ((ifcopenshell::IfcBaseEntity*)s)->get_value<std::string>("Name");
|
||||
std::wcout << n.c_str() << " ";
|
||||
}
|
||||
std::wcout << std::endl;
|
||||
@@ -121,7 +121,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
|
||||
/*
|
||||
std::stringstream ss;
|
||||
ss << geom_object->product()->data().toString();
|
||||
ss << geom_object->product()->data().to_string();
|
||||
auto sss = ss.str();
|
||||
std::wcout << sss.c_str() << std::endl;
|
||||
*/
|
||||
@@ -196,9 +196,9 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
auto assigned_overlap = intersection_volumes[assigned_idx];
|
||||
if (calc_overlap > 0 && assigned_overlap < calc_overlap * 0.9) {
|
||||
auto s = geom_object->product()->get_value<std::string>("GlobalId");
|
||||
auto s1 = ((IfcUtil::IfcBaseEntity*)storeys_sorted[calc_idx])->get_value<std::string>("GlobalId");
|
||||
auto s2 = ((IfcUtil::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value<std::string>("GlobalId");
|
||||
Logger::Error("Element " + s + " contained in " + s2 + " located on " + s1);
|
||||
auto s1 = ((ifcopenshell::IfcBaseEntity*)storeys_sorted[calc_idx])->get_value<std::string>("GlobalId");
|
||||
auto s2 = ((ifcopenshell::IfcBaseEntity*)elem_to_storey[geom_object->product()])->get_value<std::string>("GlobalId");
|
||||
logger::error("Element " + s + " contained in " + s2 + " located on " + s1);
|
||||
}
|
||||
|
||||
if (!no_progress) {
|
||||
@@ -214,7 +214,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
std::cerr << std::flush;
|
||||
} else {
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress != progress) Logger::ProgressBar(progress);
|
||||
if (old_progress != progress) logger::progress_bar(progress);
|
||||
old_progress = progress;
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b
|
||||
if (stderr_progress)
|
||||
std::cerr << std::flush;
|
||||
} else {
|
||||
Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
|
||||
logger::status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
|
||||
" objects ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
void fix_wallconnectivity(ifcopenshell::file& f, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress);
|
||||
|
||||
ifcopenshell::geometry::Settings settings;
|
||||
@@ -27,14 +27,14 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
ifcopenshell::geometry::Converter c("cgal", &f, settings);
|
||||
|
||||
auto rels = f.instances_by_type("IfcRelConnectsPathElements");
|
||||
std::map<std::set<const IfcUtil::IfcBaseClass*>, const IfcUtil::IfcBaseClass*> rel_by_elem;
|
||||
std::for_each(rels->begin(), rels->end(), [&rel_by_elem](const IfcUtil::IfcBaseClass* rel) {
|
||||
auto x = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
|
||||
auto y = ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedElement");
|
||||
std::map<std::set<const ifcopenshell::IfcBaseClass*>, const ifcopenshell::IfcBaseClass*> rel_by_elem;
|
||||
std::for_each(rels->begin(), rels->end(), [&rel_by_elem](const ifcopenshell::IfcBaseClass* rel) {
|
||||
auto x = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingElement");
|
||||
auto y = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatedElement");
|
||||
rel_by_elem.insert({{ x,y }, rel});
|
||||
});
|
||||
|
||||
std::set<const IfcUtil::IfcBaseClass*> rels_encounted;
|
||||
std::set<const ifcopenshell::IfcBaseClass*> rels_encounted;
|
||||
|
||||
double total_nef_intersection_time = 0.;
|
||||
double conversion_to_poly = 0.;
|
||||
@@ -43,15 +43,15 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
auto A = a.handle()->first;
|
||||
auto B = b.handle()->first;
|
||||
|
||||
const IfcUtil::IfcBaseClass* rel = nullptr;
|
||||
const ifcopenshell::IfcBaseClass* rel = nullptr;
|
||||
std::string a_type, b_type;
|
||||
|
||||
auto rit = rel_by_elem.find({ A, B });
|
||||
if (rit != rel_by_elem.end()) {
|
||||
rel = rit->second;
|
||||
const bool a_is_relating = A == ((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
|
||||
a_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value<std::string>("RelatingConnectionType");
|
||||
b_type = ((IfcUtil::IfcBaseEntity*)rel)->get_value<std::string>("RelatedConnectionType");
|
||||
const bool a_is_relating = A == ((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingElement");
|
||||
a_type = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<std::string>("RelatingConnectionType");
|
||||
b_type = ((ifcopenshell::IfcBaseEntity*)rel)->get_value<std::string>("RelatedConnectionType");
|
||||
if (!a_is_relating) {
|
||||
std::swap(a_type, b_type);
|
||||
}
|
||||
@@ -79,7 +79,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
#endif
|
||||
|
||||
std::ostringstream ss;
|
||||
ss << A->data().toString() << "x" << B->data().toString() << std::endl;
|
||||
ss << A->data().to_string() << "x" << B->data().to_string() << std::endl;
|
||||
std::clock_t intersection_begin = std::clock();
|
||||
auto x = a.handle()->second * b.handle()->second;
|
||||
std::clock_t intersection_end = std::clock();
|
||||
@@ -108,7 +108,7 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
return;
|
||||
}
|
||||
|
||||
auto get_axis_parameter_min_max = [&c, &x_poly](const IfcUtil::IfcBaseEntity* inst) {
|
||||
auto get_axis_parameter_min_max = [&c, &x_poly](const ifcopenshell::IfcBaseEntity* inst) {
|
||||
auto item = c.mapping()->map(inst);
|
||||
auto shaperep = taxonomy::cast<taxonomy::collection>(item)->children[0];
|
||||
auto loop = taxonomy::dcast<taxonomy::loop>(taxonomy::cast<taxonomy::collection>(shaperep)->children[0]);
|
||||
@@ -169,21 +169,21 @@ void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bo
|
||||
|
||||
if (a_type != atype_computed || b_type != btype_computed) {
|
||||
if (rel) {
|
||||
Logger::Error(std::string("Connection type ") + atype_computed + " " + btype_computed + " for:", rel);
|
||||
logger::error(std::string("Connection type ") + atype_computed + " " + btype_computed + " for:", rel);
|
||||
} else {
|
||||
auto A_str = A->get_value<std::string>("GlobalId");
|
||||
auto B_str = B->get_value<std::string>("GlobalId");
|
||||
Logger::Error("No connection for adjacent " + A_str + " " + B_str);
|
||||
logger::error("No connection for adjacent " + A_str + " " + B_str);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
std::for_each(rels->begin(), rels->end(), [&rels_encounted, &v](const IfcUtil::IfcBaseClass* rel) {
|
||||
std::for_each(rels->begin(), rels->end(), [&rels_encounted, &v](const ifcopenshell::IfcBaseClass* rel) {
|
||||
if (rels_encounted.find(rel) == rels_encounted.end()) {
|
||||
auto x = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatingElement");
|
||||
auto y = (IfcUtil::IfcBaseEntity*)((IfcUtil::IfcBaseEntity*)rel)->get_value<IfcUtil::IfcBaseClass*>("RelatedElement");
|
||||
auto x = (ifcopenshell::IfcBaseEntity*)((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatingElement");
|
||||
auto y = (ifcopenshell::IfcBaseEntity*)((ifcopenshell::IfcBaseEntity*)rel)->get_value<ifcopenshell::IfcBaseClass*>("RelatedElement");
|
||||
if (v.successfully_processed.find(x) != v.successfully_processed.end() && v.successfully_processed.find(y) != v.successfully_processed.end()) {
|
||||
Logger::Error("Connection for non-adjacent walls", rel);
|
||||
logger::error("Connection for non-adjacent walls", rel);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -431,7 +431,7 @@ struct remove_thickness {
|
||||
|
||||
|
||||
struct intersection_validator {
|
||||
typedef std::list<std::pair<const IfcUtil::IfcBaseEntity*, CGAL::Nef_polyhedron_3<Kernel_>> > nefs_t;
|
||||
typedef std::list<std::pair<const ifcopenshell::IfcBaseEntity*, CGAL::Nef_polyhedron_3<Kernel_>> > nefs_t;
|
||||
typedef CGAL::Box_intersection_d::Box_with_handle_d<double, 3, nefs_t::value_type*> Box;
|
||||
|
||||
std::vector<Box> boxes;
|
||||
@@ -443,9 +443,9 @@ struct intersection_validator {
|
||||
double total_minkowsky_time = 0.;
|
||||
double total_box_time = 0.;
|
||||
|
||||
std::set<const IfcUtil::IfcBaseEntity*> successfully_processed;
|
||||
std::set<const ifcopenshell::IfcBaseEntity*> successfully_processed;
|
||||
|
||||
intersection_validator(IfcParse::IfcFile& f, std::initializer_list<std::string> entities, double eps, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
intersection_validator(ifcopenshell::file& f, std::initializer_list<std::string> entities, double eps, bool no_progress, bool quiet, bool stderr_progress) {
|
||||
|
||||
ifcopenshell::geometry::Settings settings;
|
||||
settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = false;
|
||||
@@ -485,7 +485,7 @@ struct intersection_validator {
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
geom_object->product()->toString(ss);
|
||||
geom_object->product()->to_string(ss);
|
||||
auto sss = ss.str();
|
||||
std::wcout << sss.c_str() << std::endl;
|
||||
|
||||
@@ -543,7 +543,7 @@ struct intersection_validator {
|
||||
|
||||
/*
|
||||
std::ostringstream ss;
|
||||
ss << geom_object->product()->data().toString() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl;
|
||||
ss << geom_object->product()->data().to_string() << std::endl << b.min_coord(0) << " - " << b.max_coord(0) << std::endl;
|
||||
auto sss = ss.str();
|
||||
std::wcout << sss.c_str();
|
||||
*/
|
||||
@@ -562,7 +562,7 @@ struct intersection_validator {
|
||||
std::cerr << std::flush;
|
||||
} else {
|
||||
const int progress = context_iterator.progress() / 2;
|
||||
if (old_progress != progress) Logger::ProgressBar(progress);
|
||||
if (old_progress != progress) logger::progress_bar(progress);
|
||||
old_progress = progress;
|
||||
}
|
||||
}
|
||||
@@ -578,7 +578,7 @@ struct intersection_validator {
|
||||
if (stderr_progress)
|
||||
std::cerr << std::flush;
|
||||
} else {
|
||||
Logger::Status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
|
||||
logger::status("\rDone fixing space boundaries for " + boost::lexical_cast<std::string>(num_created) +
|
||||
" objects ");
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::pt
|
||||
auto it = cache_.find(item);
|
||||
if (it != cache_.end()) {
|
||||
results = it->second;
|
||||
Logger::Notice("Cache hit #" + std::to_string(item->instance->as<IfcUtil::IfcBaseEntity>()->id()) +
|
||||
" -> #" + std::to_string(it->first->instance->as<IfcUtil::IfcBaseEntity>()->id()));
|
||||
logger::notice("Cache hit #" + std::to_string(item->instance.id()) +
|
||||
" -> #" + std::to_string(it->first->instance.id()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::pt
|
||||
try {
|
||||
return fn();
|
||||
} catch (std::exception& e) {
|
||||
Logger::Error(e, item->instance);
|
||||
logger::error(e, item->instance);
|
||||
return false;
|
||||
} catch (...) {
|
||||
// @todo we can't log OCCT exceptions here, can we do some reraising to solve this?
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
#define ABSTRACT_KERNEL_H
|
||||
|
||||
#include "../ifcparse/macros.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcparse/logger.h"
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
#include "../ifcgeom/abstract_mapping.h"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
static const double ALMOST_ZERO = 1.e-9;
|
||||
|
||||
template <typename T>
|
||||
@@ -79,6 +81,12 @@ namespace ifcopenshell {
|
||||
const std::string& geometry_library() const {
|
||||
return geometry_library_;
|
||||
}
|
||||
virtual std::string_view backend_id() const {
|
||||
return geometry_library_;
|
||||
}
|
||||
virtual bool accepts(const IfcGeom::ConversionResultShape& shape) const {
|
||||
return shape.backend_id() == backend_id();
|
||||
}
|
||||
|
||||
virtual bool supports_boolean_operations() const = 0;
|
||||
|
||||
@@ -121,8 +129,8 @@ namespace ifcopenshell {
|
||||
*/
|
||||
|
||||
virtual bool apply_layerset(IfcGeom::ConversionResults&, const ifcopenshell::geometry::layerset_information&) { throw not_implemented_error(); }
|
||||
virtual bool apply_folded_layerset(IfcGeom::ConversionResults&, const ifcopenshell::geometry::layerset_information&, const std::map<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::layerset_information>&) { throw not_implemented_error(); }
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
virtual bool apply_folded_layerset(IfcGeom::ConversionResults&, const ifcopenshell::geometry::layerset_information&, const std::map<express::Base, ifcopenshell::geometry::layerset_information>&) { throw not_implemented_error(); }
|
||||
virtual bool convert_openings(const express::Base& entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes) = 0;
|
||||
virtual bool unify_shapes(const IfcGeom::ConversionResults&, IfcGeom::ConversionResults&) { throw not_implemented_error(); }
|
||||
|
||||
@@ -149,8 +157,10 @@ namespace {
|
||||
|
||||
template <>
|
||||
struct dispatch_conversion<ifcopenshell::geometry::taxonomy::type_by_kind::max> {
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, ifcopenshell::geometry::taxonomy::kinds, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) {
|
||||
Logger::Error("No conversion for " + std::to_string(item->kind()));
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* k, ifcopenshell::geometry::taxonomy::kinds, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) {
|
||||
if (k->partial_success_is_success) {
|
||||
logger::error("No conversion for " + std::to_string(item->kind()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -169,8 +179,10 @@ namespace {
|
||||
|
||||
template <>
|
||||
struct dispatch_with_upgrade<ifcopenshell::geometry::taxonomy::upgrades::max> {
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) {
|
||||
Logger::Error("No conversion with upgrade for " + std::to_string(item->kind()));
|
||||
static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* k, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) {
|
||||
if (k->partial_success_is_success) {
|
||||
logger::error("No conversion with upgrade for " + std::to_string(item->kind()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -206,7 +218,7 @@ namespace {
|
||||
template <typename T>
|
||||
struct dispatch_curve_creation<T, ifcopenshell::geometry::taxonomy::curves::max> {
|
||||
static bool dispatch(const ifcopenshell::geometry::taxonomy::ptr& item, T&) {
|
||||
Logger::Error("No conversion for " + std::to_string(item->kind()));
|
||||
logger::error("No conversion for " + std::to_string(item->kind()));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -228,10 +240,10 @@ namespace {
|
||||
template <typename T>
|
||||
struct dispatch_surface_creation<T, ifcopenshell::geometry::taxonomy::surfaces::max> {
|
||||
static bool dispatch(const ifcopenshell::geometry::taxonomy::ptr& item, T&) {
|
||||
Logger::Error("No conversion for " + std::to_string(item->kind()));
|
||||
logger::error("No conversion for " + std::to_string(item->kind()));
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+37
-26
@@ -1,27 +1,34 @@
|
||||
add_subdirectory(kernels)
|
||||
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
|
||||
|
||||
if((BUILD_CONVERT OR BUILD_IFCPYTHON) AND WITH_OPENCASCADE)
|
||||
add_subdirectory(Serialization)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
add_subdirectory(mapping)
|
||||
set(mapping_libraries ${mapping_libraries} PARENT_SCOPE)
|
||||
|
||||
# IfcGeom (schema agnostic)
|
||||
file(GLOB SCHEMA_AGNOSTIC_H_FILES *.h)
|
||||
file(GLOB SCHEMA_AGNOSTIC_CPP_FILES *.cpp)
|
||||
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
|
||||
set(SERIALIZER_RUNTIME_CPP_FILES
|
||||
../serializers/document_serializer_plugin.cpp
|
||||
../serializers/geometry_serializer_plugin.cpp
|
||||
)
|
||||
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES} ${SERIALIZER_RUNTIME_CPP_FILES})
|
||||
|
||||
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
|
||||
set_target_properties(
|
||||
IfcGeom
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS -DIFC_GEOM_EXPORTS
|
||||
VERSION "${PROJECT_VERSION}"
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
PUBLIC_HEADER "${SCHEMA_AGNOSTIC_H_FILES}"
|
||||
)
|
||||
add_library(geometry ALIAS IfcGeom)
|
||||
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
|
||||
if (NOT CREATE_BUNDLE)
|
||||
set_target_properties(IfcGeom PROPERTIES VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||
endif()
|
||||
target_compile_definitions(IfcGeom PRIVATE BOOST_DLL_USE_STD_FS SERIALIZERS_EXPORTS)
|
||||
if(WITH_CGAL)
|
||||
target_compile_definitions(IfcGeom PUBLIC IFOPSH_WITH_CGAL)
|
||||
endif()
|
||||
if(WITH_OPENCASCADE)
|
||||
target_compile_definitions(IfcGeom PUBLIC IFOPSH_WITH_OPENCASCADE)
|
||||
endif()
|
||||
if(WITH_MANIFOLD)
|
||||
target_compile_definitions(IfcGeom PUBLIC IFOPSH_WITH_MANIFOLD)
|
||||
endif()
|
||||
if(HDF5_SUPPORT)
|
||||
target_compile_definitions(IfcGeom PUBLIC WITH_HDF5)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
find_package(Threads)
|
||||
@@ -29,18 +36,22 @@ endif()
|
||||
|
||||
find_package(Eigen3 REQUIRED)
|
||||
|
||||
target_link_libraries(IfcGeom ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen" ${CGAL_LIBRARIES})
|
||||
add_subdirectory(kernels)
|
||||
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
|
||||
set(tree_libraries ${tree_libraries} PARENT_SCOPE)
|
||||
|
||||
if(WITH_OPENCASCADE)
|
||||
target_link_libraries(IfcGeom TKernel)
|
||||
if(WASM_BUILD)
|
||||
target_link_libraries(IfcGeom plugin ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
|
||||
else()
|
||||
target_link_libraries(IfcGeom plugin IfcParse ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
|
||||
endif()
|
||||
|
||||
if(NOT WASM_BUILD)
|
||||
target_link_libraries(IfcGeom IfcParse)
|
||||
if((BUILD_CONVERT OR BUILD_IFCPYTHON) AND WITH_OPENCASCADE)
|
||||
add_subdirectory(Serialization)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
|
||||
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
install(
|
||||
TARGETS IfcGeom
|
||||
EXPORT ${IFCOPENSHELL_EXPORT_TARGETS}
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ifcgeom"
|
||||
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -57,6 +58,7 @@ struct EdgeKey {
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef SWIG
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<EdgeKey> {
|
||||
@@ -65,6 +67,7 @@ namespace std {
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
@@ -72,6 +75,7 @@ namespace IfcGeom {
|
||||
class IFC_GEOM_API Triangulation;
|
||||
}
|
||||
|
||||
#ifndef SWIG
|
||||
template <typename T>
|
||||
constexpr T add_(T a, T b) {
|
||||
return a + b;
|
||||
@@ -106,6 +110,7 @@ namespace IfcGeom {
|
||||
constexpr T negate_(T a) {
|
||||
return -a;
|
||||
}
|
||||
#endif
|
||||
|
||||
class IFC_GEOM_API OpaqueNumber {
|
||||
public:
|
||||
@@ -125,6 +130,7 @@ namespace IfcGeom {
|
||||
};
|
||||
|
||||
// @todo this can simply be a template class, to remove the need for the NumberEpeck in CGAL kernel.
|
||||
#ifndef SWIG
|
||||
class IFC_GEOM_API NumberNativeDouble : public OpaqueNumber {
|
||||
private:
|
||||
double value_;
|
||||
@@ -188,7 +194,24 @@ namespace IfcGeom {
|
||||
return new NumberNativeDouble(value_);
|
||||
}
|
||||
};
|
||||
#else
|
||||
class IFC_GEOM_API NumberNativeDouble : public OpaqueNumber {
|
||||
public:
|
||||
NumberNativeDouble(double v);
|
||||
virtual double to_double() const;
|
||||
virtual std::string to_string() const;
|
||||
virtual OpaqueNumber* operator+(OpaqueNumber* other) const;
|
||||
virtual OpaqueNumber* operator-(OpaqueNumber* other) const;
|
||||
virtual OpaqueNumber* operator*(OpaqueNumber* other) const;
|
||||
virtual OpaqueNumber* operator/(OpaqueNumber* other) const;
|
||||
virtual bool operator==(OpaqueNumber* other) const;
|
||||
virtual bool operator<(OpaqueNumber* other) const;
|
||||
virtual OpaqueNumber* operator-() const;
|
||||
virtual OpaqueNumber* clone() const;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef SWIG
|
||||
template <size_t N>
|
||||
struct IFC_GEOM_API OpaqueCoordinate {
|
||||
private:
|
||||
@@ -250,9 +273,25 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
};
|
||||
#else
|
||||
template <size_t N>
|
||||
struct IFC_GEOM_API OpaqueCoordinate {
|
||||
OpaqueCoordinate();
|
||||
OpaqueCoordinate(const OpaqueCoordinate& other);
|
||||
OpaqueCoordinate& operator=(const OpaqueCoordinate& other);
|
||||
~OpaqueCoordinate();
|
||||
OpaqueNumber* get(size_t i) const;
|
||||
void set(size_t i, OpaqueNumber* n);
|
||||
};
|
||||
#endif
|
||||
|
||||
class IFC_GEOM_API ConversionResultShape {
|
||||
public:
|
||||
#ifdef SWIG
|
||||
virtual std::string backend_id() const = 0;
|
||||
#else
|
||||
virtual std::string_view backend_id() const = 0;
|
||||
#endif
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int item_id, int surface_style_id) const = 0;
|
||||
IfcGeom::Representation::Triangulation* Triangulate(const ifcopenshell::geometry::Settings& settings) const;
|
||||
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const = 0;
|
||||
@@ -344,7 +383,7 @@ namespace IfcGeom {
|
||||
|
||||
typedef std::vector<ConversionResult> ConversionResults;
|
||||
|
||||
|
||||
#ifndef SWIG
|
||||
namespace util {
|
||||
// @todo this is now moved to occt kernel, do we need something similar in cgal?
|
||||
// bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, double tol);
|
||||
@@ -422,6 +461,7 @@ namespace IfcGeom {
|
||||
return loops;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/optional/optional_io.hpp>
|
||||
|
||||
#include "ifc_geom_api.h"
|
||||
|
||||
@@ -48,7 +47,8 @@ namespace ifcopenshell {
|
||||
// of vector settings we need to strip away the optional and detect argument presence
|
||||
// with !vector::empty()
|
||||
// tfk: we no longer do this because negative values can not be passed like this as boost confuses them with options
|
||||
// std::conditional_t<std::is_same_v<T, std::vector<double>>, T, boost::optional<T>> value;
|
||||
// std::conditional_t<std::is_same_v<T, std::vector<double>>, T, std::optional<T>> value;
|
||||
// tfk: note that we use boost::optional to avoid a lack of deserialization support with std::optional and boost program options
|
||||
boost::optional<T> value;
|
||||
|
||||
SettingBase() {}
|
||||
@@ -80,7 +80,7 @@ namespace ifcopenshell {
|
||||
return value;
|
||||
} else {
|
||||
if (value) {
|
||||
return value.get();
|
||||
return value.value();
|
||||
}
|
||||
if constexpr (HasDefault<Derived>()) {
|
||||
return Derived::defaultvalue;
|
||||
@@ -545,7 +545,7 @@ namespace ifcopenshell {
|
||||
template <typename settings_t>
|
||||
class SettingsContainer {
|
||||
public:
|
||||
typedef boost::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, FunctionStepMethod, OutputDimensionalityTypes, TriangulationMethod> value_variant_t;
|
||||
typedef std::variant<bool, int, double, std::string, std::set<int>, std::set<std::string>, std::vector<double>, IteratorOutputOptions, FunctionStepMethod, OutputDimensionalityTypes, TriangulationMethod> value_variant_t;
|
||||
private:
|
||||
settings_t settings;
|
||||
|
||||
@@ -585,15 +585,15 @@ namespace ifcopenshell {
|
||||
void set_option_(const std::string& name, const value_variant_t& val) {
|
||||
if (std::tuple_element_t<Index, settings_t>::name == name) {
|
||||
if constexpr (std::is_enum_v<typename std::tuple_element_t<Index, settings_t>::base_type>) {
|
||||
if (auto* val_ptr = boost::get<int>(&val)) {
|
||||
if (auto* val_ptr = std::get_if<int>(&val)) {
|
||||
auto val_as_enum = (typename std::tuple_element_t<Index, settings_t>::base_type) *val_ptr;
|
||||
std::get<Index>(settings).value = val_as_enum;
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
std::get<Index>(settings).value = boost::get<typename std::tuple_element_t<Index, settings_t>::base_type>(val);
|
||||
} catch (const boost::bad_get&) {
|
||||
std::get<Index>(settings).value = std::get<typename std::tuple_element_t<Index, settings_t>::base_type>(val);
|
||||
} catch (const std::bad_variant_access&) {
|
||||
std::string ty = impl::readable_name<typename std::tuple_element_t<Index, settings_t>::base_type>::name;
|
||||
throw std::runtime_error("Expected a value of type <" + ty + "> for setting '" + name + "'");
|
||||
}
|
||||
|
||||
+50
-47
@@ -4,7 +4,7 @@
|
||||
|
||||
using namespace ifcopenshell::geometry;
|
||||
|
||||
ifcopenshell::geometry::Converter::Converter(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& s)
|
||||
ifcopenshell::geometry::Converter::Converter(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, ifcopenshell::file* file, ifcopenshell::geometry::Settings& s)
|
||||
: kernel_(std::move(geometry_library))
|
||||
{
|
||||
mapping_ = impl::mapping_implementations().construct(file, s);
|
||||
@@ -29,17 +29,19 @@ namespace {
|
||||
if (density > 1e5) {
|
||||
items[0].Shape()->set_box(box);
|
||||
items.erase(items.begin() + 1, items.end());
|
||||
Logger::Notice("Substituted element with " + boost::lexical_cast<std::string>(density) + " vertices / m3 with a bounding box");
|
||||
logger::notice("Substituted element with " + boost::lexical_cast<std::string>(density) + " vertices / m3 with a bounding box");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(taxonomy::ptr representation_node, const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4::ptr& place_) {
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::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_;
|
||||
|
||||
representation_id_builder << representation_node->instance->as<IfcUtil::IfcBaseEntity>()->id();
|
||||
representation_id_builder << representation_node->instance.id();
|
||||
|
||||
IfcGeom::Representation::BRep* shape;
|
||||
IfcGeom::ConversionResults shapes;
|
||||
@@ -47,11 +49,11 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
if (!kernel_->convert(representation_node, shapes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (settings_.get<ifcopenshell::geometry::settings::ApplyLayerSets>().get()) {
|
||||
ifcopenshell::geometry::layerset_information layerinfo;
|
||||
std::vector<ifcopenshell::geometry::endpoint_connection> neighbours;
|
||||
std::map<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::layerset_information> neigbour_layers;
|
||||
std::map<express::Base, ifcopenshell::geometry::layerset_information> neigbour_layers;
|
||||
int layerset_id, lid;
|
||||
|
||||
if (mapping_->get_layerset_information(product, layerinfo, layerset_id)) {
|
||||
@@ -99,7 +101,7 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Error("Failed processing layerset");
|
||||
logger::error("Failed processing layerset");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,15 +140,15 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
}
|
||||
}
|
||||
if (some_items_without_style) {
|
||||
Logger::Warning("No material and surface styles for:", product);
|
||||
logger::warning("No material and surface styles for:", product);
|
||||
}
|
||||
}
|
||||
|
||||
if (material_style_applied) {
|
||||
representation_id_builder << "-material-" << single_material->id();
|
||||
representation_id_builder << "-material-" << single_material.id();
|
||||
}
|
||||
|
||||
if (settings_.get<ifcopenshell::geometry::settings::ForceSpaceTransparency>().has() && product->declaration().is("IfcSpace")) {
|
||||
if (settings_.get<ifcopenshell::geometry::settings::ForceSpaceTransparency>().has() && product.declaration().is("IfcSpace")) {
|
||||
for (auto& s : shapes) {
|
||||
if (s.hasStyle()) {
|
||||
// @todo the uglyness
|
||||
@@ -157,27 +159,27 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product);
|
||||
express::Base parent_object = mapping_->get_decomposing_entity(product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->id();
|
||||
parent_id = parent_object.id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
}
|
||||
|
||||
const std::string name = product->get_value<std::string>("Name", "");
|
||||
const std::string guid = product->get_value<std::string>("GlobalId", "");
|
||||
const std::string name = product.get_value<std::string>("Name", "");
|
||||
const std::string guid = product.get_value<std::string>("GlobalId", "");
|
||||
|
||||
const std::string product_type = product->declaration().name();
|
||||
const std::string product_type = product.declaration().name();
|
||||
|
||||
// Does the IfcElement have any IfcOpenings?
|
||||
// Note that openings for IfcOpeningElements are not processed
|
||||
auto openings = mapping_->find_openings(product);
|
||||
|
||||
if (!settings_.get<ifcopenshell::geometry::settings::DisableOpeningSubtractions>().get() && openings && openings->size()) {
|
||||
if (!settings_.get<ifcopenshell::geometry::settings::DisableOpeningSubtractions>().get() && !openings.empty()) {
|
||||
representation_id_builder << "-openings";
|
||||
for (auto it = openings->begin(); it != openings->end(); ++it) {
|
||||
representation_id_builder << "-" << (*it)->id();
|
||||
for (auto& op : openings) {
|
||||
representation_id_builder << "-" << op.id();
|
||||
}
|
||||
|
||||
IfcGeom::ConversionResults opened_shapes;
|
||||
@@ -185,9 +187,9 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
try {
|
||||
std::vector<std::pair<taxonomy::ptr, taxonomy::matrix4>> opening_items;
|
||||
|
||||
std::transform(openings->begin(), openings->end(), std::back_inserter(opening_items), [this](IfcUtil::IfcBaseClass* opening) {
|
||||
std::transform(openings.begin(), openings.end(), std::back_inserter(opening_items), [this](express::Base opening) {
|
||||
auto prod_item = mapping()->map(opening);
|
||||
auto repr = mapping()->representation_of(opening->as<IfcUtil::IfcBaseEntity>());
|
||||
auto repr = mapping()->representation_of(opening);
|
||||
if (repr) {
|
||||
return std::make_pair(mapping()->map(repr), *taxonomy::cast<taxonomy::geom_item>(prod_item)->matrix);
|
||||
} else {
|
||||
@@ -208,10 +210,10 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
kernel_->convert_openings(product, opening_items, shapes, *place, opened_shapes);
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Message(Logger::LOG_ERROR, std::string("Error processing openings for: ") + e.what() + ":", product);
|
||||
logger::message(logger::LOG_ERROR, std::string("error processing openings for: ") + e.what() + ":", product);
|
||||
caught_error = true;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Error processing openings for:", product);
|
||||
logger::message(logger::LOG_ERROR, "error processing openings for:", product);
|
||||
}
|
||||
|
||||
if (!(caught_error && opened_shapes.size() < shapes.size())) {
|
||||
@@ -239,7 +241,7 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
std::swap(shapes, unified_shapes);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,21 +250,21 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
std::string context_string = "";
|
||||
|
||||
// IfcShapeRepresentation.
|
||||
const IfcUtil::IfcBaseEntity *representation = representation_node->instance->as<IfcUtil::IfcBaseEntity>();
|
||||
auto representation_identifier = representation->get("RepresentationIdentifier");
|
||||
auto representation = representation_node->instance.as<express::Entity>();
|
||||
auto representation_identifier = representation.get("RepresentationIdentifier");
|
||||
if (!representation_identifier.isNull()) {
|
||||
context_string = (std::string) representation_identifier;
|
||||
}
|
||||
else {
|
||||
IfcUtil::IfcBaseClass *context = (IfcUtil::IfcBaseClass*)representation->get("ContextOfItems");
|
||||
auto context_type = context->as<IfcUtil::IfcBaseEntity>()->get("ContextType");
|
||||
auto context = (express::Base)representation.get("ContextOfItems");
|
||||
auto context_type = context.as<express::Entity>().get("ContextType");
|
||||
if (!context_type.isNull()) {
|
||||
context_string = (std::string)context_type;
|
||||
}
|
||||
}
|
||||
|
||||
auto elem = new IfcGeom::BRepElement(
|
||||
product->id(),
|
||||
product.id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
@@ -295,12 +297,12 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
if (elem->geometry().calculate_surface_area(a_calc)) {
|
||||
double diff = std::abs(a_calc - a_file);
|
||||
if (diff / std::sqrt(a_file) > getValue(GV_PRECISION)) {
|
||||
Logger::Error("Validation of surface area failed for:", product);
|
||||
logger::error("Validation of surface area failed for:", product);
|
||||
} else {
|
||||
Logger::Notice("Validation of surface area succeeded for:", product);
|
||||
logger::notice("Validation of surface area succeeded for:", product);
|
||||
}
|
||||
} else {
|
||||
Logger::Error("Validation of surface area failed for:", product);
|
||||
logger::error("Validation of surface area failed for:", product);
|
||||
}
|
||||
} else if (q->as<IfcSchema::IfcQuantityVolume>() && q->Name() == "Volume") {
|
||||
double v_calc;
|
||||
@@ -308,12 +310,12 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
if (elem->geometry().calculate_volume(v_calc)) {
|
||||
double diff = std::abs(v_calc - v_file);
|
||||
if (diff / std::sqrt(v_file) > getValue(GV_PRECISION)) {
|
||||
Logger::Error("Validation of volume failed for:", product);
|
||||
logger::error("Validation of volume failed for:", product);
|
||||
} else {
|
||||
Logger::Notice("Validation of volume succeeded for:", product);
|
||||
logger::notice("Validation of volume succeeded for:", product);
|
||||
}
|
||||
} else {
|
||||
Logger::Error("Validation of volume failed for:", product);
|
||||
logger::error("Validation of volume failed for:", product);
|
||||
}
|
||||
} else if (q->as<IfcSchema::IfcPhysicalComplexQuantity>() && q->Name() == "Shape Validation Properties") {
|
||||
auto qs2 = q->as<IfcSchema::IfcPhysicalComplexQuantity>()->HasQuantities();
|
||||
@@ -332,9 +334,9 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
}
|
||||
}
|
||||
if (!all_succeeded) {
|
||||
Logger::Error("Validation of surface genus failed for:", product);
|
||||
logger::error("Validation of surface genus failed for:", product);
|
||||
} else {
|
||||
Logger::Notice("Validation of surface genus succeeded for:", product);
|
||||
logger::notice("Validation of surface genus succeeded for:", product);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,25 +350,26 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
return elem;
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4::ptr& place, IfcGeom::BRepElement* brep) {
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_processed_representation(const express::Base product_, const taxonomy::matrix4::ptr& place, IfcGeom::BRepElement* brep) {
|
||||
auto product = product_.as<express::Entity>();
|
||||
|
||||
int parent_id = -1;
|
||||
try {
|
||||
IfcUtil::IfcBaseEntity* parent_object = mapping_->get_decomposing_entity(product);
|
||||
express::Base parent_object = mapping_->get_decomposing_entity(product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->id();
|
||||
parent_id = parent_object.id();
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
}
|
||||
|
||||
const std::string guid = product->get_value<std::string>("GlobalId");
|
||||
const std::string name = product->get_value<std::string>("Name", "");
|
||||
const std::string product_type = product->declaration().name();
|
||||
const std::string guid = product.get_value<std::string>("GlobalId");
|
||||
const std::string name = product.get_value<std::string>("Name", "");
|
||||
const std::string product_type = product.declaration().name();
|
||||
const std::string context_string = brep->context();
|
||||
|
||||
return new IfcGeom::BRepElement(
|
||||
product->id(),
|
||||
product.id(),
|
||||
parent_id,
|
||||
name,
|
||||
product_type,
|
||||
@@ -378,7 +381,7 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_process
|
||||
);
|
||||
}
|
||||
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product) {
|
||||
IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_representation_and_product(const express::Base representation, const express::Base product) {
|
||||
auto interpreted_representation = mapping_->map(representation);
|
||||
if (!interpreted_representation) {
|
||||
interpreted_representation = taxonomy::make<taxonomy::collection>();
|
||||
@@ -391,7 +394,7 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe
|
||||
);
|
||||
}
|
||||
|
||||
IfcGeom::ConversionResults ifcopenshell::geometry::Converter::convert(IfcUtil::IfcBaseClass * item)
|
||||
IfcGeom::ConversionResults ifcopenshell::geometry::Converter::convert(express::Base item)
|
||||
{
|
||||
std::clock_t map_start = std::clock();
|
||||
auto geom_item = mapping_->map(item);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef ITERATOR_KERNEL_H
|
||||
#define ITERATOR_KERNEL_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/file.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
#include "../ifcgeom/ConversionResult.h"
|
||||
#include "../ifcgeom/abstract_mapping.h"
|
||||
@@ -25,7 +25,7 @@ namespace ifcopenshell { namespace geometry {
|
||||
public:
|
||||
ifcopenshell::geometry::kernels::AbstractKernel* kernel() { return &*kernel_; }
|
||||
|
||||
Converter(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& settings);
|
||||
Converter(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, ifcopenshell::file* file, ifcopenshell::geometry::Settings& settings);
|
||||
|
||||
~Converter();
|
||||
|
||||
@@ -33,8 +33,8 @@ namespace ifcopenshell { namespace geometry {
|
||||
|
||||
/*
|
||||
virtual NativeElement<double, double>* convert(
|
||||
const IteratorSettings& settings, IfcUtil::IfcBaseClass* representation,
|
||||
IfcUtil::IfcBaseClass* product)
|
||||
const IteratorSettings& settings, express::Base representation,
|
||||
express::Base product)
|
||||
{
|
||||
return implementation_->convert(settings, representation, product);
|
||||
}
|
||||
@@ -43,13 +43,13 @@ namespace ifcopenshell { namespace geometry {
|
||||
double total_map_time = 0.;
|
||||
double total_geom_time = 0.;
|
||||
|
||||
IfcGeom::ConversionResults convert(IfcUtil::IfcBaseClass* item);
|
||||
IfcGeom::ConversionResults convert(express::Base item);
|
||||
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product);
|
||||
// IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product, IfcGeom::BRepElement* brep);
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(const express::Base representation, const express::Base product);
|
||||
// IfcGeom::BRepElement* create_brep_for_processed_representation(const express::Base representation, const express::Base product, IfcGeom::BRepElement* brep);
|
||||
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(ifcopenshell::geometry::taxonomy::ptr, const IfcUtil::IfcBaseEntity* product, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place);
|
||||
IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* product, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place, IfcGeom::BRepElement*);
|
||||
IfcGeom::BRepElement* create_brep_for_representation_and_product(ifcopenshell::geometry::taxonomy::ptr, const express::Base product, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place);
|
||||
IfcGeom::BRepElement* create_brep_for_processed_representation(const express::Base product, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place, IfcGeom::BRepElement*);
|
||||
|
||||
const ifcopenshell::geometry::Settings& settings() { return settings_; }
|
||||
};
|
||||
|
||||
@@ -93,27 +93,195 @@ inline namespace settings {
|
||||
static constexpr const char* const description = "Introduce a separate Z-Up node into the GlTF hierarchy instead of multiplying the transform into the root node matrices";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgBounds : public SettingBase<SvgBounds, std::string> {
|
||||
static constexpr const char* const name = "bounds";
|
||||
static constexpr const char* const description = "Specifies the bounding rectangle, for example 512x512, to which the output will be scaled. Only used when converting to SVG.";
|
||||
};
|
||||
|
||||
struct SvgScale : public SettingBase<SvgScale, std::string> {
|
||||
static constexpr const char* const name = "scale";
|
||||
static constexpr const char* const description = "Interprets SVG bounds in mm, centers layout and draw elements to scale. Only used when converting to SVG. Example 1:100.";
|
||||
};
|
||||
|
||||
struct SvgCenter : public SettingBase<SvgCenter, std::string> {
|
||||
static constexpr const char* const name = "center";
|
||||
static constexpr const char* const description = "When using --scale, specifies the location in the range [0 1]x[0 1] around which to center the drawings. Example 0.5x0.5.";
|
||||
};
|
||||
|
||||
struct SvgSectionRef : public SettingBase<SvgSectionRef, std::string> {
|
||||
static constexpr const char* const name = "section-ref";
|
||||
static constexpr const char* const description = "Element at which cross sections should be created.";
|
||||
};
|
||||
|
||||
struct SvgElevationRef : public SettingBase<SvgElevationRef, std::string> {
|
||||
static constexpr const char* const name = "elevation-ref";
|
||||
static constexpr const char* const description = "Element at which drawings should be created.";
|
||||
};
|
||||
|
||||
struct SvgElevationRefGuid : public SettingBase<SvgElevationRefGuid, std::string> {
|
||||
static constexpr const char* const name = "elevation-ref-guid";
|
||||
static constexpr const char* const description = "Element guids at which drawings should be created.";
|
||||
};
|
||||
|
||||
struct SvgAutoSection : public SettingBase<SvgAutoSection, bool> {
|
||||
static constexpr const char* const name = "auto-section";
|
||||
static constexpr const char* const description = "Creates SVG cross section drawings automatically based on model extents.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgAutoElevation : public SettingBase<SvgAutoElevation, bool> {
|
||||
static constexpr const char* const name = "auto-elevation";
|
||||
static constexpr const char* const description = "Creates SVG elevation drawings automatically based on model extents.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgDrawStoreyHeights : public SettingBase<SvgDrawStoreyHeights, std::string> {
|
||||
static constexpr const char* const name = "draw-storey-heights";
|
||||
static constexpr const char* const description = "Draws a horizontal line at the height of building storeys in vertical drawings. Accepted values are none, full, and left.";
|
||||
};
|
||||
|
||||
struct SvgStoreyHeightLineLength : public SettingBase<SvgStoreyHeightLineLength, double> {
|
||||
static constexpr const char* const name = "storey-height-line-length";
|
||||
static constexpr const char* const description = "Length of the line when --draw-storey-heights=left.";
|
||||
};
|
||||
|
||||
struct SvgUseNamespace : public SettingBase<SvgUseNamespace, bool> {
|
||||
static constexpr const char* const name = "svg-xmlns";
|
||||
static constexpr const char* const description = "Stores name and guid in a separate namespace as opposed to data-name, data-guid.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgUseHlrPoly : public SettingBase<SvgUseHlrPoly, bool> {
|
||||
static constexpr const char* const name = "svg-poly";
|
||||
static constexpr const char* const description = "Uses the polygonal algorithm for hidden line rendering.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgUsePrefiltering : public SettingBase<SvgUsePrefiltering, bool> {
|
||||
static constexpr const char* const name = "svg-prefilter";
|
||||
static constexpr const char* const description = "Prefilter faces and shapes before feeding to the hidden-line algorithm.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgSegmentProjection : public SettingBase<SvgSegmentProjection, bool> {
|
||||
static constexpr const char* const name = "svg-segment-projection";
|
||||
static constexpr const char* const description = "Segment result of projection with respect to original products.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgPolygonal : public SettingBase<SvgPolygonal, bool> {
|
||||
static constexpr const char* const name = "svg-write-poly";
|
||||
static constexpr const char* const description = "Approximate every curve as polygonal in SVG output.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgAlwaysProject : public SettingBase<SvgAlwaysProject, bool> {
|
||||
static constexpr const char* const name = "svg-project";
|
||||
static constexpr const char* const description = "Always enable hidden line rendering instead of only on elevations.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgWithoutStoreys : public SettingBase<SvgWithoutStoreys, bool> {
|
||||
static constexpr const char* const name = "svg-without-storeys";
|
||||
static constexpr const char* const description = "Do not emit drawings for building storeys.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgNoCss : public SettingBase<SvgNoCss, bool> {
|
||||
static constexpr const char* const name = "svg-no-css";
|
||||
static constexpr const char* const description = "Do not emit CSS style declarations.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgDoorArcs : public SettingBase<SvgDoorArcs, bool> {
|
||||
static constexpr const char* const name = "door-arcs";
|
||||
static constexpr const char* const description = "Draw door opening arcs for IfcDoor elements.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgSectionHeight : public SettingBase<SvgSectionHeight, double> {
|
||||
static constexpr const char* const name = "section-height";
|
||||
static constexpr const char* const description = "Specifies the cut section height for SVG 2D geometry.";
|
||||
};
|
||||
|
||||
struct SvgSectionHeightFromStoreys : public SettingBase<SvgSectionHeightFromStoreys, bool> {
|
||||
static constexpr const char* const name = "section-height-from-storeys";
|
||||
static constexpr const char* const description = "Derives section height from storey elevation. Use --section-height to override the default offset of 1.2.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgPrintSpaceNames : public SettingBase<SvgPrintSpaceNames, bool> {
|
||||
static constexpr const char* const name = "print-space-names";
|
||||
static constexpr const char* const description = "Prints IfcSpace LongName and Name in the geometry output. Applicable for SVG output.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgPrintSpaceAreas : public SettingBase<SvgPrintSpaceAreas, bool> {
|
||||
static constexpr const char* const name = "print-space-areas";
|
||||
static constexpr const char* const description = "Prints calculated IfcSpace areas in square meters. Applicable for SVG output.";
|
||||
static constexpr bool defaultvalue = false;
|
||||
};
|
||||
|
||||
struct SvgSpaceNameTransform : public SettingBase<SvgSpaceNameTransform, std::string> {
|
||||
static constexpr const char* const name = "space-name-transform";
|
||||
static constexpr const char* const description = "Additional transform to the space labels in SVG.";
|
||||
};
|
||||
}
|
||||
|
||||
class SerializerSettings : public SettingsContainer <
|
||||
// @todo should we use tuple_cat here to unify the settings into a single class?
|
||||
std::tuple<UseElementNames, UseElementGuids, UseElementStepIds, UseElementTypes, UseYUp, WriteGltfEcef, FloatingPointDigits, BaseUri, WktUseSection, SeparateZUpNode>>
|
||||
std::tuple<
|
||||
UseElementNames,
|
||||
UseElementGuids,
|
||||
UseElementStepIds,
|
||||
UseElementTypes,
|
||||
UseYUp,
|
||||
WriteGltfEcef,
|
||||
FloatingPointDigits,
|
||||
BaseUri,
|
||||
WktUseSection,
|
||||
SeparateZUpNode,
|
||||
SvgBounds,
|
||||
SvgScale,
|
||||
SvgCenter,
|
||||
SvgSectionRef,
|
||||
SvgElevationRef,
|
||||
SvgElevationRefGuid,
|
||||
SvgAutoSection,
|
||||
SvgAutoElevation,
|
||||
SvgDrawStoreyHeights,
|
||||
SvgStoreyHeightLineLength,
|
||||
SvgUseNamespace,
|
||||
SvgUseHlrPoly,
|
||||
SvgUsePrefiltering,
|
||||
SvgSegmentProjection,
|
||||
SvgPolygonal,
|
||||
SvgAlwaysProject,
|
||||
SvgWithoutStoreys,
|
||||
SvgNoCss,
|
||||
SvgDoorArcs,
|
||||
SvgSectionHeight,
|
||||
SvgSectionHeightFromStoreys,
|
||||
SvgPrintSpaceNames,
|
||||
SvgPrintSpaceAreas,
|
||||
SvgSpaceNameTransform>>
|
||||
{};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class stream_or_filename {
|
||||
class IFC_GEOM_API stream_or_filename {
|
||||
private:
|
||||
std::shared_ptr<std::ofstream> ofs_;
|
||||
std::shared_ptr<std::ostringstream> oss_;
|
||||
boost::optional<std::string> filename_;
|
||||
std::optional<std::string> filename_;
|
||||
|
||||
public:
|
||||
std::ostream& stream;
|
||||
|
||||
stream_or_filename(const std::string& fn)
|
||||
: ofs_(new std::ofstream(IfcUtil::path::from_utf8(fn).c_str()))
|
||||
: ofs_(new std::ofstream(ifcopenshell::path::from_utf8(fn).c_str()))
|
||||
, stream(*ofs_)
|
||||
{}
|
||||
|
||||
@@ -126,7 +294,7 @@ public:
|
||||
return oss_->str();
|
||||
}
|
||||
|
||||
boost::optional<std::string> filename() const {
|
||||
std::optional<std::string> filename() const {
|
||||
return filename_;
|
||||
}
|
||||
|
||||
@@ -139,7 +307,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class GeometrySerializer : public Serializer {
|
||||
class IFC_GEOM_API GeometrySerializer : public Serializer {
|
||||
public:
|
||||
enum read_type { READ_BREP, READ_TRIANGULATION };
|
||||
|
||||
@@ -153,7 +321,7 @@ public:
|
||||
virtual void write(const IfcGeom::TriangulationElement* o) = 0;
|
||||
virtual void write(const IfcGeom::BRepElement* o) = 0;
|
||||
virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0;
|
||||
virtual IfcGeom::Element* read(IfcParse::IfcFile& f, const std::string& guid, const std::string& representation_id, read_type rt = READ_BREP) = 0;
|
||||
virtual IfcGeom::Element* read(ifcopenshell::file& f, const std::string& guid, const std::string& representation_id, read_type rt = READ_BREP) = 0;
|
||||
|
||||
const ifcopenshell::geometry::SerializerSettings& settings() const { return settings_; }
|
||||
ifcopenshell::geometry::SerializerSettings& settings() { return settings_; }
|
||||
@@ -175,11 +343,11 @@ protected:
|
||||
ifcopenshell::geometry::SerializerSettings settings_;
|
||||
};
|
||||
|
||||
class WriteOnlyGeometrySerializer : public GeometrySerializer {
|
||||
class IFC_GEOM_API WriteOnlyGeometrySerializer : public GeometrySerializer {
|
||||
public:
|
||||
WriteOnlyGeometrySerializer(const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) : GeometrySerializer(geometry_settings, settings) {}
|
||||
|
||||
virtual IfcGeom::Element* read(IfcParse::IfcFile&, const std::string&, const std::string&, read_type = READ_BREP) {
|
||||
virtual IfcGeom::Element* read(ifcopenshell::file&, const std::string&, const std::string&, read_type = READ_BREP) {
|
||||
throw std::runtime_error("Not supported");
|
||||
};
|
||||
};
|
||||
|
||||
@@ -23,9 +23,10 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../ifcparse/Argument.h"
|
||||
#include "../ifcparse/IfcGlobalId.h"
|
||||
#include "../ifcparse/IfcLogger.h"
|
||||
#include "../ifcparse/argument.h"
|
||||
#include "../ifcparse/global_id.h"
|
||||
#include "../ifcparse/logger.h"
|
||||
#include "../ifcparse/instance_data.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "../ifcgeom/ifc_geom_api.h"
|
||||
@@ -60,7 +61,7 @@ namespace IfcGeom {
|
||||
std::string _context;
|
||||
std::string _unique_id;
|
||||
Transformation _transformation;
|
||||
const IfcUtil::IfcBaseEntity* product_;
|
||||
const express::Entity product_;
|
||||
std::vector<const IfcGeom::Element*> _parents;
|
||||
public:
|
||||
|
||||
@@ -71,9 +72,9 @@ namespace IfcGeom {
|
||||
// Use the id to compare, or the elevation is the elements are IfcBuildingStoreys and the elevation is set
|
||||
friend bool operator < (const Element& element1, const Element& element2) {
|
||||
if (element1.type() == "IfcBuildingStorey" && element2.type() == "IfcBuildingStorey") {
|
||||
size_t attr_index = element1.product()->declaration().as_entity()->attribute_index("Elevation");
|
||||
auto elev_attr1 = element1.product()->get_attribute_value(attr_index);
|
||||
auto elev_attr2 = element2.product()->get_attribute_value(attr_index);
|
||||
size_t attr_index = element1.product().declaration().as_entity()->attribute_index("Elevation");
|
||||
auto elev_attr1 = element1.product().get_attribute_value(attr_index);
|
||||
auto elev_attr2 = element2.product().get_attribute_value(attr_index);
|
||||
|
||||
if (!elev_attr1.isNull() && !elev_attr2.isNull()) {
|
||||
double elev1 = elev_attr1;
|
||||
@@ -95,12 +96,12 @@ namespace IfcGeom {
|
||||
const std::string& context() const { return _context; }
|
||||
const std::string& unique_id() const { return _unique_id; }
|
||||
const Transformation& transformation() const { return _transformation; }
|
||||
const IfcUtil::IfcBaseEntity* product() const { return product_; }
|
||||
const express::Entity& product() const { return product_; }
|
||||
const std::vector<const IfcGeom::Element*>& parents() const { return _parents; }
|
||||
void SetParents(std::vector<const IfcGeom::Element*>& newparents) { _parents = newparents; }
|
||||
|
||||
Element(const ifcopenshell::geometry::Settings& settings, int id, int parent_id, const std::string& name, const std::string& type,
|
||||
const std::string& guid, const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4::ptr& trsf, const IfcUtil::IfcBaseEntity* product)
|
||||
const std::string& guid, const std::string& context, const ifcopenshell::geometry::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)
|
||||
{
|
||||
@@ -110,10 +111,10 @@ namespace IfcGeom {
|
||||
oss << "project";
|
||||
} else {
|
||||
try {
|
||||
oss << "product-" << IfcParse::IfcGlobalId(guid).formatted();
|
||||
oss << "product-" << ifcopenshell::global_id(guid).formatted();
|
||||
} catch (const std::exception& e) {
|
||||
oss << "product";
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +138,7 @@ namespace IfcGeom {
|
||||
const IfcGeom::Representation::BRep& geometry() const { return *_geometry; }
|
||||
BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid,
|
||||
const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4::ptr& trsf, const boost::shared_ptr<IfcGeom::Representation::BRep>& geometry,
|
||||
const IfcUtil::IfcBaseEntity* product)
|
||||
const express::Entity& product)
|
||||
: Element(geometry->settings(), id, parent_id, name, type, guid, context, trsf, product)
|
||||
, _geometry(geometry)
|
||||
{}
|
||||
|
||||
+20
-24
@@ -29,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
#include "../ifcgeom/AbstractKernel.h"
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/file.h"
|
||||
#include "../ifcgeom/abstract_mapping.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
@@ -41,10 +41,6 @@
|
||||
#include <functional>
|
||||
|
||||
namespace IfcGeom {
|
||||
/// The filter function (free or member function) or function object (use boost::ref() to reference to it)
|
||||
/// 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 boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
|
||||
|
||||
struct filter
|
||||
{
|
||||
@@ -60,7 +56,7 @@ namespace IfcGeom {
|
||||
/// Optional description for the filtering criteria of this filter.
|
||||
std::string description;
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const {
|
||||
bool match(const express::Base& prod, const ifcopenshell::geometry::filter_t& pred) const {
|
||||
bool is_match = pred(prod);
|
||||
if (!is_match && traverse) {
|
||||
is_match = traverse_match(prod, pred);
|
||||
@@ -68,16 +64,16 @@ namespace IfcGeom {
|
||||
return is_match == include;
|
||||
}
|
||||
|
||||
bool traverse_match(IfcUtil::IfcBaseEntity* prod, const filter_t& pred) const
|
||||
bool traverse_match(const express::Base& prod, const ifcopenshell::geometry::filter_t& pred) const
|
||||
{
|
||||
IfcUtil::IfcBaseEntity* parent, *current = prod;
|
||||
express::Base parent, current = prod;
|
||||
// @todo examine if this can indeed be static. For now usage is only
|
||||
// in IfcConvert so invocation is bound to a single file with a single
|
||||
// schema.
|
||||
// @todo pass settings
|
||||
ifcopenshell::geometry::Settings s;
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->file_, s);
|
||||
while ((parent = mapping->get_decomposing_entity(current, traverse_openings)) != nullptr) {
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod.file(), s);
|
||||
while ((parent = mapping->get_decomposing_entity(current, traverse_openings))) {
|
||||
if (pred(parent)) {
|
||||
return true;
|
||||
}
|
||||
@@ -136,9 +132,9 @@ namespace IfcGeom {
|
||||
attribute_filter(const std::string& attribute_name)
|
||||
: attribute_name(attribute_name) {}
|
||||
|
||||
std::string value(IfcUtil::IfcBaseEntity* prod) const {
|
||||
std::string value(const express::Base& prod) const {
|
||||
try {
|
||||
return (std::string) prod->get(attribute_name);
|
||||
return (std::string) prod.as<express::Entity>().get(attribute_name);
|
||||
} catch (...) {
|
||||
// Either
|
||||
// (a) not an attribute name for this entity instance
|
||||
@@ -150,11 +146,11 @@ namespace IfcGeom {
|
||||
}
|
||||
}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool match(express::Base prod) const {
|
||||
return wildcard_filter::match(value(prod));
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool operator()(express::Base prod) const {
|
||||
return filter::match(prod, std::bind(&attribute_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
@@ -175,21 +171,21 @@ namespace IfcGeom {
|
||||
};
|
||||
|
||||
struct layer_filter : public wildcard_filter {
|
||||
typedef std::map<std::string, IfcUtil::IfcBaseEntity*> layer_map_t;
|
||||
typedef std::map<std::string, express::Base> layer_map_t;
|
||||
|
||||
layer_filter() {}
|
||||
layer_filter(bool include, bool traverse, const std::set<std::string>& patterns)
|
||||
: wildcard_filter(include, traverse, patterns) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool match(express::Base prod) const {
|
||||
// @todo
|
||||
ifcopenshell::geometry::Settings s;
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->file_, s);
|
||||
static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod.file(), s);
|
||||
layer_map_t layers = mapping->get_layers(prod);
|
||||
return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end();
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool operator()(express::Base prod) const {
|
||||
return filter::match(prod, std::bind(&layer_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
@@ -222,17 +218,17 @@ namespace IfcGeom {
|
||||
: filter(include, traverse)
|
||||
, entity_names(entity_names) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool match(express::Base prod) const {
|
||||
// The set is iterated over to able to filter on subtypes.
|
||||
for (auto& name : entity_names) {
|
||||
if (prod->declaration().is(name)) {
|
||||
if (prod.declaration().is(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool operator()(express::Base prod) const {
|
||||
return filter::match(prod, std::bind(&entity_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
@@ -254,11 +250,11 @@ namespace IfcGeom {
|
||||
: filter(include, traverse)
|
||||
, instance_ids_(instance_ids) {}
|
||||
|
||||
bool match(IfcUtil::IfcBaseEntity* prod) const {
|
||||
return instance_ids_.find(prod->id()) != instance_ids_.end();
|
||||
bool match(express::Base prod) const {
|
||||
return instance_ids_.find(prod.id()) != instance_ids_.end();
|
||||
}
|
||||
|
||||
bool operator()(IfcUtil::IfcBaseEntity* prod) const {
|
||||
bool operator()(express::Base prod) const {
|
||||
return filter::match(prod, std::bind(&instance_id_filter::match, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep)
|
||||
surface_styles_.push_back(clr(1));
|
||||
surface_styles_.push_back(clr(2));
|
||||
|
||||
sid = it->Style().instance ? it->Style().instance->as<IfcUtil::IfcBaseEntity>()->id() : -1;
|
||||
sid = it->Style().instance ? it->Style().instance.id() : -1;
|
||||
} else {
|
||||
surface_styles_.push_back(-1.);
|
||||
surface_styles_.push_back(-1.);
|
||||
|
||||
+65
-63
@@ -31,7 +31,7 @@ bool IfcGeom::Iterator::initialize() {
|
||||
try {
|
||||
converter_->mapping()->get_representations(reps, filters_);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
}
|
||||
time_points[1] = high_resolution_clock::now();
|
||||
|
||||
@@ -46,9 +46,9 @@ bool IfcGeom::Iterator::initialize() {
|
||||
if (!res.item) {
|
||||
continue;
|
||||
}
|
||||
std::transform(task.products->begin(), task.products->end(), std::back_inserter(res.products), [this, &res](IfcUtil::IfcBaseClass* prod) {
|
||||
std::transform(task.products.begin(), task.products.end(), std::back_inserter(res.products), [this, &res](const express::Base& prod) {
|
||||
auto prod_item = converter_->mapping()->map(prod);
|
||||
return std::make_pair(prod->as<IfcUtil::IfcBaseEntity>(), ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
|
||||
return std::make_pair(prod, ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
|
||||
});
|
||||
}
|
||||
tasks_.push_back(res);
|
||||
@@ -57,7 +57,7 @@ bool IfcGeom::Iterator::initialize() {
|
||||
if (settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() && settings_.get<ifcopenshell::geometry::settings::PermissiveShapeReuse>().get()) {
|
||||
std::unordered_map<
|
||||
ifcopenshell::geometry::taxonomy::item::ptr,
|
||||
std::vector<std::pair<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>>> folded;
|
||||
std::vector<std::pair<express::Base, ifcopenshell::geometry::taxonomy::matrix4::ptr>>> folded;
|
||||
|
||||
for (auto& r : tasks_) {
|
||||
auto i = r.item;
|
||||
@@ -94,7 +94,7 @@ bool IfcGeom::Iterator::initialize() {
|
||||
tasks_.back().item = p.first;
|
||||
tasks_.back().products = p.second;
|
||||
}
|
||||
Logger::Notice("Merged " + std::to_string(old_size) + " tasks into " + std::to_string(tasks_.size()) + " tasks due to permissive shape reuse");
|
||||
logger::notice("Merged " + std::to_string(old_size) + " tasks into " + std::to_string(tasks_.size()) + " tasks due to permissive shape reuse");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ bool IfcGeom::Iterator::initialize() {
|
||||
|
||||
size_t num_products = 0;
|
||||
for (auto& r : tasks_) {
|
||||
num_products += !settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() ? r.products_2->size() : r.products.size();
|
||||
num_products += !settings_.get<ifcopenshell::geometry::settings::NoParallelMapping>().get() ? r.products_2.size() : r.products.size();
|
||||
}
|
||||
|
||||
time_points[2] = high_resolution_clock::now();
|
||||
@@ -116,7 +116,7 @@ bool IfcGeom::Iterator::initialize() {
|
||||
|
||||
std::vector<taxonomy::ptr> items;
|
||||
std::map<taxonomy::ptr, taxonomy::matrix4> placements;
|
||||
std::transform(products.begin(), products.end(), std::back_inserter(items), [this, &placements](IfcUtil::IfcBaseClass* p) {
|
||||
std::transform(products.begin(), products.end(), std::back_inserter(items), [this, &placements](express::Base p) {
|
||||
auto item = converter_->mapping()->map(p);
|
||||
// Product placements do not affect item reuse and should temporarily be swapped to identity
|
||||
if (item) {
|
||||
@@ -132,18 +132,18 @@ bool IfcGeom::Iterator::initialize() {
|
||||
geometry_conversion_result r;
|
||||
r.item = *it;
|
||||
std::transform(it, jt, std::back_inserter(r.products), [&r, &placements](taxonomy::ptr product_node) {
|
||||
return std::make_pair((IfcUtil::IfcBaseEntity*) product_node->instance, placements[product_node]);
|
||||
return std::make_pair((express::Base) product_node->instance, placements[product_node]);
|
||||
});
|
||||
tasks_.push_back(r);
|
||||
it = jt;
|
||||
}
|
||||
*/
|
||||
|
||||
Logger::Notice("Created " + boost::lexical_cast<std::string>(tasks_.size()) + " tasks for " + boost::lexical_cast<std::string>(num_products) + " products");
|
||||
logger::notice("Created " + boost::lexical_cast<std::string>(tasks_.size()) + " tasks for " + boost::lexical_cast<std::string>(num_products) + " products");
|
||||
|
||||
if (tasks_.size() == 0) {
|
||||
Logger::Warning("No representations encountered, aborting");
|
||||
initialization_outcome_.reset(false);
|
||||
logger::warning("No representations encountered, aborting");
|
||||
initialization_outcome_.emplace(false);
|
||||
} else if (!settings_.get<ifcopenshell::geometry::settings::DeferProcessingFirstElement>().get()) {
|
||||
|
||||
task_iterator_ = tasks_.begin();
|
||||
@@ -161,7 +161,7 @@ bool IfcGeom::Iterator::initialize() {
|
||||
initialization_outcome_ = create();
|
||||
}
|
||||
} else {
|
||||
initialization_outcome_.reset(true);
|
||||
initialization_outcome_.emplace(true);
|
||||
}
|
||||
|
||||
return *initialization_outcome_;
|
||||
@@ -231,14 +231,14 @@ void IfcGeom::Iterator::process_concurrently() {
|
||||
try {
|
||||
this->create_element_(kernel, settings, rep);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(
|
||||
logger::error(
|
||||
std::string("Exception '") + e.what() +
|
||||
std::string("' occurred while iterator was creating a shape: "),
|
||||
rep->item->instance
|
||||
);
|
||||
had_error_processing_elements_ = true;
|
||||
} catch (...) {
|
||||
Logger::Error(
|
||||
logger::error(
|
||||
"Unknown exception occurred while iteartor was creating a shape: ",
|
||||
rep->item->instance
|
||||
);
|
||||
@@ -263,10 +263,10 @@ void IfcGeom::Iterator::process_concurrently() {
|
||||
|
||||
finished_ = true;
|
||||
|
||||
Logger::SetProduct(boost::none);
|
||||
logger::set_product(std::nullopt);
|
||||
|
||||
if (!terminating_) {
|
||||
Logger::Status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
|
||||
logger::status("\rDone creating geometry (" + boost::lexical_cast<std::string>(all_processed_elements_.size()) +
|
||||
" objects) ");
|
||||
}
|
||||
}
|
||||
@@ -306,9 +306,9 @@ void IfcGeom::Iterator::compute_bounds(bool with_geometry)
|
||||
std::vector<ifcopenshell::geometry::geometry_conversion_task> reps;
|
||||
converter_->mapping()->get_representations(reps, filters_);
|
||||
|
||||
std::vector<IfcUtil::IfcBaseClass*> products;
|
||||
std::vector<express::Base> products;
|
||||
for (auto& r : reps) {
|
||||
std::copy(r.products->begin(), r.products->end(), std::back_inserter(products));
|
||||
std::copy(r.products.begin(), r.products.end(), std::back_inserter(products));
|
||||
}
|
||||
|
||||
for (auto& product : products) {
|
||||
@@ -323,7 +323,7 @@ void IfcGeom::Iterator::compute_bounds(bool with_geometry)
|
||||
}
|
||||
}
|
||||
|
||||
const IfcUtil::IfcBaseClass* IfcGeom::Iterator::create_shape_model_for_next_entity() {
|
||||
express::Base IfcGeom::Iterator::create_shape_model_for_next_entity() {
|
||||
geometry_conversion_result* task = nullptr;
|
||||
for (; task_iterator_ < tasks_.end();) {
|
||||
task = &*task_iterator_++;
|
||||
@@ -336,9 +336,9 @@ const IfcUtil::IfcBaseClass* IfcGeom::Iterator::create_shape_model_for_next_enti
|
||||
}
|
||||
if (task) {
|
||||
process_finished_rep(task);
|
||||
return task->item->instance->as<IfcUtil::IfcBaseClass>();
|
||||
return task->item->instance;
|
||||
} else {
|
||||
return nullptr;
|
||||
return express::Base{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,31 +349,31 @@ void IfcGeom::Iterator::create_element_(ifcopenshell::geometry::Converter* kerne
|
||||
if (!rep->item) {
|
||||
return;
|
||||
}
|
||||
std::transform(rep->products_2->begin(), rep->products_2->end(), std::back_inserter(rep->products), [this, &rep, kernel](IfcUtil::IfcBaseClass* prod) {
|
||||
std::transform(rep->products_2.begin(), rep->products_2.end(), std::back_inserter(rep->products), [this, &rep, kernel](const express::Base& prod) {
|
||||
auto prod_item = kernel->mapping()->map(prod);
|
||||
return std::make_pair(prod->as<IfcUtil::IfcBaseEntity>(), ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
|
||||
return std::make_pair(prod, ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::geom_item>(prod_item)->matrix);
|
||||
});
|
||||
} else {
|
||||
}
|
||||
|
||||
auto product_node = rep->products.front();
|
||||
const IfcUtil::IfcBaseEntity* product = product_node.first;
|
||||
const express::Base product = product_node.first;
|
||||
const auto& place = product_node.second;
|
||||
|
||||
Logger::SetProduct(product);
|
||||
logger::set_product(product);
|
||||
|
||||
IfcGeom::BRepElement* brep = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product->get("GlobalId"), std::to_string(rep->item->instance->as<IfcUtil::IfcBaseEntity>()->id()), [kernel, settings, product, place, rep]() {
|
||||
IfcGeom::BRepElement* brep = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product.as<express::Entity>().get("GlobalId"), std::to_string(rep->item->instance.id()), [kernel, settings, product, place, rep]() {
|
||||
return kernel->create_brep_for_representation_and_product(rep->item, product, place);
|
||||
}));
|
||||
|
||||
if (!brep) {
|
||||
Logger::SetProduct(boost::none);
|
||||
logger::set_product(std::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto elem = process_based_on_settings(settings, brep);
|
||||
if (!elem) {
|
||||
Logger::SetProduct(boost::none);
|
||||
logger::set_product(std::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -382,10 +382,10 @@ void IfcGeom::Iterator::create_element_(ifcopenshell::geometry::Converter* kerne
|
||||
|
||||
for (auto it = rep->products.begin() + 1; it != rep->products.end(); ++it) {
|
||||
const auto& p = *it;
|
||||
const IfcUtil::IfcBaseEntity* product2 = p.first;
|
||||
const express::Base product2 = p.first;
|
||||
const auto& place2 = p.second;
|
||||
|
||||
IfcGeom::BRepElement* brep2 = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product2->get("GlobalId"), std::to_string(rep->item->instance->as<IfcUtil::IfcBaseEntity>()->id()), [kernel, settings, product2, place2, brep]() {
|
||||
IfcGeom::BRepElement* brep2 = static_cast<IfcGeom::BRepElement*>(decorate_with_cache_(GeometrySerializer::READ_BREP, (std::string)product2.as<express::Entity>().get("GlobalId"), std::to_string(rep->item->instance.id()), [kernel, settings, product2, place2, brep]() {
|
||||
return kernel->create_brep_for_processed_representation(product2, place2, brep);
|
||||
}));
|
||||
if (brep2) {
|
||||
@@ -397,7 +397,7 @@ void IfcGeom::Iterator::create_element_(ifcopenshell::geometry::Converter* kerne
|
||||
}
|
||||
}
|
||||
|
||||
Logger::SetProduct(boost::none);
|
||||
logger::set_product(std::nullopt);
|
||||
}
|
||||
|
||||
IfcGeom::Element* IfcGeom::Iterator::process_based_on_settings(ifcopenshell::geometry::Settings settings, IfcGeom::BRepElement* elem, IfcGeom::TriangulationElement* previous)
|
||||
@@ -406,7 +406,7 @@ IfcGeom::Element* IfcGeom::Iterator::process_based_on_settings(ifcopenshell::geo
|
||||
try {
|
||||
return new IfcGeom::SerializedElement(*elem);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
logger::message(logger::LOG_ERROR, "Getting a serialized element from model failed.");
|
||||
return nullptr;
|
||||
}
|
||||
} else if (settings.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::TRIANGULATED) {
|
||||
@@ -425,7 +425,7 @@ IfcGeom::Element* IfcGeom::Iterator::process_based_on_settings(ifcopenshell::geo
|
||||
return new TriangulationElement(*elem, previous->geometry_pointer());
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
logger::message(logger::LOG_ERROR, "Getting a triangulation element from model failed.");
|
||||
}
|
||||
return (TriangulationElement*)nullptr;
|
||||
});
|
||||
@@ -466,7 +466,7 @@ void IfcGeom::Iterator::log_timepoints() const {
|
||||
for (auto it = time_points.begin() + 1; it != time_points.end(); ++it) {
|
||||
auto jt = it - 1;
|
||||
duration<double, std::milli> ms_double = (*it) - (*jt);
|
||||
Logger::Notice(labels[std::distance(time_points.begin(), jt)] + " took " + std::to_string(ms_double.count()) + "ms");
|
||||
logger::notice(labels[std::distance(time_points.begin(), jt)] + " took " + std::to_string(ms_double.count()) + "ms");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,7 +490,7 @@ void IfcGeom::Iterator::validate_iterator_state() const {
|
||||
|
||||
/// Moves to the next shape representation, create its geometry, and returns the associated product.
|
||||
/// Use get() to retrieve the created geometry.
|
||||
const IfcUtil::IfcBaseClass* IfcGeom::Iterator::next() {
|
||||
express::Base IfcGeom::Iterator::next() {
|
||||
using std::chrono::high_resolution_clock;
|
||||
validate_iterator_state();
|
||||
|
||||
@@ -501,11 +501,11 @@ const IfcUtil::IfcBaseClass* IfcGeom::Iterator::next() {
|
||||
|
||||
if (num_threads_ != 1) {
|
||||
if (!wait_for_element()) {
|
||||
Logger::SetProduct(boost::none);
|
||||
logger::set_product(std::nullopt);
|
||||
time_points[3] = high_resolution_clock::now();
|
||||
log_timepoints();
|
||||
task_result_ptr_exhausted = true;
|
||||
return nullptr;
|
||||
return express::Base{};
|
||||
}
|
||||
|
||||
task_result_iterator_++;
|
||||
@@ -517,11 +517,11 @@ const IfcUtil::IfcBaseClass* IfcGeom::Iterator::next() {
|
||||
// shape representation
|
||||
if (task_result_iterator_ == --all_processed_elements_.end()) {
|
||||
if (!create()) {
|
||||
Logger::SetProduct(boost::none);
|
||||
logger::set_product(std::nullopt);
|
||||
time_points[3] = high_resolution_clock::now();
|
||||
log_timepoints();
|
||||
task_result_ptr_exhausted = true;
|
||||
return nullptr;
|
||||
return express::Base{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,7 +554,7 @@ IfcGeom::Element* IfcGeom::Iterator::get()
|
||||
try {
|
||||
parent_object = get_object(ret->parent_id());
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
|
||||
@@ -565,14 +565,14 @@ IfcGeom::Element* IfcGeom::Iterator::get()
|
||||
while (parent_object != NULL && hasParent && parent_object->parent_id() != -1) {
|
||||
// Find the next parent
|
||||
auto pid = parent_object->parent_id();
|
||||
auto ifc_product = ifc_file->instance_by_id(pid)->as<IfcUtil::IfcBaseEntity>();
|
||||
if (ifc_product->declaration().name() == "IfcProject") {
|
||||
auto ifc_product = ifc_file->instance_by_id(pid);
|
||||
if (ifc_product.declaration().name() == "IfcProject") {
|
||||
hasParent = false;
|
||||
} else {
|
||||
try {
|
||||
parent_object = get_object(pid);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
hasParent = false;
|
||||
}
|
||||
}
|
||||
@@ -595,20 +595,20 @@ const IfcGeom::Element* IfcGeom::Iterator::get_object(int id) {
|
||||
ifcopenshell::geometry::taxonomy::matrix4::ptr m4;
|
||||
int parent_id = -1;
|
||||
std::string instance_type, product_name, product_guid;
|
||||
IfcUtil::IfcBaseEntity* ifc_product = 0;
|
||||
express::Base ifc_product;
|
||||
|
||||
try {
|
||||
ifc_product = ifc_file->instance_by_id(id)->as<IfcUtil::IfcBaseEntity>();
|
||||
instance_type = ifc_product->declaration().name();
|
||||
ifc_product = ifc_file->instance_by_id(id);
|
||||
instance_type = ifc_product.declaration().name();
|
||||
|
||||
if (ifc_product->declaration().is("IfcRoot")) {
|
||||
product_guid = (std::string)ifc_product->get("GlobalId");
|
||||
product_name = ifc_product->get_value<std::string>("Name", "");
|
||||
if (ifc_product.declaration().is("IfcRoot")) {
|
||||
product_guid = ifc_product.as<express::Entity>().get_value<std::string>("GlobalId");
|
||||
product_name = ifc_product.as<express::Entity>().get_value<std::string>("Name", "");
|
||||
}
|
||||
|
||||
auto parent_object = converter_->mapping()->get_decomposing_entity(ifc_product);
|
||||
if (parent_object) {
|
||||
parent_id = parent_object->id();
|
||||
parent_id = parent_object.id();
|
||||
}
|
||||
|
||||
// fails in case of IfcProject
|
||||
@@ -619,24 +619,26 @@ const IfcGeom::Element* IfcGeom::Iterator::get_object(int id) {
|
||||
m4 = casted->matrix;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error returning product");
|
||||
logger::error(e);
|
||||
}
|
||||
catch (...) {
|
||||
logger::error("Unknown error returning product");
|
||||
}
|
||||
|
||||
Element* ifc_object = new Element(settings_, id, parent_id, product_name, instance_type, product_guid, "", m4, ifc_product);
|
||||
Element* ifc_object = new Element(settings_, id, parent_id, product_name, instance_type, product_guid, "", m4, ifc_product.as<express::Entity>());
|
||||
return ifc_object;
|
||||
}
|
||||
|
||||
const IfcUtil::IfcBaseClass* IfcGeom::Iterator::create() {
|
||||
const IfcUtil::IfcBaseClass* product = nullptr;
|
||||
express::Base IfcGeom::Iterator::create() {
|
||||
express::Base product;
|
||||
try {
|
||||
product = create_shape_model_for_next_entity();
|
||||
} catch (const std::exception& e) {
|
||||
Logger::Error(e);
|
||||
logger::error(e);
|
||||
had_error_processing_elements_ = true;
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating geometry");
|
||||
}
|
||||
catch (...) {
|
||||
logger::error("Unknown error creating geometry");
|
||||
had_error_processing_elements_ = true;
|
||||
}
|
||||
return product;
|
||||
@@ -655,7 +657,7 @@ ifcopenshell::geometry::taxonomy::direction3::ptr IfcGeom::Iterator::remove_offs
|
||||
throw std::runtime_error("remove_offset() can only be called with defer-processing-first-element and no-parallel-mapping settings");
|
||||
}
|
||||
|
||||
auto collect_offset = [&](const item::ptr& itm, const std::vector<std::pair<IfcUtil::IfcBaseEntity*, matrix4::ptr>>& pr) -> std::pair<double, Eigen::Vector3d> {
|
||||
auto collect_offset = [&](const item::ptr& itm, const std::vector<std::pair<express::Base, matrix4::ptr>>& pr) -> std::pair<double, Eigen::Vector3d> {
|
||||
std::function<std::pair<double, Eigen::Vector3d>(const item::ptr&, Eigen::Matrix4d)> traverse;
|
||||
traverse = [&](const item::ptr& node, Eigen::Matrix4d m4) -> std::pair<double, Eigen::Vector3d> {
|
||||
if (auto shl = std::dynamic_pointer_cast<shell>(node)) {
|
||||
@@ -735,7 +737,7 @@ ifcopenshell::geometry::taxonomy::direction3::ptr IfcGeom::Iterator::remove_offs
|
||||
Eigen::Matrix4d translation_matrix = Eigen::Matrix4d::Identity();
|
||||
translation_matrix.block<3, 1>(0, 3) = vec;
|
||||
|
||||
auto remove_offset = [&](const item::ptr& itm, const std::vector<std::pair<IfcUtil::IfcBaseEntity*, matrix4::ptr>>& pr) -> bool {
|
||||
auto remove_offset = [&](const item::ptr& itm, const std::vector<std::pair<express::Base, matrix4::ptr>>& pr) -> bool {
|
||||
std::function<bool(const item::ptr&, Eigen::Matrix4d)> traverse;
|
||||
traverse = [&](const item::ptr& node, Eigen::Matrix4d m4) -> bool {
|
||||
if (auto shl = std::dynamic_pointer_cast<shell>(node)) {
|
||||
@@ -808,8 +810,8 @@ ifcopenshell::geometry::taxonomy::direction3::ptr IfcGeom::Iterator::remove_offs
|
||||
}
|
||||
}
|
||||
|
||||
Logger::Notice("Removed large offsets within " + std::to_string(num_offset_applied) + " products");
|
||||
Logger::Notice("Offset applied (" + std::to_string(vec(0)) + "," + std::to_string(vec(1)) + "," + std::to_string(vec(2)) + ")");
|
||||
logger::notice("Removed large offsets within " + std::to_string(num_offset_applied) + " products");
|
||||
logger::notice("Offset applied (" + std::to_string(vec(0)) + "," + std::to_string(vec(1)) + "," + std::to_string(vec(2)) + ")");
|
||||
|
||||
return make<direction3>(vec);
|
||||
}
|
||||
|
||||
+28
-24
@@ -58,7 +58,7 @@
|
||||
#ifndef IFCGEOMITERATOR_H
|
||||
#define IFCGEOMITERATOR_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/file.h"
|
||||
|
||||
#include "../ifcgeom/IfcGeomElement.h"
|
||||
#include "../ifcgeom/ConversionResult.h"
|
||||
@@ -87,14 +87,18 @@ namespace IfcGeom {
|
||||
|
||||
// For NoParallelMapping==true
|
||||
ifcopenshell::geometry::taxonomy::ptr item;
|
||||
std::vector<std::pair<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::taxonomy::matrix4::ptr>> products;
|
||||
std::vector<std::pair<express::Base, ifcopenshell::geometry::taxonomy::matrix4::ptr>> products;
|
||||
|
||||
// For NoParallelMapping==false
|
||||
IfcUtil::IfcBaseEntity* representation;
|
||||
aggregate_of_instance::ptr products_2;
|
||||
express::Base representation;
|
||||
std::vector<express::Base> products_2;
|
||||
|
||||
std::vector<IfcGeom::BRepElement*> breps;
|
||||
std::vector<IfcGeom::Element*> elements;
|
||||
|
||||
bool is_parallel() const {
|
||||
return !!representation;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -122,8 +126,8 @@ namespace IfcGeom {
|
||||
size_t async_elements_returned_ = 0;
|
||||
|
||||
ifcopenshell::geometry::Settings settings_;
|
||||
IfcParse::IfcFile* ifc_file;
|
||||
std::vector<filter_t> filters_;
|
||||
ifcopenshell::file* ifc_file;
|
||||
std::vector<ifcopenshell::geometry::filter_t> filters_;
|
||||
int num_threads_;
|
||||
std::string geometry_library_;
|
||||
|
||||
@@ -189,7 +193,7 @@ namespace IfcGeom {
|
||||
return element;
|
||||
}
|
||||
|
||||
const IfcUtil::IfcBaseClass* create_shape_model_for_next_entity();
|
||||
express::Base create_shape_model_for_next_entity();
|
||||
|
||||
void create_element_(
|
||||
ifcopenshell::geometry::Converter* kernel,
|
||||
@@ -209,7 +213,7 @@ namespace IfcGeom {
|
||||
ifcopenshell::geometry::taxonomy::direction3::ptr remove_offset_();
|
||||
public:
|
||||
|
||||
Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector<IfcGeom::filter_t>& filters, int num_threads)
|
||||
Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, const ifcopenshell::geometry::Settings& settings, ifcopenshell::file* file, const std::vector<ifcopenshell::geometry::filter_t>& filters, int num_threads)
|
||||
: settings_(settings)
|
||||
, ifc_file(file)
|
||||
, filters_(filters)
|
||||
@@ -220,7 +224,7 @@ namespace IfcGeom {
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file)
|
||||
Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, const ifcopenshell::geometry::Settings& settings, ifcopenshell::file* file)
|
||||
: settings_(settings)
|
||||
, ifc_file(file)
|
||||
, num_threads_(1)
|
||||
@@ -229,7 +233,7 @@ namespace IfcGeom {
|
||||
{
|
||||
}
|
||||
|
||||
Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, int num_threads)
|
||||
Iterator(std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel>&& geometry_library, const ifcopenshell::geometry::Settings& settings, ifcopenshell::file* file, int num_threads)
|
||||
: settings_(settings)
|
||||
, ifc_file(file)
|
||||
, num_threads_(num_threads)
|
||||
@@ -251,16 +255,16 @@ namespace IfcGeom {
|
||||
return items;
|
||||
}
|
||||
|
||||
aggregate_of_aggregate_of_instance::ptr get_task_products() const {
|
||||
aggregate_of_aggregate_of_instance::ptr products = aggregate_of_aggregate_of_instance::ptr(new aggregate_of_aggregate_of_instance);
|
||||
std::vector<std::vector<express::Base>> get_task_products() const {
|
||||
std::vector<std::vector<express::Base>> products;
|
||||
for (const auto& task : tasks_) {
|
||||
if (task.products_2) {
|
||||
products->push(task.products_2);
|
||||
if (task.is_parallel()) {
|
||||
products.push_back(task.products_2);
|
||||
} else {
|
||||
for (auto& product : task.products) {
|
||||
aggregate_of_instance::ptr p(new aggregate_of_instance);
|
||||
p->push(product.first);
|
||||
products->push(p);
|
||||
std::vector<express::Base> p;
|
||||
p.push_back(product.first);
|
||||
products.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,7 +276,7 @@ namespace IfcGeom {
|
||||
// Check if error occurred during iterator initialization or iteration over elements.
|
||||
bool had_error_processing_elements() const { return had_error_processing_elements_; }
|
||||
|
||||
boost::optional<bool> initialization_outcome_;
|
||||
std::optional<bool> initialization_outcome_;
|
||||
|
||||
/**
|
||||
* @return Returns true if the iterator is initialized with any elements, false otherwise.
|
||||
@@ -301,19 +305,19 @@ namespace IfcGeom {
|
||||
return progress_;
|
||||
}
|
||||
|
||||
std::string getLog() const { return Logger::GetLog(); }
|
||||
std::string getLog() const { return logger::get_log(); }
|
||||
|
||||
IfcParse::IfcFile* file() const { return ifc_file; }
|
||||
ifcopenshell::file* file() const { return ifc_file; }
|
||||
|
||||
const std::vector<IfcGeom::filter_t>& filters() const { return filters_; }
|
||||
std::vector<IfcGeom::filter_t>& filters() { return filters_; }
|
||||
const std::vector<ifcopenshell::geometry::filter_t>& filters() const { return filters_; }
|
||||
std::vector<ifcopenshell::geometry::filter_t>& filters() { return filters_; }
|
||||
|
||||
const ifcopenshell::geometry::taxonomy::point3& bounds_min() const { return bounds_min_; }
|
||||
const ifcopenshell::geometry::taxonomy::point3& bounds_max() const { return bounds_max_; }
|
||||
|
||||
/// Moves to the next shape representation, create its geometry, and returns the associated product.
|
||||
/// Use get() to retrieve the created geometry.
|
||||
const IfcUtil::IfcBaseClass* next();
|
||||
express::Base next();
|
||||
|
||||
/// Gets the representation of the current geometrical entity.
|
||||
Element* get();
|
||||
@@ -326,7 +330,7 @@ namespace IfcGeom {
|
||||
|
||||
const Element* get_object(int id);
|
||||
|
||||
const IfcUtil::IfcBaseClass* create();
|
||||
express::Base create();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
set(geometry_serialization_plugin_runtime_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
|
||||
|
||||
add_subdirectory(schema)
|
||||
|
||||
add_library(geometry_serializer Serialization.cpp)
|
||||
file(GLOB IFCGEOM_SERIALIZATION_H_FILE *.h)
|
||||
|
||||
set_target_properties(
|
||||
geometry_serializer
|
||||
PROPERTIES COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS" PUBLIC_HEADER "${IFCGEOM_SERIALIZATION_H_FILE}"
|
||||
add_library(geometry_serializer Serialization.cpp opencascade_geometry_ifc_writer_plugin.cpp)
|
||||
add_library(opencascade_geometry_ifc_writer ALIAS geometry_serializer)
|
||||
set_target_properties(geometry_serializer PROPERTIES
|
||||
COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
)
|
||||
target_link_libraries(geometry_serializer ${geometry_serializer_libraries} IfcParse)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer" ${geometry_serializer_libraries})
|
||||
target_link_libraries(geometry_serializer plugin IfcGeom IfcParse ${OpenCASCADE_LIBRARIES})
|
||||
target_link_libraries(geometry_serializer geometry_kernel_opencascade)
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer")
|
||||
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
|
||||
|
||||
install(
|
||||
TARGETS geometry_serializer ${geometry_serializer_libraries}
|
||||
EXPORT ${IFCOPENSHELL_EXPORT_TARGETS}
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ifcgeom/Serialization"
|
||||
install(FILES Serialization.h
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/Serialization
|
||||
)
|
||||
|
||||
install(TARGETS geometry_serializer ${geometry_serializer_libraries})
|
||||
|
||||
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
|
||||
|
||||
@@ -1,52 +1,64 @@
|
||||
#include "Serialization.h"
|
||||
#include "opencascade_geometry_ifc_writer_plugin.h"
|
||||
|
||||
#include "../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
|
||||
#include "../../ifcparse/file.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <mutex>
|
||||
|
||||
#define EXTERNAL_DEFS_1(r, data, elem) \
|
||||
IfcUtil::IfcBaseClass* BOOST_PP_CAT(tesselate_Ifc, elem)(const TopoDS_Shape& shape, double deflection);
|
||||
|
||||
#define EXTERNAL_DEFS_2(r, data, elem) \
|
||||
IfcUtil::IfcBaseClass* BOOST_PP_CAT(serialise_Ifc, elem)(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
#define CONDITIONAL_CALL(r, data, elem) \
|
||||
if (schema_name_lower == BOOST_PP_STRINGIZE(BOOST_PP_CAT(elem,))) { \
|
||||
return BOOST_PP_CAT(METHOD_NAME, elem)(shape, arg_2); \
|
||||
namespace {
|
||||
std::string writer_schema_key(const std::string& schema_name) {
|
||||
return boost::to_upper_copy(schema_name);
|
||||
}
|
||||
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_1, , SCHEMA_SEQ);
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_2, , SCHEMA_SEQ);
|
||||
|
||||
#define METHOD_NAME tesselate_Ifc
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double arg_2) {
|
||||
// @todo an ugly hack to guarantee schemas are initialised.
|
||||
try {
|
||||
IfcParse::schema_by_name("IFC2X3");
|
||||
} catch (IfcParse::IfcException&) {}
|
||||
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name.substr(3));
|
||||
|
||||
BOOST_PP_SEQ_FOR_EACH(CONDITIONAL_CALL, , SCHEMA_SEQ);
|
||||
|
||||
throw IfcParse::IfcException("No geometry serialization available for " + schema_name);
|
||||
}
|
||||
|
||||
#undef METHOD_NAME
|
||||
#define METHOD_NAME serialise_Ifc
|
||||
IfcGeom::opencascade_geometry_ifc_writer_registry& IfcGeom::opencascade_geometry_ifc_writer_registry_instance() {
|
||||
static opencascade_geometry_ifc_writer_registry registry;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, load_opencascade_geometry_ifc_writer_plugins, std::ref(registry));
|
||||
return registry;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* IfcGeom::serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool arg_2) {
|
||||
// @todo an ugly hack to guarantee schemas are initialised.
|
||||
try {
|
||||
IfcParse::schema_by_name("IFC2X3");
|
||||
} catch (IfcParse::IfcException&) {}
|
||||
void IfcGeom::opencascade_geometry_ifc_writer_registry::bind(const std::string& schema_name, serialise_fn serialise, tesselate_fn tesselate, const ifcopenshell::plugin::module& module) {
|
||||
entry entry;
|
||||
entry.serialise_ = serialise;
|
||||
entry.tesselate_ = tesselate;
|
||||
entry.module_ = module.meta().id.empty() ? ifcopenshell::plugin::module(opencascade_geometry_ifc_writer_plugin_metadata(schema_name)) : module;
|
||||
entries_[writer_schema_key(schema_name)] = entry;
|
||||
}
|
||||
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name.substr(3));
|
||||
express::Base IfcGeom::opencascade_geometry_ifc_writer_registry::tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection) const {
|
||||
const auto iter = entries_.find(writer_schema_key(f.schema()->name()));
|
||||
if (iter == entries_.end()) {
|
||||
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
|
||||
}
|
||||
return iter->second.tesselate_(f, shape, deflection);
|
||||
}
|
||||
|
||||
BOOST_PP_SEQ_FOR_EACH(CONDITIONAL_CALL, , SCHEMA_SEQ);
|
||||
express::Base IfcGeom::opencascade_geometry_ifc_writer_registry::serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced) const {
|
||||
const auto iter = entries_.find(writer_schema_key(f.schema()->name()));
|
||||
if (iter == entries_.end()) {
|
||||
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
|
||||
}
|
||||
return iter->second.serialise_(f, shape, advanced);
|
||||
}
|
||||
|
||||
throw IfcParse::IfcException("No geometry serialization available for " + schema_name);
|
||||
}
|
||||
express::Base IfcGeom::tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection) {
|
||||
return opencascade_geometry_ifc_writer_registry_instance().tesselate(f, shape, deflection);
|
||||
}
|
||||
|
||||
express::Base IfcGeom::serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced) {
|
||||
return opencascade_geometry_ifc_writer_registry_instance().serialise(f, shape, advanced);
|
||||
}
|
||||
|
||||
express::Base IfcGeom::tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection) {
|
||||
ifcopenshell::geometry::OpenCascadeShape converted(shape);
|
||||
return tesselate(f, converted, deflection);
|
||||
}
|
||||
|
||||
express::Base IfcGeom::serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced) {
|
||||
ifcopenshell::geometry::OpenCascadeShape converted(shape);
|
||||
return serialise(f, converted, advanced);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,49 @@
|
||||
#include "../../ifcparse/IfcBaseClass.h"
|
||||
#ifndef IFC_GEOM_SERIALIZATION_H
|
||||
#define IFC_GEOM_SERIALIZATION_H
|
||||
|
||||
#include "../../ifcparse/express.h"
|
||||
#include "../../plugin/plugin.h"
|
||||
#include "../../ifcgeom/ConversionResult.h"
|
||||
|
||||
#include "ifc_geomserialization_api.h"
|
||||
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace IfcGeom {
|
||||
IFC_GEOMSERIALIZATION_API IfcUtil::IfcBaseClass* tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection);
|
||||
IFC_GEOMSERIALIZATION_API IfcUtil::IfcBaseClass* serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced);
|
||||
class TopoDS_Shape;
|
||||
|
||||
namespace ifcopenshell {
|
||||
class file;
|
||||
}
|
||||
|
||||
namespace IfcGeom {
|
||||
class IFC_GEOMSERIALIZATION_API opencascade_geometry_ifc_writer_registry {
|
||||
public:
|
||||
typedef boost::function3<express::Base, ifcopenshell::file&, const ConversionResultShape&, double> tesselate_fn;
|
||||
typedef boost::function3<express::Base, ifcopenshell::file&, const ConversionResultShape&, bool> serialise_fn;
|
||||
|
||||
void bind(const std::string& schema_name, serialise_fn serialise, tesselate_fn tesselate, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
|
||||
express::Base tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection) const;
|
||||
express::Base serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced) const;
|
||||
|
||||
private:
|
||||
struct entry {
|
||||
serialise_fn serialise_;
|
||||
tesselate_fn tesselate_;
|
||||
ifcopenshell::plugin::module module_;
|
||||
};
|
||||
|
||||
std::map<std::string, entry> entries_;
|
||||
};
|
||||
|
||||
IFC_GEOMSERIALIZATION_API opencascade_geometry_ifc_writer_registry& opencascade_geometry_ifc_writer_registry_instance();
|
||||
|
||||
IFC_GEOMSERIALIZATION_API express::Base tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection);
|
||||
IFC_GEOMSERIALIZATION_API express::Base serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced);
|
||||
IFC_GEOMSERIALIZATION_API express::Base tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection);
|
||||
IFC_GEOMSERIALIZATION_API express::Base serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced);
|
||||
} // namespace IfcGeom
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
#ifndef IFC_GEOMSERIALIZATION_API_H
|
||||
#define IFC_GEOMSERIALIZATION_API_H
|
||||
|
||||
#ifdef IFC_SHARED_BUILD
|
||||
#ifdef _WIN32
|
||||
#ifdef SWIG
|
||||
#define IFC_GEOMSERIALIZATION_API
|
||||
#elif defined(_WIN32)
|
||||
#ifdef IFC_GEOMSERIALIZATION_EXPORTS
|
||||
#define IFC_GEOMSERIALIZATION_API __declspec(dllexport)
|
||||
#else
|
||||
@@ -30,8 +31,5 @@
|
||||
#else // simply assume *nix + GCC-like compiler
|
||||
#define IFC_GEOMSERIALIZATION_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
#else
|
||||
#define IFC_GEOMSERIALIZATION_API
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "opencascade_geometry_ifc_writer_plugin.h"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
namespace {
|
||||
constexpr const char* opencascade_geometry_ifc_writer_plugin_prefix = "geometry.serialization.";
|
||||
}
|
||||
|
||||
const char* IfcGeom::opencascade_geometry_ifc_writer_plugin_registration_symbol() {
|
||||
return "ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1";
|
||||
}
|
||||
|
||||
ifcopenshell::plugin::metadata IfcGeom::opencascade_geometry_ifc_writer_plugin_metadata(const std::string& schema_name) {
|
||||
ifcopenshell::plugin::metadata metadata;
|
||||
metadata.kind_ = ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer;
|
||||
metadata.id = opencascade_geometry_ifc_writer_plugin_prefix + boost::to_lower_copy(schema_name);
|
||||
metadata.schema = boost::to_upper_copy(schema_name);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
std::filesystem::path IfcGeom::opencascade_geometry_ifc_writer_plugin_directory() {
|
||||
return ifcopenshell::plugin::module_directory(reinterpret_cast<const void*>(&IfcGeom::load_opencascade_geometry_ifc_writer_plugins));
|
||||
}
|
||||
|
||||
void IfcGeom::load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_ifc_writer_registry& registry) {
|
||||
ifcopenshell::plugin::manager manager;
|
||||
manager.add_search_path(opencascade_geometry_ifc_writer_plugin_directory());
|
||||
|
||||
for (const auto& path : manager.discover(opencascade_geometry_ifc_writer_plugin_prefix)) {
|
||||
auto module = manager.load(path);
|
||||
if (module.meta().kind_ != ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto register_plugin = module.get_alias<register_opencascade_geometry_ifc_writer_plugin_fn>(opencascade_geometry_ifc_writer_plugin_registration_symbol());
|
||||
register_plugin(registry, module);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCOPENSHELL_OPENCASCADE_GEOMETRY_IFC_WRITER_PLUGIN_H
|
||||
#define IFCOPENSHELL_OPENCASCADE_GEOMETRY_IFC_WRITER_PLUGIN_H
|
||||
|
||||
#include "Serialization.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
typedef void register_opencascade_geometry_ifc_writer_plugin_fn(opencascade_geometry_ifc_writer_registry&, const ifcopenshell::plugin::module&);
|
||||
|
||||
IFC_GEOMSERIALIZATION_API const char* opencascade_geometry_ifc_writer_plugin_registration_symbol();
|
||||
IFC_GEOMSERIALIZATION_API ifcopenshell::plugin::metadata opencascade_geometry_ifc_writer_plugin_metadata(const std::string& schema_name);
|
||||
IFC_GEOMSERIALIZATION_API std::filesystem::path opencascade_geometry_ifc_writer_plugin_directory();
|
||||
IFC_GEOMSERIALIZATION_API void load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_ifc_writer_registry& registry);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,11 @@
|
||||
foreach(schema ${SCHEMA_VERSIONS})
|
||||
add_library(geometry_serializer_ifc${schema} OBJECT Serialization.cpp)
|
||||
target_link_libraries(geometry_serializer_ifc${schema} ${OpenCASCADE_LIBRARIES})
|
||||
set_target_properties(
|
||||
geometry_serializer_ifc${schema}
|
||||
PROPERTIES COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS -DIfcSchema=Ifc${schema}"
|
||||
add_library(geometry_serializer_ifc${schema} SHARED Serialization.cpp plugin.cpp)
|
||||
target_link_libraries(geometry_serializer_ifc${schema} PRIVATE plugin geometry_serializer IfcGeom IfcParse ${OpenCASCADE_LIBRARIES})
|
||||
set_target_properties(geometry_serializer_ifc${schema} PROPERTIES
|
||||
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
|
||||
OUTPUT_NAME "geometry.serialization.ifc${schema}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
|
||||
)
|
||||
list(APPEND geometry_serializer_libraries geometry_serializer_ifc${schema})
|
||||
endforeach()
|
||||
|
||||
@@ -23,37 +23,36 @@
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include "../../../ifcparse/macros.h"
|
||||
#include "../../../ifcparse/IfcParse.h"
|
||||
#include "../../../ifcparse/parse.h"
|
||||
#include "../../../ifcparse/file.h"
|
||||
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/x.h)
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/schemas/x.h)
|
||||
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
|
||||
#undef INCLUDE_PARENT_PARENT_DIR
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/x-definitions.h)
|
||||
#define INCLUDE_PARENT_PARENT_DIR(x) STRINGIFY(../../../ifcparse/schemas/x-definitions.h)
|
||||
#include INCLUDE_PARENT_PARENT_DIR(IfcSchema)
|
||||
|
||||
#include <numeric>
|
||||
|
||||
#include <numeric>
|
||||
|
||||
template <typename T, typename U>
|
||||
int convert_to_ifc(const T& t, U*& u, bool /*advanced*/) {
|
||||
std::vector<double> coords(3);
|
||||
coords[0] = t.X(); coords[1] = t.Y(); coords[2] = t.Z();
|
||||
u = new U(coords);
|
||||
int convert_to_ifc(ifcopenshell::file& f, const T& t, U& u, bool /*advanced*/) {
|
||||
u = f.create<U>();
|
||||
u.set_attribute_value(0, std::vector<double>{t.X(), t.Y(), t.Z()});
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint*& p, bool advanced) {
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Vertex& v, IfcSchema::IfcCartesianPoint& p, bool advanced) {
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(v);
|
||||
return convert_to_ifc(pnt, p, advanced);
|
||||
return convert_to_ifc(f, pnt, p, advanced);
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (convert_to_ifc(v, p, advanced)) {
|
||||
vertex = new IfcSchema::IfcVertexPoint(p);
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Vertex& v, IfcSchema::IfcVertexPoint& vertex, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (convert_to_ifc(f, v, p, advanced)) {
|
||||
vertex = f.create<IfcSchema::IfcVertexPoint>();
|
||||
vertex.setVertexGeometry(p);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
@@ -61,14 +60,17 @@ int convert_to_ifc(const TopoDS_Vertex& v, IfcSchema::IfcVertex*& vertex, bool a
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D*& ax, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
IfcSchema::IfcDirection *x, *z;
|
||||
if (!(convert_to_ifc(a.Location(), p, advanced) && convert_to_ifc(a.Direction(), z, advanced) && convert_to_ifc(a.XDirection(), x, advanced))) {
|
||||
ax = 0;
|
||||
int convert_to_ifc(ifcopenshell::file& f, const gp_Ax2& a, IfcSchema::IfcAxis2Placement3D& ax, bool advanced) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
IfcSchema::IfcDirection x, z;
|
||||
if (!(convert_to_ifc(f, a.Location(), p, advanced) && convert_to_ifc(f, a.Direction(), z, advanced) && convert_to_ifc(f, a.XDirection(), x, advanced))) {
|
||||
ax = IfcSchema::IfcAxis2Placement3D{};
|
||||
return 0;
|
||||
}
|
||||
ax = new IfcSchema::IfcAxis2Placement3D(p, z, x);
|
||||
ax = f.create<IfcSchema::IfcAxis2Placement3D>();
|
||||
ax.setLocation(p);
|
||||
ax.setAxis(z);
|
||||
ax.setRefDirection(x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -110,44 +112,55 @@ namespace {
|
||||
#endif
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool advanced) {
|
||||
int convert_to_ifc(ifcopenshell::file& f, const Handle_Geom_Curve& c, IfcSchema::IfcCurve& curve, bool advanced) {
|
||||
if (c->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve)) {
|
||||
Handle_Geom_TrimmedCurve trim = Handle_Geom_TrimmedCurve::DownCast(c);
|
||||
const Handle_Geom_Curve basis = trim->BasisCurve();
|
||||
return convert_to_ifc(basis, curve, advanced);
|
||||
return convert_to_ifc(f, basis, curve, advanced);
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Line)) {
|
||||
IfcSchema::IfcDirection* d;
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
IfcSchema::IfcDirection d;
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
|
||||
Handle_Geom_Line line = Handle_Geom_Line::DownCast(c);
|
||||
|
||||
if (!convert_to_ifc(line->Position().Location(), p, advanced)) {
|
||||
if (!convert_to_ifc(f, line->Position().Location(), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
if (!convert_to_ifc(line->Position().Direction(), d, advanced)) {
|
||||
if (!convert_to_ifc(f, line->Position().Direction(), d, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcVector* v = new IfcSchema::IfcVector(d, 1.);
|
||||
curve = new IfcSchema::IfcLine(p, v);
|
||||
IfcSchema::IfcVector v = f.create<IfcSchema::IfcVector>();
|
||||
v.setOrientation(d);
|
||||
v.setMagnitude(1.);
|
||||
IfcSchema::IfcLine l = f.create<IfcSchema::IfcLine>();
|
||||
l.setPnt(p);
|
||||
l.setDir(v);
|
||||
curve = l;
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Circle)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
IfcSchema::IfcAxis2Placement3D ax;
|
||||
|
||||
Handle_Geom_Circle circle = Handle_Geom_Circle::DownCast(c);
|
||||
|
||||
convert_to_ifc(circle->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcCircle(ax, circle->Radius());
|
||||
convert_to_ifc(f, circle->Position(), ax, advanced);
|
||||
auto circ = f.create<IfcSchema::IfcCircle>();
|
||||
circ.setPosition(ax);
|
||||
circ.setRadius(circle->Radius());
|
||||
curve = circ;
|
||||
|
||||
return 1;
|
||||
} else if (c->DynamicType() == STANDARD_TYPE(Geom_Ellipse)) {
|
||||
IfcSchema::IfcAxis2Placement3D* ax;
|
||||
IfcSchema::IfcAxis2Placement3D ax;
|
||||
|
||||
Handle_Geom_Ellipse ellipse = Handle_Geom_Ellipse::DownCast(c);
|
||||
|
||||
convert_to_ifc(ellipse->Position(), ax, advanced);
|
||||
curve = new IfcSchema::IfcEllipse(ax, ellipse->MajorRadius(), ellipse->MinorRadius());
|
||||
auto el = f.create<IfcSchema::IfcEllipse>();
|
||||
el.setPosition(ax);
|
||||
el.setSemiAxis1(ellipse->MajorRadius());
|
||||
el.setSemiAxis2(ellipse->MinorRadius());
|
||||
curve = el;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -161,15 +174,15 @@ int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool
|
||||
|
||||
IfcSchema::IfcKnotType::Value knot_spec = IfcSchema::IfcKnotType::IfcKnotType_QUASI_UNIFORM_KNOTS;
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points;
|
||||
TColgp_Array1OfPnt poles(1, bezier->NbPoles());
|
||||
bezier->Poles(poles);
|
||||
for (int i = 1; i <= bezier->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (!convert_to_ifc(f, poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points->push(p);
|
||||
points.push_back(p);
|
||||
|
||||
if (i == 1 || i == bezier->NbPoles()) {
|
||||
mults.push_back(bezier->Degree() + 1);
|
||||
@@ -184,32 +197,31 @@ int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool
|
||||
bezier->Weights(bspline_weights);
|
||||
opencascade_array_to_vector(bspline_weights, weights);
|
||||
|
||||
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
|
||||
bezier->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bezier->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec,
|
||||
weights
|
||||
);
|
||||
auto bspl = f.create<IfcSchema::IfcRationalBSplineCurveWithKnots>();
|
||||
bspl.setDegree(bezier->Degree());
|
||||
bspl.setControlPointsList(points);
|
||||
bspl.setCurveForm(IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED);
|
||||
bspl.setClosedCurve(bezier->IsClosed() != 0);
|
||||
bspl.setSelfIntersect(false);
|
||||
bspl.setKnotMultiplicities(mults);
|
||||
bspl.setKnots(knots);
|
||||
bspl.setKnotSpec(knot_spec);
|
||||
bspl.setWeightsData(weights);
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (c->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
|
||||
Handle_Geom_BSplineCurve bspline = Handle_Geom_BSplineCurve::DownCast(c);
|
||||
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points;
|
||||
TColgp_Array1OfPnt poles(1, bspline->NbPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbPoles(); ++i) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i), p, advanced)) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (!convert_to_ifc(f, poles.Value(i), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
points->push(p);
|
||||
points.push_back(p);
|
||||
}
|
||||
IfcSchema::IfcKnotType::Value knot_spec = opencascade_knotspec_to_ifc(bspline->KnotDistribution());
|
||||
|
||||
@@ -237,39 +249,33 @@ int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool
|
||||
}
|
||||
}
|
||||
|
||||
if (bspline->IsPeriodic() && points->size()) {
|
||||
points->push(*points->begin());
|
||||
if (bspline->IsPeriodic() && points.size()) {
|
||||
points.push_back(points.front());
|
||||
weights.push_back(weights[0]);
|
||||
auto sum = std::accumulate(mults.begin(), mults.end(), 0);
|
||||
auto d = sum - (bspline->Degree() + (int)points->size() + 1);
|
||||
auto d = sum - (bspline->Degree() + (int) points.size() + 1);
|
||||
(*mults.begin()) -= d / 2;
|
||||
(*mults.rbegin()) -= d / 2;
|
||||
}
|
||||
|
||||
IfcSchema::IfcBSplineCurveWithKnots bspl;
|
||||
|
||||
if (rational) {
|
||||
curve = new IfcSchema::IfcRationalBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec,
|
||||
weights
|
||||
);
|
||||
} else {
|
||||
curve = new IfcSchema::IfcBSplineCurveWithKnots(
|
||||
bspline->Degree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED,
|
||||
bspline->IsClosed() != 0,
|
||||
false,
|
||||
mults,
|
||||
knots,
|
||||
knot_spec
|
||||
);
|
||||
}
|
||||
auto rbspl = f.create<IfcSchema::IfcRationalBSplineCurveWithKnots>();
|
||||
rbspl.setWeightsData(weights);
|
||||
bspl = rbspl;
|
||||
} else {
|
||||
bspl = f.create<IfcSchema::IfcBSplineCurveWithKnots>();
|
||||
}
|
||||
|
||||
bspl.setDegree(bspline->Degree());
|
||||
bspl.setControlPointsList(points);
|
||||
bspl.setCurveForm(IfcSchema::IfcBSplineCurveForm::IfcBSplineCurveForm_UNSPECIFIED);
|
||||
bspl.setClosedCurve(bspline->IsClosed() != 0);
|
||||
bspl.setSelfIntersect(false);
|
||||
bspl.setKnotMultiplicities(mults);
|
||||
bspl.setKnots(knots);
|
||||
bspl.setKnotSpec(knot_spec);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -278,46 +284,50 @@ int convert_to_ifc(const Handle_Geom_Curve& c, IfcSchema::IfcCurve*& curve, bool
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface, bool advanced) {
|
||||
int convert_to_ifc(ifcopenshell::file& f, const Handle_Geom_Surface& s, IfcSchema::IfcSurface& surface, bool advanced) {
|
||||
if (s->DynamicType() == STANDARD_TYPE(Geom_Plane)) {
|
||||
Handle_Geom_Plane plane = Handle_Geom_Plane::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
IfcSchema::IfcAxis2Placement3D place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(plane->Position().Ax2(), place, advanced)) {
|
||||
if (!convert_to_ifc(f, plane->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcPlane(place);
|
||||
auto pln = f.create<IfcSchema::IfcPlane>();
|
||||
pln.setPosition(place);
|
||||
surface = pln;
|
||||
return 1;
|
||||
}
|
||||
#ifdef SCHEMA_HAS_IfcRationalBSplineSurfaceWithKnots
|
||||
else if (s->DynamicType() == STANDARD_TYPE(Geom_CylindricalSurface)) {
|
||||
Handle_Geom_CylindricalSurface cyl = Handle_Geom_CylindricalSurface::DownCast(s);
|
||||
IfcSchema::IfcAxis2Placement3D* place;
|
||||
IfcSchema::IfcAxis2Placement3D place;
|
||||
/// @todo: Note that the Ax3 is converted to an Ax2 here
|
||||
if (!convert_to_ifc(cyl->Position().Ax2(), place, advanced)) {
|
||||
if (!convert_to_ifc(f, cyl->Position().Ax2(), place, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
surface = new IfcSchema::IfcCylindricalSurface(place, cyl->Radius());
|
||||
|
||||
auto surf = f.create<IfcSchema::IfcCylindricalSurface>();
|
||||
surf.setPosition(place);
|
||||
surf.setRadius(cyl->Radius());
|
||||
surface = surf;
|
||||
|
||||
return 1;
|
||||
} else if (s->DynamicType() == STANDARD_TYPE(Geom_BSplineSurface)) {
|
||||
typedef aggregate_of_aggregate_of<IfcSchema::IfcCartesianPoint> points_t;
|
||||
|
||||
std::vector<std::vector<IfcSchema::IfcCartesianPoint>> points;
|
||||
Handle_Geom_BSplineSurface bspline = Handle_Geom_BSplineSurface::DownCast(s);
|
||||
points_t::ptr points(new points_t);
|
||||
|
||||
TColgp_Array2OfPnt poles(1, bspline->NbUPoles(), 1, bspline->NbVPoles());
|
||||
bspline->Poles(poles);
|
||||
for (int i = 1; i <= bspline->NbUPoles(); ++i) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> ps;
|
||||
auto& ps = points.emplace_back();
|
||||
ps.reserve(bspline->NbVPoles());
|
||||
for (int j = 1; j <= bspline->NbVPoles(); ++j) {
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
if (!convert_to_ifc(poles.Value(i, j), p, advanced)) {
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
if (!convert_to_ifc(f, poles.Value(i, j), p, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
ps.push_back(p);
|
||||
}
|
||||
points->push(ps);
|
||||
}
|
||||
|
||||
IfcSchema::IfcKnotType::Value knot_spec_u = opencascade_knotspec_to_ifc(bspline->UKnotDistribution());
|
||||
@@ -361,38 +371,30 @@ int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcBSplineSurfaceWithKnots bspl;
|
||||
|
||||
if (rational) {
|
||||
surface = new IfcSchema::IfcRationalBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u,
|
||||
weights
|
||||
);
|
||||
auto rbspl = f.create<IfcSchema::IfcRationalBSplineSurfaceWithKnots>();
|
||||
rbspl.setWeightsData(weights);
|
||||
bspl = rbspl;
|
||||
} else {
|
||||
surface = new IfcSchema::IfcBSplineSurfaceWithKnots(
|
||||
bspline->UDegree(),
|
||||
bspline->VDegree(),
|
||||
points,
|
||||
IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED,
|
||||
bspline->IsUClosed() != 0,
|
||||
bspline->IsVClosed() != 0,
|
||||
false,
|
||||
umults,
|
||||
vmults,
|
||||
uknots,
|
||||
vknots,
|
||||
knot_spec_u
|
||||
);
|
||||
}
|
||||
bspl = f.create<IfcSchema::IfcBSplineSurfaceWithKnots>();
|
||||
}
|
||||
|
||||
bspl.setUDegree(bspline->UDegree());
|
||||
bspl.setVDegree(bspline->VDegree());
|
||||
bspl.setControlPointsList(points);
|
||||
bspl.setSurfaceForm(IfcSchema::IfcBSplineSurfaceForm::IfcBSplineSurfaceForm_UNSPECIFIED);
|
||||
bspl.setUClosed(bspline->IsUClosed() != 0);
|
||||
bspl.setVClosed(bspline->IsVClosed() != 0);
|
||||
bspl.setSelfIntersect(false);
|
||||
bspl.setUMultiplicities(umults);
|
||||
bspl.setVMultiplicities(vmults);
|
||||
bspl.setUKnots(uknots);
|
||||
bspl.setVKnots(vknots);
|
||||
bspl.setKnotSpec(knot_spec_u);
|
||||
|
||||
surface = bspl;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -401,27 +403,37 @@ int convert_to_ifc(const Handle_Geom_Surface& s, IfcSchema::IfcSurface*& surface
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcCurve*& c, bool advanced) {
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Edge& e, IfcSchema::IfcCurve& c, bool advanced) {
|
||||
double a, b;
|
||||
IfcSchema::IfcCurve* base;
|
||||
IfcSchema::IfcCurve base;
|
||||
|
||||
Handle_Geom_Curve crv = BRep_Tool::Curve(e, a, b);
|
||||
if (!convert_to_ifc(crv, base, advanced)) {
|
||||
if (!convert_to_ifc(f, crv, base, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
IfcSchema::IfcTrimmingSelect::list::ptr trim1(new IfcSchema::IfcTrimmingSelect::list);
|
||||
IfcSchema::IfcTrimmingSelect::list::ptr trim2(new IfcSchema::IfcTrimmingSelect::list);
|
||||
trim1->push(new IfcSchema::IfcParameterValue(a));
|
||||
trim2->push(new IfcSchema::IfcParameterValue(b));
|
||||
auto ta = f.create<IfcSchema::IfcParameterValue>();
|
||||
ta.set_attribute_value(0, a);
|
||||
auto tb = f.create<IfcSchema::IfcParameterValue>();
|
||||
tb.set_attribute_value(0, b);
|
||||
|
||||
c = new IfcSchema::IfcTrimmedCurve(base, trim1, trim2, true, IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
std::vector<IfcSchema::IfcTrimmingSelect> trim1{ta};
|
||||
std::vector<IfcSchema::IfcTrimmingSelect> trim2{tb};
|
||||
|
||||
auto tc = f.create<IfcSchema::IfcTrimmedCurve>();
|
||||
tc.setBasisCurve(base);
|
||||
tc.setTrim1(trim1);
|
||||
tc.setTrim2(trim2);
|
||||
tc.setSenseAgreement(true);
|
||||
tc.setMasterRepresentation(IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER);
|
||||
|
||||
c = tc;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advanced) {
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Edge& e, IfcSchema::IfcEdge& edge, bool advanced) {
|
||||
double a, b;
|
||||
|
||||
TopExp_Explorer exp(e, TopAbs_VERTEX);
|
||||
@@ -431,8 +443,8 @@ int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advance
|
||||
if (!exp.More()) return 0;
|
||||
TopoDS_Vertex v2 = TopoDS::Vertex(exp.Current());
|
||||
|
||||
IfcSchema::IfcVertex *vertex1, *vertex2;
|
||||
if (!(convert_to_ifc(v1, vertex1, advanced) && convert_to_ifc(v2, vertex2, advanced))) {
|
||||
IfcSchema::IfcVertexPoint vertex1, vertex2;
|
||||
if (!(convert_to_ifc(f, v1, vertex1, advanced) && convert_to_ifc(f, v2, vertex2, advanced))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -443,18 +455,36 @@ int convert_to_ifc(const TopoDS_Edge& e, IfcSchema::IfcEdge*& edge, bool advance
|
||||
}
|
||||
|
||||
if (crv->DynamicType() == STANDARD_TYPE(Geom_Line) && !advanced) {
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdge(vertex1, vertex2);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, true);
|
||||
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 {
|
||||
IfcSchema::IfcCurve* curve;
|
||||
if (!convert_to_ifc(crv, curve, advanced)) {
|
||||
IfcSchema::IfcCurve curve;
|
||||
if (!convert_to_ifc(f, crv, curve, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @todo probably not correct
|
||||
const bool sense = e.Orientation() == TopAbs_FORWARD;
|
||||
IfcSchema::IfcEdge* edge2 = new IfcSchema::IfcEdgeCurve(vertex1, vertex2, curve, true);
|
||||
edge = new IfcSchema::IfcOrientedEdge(edge2, sense);
|
||||
|
||||
auto ec = f.create<IfcSchema::IfcEdgeCurve>();
|
||||
ec.setEdgeStart(vertex1);
|
||||
ec.setEdgeEnd(vertex2);
|
||||
ec.setEdgeGeometry(curve);
|
||||
ec.setSameSense(true);
|
||||
|
||||
auto ori = f.create<IfcSchema::IfcOrientedEdge>();
|
||||
ori.setEdgeElement(ec);
|
||||
ori.setOrientation(sense);
|
||||
|
||||
edge = ori;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -475,7 +505,7 @@ namespace {
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool advanced) {
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Wire& wire, IfcSchema::IfcLoop& loop, bool advanced) {
|
||||
bool polygonal = true;
|
||||
for (TopExp_Explorer exp(wire, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
double a, b;
|
||||
@@ -491,25 +521,27 @@ int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool adva
|
||||
if (!polygonal && !advanced) {
|
||||
return 0;
|
||||
} else if (polygonal && !advanced) {
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points;
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
IfcSchema::IfcCartesianPoint* p;
|
||||
IfcSchema::IfcCartesianPoint p;
|
||||
for (; exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(exp.CurrentVertex(), p, advanced)) {
|
||||
points->push(p);
|
||||
if (convert_to_ifc(f, exp.CurrentVertex(), p, advanced)) {
|
||||
points.push_back(p);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
loop = new IfcSchema::IfcPolyLoop(points);
|
||||
auto pl = f.create<IfcSchema::IfcPolyLoop>();
|
||||
pl.setPolygon(points);
|
||||
loop = pl;
|
||||
return 1;
|
||||
} else {
|
||||
IfcSchema::IfcOrientedEdge::list::ptr edges(new IfcSchema::IfcOrientedEdge::list);
|
||||
std::vector<IfcSchema::IfcOrientedEdge> edges;
|
||||
BRepTools_WireExplorer exp(wire);
|
||||
for (; exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcEdge* edge;
|
||||
// With advanced set to true convert_to_ifc(TopoDS_Edge&) will always create an IfcOrientedEdge
|
||||
if (!convert_to_ifc(exp.Current(), edge, true)) {
|
||||
IfcSchema::IfcEdge edge;
|
||||
// With advanced set to true convert_to_ifc(ifcopenshell::file& f, TopoDS_Edge&) will always create an IfcOrientedEdge
|
||||
if (!convert_to_ifc(f, exp.Current(), edge, true)) {
|
||||
double a, b;
|
||||
if (BRep_Tool::Curve(TopoDS::Edge(exp.Current()), a, b).IsNull()) {
|
||||
continue;
|
||||
@@ -517,32 +549,37 @@ int convert_to_ifc(const TopoDS_Wire& wire, IfcSchema::IfcLoop*& loop, bool adva
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
edges->push(edge->as<IfcSchema::IfcOrientedEdge>());
|
||||
edges.push_back(edge.as<IfcSchema::IfcOrientedEdge>());
|
||||
}
|
||||
loop = new IfcSchema::IfcEdgeLoop(edges);
|
||||
auto el = f.create<IfcSchema::IfcEdgeLoop>();
|
||||
el.setEdgeList(edges);
|
||||
loop = el;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advanced) {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(f);
|
||||
TopExp_Explorer exp(f, TopAbs_WIRE);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Face& fa, IfcSchema::IfcFace& face, bool advanced) {
|
||||
Handle_Geom_Surface surf = BRep_Tool::Surface(fa);
|
||||
TopExp_Explorer exp(fa, TopAbs_WIRE);
|
||||
std::vector<IfcSchema::IfcFaceBound> bounds;
|
||||
int index = 0;
|
||||
auto outer = BRepTools::OuterWire(f);
|
||||
auto outer = BRepTools::OuterWire(fa);
|
||||
for (; exp.More(); exp.Next(), ++index) {
|
||||
IfcSchema::IfcLoop* loop;
|
||||
if (!convert_to_ifc(TopoDS::Wire(exp.Current()), loop, advanced)) {
|
||||
IfcSchema::IfcLoop loop;
|
||||
if (!convert_to_ifc(f, TopoDS::Wire(exp.Current()), loop, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
IfcSchema::IfcFaceBound* bnd;
|
||||
IfcSchema::IfcFaceBound bnd;
|
||||
if (outer == exp.Current()) {
|
||||
bnd = new IfcSchema::IfcFaceOuterBound(loop, true);
|
||||
bnd = f.create<IfcSchema::IfcFaceOuterBound>();
|
||||
} else {
|
||||
bnd = new IfcSchema::IfcFaceBound(loop, true);
|
||||
bnd = f.create<IfcSchema::IfcFaceBound>();
|
||||
}
|
||||
bounds->push(bnd);
|
||||
bnd.setBound(loop);
|
||||
bnd.setOrientation(true);
|
||||
|
||||
bounds.push_back(bnd);
|
||||
}
|
||||
|
||||
const bool is_planar = surf->DynamicType() == STANDARD_TYPE(Geom_Plane);
|
||||
@@ -551,15 +588,20 @@ int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advance
|
||||
return 0;
|
||||
}
|
||||
if (is_planar && !advanced) {
|
||||
face = new IfcSchema::IfcFace(bounds);
|
||||
face = f.create<IfcSchema::IfcFace>();
|
||||
face.setBounds(bounds);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef SCHEMA_HAS_IfcAdvancedFace
|
||||
IfcSchema::IfcSurface* surface;
|
||||
if (!convert_to_ifc(surf, surface, advanced)) {
|
||||
IfcSchema::IfcSurface surface;
|
||||
if (!convert_to_ifc(f, surf, surface, advanced)) {
|
||||
return 0;
|
||||
}
|
||||
face = new IfcSchema::IfcAdvancedFace(bounds, surface, f.Orientation() == TopAbs_FORWARD);
|
||||
auto adv = f.create<IfcSchema::IfcAdvancedFace>();
|
||||
adv.setBounds(bounds);
|
||||
adv.setFaceSurface(surface);
|
||||
adv.setSameSense(fa.Orientation() == TopAbs_FORWARD);
|
||||
face = adv;
|
||||
return 1;
|
||||
#else
|
||||
// No IfcAdvancedFace in Ifc2x3
|
||||
@@ -569,30 +611,33 @@ int convert_to_ifc(const TopoDS_Face& f, IfcSchema::IfcFace*& face, bool advance
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
int convert_to_ifc(const TopoDS_Shape& s, U*& item, bool advanced) {
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
IfcSchema::IfcFace* f;
|
||||
int convert_to_ifc(ifcopenshell::file& f, const TopoDS_Shape& s, U& item, bool advanced) {
|
||||
std::vector<IfcSchema::IfcFace> faces;
|
||||
IfcSchema::IfcFace fa;
|
||||
|
||||
for (TopExp_Explorer exp(s, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
if (convert_to_ifc(TopoDS::Face(exp.Current()), f, advanced)) {
|
||||
faces->push(f);
|
||||
if (convert_to_ifc(f, TopoDS::Face(exp.Current()), fa, advanced)) {
|
||||
faces.push_back(fa);
|
||||
} else {
|
||||
/// Cleanup:
|
||||
for (IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++it) {
|
||||
aggregate_of_instance::ptr data = IfcParse::traverse(*it)->unique();
|
||||
for (aggregate_of_instance::it jt = data->begin(); jt != data->end(); ++jt) {
|
||||
delete *jt;
|
||||
}
|
||||
std::set<express::Base> created;
|
||||
for (auto& face : faces) {
|
||||
auto resources = f.traverse(face);
|
||||
created.insert(resources.begin(), resources.end());
|
||||
}
|
||||
for (auto& c : created) {
|
||||
f.remove_entity(c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
item = new U(faces);
|
||||
return faces->size();
|
||||
item = f.create<U>();
|
||||
item.setCfsFaces(faces);
|
||||
|
||||
return faces.size();
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise)(const TopoDS_Shape& shape, bool advanced) {
|
||||
express::Base POSTFIX_SCHEMA(serialise)(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced) {
|
||||
|
||||
#ifndef SCHEMA_HAS_IfcAdvancedBrep
|
||||
advanced = false;
|
||||
@@ -600,25 +645,25 @@ IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise)(const TopoDS_Shape& shape, bool
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_COMPSOLID); exp.More();) {
|
||||
/// @todo CompSolids are not supported
|
||||
return 0;
|
||||
return express::Base{};
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation* rep = 0;
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
IfcSchema::IfcRepresentation rep;
|
||||
std::vector<IfcSchema::IfcRepresentationItem> items;
|
||||
|
||||
// First check if there is a solid with one or more shells
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SOLID); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcClosedShell* outer = 0;
|
||||
IfcSchema::IfcClosedShell::list::ptr inner(new IfcSchema::IfcClosedShell::list);
|
||||
IfcSchema::IfcClosedShell outer;
|
||||
std::vector<IfcSchema::IfcClosedShell> inner;
|
||||
for (TopExp_Explorer exp2(exp.Current(), TopAbs_SHELL); exp2.More(); exp2.Next()) {
|
||||
IfcSchema::IfcClosedShell* shell;
|
||||
if (!convert_to_ifc(exp2.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
IfcSchema::IfcClosedShell shell;
|
||||
if (!convert_to_ifc(f, exp2.Current(), shell, advanced)) {
|
||||
return express::Base{};
|
||||
}
|
||||
/// @todo Are shells always in this order or does Orientation() needs to be checked?
|
||||
/// > #4216, no, consider using BRepClass3d::OuterShell()
|
||||
if (outer) {
|
||||
inner->push(shell);
|
||||
inner.push_back(shell);
|
||||
} else {
|
||||
outer = shell;
|
||||
}
|
||||
@@ -626,89 +671,129 @@ IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise)(const TopoDS_Shape& shape, bool
|
||||
|
||||
#ifdef SCHEMA_HAS_IfcAdvancedBrep
|
||||
if (advanced) {
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcAdvancedBrepWithVoids(outer, inner));
|
||||
if (inner.size()) {
|
||||
auto inst = f.create<IfcSchema::IfcAdvancedBrepWithVoids>();
|
||||
inst.setOuter(outer);
|
||||
inst.setVoids(inner);
|
||||
items.push_back(inst);
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcAdvancedBrep(outer));
|
||||
auto inst = f.create<IfcSchema::IfcAdvancedBrep>();
|
||||
inst.setOuter(outer);
|
||||
items.push_back(inst);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
|
||||
/// @todo this is not necessarily correct as the shell is not necessarily facetted.
|
||||
if (inner->size()) {
|
||||
items->push(new IfcSchema::IfcFacetedBrepWithVoids(outer, inner));
|
||||
if (inner.size()) {
|
||||
auto inst = f.create<IfcSchema::IfcFacetedBrepWithVoids>();
|
||||
inst.setOuter(outer);
|
||||
inst.setVoids(inner);
|
||||
items.push_back(inst);
|
||||
} else {
|
||||
items->push(new IfcSchema::IfcFacetedBrep(outer));
|
||||
auto inst = f.create<IfcSchema::IfcFacetedBrep>();
|
||||
inst.setOuter(outer);
|
||||
items.push_back(inst);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (items->size() > 0) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), advanced ? std::string("AdvancedBrep") : std::string("Brep"), items);
|
||||
if (items.size() > 0) {
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Body");
|
||||
srep.setRepresentationType(advanced ? "AdvancedBrep" : "Brep");
|
||||
srep.setItems(items);
|
||||
rep = srep;
|
||||
} else {
|
||||
|
||||
// If not, see if there is a shell
|
||||
IfcSchema::IfcShell::list::ptr shells(new IfcSchema::IfcShell::list);
|
||||
std::vector<IfcSchema::IfcShell> shells;
|
||||
for (TopExp_Explorer exp(shape, TopAbs_SHELL); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
if (!convert_to_ifc(exp.Current(), shell, advanced)) {
|
||||
return 0;
|
||||
IfcSchema::IfcOpenShell shell;
|
||||
if (!convert_to_ifc(f, exp.Current(), shell, advanced)) {
|
||||
return express::Base{};
|
||||
}
|
||||
shells->push(shell);
|
||||
shells.push_back(shell);
|
||||
}
|
||||
|
||||
if (shells->size() > 0) {
|
||||
items->push(new IfcSchema::IfcShellBasedSurfaceModel(shells));
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), advanced ? std::string("AdvancedBrep") : std::string("Brep"), items);
|
||||
if (shells.size() > 0) {
|
||||
auto inst = f.create<IfcSchema::IfcShellBasedSurfaceModel>();
|
||||
inst.setSbsmBoundary(shells);
|
||||
items.push_back(inst);
|
||||
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Body");
|
||||
srep.setRepresentationType(advanced ? "AdvancedBrep" : "Brep");
|
||||
srep.setItems(items);
|
||||
|
||||
rep = srep;
|
||||
} else {
|
||||
|
||||
// If not, see if there is are one of more faces. Note that they will be grouped into a shell.
|
||||
IfcSchema::IfcOpenShell* shell;
|
||||
int face_count = convert_to_ifc(shape, shell, advanced);
|
||||
IfcSchema::IfcOpenShell shell;
|
||||
int face_count = convert_to_ifc(f, shape, shell, advanced);
|
||||
|
||||
if (face_count > 0) {
|
||||
items->push(shell);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Body"), advanced ? std::string("AdvancedBrep") : std::string("Brep"), items);
|
||||
items.push_back(shell);
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Body");
|
||||
srep.setRepresentationType(advanced ? "AdvancedBrep" : "Brep");
|
||||
srep.setItems(items);
|
||||
|
||||
rep = srep;
|
||||
} else {
|
||||
|
||||
// If not, see if there are any edges. Note that wires are skipped as
|
||||
// they are not commonly top-level geometrical descriptions in IFC.
|
||||
// Also note that edges are written as trimmed curves rather than edges.
|
||||
|
||||
aggregate_of_instance::ptr edges(new aggregate_of_instance);
|
||||
std::vector<express::Entity> edges;
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_EDGE); exp.More(); exp.Next()) {
|
||||
IfcSchema::IfcCurve* c;
|
||||
if (!convert_to_ifc(TopoDS::Edge(exp.Current()), c, advanced)) {
|
||||
return 0;
|
||||
IfcSchema::IfcCurve c;
|
||||
if (!convert_to_ifc(f, TopoDS::Edge(exp.Current()), c, advanced)) {
|
||||
return express::Base{};
|
||||
}
|
||||
edges->push(c);
|
||||
edges.push_back(c);
|
||||
}
|
||||
|
||||
if (edges->size() == 0) {
|
||||
return 0;
|
||||
} else if (edges->size() == 1) {
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("Curve2D"), edges->as<IfcSchema::IfcRepresentationItem>());
|
||||
if (edges.size() == 0) {
|
||||
return express::Base{};
|
||||
} else if (edges.size() == 1) {
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Axis");
|
||||
srep.setRepresentationType("Curve2D");
|
||||
srep.setItems(cast_vector<IfcSchema::IfcRepresentationItem>(edges));
|
||||
rep = srep;
|
||||
} else {
|
||||
// A geometric set is created as that probably (?) makes more sense in IFC
|
||||
IfcSchema::IfcGeometricCurveSet* curves = new IfcSchema::IfcGeometricCurveSet(edges->as<IfcSchema::IfcGeometricSetSelect>());
|
||||
items->push(curves);
|
||||
rep = new IfcSchema::IfcShapeRepresentation(0, std::string("Axis"), std::string("GeometricCurveSet"), items->as<IfcSchema::IfcRepresentationItem>());
|
||||
auto curves = f.create<IfcSchema::IfcGeometricCurveSet>();
|
||||
curves.setElements(cast_vector<IfcSchema::IfcGeometricSetSelect>(edges));
|
||||
items.push_back(curves);
|
||||
|
||||
auto srep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
srep.setRepresentationIdentifier("Axis");
|
||||
srep.setRepresentationType("GeometricCurveSet");
|
||||
srep.setItems(items);
|
||||
rep = srep;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
reps->push(rep);
|
||||
return new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
auto pds = f.create<IfcSchema::IfcProductDefinitionShape>();
|
||||
pds.setRepresentations({rep});
|
||||
|
||||
return pds;
|
||||
}
|
||||
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate)(const TopoDS_Shape& shape, double deflection) {
|
||||
express::Base POSTFIX_SCHEMA(tesselate)(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection) {
|
||||
// @todo use triangulated face set in ifc4+ schema
|
||||
|
||||
BRepMesh_IncrementalMesh(shape, deflection);
|
||||
|
||||
IfcSchema::IfcFace::list::ptr faces(new IfcSchema::IfcFace::list);
|
||||
std::vector<IfcSchema::IfcFace> faces;
|
||||
|
||||
for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
|
||||
const TopoDS_Face& face = TopoDS::Face(exp.Current());
|
||||
@@ -716,45 +801,45 @@ IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate)(const TopoDS_Shape& shape, doub
|
||||
Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (!tri.IsNull()) {
|
||||
std::vector<IfcSchema::IfcCartesianPoint*> vertices;
|
||||
std::vector<IfcSchema::IfcCartesianPoint> vertices;
|
||||
for (int i = 1; i <= tri->NbNodes(); ++i) {
|
||||
gp_Pnt pnt = tri->Node(i).Transformed(loc);
|
||||
std::vector<double> xyz; xyz.push_back(pnt.X()); xyz.push_back(pnt.Y()); xyz.push_back(pnt.Z());
|
||||
IfcSchema::IfcCartesianPoint* cpnt = new IfcSchema::IfcCartesianPoint(xyz);
|
||||
IfcSchema::IfcCartesianPoint cpnt = f.create<IfcSchema::IfcCartesianPoint>();
|
||||
cpnt.setCoordinates(xyz);
|
||||
vertices.push_back(cpnt);
|
||||
}
|
||||
const Poly_Array1OfTriangle& triangles = tri->Triangles();
|
||||
for (int i = 1; i <= triangles.Length(); ++i) {
|
||||
int n1, n2, n3;
|
||||
triangles(i).Get(n1, n2, n3);
|
||||
IfcSchema::IfcCartesianPoint::list::ptr points(new IfcSchema::IfcCartesianPoint::list);
|
||||
points->push(vertices[n1 - 1]);
|
||||
points->push(vertices[n2 - 1]);
|
||||
points->push(vertices[n3 - 1]);
|
||||
IfcSchema::IfcPolyLoop* loop = new IfcSchema::IfcPolyLoop(points);
|
||||
IfcSchema::IfcFaceOuterBound* bound = new IfcSchema::IfcFaceOuterBound(loop, face.Orientation() != TopAbs_REVERSED);
|
||||
IfcSchema::IfcFaceBound::list::ptr bounds(new IfcSchema::IfcFaceBound::list);
|
||||
bounds->push(bound);
|
||||
IfcSchema::IfcFace* face2 = new IfcSchema::IfcFace(bounds);
|
||||
faces->push(face2);
|
||||
std::vector<IfcSchema::IfcCartesianPoint> points {
|
||||
vertices[n1 - 1], vertices[n2 - 1], vertices[n3 - 1]
|
||||
};
|
||||
IfcSchema::IfcPolyLoop loop = f.create<IfcSchema::IfcPolyLoop>();
|
||||
loop.setPolygon(points);
|
||||
IfcSchema::IfcFaceOuterBound bound = f.create<IfcSchema::IfcFaceOuterBound>();
|
||||
bound.setBound(loop);
|
||||
bound.setOrientation(face.Orientation() != TopAbs_REVERSED);
|
||||
IfcSchema::IfcFace face2 = f.create<IfcSchema::IfcFace>();
|
||||
face2.setBounds({bound});
|
||||
faces.push_back(face2);
|
||||
}
|
||||
}
|
||||
}
|
||||
IfcSchema::IfcOpenShell* shell = new IfcSchema::IfcOpenShell(faces);
|
||||
IfcSchema::IfcConnectedFaceSet::list::ptr shells(new IfcSchema::IfcConnectedFaceSet::list);
|
||||
shells->push(shell);
|
||||
IfcSchema::IfcFaceBasedSurfaceModel* surface_model = new IfcSchema::IfcFaceBasedSurfaceModel(shells);
|
||||
auto shell = f.create<IfcSchema::IfcOpenShell>();
|
||||
shell.setCfsFaces(faces);
|
||||
|
||||
IfcSchema::IfcRepresentation::list::ptr reps(new IfcSchema::IfcRepresentation::list);
|
||||
IfcSchema::IfcRepresentationItem::list::ptr items(new IfcSchema::IfcRepresentationItem::list);
|
||||
auto surface_model = f.create<IfcSchema::IfcFaceBasedSurfaceModel>();
|
||||
surface_model.setFbsmFaces({shell});
|
||||
|
||||
items->push(surface_model);
|
||||
auto rep = f.create<IfcSchema::IfcShapeRepresentation>();
|
||||
rep.setRepresentationIdentifier("Tessellation");
|
||||
rep.setRepresentationType("SurfaceModel");
|
||||
rep.setItems({surface_model});
|
||||
|
||||
IfcSchema::IfcShapeRepresentation* rep = new IfcSchema::IfcShapeRepresentation(
|
||||
0, std::string("Facetation"), std::string("SurfaceModel"), items);
|
||||
|
||||
reps->push(rep);
|
||||
IfcSchema::IfcProductDefinitionShape* shapedef = new IfcSchema::IfcProductDefinitionShape(boost::none, boost::none, reps);
|
||||
auto shapedef = f.create<IfcSchema::IfcProductDefinitionShape>();
|
||||
shapedef.setRepresentations({rep});
|
||||
|
||||
return shapedef;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../opencascade_geometry_ifc_writer_plugin.h"
|
||||
|
||||
#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
|
||||
#include "../../../ifcparse/exception.h"
|
||||
#include "../../../ifcparse/macros.h"
|
||||
|
||||
#include <boost/dll/alias.hpp>
|
||||
|
||||
express::Base POSTFIX_SCHEMA(serialise)(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced);
|
||||
express::Base POSTFIX_SCHEMA(tesselate)(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection);
|
||||
|
||||
namespace {
|
||||
const ifcopenshell::geometry::OpenCascadeShape& require_opencascade_shape(const IfcGeom::ConversionResultShape& shape) {
|
||||
const auto* oc_shape = dynamic_cast<const ifcopenshell::geometry::OpenCascadeShape*>(&shape);
|
||||
if (!oc_shape) {
|
||||
throw ifcopenshell::exception("OpenCascade geometry IFC writer requires an opencascade conversion result shape");
|
||||
}
|
||||
return *oc_shape;
|
||||
}
|
||||
|
||||
express::Base serialise_adapter(ifcopenshell::file& f, const IfcGeom::ConversionResultShape& shape, bool advanced) {
|
||||
return POSTFIX_SCHEMA(serialise)(f, require_opencascade_shape(shape).shape(), advanced);
|
||||
}
|
||||
|
||||
express::Base tesselate_adapter(ifcopenshell::file& f, const IfcGeom::ConversionResultShape& shape, double deflection) {
|
||||
return POSTFIX_SCHEMA(tesselate)(f, require_opencascade_shape(shape).shape(), deflection);
|
||||
}
|
||||
}
|
||||
|
||||
namespace IfcGeom {
|
||||
namespace opencascade_geometry_ifc_writer_plugin {
|
||||
|
||||
ifcopenshell::plugin::abi_info plugin_abi() {
|
||||
return ifcopenshell::plugin::host_abi();
|
||||
}
|
||||
|
||||
ifcopenshell::plugin::metadata plugin_metadata() {
|
||||
return opencascade_geometry_ifc_writer_plugin_metadata(STRINGIFY(IfcSchema));
|
||||
}
|
||||
|
||||
void register_plugin(opencascade_geometry_ifc_writer_registry& registry, const ifcopenshell::plugin::module& module) {
|
||||
registry.bind(STRINGIFY(IfcSchema), &serialise_adapter, &tesselate_adapter, module);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_DLL_ALIAS(IfcGeom::opencascade_geometry_ifc_writer_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
|
||||
BOOST_DLL_ALIAS(IfcGeom::opencascade_geometry_ifc_writer_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
|
||||
BOOST_DLL_ALIAS(IfcGeom::opencascade_geometry_ifc_writer_plugin::register_plugin, ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1)
|
||||
@@ -20,16 +20,17 @@
|
||||
#ifndef SERIALIZER_H
|
||||
#define SERIALIZER_H
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "ifc_geom_api.h"
|
||||
#include "../ifcparse/file.h"
|
||||
|
||||
class Serializer {
|
||||
class IFC_GEOM_API Serializer {
|
||||
public:
|
||||
virtual ~Serializer() {}
|
||||
|
||||
virtual bool ready() = 0;
|
||||
virtual void writeHeader() = 0;
|
||||
virtual void finalize() = 0;
|
||||
virtual void setFile(IfcParse::IfcFile*) = 0;
|
||||
virtual void setFile(ifcopenshell::file*) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -86,14 +86,14 @@ void IfcGeom::set_default_style_file(const std::string& json_file) {
|
||||
default_materials.insert(std::make_pair(name, std::make_shared<ifcopenshell::geometry::taxonomy::style>(name)));
|
||||
|
||||
pt::ptree material = material_pair.second;
|
||||
boost::optional<pt::ptree&> diffuse = material.get_child_optional("diffuse");
|
||||
auto diffuse = material.get_child_optional("diffuse");
|
||||
default_materials[name]->diffuse = read_colour_component(diffuse);
|
||||
|
||||
// @todo Is it necessary to get the surface too?
|
||||
// boost::optional<pt::ptree&> surface = material.get_child_optional("surface");
|
||||
// std::optional<pt::ptree&> surface = material.get_child_optional("surface");
|
||||
// default_materials[name]->surface = read_colour_component(surface);
|
||||
|
||||
boost::optional<pt::ptree&> specular = material.get_child_optional("specular");
|
||||
auto specular = material.get_child_optional("specular");
|
||||
default_materials[name]->specular = read_colour_component(specular);
|
||||
|
||||
if (material.get_child_optional("specular-roughness")) {
|
||||
|
||||
@@ -1,50 +1,55 @@
|
||||
#include "abstract_mapping.h"
|
||||
|
||||
#include "../ifcparse/IfcFile.h"
|
||||
#include "../ifcparse/file.h"
|
||||
#include "../ifcgeom/mapping_plugin.h"
|
||||
|
||||
#include <boost/preprocessor/stringize.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <mutex>
|
||||
|
||||
#ifndef SCHEMA_SEQ
|
||||
static_assert(false, "A boost preprocessor sequence of schema identifiers is needed for this file to compile.");
|
||||
#endif
|
||||
namespace {
|
||||
std::string mapping_key(const std::string& schema_name) {
|
||||
return boost::to_lower_copy(schema_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::impl::mapping_registry& ifcopenshell::geometry::impl::mapping_registry_instance() {
|
||||
static mapping_registry registry;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, load_mapping_plugins, std::ref(registry));
|
||||
return registry;
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::impl::mapping_registry::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn, const plugin::module& module) {
|
||||
auto& entry = entries_[mapping_key(schema_name)];
|
||||
entry.fn_ = fn;
|
||||
entry.module_ = module.meta().id.empty() ? plugin::module(mapping_plugin_metadata(schema_name)) : module;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::mapping_registry::construct(ifcopenshell::file* file, Settings& s) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name());
|
||||
const auto it = entries_.find(schema_name_lower);
|
||||
if (it == entries_.end()) {
|
||||
throw ifcopenshell::exception("No geometry mapping registered for " + schema_name_lower);
|
||||
}
|
||||
auto new_mapping = it->second.fn_(file, s);
|
||||
new_mapping->initialize_settings();
|
||||
return new_mapping;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::impl::MappingFactoryImplementation& ifcopenshell::geometry::impl::mapping_implementations() {
|
||||
static MappingFactoryImplementation impl;
|
||||
return impl;
|
||||
}
|
||||
|
||||
// Declares the schema-based external kernel initialization routines:
|
||||
// - extern void init_MappingImplementation_Ifc2x3(IfcGeom::impl::MappingFactoryImplementation*);
|
||||
// - ...
|
||||
#define EXTERNAL_DEFS(r, data, elem) \
|
||||
extern void BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
|
||||
|
||||
// Declares the schema-based external iterator initialization routines:
|
||||
// - init_MappingImplementation_Ifc2x3(this);
|
||||
// - ...
|
||||
#define CALL_DEFS(r, data, elem) \
|
||||
BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(this);
|
||||
|
||||
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS, , SCHEMA_SEQ)
|
||||
|
||||
ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplementation() {
|
||||
BOOST_PP_SEQ_FOR_EACH(CALL_DEFS, , SCHEMA_SEQ)
|
||||
mapping_registry_instance();
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
|
||||
this->insert(std::make_pair(schema_name_lower, fn));
|
||||
mapping_registry_instance().bind(schema_name, fn, plugin::module(mapping_plugin_metadata(schema_name)));
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, Settings& s) {
|
||||
const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name());
|
||||
std::map<std::string, ifcopenshell::geometry::impl::mapping_fn>::const_iterator it;
|
||||
it = this->find(schema_name_lower);
|
||||
if (it == end()) {
|
||||
throw IfcParse::IfcException("No geometry mapping registered for " + schema_name_lower);
|
||||
}
|
||||
auto new_mapping = it->second(file, s);
|
||||
new_mapping->initialize_settings();
|
||||
return new_mapping;
|
||||
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(ifcopenshell::file* file, Settings& s) {
|
||||
return mapping_registry_instance().construct(file, s);
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
#ifndef ABSTRACT_MAPPING_H
|
||||
#define ABSTRACT_MAPPING_H
|
||||
|
||||
#include "../ifcparse/IfcBaseClass.h"
|
||||
#include "../ifcparse/aggregate_of_instance.h"
|
||||
#include "../ifcparse/express.h"
|
||||
#include "../ifcgeom/taxonomy.h"
|
||||
#include "../ifcgeom/ConversionSettings.h"
|
||||
#include "../plugin/plugin.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
@@ -37,11 +37,14 @@ namespace geometry {
|
||||
|
||||
struct IFC_GEOM_API geometry_conversion_task {
|
||||
int index;
|
||||
IfcUtil::IfcBaseEntity* representation;
|
||||
aggregate_of_instance::ptr products;
|
||||
express::Base representation;
|
||||
std::vector<express::Base> products;
|
||||
};
|
||||
|
||||
typedef boost::function<bool(IfcUtil::IfcBaseEntity*)> filter_t;
|
||||
/// The filter function (free or member function) or function object (use boost::ref() to reference to it)
|
||||
/// 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 boost::function<bool(const express::Base&)> filter_t;
|
||||
|
||||
class IFC_GEOM_API abstract_mapping {
|
||||
protected:
|
||||
@@ -53,19 +56,19 @@ namespace geometry {
|
||||
abstract_mapping(Settings& s) : settings_(s) {}
|
||||
virtual ~abstract_mapping() {}
|
||||
|
||||
virtual ifcopenshell::geometry::taxonomy::ptr map(const IfcUtil::IfcBaseInterface*) = 0;
|
||||
virtual void get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters) = 0;
|
||||
virtual IfcUtil::IfcBaseEntity* get_decomposing_entity(const IfcUtil::IfcBaseEntity* product, bool include_openings = true) = 0;
|
||||
virtual std::map<std::string, IfcUtil::IfcBaseEntity*> get_layers(IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual aggregate_of_instance::ptr find_openings(const IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual ifcopenshell::geometry::taxonomy::ptr map(const express::Base&) = 0;
|
||||
virtual void get_representations(std::vector<geometry_conversion_task>& tasks, std::vector<filter_t>& filters) = 0;
|
||||
virtual express::Base get_decomposing_entity(const express::Base& product, bool include_openings = true) = 0;
|
||||
virtual std::map<std::string, express::Base> get_layers(const express::Base&) = 0;
|
||||
virtual std::vector<express::Base> find_openings(const express::Base&) = 0;
|
||||
virtual void initialize_settings() = 0;
|
||||
virtual bool get_layerset_information(const IfcUtil::IfcBaseInterface*, layerset_information&, int&) = 0;
|
||||
virtual bool get_wall_neighbours(const IfcUtil::IfcBaseInterface*, std::vector<endpoint_connection>&) = 0;
|
||||
virtual const IfcUtil::IfcBaseEntity* get_product_type(const IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual const IfcUtil::IfcBaseEntity* get_single_material_association(const IfcUtil::IfcBaseEntity*) = 0;
|
||||
virtual bool get_layerset_information(const express::Base&, layerset_information&, int&) = 0;
|
||||
virtual bool get_wall_neighbours(const express::Base&, std::vector<endpoint_connection>&) = 0;
|
||||
virtual const express::Base get_product_type(const express::Base&) = 0;
|
||||
virtual const express::Base get_single_material_association(const express::Base&) = 0;
|
||||
virtual double get_length_unit() const = 0;
|
||||
virtual const std::string& get_length_unit_name() const = 0;
|
||||
virtual IfcUtil::IfcBaseEntity* representation_of(const IfcUtil::IfcBaseEntity* product) = 0;
|
||||
virtual express::Base representation_of(const express::Base& product) = 0;
|
||||
|
||||
const Settings& settings() const { return settings_; }
|
||||
Settings& settings() { return settings_; }
|
||||
@@ -75,13 +78,29 @@ namespace geometry {
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
typedef boost::function2<abstract_mapping*, IfcParse::IfcFile*, Settings&> mapping_fn;
|
||||
typedef boost::function2<abstract_mapping*, ifcopenshell::file*, Settings&> mapping_fn;
|
||||
|
||||
class IFC_GEOM_API MappingFactoryImplementation : public std::map<std::string, mapping_fn> {
|
||||
class IFC_GEOM_API mapping_registry {
|
||||
public:
|
||||
void bind(const std::string& schema_name, mapping_fn fn, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
|
||||
abstract_mapping* construct(ifcopenshell::file* file, Settings& settings);
|
||||
|
||||
private:
|
||||
struct entry {
|
||||
mapping_fn fn_;
|
||||
ifcopenshell::plugin::module module_;
|
||||
};
|
||||
|
||||
std::map<std::string, entry> entries_;
|
||||
};
|
||||
|
||||
IFC_GEOM_API mapping_registry& mapping_registry_instance();
|
||||
|
||||
class IFC_GEOM_API MappingFactoryImplementation {
|
||||
public:
|
||||
MappingFactoryImplementation();
|
||||
void bind(const std::string& schema_name, mapping_fn);
|
||||
abstract_mapping* construct(IfcParse::IfcFile*, Settings&);
|
||||
abstract_mapping* construct(ifcopenshell::file*, Settings&);
|
||||
};
|
||||
|
||||
IFC_GEOM_API MappingFactoryImplementation& mapping_implementations();
|
||||
|
||||
@@ -76,7 +76,7 @@ struct piecewise_fn_evaluator : public fn_evaluator {
|
||||
span_start += fn->length();
|
||||
}
|
||||
|
||||
Logger::Error("piecewise span not found.");
|
||||
logger::error("piecewise span not found.");
|
||||
return {0, 0, nullptr};
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ struct offset_fn_evaluator : public fn_evaluator {
|
||||
|
||||
|
||||
function_item_evaluator::function_item_evaluator(const ifcopenshell::geometry::Settings& settings,taxonomy::function_item::const_ptr fn) {
|
||||
auto kind = fn->kind();
|
||||
auto kind = fn ? fn->kind() : taxonomy::kinds::NODE;
|
||||
if (kind == taxonomy::FUNCTOR_ITEM) {
|
||||
fn_evaluator_ = new functor_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::functor_item>(fn),settings);
|
||||
} else if (kind == taxonomy::PIECEWISE_FUNCTION) {
|
||||
@@ -235,7 +235,7 @@ function_item_evaluator::function_item_evaluator(const ifcopenshell::geometry::S
|
||||
} else if (kind == taxonomy::OFFSET_FUNCTION) {
|
||||
fn_evaluator_ = new offset_fn_evaluator(std::dynamic_pointer_cast<const taxonomy::offset_function>(fn), settings);
|
||||
} else {
|
||||
Logger::Error("Unexpected function type");
|
||||
logger::error("Unexpected function type");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +308,9 @@ taxonomy::item::ptr function_item_evaluator::evaluate(const std::vector<double>&
|
||||
}
|
||||
|
||||
Eigen::Matrix4d function_item_evaluator::evaluate(double u) const {
|
||||
if (fn_evaluator_ == nullptr) {
|
||||
throw std::runtime_error("Function item not initialized");
|
||||
}
|
||||
Eigen::Matrix4d m = fn_evaluator_->evaluate(u);
|
||||
if (!fn_evaluator_->settings_.get<ifcopenshell::geometry::settings::ComputeCurvature>().get()) {
|
||||
m.row(3) = Eigen::Vector4d(0, 0, 0, 1);
|
||||
|
||||
@@ -76,7 +76,7 @@ class IFC_GEOM_API function_item_evaluator {
|
||||
taxonomy::item::ptr evaluate(const std::vector<double>& dist) const;
|
||||
fn_evaluator* fn_evaluator_ = nullptr;
|
||||
|
||||
mutable boost::optional<std::vector<double>> eval_points_; // cache evaluation points
|
||||
mutable std::optional<std::vector<double>> eval_points_; // cache evaluation points
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
+12
-107
@@ -21,39 +21,7 @@
|
||||
#define HYBRID_KERNEL_H
|
||||
|
||||
#include "AbstractKernel.h"
|
||||
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h"
|
||||
#undef Handle
|
||||
#endif
|
||||
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
|
||||
#undef CGAL_KERNEL_H
|
||||
#undef CGALCONVERSIONRESULT_H
|
||||
#define IFOPSH_SIMPLE_KERNEL
|
||||
#include "../ifcgeom/kernels/cgal/CgalKernel.h"
|
||||
#undef CgalKernel
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
inline bool is_valid_for_kernel(const ifcopenshell::geometry::kernels::AbstractKernel* k, const IfcGeom::ConversionResult& shp) {
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
if (k->geometry_library() == "opencascade") {
|
||||
return dynamic_cast<ifcopenshell::geometry::OpenCascadeShape*>(shp.Shape().get()) != nullptr;
|
||||
}
|
||||
#endif
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
if (k->geometry_library() == "cgal-simple") {
|
||||
return dynamic_cast<ifcopenshell::geometry::SimpleCgalShape*>(shp.Shape().get()) != nullptr;
|
||||
}
|
||||
if (k->geometry_library() == "cgal") {
|
||||
return dynamic_cast<ifcopenshell::geometry::CgalShape*>(shp.Shape().get()) != nullptr;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#include "kernel_registry.h"
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
@@ -62,9 +30,9 @@ namespace ifcopenshell {
|
||||
class HybridKernel : public ifcopenshell::geometry::kernels::AbstractKernel {
|
||||
std::vector<std::unique_ptr<AbstractKernel>> kernels_;
|
||||
ifcopenshell::geometry::abstract_mapping* mapping_;
|
||||
IfcParse::IfcFile* file_;
|
||||
ifcopenshell::file* file_;
|
||||
public:
|
||||
HybridKernel(const std::string& name, IfcParse::IfcFile* file, Settings& settings, std::vector<std::unique_ptr<AbstractKernel>>&& kernels)
|
||||
HybridKernel(const std::string& name, ifcopenshell::file* file, Settings& settings, std::vector<std::unique_ptr<AbstractKernel>>&& kernels)
|
||||
: AbstractKernel(name, settings)
|
||||
, kernels_(std::move(kernels))
|
||||
, mapping_(ifcopenshell::geometry::impl::mapping_implementations().construct(file, settings))
|
||||
@@ -82,8 +50,8 @@ namespace ifcopenshell {
|
||||
}
|
||||
virtual bool convert(const taxonomy::ptr item, IfcGeom::ConversionResults& rs)
|
||||
{
|
||||
auto ops = mapping_->find_openings(item->instance->as<IfcUtil::IfcBaseEntity>());
|
||||
bool has_openings = ops && ops->size();
|
||||
auto ops = mapping_->find_openings(item->instance);
|
||||
bool has_openings = ops.size();
|
||||
for (auto& k : kernels_) {
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
if (has_openings && !k->supports_boolean_operations()) {
|
||||
@@ -96,6 +64,9 @@ namespace ifcopenshell {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (has_openings && k->geometry_library() == "passthrough") {
|
||||
continue;
|
||||
}
|
||||
bool success = false;
|
||||
try {
|
||||
success = k->convert(item, rs);
|
||||
@@ -119,7 +90,7 @@ namespace ifcopenshell {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual bool apply_folded_layerset(IfcGeom::ConversionResults& items, const ifcopenshell::geometry::layerset_information& layers, const std::map<IfcUtil::IfcBaseEntity*, ifcopenshell::geometry::layerset_information>& folds)
|
||||
virtual bool apply_folded_layerset(IfcGeom::ConversionResults& items, const ifcopenshell::geometry::layerset_information& layers, const std::map<express::Base, ifcopenshell::geometry::layerset_information>& folds)
|
||||
{
|
||||
for (auto& k : kernels_) {
|
||||
bool success = false;
|
||||
@@ -132,13 +103,13 @@ namespace ifcopenshell {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
virtual bool convert_openings(const express::Base& entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes)
|
||||
{
|
||||
for (auto& k : kernels_) {
|
||||
bool is_valid = true;
|
||||
for (auto& s : entity_shapes) {
|
||||
if (!is_valid_for_kernel(k.get(), s)) {
|
||||
if (!k->accepts(*s.Shape())) {
|
||||
is_valid = false;
|
||||
break;
|
||||
}
|
||||
@@ -166,74 +137,8 @@ namespace ifcopenshell {
|
||||
return new HybridKernel(geometry_library(), file_, const_cast<Settings&>(settings()), std::move(ks));
|
||||
}
|
||||
};
|
||||
|
||||
inline std::unique_ptr<AbstractKernel> construct(IfcParse::IfcFile* file, const std::string& geometry_library, Settings& conv_settings) {
|
||||
std::string geometry_library_lower = boost::to_lower_copy(geometry_library);
|
||||
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
if (geometry_library_lower == "opencascade") {
|
||||
return std::make_unique<IfcGeom::OpenCascadeKernel>(conv_settings);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
if (geometry_library_lower == "cgal") {
|
||||
return std::make_unique<CgalKernel>(conv_settings);
|
||||
}
|
||||
|
||||
if (geometry_library_lower == "cgal-simple") {
|
||||
return std::make_unique<SimpleCgalKernel>(conv_settings);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (geometry_library_lower.rfind("hybrid-", 0) == 0) {
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("hybrid"));
|
||||
std::vector<std::unique_ptr<AbstractKernel>> kernels;
|
||||
while (!geometry_library_lower.empty()) {
|
||||
if (geometry_library_lower.find("-", 0) == 0) {
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("-"));
|
||||
} else {
|
||||
throw IfcParse::IfcException("Invalid hybrid kernel " + geometry_library);
|
||||
}
|
||||
auto n = kernels.size();
|
||||
#ifdef IFOPSH_WITH_OPENCASCADE
|
||||
if (geometry_library_lower.find("opencascade", 0) == 0) {
|
||||
kernels.emplace_back(new IfcGeom::OpenCascadeKernel(conv_settings));
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("opencascade"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IFOPSH_WITH_CGAL
|
||||
if (geometry_library_lower.find("cgal-simple", 0) == 0) {
|
||||
kernels.emplace_back(new SimpleCgalKernel(conv_settings));
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("cgal-simple"));
|
||||
}
|
||||
|
||||
if (geometry_library_lower.find("cgal", 0) == 0) {
|
||||
kernels.emplace_back(new CgalKernel(conv_settings));
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("cgal"));
|
||||
}
|
||||
#endif
|
||||
if (kernels.size() != n + 1) {
|
||||
throw IfcParse::IfcException("Invalid hybrid kernel " + geometry_library);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = kernels.begin(); it != kernels.end(); ++it) {
|
||||
(**it).propagate_exceptions = it == kernels.begin();
|
||||
(**it).partial_success_is_success = it == kernels.end() - 1;
|
||||
}
|
||||
|
||||
if (!kernels.empty()) {
|
||||
return std::make_unique<HybridKernel>(geometry_library, file, conv_settings, std::move(kernels));
|
||||
}
|
||||
}
|
||||
|
||||
throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -20,18 +20,16 @@
|
||||
#ifndef IFC_GEOM_API_H
|
||||
#define IFC_GEOM_API_H
|
||||
|
||||
#ifdef IFC_SHARED_BUILD
|
||||
#ifdef _WIN32
|
||||
#ifdef IFC_GEOM_EXPORTS
|
||||
#define IFC_GEOM_API __declspec(dllexport)
|
||||
#else
|
||||
#define IFC_GEOM_API __declspec(dllimport)
|
||||
#endif
|
||||
#else // simply assume *nix + GCC-like compiler
|
||||
#define IFC_GEOM_API __attribute__((visibility("default")))
|
||||
#ifdef SWIG
|
||||
#define IFC_GEOM_API
|
||||
#elif defined(_WIN32)
|
||||
#ifdef IFC_GEOM_EXPORTS
|
||||
#define IFC_GEOM_API __declspec(dllexport)
|
||||
#else
|
||||
#define IFC_GEOM_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define IFC_GEOM_API
|
||||
#define IFC_GEOM_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,7 @@ bool has_intersection(const std::set<T, Cmp>& A,
|
||||
|
||||
}
|
||||
|
||||
taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::function_item::ptr& fn, std::vector<cross_section>& cross_sections)
|
||||
taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_, const express::Base inst, const taxonomy::function_item::ptr& fn, std::vector<cross_section>& cross_sections)
|
||||
{
|
||||
std::sort(cross_sections.begin(), cross_sections.end());
|
||||
|
||||
@@ -51,7 +51,7 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
double end = std::min(fn->length(), cross_sections.back().dist_along);
|
||||
|
||||
if (end - start < 1.e-9) {
|
||||
Logger::Warning("Empty sweep domain with start at " + std::to_string(cross_sections.front().dist_along) + " end at " + std::to_string(cross_sections.back().dist_along) + " and curve domain length " + std::to_string(fn->length()), inst);
|
||||
logger::warning("Empty sweep domain with start at " + std::to_string(cross_sections.front().dist_along) + " end at " + std::to_string(cross_sections.back().dist_along) + " and curve domain length " + std::to_string(fn->length()), inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -98,12 +98,12 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
(profile_index + 1 < longitudes.end()) &&
|
||||
(relative_dist_along >= 1.e-9 || offset_a.cwiseAbs().maxCoeff() > 0. || rotation_a);
|
||||
|
||||
boost::optional<Eigen::Matrix3d> interpolated_rotation;
|
||||
std::optional<Eigen::Matrix3d> interpolated_rotation;
|
||||
|
||||
if (should_interpolate) {
|
||||
taxonomy::geom_item::ptr profile_b;
|
||||
Eigen::Vector3d offset_b;
|
||||
boost::optional<Eigen::Matrix3d> rotation_b;
|
||||
std::optional<Eigen::Matrix3d> rotation_b;
|
||||
if ((profile_index + 1 < longitudes.end())) {
|
||||
profile_b = cross_sections[std::distance(longitudes.begin(), profile_index) + 1].section_geometry;
|
||||
offset_b = cross_sections[std::distance(longitudes.begin(), profile_index) + 1].offset;
|
||||
@@ -130,7 +130,7 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
auto profile_b_f = std::static_pointer_cast<taxonomy::face>(profile_b);
|
||||
|
||||
if (profile_a_f->children.size() != profile_b_f->children.size()) {
|
||||
Logger::Warning("Mismatching number of face boundaries: " +
|
||||
logger::warning("Mismatching number of face boundaries: " +
|
||||
std::to_string(profile_a_f->children.size()) + " vs " +
|
||||
std::to_string(profile_b_f->children.size()),
|
||||
inst
|
||||
@@ -160,12 +160,12 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
}
|
||||
|
||||
auto interpolated_offset = lerp(offset_a, offset_b, relative_dist_along);
|
||||
if (rotation_a.has_value() && rotation_b.has_value() ) {
|
||||
// @todo we don't support an overridden rotation on only one of the placements
|
||||
if (rotation_a == rotation_b && rotation_a) {
|
||||
// @todo we don't support an overridden rotation on only one of the placements
|
||||
// in which case we would need to lerp with the rotation component below in m4b.
|
||||
interpolated_rotation = lerp(*rotation_a, *rotation_b, relative_dist_along);
|
||||
} else if (rotation_a != rotation_b) {
|
||||
Logger::Error("Direction vectors on cross section placements only supported when used consistently");
|
||||
logger::error("Direction vectors on cross section placements only supported when used consistently");
|
||||
}
|
||||
|
||||
taxonomy::loop::ptr w1, w2;
|
||||
@@ -176,12 +176,12 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
boost::tie(w1, w2) = tmp_;
|
||||
|
||||
if (w1->closed != w2->closed) {
|
||||
Logger::Warning("Mismatching closed property on loops", inst);
|
||||
logger::warning("Mismatching closed property on loops", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (w1->tags.is_initialized() != w2->tags.is_initialized()) {
|
||||
Logger::Warning("Mismatching availability tags on loops", inst);
|
||||
if (w1->tags.has_value() != w2->tags.has_value()) {
|
||||
logger::warning("Mismatching availability tags on loops", inst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
std::set<std::string> tags_seen;
|
||||
for (const auto& t : *w1->tags) {
|
||||
if (tags_seen.find(t) != tags_seen.end()) {
|
||||
Logger::Warning("Duplicate tag '" + t + "' on loft profile", inst);
|
||||
logger::warning("Duplicate tag '" + t + "' on loft profile", inst);
|
||||
return nullptr;
|
||||
}
|
||||
tags_seen.insert(t);
|
||||
@@ -202,7 +202,7 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
std::set<std::string> tags_seen;
|
||||
for (const auto& t : *w2->tags) {
|
||||
if (tags_seen.find(t) != tags_seen.end()) {
|
||||
Logger::Warning("Duplicate tag '" + t + "' on loft profile", inst);
|
||||
logger::warning("Duplicate tag '" + t + "' on loft profile", inst);
|
||||
return nullptr;
|
||||
}
|
||||
tags_seen.insert(t);
|
||||
@@ -211,26 +211,26 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
|
||||
std::map<std::string, taxonomy::point3::ptr> tag_to_point_on_w1, tag_to_point_on_w2;
|
||||
|
||||
auto loop_to_points = [](const taxonomy::loop::ptr& loop, const boost::optional<std::vector<std::string>>& input_tags) -> std::pair<std::vector<taxonomy::point3::ptr>, std::vector<std::set<std::string>>> {
|
||||
auto loop_to_points = [](const taxonomy::loop::ptr& loop, const std::optional<std::vector<std::string>>& input_tags) -> std::pair<std::vector<taxonomy::point3::ptr>, std::vector<std::set<std::string>>> {
|
||||
std::vector<taxonomy::point3::ptr> points;
|
||||
std::vector<std::set<std::string>> tags;
|
||||
std::vector<std::string>::const_iterator tag_it;
|
||||
|
||||
if (!loop->closed.get_value_or(false)) {
|
||||
points = {boost::get<taxonomy::point3::ptr>(loop->children[0]->start)};
|
||||
if (!loop->closed.value_or(false)) {
|
||||
points = {std::get<taxonomy::point3::ptr>(loop->children[0]->start)};
|
||||
if (input_tags) {
|
||||
tags = {{input_tags->front()}};
|
||||
tag_it = ++input_tags->begin();
|
||||
}
|
||||
}
|
||||
for (auto& e : loop->children) {
|
||||
const auto& p1_ = boost::get<taxonomy::point3::ptr>(e->start);
|
||||
const auto& p2_ = boost::get<taxonomy::point3::ptr>(e->end);
|
||||
if (input_tags && p1_->ccomponents() == p2_->ccomponents()) {
|
||||
const auto& p1 = std::get<taxonomy::point3::ptr>(e->start);
|
||||
const auto& p2 = std::get<taxonomy::point3::ptr>(e->end);
|
||||
if (input_tags && p1->ccomponents() == p2->ccomponents()) {
|
||||
tags.back().insert(*tag_it);
|
||||
++tag_it;
|
||||
} else {
|
||||
points.push_back(p2_);
|
||||
points.push_back(p2);
|
||||
if (input_tags) {
|
||||
tags.emplace_back();
|
||||
tags.back().insert(*tag_it);
|
||||
@@ -239,7 +239,7 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
}
|
||||
}
|
||||
if (!input_tags) {
|
||||
if (loop->closed.get_value_or(false)) {
|
||||
if (loop->closed.value_or(false)) {
|
||||
// close polygon by referencing first point
|
||||
points.push_back(points.front());
|
||||
}
|
||||
@@ -303,20 +303,20 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
|
||||
for (auto& p1_tags : w1_tags) {
|
||||
if (!has_intersection(p1_tags, w2_tags_combined)) {
|
||||
Logger::Warning("No matching tags found on loft profiles: " + join_tags(p1_tags) + " not in " + join_tags(w2_tags_combined), inst);
|
||||
logger::warning("No matching tags found on loft profiles: " + join_tags(p1_tags) + " not in " + join_tags(w2_tags_combined), inst);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& p2_tags : w2_tags) {
|
||||
if (!has_intersection(p2_tags, w1_tags_combined)) {
|
||||
Logger::Warning("No matching tags found on loft profiles: " + join_tags(p2_tags) + " not in " + join_tags(w1_tags_combined), inst);
|
||||
logger::warning("No matching tags found on loft profiles: " + join_tags(p2_tags) + " not in " + join_tags(w1_tags_combined), inst);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (w1->children.size() != w2->children.size()) {
|
||||
Logger::Warning("Mismatching number of edges: " +
|
||||
logger::warning("Mismatching number of edges: " +
|
||||
std::to_string(w1->children.size()) + " vs " +
|
||||
std::to_string(w2->children.size()),
|
||||
inst);
|
||||
@@ -334,10 +334,10 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& p1_ = tag_to_point_on_w1[t];
|
||||
const auto& p2_ = tag_to_point_on_w2[t];
|
||||
const auto& p1 = tag_to_point_on_w1[t];
|
||||
const auto& p2 = tag_to_point_on_w2[t];
|
||||
|
||||
auto p3 = (lerp(p1_->ccomponents(), p2_->ccomponents(), relative_dist_along) + interpolated_offset).eval();
|
||||
auto p3 = (lerp(p1->ccomponents(), p2->ccomponents(), relative_dist_along) + interpolated_offset).eval();
|
||||
|
||||
std::set<std::string> tags_for_this_point_on_subsequent_profile = {t};
|
||||
|
||||
@@ -365,13 +365,13 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
/*
|
||||
// This is handled in the loop_to_points() function above
|
||||
if (!points.empty()) {
|
||||
if (!w1->closed.get_value_or(true) && !w2->closed.get_value_or(true)) {
|
||||
if (!w1->closed.value_or(true) && !w2->closed.value_or(true)) {
|
||||
// open polygon, add last point
|
||||
auto& p1 = boost::get<taxonomy::point3::ptr>(w1->children.back()->end);
|
||||
auto& p2 = boost::get<taxonomy::point3::ptr>(w2->children.back()->end);
|
||||
auto& p1 = std::get<taxonomy::point3::ptr>(w1->children.back()->end);
|
||||
auto& p2 = std::get<taxonomy::point3::ptr>(w2->children.back()->end);
|
||||
auto p3 = (lerp(p1->ccomponents(), p2->ccomponents(), relative_dist_along) + interpolated_offset).eval();
|
||||
points.push_back(taxonomy::make<taxonomy::point3>(p3));
|
||||
} else if (w1->closed.get_value_or(true) && w2->closed.get_value_or(true)) {
|
||||
} else if (w1->closed.value_or(true) && w2->closed.value_or(true)) {
|
||||
// close polygon by referencing first point
|
||||
// @todo add a closed=true|false to polygon_from_points()?
|
||||
points.push_back(points.front());
|
||||
@@ -431,6 +431,19 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
auto m = (m4b * loft->children.back()->matrix->ccomponents()).eval();
|
||||
loft->children.back()->matrix->components() = m;
|
||||
}
|
||||
|
||||
auto find_closest = [](const std::vector<double>& v, double target) -> std::vector<double>::const_iterator {
|
||||
auto it = std::lower_bound(v.begin(), v.end(), target);
|
||||
|
||||
if (it == v.begin()) {
|
||||
return it;
|
||||
}
|
||||
|
||||
double after = *it;
|
||||
double before = *(it - 1);
|
||||
|
||||
return (std::abs(after - target) < std::abs(target - before)) ? it : (it - 1);
|
||||
};
|
||||
}
|
||||
|
||||
return loft;
|
||||
|
||||
@@ -14,14 +14,14 @@ namespace ifcopenshell {
|
||||
double dist_along;
|
||||
taxonomy::geom_item::ptr section_geometry;
|
||||
Eigen::Vector3d offset;
|
||||
boost::optional<Eigen::Matrix3d> rotation;
|
||||
std::optional<Eigen::Matrix3d> rotation;
|
||||
|
||||
bool operator <(const cross_section& other) const {
|
||||
return dist_along < other.dist_along;
|
||||
}
|
||||
};
|
||||
|
||||
IFC_GEOM_API taxonomy::loft::ptr make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::function_item::ptr& directrix, std::vector<cross_section>& cross_sections);
|
||||
IFC_GEOM_API taxonomy::loft::ptr make_loft(const Settings& settings_, const express::Base inst, const taxonomy::function_item::ptr& directrix, std::vector<cross_section>& cross_sections);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "kernel_plugin.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace {
|
||||
constexpr const char* kernel_plugin_prefix = "geometry.kernel.";
|
||||
}
|
||||
|
||||
const char* ifcopenshell::geometry::kernels::kernel_plugin_registration_symbol() {
|
||||
return "ifcopenshell_register_kernel_plugin_v1";
|
||||
}
|
||||
|
||||
ifcopenshell::plugin::metadata ifcopenshell::geometry::kernels::kernel_plugin_metadata(const std::string& plugin_name) {
|
||||
plugin::metadata metadata;
|
||||
metadata.kind_ = plugin::kind::kernel;
|
||||
metadata.id = kernel_plugin_prefix + plugin_name;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
std::filesystem::path ifcopenshell::geometry::kernels::kernel_plugin_directory() {
|
||||
return plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::geometry::kernels::load_kernel_plugins));
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::kernels::load_kernel_plugins(kernel_registry& registry) {
|
||||
plugin::manager manager;
|
||||
manager.add_search_path(kernel_plugin_directory());
|
||||
|
||||
for (const auto& path : manager.discover(kernel_plugin_prefix)) {
|
||||
auto module = manager.load(path);
|
||||
if (module.meta().kind_ != plugin::kind::kernel) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto register_plugin = module.get_alias<register_kernel_plugin_fn>(kernel_plugin_registration_symbol());
|
||||
register_plugin(registry, module);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef IFCOPENSHELL_KERNEL_PLUGIN_H
|
||||
#define IFCOPENSHELL_KERNEL_PLUGIN_H
|
||||
|
||||
#include "../ifcgeom/kernel_registry.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
namespace kernels {
|
||||
|
||||
typedef void register_kernel_plugin_fn(kernel_registry&, const ifcopenshell::plugin::module&);
|
||||
|
||||
IFC_GEOM_API const char* kernel_plugin_registration_symbol();
|
||||
IFC_GEOM_API ifcopenshell::plugin::metadata kernel_plugin_metadata(const std::string& plugin_name);
|
||||
IFC_GEOM_API std::filesystem::path kernel_plugin_directory();
|
||||
IFC_GEOM_API void load_kernel_plugins(kernel_registry& registry);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,118 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "kernel_registry.h"
|
||||
|
||||
#include "../ifcgeom/kernel_plugin.h"
|
||||
#include "../ifcgeom/hybrid_kernel.h"
|
||||
#include "../ifcparse/file.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
namespace {
|
||||
std::string kernel_key(const std::string& backend_id) {
|
||||
return boost::to_lower_copy(backend_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::kernels::kernel_registry::bind(const kernel_info& info, create_fn create, const plugin::module& module) {
|
||||
entry entry;
|
||||
entry.info_ = info;
|
||||
entry.create_ = create;
|
||||
entry.module_ = module;
|
||||
entries_[kernel_key(info.backend_id)] = entry;
|
||||
}
|
||||
|
||||
bool ifcopenshell::geometry::kernels::kernel_registry::has(const std::string& backend_id) const {
|
||||
return entries_.find(kernel_key(backend_id)) != entries_.end();
|
||||
}
|
||||
|
||||
std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel> ifcopenshell::geometry::kernels::kernel_registry::create(const std::string& backend_id, ifcopenshell::file* file, Settings& settings) const {
|
||||
const auto iter = entries_.find(kernel_key(backend_id));
|
||||
if (iter == entries_.end()) {
|
||||
throw ifcopenshell::exception("No geometry kernel registered for " + backend_id);
|
||||
}
|
||||
return std::unique_ptr<AbstractKernel>(iter->second.create_(file, settings));
|
||||
}
|
||||
|
||||
std::vector<ifcopenshell::geometry::kernels::kernel_info> ifcopenshell::geometry::kernels::kernel_registry::kernels() const {
|
||||
std::vector<kernel_info> result;
|
||||
for (const auto& pair : entries_) {
|
||||
result.push_back(pair.second.info_);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::kernels::kernel_registry& ifcopenshell::geometry::kernels::kernel_registry_instance() {
|
||||
static kernel_registry registry;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, load_kernel_plugins, std::ref(registry));
|
||||
return registry;
|
||||
}
|
||||
|
||||
std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel> ifcopenshell::geometry::kernels::construct(ifcopenshell::file* file, const std::string& geometry_library, Settings& settings) {
|
||||
auto geometry_library_lower = boost::to_lower_copy(geometry_library);
|
||||
auto& registry = kernel_registry_instance();
|
||||
|
||||
if (registry.has(geometry_library_lower)) {
|
||||
return registry.create(geometry_library_lower, file, settings);
|
||||
}
|
||||
|
||||
if (geometry_library_lower.rfind("hybrid-", 0) == 0) {
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("hybrid"));
|
||||
std::vector<std::unique_ptr<AbstractKernel>> kernels;
|
||||
while (!geometry_library_lower.empty()) {
|
||||
if (geometry_library_lower.find("-", 0) == 0) {
|
||||
geometry_library_lower = geometry_library_lower.substr(strlen("-"));
|
||||
} else {
|
||||
throw ifcopenshell::exception("Invalid hybrid kernel " + geometry_library);
|
||||
}
|
||||
|
||||
std::string matched_backend_id;
|
||||
for (const auto& info : registry.kernels()) {
|
||||
const auto backend_id = kernel_key(info.backend_id);
|
||||
if (geometry_library_lower.rfind(backend_id, 0) == 0 && backend_id.size() > matched_backend_id.size()) {
|
||||
matched_backend_id = backend_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched_backend_id.empty()) {
|
||||
throw ifcopenshell::exception("Invalid hybrid kernel " + geometry_library);
|
||||
}
|
||||
|
||||
kernels.push_back(registry.create(matched_backend_id, file, settings));
|
||||
geometry_library_lower = geometry_library_lower.substr(matched_backend_id.size());
|
||||
}
|
||||
|
||||
for (auto it = kernels.begin(); it != kernels.end(); ++it) {
|
||||
(**it).propagate_exceptions = it == kernels.begin();
|
||||
(**it).partial_success_is_success = it == kernels.end() - 1;
|
||||
}
|
||||
|
||||
if (!kernels.empty()) {
|
||||
return std::make_unique<HybridKernel>(geometry_library, file, settings, std::move(kernels));
|
||||
}
|
||||
}
|
||||
|
||||
throw ifcopenshell::exception("No geometry kernel registered for " + geometry_library);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef KERNEL_REGISTRY_H
|
||||
#define KERNEL_REGISTRY_H
|
||||
|
||||
#include "../ifcgeom/AbstractKernel.h"
|
||||
#include "../plugin/plugin.h"
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ifcopenshell {
|
||||
class file;
|
||||
|
||||
namespace geometry {
|
||||
namespace kernels {
|
||||
|
||||
struct IFC_GEOM_API kernel_info {
|
||||
std::string backend_id;
|
||||
bool supports_boolean_operations = false;
|
||||
};
|
||||
|
||||
class IFC_GEOM_API kernel_registry {
|
||||
public:
|
||||
typedef boost::function2<AbstractKernel*, ifcopenshell::file*, Settings&> create_fn;
|
||||
|
||||
void bind(const kernel_info& info, create_fn create, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
|
||||
bool has(const std::string& backend_id) const;
|
||||
std::unique_ptr<AbstractKernel> create(const std::string& backend_id, ifcopenshell::file* file, Settings& settings) const;
|
||||
std::vector<kernel_info> kernels() const;
|
||||
|
||||
private:
|
||||
struct entry {
|
||||
kernel_info info_;
|
||||
create_fn create_;
|
||||
ifcopenshell::plugin::module module_;
|
||||
};
|
||||
|
||||
std::map<std::string, entry> entries_;
|
||||
};
|
||||
|
||||
IFC_GEOM_API kernel_registry& kernel_registry_instance();
|
||||
IFC_GEOM_API std::unique_ptr<AbstractKernel> construct(ifcopenshell::file* file, const std::string& geometry_library, Settings& settings);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,46 +1,71 @@
|
||||
find_package(Eigen3 REQUIRED)
|
||||
message(STATUS "GEOMETRY_KERNELS ${GEOMETRY_KERNELS}")
|
||||
|
||||
set(kernel_plugin_runtime_dir "$<TARGET_FILE_DIR:IfcGeom>")
|
||||
|
||||
foreach(kernel ${GEOMETRY_KERNELS})
|
||||
string(TOUPPER ${kernel} KERNEL_UPPER)
|
||||
file(GLOB IFCGEOM_H_FILES ${kernel}/*.h)
|
||||
file(GLOB IFCGEOM_CPP_FILES ${kernel}/*.cpp)
|
||||
if(${kernel} STREQUAL "opencascade")
|
||||
list(REMOVE_ITEM IFCGEOM_CPP_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/tree_brep_plugin.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/tree_trianglebvh_plugin.cpp
|
||||
)
|
||||
endif()
|
||||
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
|
||||
|
||||
set(KERNEL_TARGET "geometry_kernel_${kernel}")
|
||||
|
||||
add_library(${KERNEL_TARGET} ${IFCGEOM_FILES})
|
||||
set_target_properties(
|
||||
${KERNEL_TARGET}
|
||||
PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS" PUBLIC_HEADER "${IFCGEOM_H_FILES}"
|
||||
add_library(${KERNEL_TARGET} SHARED ${IFCGEOM_FILES})
|
||||
set_target_properties(${KERNEL_TARGET} PROPERTIES
|
||||
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS"
|
||||
OUTPUT_NAME "geometry.kernel.${kernel}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
|
||||
)
|
||||
list(APPEND kernel_libraries ${KERNEL_TARGET})
|
||||
target_link_libraries(${KERNEL_TARGET} ${${KERNEL_UPPER}_LIBRARIES} IfcGeom Eigen3::Eigen)
|
||||
install(
|
||||
TARGETS ${KERNEL_TARGET}
|
||||
EXPORT ${IFCOPENSHELL_EXPORT_TARGETS}
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ifcgeom/kernels/${kernel}"
|
||||
)
|
||||
target_link_libraries(${KERNEL_TARGET} PRIVATE plugin IfcGeom ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
|
||||
|
||||
install(TARGETS ${KERNEL_TARGET})
|
||||
|
||||
if(${kernel} STREQUAL "cgal")
|
||||
find_package(CGAL REQUIRED)
|
||||
target_link_libraries(${KERNEL_TARGET} IFCOPENSHELL_CGAL)
|
||||
set_property(TARGET ${KERNEL_TARGET} APPEND_STRING PROPERTY COMPILE_FLAGS " -DCGAL_HAS_THREADS")
|
||||
|
||||
set(KERNEL_TARGET_SIMPLE "${KERNEL_TARGET}_simple")
|
||||
add_library(${KERNEL_TARGET_SIMPLE} ${IFCGEOM_FILES})
|
||||
set_target_properties(
|
||||
${KERNEL_TARGET_SIMPLE}
|
||||
PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIFOPSH_SIMPLE_KERNEL -DCGAL_HAS_THREADS"
|
||||
add_library(${KERNEL_TARGET_SIMPLE} SHARED ${IFCGEOM_FILES})
|
||||
set_target_properties(${KERNEL_TARGET_SIMPLE} PROPERTIES
|
||||
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS -DIFOPSH_SIMPLE_KERNEL -DCGAL_HAS_THREADS"
|
||||
OUTPUT_NAME "geometry.kernel.cgalsimple"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
|
||||
)
|
||||
list(APPEND kernel_libraries ${KERNEL_TARGET_SIMPLE})
|
||||
target_link_libraries(${KERNEL_TARGET_SIMPLE} ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
|
||||
target_link_libraries(${KERNEL_TARGET_SIMPLE} IFCOPENSHELL_CGAL)
|
||||
install(TARGETS ${KERNEL_TARGET_SIMPLE} EXPORT ${IFCOPENSHELL_EXPORT_TARGETS})
|
||||
target_link_libraries(${KERNEL_TARGET_SIMPLE} PRIVATE plugin IfcGeom ${${KERNEL_UPPER}_LIBRARIES} Eigen3::Eigen)
|
||||
install(TARGETS ${KERNEL_TARGET_SIMPLE})
|
||||
elseif(${kernel} STREQUAL "opencascade")
|
||||
target_link_libraries(${KERNEL_TARGET} ${OpenCASCADE_LIBRARIES})
|
||||
target_link_libraries(${KERNEL_TARGET} PRIVATE ${OpenCASCADE_LIBRARIES})
|
||||
|
||||
foreach(tree_backend brep trianglebvh)
|
||||
set(TREE_TARGET "geometry_tree_opencascade_${tree_backend}")
|
||||
add_library(${TREE_TARGET} SHARED
|
||||
${kernel}/tree_${tree_backend}_plugin.cpp
|
||||
${kernel}/tree_backends.h
|
||||
)
|
||||
set_target_properties(${TREE_TARGET} PROPERTIES
|
||||
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS"
|
||||
OUTPUT_NAME "geometry.tree.opencascade.${tree_backend}"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
|
||||
)
|
||||
list(APPEND tree_libraries ${TREE_TARGET})
|
||||
target_link_libraries(${TREE_TARGET} PRIVATE plugin IfcGeom geometry_kernel_opencascade ${OpenCASCADE_LIBRARIES} Eigen3::Eigen)
|
||||
install(TARGETS ${TREE_TARGET})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
install(FILES ${IFCGEOM_H_FILES}
|
||||
DESTINATION ${INCLUDEDIR}/ifcgeom/kernels/${kernel}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
|
||||
|
||||
install(FILES ifc_geomlibrary_api.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ifcgeom/kernels/")
|
||||
set(tree_libraries ${tree_libraries} PARENT_SCOPE)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_mesh_to_polygon_soup.h>
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcparse/logger.h"
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
|
||||
using IfcGeom::OpaqueNumber;
|
||||
@@ -112,7 +112,7 @@ ifcopenshell::geometry::CgalShape::CgalShape(const cgal_shape_t& shape, bool con
|
||||
auto b2 = plane.base2();
|
||||
|
||||
if (V.squared_length() == 0) {
|
||||
Logger::Warning("Removed face due to self-intersections");
|
||||
logger::warning("Removed face due to self-intersections");
|
||||
faces_to_remove.insert(face);
|
||||
continue;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ ifcopenshell::geometry::CgalShape::CgalShape(const cgal_shape_t& shape, bool con
|
||||
}
|
||||
|
||||
if (!CGAL::Polygon_2<Kernel_>(ps.begin(), ps.end()).is_simple()) {
|
||||
Logger::Warning("Removed face due to self-intersections");
|
||||
logger::warning("Removed face due to self-intersections");
|
||||
faces_to_remove.insert(face);
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<double> smooth_treshold;
|
||||
std::optional<double> smooth_treshold;
|
||||
{
|
||||
auto setting_value = settings.get<ifcopenshell::geometry::settings::CgalSmoothAngleDegrees>().get();
|
||||
if (setting_value > 0.) {
|
||||
@@ -233,7 +233,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
|
||||
|
||||
if (!all_triangles) {
|
||||
if (!shape_to_use->is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)");
|
||||
logger::message(logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -241,19 +241,19 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
|
||||
try {
|
||||
success = CGAL::Polygon_mesh_processing::triangulate_faces(*shape_to_use);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation crashed");
|
||||
logger::message(logger::LOG_ERROR, "Triangulation crashed");
|
||||
return;
|
||||
}
|
||||
|
||||
CGAL::Polygon_mesh_processing::remove_degenerate_faces(*shape_to_use);
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation failed");
|
||||
logger::message(logger::LOG_ERROR, "Triangulation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shape_to_use->is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)");
|
||||
logger::message(logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -282,7 +282,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
|
||||
try {
|
||||
CGAL::Polygon_mesh_processing::compute_face_normals(*shape_to_use, face_normals_map);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Face normal calculation failed");
|
||||
logger::message(logger::LOG_ERROR, "Face normal calculation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Sett
|
||||
int num_faces = 0, num_vertices = 0;
|
||||
for (auto &face : faces(*shape_to_use)) {
|
||||
if (!face->is_triangle()) {
|
||||
std::cout << "Warning: non-triangular face!" << std::endl;
|
||||
std::cout << "warning: non-triangular face!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
CGAL::Polyhedron_3<Kernel_>::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -180,9 +180,9 @@ namespace ifcopenshell { namespace geometry {
|
||||
class IFC_GEOMLIBRARY_API CgalShape : public IfcGeom::ConversionResultShape {
|
||||
private:
|
||||
bool convex_tag_ = false;
|
||||
mutable boost::optional<cgal_shape_t> shape_;
|
||||
mutable std::optional<cgal_shape_t> shape_;
|
||||
#ifndef IFOPSH_SIMPLE_KERNEL
|
||||
mutable boost::optional<CGAL::Nef_polyhedron_3<Kernel_>> nef_;
|
||||
mutable std::optional<CGAL::Nef_polyhedron_3<Kernel_>> nef_;
|
||||
#endif
|
||||
public:
|
||||
CgalShape(const cgal_shape_t& shape, bool convex = false);
|
||||
@@ -208,6 +208,13 @@ namespace ifcopenshell { namespace geometry {
|
||||
|
||||
operator const cgal_shape_t& () const { to_poly(); return *shape_; }
|
||||
const cgal_shape_t& poly() const { to_poly(); return *shape_; }
|
||||
virtual std::string_view backend_id() const {
|
||||
#ifdef IFOPSH_SIMPLE_KERNEL
|
||||
return "cgal-simple";
|
||||
#else
|
||||
return "cgal";
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
|
||||
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
|
||||
@@ -284,6 +291,13 @@ namespace ifcopenshell { namespace geometry {
|
||||
shape_.reset(new halfspace_tree_plane<Kernel_>(shape));
|
||||
planes_.push_back(shape);
|
||||
}
|
||||
virtual std::string_view backend_id() const {
|
||||
#ifdef IFOPSH_SIMPLE_KERNEL
|
||||
return "cgal-simple";
|
||||
#else
|
||||
return "cgal";
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
|
||||
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "CgalKernel.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcparse/logger.h"
|
||||
#include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h"
|
||||
|
||||
#ifdef IFOPSH_SIMPLE_KERNEL
|
||||
@@ -47,7 +47,7 @@ namespace {
|
||||
private:
|
||||
std::list<cgal_face_t> *face_list;
|
||||
public:
|
||||
boost::optional<cgal_shape_t> from_soup;
|
||||
std::optional<cgal_shape_t> from_soup;
|
||||
PolyhedronBuilder(std::list<cgal_face_t> *face_list);
|
||||
void operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds);
|
||||
};
|
||||
@@ -76,7 +76,7 @@ CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_polyhedron(std
|
||||
|
||||
polyhedron.normalize_border();
|
||||
if (!polyhedron.is_valid(false, 1)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "create_polyhedron: Polyhedron not valid!");
|
||||
logger::message(logger::LOG_ERROR, "create_polyhedron: Polyhedron not valid!");
|
||||
// std::ofstream fresult;
|
||||
// fresult.open("/Users/ken/Desktop/invalid.off");
|
||||
// fresult << polyhedron << std::endl;
|
||||
@@ -97,11 +97,11 @@ CGAL::Polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_polyhedron(con
|
||||
nef_polyhedron.convert_to_polyhedron(polyhedron);
|
||||
return polyhedron;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!");
|
||||
logger::message(logger::LOG_ERROR, "Conversion from Nef to polyhedron failed!");
|
||||
return CGAL::Polyhedron_3<Kernel_>();
|
||||
}
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!");
|
||||
logger::message(logger::LOG_ERROR, "Nef polyhedron not simple: cannot create polyhedron!");
|
||||
return CGAL::Polyhedron_3<Kernel_>();
|
||||
}
|
||||
}
|
||||
@@ -114,7 +114,7 @@ CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhe
|
||||
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
|
||||
}
|
||||
} catch (CGAL::Failure_exception& e) {
|
||||
Logger::Message(Logger::LOG_ERROR, e);
|
||||
logger::message(logger::LOG_ERROR, e);
|
||||
}
|
||||
}
|
||||
CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron);
|
||||
@@ -122,7 +122,7 @@ CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhe
|
||||
try {
|
||||
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
|
||||
logger::message(logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
|
||||
}
|
||||
return nef_polyhedron;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhe
|
||||
CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron);
|
||||
}
|
||||
} catch (CGAL::Failure_exception& e) {
|
||||
Logger::Message(Logger::LOG_ERROR, e);
|
||||
logger::message(logger::LOG_ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,11 +148,11 @@ CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhe
|
||||
try {
|
||||
nef_polyhedron = CGAL::Nef_polyhedron_3<Kernel_>(polyhedron);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
|
||||
logger::message(logger::LOG_ERROR, "Conversion to Nef polyhedron failed!");
|
||||
}
|
||||
return nef_polyhedron;
|
||||
} else {
|
||||
Logger::Message(Logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!");
|
||||
logger::message(logger::LOG_ERROR, "Polyhedron not valid: cannot create Nef polyhedron!");
|
||||
return CGAL::Nef_polyhedron_3<Kernel_>();
|
||||
}
|
||||
}
|
||||
@@ -161,13 +161,13 @@ CGAL::Nef_polyhedron_3<Kernel_> ifcopenshell::geometry::utils::create_nef_polyhe
|
||||
bool CgalKernel::convert(const taxonomy::shell::ptr l, cgal_shape_t& shape) {
|
||||
for (auto& f : l->children) {
|
||||
if (f->basis && f->basis->kind() != taxonomy::PLANE) {
|
||||
Logger::Error("CGAL Kernel: Non-planar faces not supported at the moment");
|
||||
logger::error("CGAL Kernel: Non-planar faces not supported at the moment");
|
||||
throw not_supported_error();
|
||||
}
|
||||
for (auto& w : f->children) {
|
||||
for (auto& e : w->children) {
|
||||
if (e->basis && e->basis->kind() == taxonomy::BSPLINE_CURVE) {
|
||||
Logger::Error("CGAL Kernel: B-spline edge curves not supported at the moment");
|
||||
logger::error("CGAL Kernel: B-spline edge curves not supported at the moment");
|
||||
throw not_supported_error();
|
||||
}
|
||||
}
|
||||
@@ -196,9 +196,9 @@ bool CgalKernel::convert(const taxonomy::shell::ptr l, cgal_shape_t& shape) {
|
||||
double volume = diag(0) * diag(1) * diag(2);
|
||||
// @todo volume van be zero also..
|
||||
double density = num_points / volume;
|
||||
Logger::Notice("Density " + boost::lexical_cast<std::string>(density), l->instance);
|
||||
logger::notice("Density " + boost::lexical_cast<std::string>(density), l->instance);
|
||||
if (density > 5000) {
|
||||
Logger::Notice("Substituted element with " + boost::lexical_cast<std::string>(density) + " vertices / m3 with a bounding box");
|
||||
logger::notice("Substituted element with " + boost::lexical_cast<std::string>(density) + " vertices / m3 with a bounding box");
|
||||
CGAL::Point_3<Kernel_> lower(minmax.first(0), minmax.first(1), minmax.first(2));
|
||||
CGAL::Point_3<Kernel_> upper(minmax.second(0), minmax.second(1), minmax.second(2));
|
||||
shape = utils::create_cube(lower, upper);
|
||||
@@ -214,7 +214,7 @@ bool CgalKernel::convert(const taxonomy::shell::ptr l, cgal_shape_t& shape) {
|
||||
} catch (...) {}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Failed to convert face:", f->instance);
|
||||
logger::message(logger::LOG_WARNING, "Failed to convert face:", f->instance);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -232,11 +232,11 @@ bool CgalKernel::convert(const taxonomy::face::ptr face, std::list<cgal_face_t>&
|
||||
int num_outer_bounds = 0;
|
||||
|
||||
for (auto& bound : face->children) {
|
||||
if (bound->external.get_value_or(false)) num_outer_bounds++;
|
||||
if (bound->external.value_or(false)) num_outer_bounds++;
|
||||
}
|
||||
|
||||
if (face->children.size() > 1 && num_outer_bounds > 1 && face->children.size() != num_outer_bounds) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance);
|
||||
logger::message(logger::LOG_ERROR, "Invalid configuration of boundaries for:", face->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -244,12 +244,12 @@ bool CgalKernel::convert(const taxonomy::face::ptr face, std::list<cgal_face_t>&
|
||||
|
||||
for (auto& bound : face->children) {
|
||||
|
||||
const bool is_interior = !(bound->external.get_value_or(false) || face->children.size() == 1);
|
||||
const bool is_interior = !(bound->external.value_or(false) || face->children.size() == 1);
|
||||
// single face bound is always external... even if not marked as such
|
||||
|
||||
cgal_wire_t wire;
|
||||
if (!convert(bound, wire)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance);
|
||||
logger::message(logger::LOG_ERROR, "Failed to process face boundary loop", bound->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -284,11 +284,11 @@ namespace {
|
||||
if (auto e = taxonomy::dcast<taxonomy::edge>(curve)) {
|
||||
if (true || e->basis == nullptr) {
|
||||
if (builder.empty()) {
|
||||
const auto& p = boost::get<taxonomy::point3::ptr>(e->start);
|
||||
const auto& p = std::get<taxonomy::point3::ptr>(e->start);
|
||||
cgal_point_t pnt(p->ccomponents()(0), p->ccomponents()(1), p->ccomponents()(2));
|
||||
builder.push_back(pnt);
|
||||
}
|
||||
const auto& p = boost::get<taxonomy::point3::ptr>(e->end);
|
||||
const auto& p = std::get<taxonomy::point3::ptr>(e->end);
|
||||
cgal_point_t pnt(p->ccomponents()(0), p->ccomponents()(1), p->ccomponents()(2));
|
||||
builder.push_back(pnt);
|
||||
} else if (e->basis->kind() == taxonomy::CIRCLE) {
|
||||
@@ -450,17 +450,17 @@ namespace {
|
||||
void operator()(const taxonomy::trimmed_curve::ptr& e) {
|
||||
auto e_basis = e->basis;
|
||||
|
||||
while (e_basis->kind() == taxonomy::EDGE && e_basis->instance && e_basis->instance->declaration().name() == "IfcTrimmedCurve") {
|
||||
while (e_basis->kind() == taxonomy::EDGE && e_basis->instance && e_basis->instance.declaration().name() == "IfcTrimmedCurve") {
|
||||
// @todo we still might have something to wrt orientation on periodic curves
|
||||
// to make sure we select the correct arc later on.
|
||||
e_basis = taxonomy::cast<taxonomy::edge>(e_basis)->basis;
|
||||
}
|
||||
|
||||
point_projection_visitor v1{ e->basis }, v2{ e->basis };
|
||||
boost::apply_visitor(v1, e->start);
|
||||
boost::apply_visitor(v2, e->end);
|
||||
std::visit(v1, e->start);
|
||||
std::visit(v2, e->end);
|
||||
|
||||
if (!e->curve_sense.get_value_or(true)) {
|
||||
if (!e->curve_sense.value_or(true)) {
|
||||
std::swap(v1.u, v2.u);
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace {
|
||||
dispatch_curve_creation<cgal_curve_creation_visitor>::dispatch(e->basis, v);
|
||||
this->points = v.points;
|
||||
|
||||
if (!e->curve_sense.get_value_or(true)) {
|
||||
if (!e->curve_sense.value_or(true)) {
|
||||
std::reverse(this->points.begin(), this->points.end());
|
||||
}
|
||||
}
|
||||
@@ -581,7 +581,7 @@ namespace {
|
||||
CGAL::Polygon_2<Kernel_> loop_to_polygon_2(taxonomy::loop::ptr loop) {
|
||||
CGAL::Polygon_2<Kernel_> polygon;
|
||||
for (auto& e : loop->children) {
|
||||
auto& p = *boost::get<taxonomy::point3::ptr>(e->start);
|
||||
auto& p = *std::get<taxonomy::point3::ptr>(e->start);
|
||||
CGAL::Point_2<Kernel_> pnt(p.ccomponents()(0), p.ccomponents()(1));
|
||||
polygon.push_back(pnt);
|
||||
}
|
||||
@@ -685,12 +685,12 @@ bool CgalKernel::convert(const taxonomy::loop::ptr loop, cgal_wire_t& result) {
|
||||
convert_curve(settings_, e, edge);
|
||||
} else {
|
||||
edge = {
|
||||
*boost::get<taxonomy::point3::ptr>(e->start),
|
||||
*boost::get<taxonomy::point3::ptr>(e->end)
|
||||
*std::get<taxonomy::point3::ptr>(e->start),
|
||||
*std::get<taxonomy::point3::ptr>(e->end)
|
||||
};
|
||||
}
|
||||
|
||||
if (!e->orientation.get_value_or(true)) {
|
||||
if (!e->orientation.value_or(true)) {
|
||||
std::reverse(edge.begin(), edge.end());
|
||||
}
|
||||
|
||||
@@ -703,7 +703,7 @@ bool CgalKernel::convert(const taxonomy::loop::ptr loop, cgal_wire_t& result) {
|
||||
if (d < 1.e-5) {
|
||||
points.erase(points.end() - 1);
|
||||
} else {
|
||||
Logger::Warning("Loop not closed", loop->instance);
|
||||
logger::warning("Loop not closed", loop->instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,7 +717,7 @@ bool CgalKernel::convert(const taxonomy::loop::ptr loop, cgal_wire_t& result) {
|
||||
// A loop should consist of at least three vertices
|
||||
std::size_t original_count = polygon.size();
|
||||
if (original_count < 3) {
|
||||
Logger::Warning("Not enough edges for:", loop->instance);
|
||||
logger::warning("Not enough edges for:", loop->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -728,14 +728,14 @@ bool CgalKernel::convert(const taxonomy::loop::ptr loop, cgal_wire_t& result) {
|
||||
std::size_t count = polygon.size();
|
||||
if (original_count - count != 0) {
|
||||
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
|
||||
Logger::Warning(ss.str(), loop->instance);
|
||||
logger::warning(ss.str(), loop->instance);
|
||||
}
|
||||
|
||||
{
|
||||
std::set<cgal_point_t> visited_points;
|
||||
for (auto& p : polygon) {
|
||||
if (visited_points.find(p) != visited_points.end()) {
|
||||
Logger::Error("Skipping self-intersecting loop", loop->instance);
|
||||
logger::error("Skipping self-intersecting loop", loop->instance);
|
||||
// @todo signal somehow that occt kernel might be able to solve this
|
||||
// @todo implement cycle detection using Arrangement_2, but that only works in exact kernel
|
||||
return false;
|
||||
@@ -757,7 +757,7 @@ bool CgalKernel::convert(const taxonomy::loop::ptr loop, cgal_wire_t& result) {
|
||||
}
|
||||
|
||||
if (do_segments_intersect(segments)) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Skipping self-intersecting loop", loop->instance);
|
||||
logger::message(logger::LOG_WARNING, "Skipping self-intersecting loop", loop->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -785,7 +785,7 @@ bool CgalKernel::convert(const taxonomy::loop::ptr loop, cgal_wire_t& result) {
|
||||
*/
|
||||
|
||||
if (count < 3) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", loop->instance);
|
||||
logger::message(logger::LOG_ERROR, "Not enough edges for:", loop->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -809,7 +809,7 @@ bool CgalKernel::convert_impl(const taxonomy::shell::ptr shell, ConversionResult
|
||||
return false;
|
||||
}
|
||||
results.emplace_back(ConversionResult(
|
||||
shell->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
shell->instance.id(),
|
||||
shell->matrix,
|
||||
new CgalShape(shape),
|
||||
shell->surface_style
|
||||
@@ -819,7 +819,7 @@ bool CgalKernel::convert_impl(const taxonomy::shell::ptr shell, ConversionResult
|
||||
|
||||
bool CgalKernel::convert_impl(const taxonomy::solid::ptr solid, ConversionResults& results) {
|
||||
if (solid->children.size() > 1) {
|
||||
Logger::Error("Multiple shells in solid not supported at the moment");
|
||||
logger::error("Multiple shells in solid not supported at the moment");
|
||||
return false;
|
||||
}
|
||||
cgal_shape_t shape;
|
||||
@@ -834,7 +834,7 @@ bool CgalKernel::convert_impl(const taxonomy::solid::ptr solid, ConversionResult
|
||||
return false;
|
||||
}
|
||||
results.emplace_back(ConversionResult(
|
||||
solid->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
solid->instance.id(),
|
||||
solid->matrix,
|
||||
new CgalShape(shape),
|
||||
solid->surface_style
|
||||
@@ -857,7 +857,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
bool ifcopenshell::geometry::kernels::CgalKernel::convert_openings(const IfcUtil::IfcBaseEntity * entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings, const IfcGeom::ConversionResults & entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4 & entity_trsf, IfcGeom::ConversionResults & cut_shapes)
|
||||
bool ifcopenshell::geometry::kernels::CgalKernel::convert_openings(const express::Base& entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings, const IfcGeom::ConversionResults & entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4 & entity_trsf, IfcGeom::ConversionResults & cut_shapes)
|
||||
{
|
||||
#ifdef IFOPSH_SIMPLE_KERNEL
|
||||
return false;
|
||||
@@ -865,9 +865,9 @@ bool ifcopenshell::geometry::kernels::CgalKernel::convert_openings(const IfcUtil
|
||||
CGAL::Nef_nary_union_3<CGAL::Nef_polyhedron_3<Kernel_>> second_operand_collector;
|
||||
size_t second_operand_collector_size = 0;
|
||||
|
||||
std::list<std::pair<const IfcUtil::IfcBaseClass*, std::list<cgal_shape_t>>> operands;
|
||||
std::list<std::pair<express::Base, std::list<cgal_shape_t>>> operands;
|
||||
|
||||
std::list<const IfcUtil::IfcBaseClass*> second_operand_instances;
|
||||
std::list<express::Base> second_operand_instances;
|
||||
std::list<cgal_shape_t> first_operands, second_operands;
|
||||
std::list<CGAL::Nef_polyhedron_3<Kernel_>> first_operands_nef, second_operands_nef;
|
||||
|
||||
@@ -916,13 +916,13 @@ bool ifcopenshell::geometry::kernels::CgalKernel::convert_openings(const IfcUtil
|
||||
}
|
||||
}
|
||||
CGAL::Nef_polyhedron_3<Kernel_> nef;
|
||||
if (!preprocess_boolean_operand(op.first->instance->as<IfcUtil::IfcBaseClass>(), {}, {}, {}, entity_shape, nef, PP_NONE)) {
|
||||
if (!preprocess_boolean_operand(op.first->instance, {}, {}, {}, entity_shape, nef, PP_NONE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// auto tree = build_halfspace_tree_decomposed(nef, all_operand_planes);
|
||||
|
||||
second_operand_instances.push_back(op.first->instance->as<IfcUtil::IfcBaseClass>());
|
||||
second_operand_instances.push_back(op.first->instance);
|
||||
second_operands.push_back(entity_shape);
|
||||
second_operands_nef.push_back(nef);
|
||||
}
|
||||
@@ -964,7 +964,7 @@ bool ifcopenshell::geometry::kernels::CgalKernel::convert_openings(const IfcUtil
|
||||
try {
|
||||
a.convert_to_polyhedron(a_poly);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not convert from Nef:", entity);
|
||||
logger::message(logger::LOG_ERROR, "Could not convert from Nef:", entity);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -984,7 +984,7 @@ bool CgalKernel::convert_impl(const taxonomy::extrusion::ptr extrusion, Conversi
|
||||
return false;
|
||||
}
|
||||
results.emplace_back(ConversionResult(
|
||||
extrusion->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
extrusion->instance.id(),
|
||||
extrusion->matrix,
|
||||
new CgalShape(shape),
|
||||
extrusion->surface_style
|
||||
@@ -1163,7 +1163,7 @@ bool CgalKernel::process_extrusion(const cgal_face_t& bottom_face, taxonomy::dir
|
||||
try {
|
||||
nef_shape -= utils::create_nef_polyhedron(face_list);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:");
|
||||
logger::message(logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1180,7 +1180,7 @@ bool CgalKernel::process_extrusion(const cgal_face_t& bottom_face, taxonomy::dir
|
||||
nef_shape.convert_to_polyhedron(shape);
|
||||
return true;
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:");
|
||||
logger::message(logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
@@ -1189,7 +1189,7 @@ bool CgalKernel::process_extrusion(const cgal_face_t& bottom_face, taxonomy::dir
|
||||
bool CgalKernel::convert(const taxonomy::extrusion::ptr extrusion, cgal_shape_t &shape) {
|
||||
const double& height = extrusion->depth;
|
||||
if (height < settings_.get<settings::Precision>().get()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", extrusion->instance);
|
||||
logger::message(logger::LOG_ERROR, "Non-positive extrusion height encountered for:", extrusion->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1321,17 +1321,17 @@ bool CgalKernel::thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const std::list<cgal_shape_t>& first_operands, const std::list<CGAL::Nef_polyhedron_3<Kernel_>>& first_operands_nef, const std::list<Kernel_::Plane_3>& all_operand_planes, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, boolean_operand_preprocess proc) {
|
||||
bool CgalKernel::preprocess_boolean_operand(const express::Base& log_reference, const std::list<cgal_shape_t>& first_operands, const std::list<CGAL::Nef_polyhedron_3<Kernel_>>& first_operands_nef, const std::list<Kernel_::Plane_3>& all_operand_planes, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, boolean_operand_preprocess proc) {
|
||||
cgal_shape_t shape = shape_const;
|
||||
|
||||
if (!shape.is_valid()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Invalid geometry:", log_reference);
|
||||
logger::message(logger::LOG_ERROR, "Conversion to Nef will fail. Invalid geometry:", log_reference);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!shape.is_closed()) {
|
||||
// TODO: There can be substractions to remove parts of non-volumetric objects. Maybe iterate over all faces of an entity and put them in a Nef_polyhedron_3 through Boolean union? Highly inefficient but maybe desirable...
|
||||
Logger::Message(Logger::LOG_ERROR, "Subtraction of openings not supported for non-closed geometry:", log_reference);
|
||||
logger::message(logger::LOG_ERROR, "Subtraction of openings not supported for non-closed geometry:", log_reference);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1340,18 +1340,18 @@ bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_ref
|
||||
try {
|
||||
success = CGAL::Polygon_mesh_processing::triangulate_faces(shape);
|
||||
} catch (CGAL::Failure_exception& e) {
|
||||
Logger::Notice(e);
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry crashed:", log_reference);
|
||||
logger::notice(e);
|
||||
logger::message(logger::LOG_ERROR, "Triangulation of geometry crashed:", log_reference);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation of geometry failed:", log_reference);
|
||||
logger::message(logger::LOG_ERROR, "Triangulation of geometry failed:", log_reference);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CGAL::Polygon_mesh_processing::does_self_intersect(shape)) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", log_reference);
|
||||
logger::message(logger::LOG_ERROR, "Conversion to Nef will fail. Self-intersecting geometry:", log_reference);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1423,8 +1423,8 @@ bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_ref
|
||||
try {
|
||||
result = CGAL::Nef_polyhedron_3<Kernel_>(shape);
|
||||
} catch (CGAL::Failure_exception& e) {
|
||||
Logger::Notice(e);
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry to Nef:", log_reference);
|
||||
logger::notice(e);
|
||||
logger::message(logger::LOG_ERROR, "Could not convert geometry to Nef:", log_reference);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1496,8 +1496,8 @@ bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_ref
|
||||
// @todo don't dilate in 3 dimensions but only in the XY plane, orthogonal to wall axis.
|
||||
result = CGAL::minkowski_sum_3(result, precision_cube_);
|
||||
} catch (CGAL::Failure_exception& e) {
|
||||
Logger::Notice(e);
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not dilate boolean operand", log_reference);
|
||||
logger::notice(e);
|
||||
logger::message(logger::LOG_ERROR, "Could not dilate boolean operand", log_reference);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1522,8 +1522,8 @@ bool CgalKernel::preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_ref
|
||||
cgal_shape_t convert_back;
|
||||
result.convert_to_polyhedron(convert_back);
|
||||
} catch (CGAL::Failure_exception& e) {
|
||||
Logger::Notice(e);
|
||||
Logger::Message(Logger::LOG_WARNING, "Final conversion will likely fail. Could not convert geometry from Nef:", log_reference);
|
||||
logger::notice(e);
|
||||
logger::message(logger::LOG_WARNING, "Final conversion will likely fail. Could not convert geometry from Nef:", log_reference);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1727,7 +1727,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
bool CgalKernel::process_as_2d_polygon(const std::list<std::list<std::pair<const IfcUtil::IfcBaseClass*, cgal_shape_t>>>& operands, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1) {
|
||||
bool CgalKernel::process_as_2d_polygon(const std::list<std::list<std::pair<express::Base, cgal_shape_t>>>& operands, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1) {
|
||||
if (operands.front().size() != 1) {
|
||||
return false;
|
||||
}
|
||||
@@ -1845,7 +1845,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
// even-odd fill rule will result in incorrect results.
|
||||
// See for example the Duplex model roof.
|
||||
|
||||
Logger::Notice("Holes are not disjoint");
|
||||
logger::notice("Holes are not disjoint");
|
||||
|
||||
CGAL::Polygon_set_2<Kernel_> result;
|
||||
auto it = loops.begin();
|
||||
@@ -1891,14 +1891,14 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
}
|
||||
|
||||
return ConversionResult(
|
||||
br->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
br->instance.id(),
|
||||
br->matrix,
|
||||
new CgalShape(shp),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
);
|
||||
});
|
||||
|
||||
Logger::Notice("Processed boolean operation as 2d arrangement");
|
||||
logger::notice("Processed boolean operation as 2d arrangement");
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1916,7 +1916,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
|
||||
taxonomy::style::ptr first_item_style = nullptr;
|
||||
|
||||
std::list<std::pair<const IfcUtil::IfcBaseClass*, std::list<cgal_shape_t>>> operands;
|
||||
std::list<std::pair<express::Base, std::list<cgal_shape_t>>> operands;
|
||||
|
||||
for (auto& c : br->children) {
|
||||
// AbstractKernel::convert(c, results);
|
||||
@@ -1925,9 +1925,9 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
ConversionResults cr;
|
||||
|
||||
operands.emplace_back();
|
||||
operands.back().first = c->instance->as<IfcUtil::IfcBaseClass>();
|
||||
operands.back().first = c->instance;
|
||||
|
||||
if (c->kind() == taxonomy::SOLID && c->instance->declaration().is("IfcHalfSpaceSolid") && !first) {
|
||||
if (c->kind() == taxonomy::SOLID && c->instance.declaration().is("IfcHalfSpaceSolid") && !first) {
|
||||
auto face = taxonomy::cast<taxonomy::solid>(c)->children[0]->children[0];
|
||||
|
||||
if (face->basis == nullptr || face->basis->kind() != taxonomy::PLANE) {
|
||||
@@ -1955,7 +1955,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
});
|
||||
|
||||
double wmin, wmax;
|
||||
if (face->orientation.get_value_or(false)) {
|
||||
if (face->orientation.value_or(false)) {
|
||||
wmin = 0.;
|
||||
wmax = uvw_max[2] + eps;
|
||||
} else {
|
||||
@@ -1984,7 +1984,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
ps.push_back({ p.x(), p.y() });
|
||||
}
|
||||
if (!ps.is_simple()) {
|
||||
Logger::Warning("Polygonal boundary not simple", face->children[0]->instance);
|
||||
logger::warning("Polygonal boundary not simple", face->children[0]->instance);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2047,7 +2047,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
for (auto& li : operands) {
|
||||
for (auto& s : li.second) {
|
||||
results.emplace_back(ConversionResult(
|
||||
br->instance->data().id(),
|
||||
br->instance.data().id(),
|
||||
br->matrix,
|
||||
new CgalShape(s),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
@@ -2069,7 +2069,7 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
for (auto& p : operands) {
|
||||
for (auto& s : p.second) {
|
||||
results.emplace_back(ConversionResult(
|
||||
br->instance->data().id(),
|
||||
br->instance.data().id(),
|
||||
br->matrix,
|
||||
new CgalShape(s),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
@@ -2130,12 +2130,12 @@ bool CgalKernel::convert_impl(const taxonomy::boolean_result::ptr br, Conversion
|
||||
try {
|
||||
a.convert_to_polyhedron(a_poly);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", br->instance);
|
||||
logger::message(logger::LOG_ERROR, "Could not convert geometry with openings from Nef:", br->instance);
|
||||
return false;
|
||||
}
|
||||
|
||||
results.emplace_back(ConversionResult(
|
||||
br->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
br->instance.id(),
|
||||
br->matrix,
|
||||
new CgalShape(a_poly),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
@@ -2222,7 +2222,7 @@ void PolyhedronBuilder::operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds)
|
||||
// For now let's just skip over the triangle. We can also use
|
||||
// the Aff_transformation_3 stored in place to convert the 2d
|
||||
// coords back to 3d.
|
||||
Logger::Warning("Ignoring triangulated facet with novel point likely due to self-intersections");
|
||||
logger::warning("Ignoring triangulated facet with novel point likely due to self-intersections");
|
||||
facet_vertices.erase(facet_vertices.end() - 1);
|
||||
break;
|
||||
}
|
||||
@@ -2262,7 +2262,7 @@ void PolyhedronBuilder::operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds)
|
||||
|
||||
if (!CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(facet_vertices)) {
|
||||
// @todo seems to return false now, almost always?
|
||||
// Logger::Warning("Reoriented polygonal surface");
|
||||
// logger::warning("Reoriented polygonal surface");
|
||||
CGAL::Polygon_mesh_processing::orient_polygon_soup(unique_points_as_vector, facet_vertices);
|
||||
}
|
||||
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(unique_points_as_vector, facet_vertices, *from_soup);
|
||||
@@ -2282,12 +2282,12 @@ void PolyhedronBuilder::operator()(CGAL::Polyhedron_3<Kernel_>::HalfedgeDS &hds)
|
||||
if (added_edges.find(p) != added_edges.end()) {
|
||||
if (reoriented) {
|
||||
facet_indices_to_delete.push_back(fi);
|
||||
Logger::Notice("Removed facet");
|
||||
logger::notice("Removed facet");
|
||||
valid = false;
|
||||
break;
|
||||
} else {
|
||||
std::reverse(f.begin(), f.end());
|
||||
Logger::Notice("Reversed facet");
|
||||
logger::notice("Reversed facet");
|
||||
reoriented = true;
|
||||
goto check_edge_existence;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -80,7 +80,7 @@ namespace ifcopenshell {
|
||||
PP_NONE
|
||||
};
|
||||
|
||||
bool preprocess_boolean_operand(const IfcUtil::IfcBaseClass* log_reference, const std::list<cgal_shape_t>& first_operands, const std::list<CGAL::Nef_polyhedron_3<Kernel_>>& first_operands_nef, const std::list<Kernel_::Plane_3>& all_operand_planes, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, boolean_operand_preprocess proc);
|
||||
bool preprocess_boolean_operand(const express::Base& log_reference, const std::list<cgal_shape_t>& first_operands, const std::list<CGAL::Nef_polyhedron_3<Kernel_>>& first_operands_nef, const std::list<Kernel_::Plane_3>& all_operand_planes, const cgal_shape_t& shape_const, CGAL::Nef_polyhedron_3<Kernel_>& result, boolean_operand_preprocess proc);
|
||||
|
||||
bool thin_solid(const CGAL::Nef_polyhedron_3<Kernel_>& a, CGAL::Nef_polyhedron_3<Kernel_>& result);
|
||||
|
||||
@@ -115,14 +115,14 @@ namespace ifcopenshell {
|
||||
|
||||
bool process_extrusion(const cgal_face_t& bottom_face, taxonomy::direction3::ptr direction, double height, cgal_shape_t& shape);
|
||||
bool process_as_2d_polygon(const taxonomy::boolean_result::ptr br, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1);
|
||||
bool process_as_2d_polygon(const std::list<std::list<std::pair<const IfcUtil::IfcBaseClass*, cgal_shape_t>>>& operands, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1);
|
||||
bool process_as_2d_polygon(const std::list<std::list<std::pair<express::Base, cgal_shape_t>>>& operands, std::list<CGAL::Polygon_2<Kernel_>>& loops, double& z0, double& z1);
|
||||
|
||||
virtual bool convert_impl(const taxonomy::shell::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::extrusion::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::boolean_result::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::solid::ptr, IfcGeom::ConversionResults&);
|
||||
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
virtual bool convert_openings(const express::Base& entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes);
|
||||
|
||||
#ifndef IFOPSH_SIMPLE_KERNEL
|
||||
|
||||
@@ -621,7 +621,7 @@ struct Intersection_visitor {
|
||||
template <typename Kernel>
|
||||
struct Segment_collector {
|
||||
typedef void result_type;
|
||||
boost::optional<CGAL::Segment_3<Kernel>> segment;
|
||||
std::optional<CGAL::Segment_3<Kernel>> segment;
|
||||
|
||||
void operator()(const CGAL::Point_3<Kernel>&)
|
||||
{
|
||||
@@ -648,7 +648,7 @@ public:
|
||||
|
||||
template <typename Edge, typename Graph>
|
||||
bool tree_edge(Edge e, const Graph& g) {
|
||||
if (boost::get(boost::edge_weight, g, e) == edgetype_) {
|
||||
if (std::get(boost::edge_weight, g, e) == edgetype_) {
|
||||
auto srcid = boost::source(e, g);
|
||||
auto tgtid = boost::target(e, g);
|
||||
|
||||
@@ -667,7 +667,7 @@ public:
|
||||
|
||||
typename boost::graph_traits<Graph>::out_edge_iterator ei, ei_end;
|
||||
for (boost::tie(ei, ei_end) = boost::out_edges(tgtid, g); ei != ei_end; ++ei) {
|
||||
if (boost::get(boost::edge_weight, g, *ei) != edgetype_) {
|
||||
if (std::get(boost::edge_weight, g, *ei) != edgetype_) {
|
||||
tgt_has_any_reflex_edge = true;
|
||||
// std::cout << " reflex: " << boost::source(*ei, g) << " -- " << boost::target(*ei, g) << std::endl;
|
||||
break;
|
||||
@@ -712,9 +712,9 @@ public:
|
||||
if (x) {
|
||||
// std::cout << " triangle: " << t << std::endl;
|
||||
// Intersection_visitor v;
|
||||
// boost::apply_visitor([](auto x) {std::cout << " intersects: " << x << std::endl; })(*x);
|
||||
// std::visit([](auto x) {std::cout << " intersects: " << x << std::endl; })(*x);
|
||||
Segment_collector<Kernel> sc;
|
||||
boost::apply_visitor(sc)(*x);
|
||||
std::visit(sc)(*x);
|
||||
if (sc.segment) {
|
||||
if (!std::any_of(edges_i.begin(), edges_i.end(), [&sc](CGAL::Segment_3<Kernel>& s) {
|
||||
// When intersecting with the boundary of a facet we likely multiple co-planar facets. Exclude intersection.
|
||||
@@ -723,7 +723,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
Segment_collector<Kernel> scy;
|
||||
boost::apply_visitor(scy)(*xy);
|
||||
std::visit(scy)(*xy);
|
||||
return (bool)scy.segment;
|
||||
})) {
|
||||
return true;
|
||||
@@ -807,7 +807,7 @@ std::unique_ptr<halfspace_tree<TreeKernel>> build_halfspace_tree(Graph<Kernel>&
|
||||
bool all_convex = true;
|
||||
typename boost::graph_traits<Graph<Kernel>>::edge_iterator ei, ei_end;
|
||||
for (boost::tie(ei, ei_end) = boost::edges(G); ei != ei_end; ++ei) {
|
||||
if (boost::get(boost::edge_weight, G, *ei) != edge_trait) {
|
||||
if (std::get(boost::edge_weight, G, *ei) != edge_trait) {
|
||||
// all_convex = false;
|
||||
break;
|
||||
}
|
||||
@@ -1030,7 +1030,7 @@ public:
|
||||
auto verts_backup = verts;
|
||||
auto facets_backup = facets;
|
||||
|
||||
boost::optional<CGAL::Polygon_with_holes_2<Kernel>> pwh;
|
||||
std::optional<CGAL::Polygon_with_holes_2<Kernel>> pwh;
|
||||
auto nf = std::distance(h->facet_cycles_begin(), h->facet_cycles_end());
|
||||
for (auto fc = h->facet_cycles_begin(); fc != h->facet_cycles_end(); ++fc) {
|
||||
// std::cout << "h_plane.point() " << h_plane.point() << std::endl;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../kernel_plugin.h"
|
||||
#include "CgalKernel.h"
|
||||
|
||||
#include <boost/dll/alias.hpp>
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
namespace kernels {
|
||||
namespace cgal_plugin {
|
||||
|
||||
#ifdef IFOPSH_SIMPLE_KERNEL
|
||||
constexpr const char* plugin_name = "cgalsimple";
|
||||
constexpr const char* backend_id = "cgal-simple";
|
||||
constexpr bool supports_boolean_operations = false;
|
||||
using kernel_type = SimpleCgalKernel;
|
||||
#else
|
||||
constexpr const char* plugin_name = "cgal";
|
||||
constexpr const char* backend_id = "cgal";
|
||||
constexpr bool supports_boolean_operations = true;
|
||||
using kernel_type = CgalKernel;
|
||||
#endif
|
||||
|
||||
plugin::abi_info plugin_abi() {
|
||||
return plugin::host_abi();
|
||||
}
|
||||
|
||||
plugin::metadata plugin_metadata() {
|
||||
return kernel_plugin_metadata(plugin_name);
|
||||
}
|
||||
|
||||
AbstractKernel* create_kernel(ifcopenshell::file*, Settings& settings) {
|
||||
return new kernel_type(settings);
|
||||
}
|
||||
|
||||
void register_plugin(kernel_registry& registry, const plugin::module& module) {
|
||||
kernel_info info;
|
||||
info.backend_id = backend_id;
|
||||
info.supports_boolean_operations = supports_boolean_operations;
|
||||
registry.bind(info, create_kernel, module);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::cgal_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::cgal_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::cgal_plugin::register_plugin, ifcopenshell_register_kernel_plugin_v1)
|
||||
@@ -20,9 +20,10 @@
|
||||
#ifndef IFC_GEOMLIBRARY_API_H
|
||||
#define IFC_GEOMLIBRARY_API_H
|
||||
|
||||
#ifdef IFC_SHARED_BUILD
|
||||
#ifdef _WIN32
|
||||
#ifdef IFC_GEOM_EXPORTS
|
||||
#ifdef SWIG
|
||||
#define IFC_GEOMLIBRARY_API
|
||||
#elif defined(_WIN32)
|
||||
#ifdef IFC_GEOMLIBRARY_EXPORTS
|
||||
#define IFC_GEOMLIBRARY_API __declspec(dllexport)
|
||||
#else
|
||||
#define IFC_GEOMLIBRARY_API __declspec(dllimport)
|
||||
@@ -30,8 +31,5 @@
|
||||
#else // simply assume *nix + GCC-like compiler
|
||||
#define IFC_GEOMLIBRARY_API __attribute__((visibility("default")))
|
||||
#endif
|
||||
#else
|
||||
#define IFC_GEOMLIBRARY_API
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,534 @@
|
||||
#include "ManifoldConversionResult.h"
|
||||
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
using IfcGeom::ConversionResultShape;
|
||||
using IfcGeom::NumberNativeDouble;
|
||||
using IfcGeom::OpaqueCoordinate;
|
||||
using IfcGeom::OpaqueNumber;
|
||||
|
||||
namespace {
|
||||
using Mesh = manifold::MeshGL64;
|
||||
|
||||
Mesh transform_mesh(const Mesh& mesh, const ifcopenshell::geometry::taxonomy::matrix4& place) {
|
||||
Mesh result = mesh;
|
||||
const auto& m = place.ccomponents();
|
||||
const bool flip = m.block<3, 3>(0, 0).determinant() < 0.;
|
||||
for (size_t i = 0; i < mesh.NumVert(); ++i) {
|
||||
Eigen::Vector4d v(
|
||||
mesh.vertProperties[i * mesh.numProp + 0],
|
||||
mesh.vertProperties[i * mesh.numProp + 1],
|
||||
mesh.vertProperties[i * mesh.numProp + 2],
|
||||
1.);
|
||||
auto v2 = m * v;
|
||||
result.vertProperties[i * result.numProp + 0] = v2(0);
|
||||
result.vertProperties[i * result.numProp + 1] = v2(1);
|
||||
result.vertProperties[i * result.numProp + 2] = v2(2);
|
||||
}
|
||||
if (flip) {
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
std::swap(result.triVerts[i * 3 + 1], result.triVerts[i * 3 + 2]);
|
||||
}
|
||||
}
|
||||
result.runTransform.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<manifold::Manifold> make_manifold(const Mesh& mesh) {
|
||||
manifold::Manifold solid(mesh);
|
||||
if (solid.Status() == manifold::Manifold::Error::NoError) {
|
||||
return solid;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
manifold::Box mesh_bbox(const Mesh& mesh) {
|
||||
if (!mesh.NumVert()) {
|
||||
return {};
|
||||
}
|
||||
manifold::Box box(
|
||||
manifold::vec3(
|
||||
mesh.vertProperties[0],
|
||||
mesh.vertProperties[1],
|
||||
mesh.vertProperties[2]),
|
||||
manifold::vec3(
|
||||
mesh.vertProperties[0],
|
||||
mesh.vertProperties[1],
|
||||
mesh.vertProperties[2]));
|
||||
for (size_t i = 1; i < mesh.NumVert(); ++i) {
|
||||
box.Union(manifold::vec3(
|
||||
mesh.vertProperties[i * mesh.numProp + 0],
|
||||
mesh.vertProperties[i * mesh.numProp + 1],
|
||||
mesh.vertProperties[i * mesh.numProp + 2]));
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
double bbox_volume(const manifold::Box& box) {
|
||||
if (!box.IsFinite()) {
|
||||
return 0.;
|
||||
}
|
||||
const auto size = box.Size();
|
||||
return size[0] * size[1] * size[2];
|
||||
}
|
||||
|
||||
double triangle_area(const Mesh& mesh, size_t tri) {
|
||||
auto idx = [&](int corner) { return mesh.triVerts[tri * 3 + corner]; };
|
||||
auto point = [&](uint32_t i) {
|
||||
return Eigen::Vector3d(
|
||||
mesh.vertProperties[i * mesh.numProp + 0],
|
||||
mesh.vertProperties[i * mesh.numProp + 1],
|
||||
mesh.vertProperties[i * mesh.numProp + 2]);
|
||||
};
|
||||
const auto a = point(idx(0));
|
||||
const auto b = point(idx(1));
|
||||
const auto c = point(idx(2));
|
||||
return 0.5 * ((b - a).cross(c - a)).norm();
|
||||
}
|
||||
|
||||
double mesh_area(const Mesh& mesh) {
|
||||
double area = 0.;
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
area += triangle_area(mesh, i);
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
double mesh_volume(const Mesh& mesh) {
|
||||
double volume = 0.;
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
auto idx = [&](int corner) { return mesh.triVerts[i * 3 + corner]; };
|
||||
auto point = [&](uint32_t v) {
|
||||
return Eigen::Vector3d(
|
||||
mesh.vertProperties[v * mesh.numProp + 0],
|
||||
mesh.vertProperties[v * mesh.numProp + 1],
|
||||
mesh.vertProperties[v * mesh.numProp + 2]);
|
||||
};
|
||||
const auto a = point(idx(0));
|
||||
const auto b = point(idx(1));
|
||||
const auto c = point(idx(2));
|
||||
volume += a.dot(b.cross(c)) / 6.;
|
||||
}
|
||||
return std::abs(volume);
|
||||
}
|
||||
|
||||
struct EdgeHash {
|
||||
size_t operator()(const std::pair<uint32_t, uint32_t>& edge) const {
|
||||
return std::hash<uint64_t>()((uint64_t(edge.first) << 32) ^ uint64_t(edge.second));
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<std::pair<uint32_t, uint32_t>, int, EdgeHash> count_edges(const Mesh& mesh) {
|
||||
std::unordered_map<std::pair<uint32_t, uint32_t>, int, EdgeHash> edges;
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
uint32_t tri[3] = {
|
||||
mesh.triVerts[i * 3 + 0],
|
||||
mesh.triVerts[i * 3 + 1],
|
||||
mesh.triVerts[i * 3 + 2]
|
||||
};
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
auto a = tri[j];
|
||||
auto b = tri[(j + 1) % 3];
|
||||
if (a > b) {
|
||||
std::swap(a, b);
|
||||
}
|
||||
edges[{a, b}]++;
|
||||
}
|
||||
}
|
||||
return edges;
|
||||
}
|
||||
|
||||
double mesh_length(const Mesh& mesh) {
|
||||
double length = 0.;
|
||||
auto edges = count_edges(mesh);
|
||||
for (const auto& pair : edges) {
|
||||
const auto a = pair.first.first;
|
||||
const auto b = pair.first.second;
|
||||
Eigen::Vector3d p(
|
||||
mesh.vertProperties[a * mesh.numProp + 0],
|
||||
mesh.vertProperties[a * mesh.numProp + 1],
|
||||
mesh.vertProperties[a * mesh.numProp + 2]);
|
||||
Eigen::Vector3d q(
|
||||
mesh.vertProperties[b * mesh.numProp + 0],
|
||||
mesh.vertProperties[b * mesh.numProp + 1],
|
||||
mesh.vertProperties[b * mesh.numProp + 2]);
|
||||
length += (q - p).norm();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int mesh_edges(const Mesh& mesh) {
|
||||
return (int)count_edges(mesh).size();
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::ManifoldPart make_part(const manifold::Manifold& solid) {
|
||||
return { solid.GetMeshGL64(), solid };
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::ManifoldPart make_box_part(const manifold::Box& box) {
|
||||
const auto size = box.Size();
|
||||
auto solid = manifold::Manifold::Cube(manifold::vec3(size[0], size[1], size[2]), false).Translate(box.min);
|
||||
return make_part(solid);
|
||||
}
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::ManifoldShape::ManifoldShape(const ManifoldPart& part)
|
||||
: parts_{ part } {}
|
||||
|
||||
ifcopenshell::geometry::ManifoldShape::ManifoldShape(ManifoldPart&& part)
|
||||
: parts_{ std::move(part) } {}
|
||||
|
||||
ifcopenshell::geometry::ManifoldShape::ManifoldShape(const std::vector<ManifoldPart>& parts)
|
||||
: parts_(parts) {}
|
||||
|
||||
ifcopenshell::geometry::ManifoldShape::ManifoldShape(std::vector<ManifoldPart>&& parts)
|
||||
: parts_(std::move(parts)) {}
|
||||
|
||||
std::optional<manifold::Manifold> ifcopenshell::geometry::ManifoldShape::as_manifold() const {
|
||||
if (parts_.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
std::vector<manifold::Manifold> solids;
|
||||
solids.reserve(parts_.size());
|
||||
for (const auto& part : parts_) {
|
||||
if (!part.solid) {
|
||||
return std::nullopt;
|
||||
}
|
||||
solids.push_back(*part.solid);
|
||||
}
|
||||
if (solids.size() == 1) {
|
||||
return solids.front();
|
||||
}
|
||||
return manifold::Manifold::BatchBoolean(solids, manifold::OpType::Add);
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::ManifoldShape::Triangulate(ifcopenshell::geometry::Settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const {
|
||||
for (const auto& part : parts_) {
|
||||
auto mesh = transform_mesh(part.mesh, place);
|
||||
std::vector<int> indices(mesh.NumVert());
|
||||
for (size_t i = 0; i < mesh.NumVert(); ++i) {
|
||||
indices[i] = t->addVertex(
|
||||
item_id,
|
||||
surface_style_id,
|
||||
mesh.vertProperties[i * mesh.numProp + 0],
|
||||
mesh.vertProperties[i * mesh.numProp + 1],
|
||||
mesh.vertProperties[i * mesh.numProp + 2]);
|
||||
}
|
||||
auto edges = count_edges(mesh);
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
t->addFace(
|
||||
item_id,
|
||||
surface_style_id,
|
||||
indices[mesh.triVerts[i * 3 + 0]],
|
||||
indices[mesh.triVerts[i * 3 + 1]],
|
||||
indices[mesh.triVerts[i * 3 + 2]]);
|
||||
}
|
||||
for (const auto& edge : edges) {
|
||||
if (edge.second == 1) {
|
||||
t->registerEdge(item_id, indices[edge.first.first], indices[edge.first.second]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::ManifoldShape::Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string& result) const {
|
||||
std::stringstream stream;
|
||||
stream << std::setprecision(17);
|
||||
size_t offset = 0;
|
||||
for (const auto& part : parts_) {
|
||||
auto mesh = transform_mesh(part.mesh, place);
|
||||
for (size_t i = 0; i < mesh.NumVert(); ++i) {
|
||||
stream << "v "
|
||||
<< mesh.vertProperties[i * mesh.numProp + 0] << " "
|
||||
<< mesh.vertProperties[i * mesh.numProp + 1] << " "
|
||||
<< mesh.vertProperties[i * mesh.numProp + 2] << "\n";
|
||||
}
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
stream << "f "
|
||||
<< mesh.triVerts[i * 3 + 0] + 1 + offset << " "
|
||||
<< mesh.triVerts[i * 3 + 1] + 1 + offset << " "
|
||||
<< mesh.triVerts[i * 3 + 2] + 1 + offset << "\n";
|
||||
}
|
||||
offset += mesh.NumVert();
|
||||
}
|
||||
result = stream.str();
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::ManifoldShape::surface_genus() const {
|
||||
int genus = 0;
|
||||
for (const auto& part : parts_) {
|
||||
if (!part.solid) {
|
||||
return 0;
|
||||
}
|
||||
genus += part.solid->Genus();
|
||||
}
|
||||
return genus;
|
||||
}
|
||||
|
||||
bool ifcopenshell::geometry::ManifoldShape::is_manifold() const {
|
||||
return std::all_of(parts_.begin(), parts_.end(), [](const auto& part) { return part.solid.has_value(); });
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::ManifoldShape::num_vertices() const {
|
||||
size_t total = 0;
|
||||
for (const auto& part : parts_) {
|
||||
total += part.mesh.NumVert();
|
||||
}
|
||||
return (int)total;
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::ManifoldShape::num_edges() const {
|
||||
int total = 0;
|
||||
for (const auto& part : parts_) {
|
||||
total += part.solid ? (int)part.solid->NumEdge() : mesh_edges(part.mesh);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int ifcopenshell::geometry::ManifoldShape::num_faces() const {
|
||||
size_t total = 0;
|
||||
for (const auto& part : parts_) {
|
||||
total += part.solid ? part.solid->NumTri() : part.mesh.NumTri();
|
||||
}
|
||||
return (int)total;
|
||||
}
|
||||
|
||||
double ifcopenshell::geometry::ManifoldShape::bounding_box(void*& box_ptr) const {
|
||||
bool initialized = false;
|
||||
auto* box = static_cast<manifold::Box*>(box_ptr);
|
||||
if (!box) {
|
||||
box = new manifold::Box();
|
||||
box_ptr = box;
|
||||
}
|
||||
for (const auto& part : parts_) {
|
||||
auto bbox = part.solid ? part.solid->BoundingBox() : mesh_bbox(part.mesh);
|
||||
if (!bbox.IsFinite()) {
|
||||
continue;
|
||||
}
|
||||
if (!initialized) {
|
||||
*box = bbox;
|
||||
initialized = true;
|
||||
} else {
|
||||
box->Union(bbox.min);
|
||||
box->Union(bbox.max);
|
||||
}
|
||||
}
|
||||
return initialized ? bbox_volume(*box) : 0.;
|
||||
}
|
||||
|
||||
std::pair<OpaqueCoordinate<3>, OpaqueCoordinate<3>> ifcopenshell::geometry::ManifoldShape::bounding_box() const {
|
||||
void* box_ptr = nullptr;
|
||||
bounding_box(box_ptr);
|
||||
auto* box = static_cast<manifold::Box*>(box_ptr);
|
||||
if (!box || !box->IsFinite()) {
|
||||
delete box;
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
auto result = std::make_pair(
|
||||
OpaqueCoordinate<3>(
|
||||
new NumberNativeDouble(box->min[0]),
|
||||
new NumberNativeDouble(box->min[1]),
|
||||
new NumberNativeDouble(box->min[2])),
|
||||
OpaqueCoordinate<3>(
|
||||
new NumberNativeDouble(box->max[0]),
|
||||
new NumberNativeDouble(box->max[1]),
|
||||
new NumberNativeDouble(box->max[2])));
|
||||
delete box;
|
||||
return result;
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::ManifoldShape::set_box(void* box_ptr) {
|
||||
auto* box = static_cast<manifold::Box*>(box_ptr);
|
||||
if (!box || !box->IsFinite()) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
parts_ = { make_box_part(*box) };
|
||||
}
|
||||
|
||||
OpaqueNumber* ifcopenshell::geometry::ManifoldShape::length() {
|
||||
double total = 0.;
|
||||
for (const auto& part : parts_) {
|
||||
total += mesh_length(part.mesh);
|
||||
}
|
||||
return new NumberNativeDouble(total);
|
||||
}
|
||||
|
||||
OpaqueNumber* ifcopenshell::geometry::ManifoldShape::area() {
|
||||
double total = 0.;
|
||||
for (const auto& part : parts_) {
|
||||
total += part.solid ? part.solid->SurfaceArea() : mesh_area(part.mesh);
|
||||
}
|
||||
return new NumberNativeDouble(total);
|
||||
}
|
||||
|
||||
OpaqueNumber* ifcopenshell::geometry::ManifoldShape::volume() {
|
||||
double total = 0.;
|
||||
for (const auto& part : parts_) {
|
||||
total += part.solid ? part.solid->Volume() : mesh_volume(part.mesh);
|
||||
}
|
||||
return new NumberNativeDouble(total);
|
||||
}
|
||||
|
||||
OpaqueCoordinate<3> ifcopenshell::geometry::ManifoldShape::position() {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
|
||||
OpaqueCoordinate<3> ifcopenshell::geometry::ManifoldShape::axis() {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
|
||||
OpaqueCoordinate<4> ifcopenshell::geometry::ManifoldShape::plane_equation() {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::ManifoldShape::convex_decomposition() {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::halfspaces() {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::box() {
|
||||
void* box_ptr = nullptr;
|
||||
bounding_box(box_ptr);
|
||||
auto* box = static_cast<manifold::Box*>(box_ptr);
|
||||
if (!box || !box->IsFinite()) {
|
||||
delete box;
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
auto* result = new ManifoldShape(make_box_part(*box));
|
||||
delete box;
|
||||
return result;
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::solid() {
|
||||
if (!is_manifold()) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
return new ManifoldShape(parts_);
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::wrap_in_compound() {
|
||||
return new ManifoldShape(parts_);
|
||||
}
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::ManifoldShape::vertices() {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::ManifoldShape::edges() {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
std::vector<ConversionResultShape*> ifcopenshell::geometry::ManifoldShape::facets() {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::add(ConversionResultShape* other) {
|
||||
auto* rhs = dynamic_cast<ManifoldShape*>(other);
|
||||
if (!rhs) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
auto a = as_manifold();
|
||||
auto b = rhs->as_manifold();
|
||||
if (!a || !b) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
return new ManifoldShape(make_part(*a + *b));
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::subtract(ConversionResultShape* other) {
|
||||
auto* rhs = dynamic_cast<ManifoldShape*>(other);
|
||||
if (!rhs) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
auto a = as_manifold();
|
||||
auto b = rhs->as_manifold();
|
||||
if (!a || !b) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
return new ManifoldShape(make_part(*a - *b));
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::intersect(ConversionResultShape* other) {
|
||||
auto* rhs = dynamic_cast<ManifoldShape*>(other);
|
||||
if (!rhs) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
auto a = as_manifold();
|
||||
auto b = rhs->as_manifold();
|
||||
if (!a || !b) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
return new ManifoldShape(make_part(*a ^ *b));
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::concat(ConversionResultShape* other) {
|
||||
auto* rhs = dynamic_cast<ManifoldShape*>(other);
|
||||
if (!rhs) {
|
||||
throw std::runtime_error("Invalid shape");
|
||||
}
|
||||
auto parts = parts_;
|
||||
parts.insert(parts.end(), rhs->parts_.begin(), rhs->parts_.end());
|
||||
return new ManifoldShape(std::move(parts));
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::ManifoldShape::map(OpaqueCoordinate<4>&, OpaqueCoordinate<4>&) {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::ManifoldShape::map(const std::vector<OpaqueCoordinate<4>>&, const std::vector<OpaqueCoordinate<4>>&) {
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
ConversionResultShape* ifcopenshell::geometry::ManifoldShape::moved(ifcopenshell::geometry::taxonomy::matrix4::ptr place) const {
|
||||
std::vector<ManifoldPart> moved_parts;
|
||||
moved_parts.reserve(parts_.size());
|
||||
for (const auto& part : parts_) {
|
||||
auto mesh = transform_mesh(part.mesh, *place);
|
||||
auto solid = part.solid ? make_manifold(mesh) : std::nullopt;
|
||||
if (part.solid && !solid) {
|
||||
throw std::runtime_error("Failed to transform shape");
|
||||
}
|
||||
moved_parts.push_back({ std::move(mesh), std::move(solid) });
|
||||
}
|
||||
return new ManifoldShape(std::move(moved_parts));
|
||||
}
|
||||
|
||||
bool ifcopenshell::geometry::ManifoldShape::surface_area_along_direction(double, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place, double& along_x, double& along_y, double& along_z) const {
|
||||
along_x = along_y = along_z = 0.;
|
||||
for (const auto& part : parts_) {
|
||||
auto mesh = transform_mesh(part.mesh, *place);
|
||||
for (size_t i = 0; i < mesh.NumTri(); ++i) {
|
||||
auto point = [&](uint32_t v) {
|
||||
return Eigen::Vector3d(
|
||||
mesh.vertProperties[v * mesh.numProp + 0],
|
||||
mesh.vertProperties[v * mesh.numProp + 1],
|
||||
mesh.vertProperties[v * mesh.numProp + 2]);
|
||||
};
|
||||
const auto a = point(mesh.triVerts[i * 3 + 0]);
|
||||
const auto b = point(mesh.triVerts[i * 3 + 1]);
|
||||
const auto c = point(mesh.triVerts[i * 3 + 2]);
|
||||
auto n = (b - a).cross(c - a);
|
||||
const auto norm = n.norm();
|
||||
if (norm < 1.e-12) {
|
||||
continue;
|
||||
}
|
||||
const auto area = 0.5 * norm;
|
||||
n /= norm;
|
||||
along_x += area * std::abs(n(0));
|
||||
along_y += area * std::abs(n(1));
|
||||
along_z += area * std::abs(n(2));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
#ifndef IFCGEOMMANIFOLDREPRESENTATION_H
|
||||
#define IFCGEOMMANIFOLDREPRESENTATION_H
|
||||
|
||||
#include <manifold/manifold.h>
|
||||
|
||||
#include "../../../ifcgeom/ConversionResult.h"
|
||||
#include "../../../ifcgeom/kernels/ifc_geomlibrary_api.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
|
||||
struct IFC_GEOMLIBRARY_API ManifoldPart {
|
||||
manifold::MeshGL64 mesh;
|
||||
std::optional<manifold::Manifold> solid;
|
||||
};
|
||||
|
||||
class IFC_GEOMLIBRARY_API ManifoldShape : public IfcGeom::ConversionResultShape {
|
||||
public:
|
||||
ManifoldShape() = default;
|
||||
explicit ManifoldShape(const ManifoldPart& part);
|
||||
explicit ManifoldShape(ManifoldPart&& part);
|
||||
explicit ManifoldShape(const std::vector<ManifoldPart>& parts);
|
||||
explicit ManifoldShape(std::vector<ManifoldPart>&& parts);
|
||||
|
||||
const std::vector<ManifoldPart>& parts() const { return parts_; }
|
||||
std::optional<manifold::Manifold> as_manifold() const;
|
||||
virtual std::string_view backend_id() const { return "manifold"; }
|
||||
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
|
||||
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
|
||||
|
||||
virtual int surface_genus() const;
|
||||
virtual bool is_manifold() const;
|
||||
|
||||
virtual int num_vertices() const;
|
||||
virtual int num_edges() const;
|
||||
virtual int num_faces() const;
|
||||
|
||||
virtual double bounding_box(void*&) const;
|
||||
virtual std::pair<IfcGeom::OpaqueCoordinate<3>, IfcGeom::OpaqueCoordinate<3>> bounding_box() const;
|
||||
virtual void set_box(void* b);
|
||||
|
||||
virtual IfcGeom::OpaqueNumber* length();
|
||||
virtual IfcGeom::OpaqueNumber* area();
|
||||
virtual IfcGeom::OpaqueNumber* volume();
|
||||
|
||||
virtual IfcGeom::OpaqueCoordinate<3> position();
|
||||
virtual IfcGeom::OpaqueCoordinate<3> axis();
|
||||
virtual IfcGeom::OpaqueCoordinate<4> plane_equation();
|
||||
|
||||
virtual std::vector<IfcGeom::ConversionResultShape*> convex_decomposition();
|
||||
virtual IfcGeom::ConversionResultShape* halfspaces();
|
||||
virtual IfcGeom::ConversionResultShape* box();
|
||||
virtual IfcGeom::ConversionResultShape* solid();
|
||||
virtual IfcGeom::ConversionResultShape* wrap_in_compound();
|
||||
|
||||
virtual std::vector<IfcGeom::ConversionResultShape*> vertices();
|
||||
virtual std::vector<IfcGeom::ConversionResultShape*> edges();
|
||||
virtual std::vector<IfcGeom::ConversionResultShape*> facets();
|
||||
|
||||
virtual IfcGeom::ConversionResultShape* add(IfcGeom::ConversionResultShape*);
|
||||
virtual IfcGeom::ConversionResultShape* subtract(IfcGeom::ConversionResultShape*);
|
||||
virtual IfcGeom::ConversionResultShape* intersect(IfcGeom::ConversionResultShape*);
|
||||
virtual IfcGeom::ConversionResultShape* concat(IfcGeom::ConversionResultShape*);
|
||||
|
||||
virtual void map(IfcGeom::OpaqueCoordinate<4>& from, IfcGeom::OpaqueCoordinate<4>& to);
|
||||
virtual void map(const std::vector<IfcGeom::OpaqueCoordinate<4>>& from, const std::vector<IfcGeom::OpaqueCoordinate<4>>& to);
|
||||
virtual IfcGeom::ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const;
|
||||
|
||||
virtual bool surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const;
|
||||
|
||||
private:
|
||||
std::vector<ManifoldPart> parts_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
#ifndef MANIFOLD_KERNEL_H
|
||||
#define MANIFOLD_KERNEL_H
|
||||
|
||||
#include <manifold/manifold.h>
|
||||
|
||||
#include "../../../ifcgeom/AbstractKernel.h"
|
||||
#include "../../../ifcgeom/kernels/ifc_geomlibrary_api.h"
|
||||
#include "../../../ifcgeom/kernels/manifold/ManifoldConversionResult.h"
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
namespace kernels {
|
||||
|
||||
class IFC_GEOMLIBRARY_API ManifoldKernel : public AbstractKernel {
|
||||
public:
|
||||
ManifoldKernel(const Settings& settings)
|
||||
: AbstractKernel("manifold", settings) {}
|
||||
|
||||
virtual AbstractKernel* clone() const {
|
||||
return new ManifoldKernel(settings());
|
||||
}
|
||||
|
||||
virtual bool supports_openings() const { return true; }
|
||||
virtual bool supports_boolean_operations() const { return true; }
|
||||
|
||||
virtual bool convert_impl(const taxonomy::extrusion::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::shell::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::solid::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const taxonomy::boolean_result::ptr, IfcGeom::ConversionResults&);
|
||||
|
||||
double dilation_hack = 0.;
|
||||
|
||||
virtual bool convert_openings(const express::Base& entity, const std::vector<std::pair<taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/********************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../kernel_plugin.h"
|
||||
#include "ManifoldKernel.h"
|
||||
|
||||
#include <boost/dll/alias.hpp>
|
||||
|
||||
namespace ifcopenshell {
|
||||
namespace geometry {
|
||||
namespace kernels {
|
||||
namespace manifold_plugin {
|
||||
|
||||
plugin::abi_info plugin_abi() {
|
||||
return plugin::host_abi();
|
||||
}
|
||||
|
||||
plugin::metadata plugin_metadata() {
|
||||
return kernel_plugin_metadata("manifold");
|
||||
}
|
||||
|
||||
AbstractKernel* create_kernel(ifcopenshell::file*, Settings& settings) {
|
||||
return new ManifoldKernel(settings);
|
||||
}
|
||||
|
||||
void register_plugin(kernel_registry& registry, const plugin::module& module) {
|
||||
kernel_info info;
|
||||
info.backend_id = "manifold";
|
||||
info.supports_boolean_operations = true;
|
||||
registry.bind(info, create_kernel, module);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::manifold_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::manifold_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
|
||||
BOOST_DLL_ALIAS(ifcopenshell::geometry::kernels::manifold_plugin::register_plugin, ifcopenshell_register_kernel_plugin_v1)
|
||||
@@ -20,10 +20,11 @@
|
||||
#ifndef IFCGEOMTREE_H
|
||||
#define IFCGEOMTREE_H
|
||||
|
||||
#include "../../../ifcparse/IfcFile.h"
|
||||
#include "../../../ifcparse/file.h"
|
||||
|
||||
#include "../../../ifcgeom/IfcGeomElement.h"
|
||||
#include "../../../ifcgeom/Iterator.h"
|
||||
#include "../../../ifcgeom/tree.h"
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
#include "OpenCascadeKernel.h"
|
||||
#include "base_utils.h"
|
||||
@@ -69,26 +70,6 @@
|
||||
|
||||
|
||||
namespace IfcGeom {
|
||||
|
||||
struct ray_intersection_result {
|
||||
double distance;
|
||||
int style_index;
|
||||
const IfcUtil::IfcBaseEntity* instance;
|
||||
std::array<double, 3> position;
|
||||
std::array<double, 3> normal;
|
||||
double ray_distance;
|
||||
double dot_product;
|
||||
};
|
||||
|
||||
struct clash {
|
||||
int clash_type; // 0 = protrusion, 1 = pierce, 2 = collision, 3 = clearance
|
||||
const IfcUtil::IfcBaseClass* a;
|
||||
const IfcUtil::IfcBaseClass* b;
|
||||
double distance;
|
||||
std::array<double, 3> p1;
|
||||
std::array<double, 3> p2;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// Approximates the distance `other` protrudes into `volume` by finding the
|
||||
@@ -1442,9 +1423,9 @@ namespace IfcGeom {
|
||||
|
||||
// Temporary structures for H5
|
||||
std::vector<IfcGeom::TriangulationElement*> triangulation_elements_;
|
||||
std::map<const IfcUtil::IfcBaseClass*, std::string> global_ids_;
|
||||
std::map<const IfcUtil::IfcBaseClass*, std::string> names_;
|
||||
std::map<const IfcUtil::IfcBaseClass*, ifcopenshell::geometry::taxonomy::matrix4::ptr> placements_;
|
||||
std::map<express::Base, std::string> global_ids_;
|
||||
std::map<express::Base, std::string> names_;
|
||||
std::map<express::Base, ifcopenshell::geometry::taxonomy::matrix4::ptr> placements_;
|
||||
std::map<std::string, std::vector<double>> local_verts_;
|
||||
std::map<std::string, std::vector<int>> local_faces_;
|
||||
std::map<std::string, std::vector<ifcopenshell::geometry::taxonomy::style::ptr>> local_materials_;
|
||||
@@ -1481,24 +1462,24 @@ namespace IfcGeom {
|
||||
};
|
||||
}
|
||||
|
||||
class tree : public impl::tree<const IfcUtil::IfcBaseEntity*> {
|
||||
class opencascade_tree : public impl::tree<express::Entity> {
|
||||
public:
|
||||
|
||||
tree() {};
|
||||
opencascade_tree() {};
|
||||
|
||||
tree(IfcParse::IfcFile& f) {
|
||||
opencascade_tree(ifcopenshell::file& f) {
|
||||
add_file(f, ifcopenshell::geometry::Settings{});
|
||||
}
|
||||
|
||||
tree(IfcParse::IfcFile& f, ifcopenshell::geometry::Settings settings) {
|
||||
opencascade_tree(ifcopenshell::file& f, ifcopenshell::geometry::Settings settings) {
|
||||
add_file(f, settings);
|
||||
}
|
||||
|
||||
tree(IfcGeom::Iterator& it) {
|
||||
opencascade_tree(IfcGeom::Iterator& it) {
|
||||
add_file(it);
|
||||
}
|
||||
|
||||
void add_file(IfcParse::IfcFile& f, ifcopenshell::geometry::Settings settings) {
|
||||
void add_file(ifcopenshell::file& f, ifcopenshell::geometry::Settings settings) {
|
||||
ifcopenshell::geometry::Settings settings_ = settings;
|
||||
settings_.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
|
||||
settings_.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <map>
|
||||
#include <map>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopExp.hxx>
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcparse/logger.h"
|
||||
#include "../../../ifcgeom/IfcGeomRepresentation.h"
|
||||
#include "base_utils.h"
|
||||
#include "boolean_utils.h"
|
||||
@@ -47,13 +47,35 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::OpenCascadeShape::OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape) {}
|
||||
|
||||
ifcopenshell::geometry::OpenCascadeShape::OpenCascadeShape(TopoDS_Shape&& shape)
|
||||
: shape_(std::move(shape)) {}
|
||||
|
||||
const TopoDS_Shape& ifcopenshell::geometry::OpenCascadeShape::shape() const {
|
||||
return shape_;
|
||||
}
|
||||
|
||||
ifcopenshell::geometry::OpenCascadeShape::operator const TopoDS_Shape& () {
|
||||
return shape_;
|
||||
}
|
||||
|
||||
std::string_view ifcopenshell::geometry::OpenCascadeShape::backend_id() const {
|
||||
return "opencascade";
|
||||
}
|
||||
|
||||
IfcGeom::ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
|
||||
void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const {
|
||||
|
||||
// @todo remove duplication with OpenCascadeKernel::convert(const taxonomy::matrix4::ptr matrix, gp_GTrsf& trsf);
|
||||
// above can be static?
|
||||
|
||||
// A 3x3 matrix to rotate the vertex normals
|
||||
boost::optional<gp_Mat> rotation_matrix;
|
||||
std::optional<gp_Mat> rotation_matrix;
|
||||
|
||||
if (place.components_) {
|
||||
const auto& m = *place.components_;
|
||||
@@ -87,7 +109,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(shape_, settings.get<settings::MesherLinearDeflection>().get(), false, settings.get<settings::MesherAngularDeflection>().get());
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
logger::message(logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +135,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
Handle_Poly_Triangulation tri = BRep_Tool::Triangulation(face, loc);
|
||||
|
||||
if (tri.IsNull()) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Triangulation missing for face");
|
||||
logger::message(logger::LOG_ERROR, "Triangulation missing for face");
|
||||
} else {
|
||||
// Keep track of the number of times an edge is used
|
||||
// Manifold edges (i.e. edges used twice) are deemed invisible
|
||||
@@ -174,7 +196,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometr
|
||||
else triangles(i).Get(n1, n2, n3);
|
||||
|
||||
if (dict[n1] == dict[n2] || dict[n2] == dict[n3] || dict[n3] == dict[n1]) {
|
||||
Logger::Warning("Mesher generated a degenerate triangle, ignoring");
|
||||
logger::warning("Mesher generated a degenerate triangle, ignoring");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -619,7 +641,7 @@ namespace {
|
||||
try {
|
||||
BRepMesh_IncrementalMesh(s, tol);
|
||||
} catch (...) {
|
||||
Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
logger::message(logger::LOG_ERROR, "Failed to triangulate shape");
|
||||
return;
|
||||
}
|
||||
meshed = true;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/********************************************************************************
|
||||
/********************************************************************************
|
||||
* *
|
||||
* This file is part of IfcOpenShell. *
|
||||
* *
|
||||
@@ -45,20 +45,17 @@ namespace ifcopenshell {
|
||||
|
||||
class IFC_GEOMLIBRARY_API OpenCascadeShape : public IfcGeom::ConversionResultShape {
|
||||
public:
|
||||
OpenCascadeShape(const TopoDS_Shape& shape)
|
||||
: shape_(shape) {}
|
||||
OpenCascadeShape(TopoDS_Shape&& shape)
|
||||
: shape_(std::move(shape)) {}
|
||||
OpenCascadeShape(const TopoDS_Shape& shape);
|
||||
OpenCascadeShape(TopoDS_Shape&& shape);
|
||||
|
||||
const TopoDS_Shape& shape() const { return shape_; }
|
||||
operator const TopoDS_Shape& () { return shape_; }
|
||||
const TopoDS_Shape& shape() const;
|
||||
operator const TopoDS_Shape& ();
|
||||
virtual std::string_view backend_id() const;
|
||||
|
||||
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
|
||||
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
|
||||
|
||||
virtual IfcGeom::ConversionResultShape* clone() const {
|
||||
return new OpenCascadeShape(shape_);
|
||||
}
|
||||
virtual IfcGeom::ConversionResultShape* clone() const;
|
||||
|
||||
virtual double bounding_box(void*&) const {
|
||||
throw std::runtime_error("Not implemented");
|
||||
@@ -113,4 +110,4 @@ namespace ifcopenshell {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -145,11 +145,11 @@ public:
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::loft::ptr, IfcGeom::ConversionResults&);
|
||||
virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::sweep_along_curve::ptr, IfcGeom::ConversionResults&);
|
||||
|
||||
virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector<std::pair<ifcopenshell::geometry::taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
virtual bool convert_openings(const express::Base& entity, const std::vector<std::pair<ifcopenshell::geometry::taxonomy::ptr, ifcopenshell::geometry::taxonomy::matrix4>>& openings,
|
||||
const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes);
|
||||
virtual bool unify_shapes(const IfcGeom::ConversionResults& input, IfcGeom::ConversionResults& output);
|
||||
|
||||
typedef boost::variant<boost::blank, Handle(Geom_Curve), TopoDS_Wire> curve_creation_visitor_result_type;
|
||||
typedef std::variant<boost::blank, Handle(Geom_Curve), TopoDS_Wire> curve_creation_visitor_result_type;
|
||||
curve_creation_visitor_result_type convert_curve(const ifcopenshell::geometry::taxonomy::ptr);
|
||||
Handle(Geom_Surface) convert_surface(const ifcopenshell::geometry::taxonomy::ptr);
|
||||
|
||||
@@ -166,8 +166,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
IfcUtil::IfcBaseClass* POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
express::Base POSTFIX_SCHEMA(tesselate_)(const TopoDS_Shape& shape, double deflection);
|
||||
express::Base POSTFIX_SCHEMA(serialise_)(const TopoDS_Shape& shape, bool advanced);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "base_utils.h"
|
||||
|
||||
#include "../../../ifcparse/IfcLogger.h"
|
||||
#include "../../../ifcparse/logger.h"
|
||||
#include "OpenCascadeConversionResult.h"
|
||||
#include "boolean_utils.h"
|
||||
|
||||
@@ -711,12 +711,12 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
valid_shell &= util::count(shape, TopAbs_SHELL) > 0;
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
logger::error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error sewing shell");
|
||||
logger::error("Unknown error sewing shell");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error sewing shell");
|
||||
logger::error("Unknown error sewing shell");
|
||||
}
|
||||
|
||||
if (valid_shell) {
|
||||
@@ -744,22 +744,22 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
}
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
logger::error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error classifying solid");
|
||||
logger::error("Unknown error classifying solid");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error classifying solid");
|
||||
logger::error("Unknown error classifying solid");
|
||||
}
|
||||
}
|
||||
} catch (const Standard_Failure& e) {
|
||||
if (e.GetMessageString() && strlen(e.GetMessageString())) {
|
||||
Logger::Error(e.GetMessageString());
|
||||
logger::error(e.GetMessageString());
|
||||
} else {
|
||||
Logger::Error("Unknown error creating solid");
|
||||
logger::error("Unknown error creating solid");
|
||||
}
|
||||
} catch (...) {
|
||||
Logger::Error("Unknown error creating solid");
|
||||
logger::error("Unknown error creating solid");
|
||||
}
|
||||
|
||||
if (complete_shape.IsNull()) {
|
||||
@@ -771,7 +771,7 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
B.MakeCompound(C);
|
||||
B.Add(C, complete_shape);
|
||||
complete_shape = C;
|
||||
Logger::Warning("Multiple components in IfcConnectedFaceSet");
|
||||
logger::warning("Multiple components in IfcConnectedFaceSet");
|
||||
}
|
||||
B.Add(complete_shape, result_shape);
|
||||
}
|
||||
@@ -786,7 +786,7 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
B.MakeCompound(C);
|
||||
B.Add(C, complete_shape);
|
||||
complete_shape = C;
|
||||
Logger::Warning("Loose faces in IfcConnectedFaceSet");
|
||||
logger::warning("Loose faces in IfcConnectedFaceSet");
|
||||
}
|
||||
B.Add(complete_shape, loose_faces.Current());
|
||||
}
|
||||
@@ -794,7 +794,7 @@ bool IfcGeom::util::create_solid_from_faces(const TopTools_ListOfShape& face_lis
|
||||
shape = complete_shape;
|
||||
|
||||
} else {
|
||||
Logger::Error("Failed to sew faceset");
|
||||
logger::error("Failed to sew faceset");
|
||||
}
|
||||
|
||||
return valid_shell;
|
||||
@@ -898,7 +898,7 @@ bool IfcGeom::util::validate_shape(const TopoDS_Shape& s) {
|
||||
|
||||
dump(s);
|
||||
|
||||
Logger::Warning(str.str());
|
||||
logger::warning(str.str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
|
||||
if (settings_.get<settings::DisableBooleanResult>().get()) {
|
||||
results.emplace_back(IfcGeom::ConversionResult(
|
||||
br->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
br->instance.id(),
|
||||
br->matrix,
|
||||
new OpenCascadeShape(a),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
@@ -118,14 +118,14 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
|
||||
const double first_operand_volume = util::shape_volume(a);
|
||||
if (first_operand_volume <= ALMOST_ZERO) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Empty solid for:", c->instance);
|
||||
logger::message(logger::LOG_WARNING, "Empty solid for:", c->instance);
|
||||
}
|
||||
} else {
|
||||
|
||||
for (auto& r : cr) {
|
||||
auto S = std::static_pointer_cast<OpenCascadeShape>(r.Shape())->shape();
|
||||
if (S.IsNull()) {
|
||||
Logger::Error("Null operand");
|
||||
logger::error("Null operand");
|
||||
continue;
|
||||
}
|
||||
gp_GTrsf trsf;
|
||||
@@ -140,7 +140,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
// #2665 we also set a precision-independent threshold, because in the boolean op routine
|
||||
// the working fuzziness might still be increased.
|
||||
if (d < tol * 20. || d < 0.00002) {
|
||||
Logger::Message(Logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", c->instance);
|
||||
logger::message(logger::LOG_WARNING, "Halfspace subtraction yields unchanged volume:", c->instance);
|
||||
continue;
|
||||
} else {
|
||||
S = result;
|
||||
@@ -190,7 +190,7 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con
|
||||
}
|
||||
|
||||
results.emplace_back(IfcGeom::ConversionResult(
|
||||
br->instance->as<IfcUtil::IfcBaseEntity>()->id(),
|
||||
br->instance.id(),
|
||||
br->matrix,
|
||||
new OpenCascadeShape(a),
|
||||
br->surface_style ? br->surface_style : first_item_style
|
||||
|
||||
@@ -419,7 +419,7 @@ int IfcGeom::util::eliminate_narrow_operands(double prec, const TopTools_ListOfS
|
||||
|
||||
bool is_narrow = min_dimension < prec;
|
||||
|
||||
Logger::Notice("Min OBB dimension of operand = " + std::to_string(min_dimension));
|
||||
logger::notice("Min OBB dimension of operand = " + std::to_string(min_dimension));
|
||||
|
||||
if (!is_narrow) {
|
||||
c.Append(it.Value());
|
||||
@@ -704,7 +704,7 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
if (u11 < U1 && U1 < u12 && u21 < U2 && U2 < u22) {
|
||||
// Edge curves belonging to different operands intersect, don't process
|
||||
// using builder.
|
||||
Logger::Notice("Intersecting boundaries");
|
||||
logger::notice("Intersecting boundaries");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -751,7 +751,7 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
// any effect and marked as redundant. Feeding it to the builder algo
|
||||
// will likely cause problems.
|
||||
redundant[std::distance(wires.begin(), it)] = true;
|
||||
Logger::Notice("Subtraction operand outside of outer bound");
|
||||
logger::notice("Subtraction operand outside of outer bound");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,7 +791,7 @@ bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_
|
||||
if (wire_clss[wire_index].Perform(p2d) == TopAbs_IN) {
|
||||
// A wire is contained within another operand
|
||||
redundant[other_index] = true;
|
||||
Logger::Notice("Subtraction operand contained in other");
|
||||
logger::notice("Subtraction operand contained in other");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,11 +845,11 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
std::string debug_identifier;
|
||||
if (debug) {
|
||||
static my_thread_local size_t operation_counter_ = 0;
|
||||
static thread_local size_t operation_counter_ = 0;
|
||||
std::stringstream ss;
|
||||
ss << "bool-" << std::this_thread::get_id() << "-" << (operation_counter_++);
|
||||
debug_identifier = ss.str();
|
||||
Logger::Notice("Boolean debug identifier: " + debug_identifier);
|
||||
logger::notice("Boolean debug identifier: " + debug_identifier);
|
||||
}
|
||||
|
||||
if (fuzziness < 0.) {
|
||||
@@ -885,8 +885,8 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
a = unify(a_input, fuzziness * 1000.);
|
||||
|
||||
Logger::Message(
|
||||
Logger::LOG_DEBUG,
|
||||
logger::message(
|
||||
logger::LOG_DEBUG,
|
||||
"Simplified operand A from "s +
|
||||
std::to_string(count(a_input, TopAbs_FACE)) +
|
||||
" to "s +
|
||||
@@ -897,8 +897,8 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
TopTools_ListIteratorOfListOfShape it(b_input);
|
||||
for (; it.More(); it.Next()) {
|
||||
b.Append(unify(it.Value(), fuzziness));
|
||||
Logger::Message(
|
||||
Logger::LOG_DEBUG,
|
||||
logger::message(
|
||||
logger::LOG_DEBUG,
|
||||
"Simplified operand B from "s +
|
||||
std::to_string(count(it.Value(), TopAbs_FACE)) +
|
||||
" to "s +
|
||||
@@ -925,7 +925,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
auto N = bounding_box_overlap(fuzziness, a, b, b_tmp);
|
||||
if (N) {
|
||||
Logger::Notice("Eliminated " + std::to_string(N) + " disjoint operands");
|
||||
logger::notice("Eliminated " + std::to_string(N) + " disjoint operands");
|
||||
std::swap(b, b_tmp);
|
||||
}
|
||||
}
|
||||
@@ -936,7 +936,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
b_tmp.Clear();
|
||||
auto N = eliminate_touching_operands(fuzziness, a, b, b_tmp);
|
||||
if (N) {
|
||||
Logger::Notice("Eliminated " + std::to_string(N) + " touching operands");
|
||||
logger::notice("Eliminated " + std::to_string(N) + " touching operands");
|
||||
std::swap(b, b_tmp);
|
||||
}
|
||||
}
|
||||
@@ -947,7 +947,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
b_tmp.Clear();
|
||||
auto N = eliminate_narrow_operands(fuzziness, b, b_tmp);
|
||||
if (N) {
|
||||
Logger::Notice("Eliminated " + std::to_string(N) + " narrow operands");
|
||||
logger::notice("Eliminated " + std::to_string(N) + " narrow operands");
|
||||
std::swap(b, b_tmp);
|
||||
}
|
||||
}
|
||||
@@ -961,21 +961,21 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (b.Extent() == 0) {
|
||||
Logger::Warning("No other operands remaining, using first operand");
|
||||
logger::warning("No other operands remaining, using first operand");
|
||||
result = a;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!is_2d && Logger::LOG_NOTICE >= Logger::Verbosity()) {
|
||||
if (!is_2d && logger::LOG_NOTICE >= logger::verbosity()) {
|
||||
PERF("preliminary manifoldness check");
|
||||
|
||||
if (!a.IsNull()) {
|
||||
Logger::Notice("Operand A is " + (is_manifold(a) ? ""s : "non-"s) + "manifold");
|
||||
logger::notice("Operand A is " + (is_manifold(a) ? ""s : "non-"s) + "manifold");
|
||||
}
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
for (int i = 0; it.More(); it.Next(), ++i) {
|
||||
Logger::Notice("Operand B " + std::to_string(i) + " is " + (is_manifold(it.Value()) ? ""s : "non-"s) + "manifold");
|
||||
logger::notice("Operand B " + std::to_string(i) + " is " + (is_manifold(it.Value()) ? ""s : "non-"s) + "manifold");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1015,7 +1015,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
const double fuzz = (std::min)(min_length_orig / 3., fuzziness);
|
||||
|
||||
Logger::Notice("Used fuzziness: " + std::to_string(fuzz));
|
||||
logger::notice("Used fuzziness: " + std::to_string(fuzz));
|
||||
|
||||
const double new_fuzziness = fuzziness * 10.;
|
||||
const bool allow_retry = new_fuzziness - 1e-15 <= settings.precision * 10000. && new_fuzziness < min_length_orig;
|
||||
@@ -1049,7 +1049,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (is_extrusion_a) {
|
||||
Logger::Notice("Operand A 1/1 is an extrusion");
|
||||
logger::notice("Operand A 1/1 is an extrusion");
|
||||
|
||||
TopTools_ListIteratorOfListOfShape it(b);
|
||||
for (int nb = 1; it.More(); it.Next(), ++nb) {
|
||||
@@ -1065,10 +1065,10 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
if (is_extrusion_b) {
|
||||
Logger::Notice("Operand B " + std::to_string(nb) + "/" + std::to_string(b.Extent()) + " is an extrusion");
|
||||
logger::notice("Operand B " + std::to_string(nb) + "/" + std::to_string(b.Extent()) + " is an extrusion");
|
||||
|
||||
if (b_interval.first < a_interval.first + (fuzz * 100.) && b_interval.second > a_interval.second - (fuzz * 100.)) {
|
||||
Logger::Notice("Operand B creates a through hole");
|
||||
logger::notice("Operand B creates a through hole");
|
||||
|
||||
// Align b with a operand
|
||||
gp_Trsf trsf;
|
||||
@@ -1108,23 +1108,23 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
BRepPrimAPI_MakePrism mp(face_result, gp_Vec(gp::DY()) * (a_interval.second - a_interval.first));
|
||||
if (mp.IsDone()) {
|
||||
if (b_remainder_3d.Extent()) {
|
||||
Logger::Notice(std::to_string(b_remainder_3d.Extent()) + " operands remaining to process in 3D");
|
||||
logger::notice(std::to_string(b_remainder_3d.Extent()) + " operands remaining to process in 3D");
|
||||
b = b_remainder_3d;
|
||||
s1s.Clear();
|
||||
s1s.Append(mp.Shape());
|
||||
} else {
|
||||
Logger::Notice("Processed fully in 2D");
|
||||
logger::notice("Processed fully in 2D");
|
||||
result = mp.Shape();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Logger::Notice("Failed to extrude 2D boolean result. Retrying in 3D.");
|
||||
logger::notice("Failed to extrude 2D boolean result. Retrying in 3D.");
|
||||
}
|
||||
} else {
|
||||
Logger::Notice("Failed to perform 2D boolean operation. Retrying in 3D.");
|
||||
logger::notice("Failed to perform 2D boolean operation. Retrying in 3D.");
|
||||
}
|
||||
} else {
|
||||
Logger::Notice("No second operands can be processed as 2D inner bounds. Retrying in 3D.");
|
||||
logger::notice("No second operands can be processed as 2D inner bounds. Retrying in 3D.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1146,7 +1146,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
if (builder->IsDone()) {
|
||||
if (false && builder->DSFiller()->HasWarning(STANDARD_TYPE(BOPAlgo_AlertAcquiredSelfIntersection))) {
|
||||
Logger::Notice("Builder reports self-intersection in output");
|
||||
logger::notice("Builder reports self-intersection in output");
|
||||
success = false;
|
||||
|
||||
/*
|
||||
@@ -1160,7 +1160,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
*/
|
||||
} else if(builder->DSFiller()->HasWarning(STANDARD_TYPE(BOPAlgo_AlertBadPositioning)) && !TopoDS_Iterator(*builder).More()) {
|
||||
Logger::Notice("Builder reports bad positioning and result is empty");
|
||||
logger::notice("Builder reports bad positioning and result is empty");
|
||||
success = false;
|
||||
} else {
|
||||
TopoDS_Shape r = *builder;
|
||||
@@ -1174,7 +1174,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
fix.Perform();
|
||||
r = fix.Shape();
|
||||
} catch (...) {
|
||||
Logger::Error("Shape healing failed on boolean result");
|
||||
logger::error("Shape healing failed on boolean result");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1185,7 +1185,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
success = ana.IsValid() != 0;
|
||||
|
||||
if (!success) {
|
||||
Logger::Notice("Boolean operation yields invalid result");
|
||||
logger::notice("Boolean operation yields invalid result");
|
||||
|
||||
std::stringstream str;
|
||||
bool any_emitted = false;
|
||||
@@ -1215,7 +1215,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
dump(r);
|
||||
|
||||
Logger::Notice(str.str());
|
||||
logger::notice(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1335,7 +1335,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
|
||||
if (op == BOPAlgo_CUT && has_open_shells && all_faces_included_in_result && result_n_faces > first_op_n_faces) {
|
||||
success = false;
|
||||
Logger::Notice("Boolean result discarded because subtractions results in only the addition of faces");
|
||||
logger::notice("Boolean result discarded because subtractions results in only the addition of faces");
|
||||
} else {
|
||||
// when there are edges or vertex-edge distances close to the used fuzziness, the
|
||||
// output is not trusted and the operation is attempted with a higher fuzziness.
|
||||
@@ -1381,7 +1381,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
static const char* const reason_strings[] = { "edge length", "vertex-edge", "face-face" };
|
||||
std::stringstream str;
|
||||
str << "Boolean operation result failing " << reason_strings[reason] << " interference check, with fuzziness " << fuzziness << " with length " << v;
|
||||
Logger::Notice(str.str());
|
||||
logger::notice(str.str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1390,7 +1390,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
}
|
||||
|
||||
} else {
|
||||
Logger::Notice("Boolean operation yields non-manifold result");
|
||||
logger::notice("Boolean operation yields non-manifold result");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1400,7 +1400,7 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
#if OCC_VERSION_HEX >= 0x70200
|
||||
|
||||
if (builder->HasError(STANDARD_TYPE(BOPAlgo_AlertBOPNotAllowed))) {
|
||||
Logger::Error("Invalid operands. Using first operand");
|
||||
logger::error("Invalid operands. Using first operand");
|
||||
result = a;
|
||||
success = true;
|
||||
}
|
||||
@@ -1413,14 +1413,14 @@ bool IfcGeom::util::boolean_operation(const boolean_settings& settings, const To
|
||||
#endif
|
||||
std::string str_str = str.str();
|
||||
if (str_str.size()) {
|
||||
Logger::Notice(str_str);
|
||||
logger::notice(str_str);
|
||||
}
|
||||
}
|
||||
if (!success) {
|
||||
if (allow_retry) {
|
||||
return boolean_operation(settings, a, b, op, result, new_fuzziness);
|
||||
} else {
|
||||
Logger::Notice("No longer attempting boolean operation with higher fuzziness");
|
||||
logger::notice("No longer attempting boolean operation with higher fuzziness");
|
||||
}
|
||||
}
|
||||
return success && !result.IsNull();
|
||||
|
||||
@@ -35,13 +35,13 @@
|
||||
namespace IfcGeom {
|
||||
namespace util {
|
||||
|
||||
void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r);
|
||||
IFC_GEOMLIBRARY_API void copy_operand(const TopTools_ListOfShape& l, TopTools_ListOfShape& r);
|
||||
|
||||
TopoDS_Shape copy_operand(const TopoDS_Shape& s);
|
||||
IFC_GEOMLIBRARY_API TopoDS_Shape copy_operand(const TopoDS_Shape& s);
|
||||
|
||||
double min_edge_length(const TopoDS_Shape& a);
|
||||
IFC_GEOMLIBRARY_API double min_edge_length(const TopoDS_Shape& a);
|
||||
|
||||
double min_vertex_edge_distance(const TopoDS_Shape& a, double min_search, double max_search);
|
||||
IFC_GEOMLIBRARY_API double min_vertex_edge_distance(const TopoDS_Shape& a, double min_search, double max_search);
|
||||
|
||||
class points_on_planar_face_generator {
|
||||
private:
|
||||
@@ -69,35 +69,35 @@ namespace IfcGeom {
|
||||
bool operator()(gp_Pnt& p);
|
||||
};
|
||||
|
||||
bool faces_overlap(const TopoDS_Face& f, const TopoDS_Face& g);
|
||||
IFC_GEOMLIBRARY_API bool faces_overlap(const TopoDS_Face& f, const TopoDS_Face& g);
|
||||
|
||||
double min_face_face_distance(const TopoDS_Shape& a, double max_search);
|
||||
IFC_GEOMLIBRARY_API double min_face_face_distance(const TopoDS_Shape& a, double max_search);
|
||||
|
||||
int bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c);
|
||||
IFC_GEOMLIBRARY_API int bounding_box_overlap(double p, const TopoDS_Shape& a, const TopTools_ListOfShape& b, TopTools_ListOfShape& c);
|
||||
|
||||
bool get_edge_axis(const TopoDS_Edge& e, gp_Ax1& ax);
|
||||
IFC_GEOMLIBRARY_API bool get_edge_axis(const TopoDS_Edge& e, gp_Ax1& ax);
|
||||
|
||||
bool is_subset(const TopTools_IndexedMapOfShape& lhs, const TopTools_IndexedMapOfShape& rhs);
|
||||
IFC_GEOMLIBRARY_API bool is_subset(const TopTools_IndexedMapOfShape& lhs, const TopTools_IndexedMapOfShape& rhs);
|
||||
|
||||
bool is_extrusion(const gp_Vec& v, const TopoDS_Shape& s, TopoDS_Face& base, std::pair<double, double>& interval);
|
||||
IFC_GEOMLIBRARY_API bool is_extrusion(const gp_Vec& v, const TopoDS_Shape& s, TopoDS_Face& base, std::pair<double, double>& interval);
|
||||
|
||||
int eliminate_touching_operands(double prec, const TopoDS_Shape& a, const TopTools_ListOfShape& bs, TopTools_ListOfShape& c);
|
||||
IFC_GEOMLIBRARY_API int eliminate_touching_operands(double prec, const TopoDS_Shape& a, const TopTools_ListOfShape& bs, TopTools_ListOfShape& c);
|
||||
|
||||
int eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c);
|
||||
IFC_GEOMLIBRARY_API int eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c);
|
||||
|
||||
bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, TopoDS_Shape& result, double eps);
|
||||
IFC_GEOMLIBRARY_API bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, TopoDS_Shape& result, double eps);
|
||||
|
||||
struct boolean_settings {
|
||||
bool debug, attempt_2d;
|
||||
double precision;
|
||||
};
|
||||
|
||||
bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopTools_ListOfShape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
|
||||
bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
IFC_GEOMLIBRARY_API bool boolean_operation(const boolean_settings& settings, const TopoDS_Shape&, const TopoDS_Shape&, BOPAlgo_Operation, TopoDS_Shape&, double fuzziness = -1.);
|
||||
|
||||
TopoDS_Shape ensure_fit_for_subtraction(const TopoDS_Shape& shape, double tol);
|
||||
IFC_GEOMLIBRARY_API TopoDS_Shape ensure_fit_for_subtraction(const TopoDS_Shape& shape, double tol);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user