Integration of gauss map, osculating toroidal patches, loop detection and C2 judgement to figure out the singular or loop intersection.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

379 lines
15 KiB

#include <iostream>
#include "SingularityJudger.h"
#include "fstream"
#include "QString"
#include "QList"
#include "QRegularExpression"
#include "gauss_map.h"
#include "bvh.h"
#include "utils.h"
#include "unordered_set"
#include "unordered_map"
array2<glm::vec3> getPtsFromStr(QString srfData);
void printCtrPtsAsQuadruples(const RationalSurface<float> &s);
void printCtrPtsAsQuadruples(const Surface<double> &s);
void sampleTimeTest(const RationalSurface<float> &s_, int sampleLevel) {
// 由于ParaSolid那边曲面参数为double类型,这里也要保证是double类型(控制变量)
RationalSurface<double> s;
vector<double> knots_u(s_.knots_u.size());
vector<double> knots_v(s_.knots_v.size());
array2<double> weights(s_.weights.rows(), s_.weights.cols());
array2<glm::vec<3, double>> control_points(s_.control_points.rows(), s_.control_points.cols());
for(int i = 0; i < s_.knots_u.size(); i++) knots_u[i] = (double)s_.knots_u[i];
for(int i = 0; i < s_.knots_v.size(); i++) knots_v[i] = (double)s_.knots_v[i];
for(int i = 0; i < s_.weights.rows(); i++) {
for(int j = 0; j < s_.weights.cols(); j++) {
weights(i, j) = (double)s_.weights(i, j);
}
}
for(int i = 0; i < s_.control_points.rows(); i++) {
for(int j = 0; j < s_.control_points.cols(); j++) {
control_points(i, j).x = (double)s_.control_points(i, j).x;
control_points(i, j).y = (double)s_.control_points(i, j).y;
control_points(i, j).z = (double)s_.control_points(i, j).z;
}
}
s.knots_u = knots_u;
s.knots_v = knots_v;
s.weights = weights;
s.control_points = control_points;
s.degree_u = s_.degree_u;
s.degree_v = s_.degree_v;
auto sampleCnt = int(pow(2, sampleLevel - 1) + 1);
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) / double (sampleCnt - 1);
auto s_step_v = (*(s.knots_v.end() - 1) - s_first_v) / double (sampleCnt - 1);
// 为了分别测试赋值和求梯度的时间,这里把它们分开写了
auto startMomEval = std::chrono::steady_clock::now();
for (int i = 0; i < sampleCnt; i++) {
auto u = s_first_u + s_step_u * float(i);
for (int j = 0; j < sampleCnt; j++) {
auto v = s_first_v + s_step_v * float(j);
auto eval = tinynurbs::surfacePoint(s, u, v);
// printf("(%d, %d) --> (%g, %g, %g)\n", i, j, eval.x, eval.y, eval.z);
}
}
auto endMomEval = std::chrono::steady_clock::now();
printf("time cost of evaluation: %lf ms\n", std::chrono::duration<double, std::milli>(endMomEval - startMomEval).count());
auto startMomDer = std::chrono::steady_clock::now();
for (int i = 0; i < sampleCnt; i++) {
auto u = s_first_u + s_step_u * float(i);
for (int j = 0; j < sampleCnt; j++) {
auto v = s_first_v + s_step_v * float(j);
auto der = tinynurbs::surfaceDerivatives(s, 1, u, v);
// if(der(0, 0) == res.evaluation[i][j]) cout<<"amazing"<<endl;
// else cout<<"what??? ("<<res.evaluation[i][j].x<<" "<<res.evaluation[i][j].y<<" "<<res.evaluation[i][j].z<<") | ("<<der(0, 0).x<<" "<<der(0, 0).y<<" "<<der(0, 0).z<<")"<<endl;
// res.tangent_u[i][j] = der(1, 0);
// res.tangent_v[i][j] = der(0, 1);
}
}
auto endMomDer = std::chrono::steady_clock::now();
printf("time cost of derivatives: %lf ms\n", std::chrono::duration<double, std::milli>(endMomDer - startMomDer).count());
auto startMomScdDer = std::chrono::steady_clock::now();
for (int i = 0; i < sampleCnt; i++) {
auto u = s_first_u + s_step_u * float(i);
for (int j = 0; j < sampleCnt; j++) {
auto v = s_first_v + s_step_v * float(j);
auto der = tinynurbs::surfaceDerivatives(s, 2, u, v);
}
}
auto endMomScdDer = std::chrono::steady_clock::now();
printf("time cost of second derivatives: %lf ms\n", std::chrono::duration<double, std::milli>(endMomScdDer - startMomScdDer).count());
}
void sampleTimeTestNonRational(const RationalSurface<float> &s_, int sampleLevel) {
// 由于ParaSolid那边曲面参数为double类型,这里也要保证是double类型(控制变量)
Surface<double> s;
vector<double> knots_u(s_.knots_u.size());
vector<double> knots_v(s_.knots_v.size());
array2<glm::vec<3, double>> control_points(s_.control_points.rows(), s_.control_points.cols());
for(int i = 0; i < s_.knots_u.size(); i++) knots_u[i] = (double)s_.knots_u[i];
for(int i = 0; i < s_.knots_v.size(); i++) knots_v[i] = (double)s_.knots_v[i];
for(int i = 0; i < s_.control_points.rows(); i++) {
for(int j = 0; j < s_.control_points.cols(); j++) {
control_points(i, j).x = (double)s_.control_points(i, j).x;
control_points(i, j).y = (double)s_.control_points(i, j).y;
control_points(i, j).z = (double)s_.control_points(i, j).z;
}
}
s.knots_u = knots_u;
s.knots_v = knots_v;
s.control_points = control_points;
s.degree_u = s_.degree_u;
s.degree_v = s_.degree_v;
auto sampleCnt = int(pow(2, sampleLevel - 1) + 1);
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) / double (sampleCnt - 1);
auto s_step_v = (*(s.knots_v.end() - 1) - s_first_v) / double (sampleCnt - 1);
// 为了分别测试赋值和求梯度的时间,这里把它们分开写了
printCtrPtsAsQuadruples(s);
auto startMomEval = std::chrono::steady_clock::now();
for (int i = 0; i < sampleCnt; i++) {
auto u = s_first_u + s_step_u * float(i);
for (int j = 0; j < sampleCnt; j++) {
auto v = s_first_v + s_step_v * float(j);
auto eval = tinynurbs::surfacePoint(s, u, v);
// res.evaluation[i][j] = tinynurbs::surfacePoint(s, u, v);
}
}
auto endMomEval = std::chrono::steady_clock::now();
printf("time cost of evaluation: %lf ms\n", std::chrono::duration<double, std::milli>(endMomEval - startMomEval).count());
auto startMomDer = std::chrono::steady_clock::now();
for (int i = 0; i < sampleCnt; i++) {
auto u = s_first_u + s_step_u * float(i);
for (int j = 0; j < sampleCnt; j++) {
auto v = s_first_v + s_step_v * float(j);
auto der = tinynurbs::surfaceDerivatives(s, 1, u, v);
// if(der(0, 0) == res.evaluation[i][j]) cout<<"amazing"<<endl;
// else cout<<"what??? ("<<res.evaluation[i][j].x<<" "<<res.evaluation[i][j].y<<" "<<res.evaluation[i][j].z<<") | ("<<der(0, 0).x<<" "<<der(0, 0).y<<" "<<der(0, 0).z<<")"<<endl;
// res.tangent_u[i][j] = der(1, 0);
// res.tangent_v[i][j] = der(0, 1);
}
}
auto endMomDer = std::chrono::steady_clock::now();
printf("time cost of derivatives: %lf ms\n", std::chrono::duration<double, std::milli>(endMomDer - startMomDer).count());
auto startMomScdDer = std::chrono::steady_clock::now();
for (int i = 0; i < sampleCnt; i++) {
auto u = s_first_u + s_step_u * float(i);
for (int j = 0; j < sampleCnt; j++) {
auto v = s_first_v + s_step_v * float(j);
auto der = tinynurbs::surfaceDerivatives(s, 2, u, v);
}
}
auto endMomScdDer = std::chrono::steady_clock::now();
printf("time cost of second derivatives: %lf ms\n", std::chrono::duration<double, std::milli>(endMomScdDer - startMomScdDer).count());
}
int dirs[4][2] = {{-1, 0},
{0, 1},
{1, 0},
{0, -1}};
void dfs(const map<pair<int, int>, set<pair<int, int>>>& pairMap,
// unordered_map<pair<int, int>, char> &book,
set<pair<int, int>>& book,
// vector<vector<pair<pair<int, int>, pair<int, int>>>> &boxGroups,
vector<vector<pair<int, int>>> &boxGroups,
int x, int y, int iOfGroup) {
// book[{x, y}] = 1;
// book.insert(pair<pair<int, int>, char>(pair<int, int>(x, y), 1));
book.insert({x,y});
boxGroups[iOfGroup].emplace_back(pair<int, int>(x, y));
for (auto dir: dirs) {
auto nx = x + dir[0], ny = y + dir[1];
if (book.find({nx, ny}) != book.end() || pairMap.find({nx, ny}) == pairMap.end())continue;
dfs(pairMap, book, boxGroups, nx, ny, iOfGroup);
}
}
int main() {
RationalSurface<float> s;
RationalSurface<float> f;
int level = 9;
printf("level: %d, sample cnt: %d * %d\n", level, int(pow(2, level - 1)), int(pow(2, level - 1)));
ifstream fin;
fin.open(R"(intersectTest\casea1\surfaces.txt)");
string str;
string tmp;
while (fin.good()) {
getline(fin, tmp);
str += tmp + "\n";
}
// cout << str << endl;
auto infos = QString(str.c_str()).split(";");
auto wData = infos[0];
auto srf1Data = infos[1];
auto srf2Data = infos[2];
auto points1 = getPtsFromStr(srf1Data);
auto points2 = getPtsFromStr(srf2Data);
wData = wData.remove(0, wData.indexOf("Matrix") + 6).trimmed();
wData.remove(0, 3);
wData.remove(wData.size() - 3, 3);
auto wInfos = wData.split(QRegularExpression("\\]( )*,( )*\\["));
array2<float> weights;
vector<float> wArray(points1.cols() * points1.rows());
for (int i = 0; i < points1.cols(); i++) {
auto wsInV = wInfos[i].split(QRegularExpression("( )*,( )*"));
for (int j = 0; j < points1.rows(); j++) {
wArray[i * points1.rows() + j] = wsInV[j].toFloat();
}
}
weights = {points1.cols(), points2.rows(), wArray};
// knot
std::vector<float> knot_u(2 * points1.cols(), 1.);
for (int i = 0; i < knot_u.size() / 2; i++)knot_u[i] = 0;
std::vector<float> knot_v(2 * points1.rows(), 1.);
for (int i = 0; i < knot_v.size() / 2; i++)knot_v[i] = 0;
s.degree_u = knot_u.size() / 2 - 1;
s.degree_v = knot_v.size() / 2 - 1;
s.knots_u = knot_u;
s.knots_v = knot_v;
s.control_points = points1;
s.weights = weights;
f.degree_u = knot_u.size() / 2 - 1;
f.degree_v = knot_v.size() / 2 - 1;
f.knots_u = knot_u;
f.knots_v = knot_v;
f.control_points = points2;
f.weights = weights;
fin.close();
printCtrPtsAsQuadruples(f);
// ====================== 测试 =======================
vector<vector<glm::vec3>> s_evaluation;
vector<vector<glm::vec3>> f_evaluation;
// 曲面s和f的切向量。zd*-sznmj
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;
// sampleTimeTestNonRational(s, level);
sampleTimeTest(s, level);
auto mesh1 = SrfMesh(s, level);
auto mesh2 = SrfMesh(f, level);
BVH bvh1(mesh1.evaluation);
BVH bvh2(mesh2.evaluation);
bvh1.build();
bvh2.build();
auto intersectBoxPairs = getOverlapLeafNodes(bvh1, bvh2); // [{{u1, v1}, {u2, v2}}]
printf("box pairs size: %lld\n", intersectBoxPairs.size());
/**
* 测试对bvh结果用dfs
*/
// double timeClassify = utils::get_time();
// map<pair<int, int>, set<pair<int, int>>> pairMap;
// for (const auto &boxPair: intersectBoxPairs) {
// pairMap[boxPair.first].insert(boxPair.second);
// }
//// vector<vector<pair<pair<int, int>, pair<int, int>>>> groups;
// vector<vector<pair<int, int>>> groups;
//// unordered_map<pair<int, int>, char> book;
// set<pair<int, int>>book;
// int groupNum = 0;
// for(auto boxPair: intersectBoxPairs) {
// if(book.find(boxPair.first) != book.end())continue;
// groups.emplace_back();
// dfs(pairMap, book, groups, boxPair.first.first, boxPair.first.second, groupNum++);
// }
// timeClassify = utils::get_time() - timeClassify;
// printf("time cost to group boxes from BVH: %lf\n", timeClassify);
/**
* end of test
*/
double time_cost = utils::get_time();
SingularityJudger singularityJudger(s, f, mesh1, mesh2);
pair<int, int> cellIdxFullRange = {0, pow(2, level - 1) - 1};
auto cellsWithCriticalPts = singularityJudger.judge(intersectBoxPairs, cellIdxFullRange, cellIdxFullRange, cellIdxFullRange, cellIdxFullRange);
time_cost = utils::get_time() - time_cost;
printf("time cost of singularityJudger: %lf\n", time_cost);
// ================== 测试对整个曲面,gauss能排除多少(或保留多少)==================
// GaussMap gaussMap1(mesh1.normal);
// GaussMap gaussMap2(mesh2.normal);
// gaussMap1.build();
// gaussMap2.build();
// auto pairs = getOverlapLeafNodes(gaussMap1, gaussMap2);
// printf("Gauss Map: keep %lld samples in totally %lld boxes\n", pairs.size(),
// mesh1.normal.size() * mesh1.normal[0].size() * mesh2.normal.size() * mesh2.normal[0].size());
return 0;
}
array2<glm::vec3> getPtsFromStr(QString srfData) {
srfData = srfData.remove(0, srfData.indexOf("Matrix") + 6).trimmed();
// 去掉首尾的括号
srfData.remove(0, 1);
srfData.remove(srfData.size() - 1, 1);
auto srfInfos = srfData.split("{");
auto srfDimInfos = srfInfos[0].split(QRegularExpression(",( )*"));
auto dimU = srfDimInfos[0].toInt();
auto dimV = srfDimInfos[1].toInt();
auto srfPtInfo = srfInfos[1].remove(srfInfos[1].indexOf("}"), 1);
auto srfPtsInfos = srfPtInfo.split(QRegularExpression(",( )*\\("));
std::vector<glm::vec3> points(dimU * dimV, glm::vec3());
for (int i = 0; i < srfPtsInfos.size(); i++) {
auto pt = srfPtsInfos[i].split("=")[1].trimmed();
// 去掉首尾的方括号
pt.remove(0, 1);
pt.remove(pt.size() - 1, 1);
// int iu = i / dimU;
// int iv = i % dimU;
auto coords = pt.split(QRegularExpression(",( )*"));
for (int k = 0; k < 3; k++) {
float num;
if (coords[k].contains("/")) {
auto nums = coords[k].split("/");
num = nums[0].trimmed().toFloat() / nums[1].trimmed().toFloat();
} else {
num = coords[k].toFloat();
}
if (k == 0) points[i].x = num;
else if (k == 1) points[i].y = num;
else points[i].z = num;
}
}
array2<glm::vec3> res = {(size_t) dimU, (size_t) dimV, points};
return res;
}
void printCtrPtsAsQuadruples(const RationalSurface<float> &s) {
cout<<endl;
for(int i = 0; i < s.control_points.rows(); i++) {
for(int j = 0; j < s.control_points.cols(); j++) {
auto pt = s.control_points(i, j);
auto w = s.weights(i, j);
cout<<pt.x * w<<", "<<pt.y * w<<", "<<pt.z * w<<", "<<s.weights(i, j)<<", "<<endl;
}
}
cout<<s.control_points.rows() * s.control_points.cols() * 4 << endl;
}
void printCtrPtsAsQuadruples(const Surface<double> &s) {
cout<<endl;
for(int i = 0; i < s.control_points.rows(); i++) {
for(int j = 0; j < s.control_points.cols(); j++) {
auto pt = s.control_points(i, j);
cout<<pt.x<<", "<<pt.y<<", "<<pt.z<<", "<<endl;
}
}
cout<<s.control_points.rows() * s.control_points.cols() * 4 << endl;
}