均值坐标参数化(MVC Parameterization)

news2024/9/24 9:21:32

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

均值坐标定义

均值坐标定义

v 0 是 多 边 形 v 1 v 2 v 3 . . . v n 内 的 一 点 v_0是多边形v_1v_2v_3...v_n内的一点 v0v1v2v3...vn

就 会 存 在 均 值 坐 标 ϕ i ( v 0 ) = ω i ∑ j = 1 n ω j 就会存在均值坐标\phi_i(v_0)=\frac {\omega_i}{\sum_{j=1}^n\omega_j} ϕi(v0)=j=1nωjωi

其 中 ω i = t a n ( α i − 1 2 ) + t a n ( α i 2 ) ∣ ∣ v i − v 0 ∣ ∣ 其中\omega_i=\frac {tan \left(\frac {\alpha_{i-1}}{2} \right)+tan \left(\frac {\alpha_{i}}{2} \right)}{||v_i-v_0||} ωi=viv0tan(2αi1)+tan(2αi)

使得

v 0 = ∑ i = 1 n ϕ i ( v 0 ) ⋅ v i … … ( 1 ) v_0=\displaystyle \sum_{i=1}^n\phi_i(v_0)\cdot v_i ……(1) v0=i=1nϕi(v0)vi1

均值坐标参数化(MVC Parameterization)

该算法与tutte’s embedding 算法的基本过程一样,只是把线性组合的系数换成均值坐标表示。
该算法可以处理与圆盘同胚非闭合的三角网格面,他能保证3D与2D是一一映射的。

算法过程

  1. 先把边界点按照顺序均匀地放置在圆边界上。
  2. 对于内部的点,vi 是周围顶点的均值坐标线性组合。
    v i = ∑ j ∈ Ω ( i ) ϕ j ( v i ) ⋅ v j ( 1 ) , ϕ j ( v i ) 是 顶 均 值 坐 标 表 示 。 v_i = \displaystyle \sum_{j \in \Omega(i)} {\phi_j(v_i)\cdot v_j} (1), \phi_j(v_i)是顶均值坐标表示。 vi=jΩ(i)ϕj(vi)vj1,ϕj(vi)
    n个未知顶点,n个方程刚好解出来。

行列式构建
对 ( 1 ) 式 两 边 都 乘 以 ∑ j ∈ Ω ( i ) ω i j , 再 移 项 , 得 到 对(1)式两边都乘以 \displaystyle \sum_{j\in \Omega(i)}\omega_{ij},再移项, 得到 1jΩ(i)ωij,

( ∑ j ∈ Ω ( i ) ω i j ) v i − ∑ j ∈ Ω ( i ) ω i j ⋅ v j = 0 \left(\displaystyle \sum_{j\in \Omega(i)}\omega_{ij}\right)v_i - \displaystyle \sum_{j \in \Omega(i)} {\omega_{ij}\cdot v_j}= 0 jΩ(i)ωijvijΩ(i)ωijvj=0

利用上式,在具体实现的时候可以先计算出所有wij(没有连接关系则为0),
然后对于边界点,行列式的值r[i][i]=1, b[i]=(ui, vi)
对 于 非 边 界 点 r [ i ] [ i ] = ( ∑ j ∈ Ω ( i ) ω i j ) 对于非边界点r[i][i]=\left(\displaystyle \sum_{j\in \Omega(i)}\omega_{ij}\right) r[i][i]=jΩ(i)ωij

r [ i ] [ j ] = − ω i j , b [ i ] = ( 0 , 0 ) r[i][j]=-\omega_{ij},b[i]=(0,0) r[i][j]=ωijb[i]=(0,0)

算法实现

代码链接点击前往
代码链接点击前往
代码链接点击前往


#include"include/PolyMesh/IOManager.h"
#include"include/PolyMesh/PolyMesh.h"
#include <Eigen/Sparse>
#define pi 3.1415926
using namespace acamcad;
using namespace polymesh;
using namespace std;
using namespace Eigen;

PolyMesh mesh;

