Intersection point between circle and line (Polar coordinates) - matlab

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.

Related

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

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)

Matlab - Plotting with for loop

I am new to matlab and am trying to loop through an equation from 1 to 1000 and plot the result, but every value is turning out the same and the plot is incrorrect.
Here is my current attempt, but the variable Rm is giving only one results (instead of 1000 separate ones):
Ds = 1.04e-10;
Gamma = 1.9;
Omega = 1.09e-29;
Deltas = 2.5e-10;
Boltzmann = 1.3806e-23;
T = 1123.15;
Beta = 0.83;
Zo = 6.7;
EtaNi = 0.39;
EtaYSZ = 0.61;
Rm0 = 0.29;
RmYSZ0 = 0.265;
lambda = 4.70e-3;
C = Ds * ((Gamma * Omega * Deltas) / (2 * Boltzmann * T)) * (Beta / ((1 - Beta^2) * ((1 + Beta^2)^0.5) * ((1 + Beta)^3))) * Zo * (EtaNi/((EtaNi/Rm0) + (EtaYSZ/RmYSZ0)));
tinit=1; % Initial time value (h)
tend=1000; % End time value (h)
tinc=1; % Increment in time value (h)
t= [tinit:tinc:tend]; % Time vector
n = 1000;
for i=1:n
Rm(i) = (((5*C)/lambda) * (1 - exp(-lambda*i)) + (Rm0)^5)^(1/5);
end
plot(t,Rm);
Expected result is an exponential curve, any help would be appreciated
Your term before R0 is an exponential that ranges from 0 to 4.5e-27. R0^5 is 0.0021. Floating point precision is not enough to preserve the first term when it is added to the second. So (5C/L*(...) + Rm0^5) == Rm0^5, so it is constant.

solving integral in rectangular method in matlab

This is my code to make an integration in the rectangular method in the matlab
f=#(x) (x^(1/2))
a = 1
b = 10
% step size
h = 0.25
n = 0 % the counter
xn= a + (n * h)
%%
%Rectangle Method:
s=0
for i =0:n-1
s = s + f(xn)
end
Rectangle = h * s
the answer should be around 20, but i'm getting 29.5
what's the problem?
Two errors:
1) xn is not updated.
2) number of points n is set to zero.
There are other minor issues which I did not fix, e.g. right and left boundary points should both contribute to the sum with weight 1/2.
Quick fix:
f=#(x) (x^(1/2));
a = 1;
b = 10 ;
% step size
h = 0.25;
n = (b-a)/h; % the counter
%%
%Rectangle Method:
s=0;
for i =0:n-1
xn= a + (i * h);
s = s + f(xn);
end
Rectangle = h * s;

How to create diagonal stripe patterns and checkerboard patterns?

