I'm trying to fill the intersecting area between two circles in Matlab. I've quite literally copied and pasted this piece of code from this article on Matlab Central.
t = linspace(0, 2*pi, 100);
cir = #(r,ctr) [r*cos(t)+ctr(1); r*sin(t)+ctr(2)]; % Circle Function
c1 = cir(1.0, [0; 0]);
c2 = cir(1.5, [1; 1]);
in1 = find(inpolygon(c1(1,:), c1(2,:), c2(1,:), c2(2,:))); % Circle #1 Points Inside Circle #2
in2 = find(inpolygon(c2(1,:), c2(2,:), c1(1,:), c1(2,:))); % Circle #2 Points Inside Circle #1
[fillx,ix] = sort([c1(1,in1) c2(1,in2)]); % Sort Points
filly = [c1(2,in1) (c2(2,in2))];
filly = filly(ix);
figure(1)
plot(c1(1,:), c1(2,:))
hold on
plot(c2(1,:), c2(2,:))
fill([fillx fliplr(fillx)], [filly fliplr(filly)], 'g', 'EdgeColor','none')
hold off
axis square
What I end up with is the following image:
However, it should appear as this image:
Why is the area not being filled as it is in the example article?
If you have Mapping Toolbox you can use polybool to find the intersection between to polygones, and than patch (which dosen't require Mapping Toolbox, and is better than fill) to draw it. The folowing code works even without the first 2 lines that use poly2cw, but it issues some warnings. This can be solved with the poly2cw trasfomation:
[c1(1,:), c1(2,:)] = poly2cw(c1(1,:), c1(2,:)); % clock-wise transform
[c2(1,:), c2(2,:)] = poly2cw(c2(1,:), c2(2,:)); % clock-wise transform
[xb, yb] = polybool('intersection',c1(1,:),c1(2,:),c2(1,:), c2(2,:));
plot(c1(1,:), c1(2,:))
hold on
plot(c2(1,:), c2(2,:))
patch(xb, yb, 1, 'FaceColor', 'g','EdgeColor','none')
axis equal
The code in the question does not work because it has some mistake in the order of the points in fillx and filly. We can see that if we set the 'EdgeColor' to be visible, and follow the peripheral line of the patch (see below, here reduced to 20 points, for the illustration). We can clearly see that the point of the polygon to be filled are ordered in a 'zig-zag' between the circles, so it has no area at all. I have numbered the vertices of the polygon taken from each circle to demonstrate in what order the fill function read them.
In order to fill with color all the intersection between the circles, we need to define the 'polygon' by the points on the circles that intersect (in1 and in2) in the right order. This means we want them to make a closed shape if an imaginary pencil is drawing a line between them in the same order they are given. Like this:
We start with 1 in one of the circles and continue until the numbers on that circle are ended, and then move to 1 on the other circle, and when we reach the end in the second circle we close the polygon by connecting the last point to the first one. As you can see in both figure above, the starting point and the end point of the circles are really close, so we get 2 numbers above each other.
How can we order the points correctly?
We start by getting in1 and in2 as described in the question. Let's take a look at in1:
in1 =
1 2 3 4 5 6 7 19 20
Those are the indices of the points from c1 to be taken, they appear to be in order, but contains a gap. This gap is because inpolygon checks the points by the order in c1, and the starting point of c1 is within the intersection region. So we get the first 7 points, then we are out of the intersection, and we go back in as we reach points 19 and 20. However, for our polygon, we need this points to start from the closest point to one of that places where the circle intersect and to go around the circle until we reach the second point of intersection.
To do that, we look for the 'gap' in the points order:
gap = find(diff(in1)>1);
and reorder them correctly:
X1 = [c1(1,in1(gap+1:end)) c1(1,in1(1:gap))];
Y1 = [c1(2,in1(gap+1:end)) c1(2,in1(1:gap))];
But, there may be no 'gap', as we see in in2:
in2 =
11 12 13 14
So we need to wrap this within an if to check if the points need to be reordered:
if ~isempty(gap)
X1 = [c1(1,in1(gap+1:end)) c1(1,in1(1:gap))];
Y1 = [c1(2,in1(gap+1:end)) c1(2,in1(1:gap))];
else
X1 = c1(1,in1);
Y1 = c1(2,in1);
end
Now all we need to do it to concatenate X1 and X2 (for circle 2), and the same for the Ys, and use patch (which is like fill, but better) to draw it:
patch([X1 X2],[Y1 Y2],'g','EdgeColor','none')
With 20 points the circle is not really a circle and the intersection is partially colored, so here is the full code and the result with 200 points:
t = linspace(0, 2*pi, 200);
cir = #(r,ctr) [r*cos(t)+ctr(1); r*sin(t)+ctr(2)]; % Circle Function
c1 = cir(1.0, [0; 0]);
c2 = cir(1.5, [1; 1]);
plot(c1(1,:), c1(2,:))
hold on
plot(c2(1,:), c2(2,:))
axis equal
in1 = find(inpolygon(c1(1,:), c1(2,:), c2(1,:), c2(2,:)));
in2 = find(inpolygon(c2(1,:), c2(2,:), c1(1,:), c1(2,:)));
gap = find(diff(in1)>1);
if ~isempty(gap)
X1 = [c1(1,in1(gap+1:end)) c1(1,in1(1:gap))];
Y1 = [c1(2,in1(gap+1:end)) c1(2,in1(1:gap))];
else
X1 = c1(1,in1);
Y1 = c1(2,in1);
end
gap = find(diff(in2)>1);
if ~isempty(gap)
X2 = [c2(1,in2(gap+1:end)) c2(1,in2(1:gap))];
Y2 = [c2(2,in2(gap+1:end)) c2(2,in2(1:gap))];
else
X2 = c2(1,in2);
Y2 = c2(2,in2);
end
patch([X1 X2],[Y1 Y2],'g','EdgeColor','none')
hold off
All mentioned above could be replace with the use of convhull on the vertices that intersect and give the same result:
x = [c1(1,in1) c2(1,in2)]; % all x's for intersecting vertices
y = [c1(2,in1) c2(2,in2)]; % all y's for intersecting vertices
k = convhull(x,y); % calculate the convex polygon
patch(x(k),y(k),'g','EdgeColor','none')
This question already has an answer here:
Draw ellipse in MATLAB
(1 answer)
Closed 6 years ago.
Any ellipse can be uniquely defined by five parameters i.e. center x0 and y0, semi-major aixs length a, semi minor axis length b, and orientation angle theta. I have parameters x0, y0, a, b, and theta. How can I exactly draw the ellipse?
Some researches are necessary before to ask this kind of question. Mainly if the question was asked too much time.
You can do something like this :
Let (x1,y1) and (x2,y2) be the coordinates of the two vertices of the ellipse's major axis, and let e be its eccentricity.
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,'y-')
axis equal
I don't have time to test it, but it should work.
Next time, please read this section : How do I ask a good question
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have a binary image of the hand like that:
I have to write a Matlab function that detects the valley between two fingers.
The parameters are the binary image and the coordinates of the two finger's tips.
I'm new in image processing and I don't know how to start.
I suggest to isolate the black area between the two input points, and then find the highest point in this connected component.
You can try the following approach (you may need to tweak some of the parameters, but it should be a good start).
I = rgb2gray(imread('<your path>'));
%input parameters - points which represents two finger tips.
x1 = 408; y1 = 441;
x2 = 454; y2 = 373;
%binarize image
I = im2bw(I);
%noise reduction - close holes
I2 = imclose(I,strel('disk',10));
%draw a line between p1 and p2
ind = drawline([y1 x1],[y2 x2],size(I));
lineMat = zeros(size(I));
lineMat(ind) = 1;
%adds the line to the image
I2 = I2 | lineMat;
%finds a point in the middle of the line
[lineY, lineX] = ind2sub(size(I),ind);
midX = lineX(ceil(length(ind)/2));
midY = lineY(ceil(length(ind)/2));
%finds a point which resides in the connected component which is between
%the line and the two finger.
xSeed = midX;
ySeed = midY -5;
%perform imfill operation, starting from (xSeed,ySeed),
%in order to find the conected component in which the point (xSeed,ySeed)
%resides.
diffMat = imfill(I2,[ySeed xSeed])~=I2;
%finding the highest point in this connected component
[Y, X] = ind2sub(size(diffMat),find(diffMat));
minInd = find(Y==min(Y),1,'first');
yValley = Y(minInd);
xValley = X(minInd);
%presents result
imshow(I);hold on;
plot(x1,y1,'r.','MarkerSize',20);
plot(x2,y2,'r.','MarkerSize',20);
plot(xValley,yValley,'b.','MarkerSize',20);
*draw line function is taken from drawline webpage.
Final result (input points in red, output point in blue).
It's just the algorithm, but all these function certainly exist in MatLab:
Compute the convex hull
Compute the difference: Convex Hull minus the original shape. Then you have all the valleys you are looking for, plus some small patterns.
Connected components labeling.
Delete the small components. Then you have all the valleys between the fingers.
Then you can select the one you want using the fingertip coordinates.
I would like to find the two (2) intersection points when a linear line goes through a circle's centrum (x,y).
r = 13 radius
x = 0 x-coordinate
y = 7 y-coordinate
k = 9 slope value(?) y=kx+m y=9x+m
So first I'm drawing a circle with r=13 and a centrum of (0,7).
r=13
x=0
y=7
k=9
hold on
z = 0:pi/50:2*pi;
xunit = r * cos(z) + x;
yunit = r * sin(z) + y;
plot(xunit, yunit);
I'm wondering if it would be possible to plot up a circle in an easier way? Something like
(x−cx)^2 + (y −cy)^2 = r^2
(x-0)^2 + (y-7) = 13^2
I've tried this
plot((x−cx)^2 + (y −cy)^2 = r^2)
It doesn't do anything at all so the code must be incorrect.
Well, then I'm drawing the linear equation by calculating
y=kx+m
k=9
the line goes thorugh (0,7)
7=9*0+m
m=7
y=9x+7
so since I'm new to MatLab it took me a while to actually draw the line. I didn't find any easy function to plot it so I plotted a line like this:
I took some random values for x or y and calculated some coordinates.
(0,7)
(2,25)
(-2,-11)
plot([-2,2],[-11,25])
Result image: http://i.imgur.com/ag6HJlm.jpg
So now I just need to solve the intersection points with "solve" function. So well I would really appreciate some help!
best regards
Here is one approach to it:
%Place your lines and figures on the grid
linexypos = eye(100);
shapexypos = flipud(eye(100)) ;
% Guess where they come together
intersection = filter2(ones(3),linexypos + shapexypos);
[quality, loc] = max(intersection(:))
Note that you have to guess, as two lines with widths of 1 pixel may not have exactly the same location. (consider [1 0; 0 1] and [0 1;1 0], they cross but never exactly overlap).
If you want to visualize the situation, try contour(intersection)
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
This is the 2 body kepler problem.
The Hamiltonian is
This is supposed to be an "ellipse". How in the name of all that is holy can it be an ellipse when the initial values only have velocity components on one axis, and starting coordinates are on the same axis?
How do you plot the numerical solution using backwards euler?
I convert the two second-order equations into four first-order equations and solve using ode23 (not backwards Euler, but a different numerical method).
odefun = #(t, y) [y(3);
y(4);
-y(1) / (y(1)^2 + y(2)^2)^(3/2);
-y(2) / (y(1)^2 + y(2)^2)^(3/2)]
p0 = [1 0]; % initial position
v0 = [0 1]; % initial velocity
[t y] = ode23(odefun, [0 20], [p0 v0])
comet(y(:,1), y(:,2))
You can see now that the path traced is an ellipse (actually a circle for my initial velocity). You can play with the inital conditions (v0 = [0 1.1] gives you an ellipse).
Maybe i missunderstood what the system actually means, but what i see is a system with two bodies only under the influence of each others gravity. Starting position for body 1 is not a vector, but only a scalar, so it can only be located on the X axis. In this case it's coordinates are x = 1-a (0 < a < 1). Body 2 has it's starting position on x=0. Now, there is no force vectors pointing them away from the x axis, since the gravity gradient always is parallell to that same axis. The starting velocity is of course also a scalar, so there is no initial veolcity pointing them anywhere but on a parallell trajectory to the x axis.
When you say "this forms an ellipse", maybe i'm looking at the wrong coordinate system. I did the forward Euler plots as follows:
clear all, close all, clc
stl= 0.0005; % steplength
nos = 50000; % number of steps
q1 = zeros(1,nos);
q2 = zeros(1,nos);
q1v = zeros(1,nos);
q2v = zeros(1,nos);
q1a = zeros(1,nos);
q2a = zeros(1,nos);
% Starting positions
a=0.5;
q1(1) = 1-a;
q2(1) = 0;
q1v(1) = 0;
q2v(1) = sqrt((1+a)/(1-a));
% P is inertia, and has the same vector components as the body velocity
for i=1:nos-1
[q1a(i),q2a(i)] = u1FUNC(q1(i),q2(i));
q1v(i+1) = q1v(i) + q1a(i).*stl;
q2v(i+1) = q2v(i) + q2a(i).*stl;
q1(i+1) = q1(i) + q1v(i+1)*stl;
q2(i+1) = q2(i) + q2v(i+1)*stl;
end
plot(q1)
hold on
plot(q2,'r')
u1FUNC
function [a,b] = func(c,d)
% [a,b] = [q1'',q2'']
% [c,d] = [q1,q2]
a = -c/(((c^2)+(d^2))^(3/2));
b = -d/(((c^2)+(d^2))^(3/2));
end
Now, this code gives a plot where q1 and q2 are plotted with q1 and q2 on the y axis and time on the x axis, which seems logical to me, if q1 and q2 decribes the distance for the body in question from the origo in a non-moving reference system. But how do you make it look like an ellipse?