build: update OCCT to 8.0.1 (faster STEP and Design tab, Windows STEP crash fix) (#16089)

This commit is contained in:
Kris Austin
2026-10-04 12:36:54 -03:00
committed by GitHub
parent 0fd04ff07c
commit 78a4f2867c
22 changed files with 1665 additions and 476 deletions
+3
View File
@@ -10,3 +10,6 @@
# resume after `call :label`. With LF endings that offset can land wrong and the
# label lookup fails, so keep these CRLF whatever the platform.
*.bat text eol=crlf
# OCCT BRep fixtures, kept byte for byte as OCCT wrote them.
*.brep -text
+2 -1
View File
@@ -1131,7 +1131,8 @@ function(orcaslicer_copy_dlls target config postfix output_dlls)
if (NOT OCCT_LIBS)
message(FATAL_ERROR "OCCT_LIBS is not set; libslic3r must be configured first.")
endif ()
set(_occt_bin "${CMAKE_PREFIX_PATH}/bin/occt")
string(TOUPPER "${config}" _config_upper)
set(_occt_bin "${OCCT_BIN_DIR_${_config_upper}}")
set(_occt_dlls "")
set(_occt_staged "")
set(_missing_occt "")
-264
View File
@@ -1,264 +0,0 @@
diff --git a/adm/cmake/occt_defs_flags.cmake b/adm/cmake/occt_defs_flags.cmake
index 00000000..00000001 100644
--- a/adm/cmake/occt_defs_flags.cmake
+++ b/adm/cmake/occt_defs_flags.cmake
@@ -134,7 +134,11 @@
set (CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
endif()
# Optimize size of binaries
- set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-s ${CMAKE_SHARED_LINKER_FLAGS}")
+ # clang-cl reports the Clang compiler ID, and OCCT builds shared on Windows,
+ # where the MSVC-style linker gets this flag as an argument it does not know.
+ if (NOT WIN32)
+ set (CMAKE_SHARED_LINKER_FLAGS "-Wl,-s ${CMAKE_SHARED_LINKER_FLAGS}")
+ endif()
elseif(MINGW)
add_definitions(-D_WIN32_WINNT=0x0601)
# _WIN32_WINNT=0x0601 (use Windows 7 SDK)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d98acc0f..28eb8eb4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -225,7 +225,7 @@ if (NOT DEFINED INSTALL_DIR_BIN)
if ("${INSTALL_DIR_LAYOUT}" STREQUAL "Unix")
set (INSTALL_DIR_BIN "bin" CACHE PATH "${INSTALL_DIR_BIN_DESCR}")
else()
- set (INSTALL_DIR_BIN "${OS_WITH_BIT}/${COMPILER}/bin" CACHE PATH "${INSTALL_DIR_BIN_DESCR}")
+ set (INSTALL_DIR_BIN "bin/occt" CACHE PATH "${INSTALL_DIR_BIN_DESCR}")
endif()
endif()
@@ -243,11 +243,11 @@ if (NOT DEFINED INSTALL_DIR_LIB)
if ("${INSTALL_DIR_LAYOUT}" STREQUAL "Unix")
set (INSTALL_DIR_LIB "lib" CACHE PATH "${INSTALL_DIR_LIB_DESCR}")
else()
- set (INSTALL_DIR_LIB "${OS_WITH_BIT}/${COMPILER}/lib" CACHE PATH "${INSTALL_DIR_LIB_DESCR}")
+ set (INSTALL_DIR_LIB "lib/occt" CACHE PATH "${INSTALL_DIR_LIB_DESCR}")
endif()
endif()
-# OCCT headers: <prefix>/inc for windows,
+# OCCT headers: <prefix>/include for windows,
# <prefix>/include/opencascade-7.0.0 for unix
if (NOT DEFINED INSTALL_DIR_INCLUDE)
if ("${INSTALL_DIR_LAYOUT}" STREQUAL "Unix")
@@ -256,7 +256,7 @@ if (NOT DEFINED INSTALL_DIR_INCLUDE)
set (INSTALL_DIR_INCLUDE "include/opencascade-${OCC_VERSION_STRING_EXT}" CACHE PATH "${INSTALL_DIR_INCLUDE_DESCR}" FORCE)
endif()
else()
- set (INSTALL_DIR_INCLUDE "inc" CACHE PATH "${INSTALL_DIR_INCLUDE_DESCR}")
+ set (INSTALL_DIR_INCLUDE "include/occt" CACHE PATH "${INSTALL_DIR_INCLUDE_DESCR}")
endif()
endif()
@@ -330,7 +330,7 @@ if (NOT DEFINED INSTALL_DIR_CMAKE)
set (INSTALL_DIR_CMAKE "lib/cmake/opencascade" CACHE PATH "${INSTALL_DIR_CMAKE_DESCR}")
endif()
else()
- set (INSTALL_DIR_CMAKE "cmake" CACHE PATH "${INSTALL_DIR_CMAKE_DESCR}")
+ set (INSTALL_DIR_CMAKE "lib/cmake/occt" CACHE PATH "${INSTALL_DIR_CMAKE_DESCR}")
endif()
endif()
@@ -338,13 +338,13 @@ endif()
OCCT_INCLUDE_CMAKE_FILE ("adm/cmake/occt_resources")
# install LICENSE_LGPL_21.txt and OCCT_LGPL_EXCEPTION.txt files
-if ("${INSTALL_DIR_LAYOUT}" STREQUAL "Unix")
- OCCT_INSTALL_FILE_OR_DIR ("LICENSE_LGPL_21.txt" "${INSTALL_DIR_DOC}")
- OCCT_INSTALL_FILE_OR_DIR ("OCCT_LGPL_EXCEPTION.txt" "${INSTALL_DIR_DOC}")
-else()
- OCCT_INSTALL_FILE_OR_DIR ("LICENSE_LGPL_21.txt" ".")
- OCCT_INSTALL_FILE_OR_DIR ("OCCT_LGPL_EXCEPTION.txt" ".")
-endif()
+#if ("${INSTALL_DIR_LAYOUT}" STREQUAL "Unix")
+# OCCT_INSTALL_FILE_OR_DIR ("LICENSE_LGPL_21.txt" "${INSTALL_DIR_DOC}")
+# OCCT_INSTALL_FILE_OR_DIR ("OCCT_LGPL_EXCEPTION.txt" "${INSTALL_DIR_DOC}")
+#else()
+# OCCT_INSTALL_FILE_OR_DIR ("LICENSE_LGPL_21.txt" ".")
+# OCCT_INSTALL_FILE_OR_DIR ("OCCT_LGPL_EXCEPTION.txt" ".")
+#endif()
if(APPLE)
set (INSTALL_NAME_DIR "" CACHE STRING "install_name library suffix on OS X (e.g. @executable_path/../Frameworks)")
@@ -850,34 +850,34 @@ endif()
# build directories
if (SINGLE_GENERATOR)
- set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/lib${BIN_LETTER}")
- set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin${BIN_LETTER}")
- set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/lib${BIN_LETTER}")
+ set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/occt")
+ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/occt")
+ set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib/occt")
if (WIN32)
- set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin${BIN_LETTER}")
+ set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/occt")
endif()
endif()
-set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/lib")
-set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin")
-set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/lib")
+set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/lib/occt")
+set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/occt")
+set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/lib/occt")
-set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/libi")
-set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bini")
-set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/libi")
+set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/lib/occt/RelWithDebInfo")
+set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin/occt/RelWithDebInfo")
+set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/lib/occt/RelWithDebInfo")
-set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/libd")
-set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bind")
-set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/libd")
+set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/lib/occt/Debug")
+set (CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/occt/Debug")
+set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/lib/occt/Debug")
if (WIN32)
- set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin")
- set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bini")
- set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bind")
+ set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin/occt")
+ set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin/occt/RelWithDebInfo")
+ set (CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/occt/Debug")
endif()
string(TIMESTAMP CURRENT_TIME "%H:%M:%S")
-message (STATUS "\nInfo: \(${CURRENT_TIME}\) Start collecting all OCCT header files into ${CMAKE_BINARY_DIR}/inc ...")
+message (STATUS "\nInfo: \(${CURRENT_TIME}\) Start collecting all OCCT header files into ${CMAKE_BINARY_DIR}/include/occt ...")
# collect all the headers to <binary dir>/inc folder
COLLECT_AND_INSTALL_OCCT_HEADER_FILES ("${CMAKE_BINARY_DIR}" "${BUILD_TOOLKITS}" "${CMAKE_SOURCE_DIR}/src" "${INSTALL_DIR_INCLUDE}")
@@ -984,9 +984,9 @@ if (EXISTS "${INSTALL_DIR}/${INSTALL_DIR_SCRIPT}/custom.${SCRIPT_EXT}")
set (CUSTOM_CONTENT "${CUSTOM_CONTENT} ${ADDITIONAL_CUSTOM_CONTENT}")
- file (WRITE "${INSTALL_DIR}/${INSTALL_DIR_SCRIPT}/custom.${SCRIPT_EXT}" "${CUSTOM_CONTENT}")
+ #file (WRITE "${INSTALL_DIR}/${INSTALL_DIR_SCRIPT}/custom.${SCRIPT_EXT}" "${CUSTOM_CONTENT}")
else()
- OCCT_CONFIGURE_AND_INSTALL ("adm/templates/custom.${SCRIPT_EXT}.main" "custom.${SCRIPT_EXT}" "custom.${SCRIPT_EXT}" "${INSTALL_DIR_SCRIPT}")
+ #OCCT_CONFIGURE_AND_INSTALL ("adm/templates/custom.${SCRIPT_EXT}.main" "custom.${SCRIPT_EXT}" "custom.${SCRIPT_EXT}" "${INSTALL_DIR_SCRIPT}")
endif()
if (WIN32)
@@ -1007,7 +1007,7 @@ endforeach()
# write current custom.bat/sh (for install directory)
set (SUB_CUSTOM_BUILD_NAME "custom_${COMPILER}_${COMPILER_BITNESS}.install.${SCRIPT_EXT}")
-OCCT_CONFIGURE_AND_INSTALL ("adm/templates/custom.install.${SCRIPT_EXT}.in" "${SUB_CUSTOM_BUILD_NAME}" "${SUB_CUSTOM_NAME}" "${INSTALL_DIR_SCRIPT}")
+#OCCT_CONFIGURE_AND_INSTALL ("adm/templates/custom.install.${SCRIPT_EXT}.in" "${SUB_CUSTOM_BUILD_NAME}" "${SUB_CUSTOM_NAME}" "${INSTALL_DIR_SCRIPT}")
# write current custom.bat/sh (for build directory)
OCCT_CONFIGURE ("adm/templates/custom.build.${SCRIPT_EXT}.in" "${SUB_CUSTOM_NAME}")
@@ -1019,9 +1019,9 @@ endif()
if (WIN32)
# env script for draw in building environment
- OCCT_CONFIGURE ("adm/templates/env.${SCRIPT_EXT}.in" "env.${SCRIPT_EXT}")
+ #OCCT_CONFIGURE ("adm/templates/env.${SCRIPT_EXT}.in" "env.${SCRIPT_EXT}")
# install env script
- install (FILES "${CMAKE_BINARY_DIR}/env.${SCRIPT_EXT}" DESTINATION "${INSTALL_DIR_SCRIPT}")
+ #install (FILES "${CMAKE_BINARY_DIR}/env.${SCRIPT_EXT}" DESTINATION "${INSTALL_DIR_SCRIPT}")
# copy build.bat and install.bat scripts to CMake binary folder
OCCT_COPY_FILE_OR_DIR ("adm/templates/build.bat" "${CMAKE_BINARY_DIR}")
OCCT_COPY_FILE_OR_DIR ("adm/templates/install.bat" "${CMAKE_BINARY_DIR}")
@@ -1043,12 +1043,12 @@ endif()
FILE_TO_LIST ("adm/RESOURCES" RESOURCES)
foreach(RESOURCE ${RESOURCES})
get_filename_component(RESOURCE_FOLDER ${RESOURCE} DIRECTORY)
- if(NOT "${RESOURCE_FOLDER}" STREQUAL "")
- get_filename_component(RESOURCE_FOLDER ${RESOURCE_FOLDER} NAME)
- OCCT_INSTALL_FILE_OR_DIR ("src/${RESOURCE}" "${INSTALL_DIR_RESOURCE}/${RESOURCE_FOLDER}")
- else()
- OCCT_INSTALL_FILE_OR_DIR ("src/${RESOURCE}" "${INSTALL_DIR_RESOURCE}")
- endif()
+ #if(NOT "${RESOURCE_FOLDER}" STREQUAL "")
+ # get_filename_component(RESOURCE_FOLDER ${RESOURCE_FOLDER} NAME)
+ # OCCT_INSTALL_FILE_OR_DIR ("src/${RESOURCE}" "${INSTALL_DIR_RESOURCE}/${RESOURCE_FOLDER}")
+ #else()
+ # OCCT_INSTALL_FILE_OR_DIR ("src/${RESOURCE}" "${INSTALL_DIR_RESOURCE}")
+ #endif()
endforeach()
if (BUILD_SAMPLES_QT)
diff --git a/adm/cmake/occt_macros.cmake b/adm/cmake/occt_macros.cmake
index 224c96b1..8c94a1c5 100644
--- a/adm/cmake/occt_macros.cmake
+++ b/adm/cmake/occt_macros.cmake
@@ -608,7 +608,7 @@ macro (OCCT_INSERT_CODE_FOR_TARGET)
install(CODE "if (\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Rr][Ee][Ll][Ee][Aa][Ss][Ee])$\")
set (OCCT_INSTALL_BIN_LETTER \"\")
elseif (\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Rr][Ee][Ll][Ww][Ii][Tt][Hh][Dd][Ee][Bb][Ii][Nn][Ff][Oo])$\")
- set (OCCT_INSTALL_BIN_LETTER \"i\")
+ set (OCCT_INSTALL_BIN_LETTER \"\")
elseif (\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\")
set (OCCT_INSTALL_BIN_LETTER \"d\")
endif()")
diff --git a/adm/cmake/occt_toolkit.cmake b/adm/cmake/occt_toolkit.cmake
index 550e0e2f..7ac1a3b8 100644
--- a/adm/cmake/occt_toolkit.cmake
+++ b/adm/cmake/occt_toolkit.cmake
@@ -241,7 +241,7 @@
else()
set (aReleasePdbConf)
endif()
- install (FILES ${CMAKE_BINARY_DIR}/${OS_WITH_BIT}/${COMPILER}/bin\${OCCT_INSTALL_BIN_LETTER}/${PROJECT_NAME}.pdb
+ install (FILES $<TARGET_PDB_FILE:${PROJECT_NAME}>
CONFIGURATIONS Debug ${aReleasePdbConf} RelWithDebInfo
DESTINATION "${INSTALL_DIR_BIN}\${OCCT_INSTALL_BIN_LETTER}")
endif()
diff --git a/src/Font/Font_FTFont.cxx b/src/Font/Font_FTFont.cxx
index 5ae9899f..0a17372b 100644
--- a/src/Font/Font_FTFont.cxx
+++ b/src/Font/Font_FTFont.cxx
@@ -103,9 +103,11 @@ bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData,
{
throw Standard_ProgramError ("Font_FTFont, Light and Normal hinting styles are mutually exclusive");
}
+#ifdef HAVE_FREETYPE
setLoadFlag (FT_LOAD_TARGET_LIGHT, (theParams.FontHinting & Font_Hinting_Light) != 0);
setLoadFlag (FT_LOAD_NO_HINTING, (theParams.FontHinting & Font_Hinting_Normal) == 0
&& (theParams.FontHinting & Font_Hinting_Light) == 0);
+#endif
// manage native / autohinting
if ((theParams.FontHinting & Font_Hinting_ForceAutohint) != 0
@@ -113,8 +115,10 @@ bool Font_FTFont::Init (const Handle(NCollection_Buffer)& theData,
{
throw Standard_ProgramError ("Font_FTFont, ForceAutohint and NoAutohint are mutually exclusive");
}
+#ifdef HAVE_FREETYPE
setLoadFlag (FT_LOAD_FORCE_AUTOHINT, (theParams.FontHinting & Font_Hinting_ForceAutohint) != 0);
setLoadFlag (FT_LOAD_NO_AUTOHINT, (theParams.FontHinting & Font_Hinting_NoAutohint) != 0);
+#endif
if (!myFTLib->IsValid())
{
From 7236e83dcc1e7284e66dc61e612154617ef715d6 Mon Sep 17 00:00:00 2001
From: dpasukhi <dpasukhi@opencascade.com>
Date: Tue, 27 Aug 2024 11:33:29 +0100
Subject: [PATCH] 0033808: Coding - FreeType Use unsigned point and contour
indexing in `FT_Outline`
Changes to auto instead of specific type
---
src/StdPrs/StdPrs_BRepFont.cxx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/StdPrs/StdPrs_BRepFont.cxx b/src/StdPrs/StdPrs_BRepFont.cxx
index ab2d9b3c9f..cd701879b1 100644
--- a/src/StdPrs/StdPrs_BRepFont.cxx
+++ b/src/StdPrs/StdPrs_BRepFont.cxx
@@ -457,7 +457,7 @@ Standard_Boolean StdPrs_BRepFont::renderGlyph (const Standard_Utf32Char theChar,
for (short aContour = 0, aStartIndex = 0; aContour < anOutline->n_contours; ++aContour)
{
const FT_Vector* aPntList = &anOutline->points[aStartIndex];
- const char* aTags = &anOutline->tags[aStartIndex];
+ const auto* aTags = &anOutline->tags[aStartIndex];
const short anEndIndex = anOutline->contours[aContour];
const short aPntsNb = (anEndIndex - aStartIndex) + 1;
aStartIndex = anEndIndex + 1;
+18 -18
View File
@@ -1,5 +1,5 @@
# clang-cl cannot emit IGESAppli_GeneralModule.cxx on ARM64
# (llvm/llvm-project#62081). cl and clang-cl share an ABI.
# clang-cl cannot emit some OCCT sources for ARM64 (llvm/llvm-project#62081).
# cl and clang-cl share an ABI.
set(_occt_compiler_args "")
if ("${DEPS_ARCH}" STREQUAL "arm64" AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
set(_occt_compiler_args -DCMAKE_C_COMPILER:STRING=cl -DCMAKE_CXX_COMPILER:STRING=cl)
@@ -15,31 +15,31 @@ endif()
# (fillet/offset/loft), whose only consumer is the parametric Design/CAD tab. With it OFF
# the deps prefix matches upstream exactly.
#
# With it ON the delta is THREE toolkits, not two: TKFillet (7.40 MiB archive, used via
# BRepFilletAPI), TKOffset (5.38 MiB, used via BRepOffsetAPI) and TKFeat (4.42 MiB), which
# nothing here references but which the module flag builds anyway -- it is all-or-nothing
# per module. The module's other nine toolkits are built either way, because DataExchange
# (the STEP path upstream already ships) depends on them.
# With it ON OCCT also builds TKFillet (used via BRepFilletAPI), TKOffset (used via
# BRepOffsetAPI), and TKFeat, TKHelix, TKXMesh and TKExpress, which nothing here references
# but which the module flag builds anyway, since module flags are all-or-nothing. The
# module's other toolkits are built either way, because DataExchange (the STEP path)
# depends on them.
#
# On macOS/Linux OCCT links statically, so an unreferenced toolkit costs build time and no
# shipped bytes. The Windows figure is a real DLL cost and has NOT been measured -- an
# earlier "3.77 MiB, Windows only" note here covered only two of the three toolkits and is
# not a number to quote. See docs/HLSD/design-tab.md.
if (IN_GIT_REPO)
set(OCCT_DIRECTORY_FLAG --directory ${BINARY_DIR_REL}/dep_OCCT-prefix/src/dep_OCCT)
endif ()
# shipped bytes. Windows ships only the DLLs libslic3r links, so the tab adds the TKFillet,
# TKOffset and TKBool DLLs. See docs/HLSD/design-tab.md.
orcaslicer_add_cmake_project(OCCT
URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_6_0.zip
URL_HASH SHA256=28334f0e98f1b1629799783e9b4d21e05349d89e695809d7e6dfa45ea43e1dbc
#PATCH_COMMAND ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/0001-OCCT-fix.patch
PATCH_COMMAND git apply ${OCCT_DIRECTORY_FLAG} --verbose --ignore-space-change --whitespace=fix ${CMAKE_CURRENT_LIST_DIR}/0001-OCCT-fix.patch
URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V8_0_1.zip
URL_HASH SHA256=7c033d917ee8f040c0512d289dcc5f02c148889d5bac17c3e25639accb44f0da
#DEPENDS dep_Boost
DEPENDS ${FREETYPE_PKG}
CMAKE_ARGS
-DCMAKE_CXX_STANDARD=17
-DBUILD_LIBRARY_TYPE=${library_build_type}
# With the Unix layout, OCCT's resources and licenses go under share/ and its scripts
# into bin/occt on Windows too. libslic3r finds the CMake package in lib/cmake/occt.
-DINSTALL_DIR_LAYOUT=Unix
-DINSTALL_DIR_BIN=bin/occt
-DINSTALL_DIR_LIB=lib/occt
-DINSTALL_DIR_INCLUDE=include/occt
-DINSTALL_DIR_CMAKE=lib/cmake/occt
-DUSE_TK=OFF
-DUSE_TBB=OFF
#-DUSE_FREETYPE=OFF
+9 -8
View File
@@ -51,14 +51,13 @@ widens the existing OCCT build by one module flag in `deps/OCCT/OCCT.cmake`:
-DBUILD_MODULE_ModelingAlgorithms=${SLIC3R_CAD}
```
Most of that module's twelve toolkits were already being built, because `DataExchange` — the
STEP path upstream ships — depends on them. The delta is `TKFillet` (used through
`BRepFilletAPI`), `TKOffset` (`BRepOffsetAPI`) and `TKFeat`, which nothing here references but
which the module flag builds anyway, because OCCT's module flags are all-or-nothing. On macOS
and Linux OCCT links statically, so an unreferenced toolkit costs build time and no shipped
bytes; on Windows OCCT builds shared, so the cost there is real DLL bytes. That Windows figure
has not been measured, and `OCCT.cmake` says so rather than carrying a number that was derived
from an incomplete toolkit list.
Most of that module's toolkits are built either way, because `DataExchange`, which the STEP
importer uses, depends on them. With the flag on, OCCT also builds `TKFillet` (used through
`BRepFilletAPI`), `TKOffset` (`BRepOffsetAPI`), and `TKFeat`, `TKHelix`, `TKXMesh` and
`TKExpress`, which nothing here references but which the module flag builds anyway, because
OCCT's module flags are all-or-nothing. On macOS and Linux OCCT links statically, so an
unreferenced toolkit costs build time and no shipped bytes. On Windows OCCT builds shared and
only the linked toolkits ship, so the tab adds the `TKFillet`, `TKOffset` and `TKBool` DLLs.
On Windows the packaging step asserts that every linked OCCT toolkit has a shipped DLL and
fails the configure with the name of any that is missing, because the alternative failure — a
@@ -117,6 +116,8 @@ that keep it survivable are:
`Import` features embed the imported solid as an OCCT BRep string inside the recipe rather than
referencing the source file, so a project opens without the STEP or mesh it was built from.
The cost is that saved projects are coupled to an OCCT BRep revision.
`tests/data/cad_brep_occt76.brep` holds a solid written by OCCT 7.6, and its test fails if the
bundled OCCT can no longer read it.
## The interaction contract
@@ -301,10 +301,10 @@ modules:
sha256: a63ae025bb0a14f119e73250f2c923f4bf89aa93b8d4fafa4a9f5353a96a765a
dest: external-packages/CURL
# OCCT (OpenCASCADE) V7_6_0
# OCCT (OpenCASCADE) V8_0_1
- type: file
url: https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_6_0.zip
sha256: 28334f0e98f1b1629799783e9b4d21e05349d89e695809d7e6dfa45ea43e1dbc
url: https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V8_0_1.zip
sha256: 7c033d917ee8f040c0512d289dcc5f02c148889d5bac17c3e25639accb44f0da
dest: external-packages/OCCT
# OpenCV 4.6.0
+24 -39
View File
@@ -37,10 +37,9 @@
#include <cstdint>
#include <cereal/cereal.hpp>
#include <gp_Pln.hxx>
#include <TopTools_ListOfShape.hxx>
#include <NCollection_List.hxx>
#include <BRepPrimAPI_MakeCylinder.hxx>
#include <BRepPrimAPI_MakeCone.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <BRepCheck_Analyzer.hxx>
#include <BRepLib.hxx>
@@ -53,7 +52,7 @@
#include <Geom_ConicalSurface.hxx>
#include <Geom2d_TrimmedCurve.hxx>
#include <GeomAbs_Shape.hxx> // SurfaceFill: GeomAbs_C0
#include <GCE2d_MakeSegment.hxx>
#include <GC_MakeSegment2d.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopAbs.hxx>
@@ -105,7 +104,7 @@ static TopoDS_Wire make_helix_wire(const gp_Ax3& axis, double radius,
// In the surface (u,v) parametrization u is the angle, v the axial height.
gp_Pnt2d p0(0.0, 0.0);
gp_Pnt2d p1(2.0 * M_PI * turns, height);
Handle(Geom2d_TrimmedCurve) seg = GCE2d_MakeSegment(p0, p1);
Handle(Geom2d_TrimmedCurve) seg = GC_MakeSegment2d(p0, p1);
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(seg, cyl).Edge();
BRepLib::BuildCurves3d(e);
return BRepBuilderAPI_MakeWire(e).Wire();
@@ -147,14 +146,14 @@ static TopoDS_Wire make_helix_spine(const CadFeature& f, std::string& err)
double u1 = f.helix_left_handed ? -2.0 * M_PI * turns : 2.0 * M_PI * turns;
gp_Pnt2d p0(0.0, 0.0);
gp_Pnt2d p1(u1, H);
Handle(Geom2d_TrimmedCurve) seg = GCE2d_MakeSegment(p0, p1);
Handle(Geom2d_TrimmedCurve) seg = GC_MakeSegment2d(p0, p1);
e = BRepBuilderAPI_MakeEdge(seg, cone).Edge();
} else {
Handle(Geom_CylindricalSurface) cyl = new Geom_CylindricalSurface(ax3, R);
double u1 = f.helix_left_handed ? -2.0 * M_PI * turns : 2.0 * M_PI * turns;
gp_Pnt2d p0(0.0, 0.0);
gp_Pnt2d p1(u1, H);
Handle(Geom2d_TrimmedCurve) seg = GCE2d_MakeSegment(p0, p1);
Handle(Geom2d_TrimmedCurve) seg = GC_MakeSegment2d(p0, p1);
e = BRepBuilderAPI_MakeEdge(seg, cyl).Edge();
}
BRepLib::BuildCurves3d(e);
@@ -193,7 +192,7 @@ static TopoDS_Wire make_thread_profile(const gp_Pnt& origin, const gp_Dir& xdir,
gp_Pnt top (origin.XYZ() + (vx * inner).XYZ() + (vz * ( half)).XYZ());
gp_Pnt bot (origin.XYZ() + (vx * inner).XYZ() + (vz * (-half)).XYZ());
gp_Pnt apex(origin.XYZ() + (vx * crest).XYZ());
BRepBuilderAPI_MakePolygon poly(top, bot, apex, Standard_True);
BRepBuilderAPI_MakePolygon poly(top, bot, apex, true);
return poly.Wire(); // closed triangle, swept by MakePipeShell with a fixed binormal
}
@@ -2368,10 +2367,12 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
TopoDS_Wire wire = build_sketch_wire(sk);
if (wire.IsNull()) throw std::runtime_error("surface-extrude: empty profile");
gp_Dir nrm(sk.plane.normal.x(), sk.plane.normal.y(), sk.plane.normal.z());
gp_Vec v(nrm.XYZ() * f.distance);
TopoDS_Shape shell = BRepPrimAPI_MakePrism(wire, v, false, true).Shape();
if (shell.IsNull()) throw std::runtime_error("surface-extrude: prism failed");
result = shell; have_body = true;
try {
result = SketchEngine::make_prism(wire, gp_Vec(nrm.XYZ() * f.distance));
} catch (const std::exception& e) {
throw std::runtime_error(std::string("surface-extrude: ") + (*e.what() ? e.what() : "prism failed"));
}
have_body = true;
break;
}
case CadFeatureType::SurfaceRevolve: {
@@ -2584,7 +2585,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
double h = f.rib_thickness * 0.5;
Vec2d q0 = a + perp*h, q1 = b + perp*h, q2 = b - perp*h, q3 = a - perp*h;
auto w3 = [&](const Vec2d& p){ Vec3d w = pl.to_world(p); return gp_Pnt(w.x(),w.y(),w.z()); };
BRepBuilderAPI_MakePolygon poly(w3(q0), w3(q1), w3(q2), w3(q3), Standard_True);
BRepBuilderAPI_MakePolygon poly(w3(q0), w3(q1), w3(q2), w3(q3), true);
if (!poly.IsDone()) throw std::runtime_error("rib: profile failed");
TopoDS_Shape wall = SketchEngine::make_extrude(poly.Wire(), pl, f.rib_depth, false, 0.0);
if (wall.IsNull()) throw std::runtime_error("rib: extrude failed");
@@ -2746,7 +2747,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
if (!have_body) throw std::runtime_error("shell needs a body");
// Hollow the body to a wall thickness; the picked face (if any) is removed so the
// shell is open there. MakeThickSolidByJoin with a NEGATIVE offset shells inward.
TopTools_ListOfShape remove;
NCollection_List<TopoDS_Shape> remove;
if (f.shell_face >= 0) {
TopoDS_Face fc = GeometryEngine::face_by_index(result, f.shell_face);
if (!fc.IsNull()) remove.Append(fc);
@@ -2769,7 +2770,7 @@ void CadDocument::apply_feature(TopoDS_Shape& result, bool& have_body,
// ponytail: neutral plane / pull direction fixed to world up; pick-based neutral plane
// deferred (same as the datum-plane pick types, dgv).
Bnd_Box bb; BRepBndLib::Add(result, bb);
Standard_Real xmin, ymin, zmin, xmax, ymax, zmax;
double xmin, ymin, zmin, xmax, ymax, zmax;
bb.Get(xmin, ymin, zmin, xmax, ymax, zmax);
gp_Dir pull(0, 0, 1);
gp_Pln neutral(gp_Pnt(0, 0, zmin), pull);
@@ -2850,7 +2851,7 @@ void CadDocument::apply_boolean(std::vector<CadBody>& bodies, const CadFeature&
const TopoDS_Shape B = bodies[tool].shape; // tool, consumed unless kept
if (A.IsNull() || B.IsNull()) return;
TopTools_ListOfShape args, tools;
NCollection_List<TopoDS_Shape> args, tools;
args.Append(A);
tools.Append(B);
auto run = [&](BRepAlgoAPI_BooleanOperation& bop) -> TopoDS_Shape {
@@ -3091,7 +3092,7 @@ void CadDocument::apply_thicken_surface(std::vector<CadBody>& bodies, const CadF
int n_faces = 0;
for (TopExp_Explorer fe(sheet, TopAbs_FACE); fe.More(); fe.Next()) ++n_faces;
TopTools_ListOfShape caps;
NCollection_List<TopoDS_Shape> caps;
if (n_faces > 1) {
ShapeAnalysis_FreeBounds fb(sheet);
for (TopExp_Explorer we(fb.GetClosedWires(), TopAbs_WIRE); we.More(); we.Next()) {
@@ -3113,7 +3114,7 @@ void CadDocument::apply_thicken_surface(std::vector<CadBody>& bodies, const CadF
} else {
BRepBuilderAPI_Sewing sewer(1.0e-3);
sewer.Add(sheet);
for (TopTools_ListIteratorOfListOfShape it(caps); it.More(); it.Next())
for (NCollection_List<TopoDS_Shape>::Iterator it(caps); it.More(); it.Next())
sewer.Add(it.Value());
sewer.Perform();
@@ -3674,13 +3675,8 @@ bool CadDocument::recompute()
if (b.source_feature < 0)
b.source_feature = int(fi);
}
} catch (const Standard_Failure& e) {
// OCCT raises Standard_Failure (NOT a std::exception) — must be caught
// here or it escapes the event handler and terminates the app.
error = e.GetMessageString() ? e.GetMessageString() : "OCCT operation failed";
return false;
} catch (const std::exception& e) {
error = e.what();
error = *e.what() ? e.what() : "OCCT operation failed";
return false;
} catch (...) {
error = "unknown geometry error";
@@ -3782,11 +3778,8 @@ bool CadDocument::preview(const CadFeature& candidate, TriangleMesh& out_mesh,
std::vector<CadBody> tmp = bodies; // start from the current committed bodies
try {
route_feature(tmp, candidate); // candidate may append a new body or mutate one
} catch (const Standard_Failure& e) {
err = e.GetMessageString() ? e.GetMessageString() : "OCCT operation failed";
return false;
} catch (const std::exception& e) {
err = e.what();
err = *e.what() ? e.what() : "OCCT operation failed";
return false;
} catch (...) {
err = "unknown geometry error";
@@ -3986,13 +3979,9 @@ bool CadDocument::deserialize_recipe(const std::string& blob)
error = "saved with an older version of the Design tab (format v"
+ std::to_string(v) + "); this project cannot be opened by this build";
return false;
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
error = std::string("CAD data could not be read")
+ (what && *what ? ": " + std::string(what) : "");
return false;
} catch (const std::exception& e) {
error = std::string("CAD data could not be read: ") + e.what();
error = std::string("CAD data could not be read")
+ (*e.what() ? ": " + std::string(e.what()) : "");
return false;
} catch (...) {
error = "CAD data could not be read";
@@ -4034,11 +4023,8 @@ bool CadDocument::export_step(const std::string& path,
err = "cannot write STEP file";
return false;
}
} catch (const Standard_Failure& e) {
err = e.GetMessageString() ? e.GetMessageString() : "OCCT failed to write STEP";
return false;
} catch (const std::exception& e) {
err = e.what();
err = *e.what() ? e.what() : "OCCT failed to write STEP";
return false;
}
return true;
@@ -4109,8 +4095,7 @@ std::vector<CadDocument::Interference> CadDocument::check_interference(double mi
if (bodies[j].shape.IsNull() || is_sheet_shape(bodies[j].shape)) continue;
double v = 0;
// A boolean that blows up on one pair must not lose the report for the others,
// and OCCT signals those as Standard_Failure, which is NOT a std::exception.
// A boolean that fails on one pair must not lose the report for the others.
try {
BRepAlgoAPI_Common common(bodies[i].shape, bodies[j].shape);
common.Build();
+14 -11
View File
@@ -27,9 +27,10 @@
#include <TopoDS_Edge.hxx>
#include <TopExp.hxx>
#include <TopTools.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopTools_ShapeMapHasher.hxx>
#include <NCollection_IndexedDataMap.hxx>
#include <NCollection_IndexedMap.hxx>
#include <NCollection_List.hxx>
#include <Poly_Triangulation.hxx>
#include <gp_Ax2.hxx>
#include <gp_Dir.hxx>
@@ -62,6 +63,8 @@
namespace Slic3r {
using ShapeIndexMap = NCollection_IndexedMap<TopoDS_Shape, TopTools_ShapeMapHasher>;
// ---- STEP import (B-rep, not mesh) ----
std::vector<TopoDS_Shape> GeometryEngine::read_step_solids(const std::string& path, std::string& err)
{
@@ -82,7 +85,7 @@ std::vector<TopoDS_Shape> GeometryEngine::read_step_solids(const std::string& pa
if (out.empty())
out.push_back(shape);
} catch (const Standard_Failure& e) {
err = e.GetMessageString() ? e.GetMessageString() : "OCCT failed to read STEP";
err = *e.what() ? e.what() : "OCCT failed to read STEP";
out.clear();
}
return out;
@@ -299,13 +302,13 @@ std::vector<TopoDS_Edge> GeometryEngine::collect_edges(const TopoDS_Shape& solid
}
// Build edge-to-face map once
TopTools_IndexedDataMapOfShapeListOfShape edgeFaceMap;
NCollection_IndexedDataMap<TopoDS_Shape, NCollection_List<TopoDS_Shape>, TopTools_ShapeMapHasher> edgeFaceMap;
TopExp::MapShapesAndAncestors(solid, TopAbs_EDGE, TopAbs_FACE, edgeFaceMap);
for (TopExp_Explorer edgeExp(solid, TopAbs_EDGE); edgeExp.More(); edgeExp.Next()) {
const TopoDS_Edge& edge = TopoDS::Edge(edgeExp.Current());
if (!edgeFaceMap.Contains(edge)) continue;
const TopTools_ListOfShape& faces = edgeFaceMap.FindFromKey(edge);
const NCollection_List<TopoDS_Shape>& faces = edgeFaceMap.FindFromKey(edge);
bool include = false;
for (auto it = faces.begin(); it != faces.end(); ++it) {
@@ -569,7 +572,7 @@ std::vector<TopoDS_Face> GeometryEngine::faces_of(const TopoDS_Shape& shape)
std::vector<TopoDS_Edge> GeometryEngine::edges_of(const TopoDS_Shape& shape)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map); // same order as edge_by_index
std::vector<TopoDS_Edge> out;
out.reserve(map.Extent());
@@ -581,7 +584,7 @@ std::vector<TopoDS_Edge> GeometryEngine::edges_of(const TopoDS_Shape& shape)
std::vector<TopoDS_Edge> GeometryEngine::edges_of_face(const TopoDS_Face& face)
{
std::vector<TopoDS_Edge> result;
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(face, TopAbs_EDGE, map);
for (int i = 1; i <= map.Extent(); ++i)
result.push_back(TopoDS::Edge(map(i)));
@@ -704,14 +707,14 @@ bool GeometryEngine::face_plane_bounds(const TopoDS_Face& face, const Vec3d& ori
int GeometryEngine::edge_count(const TopoDS_Shape& shape)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map);
return map.Extent();
}
TopoDS_Edge GeometryEngine::edge_by_index(const TopoDS_Shape& shape, int index)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map);
if (index < 0 || index >= map.Extent())
return TopoDS_Edge();
@@ -720,7 +723,7 @@ TopoDS_Edge GeometryEngine::edge_by_index(const TopoDS_Shape& shape, int index)
int GeometryEngine::edge_index_of(const TopoDS_Shape& shape, const TopoDS_Edge& edge)
{
TopTools_IndexedMapOfShape map;
ShapeIndexMap map;
TopExp::MapShapes(shape, TopAbs_EDGE, map);
int idx = map.FindIndex(edge);
return (idx > 0) ? (idx - 1) : -1;
+27 -29
View File
@@ -27,9 +27,7 @@
#include <GC_MakeArcOfEllipse.hxx>
#include <Geom_TrimmedCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <NCollection_Array1.hxx>
#include <gp_Circ.hxx>
#include <gp_Elips.hxx>
#include <gp_Ax2.hxx>
@@ -179,21 +177,23 @@ TopoDS_Wire SketchProfile::to_occt_wire(const SketchPlane& plane) const
// ---- SketchEngine ----
TopoDS_Shape SketchEngine::make_prism(const TopoDS_Shape& base, const gp_Vec& vec)
{
if (vec.Magnitude() < 1e-9) throw std::runtime_error("extrude depth is zero");
BRepPrimAPI_MakePrism prism(base, vec);
if (!prism.IsDone()) throw std::runtime_error("extrude failed");
return prism.Shape();
}
static TopoDS_Shape extrude_face_internal(const TopoDS_Face& face, const gp_Dir& dir, double length, bool symmetric)
{
gp_Vec vec = gp_Vec(dir) * length;
if (symmetric) {
gp_Vec halfVec = gp_Vec(dir) * (length / 2.0);
BRepPrimAPI_MakePrism pos(face, halfVec);
BRepPrimAPI_MakePrism neg(face, -halfVec);
if (!pos.IsDone() || !neg.IsDone()) throw std::runtime_error("Symmetric extrude failed");
BRepAlgoAPI_Fuse fuse(pos.Shape(), neg.Shape());
BRepAlgoAPI_Fuse fuse(SketchEngine::make_prism(face, halfVec), SketchEngine::make_prism(face, -halfVec));
if (!fuse.IsDone()) throw std::runtime_error("Fuse failed");
return fuse.Shape();
}
BRepPrimAPI_MakePrism prism(face, vec);
if (!prism.IsDone()) throw std::runtime_error("Extrude failed");
return prism.Shape();
return SketchEngine::make_prism(face, gp_Vec(dir) * length);
}
TopoDS_Shape SketchEngine::make_extrude(const TopoDS_Wire& wire, const SketchPlane& plane,
@@ -224,12 +224,9 @@ TopoDS_Shape SketchEngine::make_extrude_two_sided(const TopoDS_Face& face, const
{
gp_Dir dir(plane.normal.x(), plane.normal.y(), plane.normal.z());
const double u = std::abs(up), d = std::abs(down);
if (u < 1e-9 && d < 1e-9) return TopoDS_Shape();
if (d < 1e-9) { BRepPrimAPI_MakePrism p(face, gp_Vec(dir) * u); return p.Shape(); }
if (u < 1e-9) { BRepPrimAPI_MakePrism p(face, gp_Vec(dir) * -d); return p.Shape(); }
BRepPrimAPI_MakePrism pos(face, gp_Vec(dir) * u);
BRepPrimAPI_MakePrism neg(face, gp_Vec(dir) * -d);
BRepAlgoAPI_Fuse fuse(pos.Shape(), neg.Shape());
if (d < 1e-9) return make_prism(face, gp_Vec(dir) * u);
if (u < 1e-9) return make_prism(face, gp_Vec(dir) * -d);
BRepAlgoAPI_Fuse fuse(make_prism(face, gp_Vec(dir) * u), make_prism(face, gp_Vec(dir) * -d));
if (!fuse.IsDone()) throw std::runtime_error("two-sided extrude fuse failed");
return fuse.Shape();
}
@@ -240,8 +237,8 @@ TopoDS_Shape SketchEngine::make_extrude_taper(const TopoDS_Wire& wire, const Ske
gp_Dir dir(plane.normal.x(), plane.normal.y(), plane.normal.z());
auto straight = [&]() -> TopoDS_Shape {
BRepBuilderAPI_MakeFace fm(wire);
BRepPrimAPI_MakePrism prism(fm.Face(), gp_Vec(dir) * length);
return prism.Shape();
if (!fm.IsDone()) throw std::runtime_error("Failed to make face from wire");
return make_prism(fm.Face(), gp_Vec(dir) * length);
};
if (std::abs(taper_deg) >= 89.0 || std::abs(length) < 1e-9) return straight();
const double off = length * std::tan(taper_deg * M_PI / 180.0);
@@ -258,10 +255,10 @@ TopoDS_Shape SketchEngine::make_extrude_taper(const TopoDS_Wire& wire, const Ske
if (topFlat.IsNull()) return straight();
// 2) lift it along the normal by `length`
gp_Trsf tr; tr.SetTranslation(gp_Vec(dir) * length);
BRepBuilderAPI_Transform xf(topFlat, tr, Standard_True);
BRepBuilderAPI_Transform xf(topFlat, tr, true);
TopoDS_Wire topWire = TopoDS::Wire(xf.Shape());
// 3) loft base -> top into a solid
BRepOffsetAPI_ThruSections loft(Standard_True /*solid*/, Standard_False /*ruled*/);
BRepOffsetAPI_ThruSections loft(true /*solid*/, false /*ruled*/);
loft.AddWire(wire);
loft.AddWire(topWire);
loft.Build();
@@ -285,6 +282,9 @@ TopoDS_Shape SketchEngine::make_extrude_regions(
const std::vector<std::vector<std::vector<Vec2d>>>& regions,
const SketchPlane& plane, double length, bool symmetric)
{
// The loop below skips regions that fail, so a zero depth is rejected before it.
if (std::abs(length) < 1e-9) throw std::runtime_error("extrude depth is zero");
// Drop consecutive coincident points and the closing duplicate. FreeType /
// SVG flattening routinely emits repeated points which would build a
// degenerate OCCT edge and make the wire builder throw — sanitising keeps a
@@ -406,8 +406,7 @@ TopoDS_Shape SketchEngine::make_loft(const std::vector<TopoDS_Wire>& profiles, b
{
if (profiles.size() < 2)
throw std::runtime_error("loft needs at least 2 profiles");
BRepOffsetAPI_ThruSections loft(Standard_True /*solid*/,
ruled ? Standard_True : Standard_False);
BRepOffsetAPI_ThruSections loft(true /*solid*/, ruled);
for (const TopoDS_Wire& w : profiles) {
if (w.IsNull()) throw std::runtime_error("loft: null profile wire");
loft.AddWire(w);
@@ -424,8 +423,7 @@ TopoDS_Shape SketchEngine::make_loft_surface(const std::vector<TopoDS_Wire>& pro
{
if (profiles.size() < 2)
throw std::runtime_error("loft needs at least 2 profiles");
BRepOffsetAPI_ThruSections loft(Standard_False /*shell, no end caps*/,
ruled ? Standard_True : Standard_False);
BRepOffsetAPI_ThruSections loft(false /*shell, no end caps*/, ruled);
for (const TopoDS_Wire& w : profiles) {
if (w.IsNull()) throw std::runtime_error("loft: null profile wire");
loft.AddWire(w);
@@ -597,15 +595,15 @@ std::vector<TopoDS_Wire> SketchEngine::entities_to_wires(const std::vector<Sketc
const int n = int(c.ctrl.size());
const int p = n >= 4 ? 3 : (n >= 2 ? n - 1 : 0);
if (p < 1) return Handle(Geom_BSplineCurve)();
TColgp_Array1OfPnt poles(1, n);
NCollection_Array1<gp_Pnt> poles(1, n);
for (int i = 0; i < n; ++i) {
Vec3d w = plane.to_world(c.ctrl[i]);
poles.SetValue(i + 1, gp_Pnt(w.x(), w.y(), w.z()));
}
const int interior = n - p - 1; // count of single interior knots
const int nknots = interior + 2;
TColStd_Array1OfReal knots(1, nknots);
TColStd_Array1OfInteger mults(1, nknots);
NCollection_Array1<double> knots(1, nknots);
NCollection_Array1<int> mults(1, nknots);
knots.SetValue(1, 0.0); mults.SetValue(1, p + 1);
for (int i = 1; i <= interior; ++i) { knots.SetValue(i + 1, double(i)); mults.SetValue(i + 1, 1); }
knots.SetValue(nknots, double(interior + 1)); mults.SetValue(nknots, p + 1);
@@ -808,7 +806,7 @@ std::vector<TopoDS_Wire> SketchEngine::entities_to_wires(const std::vector<Sketc
wm.Add(BRepBuilderAPI_MakeEdge(va, vb).Edge());
} else if (e->type == SketchEntity::Type::EllipseArc) {
if (e->radius <= 1e-9 || e->rminor <= 1e-9) return {};
GC_MakeArcOfEllipse arc_maker(make_elips(*e), e->start_angle, e->end_angle, Standard_True);
GC_MakeArcOfEllipse arc_maker(make_elips(*e), e->start_angle, e->end_angle, true);
if (!arc_maker.IsDone()) return {};
wm.Add(BRepBuilderAPI_MakeEdge(arc_maker.Value(), va, vb).Edge());
} else if (e->type == SketchEntity::Type::Arc) {
+3
View File
@@ -7,6 +7,7 @@
#include <gp_Pln.hxx>
#include <gp_Ax3.hxx>
#include <gp_Vec.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Face.hxx>
@@ -227,6 +228,8 @@ struct SketchParams {
class SketchEngine
{
public:
// Throws on a zero vector, for which OCCT returns a degenerate solid.
static TopoDS_Shape make_prism(const TopoDS_Shape& base, const gp_Vec& vec);
static TopoDS_Shape make_extrude(const TopoDS_Wire& wire, const SketchPlane& plane,
double length, bool symmetric = false, double taper_deg = 0.0);
static TopoDS_Shape make_extrude(const TopoDS_Face& face, const SketchPlane& plane,
+24 -5
View File
@@ -648,11 +648,8 @@ find_package(JPEG REQUIRED)
find_package(Draco REQUIRED)
set(OCCT_LIBS
TKXDESTEP
TKSTEP
TKSTEP209
TKSTEPAttr
TKSTEPBase
TKDESTEP
TKDE
TKXCAF
TKXSBase
TKVCAF
@@ -699,6 +696,22 @@ if (SLIC3R_CAD)
endif ()
# Published for the Windows packaging step in the top-level CMakeLists.txt.
set(OCCT_LIBS "${OCCT_LIBS}" CACHE INTERNAL "OCCT toolkits linked by libslic3r")
if (WIN32)
# OCCT installs RelWithDebInfo and Debug builds to bin/occti and bin/occtd, so each build
# type's DLL directory is read from the imported target, falling back to the first installed
# build, as CMake does when linking.
get_target_property(_occt_configs TKernel IMPORTED_CONFIGURATIONS)
list(GET _occt_configs 0 _occt_fallback)
foreach (_build_config IN ITEMS DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
set(_occt_config ${_occt_fallback})
if (_build_config IN_LIST _occt_configs)
set(_occt_config ${_build_config})
endif ()
get_target_property(_occt_dll TKernel IMPORTED_LOCATION_${_occt_config})
get_filename_component(_occt_bin "${_occt_dll}" DIRECTORY)
set(OCCT_BIN_DIR_${_build_config} "${_occt_bin}" CACHE INTERNAL "OCCT DLL directory for ${_build_config} builds")
endforeach ()
endif ()
target_link_libraries(libslic3r
PUBLIC
@@ -733,6 +746,12 @@ target_link_libraries(libslic3r
)
if(NOT WIN32)
# OCCT's static targets name FreeType as a bare "freetype", which the macOS linker cannot
# find; this target maps that name to FREETYPE_LIBRARIES.
if (NOT TARGET freetype)
add_library(freetype INTERFACE IMPORTED GLOBAL)
target_link_libraries(freetype INTERFACE ${FREETYPE_LIBRARIES})
endif ()
# Link freetype for OCCT dependency (CAD operations need font rendering)
target_link_libraries(libslic3r PRIVATE ${FREETYPE_LIBRARIES})
if (NOT APPLE)
+17 -16
View File
@@ -47,7 +47,8 @@
#include "XCAFDoc_DocumentTool.hxx"
#include "XCAFDoc_ShapeTool.hxx"
#include "XCAFApp_Application.hxx"
#include "TDF_LabelSequence.hxx"
#include "NCollection_Sequence.hxx"
#include "TDF_Label.hxx"
#include "TopoDS_Solid.hxx"
#include "TopoDS_Compound.hxx"
#include "TopoDS_Builder.hxx"
@@ -223,9 +224,9 @@ static void getNamedSolids(const TopLoc_Location& location,
std::string fullName{name};
TopLoc_Location localLocation = location * shapeTool->GetLocation(label);
TDF_LabelSequence components;
NCollection_Sequence<TDF_Label> components;
if (shapeTool->GetComponents(referredLabel, components)) {
for (Standard_Integer compIndex = 1; compIndex <= components.Length(); ++compIndex) {
for (int compIndex = 1; compIndex <= components.Length(); ++compIndex) {
getNamedSolids(localLocation, fullName, id, shapeTool, components.Value(compIndex), namedSolids, isSplitCompound);
}
} else {
@@ -233,7 +234,7 @@ static void getNamedSolids(const TopLoc_Location& location,
TopExp_Explorer explorer;
shapeTool->GetShape(referredLabel, shape);
TopAbs_ShapeEnum shape_type = shape.ShapeType();
BRepBuilderAPI_Transform transform(shape, localLocation, Standard_True);
BRepBuilderAPI_Transform transform(shape, localLocation, true);
int i = 0;
switch (shape_type) {
case TopAbs_COMPOUND:
@@ -503,11 +504,11 @@ Step::Step_Status Step::load()
if (cb_cancel) return;
progress = 6;
m_shape_tool = XCAFDoc_DocumentTool::ShapeTool(m_doc->Main());
TDF_LabelSequence topLevelShapes;
NCollection_Sequence<TDF_Label> topLevelShapes;
m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
int topShapeLength = topLevelShapes.Length() + 1;
for (int iLabel = 1; iLabel < topShapeLength; ++iLabel) {
if (cb_cancel) return;
getNamedSolids(TopLoc_Location{}, "", id, m_shape_tool, topLevelShapes.Value(iLabel), m_name_solids);
}
@@ -562,12 +563,12 @@ Step::Step_Status Step::mesh(Model* model,
new_object->input_file = m_path.c_str();
auto task = new boost::thread(Slic3r::create_thread([&]() -> void {
TDF_LabelSequence topLevelShapes;
NCollection_Sequence<TDF_Label> topLevelShapes;
m_shape_tool->GetFreeShapes(topLevelShapes);
unsigned int id{ 1 };
Standard_Integer topShapeLength = topLevelShapes.Length() + 1;
int topShapeLength = topLevelShapes.Length() + 1;
for (Standard_Integer iLabel = 1; iLabel < topShapeLength; ++iLabel) {
for (int iLabel = 1; iLabel < topShapeLength; ++iLabel) {
progress = static_cast<double>(iLabel) / (topShapeLength-1);
if (cb_cancel) {
return;
@@ -604,10 +605,10 @@ Step::Step_Status Step::mesh(Model* model,
std::vector<Vec3f> points;
points.reserve(aNbNodes);
// BBS: count faces missing triangulation
Standard_Integer aNbFacesNoTri = 0;
int aNbFacesNoTri = 0;
// BBS: fill temporary triangulation
Standard_Integer aNodeOffset = 0;
Standard_Integer aTriangleOffet = 0;
int aNodeOffset = 0;
int aTriangleOffet = 0;
for (TopExp_Explorer anExpSF(namedSolids[i].solid, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
const TopoDS_Shape& aFace = anExpSF.Current();
TopLoc_Location aLoc;
@@ -618,15 +619,15 @@ Step::Step_Status Step::mesh(Model* model,
}
// BBS: copy nodes
gp_Trsf aTrsf = aLoc.Transformation();
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
for (int aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
aPnt.Transform(aTrsf);
points.emplace_back(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()));
}
// BBS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
Standard_Integer anId[3] = {};
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
int anId[3] = {};
for (int aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
aTri.Get(anId[0], anId[1], anId[2]);
+2 -2
View File
@@ -84,9 +84,9 @@ class StepProgressIncdicator : public Message_ProgressIndicator
public:
StepProgressIncdicator(std::atomic<bool>& stop_flag) : should_stop(stop_flag){}
Standard_Boolean UserBreak() override { return should_stop.load(); }
bool UserBreak() override { return should_stop.load(); }
void Show(const Message_ProgressScope&, const Standard_Boolean) override {
void Show(const Message_ProgressScope&, const bool) override {
std::cout << "Progress: " << std::fixed << std::setprecision(2) << 100.0 * GetPosition() << "%" << std::endl;
}
private:
+6 -6
View File
@@ -339,10 +339,10 @@ bool load_svg(const char *path, Model *model, std::string &message)
std::vector<Vec3f> points;
points.reserve(aNbNodes);
// BBS: count faces missing triangulation
Standard_Integer aNbFacesNoTri = 0;
int aNbFacesNoTri = 0;
// BBS: fill temporary triangulation
Standard_Integer aNodeOffset = 0;
Standard_Integer aTriangleOffet = 0;
int aNodeOffset = 0;
int aTriangleOffet = 0;
for (TopExp_Explorer anExpSF(namedSolids[i].shape, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
const TopoDS_Shape &aFace = anExpSF.Current();
TopLoc_Location aLoc;
@@ -353,15 +353,15 @@ bool load_svg(const char *path, Model *model, std::string &message)
}
// BBS: copy nodes
gp_Trsf aTrsf = aLoc.Transformation();
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
for (int aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
aPnt.Transform(aTrsf);
points.emplace_back(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()));
}
// BBS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
Standard_Integer anId[3];
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
int anId[3];
for (int aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
aTri.Get(anId[0], anId[1], anId[2]);
+20 -20
View File
@@ -50,6 +50,8 @@
#include "Font_BRepTextBuilder.hxx"
#include "BRepPrimAPI_MakePrism.hxx"
#include "Font_FontMgr.hxx"
#include "NCollection_Sequence.hxx"
#include "TCollection_HAsciiString.hxx"
#include <boost/log/trivial.hpp>
@@ -57,7 +59,7 @@ namespace Slic3r {
static std::map<std::string, std::string> g_occt_fonts_maps; //map<font_name, font_path>
static const std::vector<Standard_CString> fonts_suffix{ "Bold", "Medium", "Heavy", "Italic", "Oblique", "Inclined", "Light", "Thin",
static const std::vector<const char*> fonts_suffix{ "Bold", "Medium", "Heavy", "Italic", "Oblique", "Inclined", "Light", "Thin",
"Semibold", "ExtraBold", "ExtraBold", "Semilight", "SemiLight", "ExtraLight", "Extralight", "Ultralight",
"Condensed", "Ultra", "Extra", "Expanded", "Extended", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Al Tarikh"};
@@ -73,7 +75,7 @@ std::vector<std::string> init_occt_fonts()
Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
aFontMgr->InitFontDataBase();
TColStd_SequenceOfHAsciiString availFontNames;
NCollection_Sequence<Handle(TCollection_HAsciiString)> availFontNames;
aFontMgr->GetAvailableFontsNames(availFontNames);
stdFontNames.reserve(availFontNames.Size());
@@ -122,16 +124,14 @@ std::vector<std::string> init_occt_fonts()
static bool TextToBRep(const char* text, const char* font, const float theTextHeight, Font_FontAspect& theFontAspect, TopoDS_Shape& theShape, double& text_width)
{
Standard_Integer anArgIt = 1;
Standard_CString aName = "text_shape";
Standard_CString aText = text;
const char* aText = text;
Font_BRepFont aFont;
//TCollection_AsciiString aFontName("Courier");
TCollection_AsciiString aFontName(font);
Standard_Real aTextHeight = theTextHeight;
double aTextHeight = theTextHeight;
Font_FontAspect aFontAspect = theFontAspect;
Standard_Boolean anIsCompositeCurve = Standard_False;
bool anIsCompositeCurve = false;
gp_Ax3 aPenAx3(gp::XOY());
gp_Dir aNormal(0.0, 0.0, 1.0);
gp_Dir aDirection(1.0, 0.0, 0.0);
@@ -156,10 +156,10 @@ static bool TextToBRep(const char* text, const char* font, const float theTextHe
// get the text width
text_width = 0;
NCollection_String coll_str = aText;
for (NCollection_Utf8Iter anIter = coll_str.Iterator(); *anIter != 0;) {
const Standard_Utf32Char aCharThis = *anIter;
const Standard_Utf32Char aCharNext = *++anIter;
double width = aFont.AdvanceX(aCharThis, aCharNext);
for (auto anIter = coll_str.Iterator(); *anIter != 0;) {
const char32_t aCharThis = *anIter;
const char32_t aCharNext = *++anIter;
double width = aFont.AdvanceX(aCharThis, aCharNext);
text_width += width;
}
@@ -173,9 +173,9 @@ static bool Prism(const TopoDS_Shape& theBase, const float thickness, TopoDS_Sha
if (theBase.IsNull()) return false;
gp_Vec V(0.f, 0.f, thickness);
BRepPrimAPI_MakePrism* Prism = new BRepPrimAPI_MakePrism(theBase, V, Standard_False);
BRepPrimAPI_MakePrism prism(theBase, V, false);
theSolid = Prism->Shape();
theSolid = prism.Shape();
return true;
}
@@ -205,10 +205,10 @@ static void MakeMesh(TopoDS_Shape& theSolid, TriangleMesh& theMesh)
std::vector<Vec3f> points;
points.reserve(aNbNodes);
//BBS: count faces missing triangulation
Standard_Integer aNbFacesNoTri = 0;
int aNbFacesNoTri = 0;
//BBS: fill temporary triangulation
Standard_Integer aNodeOffset = 0;
Standard_Integer aTriangleOffet = 0;
int aNodeOffset = 0;
int aTriangleOffet = 0;
for (TopExp_Explorer anExpSF(theSolid, TopAbs_FACE); anExpSF.More(); anExpSF.Next()) {
const TopoDS_Shape& aFace = anExpSF.Current();
TopLoc_Location aLoc;
@@ -219,21 +219,21 @@ static void MakeMesh(TopoDS_Shape& theSolid, TriangleMesh& theMesh)
}
//BBS: copy nodes
gp_Trsf aTrsf = aLoc.Transformation();
for (Standard_Integer aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
for (int aNodeIter = 1; aNodeIter <= aTriangulation->NbNodes(); ++aNodeIter) {
gp_Pnt aPnt = aTriangulation->Node(aNodeIter);
aPnt.Transform(aTrsf);
points.emplace_back(Vec3f(aPnt.X(), aPnt.Y(), aPnt.Z()));
}
//BBS: copy triangles
const TopAbs_Orientation anOrientation = anExpSF.Current().Orientation();
for (Standard_Integer aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
for (int aTriIter = 1; aTriIter <= aTriangulation->NbTriangles(); ++aTriIter) {
Poly_Triangle aTri = aTriangulation->Triangle(aTriIter);
Standard_Integer anId[3];
int anId[3];
aTri.Get(anId[0], anId[1], anId[2]);
if (anOrientation == TopAbs_REVERSED) {
//BBS: swap 1, 2.
Standard_Integer aTmpIdx = anId[1];
int aTmpIdx = anId[1];
anId[1] = anId[2];
anId[2] = aTmpIdx;
}
+6 -24
View File
@@ -16,7 +16,6 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/log/trivial.hpp> // the offer/atlas join check reports on the log
#include <Standard_Failure.hxx>
#include <cassert>
#include <cstdarg> // offer_trace: diagnostic row dump for the offer ladder
@@ -4694,7 +4693,7 @@ void DesignPanel::on_import_svg()
// (parse + tessellate); running it inline froze the whole window — the compositor marked the
// app unresponsive and nothing repainted. The dialog is app-modal, so the document cannot be
// touched while the worker owns it. Exceptions must not escape the worker: `work` is expected
// to swallow them (OCCT throws Standard_Failure, which is not a std::exception).
// to swallow them.
static void run_off_ui_thread(wxWindow* parent, const wxString& message, const std::function<void()>& work)
{
std::atomic<bool> done{false};
@@ -4722,10 +4721,6 @@ static void run_off_ui_thread(wxWindow* parent, const wxString& message, const s
worker.join();
}
// Rebuild the document off the UI thread. Every feature op (fillet, cut, shell, boolean, ...)
// goes through recompute(), and on a heavy imported solid that is seconds of OCCT work — inline
// it freezes the window. OCCT throws Standard_Failure, which is not a std::exception and would
// terminate the process if it escaped the worker, so both are caught here.
// Keep the Model's copy of the recipe in step with the document.
//
// This used to be written in exactly ONE place — on_commit(), as a side effect of Commit to
@@ -4756,18 +4751,15 @@ void DesignPanel::sync_recipe_to_model()
Slic3r::put_other_changes();
}
// Runs recompute() off the UI thread, because on a heavy imported solid it takes seconds.
bool DesignPanel::recompute_guarded(const wxString& message)
{
bool ok = false;
run_off_ui_thread(this, message, [this, &ok]() {
try {
ok = m_doc.recompute();
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
m_doc.error = (what != nullptr && *what != '\0') ? what : "OCCT failure";
ok = false;
} catch (const std::exception& e) {
m_doc.error = e.what();
m_doc.error = *e.what() ? e.what() : "OCCT failure";
ok = false;
}
});
@@ -4792,11 +4784,8 @@ void DesignPanel::on_import_step()
run_off_ui_thread(this, _L("Reading STEP…"), [&]() {
try {
solids = GeometryEngine::read_step_solids(path, err);
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
err = (what != nullptr && *what != '\0') ? what : "OCCT failure";
} catch (const std::exception& e) {
err = e.what();
err = *e.what() ? e.what() : "OCCT failure";
}
});
if (solids.empty()) {
@@ -4820,11 +4809,8 @@ void DesignPanel::on_import_step()
run_off_ui_thread(this, _L("Rebuilding model…"), [&]() {
try {
rebuilt = m_doc.recompute();
} catch (const Standard_Failure& e) {
const char* what = e.GetMessageString();
m_doc.error = (what != nullptr && *what != '\0') ? what : "OCCT failure";
} catch (const std::exception& e) {
m_doc.error = e.what();
m_doc.error = *e.what() ? e.what() : "OCCT failure";
}
});
if (!rebuilt) {
@@ -4901,12 +4887,8 @@ void DesignPanel::on_import_mesh()
try {
shape = GeometryEngine::mesh_to_brep(mesh.its, MESH_IMPORT_TOLERANCE,
MESH_IMPORT_MERGE_ANGLE_DEG, stats);
} catch (const Standard_Failure& e) { // on OCCT >= 8 Standard_Failure derives from std::exception — must precede that handler
fail(_L("Mesh conversion failed: ") + wxString::FromUTF8(
e.GetMessageString() ? e.GetMessageString() : "OCCT error"));
return;
} catch (const std::exception& e) {
fail(_L("Mesh conversion failed: ") + wxString::FromUTF8(e.what()));
fail(_L("Mesh conversion failed: ") + wxString::FromUTF8(*e.what() ? e.what() : "OCCT error"));
return;
}
if (shape.IsNull()) { fail(_L("Mesh conversion produced no geometry")); return; }
+7 -7
View File
@@ -27,7 +27,7 @@
#include <nlohmann/json.hpp>
#include <boost/log/trivial.hpp>
#include <Standard_Failure.hxx> // OCCT base error (not a std::exception)
#include <Standard_Failure.hxx> // OCCT base error
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/MainFrame.hpp"
@@ -637,9 +637,9 @@ json slice_body(DesignPanel* panel, const json& params)
: plane_name == "YZ" ? gp_Dir(1, 0, 0)
: gp_Dir(0, 0, 1);
gp_Pnt o(n.X() * offset, n.Y() * offset, n.Z() * offset);
BRepAlgoAPI_Section sect(shape, gp_Pln(o, n), Standard_False);
sect.ComputePCurveOn1(Standard_False);
sect.Approximation(Standard_True);
BRepAlgoAPI_Section sect(shape, gp_Pln(o, n), false);
sect.ComputePCurveOn1(false);
sect.Approximation(true);
sect.Build();
if (!sect.IsDone()) throw std::runtime_error("section failed");
std::vector<std::vector<Vec3d>> segs;
@@ -751,7 +751,7 @@ ShapeMetrics shape_metrics(const TopoDS_Shape& s)
GProp_GProps vp; BRepGProp::VolumeProperties(s, vp);
gp_Pnt c = vp.CentreOfMass();
Bnd_Box bb; BRepBndLib::Add(s, bb);
Standard_Real x0, y0, z0, x1, y1, z1; bb.Get(x0, y0, z0, x1, y1, z1);
double x0, y0, z0, x1, y1, z1; bb.Get(x0, y0, z0, x1, y1, z1);
return {vp.Mass(), Vec3d(c.X(), c.Y(), c.Z()), Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)};
}
@@ -2095,8 +2095,8 @@ std::string handle_on_main(const std::string& method, const json& params, const
if (method == "mate") return rpc_result(id, action_mate(panel, params));
if (method == "check_interference") return rpc_result(id, action_check_interference(panel, params));
return rpc_error(id, -32601, "Unknown method: " + method);
} catch (const Standard_Failure& ex) { // OCCT errors are NOT std::exception
return rpc_error(id, -32000, std::string("OCCT: ") + (ex.GetMessageString() ? ex.GetMessageString() : "failure"));
} catch (const Standard_Failure& ex) { // derives from std::exception, so it comes first
return rpc_error(id, -32000, std::string("OCCT: ") + (*ex.what() ? ex.what() : "failure"));
} catch (const std::exception& ex) {
return rpc_error(id, -32000, ex.what());
}
+1 -1
View File
@@ -827,7 +827,7 @@ indexed_triangle_set GLGizmoCut3D::its_make_groove_plane()
float slot_mouth_outer_x = slot_neck_half_width + flap_taper_offset; // upper_x extension
float slot_neck_outer_x = slot_mouth_half_width + flap_taper_offset; // lower_x extension
float slot_outer_x_max = Max(slot_neck_outer_x, slot_mouth_outer_x); // max x extension
float slot_outer_x_max = std::max(slot_neck_outer_x, slot_mouth_outer_x); // max x extension
float slot_neck_inner_x = slot_neck_half_width - flap_taper_offset; // upper_x narrowing
float slot_mouth_inner_x = slot_mouth_half_width - flap_taper_offset; // lower_x narrowing
File diff suppressed because it is too large Load Diff
+61
View File
@@ -0,0 +1,61 @@
ISO-10303-21;
HEADER;
FILE_DESCRIPTION((''),'2;1');
FILE_NAME('security_classification','2026-10-01T00:00:00',(''),(''),'','','');
FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));
ENDSEC;
DATA;
#1=APPLICATION_CONTEXT('automotive design');
#2=APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#1);
#3=PRODUCT_CONTEXT('',#1,'mechanical');
#4=PRODUCT('tetrahedron','tetrahedron','',(#3));
#5=PRODUCT_DEFINITION_FORMATION('','',#4);
#6=PRODUCT_DEFINITION_CONTEXT('part definition',#1,'design');
#7=PRODUCT_DEFINITION('design','',#5,#6);
#8=PRODUCT_DEFINITION_SHAPE('','',#7);
#9=SHAPE_DEFINITION_REPRESENTATION(#8,#20);
#10=SECURITY_CLASSIFICATION_LEVEL('unclassified');
#11=SECURITY_CLASSIFICATION('','',#10);
#12=APPLIED_SECURITY_CLASSIFICATION_ASSIGNMENT(#11,(#5));
#13=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));
#14=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));
#15=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());
#16=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.001),#13,'distance_accuracy_value','');
#17=(GEOMETRIC_REPRESENTATION_CONTEXT(3)GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#16))GLOBAL_UNIT_ASSIGNED_CONTEXT((#13,#14,#15))REPRESENTATION_CONTEXT('',''));
#20=FACETED_BREP_SHAPE_REPRESENTATION('',(#21,#22),#17);
#21=AXIS2_PLACEMENT_3D('',#30,#40,#41);
#22=FACETED_BREP('',#23);
#23=CLOSED_SHELL('',(#50,#51,#52,#53));
#30=CARTESIAN_POINT('',(0.,0.,0.));
#31=CARTESIAN_POINT('',(10.,0.,0.));
#32=CARTESIAN_POINT('',(0.,10.,0.));
#33=CARTESIAN_POINT('',(0.,0.,10.));
#40=DIRECTION('',(0.,0.,1.));
#41=DIRECTION('',(1.,0.,0.));
#42=DIRECTION('',(0.,0.,-1.));
#43=DIRECTION('',(0.,-1.,0.));
#44=DIRECTION('',(-1.,0.,0.));
#45=DIRECTION('',(0.577350269189626,0.577350269189626,0.577350269189626));
#46=DIRECTION('',(0.,0.,1.));
#50=FACE_SURFACE('',(#60),#70,.T.);
#51=FACE_SURFACE('',(#61),#71,.T.);
#52=FACE_SURFACE('',(#62),#72,.T.);
#53=FACE_SURFACE('',(#63),#73,.T.);
#60=FACE_OUTER_BOUND('',#80,.T.);
#61=FACE_OUTER_BOUND('',#81,.T.);
#62=FACE_OUTER_BOUND('',#82,.T.);
#63=FACE_OUTER_BOUND('',#83,.T.);
#70=PLANE('',#90);
#71=PLANE('',#91);
#72=PLANE('',#92);
#73=PLANE('',#93);
#80=POLY_LOOP('',(#30,#32,#31));
#81=POLY_LOOP('',(#30,#31,#33));
#82=POLY_LOOP('',(#30,#33,#32));
#83=POLY_LOOP('',(#31,#32,#33));
#90=AXIS2_PLACEMENT_3D('',#30,#42,#41);
#91=AXIS2_PLACEMENT_3D('',#30,#43,#41);
#92=AXIS2_PLACEMENT_3D('',#30,#44,#46);
#93=AXIS2_PLACEMENT_3D('',#31,#45,$);
ENDSEC;
END-ISO-10303-21;
+114 -22
View File
@@ -1719,7 +1719,7 @@ TEST_CASE("split by face round-trip serialization", "[CadDocument][cut]")
std::vector<std::pair<Vec3d, Vec3d>> bboxes;
for (const auto& b : doc.bodies) {
Bnd_Box bb; BRepBndLib::Add(b.shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
bboxes.push_back({Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)});
}
@@ -1740,7 +1740,7 @@ TEST_CASE("split by face round-trip serialization", "[CadDocument][cut]")
for (size_t i = 0; i < saved_nb; ++i) {
Bnd_Box bb; BRepBndLib::Add(doc2.bodies[i].shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
REQUIRE_THAT(double(x0), WithinAbs(bboxes[i].first.x(), 1e-6));
REQUIRE_THAT(double(y0), WithinAbs(bboxes[i].first.y(), 1e-6));
@@ -2205,6 +2205,34 @@ TEST_CASE("a v5 project still opens", "[CadDocument][recipe]")
REQUIRE_FALSE(doc.features.empty());
}
// OCCT 7.6 wrote cad_brep_occt76.brep, so do NOT regenerate it. It holds a 30 x 30 x 5 plate
// with a 3 x 3 grid of r3 holes, their rims filleted r0.5.
TEST_CASE("an Import solid written by OCCT 7.6 still loads", "[CadDocument][recipe]")
{
using Catch::Matchers::WithinRel;
std::ifstream ifs(std::string(TEST_DATA_DIR) + "/cad_brep_occt76.brep", std::ios::binary);
REQUIRE(ifs.is_open());
const std::string brep((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
const TopoDS_Shape shape = brep_from_string(brep);
REQUIRE_FALSE(shape.IsNull());
int faces = 0;
for (TopExp_Explorer it(shape, TopAbs_FACE); it.More(); it.Next())
++faces;
CHECK(faces == 6 + 9 + 9); // box, hole walls, rim fillets
// Each rim fillet removes the corner between a quarter circle and its square, swept around the
// hole, so its volume is that area times the path of the corner's centroid (Pappus).
const double hole_r = 3.0, fillet_r = 0.5;
const double corner_area = fillet_r * fillet_r * (1 - M_PI / 4);
const double corner_centroid = hole_r + fillet_r * (10 - 3 * M_PI) / (3 * (4 - M_PI));
const double expected = 30.0 * 30.0 * 5.0 - 9 * M_PI * hole_r * hole_r * 5.0 - 9 * corner_area * 2 * M_PI * corner_centroid;
GProp_GProps props;
BRepGProp::VolumeProperties(shape, props);
CHECK_THAT(props.Mass(), WithinRel(expected, 1e-4));
}
TEST_CASE("a v5 round trip is exact", "[CadDocument][recipe]")
{
using Catch::Matchers::WithinRel;
@@ -3437,7 +3465,7 @@ TEST_CASE("thicken flip offsets against face normal", "[CadDocument]")
doc2.add_thicken(0, tf2, 3.0, false, "PlateFwd");
REQUIRE(doc2.recompute());
Bnd_Box bb_fwd; BRepBndLib::Add(doc2.bodies[1].shape, bb_fwd);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb_fwd.Get(x0, y0, z0, x1, y1, z1);
// flipped: plate grows below the face plane (z < 10)
@@ -3456,7 +3484,7 @@ TEST_CASE("thicken flip offsets against face normal", "[CadDocument]")
doc3.add_thicken(0, tf3, 3.0, true, "PlateRev");
REQUIRE(doc3.recompute());
Bnd_Box bb_rev; BRepBndLib::Add(doc3.bodies[1].shape, bb_rev);
Standard_Real rx0, ry0, rz0, rx1, ry1, rz1;
double rx0, ry0, rz0, rx1, ry1, rz1;
bb_rev.Get(rx0, ry0, rz0, rx1, ry1, rz1);
// forward plate bbox z > 10 (source face at z=10, +3 offset = z in (10,13))
@@ -3564,7 +3592,7 @@ TEST_CASE("thicken round-trip serialization", "[CadDocument]")
std::vector<std::pair<Vec3d, Vec3d>> bboxes;
for (const auto& b : doc.bodies) {
Bnd_Box bb; BRepBndLib::Add(b.shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
bboxes.push_back({Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)});
}
@@ -3584,7 +3612,7 @@ TEST_CASE("thicken round-trip serialization", "[CadDocument]")
for (size_t i = 0; i < nb; ++i) {
Bnd_Box bb; BRepBndLib::Add(doc2.bodies[i].shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
REQUIRE_THAT(double(x0), WithinAbs(bboxes[i].first.x(), 1e-6));
REQUIRE_THAT(double(y0), WithinAbs(bboxes[i].first.y(), 1e-6));
@@ -3750,7 +3778,7 @@ TEST_CASE("project round-trip serialization", "[CadDocument][project]")
std::vector<std::pair<Vec3d, Vec3d>> bboxes;
for (const auto& b : doc.bodies) {
Bnd_Box bb; BRepBndLib::Add(b.shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
bboxes.push_back({Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)});
}
@@ -3770,7 +3798,7 @@ TEST_CASE("project round-trip serialization", "[CadDocument][project]")
for (size_t i = 0; i < saved_nb; ++i) {
Bnd_Box bb; BRepBndLib::Add(doc2.bodies[i].shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
REQUIRE_THAT(double(x0), WithinAbs(bboxes[i].first.x(), 1e-6));
REQUIRE_THAT(double(y0), WithinAbs(bboxes[i].first.y(), 1e-6));
@@ -4839,7 +4867,7 @@ TEST_CASE("delete_face round-trip serialization", "[CadDocument][deleteface]")
std::vector<std::pair<Vec3d, Vec3d>> bboxes;
for (const auto& b : doc.bodies) {
Bnd_Box bb; BRepBndLib::Add(b.shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
bboxes.push_back({Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)});
}
@@ -4856,7 +4884,7 @@ TEST_CASE("delete_face round-trip serialization", "[CadDocument][deleteface]")
for (size_t i = 0; i < bboxes.size(); ++i) {
Bnd_Box bb; BRepBndLib::Add(doc2.bodies[i].shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
REQUIRE_THAT(double(x0), WithinAbs(bboxes[i].first.x(), 1e-6));
REQUIRE_THAT(double(y0), WithinAbs(bboxes[i].first.y(), 1e-6));
@@ -4961,7 +4989,7 @@ TEST_CASE("hole: round-trip preserves styled counterbore hole", "[CadDocument][h
std::vector<std::pair<Vec3d, Vec3d>> bboxes;
for (const auto& b : doc.bodies) {
Bnd_Box bb; BRepBndLib::Add(b.shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
bboxes.emplace_back(Vec3d(x0, y0, z0), Vec3d(x1, y1, z1));
}
@@ -4976,7 +5004,7 @@ TEST_CASE("hole: round-trip preserves styled counterbore hole", "[CadDocument][h
for (size_t i = 0; i < bboxes.size(); ++i) {
Bnd_Box bb; BRepBndLib::Add(doc2.bodies[i].shape, bb);
Standard_Real x0, y0, z0, x1, y1, z1;
double x0, y0, z0, x1, y1, z1;
bb.Get(x0, y0, z0, x1, y1, z1);
REQUIRE_THAT(double(x0), WithinAbs(bboxes[i].first.x(), 1e-6));
REQUIRE_THAT(double(y0), WithinAbs(bboxes[i].first.y(), 1e-6));
@@ -5280,9 +5308,9 @@ TEST_CASE("surface round-trip serialize/deserialize", "[CadDocument][surface]")
Bnd_Box fresh_bb;
BRepBndLib::Add(fresh.bodies.back().shape, fresh_bb);
Standard_Real ox0, oy0, oz0, ox1, oy1, oz1;
double ox0, oy0, oz0, ox1, oy1, oz1;
orig_bb.Get(ox0, oy0, oz0, ox1, oy1, oz1);
Standard_Real fx0, fy0, fz0, fx1, fy1, fz1;
double fx0, fy0, fz0, fx1, fy1, fz1;
fresh_bb.Get(fx0, fy0, fz0, fx1, fy1, fz1);
REQUIRE_THAT(double(fx0), WithinAbs(double(ox0), 1e-6));
REQUIRE_THAT(double(fy0), WithinAbs(double(oy0), 1e-6));
@@ -5321,8 +5349,8 @@ TEST_CASE("thicken-surface makes a solid from a sheet", "[CadDocument][surface]"
Bnd_Box thick_bb;
BRepBndLib::Add(doc.bodies.back().shape, thick_bb);
Standard_Real sx0, sy0, sz0, sx1, sy1, sz1;
Standard_Real tx0, ty0, tz0, tx1, ty1, tz1;
double sx0, sy0, sz0, sx1, sy1, sz1;
double tx0, ty0, tz0, tx1, ty1, tz1;
sheet_bb.Get(sx0, sy0, sz0, sx1, sy1, sz1);
thick_bb.Get(tx0, ty0, tz0, tx1, ty1, tz1);
REQUIRE_THAT(double(tx0), WithinAbs(double(sx0), 2.1));
@@ -5439,8 +5467,8 @@ TEST_CASE("surface-offset creates another sheet shifted outward", "[CadDocument]
Bnd_Box off_bb;
BRepBndLib::Add(doc.bodies.back().shape, off_bb);
Standard_Real sx0, sy0, sz0, sx1, sy1, sz1;
Standard_Real ox0, oy0, oz0, ox1, oy1, oz1;
double sx0, sy0, sz0, sx1, sy1, sz1;
double ox0, oy0, oz0, ox1, oy1, oz1;
src_bb.Get(sx0, sy0, sz0, sx1, sy1, sz1);
off_bb.Get(ox0, oy0, oz0, ox1, oy1, oz1);
REQUIRE(std::abs(double(ox0) - double(sx0)) > 1e-3);
@@ -5493,8 +5521,8 @@ TEST_CASE("thicken-surface round-trip serialize/deserialize", "[CadDocument][sur
Bnd_Box fresh_bb;
BRepBndLib::Add(fresh.bodies.back().shape, fresh_bb);
Standard_Real ox0, oy0, oz0, ox1, oy1, oz1;
Standard_Real fx0, fy0, fz0, fx1, fy1, fz1;
double ox0, oy0, oz0, ox1, oy1, oz1;
double fx0, fy0, fz0, fx1, fy1, fz1;
orig_bb.Get(ox0, oy0, oz0, ox1, oy1, oz1);
fresh_bb.Get(fx0, fy0, fz0, fx1, fy1, fz1);
REQUIRE_THAT(double(fx0), WithinAbs(double(ox0), 1e-6));
@@ -5615,8 +5643,8 @@ TEST_CASE("surface-loft round-trip serialize/deserialize", "[CadDocument][surfac
Bnd_Box fresh_bb;
BRepBndLib::Add(fresh.bodies.back().shape, fresh_bb);
Standard_Real ox0, oy0, oz0, ox1, oy1, oz1;
Standard_Real fx0, fy0, fz0, fx1, fy1, fz1;
double ox0, oy0, oz0, ox1, oy1, oz1;
double fx0, fy0, fz0, fx1, fy1, fz1;
orig_bb.Get(ox0, oy0, oz0, ox1, oy1, oz1);
fresh_bb.Get(fx0, fy0, fz0, fx1, fy1, fz1);
REQUIRE_THAT(double(fx0), WithinAbs(double(ox0), 1e-6));
@@ -8312,6 +8340,70 @@ TEST_CASE("A sketch-only document recomputes and round-trips", "[CadDocument]")
REQUIRE_FALSE(bad.error.empty());
}
TEST_CASE("A zero-depth extrude is an error on every path", "[CadDocument]")
{
CadDocument doc;
const int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 20, 20, 0, "Rect");
REQUIRE(sk == 0);
// nz = 1 picks the box's +z face, nz = -1 its -z face.
auto add_box_and_find_face = [&](double nz) {
doc.add_extrude(sk, 10.0, false, BooleanMode::New, "Box");
REQUIRE(doc.recompute());
const TopoDS_Shape& box = doc.bodies[0].shape;
for (int i = 0; i < GeometryEngine::face_count(box); ++i)
if (GeometryEngine::face_normal_world(GeometryEngine::face_by_index(box, i)).z() * nz > 0.9)
return i;
return -1;
};
SECTION("blind") { doc.add_extrude(sk, 0.0, false, BooleanMode::New, "ZeroDepth"); }
SECTION("tapered")
{
doc.add_extrude(sk, 0.0, false, BooleanMode::New, "ZeroDepth");
doc.features.back().taper_deg = 8.0;
}
SECTION("symmetric") { doc.add_extrude(sk, 0.0, true, BooleanMode::New, "ZeroDepth"); }
SECTION("two-sided")
{
doc.add_extrude(sk, 0.0, false, BooleanMode::New, "ZeroDepth");
doc.features.back().extrude_end = ExtrudeEnd::TwoSided;
}
SECTION("up to a vertex in the sketch plane")
{
doc.add_extrude(sk, 10.0, false, BooleanMode::New, "ZeroDepth");
doc.features.back().extrude_end = ExtrudeEnd::UpToVertex;
doc.features.back().up_to_point = Vec3d(5, 5, 0);
}
SECTION("up to a face in the sketch plane")
{
const int bottom = add_box_and_find_face(-1.0);
REQUIRE(bottom >= 0);
doc.add_extrude(sk, 10.0, false, BooleanMode::Add, "ZeroDepth");
doc.features.back().extrude_end = ExtrudeEnd::UpToFace;
doc.features.back().up_to_face = bottom;
}
SECTION("from a body face")
{
const int top = add_box_and_find_face(1.0);
REQUIRE(top >= 0);
doc.add_extrude_face(top, 0.0, false, BooleanMode::Add, "ZeroDepth");
}
SECTION("imported text or SVG regions")
{
CadFeature art;
art.type = CadFeatureType::Sketch;
art.plane = SketchPlane::XY();
art.imported_regions = {{ {Vec2d(0, 0), Vec2d(10, 0), Vec2d(10, 10), Vec2d(0, 10)} }};
doc.features.push_back(art);
doc.add_extrude(int(doc.features.size()) - 1, 0.0, false, BooleanMode::New, "ZeroDepth");
}
SECTION("surface") { doc.add_surface_extrude(sk, 0.0, "ZeroDepth"); }
REQUIRE_FALSE(doc.recompute());
CHECK_CONTAINS(doc.error, "zero");
}
// A body is NOT the feature that created it. Reported 2026-08-23, in these words: "you have
// renamed the feature extrusion, not the body ... this means that you consider the extrusion =
// the body, which is very far from truth as a body can contain several extrusions." The rename
+16
View File
@@ -57,6 +57,22 @@ TEST_CASE("Part names with multi-byte UTF-8 survive import", "[Step]")
CHECK(object->volumes[2]->name == "bracket");
}
TEST_CASE("A security classification assignment does not crash import", "[Step]")
{
const std::string path = std::string(TEST_DATA_DIR) + PATH_SEPARATOR "security_classification.step";
Model model;
bool cancel = false;
Step step(path);
REQUIRE(step.load() == Step::Step_Status::LOAD_SUCCESS);
REQUIRE(step.mesh(&model, cancel, false) == Step::Step_Status::MESH_SUCCESS);
REQUIRE(model.objects.size() == 1);
REQUIRE(model.objects.front()->volumes.size() == 1);
CHECK(model.objects.front()->volumes.front()->mesh().facets_count() == 4); // a tetrahedron
}
TEST_CASE("isUtf8 recognises two, three and four byte sequences", "[Step]")
{
CHECK(StepPreProcessor::isUtf8("\xC3\xA9")); // U+00E9