void MVCCoordinates(PolyMesh* mesh)
{
	int v_n = mesh->numVertices();
	int iter;
	int boundary_num=0;

	VectorXd u(v_n), v(v_n);// u, v代表方程行列式的B列

	for (VertexIter v_it = mesh->vertices_begin(); v_it != mesh->vertices_end(); ++v_it)
	{
		if (mesh->isBoundary(*v_it))boundary_num++;
	}

	MHalfedge* first_heh= *mesh->halfedge_begin();
	// 查找边界
	for (HalfEdgeIter he_it = mesh->halfedge_begin(); he_it != mesh->halfedge_end(); ++he_it)
	{
		if (mesh->isBoundary(*he_it))
		{
			first_heh = *he_it;
			break;
		}
	}
	MHalfedge* iter_heh = first_heh->next();
	iter = 0;
	// 初始化边界点的uv值
	while (iter_heh != first_heh)
	{
		MVert* from_v = iter_heh->fromVertex();
		u[from_v->index()] = cos(double(2 * pi * iter / boundary_num));
		v[from_v->index()] = sin(double(2 * pi * iter / boundary_num));
		iter_heh = iter_heh->next();
		iter++;
	}
	u[first_heh->fromVertex()->index()] = cos(double(2 * pi * iter / boundary_num));
	v[first_heh->fromVertex()->index()] = sin(double(2 * pi * iter / boundary_num));

	SparseMatrix<double> weight(v_n, v_n);
	std::vector<Triplet<double>> triplet;

	// 针对每个面计算出边的wij. 后面可以聚合到矩阵中。
	for (FaceIter f_it = mesh->polyfaces_begin(); f_it != mesh->polyfaces_end(); ++f_it)
	{
		MHalfedge* heh = (*f_it)->halfEdge();
		MVert* v0 = heh->fromVertex();
		MVert* v1 = heh->toVertex();
		MHalfedge* next_heh = heh->next();
		MVert* v2 = next_heh->toVertex();

		double l2 = (v0->position() - v1->position()).norm();
		double l1 = (v0->position() - v2->position()).norm();
		double l0 = (v1->position() - v2->position()).norm();

		double angle = acos(dot(v2->position() - v0->position(), v1->position() - v0->position()) / (l1 * l2));
		triplet.push_back(Triplet<double>(v0->index(), v1->index(), tan(angle * 0.5) / l2));
		triplet.push_back(Triplet<double>(v0->index(), v2->index(), tan(angle * 0.5) / l1));

		angle = acos(dot(v0->position() - v1->position(), v2->position() - v1->position()) / (l2 * l0));
		triplet.push_back(Triplet<double>(v1->index(), v0->index(), tan(angle * 0.5) / l2));
		triplet.push_back(Triplet<double>(v1->index(), v2->index(), tan(angle * 0.5) / l0));

		angle = acos(dot(v0->position() - v2->position(), v1->position() - v2->position()) / (l0 * l1));
		triplet.push_back(Triplet<double>(v2->index(), v0->index(), tan(angle * 0.5) / l1));
		triplet.push_back(Triplet<double>(v2->index(), v1->index(), tan(angle * 0.5) / l0));
	}
	// 矩阵聚合
	weight.setFromTriplets(triplet.begin(), triplet.end());

	SparseMatrix<double> matrix(v_n, v_n);

	triplet.clear();
	for (VertexIter v_it = mesh->vertices_begin(); v_it != mesh->vertices_end(); ++v_it)
	{
		// 边界处只要设置 matirx[i][i]=1
		if (mesh->isBoundary(*v_it)) {
			triplet.push_back(Triplet<double>((*v_it)->index(), (*v_it)->index(), 1));
			continue;
		}

		// 内部点,设置 B列为0
		u[(*v_it)->index()] = 0;
		v[(*v_it)->index()] = 0;

		// maxtrix[i][i] = sum(wij), maxtrix[i][j] = -wij 
		for (VertexVertexIter vv_it = mesh->vv_iter(*v_it); vv_it.isValid(); ++vv_it)
		{
			triplet.push_back(Triplet<double>((*v_it)->index(), (*vv_it)->index(), -weight.coeff((*v_it)->index(), (*vv_it)->index())));
			triplet.push_back(Triplet<double>((*v_it)->index(), (*v_it)->index(), weight.coeff((*v_it)->index(), (*vv_it)->index())));
		}
	}
	matrix.setFromTriplets(triplet.begin(), triplet.end());
	SparseLU<SparseMatrix<double>> solver;
	solver.analyzePattern(matrix);
	solver.factorize(matrix);
	VectorXd result_u = solver.solve(u);
	VectorXd result_v = solver.solve(v);

	for (VertexIter v_it = mesh->vertices_begin(); v_it != mesh->vertices_end(); ++v_it)
	{
		(*v_it)->setPosition(result_u[(*v_it)->index()], result_v[(*v_it)->index()], 0);
	}
}


