Connecting a set of points to get a non-self-intersecting non-convex polygon

前端 未结 3 2015
忘掉有多难
忘掉有多难 2021-01-28 08:26

I have an unordered set of 2D points which represents the corners of a building. I need to connect them to get the outline of the building.

The points were obtained by c

3条回答
  •  逝去的感伤
    2021-01-28 09:20

    Here's a solution which that good for shapes that have outlines made from perpendicular* lines (as the one in your example). The idea is as follows:

    1. We rotate the points to align* them to the XY grid.
    2. We group points into families that have either the same* X or Y coordinates.
    3. For each point we compute two points: the closest horizontally, and the closest vertically, from within the allowed families.
    4. Build a connectivity matrix and transform back.

    Just like in HansHirse's answer, I must change the dataset: add a missing corner (pt. 30), remove two non-corners (pts. 7-8), remove the duplicate last point.

    * - approximately.

    function A = q55511236
    %% Initialization:
    % Define points:
    X = [364.533 372.267 397.067 408.133 382.471 379.533 329.250 257.200 199.412 195.267 184.385 ...
         168.643 157.533 174.500 108.533 99.333 150.733 184.800 138.105 179.474 218.278 232.133 ...
         267.714 306.929 312.143 357.733 421.333 431.000 371.867];
    Y = [192.027 233.360 228.627 286.693 314.541 292.960 327.450 340.500 348.671 326.693 269.308 ...
         330.857 274.493 226.786 239.200 193.467 182.760 101.893 111.000 80.442 74.356 140.360 ...
         64.643 56.857 77.786 69.493 133.293 180.427 142.160];
    
    %% Preprocessing:
    % Centering:
    XY = [X;Y] - [mean(X); mean(Y)];
    % Rotation:
    [U,~,~] = svd(XY,'econ');
    rXY = (U.' * XY).';
    
    % Fixing problems w/ some points:
    rXY = vertcat(rXY, [-21.8, 66]); % add missing point
    rXY(7:8, :) = NaN; % remove non-corners
    % figure(); scatter(rXY(:,1),rXY(:,2));
    
    %% Processing:
    % Group points according to same-X and same-Y
    CLOSE_ENOUGH_DISTANCE = 10; % found using trial and error
    [~,~,sameXpts] = uniquetol(rXY(:,1), CLOSE_ENOUGH_DISTANCE, 'DataScale', 1);
    [~,~,sameYpts] = uniquetol(rXY(:,2), CLOSE_ENOUGH_DISTANCE, 'DataScale', 1);
    
    % Create masks for distance evaluations:
    nP = size(rXY,1);
    [maskX,maskY] = deal(zeros(nP));
    maskX(sameXpts == sameXpts.') = Inf;
    maskY(sameYpts == sameYpts.') = Inf;
    
    % Compute X and Y distances separately (we can do this in the rotated space)
    dX = abs(rXY(:,1) - rXY(:,1).') + maskX + 1./maskY;
    dY = abs(rXY(:,2) - rXY(:,2).') + maskY + 1./maskX;
    [~,nX] = min(dX);
    [~,nY] = min(dY);
    
    % Construct connectivity matrix:
    A = false(nP);
    idxTrue = sub2ind(size(A), repmat(1:nP, [1,2]), [nX(:).', nY(:).']);
    A(idxTrue) = true;
    
    %% Plot result:
    % Rotated coordinates:
    figure(); gplot(A, rXY, '-o'); text(rXY(:,1), rXY(:,2), string(1:nP));
    uXY = (U*rXY.').';
    % Original coordinates:
    figure(); gplot(A, uXY, '-o'); text(uXY(:,1), uXY(:,2), string(1:nP)); axis ij;
    

    Resulting in:

提交回复
热议问题