0
votes

Consider for the example the following points scatter:

x=[-1.6794 -2.6072 0.4175 0.1898 -0.7749 1.8392 1.7411];
y=[7.9969 9.5312 8.0302 7.2956 6.5550 9.9890 7.9462];

with a reference point :

xc = -0.9311; yc = 9.1109;

Plotting the scatter points:

 figure(1)
 hold on
 scatter(x,y,'.b')
 scatter(xc,yc,'.r')
 xlim([-10 10]); ylim([0 15]);

enter image description here

I can calculate all the angles between all the vectors that start at [xc,yc] in the following way:

v=[x-xc;y-yc]';
dot_v=v*v';
norm_v=sqrt(v(:,1).^2+v(:,2).^2);
angles=acosd(dot_v./(norm_v.*norm_v'));

The following plot will visualize the vectors and the angles between them:

figure(1)
hold on
scatter(x,y,'.b')
scatter(xc,yc,'.r')
xlim([-10 10]); ylim([0 15]);
for i=1:length(x)
    for j=1:length(x)
        hh1=plot([xc x(i)],[yc y(i)]);
        hh2=plot([xc x(j)],[yc y(j)]);
        th=title(num2str(angles(i,j)));        
        pause
        delete(hh1); delete(hh2); delete(th);
    end   
end

enter image description here

I would like however to obtain all the angles in the trianle created by these two vectors, for example:

enter image description here

I can use loops and calculate the angles between each vector that is made out of two points in the data, however, the data I have contains a very large number of points, therefore I would like to avoid using loops and make use of matlab abilities in writing things in matrix form, therefore please provide an elegant and efficient answer.

1

1 Answers

2
votes

Actually, it's pretty easy to create the missing line of your triangles... it's given by the following coordinates:

[x(i) x(j)] [y(i) y(j)]

Taking back your code, you can achieve the desired result as follows:

x = [-1.6794 -2.6072 0.4175 0.1898 -0.7749 1.8392 1.7411];
y = [7.9969 9.5312 8.0302 7.2956 6.5550 9.9890 7.9462];

xc = -0.9311;
yc = 9.1109;

v = [x - xc; y - yc].';
d = v * v.';
n = sqrt(v(:,1).^2 + v(:,2).^2);

angles = acosd(d ./ (n .* n.'));
angles = round(real(angles),2);

f = figure();    
hold on;
scatter(x,y,'.b');
scatter(xc,yc,'.r');
xlim([-10 10]);
ylim([0 15]);
hold off;

len = numel(x);

for i = 1:len
    for j = 1:len
        ang = angles(i,j);

        if (ang == 0)
            continue;
        end

        xi = x(i); xj = x(j);
        yi = y(i); yj = y(j);  

        hold on;
        p1 = plot([xc xi],[yc yi],'b');
        p2 = plot([xc xj],[yc yj],'b'); 
        p3 = plot([xi xj],[yi yj],'b'); 
        t = title(num2str(ang));
        hold off;

        pause(2);
        delete(p1);
        delete(p2);
        delete(p3);
        delete(t);
    end   
end

A made a few adjustements on it:

  • I used the real transpose function (.') instead of the conjugate transpose function ('), which is what you should apply in this case.
  • I rounded the angles taking only their real part.
  • I fixed the pause inside the loops to make everything smoother.
  • I cached the loops indexing.
  • I uniformed the color of the triangle lines.
  • I skipped the plotting for flat triangles (angle = 0).

Matlab produces amazing performances when using vectorized code... but this cannot be always the way to go. I know how to reduce your two loops into a single one... but if you want to use this plotting approach, soon or later you must implement at least one iteration in your code and there is nothing you can do about it. Here is what you can achieve, at best:

f = figure();    
hold on;
scatter(x,y,'.b');
scatter(xc,yc,'.r');
xlim([-10 10]);
ylim([0 15]);
hold off;

len = numel(x);

ang = angles(:);
ang_ok = ang ~= 0;
ang = ang(ang_ok);

idx = [repelem((1:len).',len,1) repmat((1:len).',len,1)];
idx = idx(ang_ok,:);

for k = 1:size(idx,1)
    i = idx(k,1);
    j = idx(k,2);

    xi = x(i); xj = x(j);
    yi = y(i); yj = y(j);  

    hold on;
    p1 = plot([xc xi],[yc yi],'b');
    p2 = plot([xc xj],[yc yj],'b'); 
    p3 = plot([xi xj],[yi yj],'b'); 
    t = title(num2str(ang(k)));
    hold off;

    pause(2);
    delete(p1);
    delete(p2);
    delete(p3);
    delete(t); 
end

Inner angles, those that are created once the triangle is completed, can be calculated inside the loop itself with the approach you currently use, just shifting the coordinates. In fact, since the sum of the angles inside a triangle is 180°... you need to compute just two of them, and the third one can be obtained using the following equation: AngleC = 180 - AngleA - AngleB.