Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_experiments

This commit is contained in:
Enrico Turri 2019-06-24 08:15:41 +02:00
commit 96276394d1
1203 changed files with 5528 additions and 4690 deletions

View file

@ -16,6 +16,8 @@ my %prereqs = qw(
ExtUtils::MakeMaker 6.80 ExtUtils::MakeMaker 6.80
ExtUtils::ParseXS 3.22 ExtUtils::ParseXS 3.22
ExtUtils::XSpp 0 ExtUtils::XSpp 0
ExtUtils::XSpp::Cmd 0
ExtUtils::CppGuess 0
ExtUtils::Typemaps 0 ExtUtils::Typemaps 0
ExtUtils::Typemaps::Basic 0 ExtUtils::Typemaps::Basic 0
File::Basename 0 File::Basename 0

View file

@ -60,7 +60,7 @@ if (MSVC)
# /bigobj (Increase Number of Sections in .Obj file) # /bigobj (Increase Number of Sections in .Obj file)
# error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater # error C3859: virtual memory range for PCH exceeded; please recompile with a command line option of '-Zm90' or greater
# Generate symbols at every build target, even for the release. # Generate symbols at every build target, even for the release.
add_compile_options(-bigobj -Zm316 /Zi) add_compile_options(-bigobj -Zm520 /Zi)
endif () endif ()
# Display and check CMAKE_PREFIX_PATH # Display and check CMAKE_PREFIX_PATH
@ -89,8 +89,6 @@ enable_testing ()
# Enable C++11 language standard. # Enable C++11 language standard.
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
if(NOT WIN32) if(NOT WIN32)
# Add DEBUG flags to debug builds. # Add DEBUG flags to debug builds.
@ -172,7 +170,7 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STRE
add_compile_options(-Werror=return-type) add_compile_options(-Werror=return-type)
#removes LOTS of extraneous Eigen warnings #removes LOTS of extraneous Eigen warnings
add_compile_options(-Wno-ignored-attributes) # add_compile_options(-Wno-ignored-attributes) # Tamas: Eigen include dirs are marked as SYSTEM
if (SLIC3R_ASAN) if (SLIC3R_ASAN)
add_compile_options(-fsanitize=address -fno-omit-frame-pointer) add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
@ -240,15 +238,34 @@ if(NOT WIN32)
set(MINIMUM_BOOST_VERSION "1.64.0") set(MINIMUM_BOOST_VERSION "1.64.0")
endif() endif()
find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS system filesystem thread log locale regex) find_package(Boost ${MINIMUM_BOOST_VERSION} REQUIRED COMPONENTS system filesystem thread log locale regex)
if(Boost_FOUND)
# include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) add_library(boost_libs INTERFACE)
if (APPLE) add_library(boost_headeronly INTERFACE)
# BOOST_ASIO_DISABLE_KQUEUE : prevents a Boost ASIO bug on OS X: https://svn.boost.org/trac/boost/ticket/5339
add_definitions(-DBOOST_ASIO_DISABLE_KQUEUE) if (APPLE)
endif() # BOOST_ASIO_DISABLE_KQUEUE : prevents a Boost ASIO bug on OS X: https://svn.boost.org/trac/boost/ticket/5339
if(NOT SLIC3R_STATIC) target_compile_definitions(boost_headeronly INTERFACE BOOST_ASIO_DISABLE_KQUEUE)
add_definitions(-DBOOST_LOG_DYN_LINK) endif()
endif()
if(NOT SLIC3R_STATIC)
target_compile_definitions(boost_headeronly INTERFACE BOOST_LOG_DYN_LINK)
endif()
if(TARGET Boost::system)
message(STATUS "Boost::boost exists")
target_link_libraries(boost_headeronly INTERFACE Boost::boost)
target_link_libraries(boost_libs INTERFACE
boost_headeronly # includes the custom compile definitions as well
Boost::system
Boost::filesystem
Boost::thread
Boost::log
Boost::locale
Boost::regex
)
else()
target_include_directories(boost_headeronly INTERFACE ${Boost_INCLUDE_DIRS})
target_link_libraries(boost_libs INTERFACE boost_headeronly ${Boost_LIBRARIES})
endif() endif()
# Find and configure intel-tbb # Find and configure intel-tbb
@ -295,7 +312,7 @@ if (NOT Eigen3_FOUND)
set(Eigen3_FOUND 1) set(Eigen3_FOUND 1)
set(EIGEN3_INCLUDE_DIR ${LIBDIR}/eigen/) set(EIGEN3_INCLUDE_DIR ${LIBDIR}/eigen/)
endif () endif ()
include_directories(${EIGEN3_INCLUDE_DIR}) include_directories(BEFORE SYSTEM ${EIGEN3_INCLUDE_DIR})
# Find expat or use bundled version # Find expat or use bundled version
# Always use the system libexpat on Linux. # Always use the system libexpat on Linux.

8
deps/CMakeLists.txt vendored
View file

@ -36,6 +36,11 @@ set(DESTDIR "${CMAKE_CURRENT_BINARY_DIR}/destdir" CACHE PATH "Destination direct
option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON) option(DEP_DEBUG "Build debug variants (only applicable on Windows)" ON)
option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF) option(DEP_WX_STABLE "Build against wxWidgets stable 3.0 as opposed to default 3.1 (Linux only)" OFF)
# IGL static library in release mode produces 50MB binary. On the build server, it should be
# disabled and used in header-only mode. On developer machines, it can be enabled to speed
# up conpilation and suppress warnings coming from IGL.
option(DEP_BUILD_IGL_STATIC "Build IGL as a static library. Might cause link errors and increase binary size." OFF)
message(STATUS "PrusaSlicer deps DESTDIR: ${DESTDIR}") message(STATUS "PrusaSlicer deps DESTDIR: ${DESTDIR}")
message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}") message(STATUS "PrusaSlicer deps debug build: ${DEP_DEBUG}")
@ -84,6 +89,7 @@ if (MSVC)
dep_wxwidgets dep_wxwidgets
dep_gtest dep_gtest
dep_nlopt dep_nlopt
# dep_qhull # Experimental
dep_zlib # on Windows we still need zlib dep_zlib # on Windows we still need zlib
) )
@ -97,6 +103,8 @@ else()
dep_wxwidgets dep_wxwidgets
dep_gtest dep_gtest
dep_nlopt dep_nlopt
dep_qhull
dep_libigl
) )
endif() endif()

View file

@ -32,3 +32,44 @@ ExternalProject_Add(dep_nlopt
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local -DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
${DEP_CMAKE_OPTS} ${DEP_CMAKE_OPTS}
) )
find_package(Git REQUIRED)
ExternalProject_Add(dep_qhull
EXCLUDE_FROM_ALL 1
URL "https://github.com/qhull/qhull/archive/v7.2.1.tar.gz"
URL_HASH SHA256=6fc251e0b75467e00943bfb7191e986fce0e1f8f6f0251f9c6ce5a843821ea78
CMAKE_ARGS
-DBUILD_SHARED_LIBS=OFF
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
${DEP_CMAKE_OPTS}
PATCH_COMMAND ${GIT_EXECUTABLE} apply --ignore-space-change --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch
)
ExternalProject_Add(dep_libigl
EXCLUDE_FROM_ALL 1
URL "https://github.com/libigl/libigl/archive/v2.0.0.tar.gz"
URL_HASH SHA256=42518e6b106c7209c73435fd260ed5d34edeb254852495b4c95dce2d95401328
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
-DLIBIGL_BUILD_PYTHON=OFF
-DLIBIGL_BUILD_TESTS=OFF
-DLIBIGL_BUILD_TUTORIALS=OFF
-DLIBIGL_USE_STATIC_LIBRARY=${DEP_BUILD_IGL_STATIC}
-DLIBIGL_WITHOUT_COPYLEFT=OFF
-DLIBIGL_WITH_CGAL=OFF
-DLIBIGL_WITH_COMISO=OFF
-DLIBIGL_WITH_CORK=OFF
-DLIBIGL_WITH_EMBREE=OFF
-DLIBIGL_WITH_MATLAB=OFF
-DLIBIGL_WITH_MOSEK=OFF
-DLIBIGL_WITH_OPENGL=OFF
-DLIBIGL_WITH_OPENGL_GLFW=OFF
-DLIBIGL_WITH_OPENGL_GLFW_IMGUI=OFF
-DLIBIGL_WITH_PNG=OFF
-DLIBIGL_WITH_PYTHON=OFF
-DLIBIGL_WITH_TETGEN=OFF
-DLIBIGL_WITH_TRIANGLE=OFF
-DLIBIGL_WITH_XML=OFF
PATCH_COMMAND ${GIT_EXECUTABLE} apply --ignore-space-change --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/igl-fixes.patch
)

View file

