Get the minimum value of a property from an array of objects
Apologies if this is a stupid question, I am relatively new to Matlab.
I have an array of rectangles of class Rectangle with properties minx, miny, maxx, maxy
that represent angular coordinates.
I am trying to get the index of the top left rectangle in an array.
I can loop through objects to get an object that matches the minimum x and y coordinates, but that doesn't seem like a very malabian (maclabian? Doesn't sound nearly as good as pythonic) way of doing it.
minx = -1
miny = -1
tl_rect_id = 0
for id = 1:num_objects
if ((rectangles(id).minx < minx || minx == -1) && (rectangles(id).miny < miny || miny == -1))
tl_rect_id = id
minx = rectangles(id).minx
miny = rectangles(id).miny
end
% plot coordinates of top left corners
plot(rectangles(id).minx,rectangles(id).miny,'+r')
end
source to share
You don't need to use arrayfun to work with arrays of objects in Matlab. There's a very useful shorthand for getting an array of properties from an array of objects:
[rectangles.minx]
This gives the entire rectangle minx
in the array.
So, to find out which point is closer to the origin, I would calculate a good Euclidean distance to the origin. With vectors available it REALLY .
The Euclidean distance is defined as follows:
d(a,b) = sqrt( (a.x - b.x)^2 + (a.y - b.y)^2);
to compute it using your vectors:
distances = sqrt([rectangles.minx].^2 + [rectangles.miny].^2)
This will give a vector with the distances of all points. Finding the minimum is trivial:
[~, idx] = min (distances);
The min function returns a 1x2 array, the first position is the minimum value, the second is the index. I used matlab notation [~, idx]
to indicate that I am not interested in the first return value and the second should be stored in a variable idx
.
I wrote an example where I created my rectangle class just to test it, but it will work with your class too. Below are the codes for class i and the code that calculates the point closest to (0,0).
Run it to play with the idea and adapt it to your needs :)
Test class definition (except in the Rectangle.m file):
classdef Rectangle
properties
minx;
miny;
end
methods
function obj = Rectangle(v1,v2)
if nargin > 1
obj.minx = v1;
obj.miny = v2;
end
end
end
end
code
clear all;
numRect = 100;
rect_array = Rectangle(numRect);
% initialize rectangles
for n=1:numRect
r = Rectangle;
r.minx = 100*rand(1,1);
r.miny = 100*rand(1,1);
rect_array(n) = r;
end
% find point closest to the origin
[~, idx] = min(sqrt([rect_array.minx].^2 + [rect_array.miny].^2));
close all;
figure;
% plot the points in blue
plot([rect_array.minx],[rect_array.miny],'b.');
hold on;
% mark a red cross on the point closest to the origin
plot(rect_array(idx).minx, rect_array(idx).miny, 'rx');
source to share
Your code finds either the rectangle that is further left or the rectangle that is further away. If you are not worried about multiple parchments having the same meaning for minx, you can do
[v i] = min(arrayfun(@(i)rectangles(i).minx, 1:num_objects))
fprintf('Furthest left rectangle is %g\n', i);
Alternatively, you can do:
[v i] = sortrows(cell2mat(arrayfun(@(i)[rectangles(i).minx; rectangles(i).miny], 1:num_objects, 'uniformoutput', 0))');
fprintf('Furthest left rectangle is %g\n', i(1));
which will sort by X and then Y and then take the first in that order. It's slower because it pretends. To get the exact behavior of your algorithm above, you should probably just stick with for loops, I think doing that would be rough, it would be messy.
source to share