算法效果

原模型
在这里插入图片描述
参数化结果
在这里插入图片描述
原模型
在这里插入图片描述

参数化结果
在这里插入图片描述


本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/79031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

腾讯云服务器CVM快速配置购买教程,新手上云必备!

腾讯云服务器快速配置购买教程是新手必备的上云教程。主机教程网在本文中以腾讯云服务器为例&#xff0c;给大家带来一个完整的、手把手教学的服务器购买流程。助力快速完成服务器的购买、配置、以及网站的搭建&#xff0c;给新手节省宝贵的时间&#xff0c;避免采坑&#xff0…

线程相关学习记录(1)

认识线程 什么是线程 进程&#xff1a; 正常电脑中启动的某个程序应用&#xff0c;并且会获得计算机分配的资源&#xff08;cpu&#xff0c;内存&#xff0c;硬件设备&#xff09; 线程&#xff1a; 进程中为了完成某个功能&#xff0c;内部划分出的不同的资源分配单位。通常…

[附源码]Python计算机毕业设计SSM基于框架的旅游管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MyBatis详细学习笔记

一、MyBatis简介 MyBatis是ORM框架&#xff0c;即对象关系映射框架。 二、搭建MyBatis 不同的MySQL版本使用的JDBC不同 com.mysql.jdbc.Driver // MySQL 5 com.mysql.cj.jdbc.Driver // MySQL 8不同版本的MySQL的url也不同 jdbc:mysql://localhost:3306/ssm // MySQL 5 jd…

神仙级Python办公自动化教程(非常详细),从零基础入门到精通,轻松玩转Excel,从看这篇开始

Excel是Office办公中使用非常频繁的一个表格制作、数据分析与图表制作的组件。随着现在数据处理量越来越大&#xff0c;日常办公中很多重复性工作耗费了广大办公人员越来越多的时间&#xff0c;那么如何才能化繁为简&#xff0c;提高办公自动化水平呢&#xff1f;借助Python中的…

【小程序】小程序中插槽使用

&#x1f4ad;&#x1f4ad; ✨&#xff1a;小程序插槽   &#x1f49f;&#xff1a;东非不开森的主页   &#x1f49c;: 没关系 天空越黑星星越亮&#x1f49c;&#x1f49c;   &#x1f338;: 如有错误或不足之处&#xff0c;希望可以指正&#xff0c;非常感谢&#x1f60…

大学生个人网站作业 超简单DIV CSS个人网页成品 简单个人网站作业模板 HTML个人网页设计下载 简约黑白色个人主页

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

Redis大key多key拆分方案

业务场景中经常会有各种大key多key的情况&#xff0c; 比如&#xff1a; 1&#xff1a;单个简单的key存储的value很大 2&#xff1a;hash&#xff0c; set&#xff0c;zset&#xff0c;list 中存储过多的元素&#xff08;以万为单位&#xff09; 3&#xff1a;一个集群存储了…

Java脚本化编程实践整理 ScriptEngineManager万字详解