@ -1,21 +1,34 @@
# https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html
if (MSVC_VERSION EQUAL 1800) if (MSVC_VERSION EQUAL 1800)
# 1800 = VS 12.0 (v120 toolset)
set(DEP_VS_VER "12") set(DEP_VS_VER "12")
set(DEP_BOOST_TOOLSET "msvc-12.0") set(DEP_BOOST_TOOLSET "msvc-12.0")
elseif (MSVC_VERSION EQUAL 1900) elseif (MSVC_VERSION EQUAL 1900)
# 1900 = VS 14.0 (v140 toolset)
set(DEP_VS_VER "14") set(DEP_VS_VER "14")
set(DEP_BOOST_TOOLSET "msvc-14.0") set(DEP_BOOST_TOOLSET "msvc-14.0")
elseif (MSVC_VERSION GREATER 1900) elseif (MSVC_VERSION LESS 1920)
# 1910-1919 = VS 15.0 (v141 toolset)
set(DEP_VS_VER "15") set(DEP_VS_VER "15")
set(DEP_BOOST_TOOLSET "msvc-14.1") set(DEP_BOOST_TOOLSET "msvc-14.1")
elseif (MSVC_VERSION LESS 1930)
# 1920-1929 = VS 16.0 (v142 toolset)
set(DEP_VS_VER "16")
set(DEP_BOOST_TOOLSET "msvc-14.2")
else () else ()
message(FATAL_ERROR "Unsupported MSVC version") message(FATAL_ERROR "Unsupported MSVC version")
endif () endif ()
if (${DEPS_BITS} EQUAL 32) if (${DEPS_BITS} EQUAL 32)
set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER}") set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER}")
set(DEP_PLATFORM "Win32")
else () else ()
set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER} Win64") if (DEP_VS_VER LESS 16)
set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER} Win64")
else ()
set(DEP_MSVC_GEN "Visual Studio ${DEP_VS_VER}")
endif ()
set(DEP_PLATFORM "x64")
endif () endif ()
@ -28,8 +41,8 @@ endif ()
ExternalProject_Add(dep_boost ExternalProject_Add(dep_boost
EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_ALL 1
URL "https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz" URL "https://dl.bintray.com/boostorg/release/1.70.0/source/boost_1_70_0.tar.gz"
URL_HASH SHA256=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60 URL_HASH SHA256=882b48708d211a5f48e60b0124cf5863c1534cd544ecd0664bb534a4b5d506e9
BUILD_IN_SOURCE 1 BUILD_IN_SOURCE 1
CONFIGURE_COMMAND bootstrap.bat CONFIGURE_COMMAND bootstrap.bat
BUILD_COMMAND b2.exe BUILD_COMMAND b2.exe
@ -57,6 +70,7 @@ ExternalProject_Add(dep_tbb
URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz" URL "https://github.com/wjakob/tbb/archive/a0dc9bf76d0120f917b641ed095360448cabc85b.tar.gz"
URL_HASH SHA256=0545cb6033bd1873fcae3ea304def720a380a88292726943ae3b9b207f322efe URL_HASH SHA256=0545cb6033bd1873fcae3ea304def720a380a88292726943ae3b9b207f322efe
CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS CMAKE_ARGS
-DCMAKE_DEBUG_POSTFIX=_debug -DCMAKE_DEBUG_POSTFIX=_debug
-DTBB_BUILD_SHARED=OFF -DTBB_BUILD_SHARED=OFF
@ -81,6 +95,7 @@ ExternalProject_Add(dep_gtest
URL "https://github.com/google/googletest/archive/release-1.8.1.tar.gz" URL "https://github.com/google/googletest/archive/release-1.8.1.tar.gz"
URL_HASH SHA256=9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c URL_HASH SHA256=9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c
CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS CMAKE_ARGS
-DBUILD_GMOCK=OFF -DBUILD_GMOCK=OFF
-Dgtest_force_shared_crt=ON -Dgtest_force_shared_crt=ON
@ -105,6 +120,7 @@ ExternalProject_Add(dep_nlopt
URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz" URL "https://github.com/stevengj/nlopt/archive/v2.5.0.tar.gz"
URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae URL_HASH SHA256=c6dd7a5701fff8ad5ebb45a3dc8e757e61d52658de3918e38bab233e7fd3b4ae
CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS CMAKE_ARGS
-DBUILD_SHARED_LIBS=OFF -DBUILD_SHARED_LIBS=OFF
-DNLOPT_PYTHON=OFF -DNLOPT_PYTHON=OFF
@ -133,6 +149,7 @@ ExternalProject_Add(dep_zlib
URL "https://zlib.net/zlib-1.2.11.tar.xz" URL "https://zlib.net/zlib-1.2.11.tar.xz"
URL_HASH SHA256=4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066 URL_HASH SHA256=4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066
CMAKE_GENERATOR "${DEP_MSVC_GEN}" CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_GENERATOR_PLATFORM "${DEP_PLATFORM}"
CMAKE_ARGS CMAKE_ARGS
-DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al. -DSKIP_INSTALL_FILES=ON # Prevent installation of man pages et al.
"-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib from creating & installing DLLs :-/ "-DINSTALL_BIN_DIR=${CMAKE_CURRENT_BINARY_DIR}\\fallout" # I found no better way of preventing zlib from creating & installing DLLs :-/
@ -199,6 +216,33 @@ if (${DEP_DEBUG})
) )
endif () endif ()
find_package(Git REQUIRED)
ExternalProject_Add(dep_qhull
EXCLUDE_FROM_ALL 1
URL "https://github.com/qhull/qhull/archive/v7.2.1.tar.gz"
URL_HASH SHA256=6fc251e0b75467e00943bfb7191e986fce0e1f8f6f0251f9c6ce5a843821ea78
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
-DBUILD_SHARED_LIBS=OFF
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-DCMAKE_DEBUG_POSTFIX=d
PATCH_COMMAND ${GIT_EXECUTABLE} apply --ignore-space-change --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/qhull-mods.patch
BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj
INSTALL_COMMAND ""
)
if (${DEP_DEBUG})
ExternalProject_Get_Property(dep_qhull BINARY_DIR)
ExternalProject_Add_Step(dep_qhull build_debug
DEPENDEES build
DEPENDERS install
COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj
WORKING_DIRECTORY "${BINARY_DIR}"
)
endif ()
if (${DEPS_BITS} EQUAL 32) if (${DEPS_BITS} EQUAL 32)
set(DEP_WXWIDGETS_TARGET "") set(DEP_WXWIDGETS_TARGET "")
@ -208,6 +252,51 @@ else ()
set(DEP_WXWIDGETS_LIBDIR "vc_x64_lib") set(DEP_WXWIDGETS_LIBDIR "vc_x64_lib")
endif () endif ()
find_package(Git REQUIRED)
ExternalProject_Add(dep_libigl
EXCLUDE_FROM_ALL 1
URL "https://github.com/libigl/libigl/archive/v2.0.0.tar.gz"
URL_HASH SHA256=42518e6b106c7209c73435fd260ed5d34edeb254852495b4c95dce2d95401328
CMAKE_GENERATOR "${DEP_MSVC_GEN}"
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${DESTDIR}/usr/local
-DLIBIGL_BUILD_PYTHON=OFF
-DLIBIGL_BUILD_TESTS=OFF
-DLIBIGL_BUILD_TUTORIALS=OFF
-DLIBIGL_USE_STATIC_LIBRARY=${DEP_BUILD_IGL_STATIC}
-DLIBIGL_WITHOUT_COPYLEFT=OFF
-DLIBIGL_WITH_CGAL=OFF
-DLIBIGL_WITH_COMISO=OFF
-DLIBIGL_WITH_CORK=OFF
-DLIBIGL_WITH_EMBREE=OFF
-DLIBIGL_WITH_MATLAB=OFF
-DLIBIGL_WITH_MOSEK=OFF
-DLIBIGL_WITH_OPENGL=OFF
-DLIBIGL_WITH_OPENGL_GLFW=OFF
-DLIBIGL_WITH_OPENGL_GLFW_IMGUI=OFF
-DLIBIGL_WITH_PNG=OFF
-DLIBIGL_WITH_PYTHON=OFF
-DLIBIGL_WITH_TETGEN=OFF
-DLIBIGL_WITH_TRIANGLE=OFF
-DLIBIGL_WITH_XML=OFF
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-DCMAKE_DEBUG_POSTFIX=d
PATCH_COMMAND ${GIT_EXECUTABLE} apply --ignore-space-change --ignore-whitespace ${CMAKE_CURRENT_SOURCE_DIR}/igl-fixes.patch
BUILD_COMMAND msbuild /m /P:Configuration=Release INSTALL.vcxproj
INSTALL_COMMAND ""
)
if (${DEP_DEBUG})
ExternalProject_Get_Property(dep_libigl BINARY_DIR)
ExternalProject_Add_Step(dep_libigl build_debug
DEPENDEES build
DEPENDERS install
COMMAND msbuild /m /P:Configuration=Debug INSTALL.vcxproj
WORKING_DIRECTORY "${BINARY_DIR}"
)
endif ()
ExternalProject_Add(dep_wxwidgets ExternalProject_Add(dep_wxwidgets
EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_ALL 1
GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets" GIT_REPOSITORY "https://github.com/prusa3d/wxWidgets"

128
deps/igl-fixes.patch vendored Normal file
View file

@ -0,0 +1,128 @@
diff --git a/cmake/libigl-config.cmake.in b/cmake/libigl-config.cmake.in
index 317c745c..f9808e1e 100644
--- a/cmake/libigl-config.cmake.in
+++ b/cmake/libigl-config.cmake.in
@@ -2,28 +2,28 @@
include(${CMAKE_CURRENT_LIST_DIR}/libigl-export.cmake)
-if (TARGET igl::core)
- if (NOT TARGET Eigen3::Eigen)
- find_package(Eigen3 QUIET)
- if (NOT Eigen3_FOUND)
- # try with PkgCOnfig
- find_package(PkgConfig REQUIRED)
- pkg_check_modules(Eigen3 QUIET IMPORTED_TARGET eigen3)
- endif()
-
- if (NOT Eigen3_FOUND)
- message(FATAL_ERROR "Could not find required dependency Eigen3")
- set(libigl_core_FOUND FALSE)
- else()
- target_link_libraries(igl::core INTERFACE PkgConfig::Eigen3)
- set(libigl_core_FOUND TRUE)
- endif()
- else()
- target_link_libraries(igl::core INTERFACE Eigen3::Eigen)
- set(libigl_core_FOUND TRUE)
- endif()
-
-endif()
+# if (TARGET igl::core)
+# if (NOT TARGET Eigen3::Eigen)
+# find_package(Eigen3 QUIET)
+# if (NOT Eigen3_FOUND)
+# # try with PkgCOnfig
+# find_package(PkgConfig REQUIRED)
+# pkg_check_modules(Eigen3 QUIET IMPORTED_TARGET eigen3)
+# endif()
+#
+# if (NOT Eigen3_FOUND)
+# message(FATAL_ERROR "Could not find required dependency Eigen3")
+# set(libigl_core_FOUND FALSE)
+# else()
+# target_link_libraries(igl::core INTERFACE PkgConfig::Eigen3)
+# set(libigl_core_FOUND TRUE)
+# endif()
+# else()
+# target_link_libraries(igl::core INTERFACE Eigen3::Eigen)
+# set(libigl_core_FOUND TRUE)
+# endif()
+#
+# endif()
check_required_components(libigl)
diff --git a/cmake/libigl.cmake b/cmake/libigl.cmake
index 4b11007a..47e6c395 100644
--- a/cmake/libigl.cmake
+++ b/cmake/libigl.cmake
@@ -445,6 +445,7 @@ function(install_dir_files dir_name)
if(NOT LIBIGL_USE_STATIC_LIBRARY)
file(GLOB public_sources
${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/igl${subpath}/*.c
)
endif()
list(APPEND files_to_install ${public_sources})
diff --git a/include/igl/AABB.cpp b/include/igl/AABB.cpp
index 09537335..92e90cb7 100644
--- a/include/igl/AABB.cpp
+++ b/include/igl/AABB.cpp
@@ -1071,5 +1071,11 @@ template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen
// generated by autoexplicit.sh
template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
+template float igl::AABB<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, 3>::squared_distance<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > >(Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, igl::Hit&) const;
+template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, std::vector<igl::Hit>&) const;
+
+template void igl::AABB<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, 3>::init<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > >(Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&);
+
+template bool igl::AABB<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, 3>::intersect_ray<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > >(Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&) const;
#endif
diff --git a/include/igl/barycenter.cpp b/include/igl/barycenter.cpp
index 065f82aa..ec2d96cd 100644
--- a/include/igl/barycenter.cpp
+++ b/include/igl/barycenter.cpp
@@ -54,4 +54,6 @@ template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::M
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+
+template void igl::barycenter<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
#endif
diff --git a/include/igl/point_simplex_squared_distance.cpp b/include/igl/point_simplex_squared_distance.cpp
index 2b98bd28..c66d9ae1 100644
--- a/include/igl/point_simplex_squared_distance.cpp
+++ b/include/igl/point_simplex_squared_distance.cpp
@@ -178,4 +178,6 @@ template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3,
template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 1, 1, 3> >&);
template void igl::point_simplex_squared_distance<2, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
template void igl::point_simplex_squared_distance<2, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 1, 1, 2> >&);
+
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >::Index, float&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
#endif
diff --git a/include/igl/ray_box_intersect.cpp b/include/igl/ray_box_intersect.cpp
index 4a88b89e..b547f8f8 100644
--- a/include/igl/ray_box_intersect.cpp
+++ b/include/igl/ray_box_intersect.cpp
@@ -147,4 +147,6 @@ IGL_INLINE bool igl::ray_box_intersect(
#ifdef IGL_STATIC_LIBRARY
// Explicit template instantiation
template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
+
+template bool igl::ray_box_intersect<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float>(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<float, 3> const&, float const&, float const&, float&, float&);
#endif
diff --git a/include/igl/ray_mesh_intersect.cpp b/include/igl/ray_mesh_intersect.cpp
index 9a70a22b..4233e722 100644
--- a/include/igl/ray_mesh_intersect.cpp
+++ b/include/igl/ray_mesh_intersect.cpp
@@ -83,4 +83,7 @@ IGL_INLINE bool igl::ray_mesh_intersect(
template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::Hit&);
template bool igl::ray_mesh_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, igl::Hit&);
+template bool igl::ray_mesh_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+
+template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> >, Eigen::Block<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > const, 1, -1, true> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Map<Eigen::Matrix<float, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Map<Eigen::Matrix<int, -1, -1, 3, -1, -1> const, 0, Eigen::Stride<0, 0> > const, 1, -1, true> > const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
#endif

121
deps/qhull-mods.patch vendored Normal file
View file

@ -0,0 +1,121 @@
From a31ae4781a4afa60e21c70e5b4ae784bcd447c8a Mon Sep 17 00:00:00 2001
From: tamasmeszaros <meszaros.q@gmail.com>
Date: Thu, 6 Jun 2019 15:41:43 +0200
Subject: [PATCH] prusa-slicer changes
---
CMakeLists.txt | 44 +++++++++++++++++++++++++++++++++++---
Config.cmake.in | 2 ++
src/libqhull_r/qhull_r-exports.def | 2 ++
src/libqhull_r/user_r.h | 2 +-
4 files changed, 46 insertions(+), 4 deletions(-)
create mode 100644 Config.cmake.in
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 59dff41..20c2ec5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,7 +61,7 @@
# $DateTime: 2016/01/18 19:29:17 $$Author: bbarber $
project(qhull)
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 3.0)
# Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, qhull-warn.pri
set(qhull_VERSION2 "2015.2 2016/01/18") # not used, See global.c, global_r.c, rbox.c, rbox_r.c
@@ -610,10 +610,48 @@ add_test(NAME user_eg3
# Define install
# ---------------------------------------
-install(TARGETS ${qhull_TARGETS_INSTALL}
+install(TARGETS ${qhull_TARGETS_INSTALL} EXPORT QhullTargets
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
- ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
+ ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+ INCLUDES DESTINATION include)
+
+include(CMakePackageConfigHelpers)
+
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfigVersion.cmake"
+ VERSION ${qhull_VERSION}
+ COMPATIBILITY AnyNewerVersion
+)
+
+export(EXPORT QhullTargets
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullTargets.cmake"
+ NAMESPACE Qhull::
+)
+
+configure_file(Config.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfig.cmake"
+ @ONLY
+)
+
+set(ConfigPackageLocation lib/cmake/Qhull)
+install(EXPORT QhullTargets
+ FILE
+ QhullTargets.cmake
+ NAMESPACE
+ Qhull::
+ DESTINATION
+ ${ConfigPackageLocation}
+)
+install(
+ FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/Qhull/QhullConfigVersion.cmake"
+ DESTINATION
+ ${ConfigPackageLocation}
+ COMPONENT
+ Devel
+)
install(FILES ${libqhull_HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull)
install(FILES ${libqhull_DOC} DESTINATION ${INCLUDE_INSTALL_DIR}/libqhull)
diff --git a/Config.cmake.in b/Config.cmake.in
new file mode 100644
index 0000000..bc92bfe
--- /dev/null
+++ b/Config.cmake.in
@@ -0,0 +1,2 @@
+include("${CMAKE_CURRENT_LIST_DIR}/QhullTargets.cmake")
+
diff --git a/src/libqhull_r/qhull_r-exports.def b/src/libqhull_r/qhull_r-exports.def
index 325d57c..72f6ad0 100644
--- a/src/libqhull_r/qhull_r-exports.def
+++ b/src/libqhull_r/qhull_r-exports.def
@@ -185,6 +185,7 @@ qh_memsetup
qh_memsize
qh_memstatistics
qh_memtotal
+qh_memcheck
qh_merge_degenredundant
qh_merge_nonconvex
qh_mergecycle
@@ -372,6 +373,7 @@ qh_settruncate
qh_setunique
qh_setvoronoi_all
qh_setzero
+qh_setendpointer
qh_sharpnewfacets
qh_skipfacet
qh_skipfilename
diff --git a/src/libqhull_r/user_r.h b/src/libqhull_r/user_r.h
index fc105b9..7cca65a 100644
--- a/src/libqhull_r/user_r.h
+++ b/src/libqhull_r/user_r.h
@@ -139,7 +139,7 @@ Code flags --
REALfloat = 1 all numbers are 'float' type
= 0 all numbers are 'double' type
*/
-#define REALfloat 0
+#define REALfloat 1
#if (REALfloat == 1)
#define realT float
--
2.16.2.windows.1

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

View file

@ -15,6 +15,7 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define INTENSITY_AMBIENT 0.3 #define INTENSITY_AMBIENT 0.3
uniform mat4 volume_world_matrix; uniform mat4 volume_world_matrix;
uniform float object_max_z;
// x = tainted, y = specular; // x = tainted, y = specular;
varying vec2 intensity; varying vec2 intensity;
@ -42,6 +43,12 @@ void main()
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
// Scaled to widths of the Z texture. // Scaled to widths of the Z texture.
object_z = (volume_world_matrix * gl_Vertex).z; if (object_max_z > 0.0)
// when rendering the overlay
object_z = object_max_z * gl_MultiTexCoord0.y;
else
// when rendering the volumes
object_z = (volume_world_matrix * gl_Vertex).z;
gl_Position = ftransform(); gl_Position = ftransform();
} }

View file

@ -12,14 +12,12 @@ add_subdirectory(poly2tri)
add_subdirectory(qhull) add_subdirectory(qhull)
add_subdirectory(Shiny) add_subdirectory(Shiny)
add_subdirectory(semver) add_subdirectory(semver)
add_subdirectory(libigl)
# Adding libnest2d project for bin packing... # Adding libnest2d project for bin packing...
set(LIBNEST2D_UNITTESTS ON CACHE BOOL "Force generating unittests for libnest2d") set(LIBNEST2D_UNITTESTS ON CACHE BOOL "Force generating unittests for libnest2d")
add_subdirectory(libnest2d) add_subdirectory(libnest2d)
include_directories(${LIBDIR}/qhull/src)
#message(STATUS ${LIBDIR}/qhull/src)
add_subdirectory(libslic3r) add_subdirectory(libslic3r)
if (SLIC3R_GUI) if (SLIC3R_GUI)
@ -142,7 +140,7 @@ if (MSVC)
target_compile_definitions(PrusaSlicer_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE) target_compile_definitions(PrusaSlicer_app_gui PRIVATE -DSLIC3R_WRAPPER_NOCONSOLE)
add_dependencies(PrusaSlicer_app_gui PrusaSlicer) add_dependencies(PrusaSlicer_app_gui PrusaSlicer)
set_target_properties(PrusaSlicer_app_gui PROPERTIES OUTPUT_NAME "prusa-slicer") set_target_properties(PrusaSlicer_app_gui PROPERTIES OUTPUT_NAME "prusa-slicer")
target_include_directories(PrusaSlicer_app_gui SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) target_link_libraries(PrusaSlicer_app_gui PRIVATE boost_headeronly)
add_executable(PrusaSlicer_app_console PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc) add_executable(PrusaSlicer_app_console PrusaSlicer_app_msvc.cpp ${CMAKE_CURRENT_BINARY_DIR}/PrusaSlicer.rc)
# Generate debug symbols even in release mode. # Generate debug symbols even in release mode.
@ -150,7 +148,7 @@ if (MSVC)
target_compile_definitions(PrusaSlicer_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE) target_compile_definitions(PrusaSlicer_app_console PRIVATE -DSLIC3R_WRAPPER_CONSOLE)
add_dependencies(PrusaSlicer_app_console PrusaSlicer) add_dependencies(PrusaSlicer_app_console PrusaSlicer)
set_target_properties(PrusaSlicer_app_console PROPERTIES OUTPUT_NAME "prusa-slicer-console") set_target_properties(PrusaSlicer_app_console PROPERTIES OUTPUT_NAME "prusa-slicer-console")
target_include_directories(PrusaSlicer_app_console SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) target_link_libraries(PrusaSlicer_app_console PRIVATE boost_headeronly)
endif () endif ()
# Link the resources dir to where Slic3r GUI expects it # Link the resources dir to where Slic3r GUI expects it

View file

@ -7,10 +7,13 @@
#include <Windows.h> #include <Windows.h>
#include <wchar.h> #include <wchar.h>
#ifdef SLIC3R_GUI #ifdef SLIC3R_GUI
extern "C"
{
// Let the NVIDIA and AMD know we want to use their graphics card // Let the NVIDIA and AMD know we want to use their graphics card
// on a dual graphics card system. // on a dual graphics card system.
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */
#endif /* WIN32 */ #endif /* WIN32 */
@ -241,8 +244,7 @@ int CLI::run(int argc, char **argv)
} else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") { } else if (opt_key == "cut" || opt_key == "cut_x" || opt_key == "cut_y") {
std::vector<Model> new_models; std::vector<Model> new_models;
for (auto &model : m_models) { for (auto &model : m_models) {
model.repair(); model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0
model.translate(0, 0, -model.bounding_box().min.z()); // align to z = 0
size_t num_objects = model.objects.size(); size_t num_objects = model.objects.size();
for (size_t i = 0; i < num_objects; ++ i) { for (size_t i = 0; i < num_objects; ++ i) {
@ -301,8 +303,9 @@ int CLI::run(int argc, char **argv)
} }
} }
} else if (opt_key == "repair") { } else if (opt_key == "repair") {
for (auto &model : m_models) // Models are repaired by default.
model.repair(); //for (auto &model : m_models)
// model.repair();
} else { } else {
boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl;
return 1; return 1;

View file

@ -8,10 +8,13 @@
#include <wchar.h> #include <wchar.h>
#ifdef SLIC3R_GUI #ifdef SLIC3R_GUI
extern "C"
{
// Let the NVIDIA and AMD know we want to use their graphics card // Let the NVIDIA and AMD know we want to use their graphics card
// on a dual graphics card system. // on a dual graphics card system.
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
}
#endif /* SLIC3R_GUI */ #endif /* SLIC3R_GUI */
#include <stdlib.h> #include <stdlib.h>

View file

@ -11,4 +11,4 @@ add_library(admesh STATIC
util.cpp util.cpp
) )
target_include_directories(admesh SYSTEM PRIVATE ${Boost_INCLUDE_DIRS}) target_link_libraries(admesh PRIVATE boost_headeronly)

File diff suppressed because it is too large Load diff

View file

@ -25,271 +25,214 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
// Boost pool: Don't use mutexes to synchronize memory allocation.
#define BOOST_POOL_NO_MT
#include <boost/pool/object_pool.hpp>
#include "stl.h" #include "stl.h"
static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag); static void reverse_facet(stl_file *stl, int facet_num)
{
++ stl->stats.facets_reversed;
static void int neighbor[3] = { stl->neighbors_start[facet_num].neighbor[0], stl->neighbors_start[facet_num].neighbor[1], stl->neighbors_start[facet_num].neighbor[2] };
stl_reverse_facet(stl_file *stl, int facet_num) { int vnot[3] = { stl->neighbors_start[facet_num].which_vertex_not[0], stl->neighbors_start[facet_num].which_vertex_not[1], stl->neighbors_start[facet_num].which_vertex_not[2] };
stl_vertex tmp_vertex;
/* int tmp_neighbor;*/
int neighbor[3];
int vnot[3];
stl->stats.facets_reversed += 1; // reverse the facet
stl_vertex tmp_vertex = stl->facet_start[facet_num].vertex[0];
stl->facet_start[facet_num].vertex[0] = stl->facet_start[facet_num].vertex[1];
stl->facet_start[facet_num].vertex[1] = tmp_vertex;
neighbor[0] = stl->neighbors_start[facet_num].neighbor[0]; // fix the vnots of the neighboring facets
neighbor[1] = stl->neighbors_start[facet_num].neighbor[1]; if (neighbor[0] != -1)
neighbor[2] = stl->neighbors_start[facet_num].neighbor[2]; stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = (stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
vnot[0] = stl->neighbors_start[facet_num].which_vertex_not[0]; if (neighbor[1] != -1)
vnot[1] = stl->neighbors_start[facet_num].which_vertex_not[1]; stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = (stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
vnot[2] = stl->neighbors_start[facet_num].which_vertex_not[2]; if (neighbor[2] != -1)
stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] = (stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
/* reverse the facet */ // swap the neighbors of the facet that is being reversed
tmp_vertex = stl->facet_start[facet_num].vertex[0]; stl->neighbors_start[facet_num].neighbor[1] = neighbor[2];
stl->facet_start[facet_num].vertex[0] = stl->neighbors_start[facet_num].neighbor[2] = neighbor[1];
stl->facet_start[facet_num].vertex[1];
stl->facet_start[facet_num].vertex[1] = tmp_vertex;
/* fix the vnots of the neighboring facets */ // swap the vnots of the facet that is being reversed
if(neighbor[0] != -1) stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2];
stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1];
(stl->neighbors_start[neighbor[0]].
which_vertex_not[(vnot[0] + 1) % 3] + 3) % 6;
if(neighbor[1] != -1)
stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] =
(stl->neighbors_start[neighbor[1]].
which_vertex_not[(vnot[1] + 1) % 3] + 4) % 6;
if(neighbor[2] != -1)
stl->neighbors_start[neighbor[2]].which_vertex_not[(vnot[2] + 1) % 3] =
(stl->neighbors_start[neighbor[2]].
which_vertex_not[(vnot[2] + 1) % 3] + 2) % 6;
/* swap the neighbors of the facet that is being reversed */ // reverse the values of the vnots of the facet that is being reversed
stl->neighbors_start[facet_num].neighbor[1] = neighbor[2]; stl->neighbors_start[facet_num].which_vertex_not[0] = (stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6;
stl->neighbors_start[facet_num].neighbor[2] = neighbor[1]; stl->neighbors_start[facet_num].which_vertex_not[1] = (stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6;
stl->neighbors_start[facet_num].which_vertex_not[2] = (stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
/* swap the vnots of the facet that is being reversed */
stl->neighbors_start[facet_num].which_vertex_not[1] = vnot[2];
stl->neighbors_start[facet_num].which_vertex_not[2] = vnot[1];
/* reverse the values of the vnots of the facet that is being reversed */
stl->neighbors_start[facet_num].which_vertex_not[0] =
(stl->neighbors_start[facet_num].which_vertex_not[0] + 3) % 6;
stl->neighbors_start[facet_num].which_vertex_not[1] =
(stl->neighbors_start[facet_num].which_vertex_not[1] + 3) % 6;
stl->neighbors_start[facet_num].which_vertex_not[2] =
(stl->neighbors_start[facet_num].which_vertex_not[2] + 3) % 6;
} }
void // Returns true if the normal was flipped.
stl_fix_normal_directions(stl_file *stl) { static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
char *norm_sw; {
/* int edge_num;*/ stl_facet *facet = &stl->facet_start[facet_num];
/* int vnot;*/
int checked = 0;
int facet_num;
/* int next_facet;*/
int i;
int j;
struct stl_normal {
int facet_num;
struct stl_normal *next;
};
struct stl_normal *head;
struct stl_normal *tail;
struct stl_normal *newn;
struct stl_normal *temp;
int* reversed_ids; stl_normal normal;
int reversed_count = 0; stl_calculate_normal(normal, facet);
int id; stl_normalize_vector(normal);
int force_exit = 0; stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
if (stl->error) return; const float eps = 0.001f;
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
// Normal is within tolerance. It is not really necessary to change the values here, but just for consistency, I will.
facet->normal = normal;
return false;
}
// this may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209 stl_normal test_norm = facet->normal;
if (stl->stats.number_of_facets == 0) return; stl_normalize_vector(test_norm);
normal_dif = (normal - test_norm).cwiseAbs();
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
// The normal is not within tolerance, but direction is OK.
if (normal_fix_flag) {
facet->normal = normal;
++ stl->stats.normals_fixed;
}
return false;
}
/* Initialize linked list. */ test_norm *= -1.f;
head = (struct stl_normal*)malloc(sizeof(struct stl_normal)); normal_dif = (normal - test_norm).cwiseAbs();
if(head == NULL) perror("stl_fix_normal_directions"); if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
tail = (struct stl_normal*)malloc(sizeof(struct stl_normal)); // The normal is not within tolerance and backwards.
if(tail == NULL) perror("stl_fix_normal_directions"); if (normal_fix_flag) {
head->next = tail; facet->normal = normal;
tail->next = tail; ++ stl->stats.normals_fixed;
}
/* Initialize list that keeps track of already fixed facets. */ return true;
norm_sw = (char*)calloc(stl->stats.number_of_facets, sizeof(char)); }
if(norm_sw == NULL) perror("stl_fix_normal_directions"); if (normal_fix_flag) {
facet->normal = normal;
/* Initialize list that keeps track of reversed facets. */ ++ stl->stats.normals_fixed;
reversed_ids = (int*)calloc(stl->stats.number_of_facets, sizeof(int)); }
if (reversed_ids == NULL) perror("stl_fix_normal_directions reversed_ids"); // Status is unknown.
return false;
facet_num = 0;
/* If normal vector is not within tolerance and backwards:
Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
of it being wrong randomly are low if most of the triangles are right: */
if (stl_check_normal_vector(stl, 0, 0) == 2) {
stl_reverse_facet(stl, 0);
reversed_ids[reversed_count++] = 0;
}
/* Say that we've fixed this facet: */
norm_sw[facet_num] = 1;
checked++;
for(;;) {
/* Add neighbors_to_list.
Add unconnected neighbors to the list:a */
for(j = 0; j < 3; j++) {
/* Reverse the neighboring facets if necessary. */
if(stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
/* If the facet has a neighbor that is -1, it means that edge isn't shared by another facet */
if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
/* trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206) */
for (id = reversed_count - 1; id >= 0; --id) {
stl_reverse_facet(stl, reversed_ids[id]);
}
force_exit = 1;
break;
} else {
stl_reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
reversed_ids[reversed_count++] = stl->neighbors_start[facet_num].neighbor[j];
}
}
}
/* If this edge of the facet is connected: */
if(stl->neighbors_start[facet_num].neighbor[j] != -1) {
/* If we haven't fixed this facet yet, add it to the list: */
if(norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
/* Add node to beginning of list. */
newn = (struct stl_normal*)malloc(sizeof(struct stl_normal));
if(newn == NULL) perror("stl_fix_normal_directions");
newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
newn->next = head->next;
head->next = newn;
}
}
}
/* an error occourred, quit the for loop and exit */
if (force_exit) break;
/* Get next facet to fix from top of list. */
if(head->next != tail) {
facet_num = head->next->facet_num;
if(norm_sw[facet_num] != 1) { /* If facet is in list mutiple times */
norm_sw[facet_num] = 1; /* Record this one as being fixed. */
checked++;
}
temp = head->next; /* Delete this facet from the list. */
head->next = head->next->next;
free(temp);
} else { /* if we ran out of facets to fix: */
/* All of the facets in this part have been fixed. */
stl->stats.number_of_parts += 1;
if(checked >= stl->stats.number_of_facets) {
/* All of the facets have been checked. Bail out. */
break;
} else {
/* There is another part here. Find it and continue. */
for(i = 0; i < stl->stats.number_of_facets; i++) {
if(norm_sw[i] == 0) {
/* This is the first facet of the next part. */
facet_num = i;
if(stl_check_normal_vector(stl, i, 0) == 2) {
stl_reverse_facet(stl, i);
reversed_ids[reversed_count++] = i;
}
norm_sw[facet_num] = 1;
checked++;
break;
}
}
}
}
}
free(head);
free(tail);
free(reversed_ids);
free(norm_sw);
} }
static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag) { void stl_fix_normal_directions(stl_file *stl)
/* Returns 0 if the normal is within tolerance */ {
/* Returns 1 if the normal is not within tolerance, but direction is OK */ // This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
/* Returns 2 if the normal is not within tolerance and backwards */ if (stl->stats.number_of_facets == 0)
/* Returns 4 if the status is unknown. */ return;
stl_facet *facet; struct stl_normal {
int facet_num;
stl_normal *next;
};
facet = &stl->facet_start[facet_num]; // Initialize linked list.
boost::object_pool<stl_normal> pool;
stl_normal *head = pool.construct();
stl_normal *tail = pool.construct();
head->next = tail;
tail->next = tail;
stl_normal normal; // Initialize list that keeps track of already fixed facets.
stl_calculate_normal(normal, facet); std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
stl_normalize_vector(normal); // Initialize list that keeps track of reversed facets.
stl_normal normal_dif = (normal - facet->normal).cwiseAbs(); std::vector<int> reversed_ids(stl->stats.number_of_facets, 0);
const float eps = 0.001f; int facet_num = 0;
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { int reversed_count = 0;
/* It is not really necessary to change the values here */ // If normal vector is not within tolerance and backwards:
/* but just for consistency, I will. */ // Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
facet->normal = normal; // of it being wrong randomly are low if most of the triangles are right:
return 0; if (check_normal_vector(stl, 0, 0)) {
} reverse_facet(stl, 0);
reversed_ids[reversed_count ++] = 0;
}
stl_normal test_norm = facet->normal; // Say that we've fixed this facet:
stl_normalize_vector(test_norm); norm_sw[facet_num] = 1;
normal_dif = (normal - test_norm).cwiseAbs(); int checked = 1;
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
if(normal_fix_flag) {
facet->normal = normal;
stl->stats.normals_fixed += 1;
}
return 1;
}
test_norm *= -1.f; for (;;) {
normal_dif = (normal - test_norm).cwiseAbs(); // Add neighbors_to_list. Add unconnected neighbors to the list.
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) { bool force_exit = false;
// Facet is backwards. for (int j = 0; j < 3; ++ j) {
if(normal_fix_flag) { // Reverse the neighboring facets if necessary.
facet->normal = normal; if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
stl->stats.normals_fixed += 1; // If the facet has a neighbor that is -1, it means that edge isn't shared by another facet
} if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
return 2; if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
} // trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206)
if(normal_fix_flag) { for (int id = reversed_count - 1; id >= 0; -- id)
facet->normal = normal; reverse_facet(stl, reversed_ids[id]);
stl->stats.normals_fixed += 1; force_exit = true;
} break;
return 4; }
reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
reversed_ids[reversed_count ++] = stl->neighbors_start[facet_num].neighbor[j];
}
}
// If this edge of the facet is connected:
if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
// If we haven't fixed this facet yet, add it to the list:
if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
// Add node to beginning of list.
stl_normal *newn = pool.construct();
newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
newn->next = head->next;
head->next = newn;
}
}
}
// an error occourred, quit the for loop and exit
if (force_exit)
break;
// Get next facet to fix from top of list.
if (head->next != tail) {
facet_num = head->next->facet_num;
if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times
norm_sw[facet_num] = 1; // Record this one as being fixed.
++ checked;
}
stl_normal *temp = head->next; // Delete this facet from the list.
head->next = head->next->next;
// pool.destroy(temp);
} else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
++ stl->stats.number_of_parts;
if (checked >= stl->stats.number_of_facets)
// All of the facets have been checked. Bail out.
break;
// There is another part here. Find it and continue.
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
if (norm_sw[i] == 0) {
// This is the first facet of the next part.
facet_num = i;
if (check_normal_vector(stl, i, 0)) {
reverse_facet(stl, i);
reversed_ids[reversed_count++] = i;
}
norm_sw[facet_num] = 1;
++ checked;
break;
}
}
}
// pool.destroy(head);
// pool.destroy(tail);
} }
void stl_fix_normal_values(stl_file *stl) { void stl_fix_normal_values(stl_file *stl)
int i; {
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
if (stl->error) return; check_normal_vector(stl, i, 1);
for(i = 0; i < stl->stats.number_of_facets; i++) {
stl_check_normal_vector(stl, i, 1);
}
} }
void stl_reverse_all_facets(stl_file *stl) void stl_reverse_all_facets(stl_file *stl)
{ {
if (stl->error) stl_normal normal;
return; for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
reverse_facet(stl, i);
stl_normal normal; stl_calculate_normal(normal, &stl->facet_start[i]);
for(int i = 0; i < stl->stats.number_of_facets; i++) { stl_normalize_vector(normal);
stl_reverse_facet(stl, i); stl->facet_start[i].normal = normal;
stl_calculate_normal(normal, &stl->facet_start[i]); }
stl_normalize_vector(normal);
stl->facet_start[i].normal = normal;
}
} }

