使用特殊情况

时间:2017-09-06 15:51:47

标签: vectorization octave

我需要实现以下逻辑: 给定一组2d样本点(以x-y坐标对给出)和一组线段(也是x-y-坐标对)。 编辑1:如何计算(向量化)点 pi Li 的距离?

Sample data (red) and model data (blue).

这些点大致靠近直线,我想得到每个采样点到最近的线段的距离。可能是点,有点"关" (参见第一张图中的第6页),这些可以通过以下算法找到:

  1. 案例:投影到线段的样本点是"离开"。在这种情况下,我需要从p1到x1的欧氏距离。
  2. 案例:投影到线段的样本点是"内部"线段。在这种情况下,我需要从p2到x1到x2之间的距离。
  3. 案例:投影到线段的样本点是"在右边"。在这种情况下,我需要从p3到x2的欧几里德距离。
  4. enter image description here

    有一个矢量化解决方案(感谢用户Andy),它使用投影"全局",总是假设每个点 - 中文对的情况2。但是,这会返回p1 ... p3的距离[1 1 1],其中所需距离为[1.4142 1 1.4142]。可以根据这些需求修改此代码吗?

    ptsx = [1 3 5];
    ptsy= [1 1 1];
    
    linesx = [2 4];
    linesy = [0 0];
    
    points = [ptsx;ptsy];
    lines = [linesx;linesy];
    
    % start of lines
    l = [linesx(1:end-1);linesy(1:end-1)];
    % vector perpendicular on line
    v = [diff(linesy);-diff(linesx)];
    % make unit vector
    v = v ./ hypot (v(1,:),v(2,:));
    v = repmat (v, 1, 1, size (points, 2));
    % vector from points (in third dimension) to start of lines (second dimension)
    r = bsxfun (@minus, permute (points, [1 3 2]), l);
    d = abs (dot (v, r));
    dist = squeeze (min (d, [], 2))
    

    从数学角度讲,通过查看vec(pi-x1)vec(x2-x1)的投影长度,可以分离案例。如果该长度因子是< 0,那么该点是"左"如果线段是0到1之间,则可以进行垂直投影,如果是> 0。 1,那么关键是"对"线段。

    编辑1:我将添加一个伪代码来解释如何通过双重for循环解决这个问题,但由于我有大约6000个样本和10000行,所以循环解决方案对我来说不是一个选项。

    for each sample point pi
      for each linesegment Li
        a = vector from start of Li to end of Li
        b = vector from pi to start of Li
        relLength = dot(a,b)/norm(a)^2
        if relLength < 0: distance = euclidean distance from start of Li to pi
        if relLength > 1: distance = euclidean distance from end of Li to pi
        else: distance = perpendicular distance from pi to Li
      endfor 
    endfor
    

    编辑2 / 2017-09-07:我设法对该算法的第一部分进行了矢量化。 relLength 现在包含每个pi-startOfLi投影到每个线段的相对长度。

    ptsx = [0.5 2 3 5.5 8 11];
    ptsy= [1  2 -1.5 0.5 4 5];
    
    linesx = [0 2 4 6 10 10 0 0];
    linesy = [0 0 0 0  0  4 4 0];
    
    points = [ptsx;ptsy];
    lines = [linesx;linesy];
    
    % Start of all lines
    L1 = [linesx(1:end-1); linesy(1:end-1)];
    % Vector of each line segment
    a = [diff(linesx); diff(linesy)];
    b = bsxfun(@minus, permute(points, [1 3 2]), L1);
    aRep = repmat(a, 1, 1, length(b(1,1,:)));
    relLength = dot(aRep,b)./norm(a, 'cols').^2
    

2 个答案:

答案 0 :(得分:3)

在GNU Octave中:

points = [1 4.3 3.7 2.9;0.8 0.8 2.1 -0.5];
lines = [0 2 4 3.6;0 -1 1 1.75];

% plot them
hold off
plot (points(1,:), points(2,:), 'or')
hold on
plot (lines(1,:), lines(2,:), '-xb')
text (points(1,:), points(2,:),...
      arrayfun (@(x) sprintf('  p%i',x),...
                1:columns(points),'UniformOutput', false))
axis ('equal')
grid on
zoom (0.9);

% some intermediate vars
s_lines = lines (:,1:end-1);    % start of lines
d_lines = diff(lines, 1, 2);    % vectors between line points
l_lines = hypot (d_lines(1,:),
                 d_lines(2,:)); % length of lines

现在做&#34;真实&#34;工作:

% vectors perpendicular on lines
v = [0 1;-1 0] * d_lines;
vn = v ./ norm (v, 2, 'cols');   %make unit vector

% extend to number of points
vn = repmat (vn, 1, 1, columns (points));
points_3 = permute (points, [1 3 2]);

% vectors from points (in third dimension) to start of lines (second dimension)
d =  dot (vn, points_3 - s_lines);

% check if the projection is on line
tmp = dot (repmat (d_lines, 1, 1, columns (points)),...
           points_3 - s_lines)./l_lines.^2;
point_hits_line = tmp > 0 & tmp < 1;

% set othogonal distance to Inf if there is no hit
d(~ point_hits_line) = Inf;

dist = squeeze (min (abs(d), [], 2));

% calculate the euclidean distance from points to line start/stop
% if the projection doesn't hit the line
nh = isinf (dist);
tmp = points_3(:,:,nh) - lines;
tmp = hypot(tmp(1,:,:),tmp(2,:,:));
tmp = min (tmp, [], 2);
% store the result back
dist (nh) = tmp

将结果绘制为点周围的黄色圆圈

% use for loops because this hasn't to be fast
t = linspace (0, 2*pi, 40);
for k=1:numel(dist)
  plot (points (1, k) + cos (t) * dist(k),
        points (2, k) + sin (t) * dist(k),
        '-y')
end

Result plot

答案 1 :(得分:0)

使用八度音阶几何包

Octaves geometry包中包含解决所请求问题的所有必要工具。实现您的问题的解决方案有两个功能:

函数distancePointPolylinedistancePointPolygon都应该能够计算请求的距离。多边形是封闭的折线。

实施例

以下脚本演示了这些函数的用法。有关图形结果,请参阅figure

% Load octave geometry package (package is also available for matlab)
pkg load geometry
% Define points
points = [1,4.3,3.7,2.9; 0.8, 0.8, 2.1, -0.5]';
% Define polyline
lines  = [0, 2, 4, 3.6;   0, -1, 1, 1.75]';

% Calculate distance
d = distancePointPolyline (points,lines);

% Produce figure
figure('name','Distance from points to polyline');
hold all
drawPoint(points);
drawPolyline(lines);
drawCircle(points, d);
axis equal

结果

Graphical result of sample script

相关问题