From a8705e3c76c058c008040097f80cf982a581f7da Mon Sep 17 00:00:00 2001 From: yony Date: Fri, 31 May 2024 15:54:14 +0800 Subject: [PATCH] =?UTF-8?q?intersection=20cpp=20h=20=E5=88=86=E7=A6=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 5 +- include/Geometry.h | 24 ++-- include/Intersection.h | 243 +++++------------------------------------ include/Point.h | 22 ++-- lib/CMakeLists.txt | 2 +- src/Intersection.cpp | 181 ++++++++++++++++++++++++++++++ src/xmlsql.cpp | 3 - stdafx.cpp | 8 -- stdafx.h | 26 ----- 9 files changed, 226 insertions(+), 288 deletions(-) create mode 100644 src/Intersection.cpp delete mode 100644 stdafx.cpp delete mode 100644 stdafx.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 531e874..506f4dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ project( #------------REQUIRED_4 指定C++标准------------# # !!!不要在库中使用此方式!!!,使用set_target_properties/set_property来针对目标设置标准 # 设置缓存变量: 设置了 C++ 标准的级别为 11(STRING) ,保存在CMakeCache.txt文件中,此处“”内容会写入为注释 -set(CMAKE_CXX_STANDARD 11 CACHE STRING "The C++ standard to use") +set(CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard to use") # 告诉 CMake 使用上述设置 set(CMAKE_CXX_STANDARD_REQUIRED ON) # 关闭了拓展,来明确自己使用了 -std=c++11 还是 -std=g++11 @@ -75,6 +75,9 @@ add_executable( ${SRC_DIR} ) +# warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc +set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/EHsc") + # add_custom_command( # TARGET ${PROJECT_NAME} POST_BUILD # COMMAND ${CMAKE_COMMAND} -E copy_directory diff --git a/include/Geometry.h b/include/Geometry.h index 072ce06..f13dc02 100644 --- a/include/Geometry.h +++ b/include/Geometry.h @@ -1,18 +1,10 @@ #pragma once -#ifdef MY_LIB_SHARED_BUILD - #ifdef _WIN32 - #ifdef MY_LIB_EXPORTS - #define LIB_API __declspec(dllexport) - #else - #define LIB_API __declspec(dllimport) - #endif // MY_LIB_EXPORTS - #else - #define LIB_API - #endif // _WIN32 +#ifdef _WIN32 + #define GEOMETRY_API __declspec(dllexport) #else - #define LIB_API -#endif // MY_LIB_SHARED_BUILD + #define GEOMETRY_API +#endif #include #include @@ -105,21 +97,21 @@ public: typedef Vec3 Vec3f; typedef Vec3 Vec3u; -extern "C" class LIB_API Mesh +extern "C" class GEOMETRY_API Mesh { public: std::vector vertices; std::vector indices; }; -extern "C" class LIB_API AABB +extern "C" class GEOMETRY_API AABB { public: Vec3f min, max; AABB(); }; -extern "C" class LIB_API LineSegment +extern "C" class GEOMETRY_API LineSegment { public: Vec3f start; @@ -136,7 +128,7 @@ public: void calculate(); }; -extern "C" struct LIB_API FaceCenterComparator +extern "C" struct GEOMETRY_API FaceCenterComparator { const std::vector &faceCenters; // 滻 YourVectorType Ϊ int longAxis; diff --git a/include/Intersection.h b/include/Intersection.h index a0a9393..ee08f70 100644 --- a/include/Intersection.h +++ b/include/Intersection.h @@ -1,40 +1,30 @@ #pragma once +#ifdef _WIN32 + #define INTERSECTION_API __declspec(dllexport) +#else + #define INTERSECTION_API +#endif + +#include "Geometry.h" #include #include #include #include -#include "Geometry.h" +#include // std::cerr +#include // std::length_error -struct TriangleSegmentIntersectRes +extern "C" struct INTERSECTION_API TriangleSegmentIntersectRes { bool hit; float t; - TriangleSegmentIntersectRes(bool h, float tt) : hit(h), t(tt) {} // VS2008 + TriangleSegmentIntersectRes(bool h, float tt); }; -TriangleSegmentIntersectRes -triangleSegmentIntersection(const LineSegment &segment, const Vec3f &a, const Vec3f &b, const Vec3f &c) -{ - Vec3f e1 = b - a; - Vec3f e2 = c - a; - Vec3f s = segment.start - a; - Vec3f s1 = segment.getDir().cross(e2); - Vec3f s2 = s.cross(e1); - float s1_dot_e1 = s1.dot(e1); - float b1 = s1.dot(s) / s1_dot_e1; - float b2 = s2.dot(segment.getDir()) / s1_dot_e1; - if (b1 >= 0. && b2 >= 0. && b1 + b2 <= 1.) - { - // hit - // return {true, s2.dot(e2) / s1_dot_e1}; - return TriangleSegmentIntersectRes(true, s2.dot(e2) / s1_dot_e1); // VS2008 - } - // return {false, 0.}; - return TriangleSegmentIntersectRes(false, 0.f); // VS2008 -} +INTERSECTION_API +TriangleSegmentIntersectRes triangleSegmentIntersection(const LineSegment &segment, const Vec3f &a, const Vec3f &b, const Vec3f &c); -class BVHNode +extern "C" class INTERSECTION_API BVHNode { public: size_t left; @@ -42,210 +32,27 @@ public: size_t parent; AABB boundingBox; - BVHNode(size_t l, size_t r, size_t p, const AABB &aabb) : left(l), right(r), parent(p), boundingBox(aabb) {} - BVHNode() : left(0), right(0), parent(0), boundingBox() {} + BVHNode(size_t l, size_t r, size_t p, const AABB &aabb); + BVHNode(); }; -class BVH_intersection +extern "C" class INTERSECTION_API BVH_intersection { public: const Mesh &mesh; std::vector faceCenters; std::vector nodes; - BVH_intersection(const Mesh &mesh_) : mesh(mesh_) - { - // ?????????????????? - faceCenters.reserve(mesh.indices.size()); - for (std::vector::const_iterator it = mesh.indices.begin(); it != mesh.indices.end(); ++it) - { - const Vec3u &face = *it; - Vec3f center = (mesh.vertices[face[0]] + mesh.vertices[face[1]] + mesh.vertices[face[2]]) / 3.0f; - faceCenters.push_back(center); - } // VS2008 - - // indicesList ????0,1,2...?C++11iota?? - // std::iota(indicesList.begin(), indicesList.end(), 0); - std::vector indicesList(mesh.indices.size()); - for (size_t i = 0; i < indicesList.size(); ++i) - { - indicesList[i] = i; - } - - // ??BVH???? - try - { - nodes.resize(2 * mesh.indices.size() - 1); - } - catch (const std::length_error &e) - { - std::cout << "vector.length:" << nodes.size() << " resize_pa:" << (2 * mesh.indices.size() - 1) << std::endl; - std::cerr << "Caught a length_error: " << e.what() << std::endl; - } + BVH_intersection(const Mesh &mesh_); + size_t + dfsBuild(std::vector &indicesList, AABB aabb, size_t &nowIdx); + bool intersectWithLineSegment(const LineSegment &lineSegment) const; - size_t nowIdx = 0; - dfsBuild(indicesList, computeAABB(indicesList), nowIdx); - } - - // BVH??? - size_t dfsBuild(std::vector &indicesList, AABB aabb, size_t &nowIdx) - { - const size_t nodeIdx = nowIdx; - nowIdx++; - if (indicesList.size() == 1) - { - // leaf - nodes[nodeIdx] = BVHNode(0, indicesList[0], 0, aabb); // VS2008 - return nodeIdx; - } - - // longest axis - int longAxis = -1; - float longAxisLen = -1; - for (int i = 0; i < 3; ++i) - { - const float axisLen = aabb.max[i] - aabb.min[i]; - if (axisLen > longAxisLen) - { - longAxisLen = axisLen; - longAxis = i; - } - } - - // split indices list - const size_t k = indicesList.size() / 2; - // std::nth_element(indicesList.begin(), indicesList.begin() + k - 1, indicesList.end(), - // [&](const size_t &a, const size_t &b) { - // return faceCenters[a][longAxis] < faceCenters[b][longAxis]; - // }); - nth(indicesList, k - 1, longAxis); - std::vector leftIndices(indicesList.begin(), indicesList.begin() + k); - std::vector rightIndices(indicesList.begin() + k, indicesList.end()); - - const AABB leftAABB = computeAABB(leftIndices); - const AABB rightAABB = computeAABB(rightIndices); - const size_t leftIdx = dfsBuild(leftIndices, leftAABB, nowIdx); - const size_t rightIdx = dfsBuild(rightIndices, rightAABB, nowIdx); - // nodes[nodeIdx] = {leftIdx, rightIdx, 0, aabb}; - nodes[nodeIdx] = BVHNode(leftIdx, rightIdx, 0, aabb); // VS2008 - nodes[leftIdx].parent = nodeIdx; - nodes[rightIdx].parent = nodeIdx; - return nodeIdx; - } - - bool intersectWithLineSegment(const LineSegment &lineSegment) const - { - return recursiveLineSegIntersection(lineSegment, 0); - } - - // private: - // AABB computeAABB(const std::vector &indices) { - // AABB aabb; - // for (const size_t &idx: indices) { - // const Vec3u &face = mesh.indices[idx]; - // for (int i = 0; i < 3; ++i) { - // const Vec3f &vertex = mesh.vertices[face[i]]; - // for (int j = 0; j < 3; ++j) { - // aabb.min[j] = std::min(aabb.min[j], vertex[j]); - // aabb.max[j] = std::max(aabb.max[j], vertex[j]); - // } - // } - // } - // return {aabb.min, aabb.max}; - // } private: - // ??????????????AABB??????????AABB - AABB computeAABB(const std::vector &indices) - { - AABB aabb; - for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) - { - const Vec3u &face = mesh.indices[*it]; - for (int i = 0; i < 3; ++i) - { - const Vec3f &vertex = mesh.vertices[face[i]]; - for (int j = 0; j < 3; ++j) - { - aabb.min[j] = min(aabb.min[j], vertex[j]); - aabb.max[j] = max(aabb.max[j], vertex[j]); - } - } - } - return aabb; - } - - bool recursiveLineSegIntersection(const LineSegment &lineSegment, size_t nodeIdx) const - { - // segment-box intersection test - const AABB &aabb = nodes[nodeIdx].boundingBox; - const Vec3f &dir = lineSegment.getDir(); - bool hit = false; - for (int i = 0; !hit && i < 3; ++i) - { - float t_min = (aabb.min[i] - lineSegment.start[i]) / dir[i]; - float t_max = (aabb.max[i] - lineSegment.start[i]) / dir[i]; - if (t_min > t_max) - { - std::swap(t_min, t_max); - } - if (t_min > lineSegment.getLength() || t_max < 0) - return false; - Vec3f hitPt = lineSegment.start + dir * t_min; - int otherPlane1 = (i + 1) % 3, otherPlane2 = (i + 2) % 3; - if (hitPt[otherPlane1] >= aabb.min[otherPlane1] && hitPt[otherPlane1] <= aabb.max[otherPlane1] && - hitPt[otherPlane2] >= aabb.min[otherPlane2] && hitPt[otherPlane2] <= aabb.max[otherPlane2]) - { - hit = true; - } - } - if (hit) - { - if (nodes[nodeIdx].left == 0) - { - // leaf - Vec3u face = mesh.indices[nodes[nodeIdx].right]; - TriangleSegmentIntersectRes res = triangleSegmentIntersection(lineSegment, mesh.vertices[face[0]], mesh.vertices[face[1]], - mesh.vertices[face[2]]); - if (!res.hit || res.t < 0 || res.t > lineSegment.getLength()) - return false; - return true; - } - else - { - // check children - return recursiveLineSegIntersection(lineSegment, nodes[nodeIdx].left) || - recursiveLineSegIntersection(lineSegment, nodes[nodeIdx].right); - } - } - return false; - } + AABB computeAABB(const std::vector &indices); + bool recursiveLineSegIntersection(const LineSegment &lineSegment, size_t nodeIdx) const; - // implement nth, without std::nth_element - // kth is 0-based - void nth(std::vector &indicesList, size_t kth, int longAxis) - { - recursiveChoose(indicesList, 0, indicesList.size() - 1, kth, longAxis); - } - void recursiveChoose(std::vector &indicesList, size_t begin, size_t end, size_t kth, int longAxis) - { - if (begin >= end) - return; - int i = begin, j = end; - while (i < j) - { - while (i < j && faceCenters[indicesList[j]][longAxis] >= faceCenters[indicesList[begin]][longAxis]) - j--; - while (i < j && faceCenters[indicesList[i]][longAxis] <= faceCenters[indicesList[begin]][longAxis]) - i++; - std::swap(indicesList[i], indicesList[j]); - } - std::swap(indicesList[begin], indicesList[i]); - if (i == kth) - return; - if (i < kth) - recursiveChoose(indicesList, i + 1, end, kth, longAxis); - else - recursiveChoose(indicesList, begin, i - 1, kth, longAxis); - } + void nth(std::vector &indicesList, size_t kth, int longAxis); + void recursiveChoose(std::vector &indicesList, size_t begin, size_t end, size_t kth, int longAxis); }; \ No newline at end of file diff --git a/include/Point.h b/include/Point.h index 2b81f57..47e824b 100644 --- a/include/Point.h +++ b/include/Point.h @@ -1,18 +1,10 @@ #pragma once -#ifdef MY_LIB_SHARED_BUILD - #ifdef _WIN32 - #ifdef MY_LIB_EXPORTS - #define LIB_API __declspec(dllexport) - #else - #define LIB_API __declspec(dllimport) - #endif // MY_LIB_EXPORTS - #else - #define LIB_API - #endif // _WIN32 +#ifdef _WIN32 + #define POINT_API __declspec(dllexport) #else - #define LIB_API -#endif // MY_LIB_SHARED_BUILD + #define POINT_API +#endif #include @@ -22,11 +14,11 @@ using namespace std; -extern "C" LIB_API const double eps = 1e-6; +extern "C" POINT_API const double eps = 1e-6; -extern "C" LIB_API bool Equal(double a, double b); +extern "C" POINT_API bool Equal(double a, double b); -extern "C" struct LIB_API P +extern "C" struct POINT_API P { double x, y, z; // double dx, dy, dz; // diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index d437133..f762653 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -10,7 +10,7 @@ INSTALL(TARGETS WireRouting DESTINATION ${CMAKE_SOURCE_DIR}/lib) SET_TARGET_PROPERTIES( WireRouting PROPERTIES LINKER_LANGUAGE C ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib - RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib OUTPUT_NAME "WireRouting" PREFIX "" diff --git a/src/Intersection.cpp b/src/Intersection.cpp new file mode 100644 index 0000000..cde7bf0 --- /dev/null +++ b/src/Intersection.cpp @@ -0,0 +1,181 @@ +#include "Intersection.h" + +using namespace std; + +TriangleSegmentIntersectRes::TriangleSegmentIntersectRes(bool h, float tt) : hit(h), t(tt) {} // VS2008 + +TriangleSegmentIntersectRes +triangleSegmentIntersection(const LineSegment &segment, const Vec3f &a, const Vec3f &b, const Vec3f &c) +{ + Vec3f e1 = b - a; + Vec3f e2 = c - a; + Vec3f s = segment.start - a; + Vec3f s1 = segment.getDir().cross(e2); + Vec3f s2 = s.cross(e1); + float s1_dot_e1 = s1.dot(e1); + float b1 = s1.dot(s) / s1_dot_e1; + float b2 = s2.dot(segment.getDir()) / s1_dot_e1; + if (b1 >= 0. && b2 >= 0. && b1 + b2 <= 1.) + { + return TriangleSegmentIntersectRes(true, s2.dot(e2) / s1_dot_e1); + } + return TriangleSegmentIntersectRes(false, 0.f); +} + +BVHNode::BVHNode(size_t l, size_t r, size_t p, const AABB &aabb) : left(l), right(r), parent(p), boundingBox(aabb) {} +BVHNode::BVHNode() : left(0), right(0), parent(0), boundingBox() {} + +BVH_intersection::BVH_intersection(const Mesh &mesh_) : mesh(mesh_) +{ + faceCenters.reserve(mesh.indices.size()); + for (vector::const_iterator it = mesh.indices.begin(); it != mesh.indices.end(); ++it) + { + const Vec3u &face = *it; + Vec3f center = (mesh.vertices[face[0]] + mesh.vertices[face[1]] + mesh.vertices[face[2]]) / 3.0f; + faceCenters.push_back(center); + } + vector indicesList(mesh.indices.size()); + for (size_t i = 0; i < indicesList.size(); ++i) + { + indicesList[i] = i; + } + try + { + nodes.resize(2 * mesh.indices.size() - 1); + } + catch (const length_error &e) + { + cout << "vector.length:" << nodes.size() << " resize_pa:" << (2 * mesh.indices.size() - 1) << endl; + cerr << "Caught a length_error: " << e.what() << endl; + } + size_t nowIdx = 0; + dfsBuild(indicesList, computeAABB(indicesList), nowIdx); +} + +size_t BVH_intersection::dfsBuild(vector &indicesList, AABB aabb, size_t &nowIdx) +{ + const size_t nodeIdx = nowIdx; + nowIdx++; + if (indicesList.size() == 1) + { + nodes[nodeIdx] = BVHNode(0, indicesList[0], 0, aabb); // VS2008 + return nodeIdx; + } + int longAxis = -1; + float longAxisLen = -1; + for (int i = 0; i < 3; ++i) + { + const float axisLen = aabb.max[i] - aabb.min[i]; + if (axisLen > longAxisLen) + { + longAxisLen = axisLen; + longAxis = i; + } + } + const size_t k = indicesList.size() / 2; + nth(indicesList, k - 1, longAxis); + vector leftIndices(indicesList.begin(), indicesList.begin() + k); + vector rightIndices(indicesList.begin() + k, indicesList.end()); + const AABB leftAABB = computeAABB(leftIndices); + const AABB rightAABB = computeAABB(rightIndices); + const size_t leftIdx = dfsBuild(leftIndices, leftAABB, nowIdx); + const size_t rightIdx = dfsBuild(rightIndices, rightAABB, nowIdx); + nodes[nodeIdx] = BVHNode(leftIdx, rightIdx, 0, aabb); // VS2008 + nodes[leftIdx].parent = nodeIdx; + nodes[rightIdx].parent = nodeIdx; + return nodeIdx; +} + +bool BVH_intersection::intersectWithLineSegment(const LineSegment &lineSegment) const +{ + return recursiveLineSegIntersection(lineSegment, 0); +} + +AABB BVH_intersection::computeAABB(const vector &indices) +{ + AABB aabb; + for (vector::const_iterator it = indices.begin(); it != indices.end(); ++it) + { + const Vec3u &face = mesh.indices[*it]; + for (int i = 0; i < 3; ++i) + { + const Vec3f &vertex = mesh.vertices[face[i]]; + for (int j = 0; j < 3; ++j) + { + aabb.min[j] = min(aabb.min[j], vertex[j]); + aabb.max[j] = max(aabb.max[j], vertex[j]); + } + } + } + return aabb; +} + +bool BVH_intersection::recursiveLineSegIntersection(const LineSegment &lineSegment, size_t nodeIdx) const +{ + const AABB &aabb = nodes[nodeIdx].boundingBox; + const Vec3f &dir = lineSegment.getDir(); + bool hit = false; + for (int i = 0; !hit && i < 3; ++i) + { + float t_min = (aabb.min[i] - lineSegment.start[i]) / dir[i]; + float t_max = (aabb.max[i] - lineSegment.start[i]) / dir[i]; + if (t_min > t_max) + { + swap(t_min, t_max); + } + if (t_min > lineSegment.getLength() || t_max < 0) + return false; + Vec3f hitPt = lineSegment.start + dir * t_min; + int otherPlane1 = (i + 1) % 3, otherPlane2 = (i + 2) % 3; + if (hitPt[otherPlane1] >= aabb.min[otherPlane1] && hitPt[otherPlane1] <= aabb.max[otherPlane1] && + hitPt[otherPlane2] >= aabb.min[otherPlane2] && hitPt[otherPlane2] <= aabb.max[otherPlane2]) + { + hit = true; + } + } + if (hit) + { + if (nodes[nodeIdx].left == 0) + { + Vec3u face = mesh.indices[nodes[nodeIdx].right]; + TriangleSegmentIntersectRes res = triangleSegmentIntersection(lineSegment, mesh.vertices[face[0]], mesh.vertices[face[1]], + mesh.vertices[face[2]]); + if (!res.hit || res.t < 0 || res.t > lineSegment.getLength()) + return false; + return true; + } + else + { + return recursiveLineSegIntersection(lineSegment, nodes[nodeIdx].left) || + recursiveLineSegIntersection(lineSegment, nodes[nodeIdx].right); + } + } + return false; +} + +void BVH_intersection::nth(vector &indicesList, size_t kth, int longAxis) +{ + recursiveChoose(indicesList, 0, indicesList.size() - 1, kth, longAxis); +} + +void BVH_intersection::recursiveChoose(vector &indicesList, size_t begin, size_t end, size_t kth, int longAxis) +{ + if (begin >= end) + return; + int i = begin, j = end; + while (i < j) + { + while (i < j && faceCenters[indicesList[j]][longAxis] >= faceCenters[indicesList[begin]][longAxis]) + j--; + while (i < j && faceCenters[indicesList[i]][longAxis] <= faceCenters[indicesList[begin]][longAxis]) + i++; + swap(indicesList[i], indicesList[j]); + } + swap(indicesList[begin], indicesList[i]); + if (i == kth) + return; + if (i < kth) + recursiveChoose(indicesList, i + 1, end, kth, longAxis); + else + recursiveChoose(indicesList, begin, i - 1, kth, longAxis); +} diff --git a/src/xmlsql.cpp b/src/xmlsql.cpp index 9669121..37897cc 100644 --- a/src/xmlsql.cpp +++ b/src/xmlsql.cpp @@ -1,6 +1,3 @@ -// xmlsql.cpp : 定义控制台应用程序的入口点。 -// - #include #include #include "Astar.h" diff --git a/stdafx.cpp b/stdafx.cpp deleted file mode 100644 index f7ac9a6..0000000 --- a/stdafx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : ֻ׼ļԴļ -// xmlsql.pch ΪԤͷ -// stdafx.obj ԤϢ - -#include "stdafx.h" - -// TODO: STDAFX.H -// κĸͷļڴļ diff --git a/stdafx.h b/stdafx.h deleted file mode 100644 index 4ed5f91..0000000 --- a/stdafx.h +++ /dev/null @@ -1,26 +0,0 @@ -// stdafx.h : ��׼ϵͳ�����ļ��İ����ļ��� -// ���Ǿ���ʹ�õ��������ĵ� -// �ض�����Ŀ�İ����ļ� -// - -#pragma once - -// #pragma comment(lib, "tinyxml.lib") - -#define Word Microsoft::Office::Interop::Word - -#include "targetver.h" - -#include -#ifdef _WIN32 - #include - #include - #include -#endif -#include -#include -#include - -// #include - -// TODO: �ڴ˴����ó�����Ҫ������ͷ�ļ