View file

@ -23,242 +23,237 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <vector>
#include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp> #include <boost/nowide/cstdio.hpp>
#include "stl.h" #include "stl.h"
void void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its)
stl_invalidate_shared_vertices(stl_file *stl) { {
if (stl->error) return; // 3 indices to vertex per face
its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1));
// Shared vertices (3D coordinates)
its.vertices.clear();
its.vertices.reserve(stl->stats.number_of_facets / 2);
if (stl->v_indices != NULL) { // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
free(stl->v_indices); // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
stl->v_indices = NULL; // are marked with a unique fan_traversal_stamp.
} unsigned int fan_traversal_stamp = 0;
if (stl->v_shared != NULL) { std::vector<unsigned int> fan_traversal_facet_visited(stl->stats.number_of_facets, 0);
free(stl->v_shared);
stl->v_shared = NULL; for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) {
} for (int j = 0; j < 3; ++ j) {
if (its.indices[facet_idx][j] != -1)
// Shared vertex was already assigned.
continue;
// Create a new shared vertex.
its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]);
// Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan.
int facet_in_fan_idx = facet_idx;
bool edge_direction = false;
bool traversal_reversed = false;
int vnot = (j + 2) % 3;
// Increase the
++ fan_traversal_stamp;
for (;;) {
// Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index.
int next_edge = 0;
// Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex.
int pivot_vertex = 0;
if (vnot > 2) {
// The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore
// the neighboring facet is flipped.
if (! edge_direction) {
pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex;
} else {
pivot_vertex = (vnot + 1) % 3;
next_edge = vnot % 3;
}
edge_direction = ! edge_direction;
} else {
// The neighboring facet is correctly oriented.
if (! edge_direction) {
pivot_vertex = (vnot + 1) % 3;
next_edge = vnot;
} else {
pivot_vertex = (vnot + 2) % 3;
next_edge = pivot_vertex;
}
}
its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1;
fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge];
if (next_facet == -1) {
// No neighbor going in the current direction.
if (traversal_reversed) {
// Went to one limit, then turned back and reached the other limit. Quit the fan traversal.
break;
} else {
// Reached the first limit. Now try to reverse and traverse up to the other limit.
edge_direction = true;
vnot = (j + 1) % 3;
traversal_reversed = true;
facet_in_fan_idx = facet_idx;
}
} else if (next_facet == facet_idx) {
// Traversed a closed fan all around.
// assert(! traversal_reversed);
break;
} else if (next_facet >= (int)stl->stats.number_of_facets) {
// The mesh is not valid!
// assert(false);
break;
} else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) {
// Traversed a closed fan all around, but did not reach the starting face.
// This indicates an invalid geometry (non-manifold).
//assert(false);
break;
} else {
// Continue traversal.
// next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge];
facet_in_fan_idx = next_facet;
}
}
}
}
} }
void bool its_write_off(const indexed_triangle_set &its, const char *file)
stl_generate_shared_vertices(stl_file *stl) { {
int i; /* Open the file */
int j; FILE *fp = boost::nowide::fopen(file, "w");
int first_facet; if (fp == nullptr) {
int direction; BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
int facet_num; return false;
int vnot; }
int next_edge;
int pivot_vertex;
int next_facet;
int reversed;
if (stl->error) return; fprintf(fp, "OFF\n");
fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size());
for (int i = 0; i < its.vertices.size(); ++ i)
fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
for (uint32_t i = 0; i < its.indices.size(); ++ i)
fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
fclose(fp);
return true;
}
/* make sure this function is idempotent and does not leak memory */ bool its_write_vrml(const indexed_triangle_set &its, const char *file)
stl_invalidate_shared_vertices(stl); {
/* Open the file */
FILE *fp = boost::nowide::fopen(file, "w");
if (fp == nullptr) {
BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing";
return false;
}
stl->v_indices = (v_indices_struct*) fprintf(fp, "#VRML V1.0 ascii\n\n");
calloc(stl->stats.number_of_facets, sizeof(v_indices_struct)); fprintf(fp, "Separator {\n");
if(stl->v_indices == NULL) perror("stl_generate_shared_vertices"); fprintf(fp, "\tDEF STLShape ShapeHints {\n");
stl->v_shared = (stl_vertex*) fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
calloc((stl->stats.number_of_facets / 2), sizeof(stl_vertex)); fprintf(fp, "\t\tfaceType CONVEX\n");
if(stl->v_shared == NULL) perror("stl_generate_shared_vertices"); fprintf(fp, "\t\tshapeType SOLID\n");
stl->stats.shared_malloced = stl->stats.number_of_facets / 2; fprintf(fp, "\t\tcreaseAngle 0.0\n");
stl->stats.shared_vertices = 0; fprintf(fp, "\t}\n");
fprintf(fp, "\tDEF STLModel Separator {\n");
fprintf(fp, "\t\tDEF STLColor Material {\n");
fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
fprintf(fp, "\t\t}\n");
fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
fprintf(fp, "\t\t\tpoint [\n");
for(i = 0; i < stl->stats.number_of_facets; i++) { int i = 0;
stl->v_indices[i].vertex[0] = -1; for (; i + 1 < its.vertices.size(); ++ i)
stl->v_indices[i].vertex[1] = -1; fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
stl->v_indices[i].vertex[2] = -1; fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
} fprintf(fp, "\t\t}\n");
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
fprintf(fp, "\t\t\tcoordIndex [\n");
for (size_t i = 0; i + 1 < its.indices.size(); ++ i)
fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
fprintf(fp, "\t\t}\n");
fprintf(fp, "\t}\n");
fprintf(fp, "}\n");
fclose(fp);
return true;
}
bool its_write_obj(const indexed_triangle_set &its, const char *file)
{
FILE *fp = boost::nowide::fopen(file, "w");
if (fp == nullptr) {
BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
return false;
}
for (size_t i = 0; i < its.vertices.size(); ++ i)
fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
for (size_t i = 0; i < its.indices.size(); ++ i)
fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1);
fclose(fp);
return true;
}
for(i = 0; i < stl->stats.number_of_facets; i++) { // Check validity of the mesh, assert on error.
first_facet = i; bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
for(j = 0; j < 3; j++) { {
if(stl->v_indices[i].vertex[j] != -1) { assert(! stl->facet_start.empty());
continue; assert(stl->facet_start.size() == stl->stats.number_of_facets);
} assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
if(stl->stats.shared_vertices == stl->stats.shared_malloced) { assert(stl->facet_start.size() == stl->neighbors_start.size());
stl->stats.shared_malloced += 1024; assert(! stl->neighbors_start.empty());
stl->v_shared = (stl_vertex*)realloc(stl->v_shared, assert((its.indices.empty()) == (its.vertices.empty()));
stl->stats.shared_malloced * sizeof(stl_vertex)); assert(stl->stats.number_of_facets > 0);
if(stl->v_shared == NULL) perror("stl_generate_shared_vertices"); assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets);
}
stl->v_shared[stl->stats.shared_vertices] = #ifdef _DEBUG
stl->facet_start[i].vertex[j]; // Verify validity of neighborship data.
for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
direction = 0; const stl_neighbors &nbr = stl->neighbors_start[facet_idx];
reversed = 0; const int *vertices = its.indices.empty() ? nullptr : its.indices[facet_idx].data();
facet_num = i; for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
vnot = (j + 2) % 3; int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
assert(nbr_face < (int)stl->stats.number_of_facets);
for(;;) { if (nbr_face != -1) {
if(vnot > 2) { int nbr_vnot = nbr.which_vertex_not[nbr_idx];
if(direction == 0) { assert(nbr_vnot >= 0 && nbr_vnot < 6);
pivot_vertex = (vnot + 2) % 3; // Neighbor of the neighbor is the original face.
next_edge = pivot_vertex; assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx);
direction = 1; int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3];
} else { assert(vnot_back >= 0 && vnot_back < 6);
pivot_vertex = (vnot + 1) % 3; assert((nbr_vnot < 3) == (vnot_back < 3));
next_edge = vnot % 3; assert(vnot_back % 3 == (nbr_idx + 2) % 3);
direction = 0; if (vertices != nullptr) {
} // Has shared vertices.
} else { if (nbr_vnot < 3) {
if(direction == 0) { // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
pivot_vertex = (vnot + 1) % 3; assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
next_edge = vnot; } else {
} else { // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
pivot_vertex = (vnot + 2) % 3; assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
next_edge = pivot_vertex; }
} }
}
} }
stl->v_indices[facet_num].vertex[pivot_vertex] =
stl->stats.shared_vertices;
next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
if(next_facet == -1) {
if(reversed) {
break;
} else {
direction = 1;
vnot = (j + 1) % 3;
reversed = 1;
facet_num = first_facet;
}
} else if(next_facet != first_facet) {
vnot = stl->neighbors_start[facet_num].
which_vertex_not[next_edge];
facet_num = next_facet;
} else {
break;
}
}
stl->stats.shared_vertices += 1;
} }
} #endif /* _DEBUG */
return true;
} }
void // Check validity of the mesh, assert on error.
stl_write_off(stl_file *stl, const char *file) { bool stl_validate(const stl_file *stl)
int i; {
FILE *fp; indexed_triangle_set its;
char *error_msg; return stl_validate(stl, its);
if (stl->error) return;
/* Open the file */
fp = boost::nowide::fopen(file, "w");
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
fprintf(fp, "OFF\n");
fprintf(fp, "%d %d 0\n",
stl->stats.shared_vertices, stl->stats.number_of_facets);
for(i = 0; i < stl->stats.shared_vertices; i++) {
fprintf(fp, "\t%f %f %f\n",
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
}
for(i = 0; i < stl->stats.number_of_facets; i++) {
fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0],
stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
}
fclose(fp);
}
void
stl_write_vrml(stl_file *stl, const char *file) {
int i;
FILE *fp;
char *error_msg;
if (stl->error) return;
/* Open the file */
fp = boost::nowide::fopen(file, "w");
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
fprintf(fp, "#VRML V1.0 ascii\n\n");
fprintf(fp, "Separator {\n");
fprintf(fp, "\tDEF STLShape ShapeHints {\n");
fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
fprintf(fp, "\t\tfaceType CONVEX\n");
fprintf(fp, "\t\tshapeType SOLID\n");
fprintf(fp, "\t\tcreaseAngle 0.0\n");
fprintf(fp, "\t}\n");
fprintf(fp, "\tDEF STLModel Separator {\n");
fprintf(fp, "\t\tDEF STLColor Material {\n");
fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
fprintf(fp, "\t\t}\n");
fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
fprintf(fp, "\t\t\tpoint [\n");
for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
fprintf(fp, "\t\t\t\t%f %f %f,\n",
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
}
fprintf(fp, "\t\t\t\t%f %f %f]\n",
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
fprintf(fp, "\t\t}\n");
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
fprintf(fp, "\t\t\tcoordIndex [\n");
for(i = 0; i < (stl->stats.number_of_facets - 1); i++) {
fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", stl->v_indices[i].vertex[0],
stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
}
fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", stl->v_indices[i].vertex[0],
stl->v_indices[i].vertex[1], stl->v_indices[i].vertex[2]);
fprintf(fp, "\t\t}\n");
fprintf(fp, "\t}\n");
fprintf(fp, "}\n");
fclose(fp);
}
void stl_write_obj (stl_file *stl, const char *file) {
int i;
FILE* fp;
if (stl->error) return;
/* Open the file */
fp = boost::nowide::fopen(file, "w");
if (fp == NULL) {
char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
for (i = 0; i < stl->stats.shared_vertices; i++) {
fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
}
for (i = 0; i < stl->stats.number_of_facets; i++) {
fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
}
fclose(fp);
} }

View file

@ -27,6 +27,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <vector>
#include <Eigen/Geometry> #include <Eigen/Geometry>
// Size of the binary STL header, free form. // Size of the binary STL header, free form.
@ -40,22 +41,23 @@
typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex; typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex;
typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal; typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal;
typedef Eigen::Matrix<int, 3, 1, Eigen::DontAlign> stl_triangle_vertex_indices;
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
struct stl_facet { struct stl_facet {
stl_normal normal; stl_normal normal;
stl_vertex vertex[3]; stl_vertex vertex[3];
char extra[2]; char extra[2];
stl_facet rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) { stl_facet rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) const {
stl_facet out; stl_facet out;
out.normal = rot * this->normal; out.normal = rot * this->normal;
out.vertex[0] = rot * this->vertex[0]; out.vertex[0] = rot * this->vertex[0];
out.vertex[1] = rot * this->vertex[1]; out.vertex[1] = rot * this->vertex[1];
out.vertex[2] = rot * this->vertex[2]; out.vertex[2] = rot * this->vertex[2];
return out; return out;
} }
}; };
#define SIZEOF_STL_FACET 50 #define SIZEOF_STL_FACET 50
@ -67,104 +69,94 @@ static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrec
typedef enum {binary, ascii, inmemory} stl_type; typedef enum {binary, ascii, inmemory} stl_type;
typedef struct { struct stl_neighbors {
stl_vertex p1; stl_neighbors() { reset(); }
stl_vertex p2; void reset() {
int facet_number; neighbor[0] = -1;
} stl_edge; neighbor[1] = -1;
neighbor[2] = -1;
which_vertex_not[0] = -1;
which_vertex_not[1] = -1;
which_vertex_not[2] = -1;
}
int num_neighbors_missing() const { return (this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1); }
int num_neighbors() const { return 3 - this->num_neighbors_missing(); }
typedef struct stl_hash_edge { // Index of a neighbor facet.
// Key of a hash edge: sorted vertices of the edge. int neighbor[3];
uint32_t key[6]; // Index of an opposite vertex at the neighbor face.
// Compare two keys. char which_vertex_not[3];
bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; } };
bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; }
// Index of a facet owning this edge.
int facet_number;
// Index of this edge inside the facet with an index of facet_number.
// If this edge is stored backwards, which_edge is increased by 3.
int which_edge;
struct stl_hash_edge *next;
} stl_hash_edge;
typedef struct { struct stl_stats {
// Index of a neighbor facet. stl_stats() { this->reset(); }
int neighbor[3]; void reset() { memset(this, 0, sizeof(stl_stats)); this->volume = -1.0; }
// Index of an opposite vertex at the neighbor face. char header[81];
char which_vertex_not[3]; stl_type type;
} stl_neighbors; uint32_t number_of_facets;
stl_vertex max;
stl_vertex min;
stl_vertex size;
float bounding_diameter;
float shortest_edge;
float volume;
int connected_edges;
int connected_facets_1_edge;
int connected_facets_2_edge;
int connected_facets_3_edge;
int facets_w_1_bad_edge;
int facets_w_2_bad_edge;
int facets_w_3_bad_edge;
int original_num_facets;
int edges_fixed;
int degenerate_facets;
int facets_removed;
int facets_added;
int facets_reversed;
int backwards_edges;
int normals_fixed;
int number_of_parts;
};
typedef struct { struct stl_file {
int vertex[3]; stl_file() {}
} v_indices_struct;
typedef struct { void clear() {
char header[81]; this->facet_start.clear();
stl_type type; this->neighbors_start.clear();
uint32_t number_of_facets; this->stats.reset();
stl_vertex max; }
stl_vertex min;
stl_vertex size;
float bounding_diameter;
float shortest_edge;
float volume;
unsigned number_of_blocks;
int connected_edges;
int connected_facets_1_edge;
int connected_facets_2_edge;
int connected_facets_3_edge;
int facets_w_1_bad_edge;
int facets_w_2_bad_edge;
int facets_w_3_bad_edge;
int original_num_facets;
int edges_fixed;
int degenerate_facets;
int facets_removed;
int facets_added;
int facets_reversed;
int backwards_edges;
int normals_fixed;
int number_of_parts;
int malloced;
int freed;
int facets_malloced;
int collisions;
int shared_vertices;
int shared_malloced;
} stl_stats;
typedef struct { std::vector<stl_facet> facet_start;
FILE *fp; std::vector<stl_neighbors> neighbors_start;
stl_facet *facet_start; // Statistics
stl_hash_edge **heads; stl_stats stats;
stl_hash_edge *tail; };
int M;
stl_neighbors *neighbors_start;
v_indices_struct *v_indices;
stl_vertex *v_shared;
stl_stats stats;
char error;
} stl_file;
struct indexed_triangle_set
{
indexed_triangle_set() {}
extern void stl_open(stl_file *stl, const char *file); void clear() { indices.clear(); vertices.clear(); }
extern void stl_close(stl_file *stl);
std::vector<stl_triangle_vertex_indices> indices;
std::vector<stl_vertex> vertices;
//FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
//std::vector<stl_normal> normals
};
extern bool stl_open(stl_file *stl, const char *file);
extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file); extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
extern void stl_print_neighbors(stl_file *stl, char *file); extern bool stl_print_neighbors(stl_file *stl, char *file);
extern void stl_put_little_int(FILE *fp, int value_in); extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label);
extern void stl_put_little_float(FILE *fp, float value_in); extern bool stl_write_binary(stl_file *stl, const char *file, const char *label);
extern void stl_write_ascii(stl_file *stl, const char *file, const char *label);
extern void stl_write_binary(stl_file *stl, const char *file, const char *label);
extern void stl_write_binary_block(stl_file *stl, FILE *fp);
extern void stl_check_facets_exact(stl_file *stl); extern void stl_check_facets_exact(stl_file *stl);
extern void stl_check_facets_nearby(stl_file *stl, float tolerance); extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
extern void stl_remove_unconnected_facets(stl_file *stl); extern void stl_remove_unconnected_facets(stl_file *stl);
extern void stl_write_vertex(stl_file *stl, int facet, int vertex); extern void stl_write_vertex(stl_file *stl, int facet, int vertex);
extern void stl_write_facet(stl_file *stl, char *label, int facet); extern void stl_write_facet(stl_file *stl, char *label, int facet);
extern void stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge);
extern void stl_write_neighbor(stl_file *stl, int facet); extern void stl_write_neighbor(stl_file *stl, int facet);
extern void stl_write_quad_object(stl_file *stl, char *file); extern bool stl_write_quad_object(stl_file *stl, char *file);
extern void stl_verify_neighbors(stl_file *stl); extern void stl_verify_neighbors(stl_file *stl);
extern void stl_fill_holes(stl_file *stl); extern void stl_fill_holes(stl_file *stl);
extern void stl_fix_normal_directions(stl_file *stl); extern void stl_fix_normal_directions(stl_file *stl);
@ -186,36 +178,30 @@ extern void stl_get_size(stl_file *stl);
template<typename T> template<typename T>
extern void stl_transform(stl_file *stl, T *trafo3x4) extern void stl_transform(stl_file *stl, T *trafo3x4)
{ {
if (stl->error) for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
return; stl_facet &face = stl->facet_start[i_face];
for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
stl_vertex &v_dst = face.vertex[i_vertex];
stl_vertex v_src = v_dst;
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
}
stl_vertex &v_dst = face.normal;
stl_vertex v_src = v_dst;
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2));
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2));
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
}
for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { stl_get_size(stl);
stl_facet &face = stl->facet_start[i_face];
for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
stl_vertex &v_dst = face.vertex[i_vertex];
stl_vertex v_src = v_dst;
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
}
stl_vertex &v_dst = face.normal;
stl_vertex v_src = v_dst;
v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2));
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2));
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2));
}
stl_get_size(stl);
} }
template<typename T> template<typename T>
inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t) inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
{ {
if (stl->error)
return;
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0); const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
stl_facet &f = stl->facet_start[i]; stl_facet &f = stl->facet_start[i];
for (size_t j = 0; j < 3; ++j) for (size_t j = 0; j < 3; ++j)
f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval(); f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval();
@ -228,10 +214,7 @@ inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Aff
template<typename T> template<typename T>
inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m) inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
{ {
if (stl->error) for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
return;
for (size_t i = 0; i < stl->stats.number_of_facets; ++i) {
stl_facet &f = stl->facet_start[i]; stl_facet &f = stl->facet_start[i];
for (size_t j = 0; j < 3; ++j) for (size_t j = 0; j < 3; ++j)
f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval(); f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval();
@ -241,13 +224,43 @@ inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::Don
stl_get_size(stl); stl_get_size(stl);
} }
extern void stl_open_merge(stl_file *stl, char *file);
extern void stl_invalidate_shared_vertices(stl_file *stl); template<typename T>
extern void stl_generate_shared_vertices(stl_file *stl); extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
extern void stl_write_obj(stl_file *stl, const char *file); {
extern void stl_write_off(stl_file *stl, const char *file); for (stl_vertex &v_dst : its.vertices) {
extern void stl_write_dxf(stl_file *stl, const char *file, char *label); stl_vertex v_src = v_dst;
extern void stl_write_vrml(stl_file *stl, const char *file); v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
}
}
template<typename T>
inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
{
const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
for (stl_vertex &v : its.vertices)
v = (t * v.template cast<T>()).template cast<float>().eval();
}
template<typename T>
inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
{
for (stl_vertex &v : its.vertices)
v = (m * v.template cast<T>()).template cast<float>().eval();
}
extern void its_rotate_x(indexed_triangle_set &its, float angle);
extern void its_rotate_y(indexed_triangle_set &its, float angle);
extern void its_rotate_z(indexed_triangle_set &its, float angle);
extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its);
extern bool its_write_obj(const indexed_triangle_set &its, const char *file);
extern bool its_write_off(const indexed_triangle_set &its, const char *file);
extern bool its_write_vrml(const indexed_triangle_set &its, const char *file);
extern bool stl_write_dxf(stl_file *stl, const char *file, char *label);
inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) { inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]); normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
} }
@ -258,24 +271,18 @@ inline void stl_normalize_vector(stl_normal &normal) {
else else
normal *= float(1.0 / length); normal *= float(1.0 / length);
} }
inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) {
return (a(0) != b(0)) ? (a(0) < b(0)) :
((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2)));
}
extern void stl_calculate_volume(stl_file *stl); extern void stl_calculate_volume(stl_file *stl);
extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag); extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag);
extern void stl_initialize(stl_file *stl);
extern void stl_count_facets(stl_file *stl, const char *file);
extern void stl_allocate(stl_file *stl); extern void stl_allocate(stl_file *stl);
extern void stl_read(stl_file *stl, int first_facet, bool first); extern void stl_read(stl_file *stl, int first_facet, bool first);
extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first); extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
extern void stl_reallocate(stl_file *stl); extern void stl_reallocate(stl_file *stl);
extern void stl_add_facet(stl_file *stl, stl_facet *new_facet); extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet);
extern void stl_clear_error(stl_file *stl); // Validate the mesh, assert on error.
extern int stl_get_error(stl_file *stl); extern bool stl_validate(const stl_file *stl);
extern void stl_exit_on_error(stl_file *stl); extern bool stl_validate(const stl_file *stl, const indexed_triangle_set &its);
#endif #endif

