Mouse follower easing in/out - mouse

There are a lot of mousefollower tutorials out there. Most of them feature a simple formula for easing the motion:
x += (tx - x) / interp;
y += (ty - y) / interp;
(tx = target position, x = actual position, interp > 1)
This makes the follower go very fast in the beginning, then decelerate slowly to the target position.
How do i have to change the formular, so that i can define a custom acceleration, custom deceleration and a maxspeed for the movement in between? For the very beginning i'd be happy with an added acceleration at all.
Thanks!
Hans

Acceleration is the change in velocity over time. So in 1D, to apply a constant velocity, you'd do:
v += a * dt;
x += v * dt;
where:
a is the acceleration (a constant)
v is the velocity
x is the x-position
dt is the timestep, i.e. the time between updates
You'd do something similar for deceleration, except that a would now be negative.
To set a maximum velocity, you simply need to a conditional check on v, maybe:
v = MIN(v_max, v);
where v_max is your maximum allowed velocity (a constant).
In 2D, you'd need to take into account the direction of travel:
x += v * cos(theta);
y += v * sin(theta);
I'll leave it to you to calculate theta...

Related

Translate quaternion rotation to correct frame

I place an IMU on my wrist and extend my arm as shown in the photo below. I spin in a circle once, while my arm remains in the fixed position. I calculate the euler pitch and quaternion angle. In the photo below, the euler pitch remains approximately constant ( my hand shakes a bit ), while the quaternion angle increases linearly it seems. My data is located here: (sample_data.csv)
Question:
What changes should I make to measure the angle from the quaternion? ( I suspect it is in form of RPR', adjust to world axis, but am unsure what P would be )
Matlab code:
clc;
clear;
table = readtable("sample_data.csv", 'Delimiter', ',');
euler_angles = zeros(length(table.w),1);
quaternion_angles = zeros(length(table.w),1);
for idx = 1:length(table.w)
w = table.w(idx);
x = table.x(idx);
y = table.y(idx);
z = table.z(idx);
euler_angles(idx) = getEulerAngle(w,x,y,z);
quaternion_angles(idx) = getQuaternionAngle(w,x,y,z);
end
figure(1);
clf;
hold on;
plot(euler_angles,'ro');
ylabel("Angle in deg");
xlabel("Sample");
plot(quaternion_angles, 'bo');
hold off;
legend('Euler','Quaternion');
function angle = getQuaternionAngle(w,x,y,z)
q = quaternion(w,x,y,z);
angle = acosd(w);
end
function angle = getEulerAngle(w, x, y, z)
mag = (2*(y * w - z * x));
angle = rad2deg(asin(mag));
end
Assuming you rotate around an axis [x;y;z] , the post you refer to states that the quaternion associated with the rotation is of the form:
q(1) = cos(r/2);
q(2) = sin(r/2)*x;
q(3) = sin(r/2)*y;
q(4) = sin(r/2)*z;
Where r is the angle in radians and [x;y;z] is the 3d vector representing the axis around which you rotate.
To get the instantaneous rotation r you need to calculate 2*acos(q(1)) for an angle in radians, or 2*acosd(q(1)) for an angle in degrees.
Now plotting the data from your csv file gives the following:
Which is coherent with the assumption that w is the first coordinate of your quaternion, and that you indeed rotate mostly around z.
Euler angles (Or more likely Tait Bryan angles) are a different way to represent a rotation. A rotation is represented by a composition of 3 elemental rotations. These 3 rotations are sometimes called yaw, pitch and roll. If you want to fully represent your rotation, you will have to calculate all of these 3 elemental rotations:
table = readtable("sample_data.csv", 'Delimiter', ',');
w = table.w;
x = table.x;
y = table.y;
z = table.z;
[yaw,pitch,roll] = getAngles(w, x, y, z);
quaternion_angles = getQuaternionAngle(w);
figure; plot([quaternion_angles,yaw,pitch,roll]);
legend({'quat','yaw','pitch','roll'})
function angle = getQuaternionAngle(w)
angle = 2*acosd(w);
end
function [yaw,pitch,roll] = getAngles(w, x, y, z)
yaw = atan2d(2*(y.*z + w.*x), w.*w - x.*x - y.*y + z.*z);
pitch = asind(-2*(x.*z-w.*y));
roll = atan2d(2*(x.*y + w.*z), w.*w + x.*x - y.*y - z.*z);
end
See? The angle around Z is represented by the roll (the discontinuity is due to the use of arctan). When you rotate around yourself, the angle increases steadily between 0 and 360º.
You can also see that you have a bit of yaw, i.e your IMU is a bit tilted

Coordinate from 2 vectors

All,
Suppose I have two vectors U and V with 2 units and 1 unit length, respectively as shown in the sketch. The vector U is rotated by angle theta.
There are, at least two possible cases whereby vector U can go "up" or "down" as shown in the sketch.
My question is, having the above dataset is it possible to have a generic formula that can be transferred into Matlab to get the coordinate of point M?
the length of the vector U and V and angle theta are arbitrary.
Thank you!
There is a more efficient solution.
The coordinates of the endpoints of U are given by:
(U * cos(theta), U * sin(theta))
For any vector (x, y) the clockwise perpendicular direction (i.e. the second diagram "down") is (y, -x), and those of the anti-clockwise direction are minus these. Therefore the coordinates of M are given by:
Anti-clockwise ("up"): (U * cos(theta) - M * sin(theta), U * sin(theta) + M * cos(theta))
Clockwise ("down"): (U * cos(theta) + M * sin(theta), U * sin(theta) - M * cos(theta))
No need for calls to arctan or sqrt which are both very costly. Also you can compute sin/cos just once and use the results for both components.
From Pythogoras we know that
M = sqrt(U^2 + V^2)
angle between M and U is
alpha = arctan(V/U)
So then you know that the x- and y-coordinates for M are:
the "up" case:
M = (sqrt(U^2 + V^2)*cos(theta + sign(cosd(theta))*arctan(V/U)), sqrt(U^2 + V^2)*sin(theta + sign(cosd(theta))*arctan(V/U)))
the "down" case:
M = (sqrt(U^2 + V^2)*cos(theta - sign(cosd(theta))*arctan(V/U)), sqrt(U^2 + V^2)*sin(theta - sign(cosd(theta))*arctan(V/U)))
A second way to calculate this is to look add the length of U and V in the x and y direction, and sum them.
The coordinates of U are:
(Ucos(theta), Usin(theta))
To this coordinates we must add/substract the x-and y-coordinates of V. The length of V along x and y is:
(abs(sin(theta)), abs(cos(theta))
Whether one should add or substract these from U is dependent on theta. In general we can write Vup and Vdown as
Vup = (V*sign(-cos(theta))sin(theta), Vsign(cos(theta))*cos(theta))
Vdown = (V*sign(cos(theta))sin(theta), Vsign(-cos(theta))*cos(theta))
then we can alway add U to Vup and Vdown. Finally
Mup = U + Vup
Mdown = U + Vdown
Just another compact solution
theta = 30;
L = 2; % norm of U vector
U = L*[cosd(theta) ; sind(theta)];
Vup = [-U(2) ; U(1)] / L; % Normal vectors, unit length
Vdown = [U(2) ; -U(1)] / L;
Mup = U + Vup; % Two possible values of M
Mdown = U + Vdown;
% Bonus plot
figure
plot([0 U(1)] , [0 U(2)] , 'k-')
hold on; axis equal;
plot([0 Vup(1)]+U(1) , [0 Vup(2)]+U(2) , 'r-')
plot([0 Vdown(1)]+U(1) , [0 Vdown(2)]+U(2) , 'r-')
text(Mup(1),Mup(2),'M_u_p')
text(Mdown(1),Mdown(2),'M_d_o_w_n')
You can exploit the properties of the cross product of Uinit and Urot. The sign of the product will inform you on the orientation of the resulting vector.
Supposing that the origin is O(0,0), your initial vector is Uinit(x1,y1) and your final vector is Urot(x2,y2). Also M(x,y) can be calculated easily.
If you want to filter the rotated vectors Urot that ended up 'above' or 'below' M compared to the previous orientation of your triangle, you can take the following cross products:
M cross Uinit and M cross Urot.
If their sign is the same then the resulting rotated vector didn't cross the line OM and the opposite if the sign is different.

calculate the angle between a line and x-axis

I have two points in my coordinate system (x,y) that I want to know the angle of their line and x-axis.
I use swift for solving this but I can't get the angle.
I need this angle in radians to use it in the following equation:
(x0 + r cos theta, y0 + r sin theta)
r : radius of circle
If you have two points, (x0, y0) and (x1, y1), then the angle of the line joining them (relative to the X axis) is given by:
theta = atan2((y1 - y0), (x1 - x0))
The angle between a line, for reference, let's call this A, defined by two points p1=(x1,y1),p2=(x2, y2) and the x-axis is related to finding the slope/ gradient of the line, A.
# To solve a problem you sometimes have to simplify it and then work up to the full solution"
Let's start by obtaining the gradient of the line A.
The gradient of line A:
slope = (y2 - y1)/(x2 - x1)
for a straight line, that makes an angle theta with the x-axis
tan(theta) = slope = (change in y) / (change in x)
Therefore, theta = tan_inverse (slope)
theta = atan(slope)

if statement in MATLAB for plotting the height of a ball

I am using MATLAB to calculate the height of a ball in case of projectile motion. Here is my code :
v = 10;
teta = 20; % angle of the projectile motion
vx = v*cos(teta); % velocity in x axis
vy = v*sin(teta); % velocity in y axis
x = 0:10;
y = zeros(length(x),1);
for xx=1:length(x)
% here I calculate the height of the ball in y axis
y(xx,:) = vy*(xx/vx)-(0.5*9.81*(xx./vx)^2);
% here I want to break the system when the height of the ball is
% zero (on the ground surface)
if y(xx,:) == 0
break
end
end
plot(x,y, '*')
The problem that when I plot the motion it does not stop when the height is zero
but it continues for negative values of y axis ..
What is the wrong in my if-statement?
You should never compare a float or double number to an integer. When you say if y(xx,:)== 0 you are breaking the loop only when the height is exactly zero, and that will never happen (just see the values stored in y).
If you want to keep your data from been negative, you should try if y(xx,:) < 0. Keep in mind that if you use this approach, you should always delete the last value added to y, because when that statement breaks you loop, you've already stored the first negative value. So, just add y(xx)= 0; before the break line.
<teacher_mode>
What I would do is use constant time increments rather than using constant x increments. This is not only more intuitive, but also provides a much better building block for if you'd want to level up in the future. This approach makes it easier to include additional effects (like airdrag, 3D, bounces, ...) and is a stepping stone towards more advanced methods to do these computations (numerical integration of the vector-valued equations of motion; see ode45 in MATLAB for some examples).
Here is an example of a "bouncy" ball:
v = 100; % initial speed
theta = 20; % initial angle (°) with X-axis
vx = v * cosd(theta); % initial velocity in x axis
vy = v * sind(theta); % initial velocity in y axis
T = 0 : 0.01 : 50; % times to sample
x = zeros(length(T),1);
y = zeros(length(T),1);
ay = -9.80665; % gravity
ax = 0; % ...wind perhaps
ex = 0.9; % elasticity in X-direction
ey = 0.5; % elasticity in Y-direction
for ii = 2:numel(T)
% Update time step
dt = T(ii) -T(ii-1);
% Update speed
vx = vx + ax*dt;
vy = vy + ay*dt;
% Update position
x(ii) = x(ii-1) + [vx ax/2] * dt.^(1:2)';
y(ii) = y(ii-1) + [vy ay/2] * dt.^(1:2)';
% Bounce the ball!
if y(ii) <= 0
y(ii) = 0;
vx = ex* vx;
vy = abs( ey*vy );
end
end
clf, hold on
plot(x,y)
</teacher_mode>
You can avoid for loop at all:
v=10;
theta=20; % angle of the projectile motion
vx=v*cos(theta); % velocity in x axis
vy=v*sin(theta); % velocity in y axis
x=0:0.1:10;
y=zeros(size(x));
y=vy.*(x./vx)-(0.5*9.81*(x./vx).^2); %% Calculate values for all x
x=x(y>=0); %% keep the x values where y>=0
y=y(y>=0); %% keep the y valuse where y>=0
plot(x,y,'*')

Producing normal map of a sphere

I searched Internet a lot, but it's hard to find how we can actually find a normal map of an object. Right now, I have to write a code which produces the normal map of a sphere. I mean this one. My sphere should be defined with the set of azimuth and inclination, but we say that the numbers (azimuth and inclination) should be between 0 and 100 for example. Does anybody have any idea?
Here is an explanation that provides a good insight at what is a normal map and how it can be created.
One way to create a sphere normal map in Matlab using the cartesian coordinate system would be:
% X and Y components of the normals vectors are between -1 and 1.
% The step number specifies the size of the output image.
range = -1:0.01:1;
% Repeat the range to build a matrix
X = repmat(range, [size(range, 2), 1]);
Y = flipud(repmat(range', [1, size(range, 2)]));
% These normals must be of unit norm, so find an Z component which
% solves sqrt(X^2 + Y^2 + Z^2) = 1
Z = (1 - (X.^2 + Y.^2)).^0.5;
% Change the display range of X and Y to 0..1 instead of -1..1
X = (X + 1) / 2;
Y = (Y + 1) / 2;
Z = (Z + 1) / 2;
% Mask pixels outside the sphere (in which the Z component is complex)
X(Z ~= real(Z)) = 0;
Y(Z ~= real(Z)) = 0;
Z(Z ~= real(Z)) = 0;
% Build the map
map = cat(3,X,Y,Z);
imshow(map);
This builds a matrix map containing the X, Y and Z components of the normals of a sphere. You could use the sph2cart function to convert an azimuth and elevation to their equivalent X, Y and Z components.
Note that the normal map you referred to is flipped upside-down compared to the usual normal maps where green should be in the upper left corner and red in the lower right corner.