Create a spiral between two cartesian points in MATLAB - matlab

Perhaps this is a basic question but I haven't been able to find anything specifically like this and I'm wondering how to do it in the best way.
I have two sets of points (x1,y1,z1) and (x2,y2,z2) and I have converted them into polar coordinates. I would like to create a counter-clockwise helix of decreasing radius to reach the second point.
I would also like to specify how many revolutions it takes.
All of the examples I have seen are two points on the x axis and going clockwise.
Any suggestions would be very much appreciated!
Thanks.

This example code generates a counter clockwise spiral from p1 to p2 that isn't on x-axis and you can specify the number of revolutions. However it is in 2D and initial points are in cartesian coordinates. I'm not sure how to do it in 3D but I hope this can help you with the offsetting and the counter-clockwising.
%random 2d points
p1 = [3,5];
p2 = [1,4];
%radius of first point to second
r = norm(p1-p2);
%angle between two point wrt the y-axis
theta_offset = tan((p1(2)- p2(2))/(p1(1)-p2(1)));
rez = 150; % number of points
rev = 5; % number of revolutions
t = linspace(0,r,rez); %radius as spiral decreases
theta = linspace(0,2*pi*rev,rez) + theta_offset; %angle as spiral decreases
x = cos(theta).*t+p2(1);
y = sin(theta).*t+p2(2);
plot(x,y)

Related

Plotting Two Ellipses with same Foci in Matlab

I am trying to plot two different ellipses in Matlab with the same foci. Essentially I am plotting the elliptical orbit before and after an impulse maneuver.
The first (before maneuver) ellipse will always be in-line with the x-axis, whereas the second ellipse (after maneuver) will be at an angle above/below the x-axis (The second one will have a different major/minor axis and eccentricity as well).
In order to save space, the code for plotting one ellipse will be the same as the second ellipse, so I'll only show my code here for plotting one ellipse.
The problem is that it plots from the center of the grid, and not the foci.
Re = 6378.136; %km
e = .65;
x1 = -4.4*Re; %-a
x2 = 4.4*Re; % a
y1 = 0;
y2 = 0;
a = 1/2*sqrt((x2-x1)^2+(y2-y1)^2);
b = a*sqrt(1-e^2);
t = linspace(0,2*pi);
X = a*cos(t);
Y = b*sin(t);
w = atan2(y2-y1,x2-x1);
x = (x1+x2)/2 + X*cos(w) - Y*sin(w);
y = (y1+y2)/2 + X*sin(w) + Y*cos(w);
plot(x,y,'b')
axis equal
grid on
hold on
I'm sure it's something simple but I can't seem to figure it out.
Any help is much appreciated. Thanks.
Edit: David helped solve this issue, thank you.

How to create random points alongside a complex polyline?