View file

@ -22,159 +22,86 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/predef/other/endian.h>
#include "stl.h" #include "stl.h"
#include <boost/nowide/cstdio.hpp> void stl_stats_out(stl_file *stl, FILE *file, char *input_file)
#include <boost/detail/endian.hpp> {
// This is here for Slic3r, without our config.h it won't use this part of the code anyway.
#if !defined(SEEK_SET)
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#endif
void
stl_stats_out(stl_file *stl, FILE *file, char *input_file) {
if (stl->error) return;
/* this is here for Slic3r, without our config.h
it won't use this part of the code anyway */
#ifndef VERSION #ifndef VERSION
#define VERSION "unknown" #define VERSION "unknown"
#endif #endif
fprintf(file, "\n\ fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n");
================= Results produced by ADMesh version " VERSION " ================\n"); fprintf(file, "Input file : %s\n", input_file);
fprintf(file, "\ if (stl->stats.type == binary)
Input file : %s\n", input_file); fprintf(file, "File type : Binary STL file\n");
if(stl->stats.type == binary) { else
fprintf(file, "\ fprintf(file, "File type : ASCII STL file\n");
File type : Binary STL file\n"); fprintf(file, "Header : %s\n", stl->stats.header);
} else { fprintf(file, "============== Size ==============\n");
fprintf(file, "\ fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0));
File type : ASCII STL file\n"); fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1));
} fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2));
fprintf(file, "\ fprintf(file, "========= Facet Status ========== Original ============ Final ====\n");
Header : %s\n", stl->stats.header); fprintf(file, "Number of facets : %5d %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets);
fprintf(file, "============== Size ==============\n"); fprintf(file, "Facets with 1 disconnected edge : %5d %5d\n",
fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge);
stl->stats.min(0), stl->stats.max(0)); fprintf(file, "Facets with 2 disconnected edges : %5d %5d\n",
fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge);
stl->stats.min(1), stl->stats.max(1)); fprintf(file, "Facets with 3 disconnected edges : %5d %5d\n",
fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_1_edge);
stl->stats.min(2), stl->stats.max(2)); fprintf(file, "Total disconnected facets : %5d %5d\n",
stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge + stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets - stl->stats.connected_facets_3_edge);
fprintf(file, "\ fprintf(file, "=== Processing Statistics === ===== Other Statistics =====\n");
========= Facet Status ========== Original ============ Final ====\n"); fprintf(file, "Number of parts : %5d Volume : %f\n", stl->stats.number_of_parts, stl->stats.volume);
fprintf(file, "\ fprintf(file, "Degenerate facets : %5d\n", stl->stats.degenerate_facets);
Number of facets : %5d %5d\n", fprintf(file, "Edges fixed : %5d\n", stl->stats.edges_fixed);
stl->stats.original_num_facets, stl->stats.number_of_facets); fprintf(file, "Facets removed : %5d\n", stl->stats.facets_removed);
fprintf(file, "\ fprintf(file, "Facets added : %5d\n", stl->stats.facets_added);
Facets with 1 disconnected edge : %5d %5d\n", fprintf(file, "Facets reversed : %5d\n", stl->stats.facets_reversed);
stl->stats.facets_w_1_bad_edge, stl->stats.connected_facets_2_edge - fprintf(file, "Backwards edges : %5d\n", stl->stats.backwards_edges);
stl->stats.connected_facets_3_edge); fprintf(file, "Normals fixed : %5d\n", stl->stats.normals_fixed);
fprintf(file, "\
Facets with 2 disconnected edges : %5d %5d\n",
stl->stats.facets_w_2_bad_edge, stl->stats.connected_facets_1_edge -
stl->stats.connected_facets_2_edge);
fprintf(file, "\
Facets with 3 disconnected edges : %5d %5d\n",
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
stl->stats.connected_facets_1_edge);
fprintf(file, "\
Total disconnected facets : %5d %5d\n",
stl->stats.facets_w_1_bad_edge + stl->stats.facets_w_2_bad_edge +
stl->stats.facets_w_3_bad_edge, stl->stats.number_of_facets -
stl->stats.connected_facets_3_edge);
fprintf(file,
"=== Processing Statistics === ===== Other Statistics =====\n");
fprintf(file, "\
Number of parts : %5d Volume : % f\n",
stl->stats.number_of_parts, stl->stats.volume);
fprintf(file, "\
Degenerate facets : %5d\n", stl->stats.degenerate_facets);
fprintf(file, "\
Edges fixed : %5d\n", stl->stats.edges_fixed);
fprintf(file, "\
Facets removed : %5d\n", stl->stats.facets_removed);
fprintf(file, "\
Facets added : %5d\n", stl->stats.facets_added);
fprintf(file, "\
Facets reversed : %5d\n", stl->stats.facets_reversed);
fprintf(file, "\
Backwards edges : %5d\n", stl->stats.backwards_edges);
fprintf(file, "\
Normals fixed : %5d\n", stl->stats.normals_fixed);
} }
void bool stl_write_ascii(stl_file *stl, const char *file, const char *label)
stl_write_ascii(stl_file *stl, const char *file, const char *label) { {
int i; FILE *fp = boost::nowide::fopen(file, "w");
char *error_msg; if (fp == nullptr) {
BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
return false;
}
if (stl->error) return; fprintf(fp, "solid %s\n", label);
/* Open the file */ for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
FILE *fp = boost::nowide::fopen(file, "w"); fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2));
if(fp == NULL) { fprintf(fp, " outer loop\n");
error_msg = (char*) fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
file); fprintf(fp, " endloop\n");
perror(error_msg); fprintf(fp, " endfacet\n");
free(error_msg); }
stl->error = 1;
return;
}
fprintf(fp, "solid %s\n", label); fprintf(fp, "endsolid %s\n", label);
fclose(fp);
for(i = 0; i < stl->stats.number_of_facets; i++) { return true;
fprintf(fp, " facet normal % .8E % .8E % .8E\n",
stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
stl->facet_start[i].normal(2));
fprintf(fp, " outer loop\n");
fprintf(fp, " vertex % .8E % .8E % .8E\n",
stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
stl->facet_start[i].vertex[0](2));
fprintf(fp, " vertex % .8E % .8E % .8E\n",
stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
stl->facet_start[i].vertex[1](2));
fprintf(fp, " vertex % .8E % .8E % .8E\n",
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
stl->facet_start[i].vertex[2](2));
fprintf(fp, " endloop\n");
fprintf(fp, " endfacet\n");
}
fprintf(fp, "endsolid %s\n", label);
fclose(fp);
} }
void bool stl_print_neighbors(stl_file *stl, char *file)
stl_print_neighbors(stl_file *stl, char *file) { {
int i; FILE *fp = boost::nowide::fopen(file, "w");
FILE *fp; if (fp == nullptr) {
char *error_msg; BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing";
return false;
}
if (stl->error) return; for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
/* Open the file */
fp = boost::nowide::fopen(file, "w");
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
for(i = 0; i < stl->stats.number_of_facets; i++) {
fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
i, i,
stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[0],
(int)stl->neighbors_start[i].which_vertex_not[0], (int)stl->neighbors_start[i].which_vertex_not[0],
@ -182,234 +109,142 @@ stl_print_neighbors(stl_file *stl, char *file) {
(int)stl->neighbors_start[i].which_vertex_not[1], (int)stl->neighbors_start[i].which_vertex_not[1],
stl->neighbors_start[i].neighbor[2], stl->neighbors_start[i].neighbor[2],
(int)stl->neighbors_start[i].which_vertex_not[2]); (int)stl->neighbors_start[i].which_vertex_not[2]);
} }
fclose(fp); fclose(fp);
return true;
} }
#ifndef BOOST_LITTLE_ENDIAN #if BOOST_ENDIAN_BIG_BYTE
// Swap a buffer of 32bit data from little endian to big endian and vice versa. // Swap a buffer of 32bit data from little endian to big endian and vice versa.
void stl_internal_reverse_quads(char *buf, size_t cnt) void stl_internal_reverse_quads(char *buf, size_t cnt)
{ {
for (size_t i = 0; i < cnt; i += 4) { for (size_t i = 0; i < cnt; i += 4) {
std::swap(buf[i], buf[i+3]); std::swap(buf[i], buf[i+3]);
std::swap(buf[i+1], buf[i+2]); std::swap(buf[i+1], buf[i+2]);
} }
} }
#endif #endif
void bool stl_write_binary(stl_file *stl, const char *file, const char *label)
stl_write_binary(stl_file *stl, const char *file, const char *label) { {
FILE *fp; FILE *fp = boost::nowide::fopen(file, "wb");
int i; if (fp == nullptr) {
char *error_msg; BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing";
return false;
}
if (stl->error) return; fprintf(fp, "%s", label);
for (size_t i = strlen(label); i < LABEL_SIZE; ++ i)
putc(0, fp);
/* Open the file */ #if !defined(SEEK_SET)
fp = boost::nowide::fopen(file, "wb"); #define SEEK_SET 0
if(fp == NULL) { #endif
error_msg = (char*) fseek(fp, LABEL_SIZE, SEEK_SET);
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ #if BOOST_ENDIAN_LITTLE_BYTE
sprintf(error_msg, "stl_write_binary: Couldn't open %s for writing", fwrite(&stl->stats.number_of_facets, 4, 1, fp);
file); for (const stl_facet &facet : stl->facet_start)
perror(error_msg); fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
free(error_msg); #else /* BOOST_ENDIAN_LITTLE_BYTE */
stl->error = 1; char buffer[50];
return; // Convert the number of facets to little endian.
} memcpy(buffer, &stl->stats.number_of_facets, 4);
stl_internal_reverse_quads(buffer, 4);
fprintf(fp, "%s", label); fwrite(buffer, 4, 1, fp);
for(i = strlen(label); i < LABEL_SIZE; i++) putc(0, fp); for (i = 0; i < stl->stats.number_of_facets; ++ i) {
memcpy(buffer, stl->facet_start + i, 50);
fseek(fp, LABEL_SIZE, SEEK_SET); // Convert to little endian.
#ifdef BOOST_LITTLE_ENDIAN stl_internal_reverse_quads(buffer, 48);
fwrite(&stl->stats.number_of_facets, 4, 1, fp); fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
for (i = 0; i < stl->stats.number_of_facets; ++ i) }
fwrite(stl->facet_start + i, SIZEOF_STL_FACET, 1, fp); #endif /* BOOST_ENDIAN_LITTLE_BYTE */
#else /* BOOST_LITTLE_ENDIAN */ fclose(fp);
char buffer[50]; return true;
// Convert the number of facets to little endian.
memcpy(buffer, &stl->stats.number_of_facets, 4);
stl_internal_reverse_quads(buffer, 4);
fwrite(buffer, 4, 1, fp);
for (i = 0; i < stl->stats.number_of_facets; ++ i) {
memcpy(buffer, stl->facet_start + i, 50);
// Convert to little endian.
stl_internal_reverse_quads(buffer, 48);
fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
}
#endif /* BOOST_LITTLE_ENDIAN */
fclose(fp);
} }
void void stl_write_vertex(stl_file *stl, int facet, int vertex)
stl_write_vertex(stl_file *stl, int facet, int vertex) { {
if (stl->error) return; printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
stl->facet_start[facet].vertex[vertex](0), stl->facet_start[facet].vertex[vertex](0),
stl->facet_start[facet].vertex[vertex](1), stl->facet_start[facet].vertex[vertex](1),
stl->facet_start[facet].vertex[vertex](2)); stl->facet_start[facet].vertex[vertex](2));
} }
void void stl_write_facet(stl_file *stl, char *label, int facet)
stl_write_facet(stl_file *stl, char *label, int facet) { {
if (stl->error) return; printf("facet (%d)/ %s\n", facet, label);
printf("facet (%d)/ %s\n", facet, label); stl_write_vertex(stl, facet, 0);
stl_write_vertex(stl, facet, 0); stl_write_vertex(stl, facet, 1);
stl_write_vertex(stl, facet, 1); stl_write_vertex(stl, facet, 2);
stl_write_vertex(stl, facet, 2);
} }
void void stl_write_neighbor(stl_file *stl, int facet)
stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge) { {
if (stl->error) return; printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet,
printf("edge (%d)/(%d) %s\n", edge.facet_number, edge.which_edge, label); stl->neighbors_start[facet].neighbor[0],
if(edge.which_edge < 3) { stl->neighbors_start[facet].neighbor[1],
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3); stl->neighbors_start[facet].neighbor[2],
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3); stl->neighbors_start[facet].which_vertex_not[0],
} else { stl->neighbors_start[facet].which_vertex_not[1],
stl_write_vertex(stl, edge.facet_number, (edge.which_edge + 1) % 3); stl->neighbors_start[facet].which_vertex_not[2]);
stl_write_vertex(stl, edge.facet_number, edge.which_edge % 3);
}
} }
void bool stl_write_quad_object(stl_file *stl, char *file)
stl_write_neighbor(stl_file *stl, int facet) { {
if (stl->error) return; stl_vertex connect_color = stl_vertex::Zero();
printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet, stl_vertex uncon_1_color = stl_vertex::Zero();
stl->neighbors_start[facet].neighbor[0], stl_vertex uncon_2_color = stl_vertex::Zero();
stl->neighbors_start[facet].neighbor[1], stl_vertex uncon_3_color = stl_vertex::Zero();
stl->neighbors_start[facet].neighbor[2], stl_vertex color;
stl->neighbors_start[facet].which_vertex_not[0],
stl->neighbors_start[facet].which_vertex_not[1],
stl->neighbors_start[facet].which_vertex_not[2]);
}
void FILE *fp = boost::nowide::fopen(file, "w");
stl_write_quad_object(stl_file *stl, char *file) { if (fp == nullptr) {
FILE *fp; BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
int i; return false;
int j; }
char *error_msg;
stl_vertex connect_color = stl_vertex::Zero();
stl_vertex uncon_1_color = stl_vertex::Zero();
stl_vertex uncon_2_color = stl_vertex::Zero();
stl_vertex uncon_3_color = stl_vertex::Zero();
stl_vertex color;
if (stl->error) return; fprintf(fp, "CQUAD\n");
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
/* Open the file */ switch (stl->neighbors_start[i].num_neighbors_missing()) {
fp = boost::nowide::fopen(file, "w"); case 0: color = connect_color; break;
if(fp == NULL) { case 1: color = uncon_1_color; break;
error_msg = (char*) case 2: color = uncon_2_color; break;
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */ default: color = uncon_3_color;
sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing", }
file); fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
perror(error_msg); fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
free(error_msg); fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
stl->error = 1; fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
return;
}
fprintf(fp, "CQUAD\n");
for(i = 0; i < stl->stats.number_of_facets; i++) {
j = ((stl->neighbors_start[i].neighbor[0] == -1) +
(stl->neighbors_start[i].neighbor[1] == -1) +
(stl->neighbors_start[i].neighbor[2] == -1));
if(j == 0) {
color = connect_color;
} else if(j == 1) {
color = uncon_1_color;
} else if(j == 2) {
color = uncon_2_color;
} else {
color = uncon_3_color;
}
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
stl->facet_start[i].vertex[0](0),
stl->facet_start[i].vertex[0](1),
stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
stl->facet_start[i].vertex[1](0),
stl->facet_start[i].vertex[1](1),
stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
stl->facet_start[i].vertex[2](0),
stl->facet_start[i].vertex[2](1),
stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
stl->facet_start[i].vertex[2](0),
stl->facet_start[i].vertex[2](1),
stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
} }
fclose(fp); fclose(fp);
return true;
} }
void bool stl_write_dxf(stl_file *stl, const char *file, char *label)
stl_write_dxf(stl_file *stl, const char *file, char *label) { {
int i; FILE *fp = boost::nowide::fopen(file, "w");
FILE *fp; if (fp == nullptr) {
char *error_msg; BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
return false;
}
if (stl->error) return; fprintf(fp, "999\n%s\n", label);
fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\
0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n");
fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n");
/* Open the file */ fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
fp = boost::nowide::fopen(file, "w");
if(fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
fprintf(fp, "999\n%s\n", label); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n"); fprintf(fp, "0\n3DFACE\n8\n0\n");
fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\ fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n"); fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n"); fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
}
fprintf(fp, "0\nSECTION\n2\nENTITIES\n"); fprintf(fp, "0\nENDSEC\n0\nEOF\n");
fclose(fp);
for(i = 0; i < stl->stats.number_of_facets; i++) { return true;
fprintf(fp, "0\n3DFACE\n8\n0\n");
fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
stl->facet_start[i].vertex[0](2));
fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
stl->facet_start[i].vertex[1](2));
fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
stl->facet_start[i].vertex[2](2));
fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
stl->facet_start[i].vertex[2](2));
}
fprintf(fp, "0\nENDSEC\n0\nEOF\n");
fclose(fp);
}
void
stl_clear_error(stl_file *stl) {
stl->error = 0;
}
void
stl_exit_on_error(stl_file *stl) {
if (!stl->error) return;
stl->error = 0;
stl_close(stl);
exit(1);
}
int
stl_get_error(stl_file *stl) {
return stl->error;
} }

