Home > matGeom > meshes3d > distancePointMesh.m

distancePointMesh

PURPOSE ^

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

SYNOPSIS ^

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

DESCRIPTION ^

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

   DIST = distancePointMesh(POINTS, VERTICES, FACES)
   Returns the shortest distance between the query point(s) POINTS and the
   triangular mesh defined by the set of vertex coordinates VERTICES and
   the set of faces FACES. POINTS is a NP-by-3 array, 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 is the NP-by-1 vector of distances.

   [DIST, PROJ] = distancePointMesh(...)
   Also returns the NP-by-3 projection of the query point(s) 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
       https://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf
   * "Distance between a point and a triangle in 3d", by Gwendolyn Fischer
       https://mathworks.com/matlabcentral/fileexchange/22857
   * "Distance Between Point and Triangulated Surface", by Daniel Frisch
       https://www.mathworks.com/matlabcentral/fileexchange/52882

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

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

Generated on Thu 21-Nov-2024 11:30:22 by m2html © 2003-2022