I would like to populate random points on a 2D plot, in such a way that the points fall in proximity of a "C" shaped polyline.
I managed to accomplish this for a rather simple square shaped "C":
This is how I did it:
% Marker color
c = 'k'; % Black
% Red "C" polyline
xl = [8,2,2,8];
yl = [8,8,2,2];
plot(xl,yl,'r','LineWidth',2);
hold on;
% Axis settings
axis equal;
axis([0,10,0,10]);
set(gca,'xtick',[],'ytick',[]);
step = 0.05; % Affects point quantity
coeff = 0.9; % Affects point density
% Top Horizontal segment
x = 2:step:9.5;
y = 8 + coeff*randn(size(x));
scatter(x,y,'filled','MarkerFaceColor',c);
% Vertical segment
y = 1.5:step:8.5;
x = 2 + coeff*randn(size(y));
scatter(x,y,'filled','MarkerFaceColor',c);
% Bottom Horizontal segment
x = 2:step:9.5;
y = 2 + coeff*randn(size(x));
scatter(x,y,'filled','MarkerFaceColor',c);
hold off;
As you can see in the code, for each segment of the polyline I generate the scatter point coordinates artificially using randn.
For the previous example, splitting the polyline into segments and generating the points manually is fine. However, what if I wanted to experiment with a more sophisticated "C" shape like this one:
Note that with my current approach, when the geometric complexity of the polyline increases so does the coding effort.
Before going any further, is there a better approach for this problem?
A simpler approach, which generalizes to any polyline, is to run a loop over the segments. For each segment, r is its length, and m is the number of points to be placed along that segment (it closely corresponds to the prescribed step size, with slight deviation in case the step size does not evenly divide the length). Note that both x and y are subject to random perturbation.
for n = 1:numel(xl)-1
r = norm([xl(n)-xl(n+1), yl(n)-yl(n+1)]);
m = round(r/step) + 1;
x = linspace(xl(n), xl(n+1), m) + coeff*randn(1,m);
y = linspace(yl(n), yl(n+1), m) + coeff*randn(1,m);
scatter(x,y,'filled','MarkerFaceColor',c);
end
Output:
A more complex example, using coeff = 0.4; and xl = [8,4,2,2,6,8];
yl = [8,6,8,2,4,2];
If you think this point cloud is too thin near the endpoints, you can artifically lengthen the first and last segments before running the loop. But I don't see the need: it makes sense that the fuzzied curve is thinning out at the extremities.
With your original approach, two places with the same distance to a line can sampled with a different probability, especially at the corners where two lines meet. I tried to fix this rephrasing the random experiment. The random experiment my code does is: "Pick a random point. Accept it with a probability of normpdf(d)<rand where d is the distance to the next line". This is a rejection sampling strategy.
xl = [8,4,2,2,6,8];
yl = [8,6,8,2,4,2];
resolution=50;
points_to_sample=200;
step=.5;
sigma=.4; %lower value to get points closer to the line.
xmax=(max(xl)+2);
ymax=(max(yl)+2);
dist=zeros(xmax*resolution+1,ymax*resolution+1);
x=[];
y=[];
for n = 1:numel(xl)-1
r = norm([xl(n)-xl(n+1), yl(n)-yl(n+1)]);
m = round(r/step) + 1;
x = [x,round(linspace(xl(n)*resolution+1, xl(n+1)*resolution+1, m*resolution))];
y = [y,round(linspace(yl(n)*resolution+1, yl(n+1)*resolution+1, m*resolution))];
end
%dist contains the lines:
dist(sub2ind(size(dist),x,y))=1;
%dist contains the normalized distance of each rastered pixel to the line.
dist=bwdist(dist)/resolution;
pseudo_pdf=normpdf(dist,0,sigma);
%scale up to have acceptance rate of 1 for most likely pixels.
pseudo_pdf=pseudo_pdf/max(pseudo_pdf(:));
sampled_points=zeros(0,2);
while size(sampled_points,1)<points_to_sample
%sample a random point
sx=rand*xmax;
sy=rand*ymax;
%accept it if criteria based on normal distribution matches.
if pseudo_pdf(round(sx*resolution)+1,round(sy*resolution)+1)>rand
sampled_points(end+1,:)=[sx,sy];
end
end
plot(xl,yl,'r','LineWidth',2);
hold on
scatter(sampled_points(:,1),sampled_points(:,2),'filled');

Documenting matlab code for generating random shapes