View file

@ -26,6 +26,7 @@
#include <math.h> #include <math.h>
#include <assert.h> #include <assert.h>
#include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp> #include <boost/nowide/cstdio.hpp>
#include <boost/detail/endian.hpp> #include <boost/detail/endian.hpp>
@ -35,351 +36,236 @@
#error "SEEK_SET not defined" #error "SEEK_SET not defined"
#endif #endif
void static FILE* stl_open_count_facets(stl_file *stl, const char *file)
stl_open(stl_file *stl, const char *file) { {
stl_initialize(stl); // Open the file in binary mode first.
stl_count_facets(stl, file); FILE *fp = boost::nowide::fopen(file, "rb");
stl_allocate(stl); if (fp == nullptr) {
stl_read(stl, 0, true); BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
if (stl->fp != nullptr) { return nullptr;
fclose(stl->fp); }
stl->fp = nullptr; // Find size of file.
} fseek(fp, 0, SEEK_END);
long file_size = ftell(fp);
// Check for binary or ASCII file.
fseek(fp, HEADER_SIZE, SEEK_SET);
unsigned char chtest[128];
if (! fread(chtest, sizeof(chtest), 1, fp)) {
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file;
fclose(fp);
return nullptr;
}
stl->stats.type = ascii;
for (size_t s = 0; s < sizeof(chtest); s++) {
if (chtest[s] > 127) {
stl->stats.type = binary;
break;
}
}
rewind(fp);
uint32_t num_facets = 0;
// Get the header and the number of facets in the .STL file.
// If the .STL file is binary, then do the following:
if (stl->stats.type == binary) {
// Test if the STL file has the right size.
if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) {
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size.";
fclose(fp);
return nullptr;
}
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
// Read the header.
if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79)
stl->stats.header[80] = '\0';
// Read the int following the header. This should contain # of facets.
uint32_t header_num_facets;
bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0;
#ifndef BOOST_LITTLE_ENDIAN
// Convert from little endian to big endian.
stl_internal_reverse_quads((char*)&header_num_facets, 4);
#endif /* BOOST_LITTLE_ENDIAN */
if (! header_num_faces_read || num_facets != header_num_facets)
BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file;
}
// Otherwise, if the .STL file is ASCII, then do the following:
else
{
// Reopen the file in text mode (for getting correct newlines on Windows)
// fix to silence a warning about unused return value.
// obviously if it fails we have problems....
fp = boost::nowide::freopen(file, "r", fp);
// do another null check to be safe
if (fp == nullptr) {
BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
fclose(fp);
return nullptr;
}
// Find the number of facets.
char linebuf[100];
int num_lines = 1;
while (fgets(linebuf, 100, fp) != nullptr) {
// Don't count short lines.
if (strlen(linebuf) <= 4)
continue;
// Skip solid/endsolid lines as broken STL file generators may put several of them.
if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0)
continue;
++ num_lines;
}
rewind(fp);
// Get the header.
int i = 0;
for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ;
stl->stats.header[i] = '\0'; // Lose the '\n'
stl->stats.header[80] = '\0';
num_facets = num_lines / ASCII_LINES_PER_FACET;
}
stl->stats.number_of_facets += num_facets;
stl->stats.original_num_facets = stl->stats.number_of_facets;
return fp;
} }
void /* Reads the contents of the file pointed to by fp into the stl structure,
stl_initialize(stl_file *stl) { starting at facet first_facet. The second argument says if it's our first
memset(stl, 0, sizeof(stl_file)); time running this for the stl and therefore we should reset our max and min stats. */
stl->stats.volume = -1.0; static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
{
if (stl->stats.type == binary)
fseek(fp, HEADER_SIZE, SEEK_SET);
else
rewind(fp);
char normal_buf[3][32];
for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) {
stl_facet facet;
if (stl->stats.type == binary) {
// Read a single facet from a binary .STL file. We assume little-endian architecture!
if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
return false;
#ifndef BOOST_LITTLE_ENDIAN
// Convert the loaded little endian data to big endian.
stl_internal_reverse_quads((char*)&facet, 48);
#endif /* BOOST_LITTLE_ENDIAN */
} else {
// Read a single facet from an ASCII .STL file
// skip solid/endsolid
// (in this order, otherwise it won't work when they are paired in the middle of a file)
fscanf(fp, "endsolid%*[^\n]\n");
fscanf(fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
// Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
assert(res_normal == 3);
int res_outer_loop = fscanf(fp, " outer loop");
assert(res_outer_loop == 0);
int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
assert(res_vertex1 == 3);
int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
assert(res_vertex2 == 3);
int res_vertex3 = fscanf(fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
assert(res_vertex3 == 3);
int res_endloop = fscanf(fp, " endloop");
assert(res_endloop == 0);
// There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
int res_endfacet = fscanf(fp, " endfacet ");
if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! ";
return false;
}
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
// Normal was mangled. Maybe denormals or "not a number" were stored?
// Just reset the normal and silently ignore it.
memset(&facet.normal, 0, sizeof(facet.normal));
}
}
#if 0
// Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
// close to zero values may be represented with singificantly higher precision than the rest of the vertices.
// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
// during the STL import.
for (size_t j = 0; j < 3; ++ j) {
if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
}
#endif
// Write the facet into memory.
stl->facet_start[i] = facet;
stl_facet_stats(stl, facet, first);
}
stl->stats.size = stl->stats.max - stl->stats.min;
stl->stats.bounding_diameter = stl->stats.size.norm();
return true;
}
bool stl_open(stl_file *stl, const char *file)
{
stl->clear();
FILE *fp = stl_open_count_facets(stl, file);
if (fp == nullptr)
return false;
stl_allocate(stl);
bool result = stl_read(stl, fp, 0, true);
fclose(fp);
return result;
} }
#ifndef BOOST_LITTLE_ENDIAN #ifndef BOOST_LITTLE_ENDIAN
extern void stl_internal_reverse_quads(char *buf, size_t cnt); extern void stl_internal_reverse_quads(char *buf, size_t cnt);
#endif /* BOOST_LITTLE_ENDIAN */ #endif /* BOOST_LITTLE_ENDIAN */
void void stl_allocate(stl_file *stl)
stl_count_facets(stl_file *stl, const char *file) { {
long file_size; // Allocate memory for the entire .STL file.
uint32_t header_num_facets; stl->facet_start.assign(stl->stats.number_of_facets, stl_facet());
uint32_t num_facets; // Allocate memory for the neighbors list.
int i; stl->neighbors_start.assign(stl->stats.number_of_facets, stl_neighbors());
size_t s;
unsigned char chtest[128];
int num_lines = 1;
char *error_msg;
if (stl->error) return;
/* Open the file in binary mode first */
stl->fp = boost::nowide::fopen(file, "rb");
if(stl->fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
/* Find size of file */
fseek(stl->fp, 0, SEEK_END);
file_size = ftell(stl->fp);
/* Check for binary or ASCII file */
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
if (!fread(chtest, sizeof(chtest), 1, stl->fp)) {
perror("The input is an empty file");
stl->error = 1;
return;
}
stl->stats.type = ascii;
for(s = 0; s < sizeof(chtest); s++) {
if(chtest[s] > 127) {
stl->stats.type = binary;
break;
}
}
rewind(stl->fp);
/* Get the header and the number of facets in the .STL file */
/* If the .STL file is binary, then do the following */
if(stl->stats.type == binary) {
/* Test if the STL file has the right size */
if(((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0)
|| (file_size < STL_MIN_FILE_SIZE)) {
fprintf(stderr, "The file %s has the wrong size.\n", file);
stl->error = 1;
return;
}
num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
/* Read the header */
if (fread(stl->stats.header, LABEL_SIZE, 1, stl->fp) > 79) {
stl->stats.header[80] = '\0';
}
/* Read the int following the header. This should contain # of facets */
bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp) != 0;
#ifndef BOOST_LITTLE_ENDIAN
// Convert from little endian to big endian.
stl_internal_reverse_quads((char*)&header_num_facets, 4);
#endif /* BOOST_LITTLE_ENDIAN */
if (! header_num_faces_read || num_facets != header_num_facets) {
fprintf(stderr,
"Warning: File size doesn't match number of facets in the header\n");
}
}
/* Otherwise, if the .STL file is ASCII, then do the following */
else {
/* Reopen the file in text mode (for getting correct newlines on Windows) */
// fix to silence a warning about unused return value.
// obviously if it fails we have problems....
stl->fp = boost::nowide::freopen(file, "r", stl->fp);
// do another null check to be safe
if(stl->fp == NULL) {
error_msg = (char*)
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
file);
perror(error_msg);
free(error_msg);
stl->error = 1;
return;
}
/* Find the number of facets */
char linebuf[100];
while (fgets(linebuf, 100, stl->fp) != NULL) {
/* don't count short lines */
if (strlen(linebuf) <= 4) continue;
/* skip solid/endsolid lines as broken STL file generators may put several of them */
if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0) continue;
++num_lines;
}
rewind(stl->fp);
/* Get the header */
for(i = 0;
(i < 80) && (stl->stats.header[i] = getc(stl->fp)) != '\n'; i++);
stl->stats.header[i] = '\0'; /* Lose the '\n' */
stl->stats.header[80] = '\0';
num_facets = num_lines / ASCII_LINES_PER_FACET;
}
stl->stats.number_of_facets += num_facets;
stl->stats.original_num_facets = stl->stats.number_of_facets;
} }
void void stl_reallocate(stl_file *stl)
stl_allocate(stl_file *stl) { {
if (stl->error) return; stl->facet_start.resize(stl->stats.number_of_facets);
stl->neighbors_start.resize(stl->stats.number_of_facets);
/* Allocate memory for the entire .STL file */
stl->facet_start = (stl_facet*)calloc(stl->stats.number_of_facets,
sizeof(stl_facet));
if(stl->facet_start == NULL) perror("stl_initialize");
stl->stats.facets_malloced = stl->stats.number_of_facets;
/* Allocate memory for the neighbors list */
stl->neighbors_start = (stl_neighbors*)
calloc(stl->stats.number_of_facets, sizeof(stl_neighbors));
if(stl->facet_start == NULL) perror("stl_initialize");
}
void
stl_open_merge(stl_file *stl, char *file_to_merge) {
int num_facets_so_far;
stl_type origStlType;
FILE *origFp;
stl_file stl_to_merge;
if (stl->error) return;
/* Record how many facets we have so far from the first file. We will start putting
facets in the next position. Since we're 0-indexed, it'l be the same position. */
num_facets_so_far = stl->stats.number_of_facets;
/* Record the file type we started with: */
origStlType=stl->stats.type;
/* Record the file pointer too: */
origFp=stl->fp;
/* Initialize the sturucture with zero stats, header info and sizes: */
stl_initialize(&stl_to_merge);
stl_count_facets(&stl_to_merge, file_to_merge);
/* Copy what we need to into stl so that we can read the file_to_merge directly into it
using stl_read: Save the rest of the valuable info: */
stl->stats.type=stl_to_merge.stats.type;
stl->fp=stl_to_merge.fp;
/* Add the number of facets we already have in stl with what we we found in stl_to_merge but
haven't read yet. */
stl->stats.number_of_facets=num_facets_so_far+stl_to_merge.stats.number_of_facets;
/* Allocate enough room for stl->stats.number_of_facets facets and neighbors: */
stl_reallocate(stl);
/* Read the file to merge directly into stl, adding it to what we have already.
Start at num_facets_so_far, the index to the first unused facet. Also say
that this isn't our first time so we should augment stats like min and max
instead of erasing them. */
stl_read(stl, num_facets_so_far, false);
/* Restore the stl information we overwrote (for stl_read) so that it still accurately
reflects the subject part: */
stl->stats.type=origStlType;
stl->fp=origFp;
}
extern void
stl_reallocate(stl_file *stl) {
if (stl->error) return;
/* Reallocate more memory for the .STL file(s) */
stl->facet_start = (stl_facet*)realloc(stl->facet_start, stl->stats.number_of_facets *
sizeof(stl_facet));
if(stl->facet_start == NULL) perror("stl_initialize");
stl->stats.facets_malloced = stl->stats.number_of_facets;
/* Reallocate more memory for the neighbors list */
stl->neighbors_start = (stl_neighbors*)
realloc(stl->neighbors_start, stl->stats.number_of_facets *
sizeof(stl_neighbors));
if(stl->facet_start == NULL) perror("stl_initialize");
}
/* Reads the contents of the file pointed to by stl->fp into the stl structure,
starting at facet first_facet. The second argument says if it's our first
time running this for the stl and therefore we should reset our max and min stats. */
void stl_read(stl_file *stl, int first_facet, bool first) {
stl_facet facet;
if (stl->error) return;
if(stl->stats.type == binary) {
fseek(stl->fp, HEADER_SIZE, SEEK_SET);
} else {
rewind(stl->fp);
}
char normal_buf[3][32];
for(uint32_t i = first_facet; i < stl->stats.number_of_facets; i++) {
if(stl->stats.type == binary)
/* Read a single facet from a binary .STL file */
{
/* we assume little-endian architecture! */
if (fread(&facet, 1, SIZEOF_STL_FACET, stl->fp) != SIZEOF_STL_FACET) {
stl->error = 1;
return;
}
#ifndef BOOST_LITTLE_ENDIAN
// Convert the loaded little endian data to big endian.
stl_internal_reverse_quads((char*)&facet, 48);
#endif /* BOOST_LITTLE_ENDIAN */
} else
/* Read a single facet from an ASCII .STL file */
{
// skip solid/endsolid
// (in this order, otherwise it won't work when they are paired in the middle of a file)
fscanf(stl->fp, "endsolid%*[^\n]\n");
fscanf(stl->fp, "solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
// Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
int res_normal = fscanf(stl->fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
assert(res_normal == 3);
int res_outer_loop = fscanf(stl->fp, " outer loop");
assert(res_outer_loop == 0);
int res_vertex1 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
assert(res_vertex1 == 3);
int res_vertex2 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
assert(res_vertex2 == 3);
int res_vertex3 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
assert(res_vertex3 == 3);
int res_endloop = fscanf(stl->fp, " endloop");
assert(res_endloop == 0);
// There is a leading and trailing white space around endfacet to eat up all leading and trailing white spaces including numerous tabs and new lines.
int res_endfacet = fscanf(stl->fp, " endfacet ");
if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || res_endloop != 0 || res_endfacet != 0) {
perror("Something is syntactically very wrong with this ASCII STL!");
stl->error = 1;
return;
}
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
// Normal was mangled. Maybe denormals or "not a number" were stored?
// Just reset the normal and silently ignore it.
memset(&facet.normal, 0, sizeof(facet.normal));
}
}
#if 0
// Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
// close to zero values may be represented with singificantly higher precision than the rest of the vertices.
// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
// during the STL import.
for (size_t j = 0; j < 3; ++ j) {
if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
}
#endif
/* Write the facet into memory. */
stl->facet_start[i] = facet;
stl_facet_stats(stl, facet, first);
}
stl->stats.size = stl->stats.max - stl->stats.min;
stl->stats.bounding_diameter = stl->stats.size.norm();
} }
void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first) void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
{ {
if (stl->error) // While we are going through all of the facets, let's find the
return; // maximum and minimum values for x, y, and z
// While we are going through all of the facets, let's find the if (first) {
// maximum and minimum values for x, y, and z // Initialize the max and min values the first time through
stl->stats.min = facet.vertex[0];
stl->stats.max = facet.vertex[0];
stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
first = false;
}
if (first) { // Now find the max and min values.
// Initialize the max and min values the first time through for (size_t i = 0; i < 3; ++ i) {
stl->stats.min = facet.vertex[0]; stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
stl->stats.max = facet.vertex[0]; stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs(); }
stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
first = false;
}
// Now find the max and min values.
for (size_t i = 0; i < 3; ++ i) {
stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
}
}
void stl_close(stl_file *stl)
{
assert(stl->fp == nullptr);
assert(stl->heads == nullptr);
assert(stl->tail == nullptr);
if (stl->facet_start != NULL)
free(stl->facet_start);
if (stl->neighbors_start != NULL)
free(stl->neighbors_start);
if (stl->v_indices != NULL)
free(stl->v_indices);
if (stl->v_shared != NULL)
free(stl->v_shared);
memset(stl, 0, sizeof(stl_file));
} }

