Search code examples
matlabsortingmatrix-indexing

Matlab: Sorting 2D matrix and retaining nodes in triangle groups


I am trying to optimize a Matlab script (below) that finds the bounding boxes to functional values of all lower left triangles in a 2D space. The code goes through all the triangles and then sorts the nodes in ascending order based on the functional values. This seems inefficient.

Is there some way that I could sort the functional values before the loops but still retain the nodes in the triangle groups? Or some other smart way to speed things up?

clear;

x = (1:600)';
y = (1:500);
z = 2 * x.^2 + y;

zGrid = linspace(min(z, [], 'all') - 1, max(z, [], 'all') + 1, 200);

for iX = 1:length(x) - 1
    for iY = 1:length(y) - 1
        % Node indices
        xIndices = [iX, iX, iX + 1];
        yIndices = [iY, iY + 1, iY];

        % Node values
        xTmp = x(xIndices);
        yTmp = y(yIndices);
        zTmp = z(sub2ind(size(z), xIndices, yIndices));

        % Node sorted according to z
        [zSorted, indicesSorted] = sort(zTmp);
        xSorted = xTmp(indicesSorted);
        ySorted = yTmp(indicesSorted);

        % Get bounding box on zGrid
        iMin = find(zGrid <= zSorted(1), 1, 'last');
        iMax = find(zGrid(iMin:end) >= zSorted(end), 1, 'first') + (iMin - 1);
    end
end

Solution

  • You can use meshgrid to generate all the indices, then just adapt the code to obtain the desired ouput:

    x = (1:600).';
    y = (1:500);
    z = 2 * x.^2 + y;
    
    zGrid = linspace(min(z(:)) - 1, max(z(:)) + 1, 200);
    [X,Y] = meshgrid(x(1:end-1),y(1:end-1));
    X = X(:);
    Y = Y(:);
    
    % Node indices
    xIndices = [X, X, X + 1];
    yIndices = [Y, Y + 1, Y];
    
    % Node values
    xTmp = x(xIndices);
    yTmp = y(yIndices);
    zTmp = z(sub2ind(size(z), xIndices, yIndices));
    
    % Node sorted according to z
    [zSorted, indicesSorted] = sort(zTmp,2);
    xSorted = xTmp(indicesSorted+[0:3:(length(X)-1)*3].');
    ySorted = yTmp(indicesSorted+[0:3:(length(Y)-1)*3].');
    
    % Get bounding box on zGrid
    % I use fliplr to get the last value and not the first one
    [~,iMin] = max(fliplr(zGrid <= zSorted(:,1)),[], 2);
    iMin = 200-iMin+1; %first to last value conversion
    [~,iMax] = max(zGrid(iMin:end) >= zSorted(:,end),[],2);
    iMax = iMax + iMin -1;