Can you please help me document this Matlab code that is supposed to produce random shapes?? The wiggliness of the shapes is supposed to be controlled by the variable degree...
But how the rho (radius values) are produced... I can't really get it....
degree = 5;
numPoints = 1000;
blobWidth = 5;
theta = 0:(2*pi)/(numPoints-1):2*pi;
coeffs = rand(degree,1);
rho = zeros(size(theta));
for i = 1:degree
rho = rho + coeffs(i)*sin(i*theta);
end
phase = rand*2*pi;
[x,y] = pol2cart(theta+phase, rho+blobWidth);
plot(x,y)
axis equal
set(gca,'Visible','off')
theta = 0:(2*pi)/(numPoints-1):2*pi;
So this is just a vector of angles in a revolution, if you plot this theta against a constant rho (after calling pol2cart) you will get a circle:
r = ones(size(theta));
[x,y] = pol2cart(theta, r);
plot(x,y)
axis equal
This should be obvious if you understand what pol2cart does because you have a series of all the angles in a circle and a constant radius for all of them. If you don't understand that (i.e. polar coordinates) then that's a very basic mathematical concept you need to go and read up on your own before trying to understand this code.
OK so now a circle in cartesian coords is just a line in polar coords (i.e. plot(theta, r) noting that the horizontal axis now represents angle and the vertical represents radius). So if we want to randomly mess up our circle, we could randomly mess up our line. Using sin does this in a nice smooth way. Adding random frequencies of many sin waves adds less and less predictable "jitter". I think it would help you to understand if you add the following line to your code:
rho = zeros(size(theta));
hold all
for i = 1:degree
rho = rho + coeffs(i)*sin(i*theta);
plot(theta, rho)
end
and contrast this to (be sure to close your figure window before running this)
rho = zeros(size(theta));
hold all
for i = 1:degree
rho = rho + coeffs(i)*sin(i*theta);
plot(theta, coeffs(i)*sin(i*theta))
end
The second one shows you the different frequencies of sin waves used and the first shows how these sum to create unpredictable wavy lines. Now think of the pol2rect function as bending these lines around to make a "circle". If the line is dead straight you get a perfect circle, if it's wavy you get a "wavy" circle.
degree in your code just controls how many sin waves to add up.
finally phase = rand*2*pi; just randomly rotates your shape after it has been created.
Well, this was an amazing piece of code! But regarding rho. What is done is that you have a circle with base radius of 5 (blobwidth) and then you have a random offset coeffs. Then the offset is added to rho in rho = rho + coeffs(i)*sin(i*theta);. This means that the first loop an offset is added to the circle with frequency 1Hz. This then yields a constant offset. The next loop the frequency increases to 2Hz. Then the offset will be added to every second point and the offset may be negative as well. Then it goes on like this. Finally the coordinate is transformed to polar.
A few comments though. The most readable and the easiest way to create theta is to use linspace. And also, since rho is overwritten in the loop, you may as well define it just as rho = 0;

Finding the first point of great circle Intersection

