Home > matGeom > meshes3d > distancePointMesh.m

distancePointMesh

PURPOSE ^

DISTANCEPOINTMESH Shortest distance between a (3D) point and a triangle mesh.

SYNOPSIS ^

function [dist, proj] = distancePointMesh(point, vertices, faces, varargin)

DESCRIPTION ^

DISTANCEPOINTMESH  Shortest distance between a (3D) point and a triangle mesh.

   DIST = distancePointMesh(POINT, VERTICES, FACES)
   Returns the shortest distance between the query point POINT and the
   triangular mesh defined by the set of vertex coordinates VERTICES and
   the set of faces FACES. VERTICES is a NV-by-3 array, and FACES is a
   NF-by-3 array of vertex indices.
   If FACES is NF-by-4 array, it is converted to a (NF*2)-by-3 array.

   [DIST, PROJ] = distancePointMesh(...)
   Also returns the projection of the query point on the triangular mesh.

   ... = distancePointMesh(..., 'algorithm', ALGO)
   Allows to choose the type of algorithm. Options are:
   * sequential:   process each face sequentially, using the function
               distancePointTriangle3d 
   * vectorized:   vectorized algorithm, usually faster for large number
               of faces
   * auto:         (default) automatically choose the most appropriate
               between sequential and vectorized.

   Example
     [V, F] = torusMesh();
     F2 = triangulateFaces(F);
     P = [10 20 30];
     [D, PROJ] = distancePointMesh(P, V, F2);
     figure; drawMesh(V, F)
     view(3); axis equal; lighting gouraud; light;
     drawPoint3d(P);
     drawPoint3d(PROJ, 'm*');
     drawEdge3d([P PROJ], 'linewidth', 2, 'color', 'b');

   See also
     distancePointTriangle3d

   References
   * "Distance Between Point and Triangle in 3D", David Eberly (1999)
   https://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
   * <a href="matlab:
     web('https://fr.mathworks.com/matlabcentral/fileexchange/22857-distance-between-a-point-and-a-triangle-in-3d')
   ">Distance between a point and a triangle in 3d</a>, by Gwendolyn Fischer.
   * <a href="matlab:
     web('https://fr.mathworks.com/matlabcentral/fileexchange/52882-point2trimesh------distance%C2%A0between-point-and-triangulated-surface')
   ">Distance Between Point and Triangulated Surface</a>, by Daniel Frisch.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [dist, proj] = distancePointMesh(point, vertices, faces, varargin)