文章目录认识Java支持脚本语言的意义Java对JavaScript的支持Rhino/Nashorn概述Nashorn的目的实践操作HelloWorld执行脚本文件代码脚本语言使用Java的变量执行脚本方法/函数脚本语言使用Java的类对象脚本语言实现Java的接口脚本的多个作用域脚本语言使用Java的数据类型创建java对…

[附源码]计算机毕业设计基于Web的软考题库平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

CSS固定定位与粘性定位4大企业级案例

前面两篇文章为大家详细讲解了相对定位与绝对定位的应用场景和案例。如果想了解的可以在公众号里面查看去看。本小节我们学习下固定定位与粘性定位的应用场景和案例。 属性值 描述 relative 相对定位 相对于自身正常位置进行位置的调整 absolute 绝对定位 相对于其最近的定…

如何用实时数据分析辅助企业智能决策,这个高效的解决方案了解下?

随着产业互联网的发展&#xff0c;企业数字化能力的边界也在不断拓展&#xff0c;除了对海量数据的获取、处理及应用需求以外&#xff0c;更快地获取实时数据也开始成为大数据时代各行各业的共同目标。 在企业的业务经营中&#xff0c;实时数据是营销、运维、决策的重要支撑&am…

ChatGPT OpenAI 让学习更加高效工作中实现效率翻倍

ChatGPT是一款由OpenAI开发的聊天机器人&#xff0c;它具有出色的自然语言处理能力&#xff0c;能够与人类进行真实的对话。它的核心技术是GPT-3语言模型&#xff0c;能够自动学习语言特征&#xff0c;并进行语义理解、文本生成等任务。ChatGPT具有快速回答和丰富内容的特点&am…

Mac M1使用brew安装nvm

nvm作为node版本管理器&#xff0c;全称node version manager&#xff0c;可以管理安装的node和node-sass版本。在macOS系统上的安装步骤如下&#xff1a; *本机使用的是M1芯片&#xff0c;终端配置文件默认使用.zshrc 1. 安装homebrew /usr/bin/ruby -e "$(curl -fsSL h…

2022_SPIC_FANet

Feature aggregation network for RGBD saliency detection 1. 动机 如何将RGB和Depth充分挖掘和融合仍是一个关键问题。 第一个问题是如何从深度图中充分挖掘几何信息&#xff0c;从而可以可靠地反映场景的空间结构。 第二个问题是如何有效地融合外观信息和几何信息&…

koa项目

一.koa起步 1.项目初始化 执行 npm init -y ,生成 package.json npm init -y2.安装koa 执行命令 npm install koa3.编写基本app 创建 src/main.js //1.导入koa包 const Koa new require("Koa");//2。实例化app对象 const app new Koa();//3.编写中间件 app.…

基于C#+Mysql实现(WinForm)企业的设备管理系统【100010018】

企业的设备管理系统 1 引言 企业的设备管理在企业的生产制造和管理过程之中意义比较重大&#xff0c;明确企业的设备的产权和维护成本对于企业的成本控制和财务管理之中起到了重要的作用。随着市场竞争的加剧&#xff0c;现代企业所处的市场环境发生了深刻的变革&#xff0c;…

JDK19都出来了~是时候梳理清楚JDK的各个版本的特性了【JDK13特性讲解】

JDK各个版本特性讲解-JDK13特性 一、JAVA13概述 2019年9月17日&#xff0c;国际知名的OpenJDK开源社区发布了Java编程语言环境的最新版本OpenJDK13。 Features&#xff1a;总共有5个新的JEP(JDK Enhancement Proposals): http://openjdk.java.net/projects/jdk/13/ Features: …

java基于springboot的人事管理系统-计算机毕业设计

开发环境 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven 项目介绍 在这个计…

m基于GA遗传优化的三维工程施工设施布局算法matlab仿真,显示二维和三维布局优化效果

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 GA把问题的解表示成“染色体”&#xff0c;在算法中也即是以二进制编码的串。并且&#xff0c;在执行遗传算法之前&#xff0c;给出一群“染色体”&#xff0c;也即是假设解。然后&#xff0c;把…