三角網格上高斯曲率和平均曲率
ref:https://www.cnblogs.com/eat-too-much/p/12595574.html
https://computergraphics.stackexchange.com/questions/1718/what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle
同學的CSDN部落格 https://blog.csdn.net/qq_38517015/article/details/105185241
中國科大傅孝明老師的框架:框架下載及配置執行
code
https://github.com/lishaohsuai/digital_geo
/**************************************************
@brief : 輸出弧度制的角度 使用兩個向量
@author : lee
@input : none
@output : none
@time : none
**************************************************/
double MeshAlgorithm::vector3fAngle(vector3d a, vector3d b) {
double cosTheta = a.dot(b) / (a.norm() * b.norm());
#ifndef debug
std::cout << "[DEBUG] theta is " << acos(cosTheta) << std::endl;
std::cout << "[DEBUG] vec a" << a.x << "," << a.y << "," << a.z << std::endl;
std::cout << "[DEBUG] vec b" << b.x << "," << b.y << "," << b.z << std::endl;
#endif
return acos(cosTheta);
}
/**************************************************
@brief : 應用海倫公式計算面積
@author : lee
@input : none
@output : none
@time : none
**************************************************/
double MeshAlgorithm::areaUseThreePoints(Point3d a, Point3d b, Point3d c) {
//應用海倫公式 S=1/4sqrt[(a+b+c)(a+b-c)(a+c-b)(b+c-a)]
double lenA = sqrt(pow(b.x - c.x, 2) + pow(b.y - c.y, 2) + pow(b.z - c.z, 2));// b - c 兩點的座標
double lenB = sqrt(pow(a.x - c.x, 2) + pow(a.y - c.y, 2) + pow(a.z - c.z, 2));// a - c 兩點的座標
double lenC = sqrt(pow(b.x - a.x, 2) + pow(b.y - a.y, 2) + pow(b.z - a.z, 2));// a - b 兩點的座標
double Area = 1.0 / 4.0 * sqrt((lenA + lenB + lenC) * (lenA + lenB - lenC) * (lenA + lenC - lenB) * (lenB + lenC - lenA));
#ifndef debug
std::cout << "[DEBUG] area " << Area << std::endl;
std::cout << "[DEBUG] a" << a.x << " " << a.y << " " << a.z << std::endl;
std::cout << "[DEBUG] b" << b.x << " " << b.y << " " << b.z << std::endl;
std::cout << "[DEBUG] c" << c.x << " " << c.y << " " << c.z << std::endl;
#endif
return Area;
}
/**************************************************
@brief : 計算三角形的面積通過兩個向量
@author : lee
@input : none
@output : none
@time : none
***************************************************/
double MeshAlgorithm::areaUseVector(vector3d a, vector3d b) {
double area = 0.0;
area = (a.crossp(b)).norm() * 0.5f;
return fabs(area) > std::numeric_limits<double>::min() ? area : 1e-8;
}
/**************************************************
@brief : 通過三個點計算其外接圓的圓心的座標
參考 https://www.zhihu.com/question/40422123 李玉昆
@author : lee
@input : none
@output : none
@time : none
**************************************************/
Point3d MeshAlgorithm::calPointCircumcircle(Point3d a, Point3d b, Point3d c) {
double a1, b1, c1, d1;
double a2, b2, c2, d2;
double a3, b3, c3, d3;
double x1 = a.x, y1 = a.y, z1 = a.z;
double x2 = b.x, y2 = b.y, z2 = b.z;
double x3 = c.x, y3 = c.y, z3 = c.z;
a1 = (y1*z2 - y2 * z1 - y1 * z3 + y3 * z1 + y2 * z3 - y3 * z2);
b1 = -(x1*z2 - x2 * z1 - x1 * z3 + x3 * z1 + x2 * z3 - x3 * z2);
c1 = (x1*y2 - x2 * y1 - x1 * y3 + x3 * y1 + x2 * y3 - x3 * y2);
d1 = -(x1*y2*z3 - x1 * y3*z2 - x2 * y1*z3 + x2 * y3*z1 + x3 * y1*z2 - x3 * y2*z1);
a2 = 2 * (x2 - x1);
b2 = 2 * (y2 - y1);
c2 = 2 * (z2 - z1);
d2 = x1 * x1 + y1 * y1 + z1 * z1 - x2 * x2 - y2 * y2 - z2 * z2;
a3 = 2 * (x3 - x1);
b3 = 2 * (y3 - y1);
c3 = 2 * (z3 - z1);
d3 = x1 * x1 + y1 * y1 + z1 * z1 - x3 * x3 - y3 * y3 - z3 * z3;
Point3d rlt;
rlt.x = -(b1*c2*d3 - b1 * c3*d2 - b2 * c1*d3 + b2 * c3*d1 + b3 * c1*d2 - b3 * c2*d1)
/ (a1*b2*c3 - a1 * b3*c2 - a2 * b1*c3 + a2 * b3*c1 + a3 * b1*c2 - a3 * b2*c1);
rlt.y = (a1*c2*d3 - a1 * c3*d2 - a2 * c1*d3 + a2 * c3*d1 + a3 * c1*d2 - a3 * c2*d1)
/ (a1*b2*c3 - a1 * b3*c2 - a2 * b1*c3 + a2 * b3*c1 + a3 * b1*c2 - a3 * b2*c1);
rlt.z = -(a1*b2*d3 - a1 * b3*d2 - a2 * b1*d3 + a2 * b3*d1 + a3 * b1*d2 - a3 * b2*d1)
/ (a1*b2*c3 - a1 * b3*c2 - a2 * b1*c3 + a2 * b3*c1 + a3 * b1*c2 - a3 * b2*c1);
return rlt;
}
/**************************************************
@brief : 根據外接圓的圓心是否要修正,做合理的修正
@author : lee
@input : none
@output : none
@time : none
**************************************************/
Point3d MeshAlgorithm::calPointVoronoiMixed(Point3d a, Point3d b, Point3d c) {
Point3d p = calPointCircumcircle(a, b, c);//計算外接圓的圓心
if (!isInTriangle(a, b, c, p)) {//不在三角形內部的時候 返回bc的中點
return { (b.x + c.x) / 2.0, (b.y + c.y) / 2.0, (b.z + c.z) / 2.0 };
}
return p;
}
/**************************************************
@brief : 判斷兩個向量是否同向
@author : lee
@input : none
@output : none
@time : none
**************************************************/
bool sameSide(Point3d a, Point3d b, Point3d c, Point3d p) {
vector3d AB(b.x - a.x, b.y - a.y, b.z - a.z);
vector3d AC(c.x - a.x, c.y - a.y, c.z - a.z);
vector3d AP(p.x - a.x, p.y - a.y, p.z - a.z);
vector3d v1 = AB.crossp(AC);
vector3d v2 = AB.crossp(AP);
// v1 and v2 should point to the same direction
return v1.dot(v2) >= 0;
}
/**************************************************
@brief : 判斷點是否在三角形內 參考連結 https://www.cnblogs.com/graphics/archive/2010/08/05/1793393.html
@author : lee
@input : none
@output : none
@time : none
**************************************************/
bool MeshAlgorithm::isInTriangle(Point3d a, Point3d b, Point3d c, Point3d p) {
return sameSide(a, b, c, p) &&
sameSide(b, c, a, p) &&
sameSide(c, a, b, p);
}
/**************************************************
@brief : 計算兩個三角形的對標 cotalpha cotbelta
@author : lee
@input : none
@output : none
@time : none
**************************************************/
void MeshAlgorithm::calCotAlphaCotBeta(Point3d p, Point3d a, Point3d b, Point3d c, double &cotAlpha, double &cotBeta) {
vector3d AP(p.x - a.x, p.y - a.y, p.z - a.z);
vector3d AB(b.x - a.x, b.y - a.y, b.z - a.z);
double cosAlpha = cos(vector3fAngle(AP, AB));
cotAlpha = cosAlpha / sqrt(1 - cosAlpha * cosAlpha);
vector3d CP(p.x - c.x, p.y - c.y, p.z - c.z);
vector3d CB(b.x - c.x, b.y - c.y, b.z - c.z);
double cosBeta = cos(vector3fAngle(CP, CB));
cotBeta = cosBeta / sqrt(1 - cosBeta * cosBeta);
}
/**************************************************
@brief : 顏色對映歸一化
@author : 王丹丹
@input : none
@output : none
@time : none
**************************************************/
void ImageAlgorithm::normalize(std::vector<double> & val) {
//找到最大值和最小值,然後對映到[0,1]
double max = -10000.0, min = 10000.0;
int n = val.size();
for (int i = 0; i < n; i++){
if (val[i] > max) max = val[i];
if (val[i] < min) min = val[i];
}
double t = max - min;
//需要討論一下相等的情況
for (int i = 0; i < n; i++){
val[i] = (val[i] - min) / t;
}
}
/**************************************************
@brief : 對映高斯曲率到 r g b 參照libigl中的相關程式碼
@author : 王丹丹
@input : none
@output : none
@time : none
**************************************************/
void ImageAlgorithm::colorMap(double gaussCur, double &r, double &g, double &b)
{
const double rone = 0.8;
const double gone = 1.0;
const double bone = 1.0;
double x = gaussCur;
x = (gaussCur < 0 ? 0 : (x > 1 ? 1 : x));
//可以簡單地理解:紅色的曲率最大,藍色的最小
if (x < 1. / 8.){
r = 0;
g = 0;
b = bone * (0.5 + (x) / (1. / 8.)*0.5);
}
else if (x < 3. / 8.){
r = 0;
g = gone * (x - 1. / 8.) / (3. / 8. - 1. / 8.);
b = bone;
}
else if (x < 5. / 8.){
r = rone * (x - 3. / 8.) / (5. / 8. - 3. / 8.);
g = gone;
b = (bone - (x - 3. / 8.) / (5. / 8. - 3. / 8.));
}
else if (x < 7. / 8.){
r = rone;
g = (gone - (x - 5. / 8.) / (7. / 8. - 5. / 8.));
b = 0;
}
else{
r = (rone - (x - 7. / 8.) / (1. - 7. / 8.)*0.5);
g = 0;
b = 0;
}
}
=======================================另一個檔案========================================================
/**************************************************
@brief : 計算高斯曲率 參考 https://www.cnblogs.com/VVingerfly/p/4428722.html 中的離散公式
@author : lee
@input : none
@output : none
@time : none
**************************************************/
void MeshViewerWidget::GaussianCurvatureProcess(void) {
// 遍歷所有點計算每個點的高斯曲率
//std::ofstream cout("case1.txt");
std::vector<double> gauss;
for (Mesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) {
double value = calGaussianCurvature(v_it);
gauss.push_back(value);
//std::cout << "Gaussian " << value << std::endl;
}
myImageAlgorithm.normalize(gauss);
int k = 0;
for (auto v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it)
{
double r, g, b;
myImageAlgorithm.colorMap(gauss[k++], r, g, b);
mesh.set_color(*v_it, OpenMesh::Vec3uc(int(r * 255), int(g * 255), int(b * 255)));
}
}
/**************************************************
@brief : 計算平均曲率 參考 https://computergraphics.stackexchange.com/questions/1718/
what-is-the-simplest-way-to-compute-principal-curvature-for-a-mesh-triangle
@author : lee
@input : none
@output : none
@time : none
**************************************************/
void MeshViewerWidget::MeanCurvatureProcess(void) {
// 便利所有點計算每個點的平均曲率
for (Mesh::VertexIter v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) {
std::cout << "MeanCurvature " << calMeanCurvature(v_it) << std::endl;
}
}
/**************************************************
@brief : 計算每個點的平均曲率
@author : lee
@input : none
@output : none
@time : none
**************************************************/
double MeshViewerWidget::calMeanCurvature(Mesh::VertexIter vertexIndex) {
OpenMesh::Vec3d P = (mesh).point(*vertexIndex);//中心點座標
Point3d vecPoint(P[0], P[1], P[2]);
std::vector<Point3d> neighborPoints;// N_1 rings points
for (Mesh::VertexOHalfedgeIter vo_it = mesh.voh_begin(*vertexIndex); vo_it != mesh.voh_end(*vertexIndex); ++vo_it) {//這個頂點所帶有的半邊迭代器
OpenMesh::ArrayKernel::VertexHandle to_v = mesh.to_vertex_handle(*vo_it);
OpenMesh::Vec3d toPoint = mesh.point(to_v);// 鄰接點
neighborPoints.push_back({ toPoint[0],toPoint[1],toPoint[2] });
}
// 計算 voronoi 點集
std::vector<Point3d> voronoiPoints;
double angle = 0;
vector3d sumVector(0, 0, 0);
for (int i = 0; i < neighborPoints.size(); i++) {
Point3d voronoiPoint = myMeshAlgorithm.calPointVoronoiMixed(vecPoint, neighborPoints[i], (i == (neighborPoints.size() - 1) ? neighborPoints[0] : neighborPoints[i + 1]));
voronoiPoints.push_back(voronoiPoint);
// 計算∑(cotα + cotβ)(Qi - P)
double cotAlpha;
double cotBeta;
myMeshAlgorithm.calCotAlphaCotBeta(vecPoint, (i == 0 ? neighborPoints[neighborPoints.size() - 1] : neighborPoints[i - 1]), neighborPoints[i],
(i == (neighborPoints.size() - 1) ? neighborPoints[0] : neighborPoints[i + 1]), cotAlpha, cotBeta);
sumVector.x += (cotAlpha + cotBeta)*(neighborPoints[i].x - vecPoint.x);
sumVector.y += (cotAlpha + cotBeta)*(neighborPoints[i].y - vecPoint.y);
sumVector.z += (cotAlpha + cotBeta)*(neighborPoints[i].z - vecPoint.z);
}
// 採用海倫公式計算voronoi三角形的面積和
double sumArea = 0;
for (int i = 0; i < voronoiPoints.size(); i++) {
sumArea += myMeshAlgorithm.areaUseThreePoints(vecPoint, voronoiPoints[i], (i == voronoiPoints.size() - 1) ? voronoiPoints[0] : voronoiPoints[i + 1]);
}
double lengthSumVector = sqrt(sumVector.x * sumVector.x + sumVector.y * sumVector.y + sumVector.z * sumVector.z);
return 0.5f * (1.0 / (sumArea * 2) * lengthSumVector);
}
/**************************************************
@brief : 計算一個點所對應的高斯曲率
@author : lee
@input : none
@output : none
@time : none
**************************************************/
double MeshViewerWidget::calGaussianCurvature(Mesh::VertexIter vertexIndex) {
OpenMesh::Vec3d P = (mesh).point(*vertexIndex);//中心點座標
Point3d vecPoint(P[0], P[1], P[2]);
std::vector<Point3d> neighborPoints;// N_1 rings points
for (Mesh::VertexOHalfedgeIter vo_it = mesh.voh_begin(*vertexIndex); vo_it != mesh.voh_end(*vertexIndex); ++vo_it) {//這個頂點所帶有的半邊迭代器
OpenMesh::ArrayKernel::VertexHandle to_v = mesh.to_vertex_handle(*vo_it);
OpenMesh::Vec3d toPoint = mesh.point(to_v);// 鄰接點
neighborPoints.push_back({ toPoint[0],toPoint[1],toPoint[2] });
}
// 計算 voronoi 點集
std::vector<Point3d> voronoiPoints;
double angle = 0;
for (int i = 0; i < neighborPoints.size(); i++) {
Point3d voronoiPoint = myMeshAlgorithm.calPointVoronoiMixed(vecPoint, neighborPoints[i], (i == (neighborPoints.size() - 1) ? neighborPoints[0] : neighborPoints[i + 1]));
voronoiPoints.push_back(voronoiPoint);
vector3d P1(neighborPoints[i].x - vecPoint.x, neighborPoints[i].y - vecPoint.y, neighborPoints[i].z - vecPoint.z);
Point3d tmp = (i == (neighborPoints.size() - 1) ? neighborPoints[0] : neighborPoints[i + 1]);
vector3d P2(tmp.x - vecPoint.x, tmp.y - vecPoint.y, tmp.z - vecPoint.z);
angle += myMeshAlgorithm.vector3fAngle(P1, P2);
}
// 採用海倫公式計算voronoi三角形的面積和
double sumArea = 0;
for (int i = 0; i < voronoiPoints.size(); i++) {
sumArea += myMeshAlgorithm.areaUseThreePoints(vecPoint, voronoiPoints[i], (i == voronoiPoints.size() - 1) ? voronoiPoints[0] : voronoiPoints[i + 1]);
}
// 計算選中點1鄰域角度的集合
return 1.0 / sumArea * (2 * pi - angle);
}
相關文章
- Group-IB:2019年網路釣魚套件平均價格上漲了149%套件
- 曲率表示軟體
- 實現滑鼠拾取三角網格的方法
- 曲率保持定號的黎曼流形
- 曲面屏顯示器的曲率越大越好嗎?曲面顯示器最佳曲率知識介紹
- 靜態網格體和骨架網格體的區別
- 高等數學:曲線曲率推導
- 以下是一個使用 C++ 和 OpenGL 實現滑鼠拾取三角網格的簡單程式碼示例C++
- ThreeJS Shader的效果樣例網格平面和網格球體(一)JS
- 去哪兒網:2020年五一酒店平均價格也僅為2019年的75%
- SAP MM 移動平均價的商品發票價格和採購訂單價格差異的處理
- 現代化網站品牌和風格網站
- 三角方程和恆等式(反三角函式、正弦方程、角加恆等式、使用三角恆等式)恆等式函式
- 2022年3月G7國家汽油平均價格
- CSS三角形和餅圖CSS
- 三角形最小路徑和
- SpringBoot、Kubernetes和Istio微服務網格演示原始碼Spring Boot微服務原始碼
- 服務網格Istio、Linkerd和Cilium效能比較
- QuestMobile:中國網際網路使用者每天在手機上的娛樂時間平均達到 4.7 小時
- 三角函式之積化和差公式函式公式
- Windows風格的個人網盤,支援文件線上編輯Windows
- Stock Apps:2021年全球每GB資料平均價格為4.07美元APP
- WIFI訊號滿格卻上不了網怎麼辦?WIFI無線訊號滿格不能上網的解決方法WiFi
- 服務網格定義企業上雲新路徑! | Forrester X 螞蟻集團 釋出服務網格白皮書REST
- K重交叉驗證和網格搜尋驗證
- 使用 github 和 Deno Deploy 搭建一個部落格網站Github網站
- 將 Hexo 個人部落格同時部署到 GitHub 和 Coding 上HexoGithub
- 增補部落格 第十八篇 python 楊輝三角形Python
- 萬事達經濟研究所:全球休閒旅行恢復至疫情前水平 平均機票價格上漲了18%
- webgl內建函式--角度和三角函式Web函式
- leetcode 120 三角形最小路徑和LeetCode
- centos7實現上網和管理網路yum源CentOS
- 通過生成內容和CSS網格佈局為空單元格新增樣式CSS
- 部落格網站網站
- 快速切割網格
- 怎麼修改網站模板,輕鬆更換網站外觀和風格網站
- 平均和最壞時間複雜度介紹時間複雜度
- [Leetcode]120.三角形路徑最小和LeetCode