0002 %DISTANCEPOINTMESH  Shortest distance between a (3D) point and a triangle mesh.
0003 %
0004 %   DIST = distancePointMesh(POINT, VERTICES, FACES)
0005 %   Returns the shortest distance between the query point POINT and the
0006 %   triangular mesh defined by the set of vertex coordinates VERTICES and
0007 %   the set of faces FACES. VERTICES is a NV-by-3 array, and FACES is a
0008 %   NF-by-3 array of vertex indices.
0009 %   If FACES is NF-by-4 array, it is converted to a (NF*2)-by-3 array.
0010 %
0011 %   [DIST, PROJ] = distancePointMesh(...)
0012 %   Also returns the projection of the query point on the triangular mesh.
0013 %
0014 %   ... = distancePointMesh(..., 'algorithm', ALGO)
0015 %   Allows to choose the type of algorithm. Options are:
0016 %   * sequential:   process each face sequentially, using the function
0017 %               distancePointTriangle3d
0018 %   * vectorized:   vectorized algorithm, usually faster for large number
0019 %               of faces
0020 %   * auto:         (default) automatically choose the most appropriate
0021 %               between sequential and vectorized.
0022 %
0023 %   Example
0024 %     [V, F] = torusMesh();
0025 %     F2 = triangulateFaces(F);
0026 %     P = [10 20 30];
0027 %     [D, PROJ] = distancePointMesh(P, V, F2);
0028 %     figure; drawMesh(V, F)
0029 %     view(3); axis equal; lighting gouraud; light;
0030 %     drawPoint3d(P);
0031 %     drawPoint3d(PROJ, 'm*');
0032 %     drawEdge3d([P PROJ], 'linewidth', 2, 'color', 'b');
0033 %
0034 %   See also
0035 %     distancePointTriangle3d
0036 %
0037 %   References
0038 %   * "Distance Between Point and Triangle in 3D", David Eberly (1999)
0039 %   https://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
0040 %   * <a href="matlab:
0041 %     web('https://fr.mathworks.com/matlabcentral/fileexchange/22857-distance-between-a-point-and-a-triangle-in-3d')
0042 %   ">Distance between a point and a triangle in 3d</a>, by Gwendolyn Fischer.
0043 %   * <a href="matlab:
0044 %     web('https://fr.mathworks.com/matlabcentral/fileexchange/52882-point2trimesh------distance%C2%A0between-point-and-triangulated-surface')
0045 %   ">Distance Between Point and Triangulated Surface</a>, by Daniel Frisch.
0046  
0047 % ------
0048 % Author: David Legland
0049 % e-mail: david.legland@inra.fr
0050 % Created: 2018-03-08,    using Matlab 9.3.0.713579 (R2017b)
0051 % Copyright 2018 INRA - Cepia Software Platform.
0052 
0053 
0054 %% Parses input arguments
0055 
0056 % check the case of mesh given as structure
0057 if isstruct(vertices)
0058     faces = vertices.faces;
0059     vertices = vertices.vertices;
0060 end
0061 
0062 % default option
0063 algo = 'auto';
0064 
0065 % check optional arguments
0066 while length(varargin) > 1
0067     varName = varargin{1};
0068     if ~ischar(varName)
0069         error('Require options as parameter name-value pairs');
0070     end
0071     
0072     if strcmpi(varName, 'algorithm')
0073         algo = varargin{2};
0074     else
0075         error(['Unknown option name: ' varName]);
0076     end
0077     
0078     varargin(1:2) = [];
0079 end
0080 
0081 % number of faces
0082 nFaces = size(faces, 1);
0083 
0084 if size(faces, 2) > 3 || iscell(faces)
0085     faces = triangulateFaces(faces);
0086 end
0087 
0088 % If algorithm is chosen automatically, choose depending on face number
0089 if strcmpi(algo, 'auto')
0090     if size(faces, 1) > 30
0091         algo = 'vectorized';
0092     else
0093         algo = 'sequential';
0094     end
0095 end
0096 
0097 % switch to vectorized algorithm if necessary
0098 if strcmpi(algo, 'vectorized')
0099     if nargout > 1
0100         [dist, proj] = distancePointTrimesh_vectorized(point, vertices, faces);
0101     else
0102         dist = distancePointTrimesh_vectorized(point, vertices, faces);
0103     end
0104     return;
0105 end
0106 
0107 
0108 %% Sequential algorithm
0109 % For each point, iterates over the triangular faces
0110 
0111 % allocate memory for result
0112 nPoints = size(point, 1);
0113 dist = zeros(nPoints, 1);
0114 
0115 if nargout > 1
0116     projPoints = zeros(nPoints, 3);
0117 end
0118 
0119 % iterate over points
0120 for i = 1:nPoints
0121     % % min distance and projection for current point
0122     minDist = inf;
0123     proj = [0 0 0];
0124     
0125     % iterate over faces
0126     for iFace = 1:nFaces
0127         % create triange for current face
0128         face = faces(iFace, :);
0129         triangle = vertices(face, :);
0130         
0131         [distf, projf] = distancePointTriangle3d(point(i,:), triangle);
0132         
0133         if distf < minDist
0134             minDist = distf;
0135             proj = projf;
0136         end
0137     end
0138     
0139     dist(i) = minDist;
0140     if nargout > 1
0141         projPoints(i,:) = proj;
0142     end
0143 end
0144 end
0145 
0146 function [dist, proj] = distancePointTrimesh_vectorized(point, vertices, faces)
0147 %DISTANCEPOINTTRIMESH Vectorized version of the distancePointTrimesh function
0148 %
0149 %   output = distancePointTrimesh_vectorized(input)
0150 %
0151 %   This version is  vectorized over faces: for each query point, the
0152 %   minimum distance to each triangular face is computed in parallel.
0153 %   Then the minimum distance over faces is kept.
0154 %
0155 %   Example
0156 %   distancePointTrimesh
0157 %
0158 %   See also
0159 %
0160 
0161 % ------
0162 % Author: David Legland
0163 % e-mail: david.legland@inra.fr
0164 % Created: 2018-03-08,    using Matlab 9.3.0.713579 (R2017b)
0165 % Copyright 2018 INRA - Cepia Software Platform.
0166 
0167 % Regions are not numbered as in the original paper of D. Eberly to allow
0168 % automated computation of regions from the 3 conditions on lines.
0169 % Region indices are computed as follow:
0170 %   IND = b2 * 2^2 + b1 * 2 + b0
0171 % with:
0172 %   b0 = 1 if s < 0, 0 otherwise
0173 %   b1 = 1 if t < 0, 0 otherwise
0174 %   b2 = 1 if s+t > 1, 0 otherwise
0175 % resulting ion the following region indices:
0176 %        /\ t
0177 %        |
0178 %   \ R5 |
0179 %    \   |
0180 %     \  |
0181 %      \ |
0182 %       \| P3
0183 %        *
0184 %        |\
0185 %        | \
0186 %   R1   |  \   R4
0187 %        |   \
0188 %        | R0 \
0189 %        |     \
0190 %        | P1   \ P2
0191 %  ------*-------*------> s
0192 %        |        \
0193 %   R3   |   R2    \   R6
0194 
0195 % allocate memory for result
0196 nPoints = size(point, 1);
0197 dist = zeros(nPoints, 1);
0198 proj = zeros(nPoints, 3);
0199 
0200 % triangle origins and direction vectors
0201 p1  = vertices(faces(:,1),:);
0202 v12 = vertices(faces(:,2),:) - p1;
0203 v13 = vertices(faces(:,3),:) - p1;
0204 
0205 % identify coefficients of second order equation that do not depend on
0206 % query point
0207 a = dot(v12, v12, 2);
0208 b = dot(v12, v13, 2);
0209 c = dot(v13, v13, 2);
0210 
0211 % iterate on query points
0212 for i = 1:nPoints
0213     % coefficients of second order equation that depend on query point
0214     diffP = bsxfun(@minus, p1, point(i, :));
0215     d = dot(v12, diffP, 2);
0216     e = dot(v13, diffP, 2);
0217     
0218     % compute position of projected point in the plane of the triangle
0219     det = a .* c - b .* b;
0220     s   = b .* e - c .* d;
0221     t   = b .* d - a .* e;
0222     
0223     % compute region index (one for each face)
0224     regIndex = (s < 0) + 2 * (t < 0) + 4 * (s + t > det);
0225     
0226     % for each region, process all faces whose projection fall within it
0227     
0228     % region 0
0229     % the minimum distance occurs inside the triangle
0230     inds = regIndex == 0;
0231     s(inds) = s(inds) ./ det(inds);
0232     t(inds) = t(inds) ./ det(inds);
0233     
0234 
0235     % region 1 (formerly region 3)
0236     % The minimum distance must occur on the line s = 0
0237     inds = find(regIndex == 1);
0238     s(inds) = 0;
0239     t(inds(e(inds) >= 0)) = 0;
0240     
0241     inds2 = inds(e(inds) < 0);
0242     bool3 = c(inds2) <= -e(inds2);
0243     t(inds2(bool3)) = 1;
0244     inds3 = inds2(~bool3);
0245     t(inds3) = -e(inds3) ./ c(inds3);
0246     
0247     
0248     % region 2 (formerly region 5)
0249     % The minimum distance must occur on the line t = 0
0250     inds = find(regIndex == 2);
0251     t(inds) = 0;
0252     s(inds(d(inds) >= 0)) = 0;
0253 
0254     inds2 = inds(d(inds) < 0);
0255     bool3 = a(inds2) <= -d(inds2);
0256     s(inds2(bool3)) = 1;
0257     inds3 = inds2(~bool3);
0258     s(inds3) = -d(inds3) ./ a(inds3);
0259 
0260 
0261     % region 3 (formerly region 4)
0262     % The minimum distance must occur
0263     % * on the line t = 0
0264     % * on the line s = 0 with t >= 0
0265     % * at the intersection of the two lines
0266     inds = find(regIndex == 3);
0267     
0268     inds2 = inds(d(inds) < 0);
0269     % minimum on edge t = 0 with s > 0.
0270     t(inds2) = 0;
0271     bool3 = a(inds2) <= -d(inds2);
0272     s(inds2(bool3)) = 1;
0273     inds3 = inds2(~bool3);
0274     s(inds3) = -d(inds3) ./ a(inds3);
0275       
0276     inds2 = inds(d(inds) >= 0);
0277     % minimum on edge s = 0
0278     s(inds2) = 0;
0279     bool3 = e(inds2) >= 0;
0280     t(inds2(bool3)) = 0;
0281     bool3 = e(inds2) < 0 & c(inds2) <= e(inds2);
0282     t(inds2(bool3)) = 1;
0283     bool3 = e(inds2) < 0 & c(inds2) > e(inds2);
0284     inds3 = inds2(bool3);
0285     t(inds3) = -e(inds3) ./ c(inds3);
0286     
0287 
0288     % region 4 (formerly region 1)
0289     % The minimum distance must occur on the line s + t = 1
0290     inds = find(regIndex == 4);
0291     numer = (c(inds) + e(inds)) - (b(inds) + d(inds));
0292     s(inds(numer <= 0)) = 0;
0293     inds2 = inds(numer > 0);
0294     numer = numer(numer > 0);
0295     denom = a(inds2) - 2 * b(inds2) + c(inds2);
0296     s(inds2(numer > denom)) = 1;
0297     bool3 = numer <= denom;
0298     s(inds2(bool3)) = numer(bool3) ./ denom(bool3);
0299     t(inds) = 1 - s(inds);
0300 
0301 
0302     % Region 5 (formerly region 2)
0303     % The minimum distance must occur:
0304     % * on the line s + t = 1
0305     % * on the line s = 0 with t <= 1
0306     % * or at the intersection of the two (s=0; t=1)
0307     inds = find(regIndex == 5);
0308     tmp0 = b(inds) + d(inds);
0309     tmp1 = c(inds) + e(inds);
0310     
0311     % minimum on edge s+t = 1, with s > 0
0312     bool2 = tmp1 > tmp0;
0313     inds2 = inds(bool2);
0314     numer = tmp1(bool2) - tmp0(bool2);
0315     denom = a(inds2) - 2 * b(inds2) + c(inds2);
0316     bool3 = numer < denom;
0317     s(inds2(~bool3)) = 1;
0318     inds3 = inds2(bool3);
0319     s(inds3) = numer(bool3) ./ denom(bool3);
0320     t(inds2) = 1 - s(inds2);
0321     
0322     % minimum on edge s = 0, with t <= 1
0323     inds2 = inds(~bool2);
0324     s(inds2) = 0;
0325     t(inds2(tmp1(~bool2) <= 0)) = 1;
0326     t(inds2(tmp1(~bool2) > 0 & e(inds2) >= 0)) = 0;
0327     inds3 = inds2(tmp1(~bool2) > 0 & e(inds2) < 0);
0328     t(inds3) = -e(inds3) ./ c(inds3);
0329 
0330         
0331     % region 6 (formerly region 6)
0332     % The minimum distance must occur
0333     % * on the line s + t = 1
0334     % * on the line t = 0, with s <= 1
0335     % * at the intersection of the two lines (s=1; t=0)
0336     inds = find(regIndex == 6);
0337     tmp0 = b(inds) + e(inds);
0338     tmp1 = a(inds) + d(inds);
0339     
0340     % minimum on edge s+t=1, with t > 0
0341     bool2 = tmp1 > tmp0;
0342     inds2 = inds(bool2);
0343     numer = tmp1(bool2) - tmp0(bool2);
0344     denom = a(inds2) - 2 * b(inds2) + c(inds2);
0345     bool3 = numer <= denom;
0346     t(inds2(~bool3)) = 1;
0347     inds3 = inds2(bool3);
0348     t(inds3) = numer(bool3) ./ denom(bool3);
0349     s(inds2) = 1 - t(inds2);
0350 
0351     % minimum on edge t = 0 with s <= 1
0352     inds2 = inds(~bool2);
0353     t(inds2) = 0;
0354     s(inds2(tmp1(~bool2) <= 0)) = 1;
0355     s(inds2(tmp1(~bool2) > 0 & d(inds2) >= 0)) = 0;
0356     inds3 = inds2(tmp1(~bool2) > 0 & d(inds2) < 0);
0357     s(inds3) = -d(inds3) ./ a(inds3);
0358     
0359 
0360     % compute coordinates of closest point on plane
0361     projList = p1 + bsxfun(@times, s, v12) + bsxfun(@times, t, v13);
0362     
0363     % squared distance between point and closest point on plane
0364     [dist(i), ind] = min(sum((bsxfun(@minus, point(i,:), projList)).^2, 2));
0365 
0366     % keep the valid projection
0367     proj(i, :) = projList(ind,:);
0368 end
0369 
0370 % convert squared distance to distance
0371 dist = sqrt(dist);
0372 
0373 end

Generated on Wed 16-Feb-2022 15:10:47 by m2html © 2003-2019