首先需要定义点到三维网格的距离,应该定义为这个点到三维网格的最近顶点之间的距离,因此需要遍历一遍三维网格上点的信息(在这里拓扑信息是没有用的),下面给出两种实现的方法
function [error2,surface_points] = compute_error_vertex( V1,V2 )
%COMPUTE_ERROR Summary of this function goes here
% Detailed explanation goes here
Vsize1=size(V1,1);
Vsize2=size(V2,1);
surface_points = NaN(Vsize2,3);
errorMatrix=zeros(Vsize1,Vsize2);
for i=1:Vsize1
for j=1:Vsize2
errorMatrix(i,j)=sqrt(sum((V1(i,:)-V2(j,:)).^2,2));
end
end
error2=zeros(Vsize2,1);
for i=1:Vsize2
[error2(i),I]=min(errorMatrix(:,i));
surface_points(i,:)=V1(I,:);
end
end
function [ distances, surface_points] = point2mesh_vertices( vertices,qPoints)
if isempty(qPoints)
distances = [];
surface_points = [];
return
end
%% Distance Calculation
nQPoints = size(qPoints,1);
D = NaN(nQPoints,1);
P = NaN(nQPoints,3);
for r = 1:nQPoints
% Determine the surface points
point = qPoints(r,:); % (1 x 3) query point
[d,p] = distance_to_vertices(vertices,point);
D(r) = d;
P(r,:) = p;
end
% return output arguments
distances = D; % (#qPoints x 1)
surface_points = P; % (#qPoints x 3)
end
function [D,P] = distance_to_vertices(vertices,qPoint)
% find nearest vertex
[D,nearestVertexID] = min(sum(bsxfun(@minus,vertices,qPoint).^2,2),[],1);
D = sqrt(D);
P = vertices(nearestVertexID,:); % (1 x 3)
end
其中前面一个输入参数是网格中点的信息,第二个是散点的信息
下面拿两个扳手的模型做一个例子
obj1='rockerarm_1000.obj';
obj2='rockerarm_wm.obj';
[V1,F1]=obj__read(obj1);V1=V1';F1=F1';
[V2,F2]=obj__read(obj2);V2=V2';F2=F2';
points=V2;
faces=F1;vertices=V1;qPoints=V2;
[ distances, surface_points] = point2mesh_vertices( vertices,qPoints);
[error2,surface_points1] = compute_error_vertex( V1,V2 );
%distances=abs(distances);
xxx=distances-error2;
xxxx=surface_points-surface_points1;
得到xxx和xxxx均为全0矩阵,说明两个函数得到的结果是一样的
>> tic;[ distances, surface_points] = point2mesh_vertices( vertices,qPoints);toc;
Elapsed time is 0.170430 seconds.
>> tic;[error2,surface_points1] = compute_error_vertex( V1,V2 );toc
Elapsed time is 9.817536 seconds.
如果加入面信息,则可以给距离加一个符号(判断散点在最近点处,是在最近点处面的里(1)还是外(-1)),计算方法是首先找到对应点周围一圈面,分别计算两点两线与面的法向之间的内积,内积越大表示连线与面的二面角越大,最大二面角是锐角表示在里面,是钝角表示在外面
function [ distances, surface_points] = point2mesh_vertices( faces,vertices,qPoints)
assert(~isempty(faces) && ~isempty(vertices), 'Invalid argument: ''Faces'' and ''Vertices'' mustn''t be empty.')
assert(max(faces(:))<=size(vertices,1), 'The value of ''Faces'' is invalid: the maximum vertex ID is bigger than the number of vertices in ''Vertices''')
% Calculate normals
r1 = vertices(faces(:,1),:); % (#faces x 3) % 1st vertex of every face
r2 = vertices(faces(:,2),:); % (#faces x 3) % 2nd vertex of every face
r3 = vertices(faces(:,3),:); % (#faces x 3) % 3rd vertex of every face
normals = cross((r2-r1),(r3-r1),2); % (#faces x 3) normal vector of every face
normals = bsxfun(@rdivide,normals,sqrt(sum(normals.^2,2))); % (#faces x 3) normalized normal vector of every face
if isempty(qPoints)
distances = [];
surface_points = [];
return
end
%% Distance Calculation
nQPoints = size(qPoints,1);
D = NaN(nQPoints,1);
P = NaN(nQPoints,3);
%case {'linear','normal'}
for r = 1:nQPoints
% Determine the surface points
point = qPoints(r,:); % (1 x 3) query point
[d,p] = processPoint(faces,vertices,point,normals,@distance_to_vertices);
D(r) = d;
P(r,:) = p;
end
% return output arguments
distances = D; % (#qPoints x 1)
surface_points = P; % (#qPoints x 3)
end
%% Non-vectorized Distance Functions
% (can process only one point)
function [D,P,F] = processPoint(faces,vertices,point,normals,distance_to_vertices)
d = NaN(1,1); % (distanceTypes x 1)
p = NaN(1,3); % (distanceTypes x xyz)
f = NaN(1,1); % (distanceTypes x 1)
% find nearest vertice
[d(1),p(1,:)] = distance_to_vertices(faces,vertices,point,normals);
% find nearest point on all edges
% find minimum distance type
[~,I] = min(abs(d),[],1);
D = d(I);
P = p(I,:);
F = f(I);
end
function [D,P] = distance_to_vertices(faces,vertices,qPoint,normals)
% find nearest vertex
[D,nearestVertexID] = min(sum(bsxfun(@minus,vertices,qPoint).^2,2),[],1);
D = sqrt(D);
P = vertices(nearestVertexID,:); % (1 x 3)
% find faces that belong to the vertex
connectedFaces = find(any(faces==nearestVertexID,2)); % (#connectedFaces x 1) face indices
assert(length(connectedFaces)>=1,'Vertex %u is not connected to any face.',nearestVertexID)
n = normals(connectedFaces,:); % (#connectedFaces x 3) normal vectors
% scalar product between distance vector and normal vectors
coefficients = dot2(n,qPoint-P);
sgn = signOfLargest(coefficients);
D = D*sgn;
end
function sgn = signOfLargest(coeff)
[~,I] = max(abs(coeff));
sgn = sign(coeff(I));
if sgn==0, sgn=1; end
end
function d = dot2(A,B)
% dot product along 2nd dimension with singleton extension
d = sum(bsxfun(@times,A,B),2);
end
运行之后得到的distance带符号~
运行时间
Elapsed time is 0.625030 seconds.
还是显著比计算矩阵快得多