17 changed files with 1006 additions and 0 deletions
@ -0,0 +1,16 @@ |
|||||
|
cmake_minimum_required(VERSION 3.21) |
||||
|
project(SingularityJudger) |
||||
|
|
||||
|
set(CMAKE_CXX_STANDARD 14) |
||||
|
|
||||
|
include_directories(include) |
||||
|
# 引入glm tinynurbs依赖 |
||||
|
include_directories(E:/CLib/tinynurbs/include E:/CLib/glm) |
||||
|
|
||||
|
add_executable(SingularityJudger main.cpp |
||||
|
include/loop_detector.h src/loop_detector.cpp |
||||
|
include/gauss_map.h src/gauss_map.cpp |
||||
|
include/aabb.h src/aabb.cpp |
||||
|
include/C2C4.h src/C2C4.cpp |
||||
|
include/Range.h src/Range.cpp |
||||
|
src/SingularityJudger.cpp include/SingularityJudger.h src/srf_mesh.cpp include/srf_mesh.h) |
@ -0,0 +1,50 @@ |
|||||
|
//
|
||||
|
// Created by 14727 on 2022/12/7.
|
||||
|
//
|
||||
|
|
||||
|
#ifndef C2C4_C2C4_H |
||||
|
#define C2C4_C2C4_H |
||||
|
|
||||
|
#include "glm/glm.hpp" |
||||
|
#include "../include/Range.h" |
||||
|
#include "vector" |
||||
|
#include "srf_mesh.h" |
||||
|
#include "tinynurbs/tinynurbs.h" |
||||
|
|
||||
|
using namespace tinynurbs; |
||||
|
using namespace std; |
||||
|
|
||||
|
|
||||
|
class C2C4 { |
||||
|
private: |
||||
|
// 雅可比矩阵【行】【列】<左界,右界>
|
||||
|
vector<vector<Range>> jacobian; |
||||
|
/**
|
||||
|
* 求range去掉某一列的三阶子行列式是否含零 |
||||
|
* @return 若去掉某些列,三阶子行列式含零,输出去掉的列号 |
||||
|
*/ |
||||
|
Range determinant3(int c0, int c1, int c2); |
||||
|
Range determinant2(int l0, int l1, int c0, int c1); |
||||
|
|
||||
|
|
||||
|
public: |
||||
|
|
||||
|
C2C4(const SrfMesh& mesh1_, const SrfMesh& mesh2_, RationalSurface<float> srf1_, RationalSurface<float> srf2_); |
||||
|
|
||||
|
const SrfMesh& mesh1; |
||||
|
const SrfMesh& mesh2; |
||||
|
|
||||
|
// 在给定的mesh的最小网格上重新细分的采样数目
|
||||
|
int reSampleCnt_u = 17; |
||||
|
int reSampleCnt_v = 17; |
||||
|
|
||||
|
RationalSurface<float> srf1; |
||||
|
RationalSurface<float> srf2; |
||||
|
|
||||
|
pair<bool, bool> c2OrC4(int patchIdx_u1, int patchIdx_v1, int patchIdx_u2, int patchIdx_v2); |
||||
|
vector<int> c4ExcludeCols; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif //C2C4_C2C4_H
|
@ -0,0 +1,21 @@ |
|||||
|
//
|
||||
|
// Created by 14727 on 2022/12/7.
|
||||
|
//
|
||||
|
|
||||
|
#ifndef C2C4_RANGE_H |
||||
|
#define C2C4_RANGE_H |
||||
|
|
||||
|
|
||||
|
class Range { |
||||
|
public: |
||||
|
float a; |
||||
|
float b; |
||||
|
Range(float _a, float _b); |
||||
|
Range()= default; |
||||
|
Range operator + (const Range & r2) const; |
||||
|
Range operator - (const Range & r2) const; |
||||
|
Range operator * (const Range & r2) const; |
||||
|
bool hasZero() const; |
||||
|
}; |
||||
|
|
||||
|
#endif //C2C4_RANGE_H
|
@ -0,0 +1,34 @@ |
|||||
|
#ifndef SINGULARITYJUDGER_SINGULARITYJUDGER_H |
||||
|
#define SINGULARITYJUDGER_SINGULARITYJUDGER_H |
||||
|
|
||||
|
#include "tinynurbs/tinynurbs.h" |
||||
|
#include "vector" |
||||
|
#include "srf_mesh.h" |
||||
|
#include "tinynurbs/tinynurbs.h" |
||||
|
|
||||
|
using namespace std; |
||||
|
using namespace tinynurbs; |
||||
|
|
||||
|
class SingularityJudger { |
||||
|
|
||||
|
public: |
||||
|
SingularityJudger(RationalSurface<float> &srf1_, RationalSurface<float> &srf2_, SrfMesh &mesh1_, SrfMesh &mesh2_); |
||||
|
|
||||
|
SrfMesh &mesh1; |
||||
|
SrfMesh &mesh2; |
||||
|
// 调用各个工具直接传入mesh信息,避免nurbs曲面的重复采样
|
||||
|
// 但曲面参数信息仍然需要传入,因为C2C4在最小的网格的基础上还需要进一步细分采样
|
||||
|
RationalSurface<float> &srf1; |
||||
|
RationalSurface<float> &srf2; |
||||
|
|
||||
|
// 关注mesh的采样网格中的哪个范围
|
||||
|
// 假设mesh.sampleLevel = 5;
|
||||
|
bool judge(pair<int, int> focusRange_u1, pair<int, int> focusRange_v1, |
||||
|
pair<int, int> focusRange_u2, pair<int, int> focusRange_v2); |
||||
|
|
||||
|
vector<vector<char>> judgeRes; |
||||
|
|
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif //SINGULARITYJUDGER_SINGULARITYJUDGER_H
|
@ -0,0 +1,35 @@ |
|||||
|
// AABB部分的代码直接原封不动用的gitea/GeometryMain/surface-surface-intersection.git中bvh的代码,之后可以合并过去
|
||||
|
#ifndef AABB_HPP |
||||
|
#define AABB_HPP |
||||
|
|
||||
|
#include "glm/glm.hpp" |
||||
|
#include <cmath> |
||||
|
|
||||
|
class AABB { |
||||
|
public: |
||||
|
// 边界
|
||||
|
glm::dvec3 pMin, pMax; |
||||
|
|
||||
|
public: |
||||
|
AABB() { |
||||
|
double minNum = std::numeric_limits<double>::lowest(); |
||||
|
double maxNum = std::numeric_limits<double>::max(); |
||||
|
pMax = glm::dvec3(minNum, minNum, minNum); |
||||
|
pMin = glm::dvec3(maxNum, maxNum, maxNum); |
||||
|
} |
||||
|
AABB(const glm::dvec3 p) : pMin(p), pMax(p) {} |
||||
|
AABB(const glm::dvec3 p1, const glm::dvec3 p2) { |
||||
|
pMin = glm::dvec3(fmin(p1.x, p2.x), fmin(p1.y, p2.y), fmin(p1.z, p2.z)); |
||||
|
pMax = glm::dvec3(fmax(p1.x, p2.x), fmax(p1.y, p2.y), fmax(p1.z, p2.z)); |
||||
|
} |
||||
|
}; |
||||
|
// 判断点是否在包围盒内,是返回true,否返回false
|
||||
|
bool isPointInBox(const glm::dvec3 &pt, const AABB& box); |
||||
|
// aabb包围盒合并操作,包围盒和点
|
||||
|
AABB Union(const AABB& b1, const glm::dvec3& p); |
||||
|
// aabb包围盒合并操作,两个包围盒
|
||||
|
AABB Union(const AABB& b1, const AABB& b2); |
||||
|
// 判断两个aabb包围盒是否重叠
|
||||
|
bool IsOverlap(AABB b1, AABB b2); |
||||
|
|
||||
|
#endif |
@ -0,0 +1,80 @@ |
|||||
|
//
|
||||
|
// Created by 14727 on 2022/12/24.
|
||||
|
//
|
||||
|
|
||||
|
#ifndef GAUSSMAP_GAUSS_MAP_H |
||||
|
#define GAUSSMAP_GAUSS_MAP_H |
||||
|
|
||||
|
#include "vector" |
||||
|
#include "tinynurbs/tinynurbs.h" |
||||
|
#include "glm/glm.hpp" |
||||
|
#include "aabb.h" |
||||
|
#include "map" |
||||
|
|
||||
|
// 一个节点就表示一个球上矩形面片
|
||||
|
struct GaussMapNode { |
||||
|
// 四个顶点的法向量值确定一个平面的法向量值
|
||||
|
AABB nBound; |
||||
|
int level, firstChild; |
||||
|
}; |
||||
|
|
||||
|
class GaussMap { |
||||
|
public: |
||||
|
int maxLevel; |
||||
|
int leafSampleCnt; |
||||
|
const std::vector<std::vector<glm::vec3>> & normals; |
||||
|
tinynurbs::RationalSurface<float> srf; |
||||
|
std::vector<GaussMapNode> tree; |
||||
|
|
||||
|
void recursiveBuild(int level, int idx, int idx_u, int idx_v); |
||||
|
|
||||
|
GaussMap(const std::vector<std::vector<glm::vec3>>& normals_); |
||||
|
|
||||
|
void build(); |
||||
|
|
||||
|
void normalInit(); |
||||
|
|
||||
|
void printQuadTree(); |
||||
|
}; |
||||
|
|
||||
|
std::vector<std::pair<int, int>> getOverlapLeafNodes(const GaussMap &gm1, const GaussMap &gm2); |
||||
|
|
||||
|
void recursiveGetOverlapLeafNodes(const GaussMap &gm1, const GaussMap &gm2, int idx1, int idx2, |
||||
|
std::vector<std::pair<int, int>> &pairs); |
||||
|
|
||||
|
/**
|
||||
|
* 判断两个曲面的Gauss Map在指定的、各自的参数范围内有没有交 |
||||
|
* @param idxRange_u1 第一个gauss map的参数u范围对应的u方向上的采样网格的格子下标范围 |
||||
|
* @param idxRange_v1 第一个gauss map的参数v范围对应的u方向上的采样网格的格子下标范围 |
||||
|
* @param idxRange_u2 第而个gauss map的参数u范围对应的u方向上的采样网格的格子下标范围 |
||||
|
* @param idxRange_v2 第二个gauss map的参数v范围对应的u方向上的采样网格的格子下标范围 |
||||
|
* @return true:gauss map的包围盒有交集,说明gauss map<可能>有重合;false: gauss map一定没有重合 |
||||
|
*/ |
||||
|
bool isGaussMapsOverlapped(const GaussMap &gm1, const GaussMap &gm2, std::pair<int, int> idxRange_u1, |
||||
|
std::pair<int, int> idxRange_v1, std::pair<int, int> idxRange_u2, |
||||
|
std::pair<int, int> idxRange_v2); |
||||
|
|
||||
|
/**
|
||||
|
* 判断两个曲面的Gauss Map在指定的、各自的参数范围内有没有交 |
||||
|
* @param range_u1 第一个gauss map的参数u范围 |
||||
|
* @param range_v1 第一个gauss map的参数v范围 |
||||
|
* @param range_u2 第二个gauss map的参数u范围 |
||||
|
* @param range_v2 第二个gauss map的参数v范围 |
||||
|
* @param paramRange_u1 第一个gauss map的参数u定义域 |
||||
|
* @param paramRange_v1 第一个gauss map的参数v定义域 |
||||
|
* @param paramRange_u2 第二个gauss map的参数u定义域 |
||||
|
* @param paramRange_v2 第二个gauss map的参数v定义域 |
||||
|
* @return true:gauss map的包围盒有交集,说明gauss map<可能>有重合;false: gauss map一定没有重合 |
||||
|
*/ |
||||
|
bool isGaussMapsOverlapped(const GaussMap &gm1, const GaussMap &gm2, std::pair<float, float> range_u1, |
||||
|
std::pair<float, float> range_v1, std::pair<float, float> range_u2, |
||||
|
std::pair<float, float> range_v2, std::pair<float, float> paramRange_u1, |
||||
|
std::pair<float, float> paramRange_v1, |
||||
|
std::pair<float, float> paramRange_u2, |
||||
|
std::pair<float, float> paramRange_v2); |
||||
|
|
||||
|
int getStartIdxOfLayerN(int layer); |
||||
|
|
||||
|
int getChildNodeIdx(int ix, int iy); |
||||
|
|
||||
|
#endif //GAUSSMAP_GAUSS_MAP_H
|
@ -0,0 +1,74 @@ |
|||||
|
#ifndef LOOPDETECTOR_LOOP_DETECTOR_H |
||||
|
#define LOOPDETECTOR_LOOP_DETECTOR_H |
||||
|
|
||||
|
#include "tinynurbs/tinynurbs.h" |
||||
|
#include "glm/glm.hpp" |
||||
|
|
||||
|
using namespace std; |
||||
|
|
||||
|
class LoopDetector { |
||||
|
public: |
||||
|
LoopDetector(const vector<vector<glm::vec3>> &s_evaluation_, const vector<vector<glm::vec3>> &f_evaluation_, |
||||
|
const vector<vector<glm::vec3>> &s_tangent_u_, const vector<vector<glm::vec3>> &f_tangent_u_, |
||||
|
const vector<vector<glm::vec3>> &s_tangent_v_, const vector<vector<glm::vec3>> &f_tangent_v_, |
||||
|
const vector<vector<glm::vec3>> &s_normal_, const vector<vector<glm::vec3>> &f_normal_); |
||||
|
|
||||
|
// 两个曲面
|
||||
|
tinynurbs::RationalSurface<float> s; |
||||
|
tinynurbs::RationalSurface<float> f; |
||||
|
// 细分采样的总层数(最高与BVH的总层数相等)。从第二层开始,每一层都表示把原来的一个小sub patch分成了更小的四份
|
||||
|
int maxSplitLayer; |
||||
|
|
||||
|
// 采样点的求值和求切向量先设为public,因为这些因该是算好的,LoopDetector不用重复计算
|
||||
|
// 曲面s和f的采样点。
|
||||
|
const vector<vector<glm::vec3>> &s_evaluation; |
||||
|
const vector<vector<glm::vec3>> &f_evaluation; |
||||
|
// 曲面s和f的切向量。
|
||||
|
const vector<vector<glm::vec3>> &s_tangent_u; |
||||
|
const vector<vector<glm::vec3>> &s_tangent_v; |
||||
|
const vector<vector<glm::vec3>> &f_tangent_u; |
||||
|
const vector<vector<glm::vec3>> &f_tangent_v; |
||||
|
// 曲面s和f的法向量
|
||||
|
const vector<vector<glm::vec3>> &s_normal; |
||||
|
const vector<vector<glm::vec3>> &f_normal; |
||||
|
|
||||
|
// 有向距离计算结果。有向距离通过采样的方式计算,其结果与s曲面sub patch中的采样网格规模相同,即与s_evaluation大小一致
|
||||
|
// vector<vector<glm::vec3>> distance;
|
||||
|
// 确定有向距离后,对应的f曲面上的最短距离点的位置
|
||||
|
vector<vector<pair<int, int>>> selectedPointsIdx; |
||||
|
// vector fields, 即有向距离关于u、v的导数
|
||||
|
vector<vector<glm::vec2>> vectorFields; |
||||
|
vector<vector<int>> rotationNumbers; |
||||
|
|
||||
|
// int subPatchEdgeSampleCnt; // 在一个sub patch的采样网格中,边上的采样点个数
|
||||
|
// void init(tinynurbs::RationalSurface<float> _s, tinynurbs::RationalSurface<float> _f, int _maxSplitLayer);
|
||||
|
vector<pair<int, int>> detect(pair<int, int> _s_subPatchIdxRange_u, pair<int, int> _s_subPatchIdxRange_v, |
||||
|
pair<int, int> _f_subPatchIdxRange_u, pair<int, int> _f_subPatchIdxRange_v); |
||||
|
|
||||
|
|
||||
|
// 需要做Loop检测的sub patch在最后一层上的下标的范围(每个范围都真包含于[0, 2^(maxSplitLayer-1)-1])
|
||||
|
pair<int, int> s_subPatchIdxRange_u; |
||||
|
pair<int, int> s_subPatchIdxRange_v; |
||||
|
pair<int, int> f_subPatchIdxRange_u; |
||||
|
pair<int, int> f_subPatchIdxRange_v; |
||||
|
// subPatch每条边上的采样点个数
|
||||
|
// 这四个值根据subPatchRange的范围得到
|
||||
|
int s_subPatchEdgeSampleCnt_u; |
||||
|
int s_subPatchEdgeSampleCnt_v; |
||||
|
int f_subPatchEdgeSampleCnt_u; |
||||
|
int f_subPatchEdgeSampleCnt_v; |
||||
|
|
||||
|
private: |
||||
|
// 整个曲面一条边上的采样点个数
|
||||
|
int edgeSampleCnt; |
||||
|
|
||||
|
|
||||
|
void initOrientedDistance(); |
||||
|
|
||||
|
void initVectorField(); |
||||
|
|
||||
|
void getRotationNumber(); |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif //LOOPDETECTOR_LOOP_DETECTOR_H
|
@ -0,0 +1,19 @@ |
|||||
|
#ifndef SINGULARITYJUDGER_SRF_MESH_H |
||||
|
#define SINGULARITYJUDGER_SRF_MESH_H |
||||
|
|
||||
|
#include "vector" |
||||
|
#include "glm/glm.hpp" |
||||
|
using namespace std; |
||||
|
// 用采样网格表示的一个曲面
|
||||
|
class SrfMesh { |
||||
|
public: |
||||
|
int sampleLevel; // 采样层级;每多一层,uv方向的网格数都分别x2,整个mesh的网格数x4;sampleLevel为1时,采样整个面,仅有一个网格
|
||||
|
int sampleCntOnSingleDir; |
||||
|
vector<vector<glm::vec3>> evaluation; |
||||
|
vector<vector<glm::vec3>> tangent_u; |
||||
|
vector<vector<glm::vec3>> tangent_v; |
||||
|
vector<vector<glm::vec3>> normal; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif //SINGULARITYJUDGER_SRF_MESH_H
|
@ -0,0 +1,100 @@ |
|||||
|
#include <iostream> |
||||
|
#include "SingularityJudger.h" |
||||
|
|
||||
|
SrfMesh getMesh(const RationalSurface<float>& s, int sampleLevel){ |
||||
|
SrfMesh res; |
||||
|
res.sampleLevel = sampleLevel; |
||||
|
res.sampleCntOnSingleDir = int(pow(2, sampleLevel - 1) + 1); |
||||
|
res.evaluation = vector<vector<glm::vec3>>(res.sampleCntOnSingleDir, vector<glm::vec3>(res.sampleCntOnSingleDir)); |
||||
|
res.tangent_u = vector<vector<glm::vec3>>(res.sampleCntOnSingleDir, vector<glm::vec3>(res.sampleCntOnSingleDir)); |
||||
|
res.tangent_v = vector<vector<glm::vec3>>(res.sampleCntOnSingleDir, vector<glm::vec3>(res.sampleCntOnSingleDir)); |
||||
|
res.normal = vector<vector<glm::vec3>>(res.sampleCntOnSingleDir, vector<glm::vec3>(res.sampleCntOnSingleDir)); |
||||
|
|
||||
|
auto s_first_u = *(s.knots_u.begin()); |
||||
|
auto s_first_v = *(s.knots_v.begin()); |
||||
|
auto s_step_u = (*(s.knots_u.end() - 1) - s_first_u) / float(res.sampleCntOnSingleDir - 1); |
||||
|
auto s_step_v = (*(s.knots_v.end() - 1) - s_first_v) / float(res.sampleCntOnSingleDir - 1); |
||||
|
|
||||
|
for(int i = 0; i < res.sampleCntOnSingleDir; i++) { |
||||
|
auto u = s_first_u + s_step_u * float(i); |
||||
|
for(int j = 0; j < res.sampleCntOnSingleDir; j++) { |
||||
|
auto v = s_first_v + s_step_v * float(j); |
||||
|
res.evaluation[i][j] = tinynurbs::surfacePoint(s, u, v); |
||||
|
auto der = tinynurbs::surfaceDerivatives(s, 1, u, v); |
||||
|
res.tangent_u[i][j] = der(1, 0); |
||||
|
res.tangent_v[i][j] = der(0, 1); |
||||
|
res.normal[i][j] = glm::cross(res.tangent_u[i][j], res.tangent_v[i][j]); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main() { |
||||
|
RationalSurface<float> s; |
||||
|
RationalSurface<float> f; |
||||
|
s.degree_u = 3; |
||||
|
s.degree_v = 3; |
||||
|
s.knots_u = {0, 0, 0, 0, 1, 1, 1, 1}; |
||||
|
s.knots_v = {0, 0, 0, 0, 1, 1, 1, 1}; |
||||
|
s.control_points = {4, 4, { |
||||
|
glm::vec3(0, 0.3, 0.9), glm::vec3(0, 0.6, 1), glm::vec3(0, 0.9, 1.1), glm::vec3(0, 1.2, 1), |
||||
|
glm::vec3(0.33, 0.3, 0.12), glm::vec3(0.33, 0.6, 0.12), glm::vec3(0.33, 0.9, 0.12), |
||||
|
glm::vec3(0.33, 1.2, 0.12), |
||||
|
glm::vec3(0.66, 0.3, 0.12), glm::vec3(0.66, 0.6, 0.12), glm::vec3(0.66, 0.9, 0.12), |
||||
|
glm::vec3(0.66, 1.2, 0.12), |
||||
|
glm::vec3(1, 0.3, 0.8), glm::vec3(1, 0.6, 1), glm::vec3(1, 0.9, 1.1), glm::vec3(1, 1.2, 1) |
||||
|
}}; |
||||
|
s.weights = {4, 4, |
||||
|
{ |
||||
|
1, 1, 1, 1, |
||||
|
1, 1, 1, 1, |
||||
|
1, 1, 1, 1, |
||||
|
1, 1, 1, 1, |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
f.degree_u = 3; |
||||
|
f.degree_v = 3; |
||||
|
f.knots_u = {0, 0, 0, 0, 1, 1, 1, 1}; |
||||
|
f.knots_v = {0, 0, 0, 0, 1, 1, 1, 1}; |
||||
|
f.control_points = {4, 4, { |
||||
|
glm::vec3(0, 0.2, 0.9), glm::vec3(0, 0.5, 1.8), glm::vec3(0, 0.8, 1.1), glm::vec3(0, 1.2, 1), |
||||
|
glm::vec3(0.33, 0.2, 0.12), glm::vec3(0.33, 0.5, 0.42), glm::vec3(0.33, 0.9, -0.62), |
||||
|
glm::vec3(0.33, 1.1, -1.756), |
||||
|
glm::vec3(0.66, 0.2, 0.12), glm::vec3(0.66, 0.5, 0.42), glm::vec3(0.66, 0.9, -0.62), |
||||
|
glm::vec3(0.66, 1.0, -1.756), |
||||
|
glm::vec3(1, 0.2, 0.8), glm::vec3(1, 0.5, 1), glm::vec3(1, 0.9, 1.1), glm::vec3(1, 1.2, 1) |
||||
|
}}; |
||||
|
f.weights = {4, 4, |
||||
|
{ |
||||
|
1, 1, 1, 1, |
||||
|
1, 1, 1, 1, |
||||
|
1, 1, 1, 1, |
||||
|
1, 1, 1, 1, |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
vector<vector<glm::vec3>> s_evaluation; |
||||
|
vector<vector<glm::vec3>> f_evaluation; |
||||
|
// 曲面s和f的切向量。
|
||||
|
vector<vector<glm::vec3>> s_tangent_u; |
||||
|
vector<vector<glm::vec3>> s_tangent_v; |
||||
|
vector<vector<glm::vec3>> f_tangent_u; |
||||
|
const vector<vector<glm::vec3>> f_tangent_v; |
||||
|
// 曲面s和f的法向量
|
||||
|
const vector<vector<glm::vec3>> s_normal; |
||||
|
const vector<vector<glm::vec3>> f_normal; |
||||
|
|
||||
|
auto mesh1 = getMesh(s, 7); |
||||
|
auto mesh2 = getMesh(f, 7); |
||||
|
|
||||
|
SingularityJudger singularityJudger(s, f, mesh1, mesh2); |
||||
|
auto hasSingularity = singularityJudger.judge({2,7}, {4,12}, {3, 9}, {10, 16}); |
||||
|
for(auto line: singularityJudger.judgeRes) { |
||||
|
for(auto el: line) { |
||||
|
cout<<el<<' '; |
||||
|
} |
||||
|
cout<<endl; |
||||
|
} |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,114 @@ |
|||||
|
//
|
||||
|
// Created by 14727 on 2022/12/7.
|
||||
|
//
|
||||
|
|
||||
|
#include "../include/C2C4.h" |
||||
|
|
||||
|
#include <utility> |
||||
|
|
||||
|
pair<bool, bool> C2C4::c2OrC4(int patchIdx_u1, int patchIdx_v1, int patchIdx_u2, int patchIdx_v2) { |
||||
|
jacobian = vector<vector<Range>>(3, vector<Range>(4, Range(999999.f, -999999.f))); |
||||
|
float knotsRange_u1 = srf1.knots_u[srf1.knots_u.size() - 1] - srf1.knots_u[0]; |
||||
|
float knotsRange_u2 = srf2.knots_u[srf2.knots_u.size() - 1] - srf2.knots_u[0]; |
||||
|
float knotsRange_v1 = srf1.knots_v[srf1.knots_v.size() - 1] - srf1.knots_v[0]; |
||||
|
float knotsRange_v2 = srf2.knots_v[srf2.knots_v.size() - 1] - srf2.knots_v[0]; |
||||
|
auto patchEdge_u1 = knotsRange_u1 / (mesh1.sampleCntOnSingleDir - 1); |
||||
|
auto patchEdge_u2 = knotsRange_u2 / (mesh2.sampleCntOnSingleDir - 1); |
||||
|
auto patchEdge_v1 = knotsRange_v1 / (mesh1.sampleCntOnSingleDir - 1); |
||||
|
auto patchEdge_v2 = knotsRange_v2 / (mesh2.sampleCntOnSingleDir - 1); |
||||
|
float u1Base = srf1.knots_u[0] + patchIdx_u1 * patchEdge_u1; |
||||
|
float u2Base = srf2.knots_u[0] + patchIdx_u2 * patchEdge_u2; |
||||
|
float v1Base = srf1.knots_v[0] + patchIdx_v1 * patchEdge_v1; |
||||
|
float v2Base = srf2.knots_v[0] + patchIdx_v2 * patchEdge_v2; |
||||
|
// 采样
|
||||
|
for (int i = 0; i < reSampleCnt_u; ++i) { |
||||
|
auto u1 = u1Base + i * patchEdge_u1 / (reSampleCnt_u - 1); |
||||
|
auto u2 = u2Base + i * patchEdge_u2 / (reSampleCnt_u - 1); |
||||
|
for (int j = 0; j < reSampleCnt_v; ++j) { |
||||
|
glm::vec<3, float> der1_u{}, der1_v{}; |
||||
|
glm::vec<3, float> der2_u{}, der2_v{}; |
||||
|
// 尽量减少重复采样:四个边界点的值是已经采样过的
|
||||
|
if (i == 0 && j == 0) { |
||||
|
der1_u = mesh1.tangent_u[patchIdx_u1][patchIdx_v1]; |
||||
|
der1_v = mesh1.tangent_v[patchIdx_u1][patchIdx_v1]; |
||||
|
der2_u = mesh2.tangent_u[patchIdx_u2][patchIdx_v2]; |
||||
|
der2_v = mesh2.tangent_v[patchIdx_u2][patchIdx_v2]; |
||||
|
} else if (i == 0 && j == reSampleCnt_v - 1) { |
||||
|
der1_u = mesh1.tangent_u[patchIdx_u1][patchIdx_v1 + 1]; |
||||
|
der1_v = mesh1.tangent_v[patchIdx_u1][patchIdx_v1 + 1]; |
||||
|
der2_u = mesh2.tangent_u[patchIdx_u2][patchIdx_v2 + 1]; |
||||
|
der2_v = mesh2.tangent_v[patchIdx_u2][patchIdx_v2 + 1]; |
||||
|
} else if (i == reSampleCnt_u - 1 && j == 0) { |
||||
|
der1_u = mesh1.tangent_u[patchIdx_u1 + 1][patchIdx_v1]; |
||||
|
der1_v = mesh1.tangent_v[patchIdx_u1 + 1][patchIdx_v1]; |
||||
|
der2_u = mesh2.tangent_u[patchIdx_u2 + 1][patchIdx_v2]; |
||||
|
der2_v = mesh2.tangent_v[patchIdx_u2 + 1][patchIdx_v2]; |
||||
|
} else if (i == reSampleCnt_u - 1 || j == reSampleCnt_v - 1) { |
||||
|
der1_u = mesh1.tangent_u[patchIdx_u1 + 1][patchIdx_v1 + 1]; |
||||
|
der1_v = mesh1.tangent_v[patchIdx_u1 + 1][patchIdx_v1 + 1]; |
||||
|
der2_u = mesh2.tangent_u[patchIdx_u2 + 1][patchIdx_v2 + 1]; |
||||
|
der2_v = mesh2.tangent_v[patchIdx_u2 + 1][patchIdx_v2 + 1]; |
||||
|
} else { |
||||
|
float v1 = v1Base + j * patchEdge_v1 / (reSampleCnt_v - 1); |
||||
|
float v2 = v2Base + j * patchEdge_v2 / (reSampleCnt_v - 1); |
||||
|
auto der1 = tinynurbs::surfaceDerivatives(srf1, 1, u1, v1); |
||||
|
auto der2 = tinynurbs::surfaceDerivatives(srf2, 1, u2, v2); |
||||
|
der1_u = der1[2], der1_v = der1[1]; |
||||
|
der2_u = -der2[2], der2_v = -der2[1]; |
||||
|
} |
||||
|
jacobian[0][0].a = min(jacobian[0][0].a, der1_u.x), jacobian[0][0].b = max(jacobian[0][0].b, der1_u.x); |
||||
|
jacobian[1][0].a = min(jacobian[1][0].a, der1_u.y), jacobian[1][0].b = max(jacobian[1][0].b, der1_u.y); |
||||
|
jacobian[2][0].a = min(jacobian[2][0].a, der1_u.z), jacobian[2][0].b = max(jacobian[2][0].b, der1_u.z); |
||||
|
|
||||
|
jacobian[0][1].a = min(jacobian[0][1].a, der1_v.x), jacobian[0][1].b = max(jacobian[0][1].b, der1_v.x); |
||||
|
jacobian[1][1].a = min(jacobian[1][1].a, der1_v.y), jacobian[1][1].b = max(jacobian[1][1].b, der1_v.y); |
||||
|
jacobian[2][1].a = min(jacobian[2][1].a, der1_v.z), jacobian[2][1].b = max(jacobian[2][1].b, der1_v.z); |
||||
|
|
||||
|
jacobian[0][2].a = min(jacobian[0][2].a, der2_u.x), jacobian[0][2].b = max(jacobian[0][2].b, der2_u.x); |
||||
|
jacobian[1][2].a = min(jacobian[1][2].a, der2_u.y), jacobian[1][2].b = max(jacobian[1][2].b, der2_u.y); |
||||
|
jacobian[2][2].a = min(jacobian[2][2].a, der2_u.z), jacobian[2][2].b = max(jacobian[2][2].b, der2_u.z); |
||||
|
|
||||
|
jacobian[0][3].a = min(jacobian[0][3].a, der2_v.x), jacobian[0][3].b = max(jacobian[0][3].b, der2_v.x); |
||||
|
jacobian[1][3].a = min(jacobian[1][3].a, der2_v.y), jacobian[1][3].b = max(jacobian[1][3].b, der2_v.y); |
||||
|
jacobian[2][3].a = min(jacobian[2][3].a, der2_v.z), jacobian[2][3].b = max(jacobian[2][3].b, der2_v.z); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 判断存在一个2阶子式行列式非0
|
||||
|
bool hasNotZero = false; // true: 存在一个二阶子式非0
|
||||
|
for (int l0 = 0; l0 < 2 && !hasNotZero; l0++) { |
||||
|
for (int l1 = 1; l1 < 3 && !hasNotZero; l1++) { |
||||
|
for (int c0 = 0; c0 < 3 && !hasNotZero; c0++) { |
||||
|
for (int c1 = 1; c1 < 4 && !hasNotZero; c1++) { |
||||
|
if (!determinant2(l0, l1, c0, c1).hasZero()) hasNotZero = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 判断3阶子式行列式含0情况
|
||||
|
if (!determinant3(0, 1, 2).hasZero()) c4ExcludeCols.push_back(3); |
||||
|
if (!determinant3(0, 1, 3).hasZero()) c4ExcludeCols.push_back(2); |
||||
|
if (!determinant3(0, 2, 3).hasZero()) c4ExcludeCols.push_back(1); |
||||
|
if (!determinant3(1, 2, 3).hasZero()) c4ExcludeCols.push_back(0); |
||||
|
pair<bool, bool> res(false, false); |
||||
|
if (hasNotZero && c4ExcludeCols.empty()) res.first = true; // C2
|
||||
|
else if (!c4ExcludeCols.empty()) res.second = true; // C4
|
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
Range C2C4::determinant3(int c0, int c1, int c2) { |
||||
|
return jacobian[0][c0] * jacobian[1][c1] * jacobian[2][c2] + |
||||
|
jacobian[0][c1] * jacobian[1][c2] * jacobian[2][c0] + |
||||
|
jacobian[0][c2] * jacobian[1][c0] * jacobian[2][c1] - |
||||
|
jacobian[0][c2] * jacobian[1][c1] * jacobian[2][c0] - |
||||
|
jacobian[0][c0] * jacobian[1][c2] * jacobian[2][c1] - |
||||
|
jacobian[0][c1] * jacobian[1][c0] * jacobian[2][c2]; |
||||
|
} |
||||
|
|
||||
|
Range C2C4::determinant2(int l0, int l1, int c0, int c1) { |
||||
|
return jacobian[l0][c0] * jacobian[l1][c1] - jacobian[l0][c1] * jacobian[l1][c0]; |
||||
|
} |
||||
|
|
||||
|
C2C4::C2C4(const SrfMesh &mesh1_, const SrfMesh &mesh2_, RationalSurface<float> srf1_, RationalSurface<float> srf2_) : |
||||
|
mesh1(mesh1_), mesh2(mesh2_), srf1(std::move(srf1_)), srf2(std::move(srf2_)) {} |
@ -0,0 +1,20 @@ |
|||||
|
#include "../include/Range.h" |
||||
|
#include "cmath" |
||||
|
|
||||
|
Range::Range(float _a, float _b): a(_a), b(_b) {} |
||||
|
|
||||
|
Range Range::operator-(const Range &r2) const { |
||||
|
return {a + r2.a, b + r2.b}; |
||||
|
} |
||||
|
|
||||
|
Range Range::operator+(const Range &r2) const { |
||||
|
return {a-r2.b, b-r2.a}; |
||||
|
} |
||||
|
|
||||
|
Range Range::operator*(const Range &r2) const { |
||||
|
return {fmin(fmin(fmin(a * r2.a, a * r2.b), b * r2.a), b * r2.b), fmin(fmin(fmin(a * r2.a, a * r2.b), b * r2.a), b * r2.b)}; |
||||
|
} |
||||
|
|
||||
|
bool Range::hasZero() const { |
||||
|
return a < 0 && b > 0; |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
#include "SingularityJudger.h" |
||||
|
|
||||
|
#include <utility> |
||||
|
#include "gauss_map.h" |
||||
|
#include "loop_detector.h" |
||||
|
#include "C2C4.h" |
||||
|
|
||||
|
|
||||
|
bool SingularityJudger::judge(pair<int, int> focusRange_u1, pair<int, int> focusRange_v1, pair<int, int> focusRange_u2, |
||||
|
pair<int, int> focusRange_v2) { |
||||
|
// TODO gauss map to exclude patch pair that must not make loop or singular intersection
|
||||
|
// gauss map 只需要法向量信息,不需要evaluations
|
||||
|
GaussMap gaussMap1(mesh1.normal); |
||||
|
GaussMap gaussMap2(mesh2.normal); |
||||
|
if (!isGaussMapsOverlapped(gaussMap1, gaussMap2, focusRange_u1, focusRange_u2, focusRange_v1, focusRange_v2)) { |
||||
|
// 一定没有交
|
||||
|
return false; |
||||
|
} |
||||
|
// TODO loop detection to retain patch pair that must have loop or singular intersection
|
||||
|
LoopDetector loopDetector(mesh1.evaluation, mesh2.evaluation, mesh1.tangent_u, mesh2.tangent_u, mesh1.tangent_v, |
||||
|
mesh2.tangent_v, mesh1.normal, mesh2.normal); |
||||
|
loopDetector.detect(focusRange_u1, focusRange_v1, focusRange_u2, focusRange_v2); |
||||
|
judgeRes = vector<vector<char>>(loopDetector.s_subPatchEdgeSampleCnt_u - 1, |
||||
|
vector<char>(loopDetector.s_subPatchEdgeSampleCnt_v - 1, 0)); |
||||
|
// TODO c2 determination for tangency case
|
||||
|
bool hasLoop = false; |
||||
|
C2C4 c2C4(mesh1, mesh2, srf1, srf2); |
||||
|
for (int i = 0; i < judgeRes.size(); i++) { |
||||
|
for (int j = 0; j < judgeRes[0].size(); j++) { |
||||
|
if (loopDetector.rotationNumbers[i][j] != 0) { |
||||
|
|
||||
|
hasLoop = true; |
||||
|
|
||||
|
// 非零,有loop
|
||||
|
// 依次测试C2
|
||||
|
auto accordPointOnF = loopDetector.selectedPointsIdx[i][j]; // 有向距离最短的,f曲面上的对应面片的坐标
|
||||
|
if (c2C4.c2OrC4(focusRange_u1.first + i, focusRange_v1.first + j, |
||||
|
focusRange_u2.first + accordPointOnF.first, |
||||
|
focusRange_v2.first + accordPointOnF.second).first) { |
||||
|
//C2
|
||||
|
judgeRes[i][j] = -1; |
||||
|
} else judgeRes[i][j] = 1; // 圆环
|
||||
|
} else { |
||||
|
judgeRes[i][j] = 0; // 0表示啥也没有
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return hasLoop; |
||||
|
} |
||||
|
|
||||
|
SingularityJudger:: |
||||
|
SingularityJudger(RationalSurface<float> &srf1_, RationalSurface<float> &srf2_, SrfMesh &mesh1_, SrfMesh &mesh2_) |
||||
|
:srf1(srf1_), srf2(srf2_), mesh1(mesh1_), mesh2(mesh2_){} |
@ -0,0 +1,45 @@ |
|||||
|
// AABB部分的代码直接原封不动用的gitea/GeometryMain/surface-surface-intersection.git中bvh的代码,之后可以合并过去
|
||||
|
#include "aabb.h" |
||||
|
|
||||
|
bool isPointInBox(const glm::dvec3 &pt, const AABB& box) { |
||||
|
double x = pt.x; |
||||
|
double y = pt.y; |
||||
|
double z = pt.z; |
||||
|
if (x < box.pMin.x || x > box.pMax.x) return false; |
||||
|
if (y < box.pMin.y || y > box.pMax.y) return false; |
||||
|
if (z < box.pMin.z || z > box.pMax.z) return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
AABB Union(const AABB& b1, const glm::dvec3& p) { |
||||
|
AABB ret; |
||||
|
ret.pMin = glm::dvec3(fmin(b1.pMin.x, p.x), |
||||
|
fmin(b1.pMin.y, p.y), |
||||
|
fmin(b1.pMin.z, p.z)); |
||||
|
ret.pMax = glm::dvec3(fmax(b1.pMax.x, p.x), |
||||
|
fmax(b1.pMax.y, p.y), |
||||
|
fmax(b1.pMax.z, p.z)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
AABB Union(const AABB& b1, const AABB& b2) { |
||||
|
AABB ret; |
||||
|
ret.pMin = glm::dvec3(fmin(b1.pMin.x, b2.pMin.x), |
||||
|
fmin(b1.pMin.y, b2.pMin.y), |
||||
|
fmin(b1.pMin.z, b2.pMin.z)); |
||||
|
ret.pMax = glm::dvec3(fmax(b1.pMax.x, b2.pMax.x), |
||||
|
fmax(b1.pMax.y, b2.pMax.y), |
||||
|
fmax(b1.pMax.z, b2.pMax.z)); |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
bool IsOverlap(AABB b1, AABB b2) { |
||||
|
if (b1.pMin.x > b2.pMax.x) return false; |
||||
|
if (b2.pMin.x > b1.pMax.x) return false; |
||||
|
if (b1.pMin.y > b2.pMax.y) return false; |
||||
|
if (b2.pMin.y > b1.pMax.y) return false; |
||||
|
if (b1.pMin.z > b2.pMax.z) return false; |
||||
|
if (b2.pMin.z > b1.pMax.z) return false; |
||||
|
return true; |
||||
|
} |
||||
|
|
@ -0,0 +1,197 @@ |
|||||
|
//
|
||||
|
// Created by 14727 on 2022/12/24.
|
||||
|
//
|
||||
|
|
||||
|
#include "gauss_map.h" |
||||
|
|
||||
|
#include <utility> |
||||
|
|
||||
|
|
||||
|
GaussMap::GaussMap(const std::vector<std::vector<glm::vec3>> &normals_): normals(normals_) { |
||||
|
leafSampleCnt = int(normals_.size()); |
||||
|
maxLevel = int(log2(leafSampleCnt - 1) + 1); |
||||
|
tree.resize(int((pow(4, maxLevel) - 1)) / 3); |
||||
|
} |
||||
|
|
||||
|
void GaussMap::recursiveBuild(int level, int idx, int idx_u, int idx_v) { |
||||
|
AABB bound; |
||||
|
if (level == maxLevel) { |
||||
|
// 叶子节点
|
||||
|
for (int i = 0; i < 2; i++) |
||||
|
for (int j = 0; j < 2; j++) |
||||
|
bound = Union(bound, normals[idx_u + i][idx_v + j]); |
||||
|
tree[idx].nBound = bound; |
||||
|
tree[idx].level = level; |
||||
|
tree[idx].firstChild = -1; |
||||
|
return; |
||||
|
} else { |
||||
|
int firstChild = 4 * idx + 1; |
||||
|
int halfRange = int(std::pow(2, maxLevel - level - 1)); // 当前层的曲面片的边长采样宽度的一半
|
||||
|
recursiveBuild(level + 1, firstChild, idx_u, idx_v); |
||||
|
recursiveBuild(level + 1, firstChild + 1, idx_u, idx_v + halfRange); |
||||
|
recursiveBuild(level + 1, firstChild + 2, idx_u + halfRange, idx_v); |
||||
|
recursiveBuild(level + 1, firstChild + 3, idx_u + halfRange, idx_v + halfRange); |
||||
|
for (int i = 0; i < 4; i++) |
||||
|
bound = Union(bound, tree[firstChild + i].nBound); |
||||
|
tree[idx].level = level; |
||||
|
tree[idx].nBound = bound; |
||||
|
tree[idx].firstChild = firstChild; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//void GaussMap::normalInit() {
|
||||
|
// auto first_u = *(srf.knots_u.begin());
|
||||
|
// auto first_v = *(srf.knots_v.begin());
|
||||
|
// auto step_u = (*(srf.knots_u.end() - 1) - first_u) / (leafSampleCnt - 1);
|
||||
|
// auto step_v = (*(srf.knots_v.end() - 1) - first_v) / (leafSampleCnt - 1);
|
||||
|
// normals = std::vector<std::vector<glm::vec3>>(leafSampleCnt, std::vector<glm::vec3>(leafSampleCnt, {0, 0, 0}));
|
||||
|
// for (int i = 0; i < leafSampleCnt; i++) {
|
||||
|
// auto u = first_u + i * step_u;
|
||||
|
// for (int j = 0; j < leafSampleCnt; j++) {
|
||||
|
// auto v = first_v + j * step_v;
|
||||
|
// auto res = tinynurbs::surfaceDerivatives(srf, 1, u, v);
|
||||
|
// auto &du = res(1, 0);
|
||||
|
// auto &dv = res(0, 1);
|
||||
|
// normals[i][j] = glm::normalize(glm::cross(du, dv));
|
||||
|
//// if(i == 1 && j == 1){
|
||||
|
//// if(du == res[2])printf("Woooowl\n");
|
||||
|
//// printf("x(%f, %f, %f), y(%f, %f, %f)\n", du.x, du.y, du.z, dv.x, dv.y, dv.z);
|
||||
|
//// printf("normal(%f, %f, %f)\n", normals[i][j].x, normals[i][j].y, normals[i][j].z);
|
||||
|
//// }
|
||||
|
// }
|
||||
|
// }
|
||||
|
//}
|
||||
|
|
||||
|
void GaussMap::build() { |
||||
|
recursiveBuild(1, 0, 0, 0); |
||||
|
} |
||||
|
|
||||
|
void GaussMap::printQuadTree() { |
||||
|
for (int l = 1, levelNodesCnt = 1, baseIdx = 0; l <= maxLevel; l++, levelNodesCnt *= 4, baseIdx = baseIdx * 4 + 1) { |
||||
|
for (int biasIdx = 0; biasIdx < levelNodesCnt; biasIdx++) { |
||||
|
int idx = baseIdx + biasIdx; |
||||
|
auto pMax = tree[idx].nBound.pMax; |
||||
|
auto pMin = tree[idx].nBound.pMin; |
||||
|
printf("<<%g, %g, %g>,<%g, %g, %g>> ", pMin.x, pMin.y, pMin.z, pMax.x, pMax.y, pMax.z); |
||||
|
} |
||||
|
printf("\n =============$$$$$$$============= \n"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::vector<std::pair<int, int>> getOverlapLeafNodes(const GaussMap &gm1, const GaussMap &gm2) { |
||||
|
std::vector<std::pair<int, int>> resPairs; |
||||
|
recursiveGetOverlapLeafNodes(gm1, gm2, 0, 0, resPairs); |
||||
|
return resPairs; |
||||
|
} |
||||
|
|
||||
|
void recursiveGetOverlapLeafNodes(const GaussMap &gm1, const GaussMap &gm2, int idx1, int idx2, |
||||
|
std::vector<std::pair<int, int>> &pairs) { |
||||
|
GaussMapNode A = gm1.tree[idx1]; |
||||
|
GaussMapNode B = gm2.tree[idx2]; |
||||
|
auto AABBSize = [](AABB aabb) { |
||||
|
return (aabb.pMax.z - aabb.pMin.z) * |
||||
|
(aabb.pMax.y - aabb.pMin.y) * |
||||
|
(aabb.pMax.x - aabb.pMin.x); |
||||
|
}; |
||||
|
|
||||
|
// 两个包围盒不相交,返回
|
||||
|
if (!IsOverlap(A.nBound, B.nBound)) return; |
||||
|
// 相交
|
||||
|
if (A.firstChild == -1 && B.firstChild == -1) { |
||||
|
// 两者都是叶子节点
|
||||
|
pairs.emplace_back(idx1, idx2); |
||||
|
} else if (A.firstChild != -1 && B.firstChild == -1) { |
||||
|
// A是中间结点,B是叶子结点
|
||||
|
for (int i = 0; i < 4; i++) recursiveGetOverlapLeafNodes(gm1, gm2, A.firstChild + i, idx2, pairs); |
||||
|
} else if (A.firstChild == -1 && B.firstChild != -1) { |
||||
|
// A是叶子结点,B是中间结点
|
||||
|
for (int i = 0; i < 4; i++) recursiveGetOverlapLeafNodes(gm1, gm2, idx1, B.firstChild + i, pairs); |
||||
|
} else { |
||||
|
// 都是中间结点
|
||||
|
if (AABBSize(A.nBound) > AABBSize(B.nBound)) { |
||||
|
// A的包围盒更大
|
||||
|
for (int i = 0; i < 4; i++) recursiveGetOverlapLeafNodes(gm1, gm2, A.firstChild + i, idx2, pairs); |
||||
|
} else { |
||||
|
// B的包围盒更大
|
||||
|
for (int i = 0; i < 4; i++) recursiveGetOverlapLeafNodes(gm1, gm2, idx1, B.firstChild + i, pairs); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool isGaussMapsOverlapped(const GaussMap &gm1, const GaussMap &gm2, std::pair<float, float> range_u1, |
||||
|
std::pair<float, float> range_v1, std::pair<float, float> range_u2, |
||||
|
std::pair<float, float> range_v2, std::pair<float, float> paramRange_u1, |
||||
|
std::pair<float, float> paramRange_v1, std::pair<float, float> paramRange_u2, |
||||
|
std::pair<float, float> paramRange_v2) { |
||||
|
if (gm1.maxLevel != gm2.maxLevel || gm1.maxLevel <= 0) { |
||||
|
printf("BVH Layer error!\n"); |
||||
|
return false; |
||||
|
} |
||||
|
int edgeCellCnt = pow(2, gm1.maxLevel - 1); |
||||
|
// 根据所给参数的范围和参数的定义域范围,获得对应的采样网格中的范围
|
||||
|
auto getIdxRange = [](std::pair<float, float> range, std::pair<float, float> paramRange, int edgeCellCnt) { |
||||
|
float paramStep = (paramRange.second - paramRange.first) / edgeCellCnt; |
||||
|
return std::pair<int, int>({int((range.first - paramRange.first) / paramStep), |
||||
|
int((range.second - paramRange.first) / paramStep)}); |
||||
|
}; |
||||
|
auto idxRange_u1 = getIdxRange(range_u1, paramRange_u1, edgeCellCnt); |
||||
|
auto idxRange_v1 = getIdxRange(range_v1, paramRange_v1, edgeCellCnt); |
||||
|
auto idxRange_u2 = getIdxRange(range_u2, paramRange_u2, edgeCellCnt); |
||||
|
auto idxRange_v2 = getIdxRange(range_v2, paramRange_v2, edgeCellCnt); |
||||
|
return isGaussMapsOverlapped(gm1, gm2, idxRange_u1, idxRange_v1, idxRange_u2, idxRange_v2); |
||||
|
} |
||||
|
|
||||
|
bool isGaussMapsOverlapped(const GaussMap &gm1, const GaussMap &gm2, std::pair<int, int> idxRange_u1, |
||||
|
std::pair<int, int> idxRange_v1, std::pair<int, int> idxRange_u2, |
||||
|
std::pair<int, int> idxRange_v2) { |
||||
|
if (gm1.maxLevel != gm2.maxLevel || gm1.maxLevel <= 0) { |
||||
|
printf("BVH Layer error!\n"); |
||||
|
return false; |
||||
|
} |
||||
|
int commonMaxLayer = gm1.maxLevel; |
||||
|
int edgeCellCnt = pow(2, commonMaxLayer - 1); |
||||
|
if (idxRange_u1.first < 0 || idxRange_u2.first < 0 || idxRange_v1.first < 0 || idxRange_v2.first < 0 || |
||||
|
idxRange_u1.second >= edgeCellCnt || idxRange_u2.second >= edgeCellCnt || |
||||
|
idxRange_v1.second >= edgeCellCnt || idxRange_v2.second >= edgeCellCnt) { |
||||
|
printf("Error when detecting overlapping: idx range invalid!\n"); |
||||
|
return false; |
||||
|
} |
||||
|
auto getRangedBox = [&commonMaxLayer](const GaussMap &gm, const std::pair<int, int> &idxRange_u, |
||||
|
const std::pair<int, int> idxRange_v) { |
||||
|
AABB bounding; |
||||
|
for (int i = idxRange_u.first; i <= idxRange_u.second; ++i) { |
||||
|
for (int j = idxRange_v.first; j <= idxRange_v.second; ++j) { |
||||
|
bounding = Union(bounding, |
||||
|
gm.tree[getStartIdxOfLayerN(commonMaxLayer) + getChildNodeIdx(i, j)].nBound); |
||||
|
} |
||||
|
} |
||||
|
return bounding; |
||||
|
}; |
||||
|
return IsOverlap(getRangedBox(gm1, idxRange_u1, idxRange_v1), getRangedBox(gm2, idxRange_u2, idxRange_v2)); |
||||
|
} |
||||
|
|
||||
|
int getStartIdxOfLayerN(int layer) { |
||||
|
if (layer == 1) return 0; |
||||
|
int num = 1; |
||||
|
// 找规律得出
|
||||
|
for (int i = 2; i < layer; i++) { |
||||
|
num = num * 4 + 1; |
||||
|
} |
||||
|
return num; |
||||
|
} |
||||
|
|
||||
|
int getChildNodeIdx(int ix, int iy) { |
||||
|
int idx = 0; |
||||
|
while (ix > 0) { |
||||
|
int log2XCeil = int(log2f(ix)); |
||||
|
idx += int(pow(4, log2XCeil)); |
||||
|
ix -= int(pow(2, log2XCeil)); |
||||
|
} |
||||
|
while (iy > 0) { |
||||
|
int log2XCeil = int(log2f(iy)); |
||||
|
idx += 2 * int(pow(4, log2XCeil)); |
||||
|
iy -= int(pow(2, log2XCeil)); |
||||
|
} |
||||
|
return idx; |
||||
|
} |
@ -0,0 +1,145 @@ |
|||||
|
#include "loop_detector.h" |
||||
|
#include <utility> |
||||
|
|
||||
|
const float PI = 3.1415927; |
||||
|
|
||||
|
LoopDetector:: |
||||
|
LoopDetector(const vector<vector<glm::vec3>> &s_evaluation_, const vector<vector<glm::vec3>> &f_evaluation_, |
||||
|
const vector<vector<glm::vec3>> &s_tangent_u_, const vector<vector<glm::vec3>> &f_tangent_u_, |
||||
|
const vector<vector<glm::vec3>> &s_tangent_v_, const vector<vector<glm::vec3>> &f_tangent_v_, |
||||
|
const vector<vector<glm::vec3>> &s_normal_, const vector<vector<glm::vec3>> &f_normal_) |
||||
|
: s_evaluation(s_evaluation_), f_evaluation(f_evaluation_), |
||||
|
s_tangent_u(s_tangent_u_), s_tangent_v(s_tangent_v_), |
||||
|
f_tangent_u(f_tangent_u_), f_tangent_v(f_tangent_v_), |
||||
|
s_normal(s_normal_), f_normal(f_normal_) { |
||||
|
} |
||||
|
|
||||
|
void LoopDetector::initOrientedDistance() { |
||||
|
|
||||
|
selectedPointsIdx = vector<vector<pair<int, int>>>(s_subPatchEdgeSampleCnt_u, |
||||
|
vector<pair<int, int>>(s_subPatchEdgeSampleCnt_v)); |
||||
|
// distance = vector<vector<glm::vec3>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec3>(s_subPatchEdgeSampleCnt_v));
|
||||
|
|
||||
|
for (int i = 0; i < s_subPatchEdgeSampleCnt_u; i++) { |
||||
|
for (int j = 0; j < s_subPatchEdgeSampleCnt_v; j++) { |
||||
|
float minDis = FLT_MAX; |
||||
|
int minDisFIdx_u = -1, minDisFIdx_v = -1; |
||||
|
for (int k = 0; k < f_subPatchEdgeSampleCnt_u; k++) { |
||||
|
for (int l = 0; l < f_subPatchEdgeSampleCnt_v; l++) { |
||||
|
auto dis = glm::distance( |
||||
|
s_evaluation[s_subPatchIdxRange_u.first + i][s_subPatchIdxRange_v.first + j], |
||||
|
f_evaluation[f_subPatchIdxRange_u.first + k][f_subPatchIdxRange_v.first + l]); |
||||
|
// 确定f上的对应点时,依据的最小欧氏距离,而不是有向距离
|
||||
|
if (dis < minDis) { |
||||
|
minDis = dis; |
||||
|
minDisFIdx_u = k; |
||||
|
minDisFIdx_v = l; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// auto N = glm::normalize(s_evaluation[i][j] - f_evaluation[minDisFIdx_u][minDisFIdx_v]);
|
||||
|
// // 直接normalize得到的单位向量总是与SF同向,但实际上N应当总是与f的一侧法向量成锐角
|
||||
|
// auto testAngle = N * glm::cross(f_tangent_u[minDisFIdx_u][minDisFIdx_v], f_tangent_v[minDisFIdx_u][minDisFIdx_v]);
|
||||
|
// N = testAngle.x + testAngle.y + testAngle.z > 0 ? N : -N;
|
||||
|
// distance[i][j] = N * (s_evaluation[i][j] - f_evaluation[minDisFIdx_u][minDisFIdx_v]);
|
||||
|
selectedPointsIdx[i][j] = {minDisFIdx_u, minDisFIdx_v}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void LoopDetector::initVectorField() { |
||||
|
vectorFields = vector<vector<glm::vec2>>(s_subPatchEdgeSampleCnt_u, vector<glm::vec2>(s_subPatchEdgeSampleCnt_v)); |
||||
|
for (int i = 0; i < s_subPatchEdgeSampleCnt_u; i++) { |
||||
|
for (int j = 0; j < s_subPatchEdgeSampleCnt_v; j++) { |
||||
|
auto fPointIdx = selectedPointsIdx[i][j]; |
||||
|
auto N = glm::normalize(s_evaluation[s_subPatchIdxRange_u.first + i][s_subPatchIdxRange_v.first + j] - |
||||
|
f_evaluation[f_subPatchIdxRange_u.first + fPointIdx.first] |
||||
|
[f_subPatchIdxRange_v.first + fPointIdx.second]); |
||||
|
if (isnan(N.x) || isnan(N.y) || isnan(N.z)) { |
||||
|
// 绝了,曲面s和f的交线正好经过采样点,此时就无法定义向量N
|
||||
|
// 这里取两个曲面在交点的法向量的平均做近似
|
||||
|
// auto tmp1 = glm::cross(s_tangent_u[i][j], s_tangent_v[i][j]);
|
||||
|
// auto tmp2 = glm::cross(f_tangent_u[fPointIdx.first][fPointIdx.second],
|
||||
|
// f_tangent_v[fPointIdx.first][fPointIdx.second]);
|
||||
|
N = glm::normalize(s_normal[s_subPatchIdxRange_u.first + i][s_subPatchIdxRange_v.first + j] + |
||||
|
f_normal[f_subPatchIdxRange_u.first + fPointIdx.first] |
||||
|
[f_subPatchIdxRange_v.first + fPointIdx.second]); |
||||
|
} |
||||
|
// u1、u2两个向量构成和N垂直的曲面
|
||||
|
glm::vec3 u1(1, 1, 1); |
||||
|
if (N.z != 0)u1.z = (-N.x - N.y) / N.z; |
||||
|
else if (N.y != 0)u1.y = (-N.x - N.z) / N.y; |
||||
|
else u1.x = (-N.y - N.z) / N.x; |
||||
|
u1 = glm::normalize(u1); |
||||
|
auto u2 = glm::normalize(glm::cross(N, u1)); |
||||
|
// s,f曲面在两个方向上的偏导
|
||||
|
auto ps_pu = s_tangent_u[s_subPatchIdxRange_u.first + i][s_subPatchIdxRange_v.first + j] |
||||
|
, ps_pv = s_tangent_v[s_subPatchIdxRange_u.first + i][s_subPatchIdxRange_v.first + j]; |
||||
|
auto pf_pp = f_tangent_u[f_subPatchIdxRange_u.first + fPointIdx.first] |
||||
|
[f_subPatchIdxRange_v.first + fPointIdx.second], pf_pq = f_tangent_v[f_subPatchIdxRange_u.first + fPointIdx.first] |
||||
|
[f_subPatchIdxRange_v.first + fPointIdx.second]; |
||||
|
// 构造Aij矩阵,见<Detection of loops and singularities of surface intersections> APPENDIX (A7)
|
||||
|
auto inverseAij = glm::inverse( |
||||
|
glm::mat2x2(glm::dot(u1, pf_pp), glm::dot(u1, pf_pq), glm::dot(u2, pf_pp), glm::dot(u2, pf_pq)) |
||||
|
); |
||||
|
auto mBmn = glm::mat2x2(glm::dot(u1, ps_pu), glm::dot(u1, ps_pv), glm::dot(u2, ps_pu), glm::dot(u2, ps_pv)); |
||||
|
auto tmp = glm::vec2(glm::dot(N, pf_pp), glm::dot(N, pf_pq)); |
||||
|
auto vNfpNfq_inverseAij = glm::vec2(glm::dot(N, pf_pp), glm::dot(N, pf_pq)) * inverseAij; |
||||
|
auto pd_pu = glm::dot(N, ps_pu) - |
||||
|
glm::dot(vNfpNfq_inverseAij, glm::vec2(glm::dot(u1, ps_pu), glm::dot(u2, ps_pu))); |
||||
|
auto pd_pv = glm::dot(N, ps_pv) - |
||||
|
glm::dot(vNfpNfq_inverseAij, glm::vec2(glm::dot(u1, ps_pv), glm::dot(u2, ps_pv))); |
||||
|
vectorFields[i][j] = glm::vec2(pd_pu, pd_pv); |
||||
|
} |
||||
|
} |
||||
|
int a = 1; |
||||
|
int b = 2; |
||||
|
} |
||||
|
|
||||
|
void LoopDetector::getRotationNumber() { |
||||
|
// 以小格子为单位遍历
|
||||
|
for (int i = 0; i < s_subPatchEdgeSampleCnt_u - 1; i++) { |
||||
|
for (int j = 0; j < s_subPatchEdgeSampleCnt_v - 1; j++) { |
||||
|
auto rotationNumber = 0.; |
||||
|
|
||||
|
for (int biasI = 0; biasI < 2; biasI++) { |
||||
|
for (int biasJ = 0; biasJ < 2; biasJ++) { |
||||
|
auto v = vectorFields[i + biasI][j + biasJ]; |
||||
|
rotationNumber += atan(double(v.x / v.y)); |
||||
|
} |
||||
|
} |
||||
|
auto v00 = vectorFields[i][j]; |
||||
|
auto v01 = vectorFields[i][j + 1]; |
||||
|
auto v11 = vectorFields[i + 1][j + 1]; |
||||
|
auto v10 = vectorFields[i + 1][j]; |
||||
|
|
||||
|
rotationNumber = 2 * atan(double(v11.x / v11.y)) - 2 * atan(double(v00.x / v00.y)); |
||||
|
rotationNumber /= (2 * PI); |
||||
|
|
||||
|
rotationNumbers[i][j] = int(round(rotationNumber)); |
||||
|
|
||||
|
printf("rotationNumber: %lf\n", rotationNumber); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
vector<pair<int, int>> LoopDetector::detect(pair<int, int> _s_subPatchIdxRange_u, pair<int, int> _s_subPatchIdxRange_v, |
||||
|
pair<int, int> _f_subPatchIdxRange_u, |
||||
|
pair<int, int> _f_subPatchIdxRange_v) { |
||||
|
s_subPatchIdxRange_u = _s_subPatchIdxRange_u; |
||||
|
s_subPatchIdxRange_v = _s_subPatchIdxRange_v; |
||||
|
f_subPatchIdxRange_u = _f_subPatchIdxRange_u; |
||||
|
f_subPatchIdxRange_v = _f_subPatchIdxRange_v; |
||||
|
|
||||
|
// subPatch每条边上的采样点个数。边上的格子个数=range.second-range.first+1,采样点个数=格子个数+1
|
||||
|
s_subPatchEdgeSampleCnt_u = s_subPatchIdxRange_u.second - s_subPatchIdxRange_u.first + 2; |
||||
|
s_subPatchEdgeSampleCnt_v = s_subPatchIdxRange_v.second - s_subPatchIdxRange_v.first + 2; |
||||
|
f_subPatchEdgeSampleCnt_u = f_subPatchIdxRange_u.second - f_subPatchIdxRange_u.first + 2; |
||||
|
f_subPatchEdgeSampleCnt_v = f_subPatchIdxRange_v.second - f_subPatchIdxRange_v.first + 2; |
||||
|
|
||||
|
initOrientedDistance(); |
||||
|
initVectorField(); |
||||
|
getRotationNumber(); |
||||
|
return {}; |
||||
|
} |
||||
|
|
@ -0,0 +1 @@ |
|||||
|
#include "srf_mesh.h" |
Loading…
Reference in new issue