Home > other >  Rotate line to arbitary position around unit circle
Rotate line to arbitary position around unit circle

Time:11-23

I have a unit circle with n roots of unity marked. I would like to be able to rotate, translate, and scale a line resting on the x-axis (between -1 and 1) to connect any pair of marked roots. Currently my code can do this in some cases, but doesn't work in general. I want to avoid hard-coding how the line should move for each possible pair. Here's what I have so far:

clear

%% Roots of unity
n = 10;
roots = zeros(1, n);
for k = 1 : n
    roots(k) = exp(2 * k* pi * 1i / n);
end

%% Move line
% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);

% Coordinates of pair of roots
x1 = real(point_1);
x2 = real(point_2);
y1 = imag(point_1);
y2 = imag(point_2);

d = sqrt((x1-x2)^2 (y1-y2)^2); % Euclidean distance between pair of roots
m = (y1 - y2) / (x1 - x2); % Gradient of line connecting pair of roots
c = y1 - m * x1; % y-intercept of line

int = -c / m; % x-coordinate that the rotation should occur at
shift = [int; 0];

x = linspace(-1, 1, 10); % Initial line lying purely on x-axis
y = 0 * x;
v = [x; y];

theta = atan((y2-shift(2))/(x2-shift(1))); % Angle by which to rotate

rot = [cos(theta), -sin(theta); sin(theta), cos(theta)]; % Rotation matrix

u = v * (d / 2); % Scale initial line

if m < 1e-3  % Horizontal case
    shift = [0; 0];
end

w = (rot * (u - shift))   shift; % Apply rotation

% Another shift that seems necessary
% This is definitely a problematic section
shift_x = w(1, 1) - x2;
shift_y = w(2, 1) - y2;
shift_2 = [shift_x; shift_y];
w = w - shift_2;


%% Plot
fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];
ax = gca;
tt = title(ax, 'Title');
tt.FontWeight = 'bold';
tt.FontSize = 20;
st = subtitle(ax, sprintf('More text here'));
st.FontAngle = 'italic';
st.FontSize = 15;

hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
for i = 1 : n
   x_point = real(roots(i));
   y_point = imag(roots(i));
   hPin = plot(x_point, y_point, 'Marker', 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
       'MarkerEdgeColor', 'black');
end

% Plot original and shifted line, split into colours so direction is easier to see
plot(v(1,1:4), v(2,1:4), 'b');
plot(v(1,4:7), v(2,4:7), 'r');
plot(v(1,7:end), v(2,7:end), 'g');

plot(w(1,1:4), w(2,1:4), 'b');
plot(w(1,4:7), w(2,4:7), 'r');
plot(w(1,7:end), w(2,7:end), 'g');

For example, keeping point_1 = roots(2); and changing only point_2 = roots(p); works as intended for only p=3, 4, 6, 7, 8.

Any guidance on how to get this working would be greatly appreciated, thanks!

Edit: To give some more details, basically I have an array of numbers between 0 and 1 (rather than just a line) which I want to plot on the line that would connect two roots. E.g. if my array is x=[0.2, 0.5, 0.9], then I want three points between point_1 and point_2, the first being 0.2d down the connecting line away from point_1, the second 0.5d (i.e. halfway), and the final being 0.9d away.

CodePudding user response:

First of all, since the points you want to connect are complex numbers, it is easier to work with complex coordinate directly.

Roots of unity
I have simplified your code a bit.
Some may raise a flag on naming a variable roots since roots is a built-in matlab function. I am fine with it, as long as the usage does not cause any confusion, namely, don't use roots as a variable and as a function in the same context.
As matlab provides so many built-in functions, it is impossible to avoid name collision unless one knows them all by heart or searches before naming every single variable.

n = 10;
k = 1:n;
roots = exp(2 * k * pi * 1i / n);

Scaling, rotating, and translating

% Pair of roots the line should connect
point_1 = roots(2);
point_2 = roots(6);

d = abs(point_2 - point_1);         % distance between pair of roots
theta = angle(point_2 - point_1);   % rotation angle

p_on_line = linspace(-1, 1, 10);                    % Initial line lying on x-axis
p_on_line = p_on_line * d/2;                        % scale
p_on_line = p_on_line * exp(1i*theta);              % rotate
p_on_line = p_on_line   (point_1 - p_on_line(1));   % translate

Plot
I added some scatter points and removed irrevelant parts (e.g. title, fonts).

fig = figure;
fig.Units = 'inches';
fig.Position = [1, 1, 9, 9];

hold on
hCircle = viscircles([0, 0], 1, 'Color', 'k');
hPin = plot(roots, 'o', 'MarkerSize', 20, 'MarkerfaceColor', 'red', ...
            'MarkerEdgeColor', 'black');

% Plot line connecting roots
plot(p_on_line(1:4), 'b.-', 'MarkerSize', 20);
plot(p_on_line(4:7), 'r.-', 'MarkerSize', 20);
plot(p_on_line(7:end), 'g.-', 'MarkerSize', 20);

% Plot original line
original_x = linspace(-1, 1, 10);
original_y = zeros(1, 10);
plot(original_x(1:4), original_y(1:4), 'b.-', 'MarkerSize', 20);
plot(original_x(4:7), original_y(4:7), 'r.-', 'MarkerSize', 20);
plot(original_x(7:end), original_y(7:end), 'g.-', 'MarkerSize', 20);
hold off

This should work for all combinations of root pairs.

  • Related