How to adjust length of a line drawn between two lines? - matlab

I have a line that I have drawn between two points
origin = [1 0 2];
point = [1 -2.8 2.8 ];
I want to draw a line between them at a certain distance. I have tried the following, which gives me wrong results... Is there a better way to do this?
distance = 0.5;
point3 = origin + (point-origin) * distance;
MY SOLUTION:
which assumes that I will start at the same origin, just the last point changes:
cff = 0.5; % Coefficient that determines the length of the line
point2(1)= origin(1) + cff* (point(1) - origin(1));
point2(2)= origin(2) + cff* (point(2)- origin(2));
point2(3)= origin(3) + cff* (point(3) - origin(3));
For a length of a certain distance from origin:
d = 3; % Distance
unit_v = point - origin;
u = unit_v / norm(unit_v);
point2(1)= origin(1) + d * u(1) ;
point2(2)= origin(2) + d * u(2) ;
point2(3)= origin(3) + d * u(3) ;

You can calculate the unit vector from start point to end point and move the start point:
A = [1 0 2];
B = [1 -2.8 2.8 ];
d = 0.5;
V = B-A; % A->B vector
l = norm(V); % length of V
U = V/l; % unit vector
C = A + d*U;
D = A + (l-d)*U;
hold on
plot3([A(1) B(1)], [A(2) B(2)],[A(3) B(3)], '--o')
plot3([C(1) D(1)], [C(2) D(2)],[C(3) D(3)], '-x', 'linewidth', 2)

Related

Sierpinski Triangle in MATLAB

I have written the following code but I seem to be missing something and I'm not sure what it is:
axis off
hold on
for i = 1:10000
r = [rand() rand()];
rp = [(1 - sqrt(r(1))) * -1 + (sqrt(r(1)) * (1 - r(2))) * 0 + (sqrt(r(1)) * r(2)) * 1,
(1 - sqrt(r(1))) * 0 + (sqrt(r(1)) * (1 - r(2))) * sqrt(3) + (sqrt(r(1)) * r(2)) * 0];
v1 = [-1 0 1];
v2 = [0 sqrt(3) 0];
num = randi([1 3], 1);
rv = [v1(num) v2(num)];
mid_x = (rp(1) + rv(1))/2;
mid_y = (rp(2) + rv(2))/2;
plot(mid_x, mid_y, '.r', 'MarkerSize', 0.000001)
end
this is what I'm getting instead:
triangle
Does anyone know how to fix it?
I see two issues:
You've reset r to a random value each time through the loop and then performed a computation that puts it in one of the three sub-triangles that appear in your image. Rather than doing that, you should redefine r each time in terms of its previous value. That's the basic idea behind iteration in general.
I'm not sure what the computation involving the square root is for. The basic computation for a Sierpinski triangle simply moves the current point r half the way to one of the three vertices of the triangle, which is randomly chosen. That's correctly done in your definition of mid_x and mid_y.
Taking this all into account, we get something that looks like so:
axis off
hold on
r = [rand() rand()]; % Define initial value of r outside the loop
v1 = [-1 0 1];
v2 = [0 sqrt(3) 0];
for i = 1:10000
num = randi([1 3], 1);
rv = [v1(num) v2(num)];
mid_x = (r(1) + rv(1))/2;
mid_y = (r(2) + rv(2))/2;
r = [mid_x mid_y]; % Redefine r each time through the loop
plot(mid_x, mid_y, '.r', 'MarkerSize', 0.000001)
end

Intersection point between circle and line (Polar coordinates)

