So I have 3 points in a 3D space with a curve passing through the points. I have found the tangent of the point in the middle by averaging the two points either side of it, but I want to find the Normal at the point in the middle. How would I do this without knowing the equation of the line?
`P(1) = (0,1,0)
P(2) = (2,2,2)
p(3) = (4,4,4)
Tangent at P(2) = (4,3,4)`
Thanks!
A = P2 - P1 ... vector between 2 points on the curve (one is the middle point .. P2)
normal = A x tangent
but as MBo pointed out there are infinite number of normals (all are perpendicular to the curve lying on the same plane)
above equation gives one perpendicular to curve and to that A vector
Related
Hi sorry for the confusing title.
I'm trying to make a race track using points. I want to draw 3 rectangles which form my roads. However I don't want these rectangles to overlap, I want to leave an empty space between them to place my corners (triangles) meaning they only intersect at a single point. Since the roads have a common width I know the width of the rectangles.
I know the coordinates of the points A, B and C and therefore their length and the angles between them. From this I think I can say that the angles of the yellow triangle are the same as those of the outer triangle. From there I can work out the lengths of the sides of the blue triangles. However I don't know how to find the coordinates of the points of the blue triangles or the length of the sides of the yellow triangle and therefore the rectangles.
This is an X-Y problem (asking us how to accomplish X because you think it would help you solve a problem Y better solved another way), but luckily you gave us Y so I can just answer that.
What you should do is find the lines that are the edges of the roads, figure out where they intersect, and proceed to calculate everything else from that.
First, given 2 points P and Q, we can write down the line between them in parameterized form as f(t) = P + t(Q - P). Note that Q - P = v is the vector representing the direction of the line.
Second, given a vector v = (x_v, y_v) the vector (y_v, -x_v) is at right angles to it. Divide by its length sqrt(x_v**2 + y_v**2) and you have a unit vector at right angles to the first. Project P and Q a distance d along this vector, and you've got 2 points on a parallel line at distance d from your original line.
There are two such parallel lines. Given a point on the line and a point off of the line, the sign of the dot product of your normal vector with the vector between those two lines tells you whether you've found the parallel line on the same side as the other, or on the opposite side.
You just need to figure out where they intersect. But figuring out where lines P1 + t*v1 and P2 + s*v2 intersect can be done by setting up 2 equations in 2 variables and solving that. Which calculation you can carry out.
And now you have sufficient information to calculate the edges of the roads, which edges are inside, and every intersection in your diagram. Which lets you figure out anything else that you need.
Slightly different approach with a bit of trigonometry:
Define vectors
b = B - A
c = C - A
uB = Normalized(b)
uC = Normalized(c)
angle
Alpha = atan2(CrossProduct(b, c), DotProduct(b,c))
HalfA = Alpha / 2
HalfW = Width / 2
uB_Perp = (-uB.Y, ub.X) //unit vector, perpendicular to b
//now calculate points:
P1 = A + HalfW * (uB * ctg(HalfA) + uB_Perp) //outer blue triangle vertice
P2 = A + HalfW * (uB * ctg(HalfA) - uB_Perp) //inner blue triangle vertice, lies on bisector
(I did not consider extra case of too large width)
I have a circle with origin at (cx, cy).
Radius is r.
Then, there is a line segment defined by
two points: (x1,y1) and (x2,y2).
How to determine if the line segment (not the extended line)
is tangent to the circle? And if yes, where do the two touch?
What I am doing now: find out the distance of the point
(cx, cy) from the extended line. If the distance != r, then
certainly the line segment is NOT tangent to circle. Even
if the distance == r, then we need to find out the point
where they touch. Then check whether that point lies on
the segment between (x1,y1) and (x2,y2). If yes, the line
segment IS tangent to the circle - and the touch point
is computed already. This works but involves too much math.
And all with float or double variables. Isn't there a
smarter, faster algorithm to achieve same result?
Thanks and regards,
Pramod
I recommend you stop reasoning with slopes because the singularity at the vertical is always nasty to deal with. Try instead the parametric form:
p = p1 + t v where v = p2 - p1
Now project the vector p1 - c onto v, take the derivative wrt t, set to zero, and you quickly have an expression for the value of t that describes the point on the infinite line closest to c, which is the tangent point:
(c - p1) dot v
t = --------------
v dot v
If this value is between 0 and 1, then the tangent point is between p1 and p2. This is a pretty cheap computation. When it's true, you can follow up with a radius check
(c - p1 - tv) dot (c - p1 - tv) ~= r^2 ?
Note the sub-term c - p1 is already calculated above.
You mentioned only the circle is moving, so you can compute v dot v once and save it.
You maybe aware of the property that if f(x,y) = y-m*x-c is the line segment then |f(x1,y1)|/sqrt(1+m^2) represents the distance of the line from (x1,y1). Hence:
double m = (y2-y1)/(x2-x1);//slope
double c = y1 - m*x1;//since (x1,y1) lies on the line f(x1,y1) is zero
double d = abs(cy - m*cx - c)/sqrt(1+m*m);//distance
if(d==r)//radius
//Yeah its tangent and do whatever you want
else
//Nope
And for the second part,pseudocode;
g1(x,y) = y+(1/m)*x-c1;//perpendicular line through (x1,y1)
g2(x,y) = y+(1/m)*x-c2;//perpendicular line through (x2,y2)
c1 = y1+(1/m)*x1;
c2 = y2+(1/m)*x2;
if(g1(cx,cy)*g2(cx,cy)<0)//condition if point lies between two lines.Here make sure the coeffecients of y and x are of same sign in g1 and g2
//yes
else
//no
By definition, a tangent line must be perpendicular to a radius line. In the picture below, the red line is a tangent line if, and only if, it's perpendicular to the green line (from the center to the point of contact).
So if you know the slope of the tangent line M (computed from (x1,y1) and (x2,y2)) then the slope of the radius line is -1/M. Given that you know
the center of the circle
the radius of the circle
the slope of the green line
it's easy to compute the point of contact. Actually there are two possible points of contact, on opposite sides of the circle.
So all you need to do is check whether either of the two possible points of contact are on the line segment.
I have two axis linked together ; Axis A, and Axis B. Axis B is attached to the end of Axis A and so its point of origin can vary with the angle of Axis A . Attached to Axis B is a Circle whose Diameter is 10 (and can become smaller). I need to move the edge point of the circle to intersect a Super-Ellipse at each of 38 Cartesian points x,y. So the end point of my axis B - center of the circle should follow the same basic path as the 38 points of the super ellipse - radius of circle. Once I have these points - I will need to determine the position of Axis A x_2,y_2 and angle (or more appropriately just the distance from 0 degree angle to reach the required angle to position x_2,y_2. I then need to position Axis B with relation to Axis A in order to have Axis B X_3,Y_3 match the following of the Super-Ellipse where the center of the circle is supposed to be.
I have a drawing attached and a plot in Excel where I am off as you can see the bow tie is not what I should have. I have also included the points to the super ellipse along with some quick points on the graph. I am not a math major - I am willing to learn if you post the name of an equation - so far I have learned about carnot, parametric equation for circles and formulas for parabolas - but I am still having trouble.
Axis A Radius 13" image is 90 degree rotation
X_Sub1 , Y_Sub1
-6.5 , 5
Axis B Radius 9" image is 180 degree rotation
X_Sub2 , Y_Sub2
6.5 , 5
Circle Diameter 10"
Circle Radius 5"
Super Ellipse
# 12"width
# 8.75" Deep Vertex -8.75
Points Along the Super Ellipse.
0.0000, 0.0000
0.2188, -0.6250
0.2188, -1.2500
0.2433, -1.8750
0.3290, -2.5000
0.4753, -3.1073
0.6804, -3.7091
0.9424, -4.2990
1.2585, -4.8712
1.6255, -5.4197
2.0397, -5.9388
2.4967, -6.4233
2.9920, -6.8682
3.5203, -7.2889
4.0764, -7.7213
4.6544, -8.0500
5.2285, -8.3553
5.7525, -8.5000
6.2188, -8.5516
6.6851, -8.5000
7.1891, -8.3553
7.7832, -8.0500
8.3612, -7.7213
8.9173, -7.2889
9.4456, -6.8682
9.9409, -6.4233
10.3979,-5.9388
10.8121,-5.4197
11.1791,-4.8712
11.4952,-4.2990
11.7572,-3.7091
11.9623,-3.1073
12.1086,-2.5000
12.1943,-1.8750
12.2188,-1.2500
12.2188,-0.6250
12.4376, 0.0000
First, suppose we have 3 points along the super-ellipse, p0 = (2.4967, -6.4233), p1 = (2.9920, -6.8682), and p2 = (3.5203, -7.2889). Let's figure out how to position it to touch the point p1.
First of all at the point p1 the tangent line should be very close to parallel to the line from p0 to p2. So it should be parallel to p2 - p0 = (3.5203, -7.2889) - (2.4967, -6.4233) = (1.0236, -0.8656). But you want the disk to be perpendicular to this. We can construct a perpendicular to the vector (x, y) by (-y, x), which gives us (0.8656, 1.0236) as a direction. (There are two perpendiculars, looking at the diagram this is obviously the correct one.) This means that we want to put the end of axis B a distance of 5 in that direction. Which means it needs to be a distance of 5 in the direction (0.8656, 1.0236) from p1 = (2.9920, -6.8682). So it should be at the position (2.9920, -6.8682) + 5 * (0.8656, 1.0236) / sqrt(0.8656^2 + 1.0236^2) = (6.22057, -3.050307).
Now that we know where the end of axis B is, assuming we know where the start of axis A is (you didn't specify that), we can use the law of cosines (see http://mathworld.wolfram.com/LawofCosines.html) to figure out the cos of the angles that you want. Now you can use the arccosine function to figure out the angles in question.
This procedure can be followed for every point. Figure out what you think it should be tangent to, find the orthogonal, find where you want the end of B to be, then you have a triangle that you can use the cosine law on.
I would like to check the intersection of two squares which are not axis-aligned. I know how to do it for axis-aligned squares. Can I extend the same idea?
Basically I want to distribute squares by gaussian distribution on the x-y plane in +ve quadrant say, but two squares should not be intersecting so I have to shift the original center of the square. Suggestions are welcome.
Separating axis theorem (link2) is suitable for effective checking of convex polygon intersection. For squares prerequisite (normals and so on) calculation becomes especially simple.
After almost 4-5 hours of thinking, I got one click. Just sharing if anyone needs this. PseudoCode
Input: Square1 and Square2
Bool(Sqaure1,square2)
for vertex v0 to v3 of sqaure 1
angle = 0;
for vertex P0 to P3 of square 2 (In anticlockwise of clockwise way)
angle = angle + angle(Pj,vi,P((j+1)%4));
if(abs(angle-360) == 0)
return true;
return false;
IDEA: point of one square inside or on the line of another square will have angle sum of 360 with all points if two squares intersects.So you can call function twice by swapping arguments and if anyone returns true then answer is yes.(Call twice or check if angle sum is 0 or 360 exactly)
If I am right, you can proceed as follows:
rotate both Sa and Sb so that Sa becomes axis-aligned;
check overlap of Sa' with the bounding box of Sb';
rotate both Sa and Sb so that Sb becomes axis-aligned;
check overlap of the bounding box of Sa" with Sb".
If there is a configuration with no overlap, then the squares are disjoint.
In analytical terms, the no-overlap conditions will have a form like
C1 + C2 (|cos(t1+t2)| + |sin(t1+t2)|) < 2D Min(|cos(t1)|, (|sin(t1)|)
where C1, C2 are the sides, D the distance between centers and t1, t2 are the angles between sides and the center line, and similar by exchange of 1/2.
I have a list of 2D points (x1,y1),(x2,y2)......(Xn,Yn) representing a curved segment, is there any formula to determine whether the direction of drawing that segment is clockwise or anti clockwise ?
any help is appreciated
Alternately, you can use a bit of linear algebra. If you have three points a, b, and c, in that order, then do the following:
1) create the vectors u = (b-a) = (b.x-a.x,b.y-a.y) and v = (c-b) ...
2) calculate the cross product uxv = u.x*v.y-u.y*v.x
3) if uxv is -ve then a-b-c is curving in clockwise direction (and vice-versa).
by following a longer curve along in the same manner, you can even detect when as 's'-shaped curve changes from clockwise to anticlockwise, if that is useful.
One possible approach. It should work reasonably well if the sampling of the line represented by your list of points is uniform and smooth enough, and if the line is sufficiently simple.
Subtract the mean to "center" the line.
Convert to polar coordinates to get the angle.
Unwrap the angle, to make sure its increments are meaningful.
Check if total increment is possitive or negative.
I'm assuming you have the data in x and y vectors.
theta = cart2pol(x-mean(x), y-mean(y)); %// steps 1 and 2
theta = unwrap(theta); %// step 3
clockwise = theta(end)<theta(1); %// step 4. Gives 1 if CW, 0 if ACW
This only considers the integrated effect of all points. It doesn't tell you if there are "kinks" or sections with different directions of turn along the way.
A possible improvement would be to replace the average of x and y by some kind of integral. The reason is: if sampling is denser in a region the average will be biased towards that, whereas the integral wouldn't.
Now this is my approach, as mentioned in a comment to the question -
Another approach: draw a line from starting point to ending point. This line is indeed a vector. A CW curve has most of its part on RHS of this line. For CCW, left.
I wrote a sample code to elaborate this idea. Most of the explanation can be found in comments in the code.
clear;clc;close all
%% draw a spiral curve
N = 30;
theta = linspace(0,pi/2,N); % a CCW curve
rho = linspace(1,.5,N);
[x,y] = pol2cart(theta,rho);
clearvars theta rho N
plot(x,y);
hold on
%% find "the vector"
vec(:,:,1) = [x(1), y(1); x(end), y(end)]; % "the vector"
scatter(x(1),y(1), 200,'s','r','fill') % square is the starting point
scatter(x(end),y(end), 200,'^','r','fill') % triangle is the ending point
line(vec(:,1,1), vec(:,2,1), 'LineStyle', '-', 'Color', 'r')
%% find center of mass
com = [mean(x), mean(y)]; % center of mass
vec(:,:,2) = [x(1), y(1); com]; % secondary vector (start -> com)
scatter(com(1), com(2), 200,'d','k','fill') % diamond is the com
line(vec(:,1,2), vec(:,2,2), 'LineStyle', '-', 'Color', 'k')
%% find rotation angle
dif = diff(vec,1,1);
[ang, ~] = cart2pol(reshape(dif(1,1,:),1,[]), reshape(dif(1,2,:),1,[]));
clearvars dif
% now you can tell the answer by the rotation angle
if ( diff(ang)>0 )
disp('CW!')
else
disp('CCW!')
end
One can always tell on which side of the directed line (the vector) a point is, by comparing two vectors, namely, rotating vector [starting point -> center of mass] to the vector [starting point -> ending point], and then comparing the rotation angle to 0. A few seconds of mind-animating can help understand.