Based on this question, I can confirm that horizontal patterns can be imposed onto a matrix (which in this case is an image), by multiplying it with a modulation signal created with this:
vModulationSignal = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
It would also be great if someone could explain to why the above modulation signal works.
Now I want to create diagonal patterns such as :
And criss-cross (checkered) patterns such as this:
using a similar vModulationSignal
Code Excerpt where the modulation signal is created
numRows = size(mInputImage, 1);
numCols = size(mInputImage, 2);
signalFreq = floor(numRows / 1.25);
vModulationSignal = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
mOutputImage = bsxfun(#times, mInputImage, vModulationSignal);
Code Excerpt where I'm trying to create the criss cross signal
numRows = size(mInputImage, 1);
numCols = size(mInputImage, 2);
signalFreq1 = floor(numRows / 1.25);
signalFreq2 = floor(numCols / 1.25);
vModulationSignal1 = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
vModulationSignal2 = 1 + (0.5 * cos(2 * pi * (signalFreq / numRows) * [0:(numRows - 1)].'));
mOutputImage = bsxfun(#times, mInputImage, vModulationSignal);
figure();
imshow(mOutputImage);
For horizontal, vertical, diagonal stripes:
fx = 1 / 20; % 1 / period in x direction
fy = 1 / 20; % 1 / period in y direction
Nx = 200; % image dimension in x direction
Ny = 200; % image dimension in y direction
[xi, yi] = ndgrid(1 : Nx, 1 : Ny);
mask = sin(2 * pi * (fx * xi + fy * yi)) > 0; % for binary mask
mask = (sin(2 * pi * (fx * xi + fy * yi)) + 1) / 2; % for gradual [0,1] mask
imagesc(mask); % only if you want to see it
just choose fx and fy accordingly (set fy=0 for horizontal stripes, fx=0 for vertical stripes and fx,fy equal for diagonal stripes). Btw. the period of the stripes (in pixels) is exactly
period_in_pixel = 1 / sqrt(fx^2 + fy^2);
For checkerboard patterns:
f = 1 / 20; % 1 / period
Nx = 200;
Ny = 200;
[xi, yi] = ndgrid(1 : Nx, 1 : Ny);
mask = sin(2 * pi * f * xi) .* sin(2 * pi * f * yi) > 0; % for binary mask
mask = (sin(2 * pi * f * xi) .* sin(2 * pi * f * yi) + 1) / 2; % for more gradual mask
imagesc(mask);
Here the number of black and white squares per x, y direction is:
number_squares_x = 2 * f * Nx
number_squares_y = 2 * f * Ny
And if you know the size of your image and the number of squares that you want, you can use this to calculate the parameter f.
Multiplying the mask with the image:
Now that is easy. The mask is a logical (white = true, black = false). Now you only have to decide which part you want to keep (the white or the black part).
Multiply your image with the mask
masked_image = original_image .* mask;
to keep the white areas in the mask and
masked_image = original_image .* ~mask;
for the opposite.
This is actually an extension of Trilarion's answer that gives better control on stripes appearance:
function out = diagStripes( outSize, stripeAngle, stripeDistance, stripeThickness )
stripeAngle = wrapTo2Pi(-stripeAngle+pi/2);
if (stripeAngle == pi/2) || (stripeAngle == 3*pi/2)
f = #(fx, fy, xi, yi) cos(2 * pi * (fy * yi)); % vertical stripes
elseif (stripeAngle == 0)||(stripeAngle == pi)
f = #(fx, fy, xi, yi) cos(2 * pi * (fx * xi)); % horizontal stripes
else
f = #(fx, fy, xi, yi) cos(2 * pi * (fx * xi + fy * yi)); % diagonal stripes
end
if numel(outSize) == 1
outSize = [outSize outSize];
end;
fx = cos(stripeAngle) / stripeDistance; % period in x direction
fy = sin(stripeAngle) / stripeDistance; % period in y direction
Nx = outSize(2); % image dimension in x direction
Ny = outSize(1); % image dimension in y direction
[yi, xi] = ndgrid((1 : Ny)-Ny/2, (1 : Nx)-Nx/2);
mask = (f(fx, fy, xi, yi)+1)/2; % for gradual [0,1] mask
out = mask < (cos(pi*stripeThickness)+1)/2; % for binary mask
end
outSize is a two or one element vector that gives the dimensions of output image in pixels, stripeAngle gives the slope of stripes in radians, stripeDistance is the distance between centers of stripes in pixels and stripeDistance is a float value in [0 .. 1] that gives the percent of coverage of (black) stripes in (white) background.
There're also answers to the other question for generating customized checkerboard patterns.

The distribution of chord lengths in a circle, Bertrand paradox

I want to write a program which will calculate the statistic in Bertrand paradox.
In my way, I want select two dot in circle , and pass line using them (two dots), it is my chord. Then I want to calculate how many of these chords are longer than sqrt(3); but when I run this script some of the chords are bigger than 2 ! ( radius of my circle is 1 )
I don't know what is wrong with it, can anybody help me?
See this link please for the formula used.
r1 = rand(1,1000000);
teta1 = 2*pi * rand(1,1000000);
x1 = r1 .* (cos(teta1));
y1 = r1 .* (sin(teta1));
r2 = rand(1,1000000);
teta2 = 2*pi * rand(1,1000000);
x2 = r2 .* (cos(teta2));
y2 = r2 .* (sin(teta2));
%solve this equation : solve('(t*x2 +(1-t)*x1)^2 +(t*y2 +(1-t)*y1)^2 =1', 't');
t1= ((- x1.^2.*y2.^2 + x1.^2 + 2*x1.*x2.*y1.*y2 - 2*x1.*x2 - x2.^2.*y1.^2 + x2.^2 + y1.^2 - 2*y1.*y2 + y2.^2).^(1/2) - x1.*x2 - y1.*y2 + x1.^2 + y1.^2)/(x1.^2 - 2*x1.*x2 + x2.^2 + y1.^2 - 2*y1.*y2 + y2.^2);
t2= -((- x1.^2.*y2.^2 + x1.^2 + 2*x1.*x2.*y1.*y2 - 2*x1.*x2 - x2.^2.*y1.^2 + x2.^2 + y1.^2 - 2*y1.*y2 + y2.^2).^(1/2) + x1.*x2 + y1.*y2 - x1.^2 - y1.^2)/(x1.^2 - 2*x1.*x2 + x2.^2 + y1.^2 - 2*y1.*y2 + y2.^2);
length = abs (t1-t2) * sqrt (( x2-x1).^2 + (y2-y1).^2);
hist(length)
flag = 0;
for check = length
if( check > sqrt(3) )
flag = flag + 1;
end
end
prob = (flag/1000000)^2;
Your formula for length is probably to blame for the nonsensical results, and given its length, it is easier to replace it than to debug. Here is another way to find the length of chord passing through two points (x1,y1) and (x2,y2):
Find the distance of the chord from the center
Use the Pythagorean theorem to find its length
In Matlab code, this is done by
distance = abs(x1.*y2-x2.*y1)./sqrt((x2-x1).^2+(y2-y1).^2);
length = 2*sqrt(1-distance.^2);
The formula for distance involves abs(x1.*y2-x2.*y1), which is twice the area of the triangle with vertices (0,0), (x1,y1), and (x2,y2). Dividing this quantity by the base of triangle, sqrt((x2-x1).^2+(y2-y1).^2), yields its height.
Also, putting 1000000 samples into mere 10 bins is a waste of information: you get a crude histogram for all that effort. Better to use hist(length,100).
Finally, your method of selecting two points through which to pass a line does not take them from the uniform distribution on the disk. If you want uniform distribution over the disk, use
r1 = sqrt(rand(1,1000000));
r2 = sqrt(rand(1,1000000));
because for a uniformly distributed point, the square of the distance to the center is uniformly distributed in [0,1].
Finally, I've no idea why you square in prob = (flag/1000000)^2.
Here is your code with aforementioned modifications.
r1 = sqrt(rand(1,1000000));
teta1 = 2*pi * rand(1,1000000);
x1 = r1 .* (cos(teta1));
y1 = r1 .* (sin(teta1));
r2 = sqrt(rand(1,1000000));
teta2 = 2*pi * rand(1,1000000);
x2 = r2 .* (cos(teta2));
y2 = r2 .* (sin(teta2));
distance = abs(x1.*y2-x2.*y1)./sqrt((x2-x1).^2+(y2-y1).^2);
length = 2*sqrt(1-distance.^2);
hist(length,100)
flag = 0;
for check = length
if( check > sqrt(3) )
flag = flag + 1;
end
end
prob = flag/1000000;