I'm wondering if there is a way of finding the intersection point between a line and a circle written in polar coordinates.
% Line
x_line = 10 + r * cos(th);
y_line = 10 + r * sin(th);
%Circle
circle_x = circle_r * cos(alpha);
circle_y = circle_r * sin(alpha);
So far I've tried using the intersect(y_line, circle_y) function without any success. I'm relatively new to MATLAB so bear with me.
I have generalised the below so that other values than a=10 can be used...
a = 10; % constant line offset
th = 0; % constant angle of line
% rl = ?? - variable to find
% Coordinates of line:
% [xl, yl] = [ a + rl * cos(th), a + rl * sin(th) ];
rc = 1; % constant radius of circle
% alpha = ?? - variable to find
% Coordinates of circle:
% [xc, yc] = [ rc * cos(alpha), rc * sin(alpha) ];
We want the intersection, so xl = xc, yl = yc
% a + rl * cos(th) = rc * cos(alpha)
% a + rl * sin(th) = rc * sin(alpha)
Square both sides of both equations and sum them. Simplifying sin(a)^2 + cos(a)^2 = 1. Expanding brackets and simplifying further gives
% rl^2 + 2 * a * rl * (cos(th) + sin(th)) + 2 * a - rc^2 = 0
Now you can use the quadratic formula to get the value of rl.
Test discriminant:
dsc = (2 * a * (cos(th) + sin(th)) )^2 - 4 * (2 * a - rc^2);
rl = [];
if dsc < 0
% no intersection
elseif dsc == 0
% one intersection at
rl = - cos(th) - sin(th);
else
% two intersection points
rl = -cos(th) - sin(th) + [ sqrt(dsc)/2, -sqrt(dsc)/2];
end
% Get alpha from an earlier equation
alpha = acos( ( a + rl .* cos(th) ) ./ rc );
Now you have 0, 1 or 2 points of intersection of the line with the circle, from certain known and unknown values about each line. Essentially this is just simultaneous equations, see the start of this article for a basis of the maths
https://en.wikipedia.org/wiki/System_of_linear_equations
Do you need to do it numerically? This problem would have an easy analytical solution: The point (10 + r*cos(th),10 + r*sin(th)) is on a circle with radius R iff
(10+r*cos(th))^2 + (10+r*sin(th))^2 == R^2
<=> 200+r^2 + 2*r*(cos(th)+sin(th)) == R^2
<=> r^2 + 2*r*sqrt(2)*sin(th+pi/4) + 200 - R^2 = 0
which is a quadratic equation in r. If the discriminant is positive, there are two solutions (corresponding to two intersection points), otherwise, there are none.
If you work out the math, the condition for intersection is 100*(sin(2*th)-1)+circle_r^2 >= 0 and the roots are -10*sqrt(2)*sin(th+pi/4)*[1,1] + sqrt(100*(sin(2*th)-1)+circle_r^2)*[1,-1].
Here is a Matlab plot as an example for th = pi/3 and circle_r = 15. The magenta markers are calculated in closed-form using the equation shown above.

avoid loop matlab in 2D bspline surface interpolation

I want to speed up my code. I always use vectorization. But in this code I have no idea how to avoid the for-loop. I would really appreciate a hint how to proceed.
thank u so much for your time.
close all
clear
clc
% generating sample data
x = linspace(10,130,33);
y = linspace(20,100,22);
[xx, yy] = ndgrid(x,y);
k = 2*pi/50;
s = [sin(k*xx+k*yy)];
% generating query points
xi = 10:5:130;
yi = 20:5:100;
[xxi, yyi] = ndgrid(xi,yi);
P = [xxi(:), yyi(:)];
% interpolation algorithm
dx = x(2) - x(1);
dy = y(2) - y(1);
x_ = [x(1)-dx x x(end)+dx x(end)+2*dx];
y_ = [y(1)-dy y y(end)+dy y(end)+2*dy];
s_ = [s(1) s(1,:) s(1,end) s(1,end)
s(:,1) s s(:,end) s(:,end)
s(end,1) s(end,:) s(end,end) s(end,end)
s(end,1) s(end,:) s(end,end) s(end,end)];
si = P(:,1)*0;
M = 1/6*[-1 3 -3 1
3 -6 3 0
-3 0 3 0
1 4 1 0];
tic
for nn = 1:numel(P(:,1))
u = mod(P(nn,1)- x_(1), dx)/dx;
jj = floor((P(nn,1) - x_(1))/dx) + 1;
v = mod(P(nn,2)- y_(1), dy)/dy;
ii = floor((P(nn,2) - y_(1))/dy) + 1;
D = [s_(jj-1,ii-1) s_(jj-1,ii) s_(jj-1,ii+1) s_(jj-1,ii+2)
s_(jj,ii-1) s_(jj,ii) s_(jj,ii+1) s_(jj,ii+2)
s_(jj+1,ii-1) s_(jj+1,ii) s_(jj+1,ii+1) s_(jj+1,ii+2)
s_(jj+2,ii-1) s_(jj+2,ii) s_(jj+2,ii+1) s_(jj+2,ii+2)];
U = [u.^3 u.^2 u 1];
V = [v.^3 v.^2 v 1];
si(nn) = U*M*D*M'*V';
end
toc
scatter3(P(:,1), P(:,2), si)
hold on
mesh(xx,yy,s)
This is the full example and is a cubic B-spline surface interpolation algorithm in 2D space.

Sequence of dots in matlab and psychotoolbox

