点到三维网格最近点距离

首先需要定义点到三维网格的距离,应该定义为这个点到三维网格的最近顶点之间的距离,因此需要遍历一遍三维网格上点的信息(在这里拓扑信息是没有用的),下面给出两种实现的方法

1.计算距离矩阵求最小值

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

2.调用bsxfun函数

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矩阵,说明两个函数得到的结果是一样的
在此不得不推荐bsxfun函数,下面是运行时间的对比

>> 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.
还是显著比计算矩阵快得多

你可能感兴趣的:(图形学)