View file

@ -25,435 +25,375 @@
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <boost/log/trivial.hpp>
#include "stl.h" #include "stl.h"
static void stl_rotate(float *x, float *y, const double c, const double s); void stl_verify_neighbors(stl_file *stl)
static float get_area(stl_facet *facet); {
static float get_volume(stl_file *stl); stl->stats.backwards_edges = 0;
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
void for (int j = 0; j < 3; ++ j) {
stl_verify_neighbors(stl_file *stl) { struct stl_edge {
int i; stl_vertex p1;
int j; stl_vertex p2;
stl_edge edge_a; int facet_number;
stl_edge edge_b; };
int neighbor; stl_edge edge_a;
int vnot; edge_a.p1 = stl->facet_start[i].vertex[j];
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
if (stl->error) return; int neighbor = stl->neighbors_start[i].neighbor[j];
if (neighbor == -1)
stl->stats.backwards_edges = 0; continue; // this edge has no neighbor... Continue.
int vnot = stl->neighbors_start[i].which_vertex_not[j];
for(i = 0; i < stl->stats.number_of_facets; i++) { stl_edge edge_b;
for(j = 0; j < 3; j++) { if (vnot < 3) {
edge_a.p1 = stl->facet_start[i].vertex[j]; edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3]; edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
neighbor = stl->neighbors_start[i].neighbor[j]; } else {
vnot = stl->neighbors_start[i].which_vertex_not[j]; stl->stats.backwards_edges += 1;
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
if(neighbor == -1) edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
continue; /* this edge has no neighbor... Continue. */ }
if(vnot < 3) { if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; // These edges should match but they don't. Print results.
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor;
} else { stl_write_facet(stl, (char*)"first facet", i);
stl->stats.backwards_edges += 1; stl_write_facet(stl, (char*)"second facet", neighbor);
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3]; }
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3]; }
} }
if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
/* These edges should match but they don't. Print results. */
printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
j, i, vnot + 1, neighbor);
stl_write_facet(stl, (char*)"first facet", i);
stl_write_facet(stl, (char*)"second facet", neighbor);
}
}
}
} }
void stl_translate(stl_file *stl, float x, float y, float z) void stl_translate(stl_file *stl, float x, float y, float z)
{ {
if (stl->error) stl_vertex new_min(x, y, z);
return; stl_vertex shift = new_min - stl->stats.min;
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
stl_vertex new_min(x, y, z); for (int j = 0; j < 3; ++ j)
stl_vertex shift = new_min - stl->stats.min; stl->facet_start[i].vertex[j] += shift;
for (int i = 0; i < stl->stats.number_of_facets; ++ i) stl->stats.min = new_min;
for (int j = 0; j < 3; ++ j) stl->stats.max += shift;
stl->facet_start[i].vertex[j] += shift;
stl->stats.min = new_min;
stl->stats.max += shift;
stl_invalidate_shared_vertices(stl);
} }
/* Translates the stl by x,y,z, relatively from wherever it is currently */ /* Translates the stl by x,y,z, relatively from wherever it is currently */
void stl_translate_relative(stl_file *stl, float x, float y, float z) void stl_translate_relative(stl_file *stl, float x, float y, float z)
{ {
if (stl->error) stl_vertex shift(x, y, z);
return; for (int i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; ++ j)
stl_vertex shift(x, y, z); stl->facet_start[i].vertex[j] += shift;
for (int i = 0; i < stl->stats.number_of_facets; ++ i) stl->stats.min += shift;
for (int j = 0; j < 3; ++ j) stl->stats.max += shift;
stl->facet_start[i].vertex[j] += shift;
stl->stats.min += shift;
stl->stats.max += shift;
stl_invalidate_shared_vertices(stl);
} }
void stl_scale_versor(stl_file *stl, const stl_vertex &versor) void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
{ {
if (stl->error) // Scale extents.
return; auto s = versor.array();
stl->stats.min.array() *= s;
// Scale extents. stl->stats.max.array() *= s;
auto s = versor.array(); // Scale size.
stl->stats.min.array() *= s; stl->stats.size.array() *= s;
stl->stats.max.array() *= s; // Scale volume.
// Scale size. if (stl->stats.volume > 0.0)
stl->stats.size.array() *= s; stl->stats.volume *= versor(0) * versor(1) * versor(2);
// Scale volume. // Scale the mesh.
if (stl->stats.volume > 0.0) for (int i = 0; i < stl->stats.number_of_facets; ++ i)
stl->stats.volume *= versor(0) * versor(1) * versor(2); for (int j = 0; j < 3; ++ j)
// Scale the mesh. stl->facet_start[i].vertex[j].array() *= s;
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; ++ j)
stl->facet_start[i].vertex[j].array() *= s;
stl_invalidate_shared_vertices(stl);
} }
static void calculate_normals(stl_file *stl) static void calculate_normals(stl_file *stl)
{ {
if (stl->error) stl_normal normal;
return; for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
stl_calculate_normal(normal, &stl->facet_start[i]);
stl_normal normal; stl_normalize_vector(normal);
for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) { stl->facet_start[i].normal = normal;
stl_calculate_normal(normal, &stl->facet_start[i]); }
stl_normalize_vector(normal);
stl->facet_start[i].normal = normal;
}
} }
void static inline void rotate_point_2d(float &x, float &y, const double c, const double s)
stl_rotate_x(stl_file *stl, float angle) { {
int i; double xold = x;
int j; double yold = y;
double radian_angle = (angle / 180.0) * M_PI; x = float(c * xold - s * yold);
double c = cos(radian_angle); y = float(s * xold + c * yold);
double s = sin(radian_angle);
if (stl->error) return;
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl_rotate(&stl->facet_start[i].vertex[j](1),
&stl->facet_start[i].vertex[j](2), c, s);
}
}
stl_get_size(stl);
calculate_normals(stl);
} }
void void stl_rotate_x(stl_file *stl, float angle)
stl_rotate_y(stl_file *stl, float angle) { {
int i; double radian_angle = (angle / 180.0) * M_PI;
int j; double c = cos(radian_angle);
double radian_angle = (angle / 180.0) * M_PI; double s = sin(radian_angle);
double c = cos(radian_angle); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
double s = sin(radian_angle); for (int j = 0; j < 3; ++ j)
rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s);
if (stl->error) return; stl_get_size(stl);
calculate_normals(stl);
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl_rotate(&stl->facet_start[i].vertex[j](2),
&stl->facet_start[i].vertex[j](0), c, s);
}
}
stl_get_size(stl);
calculate_normals(stl);
} }
void void stl_rotate_y(stl_file *stl, float angle)
stl_rotate_z(stl_file *stl, float angle) { {
int i; double radian_angle = (angle / 180.0) * M_PI;
int j; double c = cos(radian_angle);
double radian_angle = (angle / 180.0) * M_PI; double s = sin(radian_angle);
double c = cos(radian_angle); for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
double s = sin(radian_angle); for (int j = 0; j < 3; ++ j)
rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s);
if (stl->error) return; stl_get_size(stl);
calculate_normals(stl);
for(i = 0; i < stl->stats.number_of_facets; i++) {
for(j = 0; j < 3; j++) {
stl_rotate(&stl->facet_start[i].vertex[j](0),
&stl->facet_start[i].vertex[j](1), c, s);
}
}
stl_get_size(stl);
calculate_normals(stl);
} }
void stl_rotate_z(stl_file *stl, float angle)
{
double radian_angle = (angle / 180.0) * M_PI;
double c = cos(radian_angle);
double s = sin(radian_angle);
for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; ++ j)
rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s);
stl_get_size(stl);
calculate_normals(stl);
}
void its_rotate_x(indexed_triangle_set &its, float angle)
{
double radian_angle = (angle / 180.0) * M_PI;
double c = cos(radian_angle);
double s = sin(radian_angle);
for (stl_vertex &v : its.vertices)
rotate_point_2d(v(1), v(2), c, s);
}
static void void its_rotate_y(indexed_triangle_set& its, float angle)
stl_rotate(float *x, float *y, const double c, const double s) { {
double xold = *x; double radian_angle = (angle / 180.0) * M_PI;
double yold = *y; double c = cos(radian_angle);
*x = float(c * xold - s * yold); double s = sin(radian_angle);
*y = float(s * xold + c * yold); for (stl_vertex& v : its.vertices)
rotate_point_2d(v(2), v(0), c, s);
}
void its_rotate_z(indexed_triangle_set& its, float angle)
{
double radian_angle = (angle / 180.0) * M_PI;
double c = cos(radian_angle);
double s = sin(radian_angle);
for (stl_vertex& v : its.vertices)
rotate_point_2d(v(0), v(1), c, s);
} }
void stl_get_size(stl_file *stl) void stl_get_size(stl_file *stl)
{ {
if (stl->error || stl->stats.number_of_facets == 0) if (stl->stats.number_of_facets == 0)
return; return;
stl->stats.min = stl->facet_start[0].vertex[0]; stl->stats.min = stl->facet_start[0].vertex[0];
stl->stats.max = stl->stats.min; stl->stats.max = stl->stats.min;
for (int i = 0; i < stl->stats.number_of_facets; ++ i) { for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
const stl_facet &face = stl->facet_start[i]; const stl_facet &face = stl->facet_start[i];
for (int j = 0; j < 3; ++ j) { for (int j = 0; j < 3; ++ j) {
stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]); stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]); stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
} }
} }
stl->stats.size = stl->stats.max - stl->stats.min; stl->stats.size = stl->stats.max - stl->stats.min;
stl->stats.bounding_diameter = stl->stats.size.norm(); stl->stats.bounding_diameter = stl->stats.size.norm();
} }
void stl_mirror_xy(stl_file *stl) void stl_mirror_xy(stl_file *stl)
{ {
if (stl->error) for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
return; for (int j = 0; j < 3; ++ j)
stl->facet_start[i].vertex[j](2) *= -1.0;
for(int i = 0; i < stl->stats.number_of_facets; i++) { float temp_size = stl->stats.min(2);
for(int j = 0; j < 3; j++) { stl->stats.min(2) = stl->stats.max(2);
stl->facet_start[i].vertex[j](2) *= -1.0; stl->stats.max(2) = temp_size;
} stl->stats.min(2) *= -1.0;
} stl->stats.max(2) *= -1.0;
float temp_size = stl->stats.min(2); stl_reverse_all_facets(stl);
stl->stats.min(2) = stl->stats.max(2); stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
stl->stats.max(2) = temp_size;
stl->stats.min(2) *= -1.0;
stl->stats.max(2) *= -1.0;
stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
} }
void stl_mirror_yz(stl_file *stl) void stl_mirror_yz(stl_file *stl)
{ {
if (stl->error) return; for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
for (int j = 0; j < 3; j++)
for (int i = 0; i < stl->stats.number_of_facets; i++) { stl->facet_start[i].vertex[j](0) *= -1.0;
for (int j = 0; j < 3; j++) { float temp_size = stl->stats.min(0);
stl->facet_start[i].vertex[j](0) *= -1.0; stl->stats.min(0) = stl->stats.max(0);
} stl->stats.max(0) = temp_size;
} stl->stats.min(0) *= -1.0;
float temp_size = stl->stats.min(0); stl->stats.max(0) *= -1.0;
stl->stats.min(0) = stl->stats.max(0); stl_reverse_all_facets(stl);
stl->stats.max(0) = temp_size; stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
stl->stats.min(0) *= -1.0;
stl->stats.max(0) *= -1.0;
stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
} }
void stl_mirror_xz(stl_file *stl) void stl_mirror_xz(stl_file *stl)
{ {
if (stl->error) for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
return; for (int j = 0; j < 3; ++ j)
stl->facet_start[i].vertex[j](1) *= -1.0;
for (int i = 0; i < stl->stats.number_of_facets; i++) { float temp_size = stl->stats.min(1);
for (int j = 0; j < 3; j++) { stl->stats.min(1) = stl->stats.max(1);
stl->facet_start[i].vertex[j](1) *= -1.0; stl->stats.max(1) = temp_size;
} stl->stats.min(1) *= -1.0;
} stl->stats.max(1) *= -1.0;
float temp_size = stl->stats.min(1); stl_reverse_all_facets(stl);
stl->stats.min(1) = stl->stats.max(1); stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats
stl->stats.max(1) = temp_size;
stl->stats.min(1) *= -1.0;
stl->stats.max(1) *= -1.0;
stl_reverse_all_facets(stl);
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
}
static float get_volume(stl_file *stl)
{
if (stl->error)
return 0;
// Choose a point, any point as the reference.
stl_vertex p0 = stl->facet_start[0].vertex[0];
float volume = 0.f;
for(uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
// Do dot product to get distance from point to plane.
float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
float area = get_area(&stl->facet_start[i]);
volume += (area * height) / 3.0f;
}
return volume;
}
void stl_calculate_volume(stl_file *stl)
{
if (stl->error) return;
stl->stats.volume = get_volume(stl);
if(stl->stats.volume < 0.0) {
stl_reverse_all_facets(stl);
stl->stats.volume = -stl->stats.volume;
}
} }
static float get_area(stl_facet *facet) static float get_area(stl_facet *facet)
{ {
/* cast to double before calculating cross product because large coordinates /* cast to double before calculating cross product because large coordinates
can result in overflowing product can result in overflowing product
(bad area is responsible for bad volume and bad facets reversal) */ (bad area is responsible for bad volume and bad facets reversal) */
double cross[3][3]; double cross[3][3];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) - cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1))); ((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) - cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2))); ((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) - cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0))); ((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
} }
stl_normal sum; stl_normal sum;
sum(0) = cross[0][0] + cross[1][0] + cross[2][0]; sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
sum(1) = cross[0][1] + cross[1][1] + cross[2][1]; sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
sum(2) = cross[0][2] + cross[1][2] + cross[2][2]; sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
// This should already be done. But just in case, let's do it again. // This should already be done. But just in case, let's do it again.
//FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy. //FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
stl_normal n; stl_normal n;
stl_calculate_normal(n, facet); stl_calculate_normal(n, facet);
stl_normalize_vector(n); stl_normalize_vector(n);
return 0.5f * n.dot(sum); return 0.5f * n.dot(sum);
} }
void stl_repair(stl_file *stl, static float get_volume(stl_file *stl)
int fixall_flag, {
int exact_flag, // Choose a point, any point as the reference.
int tolerance_flag, stl_vertex p0 = stl->facet_start[0].vertex[0];
float tolerance, float volume = 0.f;
int increment_flag, for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
float increment, // Do dot product to get distance from point to plane.
int nearby_flag, float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
int iterations, float area = get_area(&stl->facet_start[i]);
int remove_unconnected_flag, volume += (area * height) / 3.0f;
int fill_holes_flag, }
int normal_directions_flag, return volume;
int normal_values_flag, }
int reverse_all_flag,
int verbose_flag) { void stl_calculate_volume(stl_file *stl)
{
int i; stl->stats.volume = get_volume(stl);
int last_edges_fixed = 0; if (stl->stats.volume < 0.0) {
stl_reverse_all_facets(stl);
if (stl->error) return; stl->stats.volume = -stl->stats.volume;
}
if(exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag }
|| fill_holes_flag || normal_directions_flag) {
if (verbose_flag) void stl_repair(
printf("Checking exact...\n"); stl_file *stl,
exact_flag = 1; bool fixall_flag,
stl_check_facets_exact(stl); bool exact_flag,
stl->stats.facets_w_1_bad_edge = bool tolerance_flag,
(stl->stats.connected_facets_2_edge - float tolerance,
stl->stats.connected_facets_3_edge); bool increment_flag,
stl->stats.facets_w_2_bad_edge = float increment,
(stl->stats.connected_facets_1_edge - bool nearby_flag,
stl->stats.connected_facets_2_edge); int iterations,
stl->stats.facets_w_3_bad_edge = bool remove_unconnected_flag,
(stl->stats.number_of_facets - bool fill_holes_flag,
stl->stats.connected_facets_1_edge); bool normal_directions_flag,
} bool normal_values_flag,
bool reverse_all_flag,
if(nearby_flag || fixall_flag) { bool verbose_flag)
if(!tolerance_flag) { {
tolerance = stl->stats.shortest_edge; if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) {
} if (verbose_flag)
if(!increment_flag) { printf("Checking exact...\n");
increment = stl->stats.bounding_diameter / 10000.0; exact_flag = true;
} stl_check_facets_exact(stl);
stl->stats.facets_w_1_bad_edge = (stl->stats.connected_facets_2_edge - stl->stats.connected_facets_3_edge);
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { stl->stats.facets_w_2_bad_edge = (stl->stats.connected_facets_1_edge - stl->stats.connected_facets_2_edge);
for(i = 0; i < iterations; i++) { stl->stats.facets_w_3_bad_edge = (stl->stats.number_of_facets - stl->stats.connected_facets_1_edge);
if(stl->stats.connected_facets_3_edge < }
stl->stats.number_of_facets) {
if (verbose_flag) if (nearby_flag || fixall_flag) {
printf("\ if (! tolerance_flag)
Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance = stl->stats.shortest_edge;
tolerance, i + 1, iterations); if (! increment_flag)
stl_check_facets_nearby(stl, tolerance); increment = stl->stats.bounding_diameter / 10000.0;
if (verbose_flag) }
printf(" Fixed %d edges.\n",
stl->stats.edges_fixed - last_edges_fixed); if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
last_edges_fixed = stl->stats.edges_fixed; int last_edges_fixed = 0;
tolerance += increment; for (int i = 0; i < iterations; ++ i) {
} else { if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
if (verbose_flag) if (verbose_flag)
printf("\ printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
All facets connected. No further nearby check necessary.\n"); stl_check_facets_nearby(stl, tolerance);
break; if (verbose_flag)
} printf(" Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed);
} last_edges_fixed = stl->stats.edges_fixed;
} else { tolerance += increment;
if (verbose_flag) } else {
printf("All facets connected. No nearby check necessary.\n"); if (verbose_flag)
} printf("All facets connected. No further nearby check necessary.\n");
} break;
}
if(remove_unconnected_flag || fixall_flag || fill_holes_flag) { }
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { } else if (verbose_flag)
if (verbose_flag) printf("All facets connected. No nearby check necessary.\n");
printf("Removing unconnected facets...\n");
stl_remove_unconnected_facets(stl); if (remove_unconnected_flag || fixall_flag || fill_holes_flag) {
} else if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
if (verbose_flag) if (verbose_flag)
printf("No unconnected need to be removed.\n"); printf("Removing unconnected facets...\n");
} stl_remove_unconnected_facets(stl);
} else if (verbose_flag)
if(fill_holes_flag || fixall_flag) { printf("No unconnected need to be removed.\n");
if(stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) { }
if (verbose_flag)
printf("Filling holes...\n"); if (fill_holes_flag || fixall_flag) {
stl_fill_holes(stl); if (stl->stats.connected_facets_3_edge < stl->stats.number_of_facets) {
} else if (verbose_flag)
if (verbose_flag) printf("Filling holes...\n");
printf("No holes need to be filled.\n"); stl_fill_holes(stl);
} } else if (verbose_flag)
printf("No holes need to be filled.\n");
if(reverse_all_flag) { }
if (verbose_flag)
printf("Reversing all facets...\n"); if (reverse_all_flag) {
stl_reverse_all_facets(stl); if (verbose_flag)
} printf("Reversing all facets...\n");
stl_reverse_all_facets(stl);
if(normal_directions_flag || fixall_flag) { }
if (verbose_flag)
printf("Checking normal directions...\n"); if (normal_directions_flag || fixall_flag) {
stl_fix_normal_directions(stl); if (verbose_flag)
} printf("Checking normal directions...\n");
stl_fix_normal_directions(stl);
if(normal_values_flag || fixall_flag) { }
if (verbose_flag)
printf("Checking normal values...\n"); if (normal_values_flag || fixall_flag) {
stl_fix_normal_values(stl); if (verbose_flag)
} printf("Checking normal values...\n");
stl_fix_normal_values(stl);
/* Always calculate the volume. It shouldn't take too long */ }
if (verbose_flag)
printf("Calculating volume...\n"); // Always calculate the volume. It shouldn't take too long.
stl_calculate_volume(stl); if (verbose_flag)
printf("Calculating volume...\n");
if(exact_flag) { stl_calculate_volume(stl);
if (verbose_flag)
printf("Verifying neighbors...\n"); if (exact_flag) {
stl_verify_neighbors(stl); if (verbose_flag)
} printf("Verifying neighbors...\n");
stl_verify_neighbors(stl);
}
} }

View file

@ -19,6 +19,6 @@ add_library(nowide STATIC
nowide/windows.hpp nowide/windows.hpp
) )
target_include_directories(nowide SYSTEM PUBLIC ${Boost_INCLUDE_DIRS}) target_link_libraries(nowide PUBLIC boost_headeronly)

14
src/libigl/CMakeLists.txt Normal file
View file

@ -0,0 +1,14 @@
project(libigl)
cmake_minimum_required(VERSION 3.0)
add_library(libigl INTERFACE)
find_package(libigl QUIET)
if(libigl_FOUND)
message(STATUS "IGL found, using system version...")
target_link_libraries(libigl INTERFACE igl::core)
else()
message(STATUS "IGL NOT found, using bundled version...")
target_include_directories(libigl INTERFACE SYSTEM ${LIBDIR}/libigl)
endif()

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