How would i display one by one dots that are in a 3x3 matrix such as in the code below?
I would like to have dot1 appears in position [x1,y1] of the grid for a time t1, then dot2 to appears in position [x2,y2] of the grid for a time t2. Only one dot is being shown at each time.
Thanks for help
%grid
dim = 1
[x, y] = meshgrid(-dim:1:dim, -dim:1:dim);
pixelScale = screenYpixels / (dim * 2 + 2);
x = x .* pixelScale;
y = y .* pixelScale;
% Calculate the number of dots
numDots = numel(x);
% Make the matrix of positions for the dots.
dotPositionMatrix = [reshape(x, 1, numDots); reshape(y, 1, numDots)];
% We can define a center for the dot coordinates to be relaitive to.
dotCenter = [xCenter yCenter];
dotColors = [1 0 0];
dotSizes = 20;
Screen('DrawDots', window, dotPositionMatrix,...
dotSizes, dotColors, dotCenter, 2);
I think you want something like this?
%positions of each successive dots:
x_vec = [1,2,3,1,2,3,1,2,3];
y_vec = [1,1,1,2,2,2,3,3,3];
%wait times in sec for each dot:
wait_times = [1,1,2,1,1,2,1,1,2]
dotColor = [1 0 0];
dotSize = 400;
num_dots = length(x_vec);
for i = 1:num_dots
scatter(x_vec(i),y_vec(i),dotSize,dotColor,'filled');
xlim([0,max(x_vec)])
ylim([0,max(y_vec)])
pause(wait_times(i));
end

How can I plot a 3D-plane in Matlab?

I would like to plot a plane using a vector that I calculated from 3 points where:
pointA = [0,0,0];
pointB = [-10,-20,10];
pointC = [10,20,10];
plane1 = cross(pointA-pointB, pointA-pointC)
How do I plot 'plane1' in 3D?
Here's an easy way to plot the plane using fill3:
points=[pointA' pointB' pointC']; % using the data given in the question
fill3(points(1,:),points(2,:),points(3,:),'r')
grid on
alpha(0.3)
You have already calculated the normal vector. Now you should decide what are the limits of your plane in x and z and create a rectangular patch.
An explanation : Each plane can be characterized by its normal vector (A,B,C) and another coefficient D. The equation of the plane is AX+BY+CZ+D=0. Cross product between two differences between points, cross(P3-P1,P2-P1) allows finding (A,B,C). In order to find D, simply put any point into the equation mentioned above:
D = -Ax-By-Cz;
Once you have the equation of the plane, you can take 4 points that lie on this plane, and draw the patch between them.
normal = cross(pointA-pointB, pointA-pointC); %# Calculate plane normal
%# Transform points to x,y,z
x = [pointA(1) pointB(1) pointC(1)];
y = [pointA(2) pointB(2) pointC(2)];
z = [pointA(3) pointB(3) pointC(3)];
%Find all coefficients of plane equation
A = normal(1); B = normal(2); C = normal(3);
D = -dot(normal,pointA);
%Decide on a suitable showing range
xLim = [min(x) max(x)];
zLim = [min(z) max(z)];
[X,Z] = meshgrid(xLim,zLim);
Y = (A * X + C * Z + D)/ (-B);
reOrder = [1 2 4 3];
figure();patch(X(reOrder),Y(reOrder),Z(reOrder),'b');
grid on;
alpha(0.3);
Here's what I came up with:
function [x, y, z] = plane_surf(normal, dist, size)
normal = normal / norm(normal);
center = normal * dist;
tangents = null(normal') * size;
res(1,1,:) = center + tangents * [-1;-1];
res(1,2,:) = center + tangents * [-1;1];
res(2,2,:) = center + tangents * [1;1];
res(2,1,:) = center + tangents * [1;-1];
x = squeeze(res(:,:,1));
y = squeeze(res(:,:,2));
z = squeeze(res(:,:,3));
end
Which you would use as:
normal = cross(pointA-pointB, pointA-pointC);
dist = dot(normal, pointA)
[x, y, z] = plane_surf(normal, dist, 30);
surf(x, y, z);
Which plots a square of side length 60 on the plane in question
I want to add to the answer given by Andrey Rubshtein, his code works perfectly well except at B=0. Here is the edited version of his code
Below Code works when A is not 0
normal = cross(pointA-pointB, pointA-pointC);
x = [pointA(1) pointB(1) pointC(1)];
y = [pointA(2) pointB(2) pointC(2)];
z = [pointA(3) pointB(3) pointC(3)];
A = normal(1); B = normal(2); C = normal(3);
D = -dot(normal,pointA);
zLim = [min(z) max(z)];
yLim = [min(y) max(y)];
[Y,Z] = meshgrid(yLim,zLim);
X = (C * Z + B * Y + D)/ (-A);
reOrder = [1 2 4 3];
figure();patch(X(reOrder),Y(reOrder),Z(reOrder),'r');
grid on;
alpha(0.3);
Below Code works when C is not 0
normal = cross(pointA-pointB, pointA-pointC);
x = [pointA(1) pointB(1) pointC(1)];
y = [pointA(2) pointB(2) pointC(2)];
z = [pointA(3) pointB(3) pointC(3)];
A = normal(1); B = normal(2); C = normal(3);
D = -dot(normal,pointA);
xLim = [min(x) max(x)];
yLim = [min(y) max(y)];
[Y,X] = meshgrid(yLim,xLim);
Z = (A * X + B * Y + D)/ (-C);
reOrder = [1 2 4 3];
figure();patch(X(reOrder),Y(reOrder),Z(reOrder),'r');
grid on;
alpha(0.3);