从三角剖分构建连通图
Building a connected graph from a triangulation
TL;DR: 我有一堆四面体,我想知道它的 4 个(或更少)相邻(面共享)四面体,我通过检查他们共享的 3D 点。这很慢。
我正在通过三角剖分构建连通图。该图的结构为 [1]:
Graph.element.nodeId
.neighbours
.nodes.positions
三角测量的输出有 2 个矩阵,TRI
和 points
,第一个是 Ntri x 4
数组,每一行都有每个四面体的节点 ID,而第二个是点 Npoint x 3
大小的列表。
我目前正在按照下面的代码构建图形,但是对于任何大小合适的网格来说它都慢得离谱。几乎所有时间的单行是 find
行(在代码中标记),找到当前元素的邻居的部分。
当前算法为每个四面体获取其所有节点,然后找到也包含这些相同节点的所有其他四面体。然后过滤掉所有不包含3个与当前四面体相同节点的四面体,只留下当前四面体的邻居。
function graph=trimesh2graph(TRI,points)
nD=size(points,2);
% preallocate.
graph.elements(size(TRI,1)).neighbours=[];
% For each element, find its node Ids and neighbouring elements
for ii=1:size(TRI,1)
nodeids=TRI(ii,:);
elem=[];
for jj=1:(nD+1)
[iind,~]=find(nodeids(jj)==TRI); % this is 80% of the time
elem=[elem; iind];
end
u = unique(elem);
% of all elements that have shared nodes with the current element,
% get only the ones that have 3 shared nodes.
graph.elements(ii).neighbours = int32((u(histc(elem,u)==nD)));
% some other code
end
% some other code
运行 这个带有演示数据的脚本:
x = gallery('uniformdata',[30 1],0);
y = gallery('uniformdata',[30 1],1);
z = gallery('uniformdata',[30 1],2);
vertices=[x,y,z];
TRI= delaunay(x,y,z)
trimesh2graph(TRI,vertices);
如何提高这段代码的性能?我预计它将需要一种不同的方法,而不仅仅是更快的命令。我看了一点 voronoi 图,但似乎发现 (find
) 无论如何都需要完成。
注意:我不一定需要MATLAB代码,如果你知道解决问题的算法请回答,我会在MATLAB中编码。
[1] 是的,最好将此信息存储在一维数组中。我稍后会,但现在使用当前结构更容易理解。
啊,当然有一个内置的
如果使用 delaunay()
而不是带有自己的 class 的较新版本,只需执行
neighbors(triangulation(TRI,points))
为了得到邻居。边界元素将有 NaN 来填充矩阵。
TL;DR: 我有一堆四面体,我想知道它的 4 个(或更少)相邻(面共享)四面体,我通过检查他们共享的 3D 点。这很慢。
我正在通过三角剖分构建连通图。该图的结构为 [1]:
Graph.element.nodeId
.neighbours
.nodes.positions
三角测量的输出有 2 个矩阵,TRI
和 points
,第一个是 Ntri x 4
数组,每一行都有每个四面体的节点 ID,而第二个是点 Npoint x 3
大小的列表。
我目前正在按照下面的代码构建图形,但是对于任何大小合适的网格来说它都慢得离谱。几乎所有时间的单行是 find
行(在代码中标记),找到当前元素的邻居的部分。
当前算法为每个四面体获取其所有节点,然后找到也包含这些相同节点的所有其他四面体。然后过滤掉所有不包含3个与当前四面体相同节点的四面体,只留下当前四面体的邻居。
function graph=trimesh2graph(TRI,points)
nD=size(points,2);
% preallocate.
graph.elements(size(TRI,1)).neighbours=[];
% For each element, find its node Ids and neighbouring elements
for ii=1:size(TRI,1)
nodeids=TRI(ii,:);
elem=[];
for jj=1:(nD+1)
[iind,~]=find(nodeids(jj)==TRI); % this is 80% of the time
elem=[elem; iind];
end
u = unique(elem);
% of all elements that have shared nodes with the current element,
% get only the ones that have 3 shared nodes.
graph.elements(ii).neighbours = int32((u(histc(elem,u)==nD)));
% some other code
end
% some other code
运行 这个带有演示数据的脚本:
x = gallery('uniformdata',[30 1],0);
y = gallery('uniformdata',[30 1],1);
z = gallery('uniformdata',[30 1],2);
vertices=[x,y,z];
TRI= delaunay(x,y,z)
trimesh2graph(TRI,vertices);
如何提高这段代码的性能?我预计它将需要一种不同的方法,而不仅仅是更快的命令。我看了一点 voronoi 图,但似乎发现 (find
) 无论如何都需要完成。
注意:我不一定需要MATLAB代码,如果你知道解决问题的算法请回答,我会在MATLAB中编码。
[1] 是的,最好将此信息存储在一维数组中。我稍后会,但现在使用当前结构更容易理解。
啊,当然有一个内置的
如果使用 delaunay()
而不是带有自己的 class 的较新版本,只需执行
neighbors(triangulation(TRI,points))
为了得到邻居。边界元素将有 NaN 来填充矩阵。