I have a problem I've been trying to solve and I cannot come up with the answer. I have written a function in Matlab which, given two lat/lon points and two bearings, will return the two great circle points of intersection.
However, what I really need is the first great circle point of intersection along the two initial headings. I.e. if two airplanes begin at lat/lon points 1 and 2, with initial bearings of bearing1 and bearing2, which of the two great circle intersection points is the first one they encounter? There are many solutions (using haversine) which will give me the closer of the two points, but I don't actually care about which is closer, I care about which I will encounter first given specific start points and headings. There are many cases where the closer of the two intersections is actually the second intersection encountered.
Now, I realize I could do this with lots of conditional statements for handling the different cases, but I figure there's got to be a way to handle it with regard to the order I take all my cross products (function code given below), but I simply can't come up with the right solution! I should also mention that this function is going to be used in a large computationally intensive model, and so I'm thinking the solution to this problem needs to be rather elegant/speedy. Can anyone help me with this problem?
The following is not my function code (I can't list that here), but it is the pseudo code that my function was based off of:
%Given inputs of lat1,lon1,Bearing1,lat2,lon2,Bearing2:
%Calculate arbitrary secondary point along same initial bearing from first
%point
dAngle = 45;
lat3 = asind( sind(lat1)*cosd(dAngle) + cosd(lat1)*sind(dAngle)*cosd(Bearing1));
lon3 = lon1 + atan2( sind(Bearing1)*sind(dAngle)*cosd(lat1), cosd(dAngle)-sind(lat1)*sind(lat3) )*180/pi;
lat4 = asind( sind(lat2)*cosd(dAngle) + cosd(lat2)*sind(dAngle)*cosd(Bearing2));
lon4 = lon2 + atan2( sind(Bearing2)*sind(dAngle)*cosd(lat2), cosd(dAngle)-sind(lat2)*sind(lat4) )*180/pi;
%% Calculate unit vectors
% We now have two points defining each of the two great circles. We need
% to calculate unit vectors from the center of the Earth to each of these
% points
[Uvec1(1),Uvec1(2),Uvec1(3)] = sph2cart(lon1*pi/180,lat1*pi/180,1);
[Uvec2(1),Uvec2(2),Uvec2(3)] = sph2cart(lon2*pi/180,lat2*pi/180,1);
[Uvec3(1),Uvec3(2),Uvec3(3)] = sph2cart(lon3*pi/180,lat3*pi/180,1);
[Uvec4(1),Uvec4(2),Uvec4(3)] = sph2cart(lon4*pi/180,lat4*pi/180,1);
%% Cross product
%Need to calculate the the "plane normals" for each of the two great
%circles
N1 = cross(Uvec1,Uvec3);
N2 = cross(Uvec2,Uvec4);
%% Plane of intersecting line
%With two plane normals, the cross prodcut defines their intersecting line
L = cross(N1,N2);
L = L./norm(L);
L2 = -L;
L2 = L2./norm(L2);
%% Convert normalized intersection line to geodetic coordinates
[lonRad,latRad,~]=cart2sph(L(1),L(2),L(3));
lonDeg = lonRad*180/pi;
latDeg = latRad*180/pi;
[lonRad,latRad,~]=cart2sph(L2(1),L2(2),L2(3));
lonDeg2 = lonRad*180/pi;
latDeg2 = latRad*180/pi;
UPDATE: A user on the Mathworks forums pointed this out:
Actually they might each reach a different point. I might have misunderstood the question, but the way you worded it suggests that both trajectories will converge towards the same point, which is not true. If you image the first point being a little after one intersection and the second point being a little after the other intersection, you have a situation were each "plane" will travel towards the intersection that was the closest to the other plane at the beginning.
I didn't think about this. It is actually very possible that each of the planes intersects a different great circle intersection first. Which just made things much more complicated...
Presumably you have a velocity vector for the direction of the plane (the direction in which you want to look for your first intersection - the "bearing vector on the surface of the earth"). You didn't actually specify this. Let us call it v.
You also have the cartesian coordinates of two points, P1 and P2, as well as the initial position of the plane, P0. Each is assumed to be already on the unit sphere (length = 1).
Now we want to know which is the shorter distance - to P1, or P2 - so we need to know the angle "as seen from the direction of the normal vector". For this we need both the sin and the cos - then we can find the angle using atan2. We obtain sin from the cross product (remember all vectors were normalized), and cos from the dot product. To get the sin "as seen from the right direction", we take dot product with the normal vector.
Here is a piece of code that puts it all together - I am using very simple coordinates for the points and direction vector so I can confirm in my head that this gives the correct answer:
% sample points of P0...P2 and v
P0 = [1 0 0];
P1 = [0 1 0];
P2 = [0 -1 0];
v = [0 1 0];
% compute the "start direction normal":
n0 = cross(P0, v);
n0 = n0 / norm( n0 ); % unit vector
% compute cross and dot products:
cr01 = cross(P0, P1);
cr02 = cross(P0, P2);
cos01 = dot(P0, P1);
cos02 = dot(P0, P2);
% to get sin with correct sign, take dot product with direction normal:
sin01 = dot(cr01, n0);
sin02 = dot(cr02, n0);
% note - since P0 P1 and P2 are all in the same plane
% cr02 and cr02 are either pointing in the same direction as n0
% or the opposite direction. In the latter case we get a sign flip for the sin
% in the former case this does nothing
% Now get the angle, mapped from 0 to 2 pi:
ang1 = mod(atan2(sin01, cos01), 2*pi);
ang2 = mod(atan2(sin02, cos02), 2*pi);
if( ang1 < ang2 )
fprintf(1,'point 1 is reached first\n');
% point 1 is the first one reached
else
fprintf(1,'point 2 is reached first\n');
% point 2 is the first
end
When you change the direction of the velocity vector (pointing towards P2 instead of P1), the program correctly tells you "point 2 is reached first".
Let me know if this works for you!

Calculate circular bins around a point + matlab

My question is related to this link stackoverflow ques
In essence repeating the figure drawn there .. I have a central point ( x , y ) in an image around which I have to draw 4 circles of 1-4 unit radius with 8 angles between them.
In this diagram there are 12 angle bins but I have 8. There is a code solution there but it is for plotting the above figure.
I want to calculate the maximum intensity point in each of the 4 regions of each wedge. Is there any inbuilt function in matlab ? I looked at rose but could'nt understand if it would help me....
I would greatly appreciate if someone could help me how to calculate it in matlab....
Thanks
I put some code below that should be the basic skeleton of what you want to do. But I left an important function unimplemented because I think you will be able to do it and it will help you understand this process better.
% I assume that data_points is an M-by-2 array, where each row corresponds
% to an (x,y) coordinate pair, and M is the number of data points.
data_points = ... ;
% I assume this array stores the intensities at each data point.
intensities = ... ;
% I assume that this stores the total number of gridded polar regions you want
% to find the max intensity in (i.e. 4*(number of cells) in your picture above).
total_num_bins = ... ;
% This will store the max intensities. For places that have no nearby
% data points, the max intensity will remain zero.
max_intensities = zeros(total_num_bins);
% I assume these store the values of the center point.
x = ... ; y = ... ;
% The number of different data points.
num_data_points = length(intensities); % also equals size(data_points,1)
% Now, loop through the data points, decide which polar bin they fall in, and
% update the max intensity of that area if needed.
for ii = 1:num_data_points
% Grab the current point coordinates.
cur_x = data_points[ii,1];
cur_y = data_points[ii,2];
% Convert the current data point to polar coordinates,
% keeping in mind that we are treating (x,y) like the center.
cur_radius = sqrt( (cur_x - x)^2 + (cur_y - y)^2 );
cur_angle = atan2(cur_y - y, cur_x - x)
% You have to write this yourself, but it
% will return an index for the bin that this
% data point falls into, i.e. which of the 4 segments
% of one of the radial cells it falls into.
cur_bin = get_bin_number(cur_radius, cur_angle);
% Check if this data point intensity is larger than
% the current max value for its bin.
if ( intensities(ii) >= max_intensities(cur_bin))
max_intensities(cur_bin) = intensities(ii);
end
end
You will now have to make the function get_bin_number() which takes as its input the angle and radius of the data point away from the center point. It should return just an index between 1 and total_num_bins, because you will be keeping the max intensities in a linear array. So, for example, index number 1 might correspond to the first 1/4 piece of the closest radial cell in the upper right quadrant, index 2 might correspond to the next 1/4 of that same cell, moving counter-clockwise, or something like this. You have to devise your own convention for keeping track of the bins.
A late answer, but I believe an even easier solution would just be to convert your data from (x,y) coordinates to (r,theta) by using (r = sqrt(x.^2 + y.^2), theta = atan(y,x)) then use the hist3 function on the (r,theta) data set to get a radial histogram.
Therefore solution is as follows:
% I assume you have some M-by-2 matrix X that's in the form (x,y)
% Convert (x,y) to (r,theta)
xVect = X(:,1);
yVect = X(:,2);
X = [sqrt(xVect.^2 + yVect.^2), ...%formula for r
atan(yVect,xVect)]; %formula for theta
% 5 is the number of wedges along 'r', your radial axis
% 12 is the number of wedges along 'theta', your theta 'axis'
dist = hist3(X,5,12);
Even if you have solved this, I hope this helps anybody else who wants to create a radial/angular histogram!