Simulating movement in 2D - math

I need assistance in simulating movement between 2 points in a plane. Consider two points P1:(x,y1) and P2:(x2,y2). I compute the distance between P1 and P2, say D, and I choose a random velocity, say V. Next, I compute the time required to move from P1 to P2, say T. Finally, I compute the equation of the straight line between P1 and P2 as y = mx + b.
For example, let T = 10 seconds. For the first 9 seconds, I would like to generate points per second on the straight line until I reach point P2 at the 10th second. Could you please assist me in doing so.

The best approach is to use parametric equations
x = x1 + t*(x2 - x1)
y = y1 + t*(y2 - y1)
where t is the "time" parameter going from 0 to 1 (0.5 means for example halfway).
If you also like your movement to be "soft" (starting from zero velocity, then accelerating then slowing down and stopping on the arrival point) you can use this modified equation
w = 3*t*t - 2*t*t*t
x = x1 + w*(x2 - x1)
y = y1 + w*(y2 - y1)
The following is a plot of the w curve compared to a linear distribution t with 11 points (t=0.0, 0.1, ... 0.9, 1.0):

Related

Connecting two points with a 3D logarithmic spiral (Julia)

I am calculating points along a three-dimensional logarithmic spiral between two points. I seem to be close, but I think I'm missing a conditional sign flip somewhere.
This code works relatively well:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p1 = [1,1,1]
p2 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1-p2)
t = range(0,r,rez)
theta_offset = atan((p1[2]-p2[2])/(p1[1]-p2[1]))
theta = range(0, 2*pi*rev, rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p1[1];
y = sin.(theta).*exp.(-t).*r.+p1[2];
z = exp.(-t).*log.(r).+p1[3]
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
and produces the following plot. Values of the endpoints are shown on the plot, with an arrow from the coordinate to its respective marker. The first point is off, but it's close enough for my liking.
The problem comes when I flip p2 and p1 such that
p1 = [3,10,2]
p2 = [1,1,1]
In this case, I still get a spiral from p2 to p1, and the end point (p1) is highly accurate. However, the other endpoint (p2) is wildly off:
I think this is due to me changing the relative Z position of the two points, but I'm not sure, and I haven't been able to solve this riddle. Any help would be greatly appreciated. (Bonus points if you can help figure out why the Z value on p2 is off in the first example!)
Assuming this is a follow-up of your other question: Drawing an equiangular spiral between two known points in Julia
I assume you just want to add a third dimension to your previous 2D problem using cylindric coordinate system. This means that you need to separate the treatment of x and y coordinate on one side, and the z coordinate on the other side.
First you need to calculate your r on the first two coordinate:
r = norm(p1[1:2]-p2[1:2])
Then, when calculating z, you need to take only the third dimension in your formula (not sure why you used a log function there in the first place):
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
That will fix your z-axis.
Finally for your x and y coordinate, use the two argument atan function:
julia>?atan
help?> atan
atan(y)
atan(y, x)
Compute the inverse tangent of y or y/x, respectively.
For one argument, this is the angle in radians between the positive x-axis and the point (1, y), returning a value in the interval [-\pi/2, \pi/2].
For two arguments, this is the angle in radians between the positive x-axis and the point (x, y), returning a value in the interval [-\pi, \pi]. This corresponds to a standard atan2
(https://en.wikipedia.org/wiki/Atan2) function. Note that by convention atan(0.0,x) is defined as \pi and atan(-0.0,x) is defined as -\pi when x < 0.
like this:
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
And finally, like in your previous question, add the p2 point instead of the p1 point at the end of x, y, and z:
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
In the end, I have this:
using PlotlyJS
using LinearAlgebra
# Points to connect (`p2` spirals into `p1`)
p2 = [1,1,1]
p1 = [3,10,2]
# Number of curve revolutions
rev = 3
# Number of points defining the curve
rez = 500 # Number of points defining the line
r = norm(p1[1:2]-p2[1:2])
t = range(0.,norm(p1-p2), length=rez)
theta_offset = atan( p1[2]-p2[2], p1[1]-p2[1] )
theta = range(0., 2*pi*rev, length=rez) .+ theta_offset
x = cos.(theta).*exp.(-t).*r.+p2[1];
y = sin.(theta).*exp.(-t).*r.+p2[2];
z = exp.(-t).*(p1[3]-p2[3]).+p2[3]
#show (x[begin], y[begin], z[begin])
#show (x[end], y[end], z[end]);
# Plot curve points
plot(scatter(x=x, y=y, z=z, marker=attr(size=2,color="red"),type="scatter3d"))
Which give the expected results:
p2 = [1,1,1]
p1 = [3,10,2]
(x[begin], y[begin], z[begin]) = (3.0, 10.0, 2.0)
(x[end], y[end], z[end]) = (1.0001877364735474, 1.0008448141309634, 1.0000938682367737)
and:
p1 = [1,1,1]
p2 = [3,10,2]
(x[begin], y[begin], z[begin]) = (0.9999999999999987, 1.0, 1.0)
(x[end], y[end], z[end]) = (2.9998122635264526, 9.999155185869036, 1.9999061317632263)
In 2D, let us assume the pole at the point C, and the spiral from P to Q, corresponding to a variation of the parameter in the interval [0, 1].
We have
X = Cx + cos(at+b).e^(ct+d)
Y = Cy + sin(at+b).e^(ct+d)
Using the known points,
Px - Cx = cos(b).e^d
Py - Cy = sin(b).e^d
Qx - Cx = cos(a+b).e^(c+d)
Qy - Cy = sin(a+b).e^(c+d)
From the first two, by a Cartesian to polar transformation (and logarithm), you can obtain b and d. From the last two, you similarly obtain a+b and c+d, and the spiral is now defined.
For the Z coordinate, I cannot answer precisely as you don't describe how you generalize the spiral to 3D. Anyway, we can assume a certain function Z(t), that you can map to [Pz, Qz] by the linear transformation
(Qz - Pz) . (Z(t) - Z(0)) / (Z(1) - Z(0)) + Pz.

Get corresponding Y position on cubic bezier when given X position [duplicate]

Let's say I have a Bezier curve with two fixed endpoints, one at x(0), y(1) and one at x(1), y(0) (bottom left corner and upper right corner)
Now let's say I have two control points, which can be at any locations between x(0), x(1), y(0), and y(1). For this question, I'll just say that control point #1 is at x(0.1) y(0.6) and control point #2 is at x(0.9) and at y(0.4). (This assumes a "from upper left" coordinate system)
Here's a small illustration of our curve:
Now let's say I'm given a y position of 0.7. What would the math look like to figure out what the corresponding x position is to the point at y(0.7)? How would I do this?
Sorry if this question doesn't belong here, but I figured this is a common problem faced in coding and that it's likely that many of you have the answer I'm looking for.
You have cubic equation for functions X(t) and Y(t) where t is curve parameter (range 0..1 for points on curve). In Bernstein polynomial basis (usual form for curve definition):
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3
Having Y value, we can find corresponding t parameters - note there might be from 0 to 3 possible roots in range 0..1. Representation of Y-component in power basis:
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3 =
t^3*(P3Y-3P2Y+3P1Y-P0Y) + t^2*(3P2Y-6P1Y+3P0Y) + t^2*(3P1Y-3P0Y) + (P0Y) =
t^3*a + t^2*b + t^2*c + d' = y_position
and finally cubic equation is:
t^3*a + t^2*b + t^2*c + d = 0
where
a = P3.Y-3*P2.Y+3*P1.Y-P0.Y
b = 3*P2.Y-6*P1.Y+3*P0.Y
c = 3*P1.Y-3*P0.Y
d = P0.Y - y_position
Solve cubic equation to calculate t (perhaps some values for wavy curves)
Then for given t calculate corresponding X value:
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3

Given a cubic Bezier curve with fixed endpoints, how can I find the x position of a point along it when given a y position to check?

Let's say I have a Bezier curve with two fixed endpoints, one at x(0), y(1) and one at x(1), y(0) (bottom left corner and upper right corner)
Now let's say I have two control points, which can be at any locations between x(0), x(1), y(0), and y(1). For this question, I'll just say that control point #1 is at x(0.1) y(0.6) and control point #2 is at x(0.9) and at y(0.4). (This assumes a "from upper left" coordinate system)
Here's a small illustration of our curve:
Now let's say I'm given a y position of 0.7. What would the math look like to figure out what the corresponding x position is to the point at y(0.7)? How would I do this?
Sorry if this question doesn't belong here, but I figured this is a common problem faced in coding and that it's likely that many of you have the answer I'm looking for.
You have cubic equation for functions X(t) and Y(t) where t is curve parameter (range 0..1 for points on curve). In Bernstein polynomial basis (usual form for curve definition):
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3
Having Y value, we can find corresponding t parameters - note there might be from 0 to 3 possible roots in range 0..1. Representation of Y-component in power basis:
Y(t) = P0.Y*(1-t)^3+3*P1.Y*(1-t)^2*t+3*P2.Y*(1-t)*t^2+P3.Y*t^3 =
t^3*(P3Y-3P2Y+3P1Y-P0Y) + t^2*(3P2Y-6P1Y+3P0Y) + t^2*(3P1Y-3P0Y) + (P0Y) =
t^3*a + t^2*b + t^2*c + d' = y_position
and finally cubic equation is:
t^3*a + t^2*b + t^2*c + d = 0
where
a = P3.Y-3*P2.Y+3*P1.Y-P0.Y
b = 3*P2.Y-6*P1.Y+3*P0.Y
c = 3*P1.Y-3*P0.Y
d = P0.Y - y_position
Solve cubic equation to calculate t (perhaps some values for wavy curves)
Then for given t calculate corresponding X value:
X(t) = P0.X*(1-t)^3+3*P1.X*(1-t)^2*t+3*P2.X*(1-t)*t^2+P3.X*t^3

drawing the tangent to the curve knowing the point and gradient

I writing a computer program to back up my knowledge of calculus. You can see the web page here
The next thing I want to do is display a tangent to the curve when the user hovers the mouse over the curve.
When that happens, I know exactly the coordinates of the mouse and I can get the derivative which in this case is 2x -2 so if the point is at (1, 1) then the gradient would be 0.
If I was drawing this with pen and paper then I would rearrange the equation into y2-y1 = m(x2 -x1).
I am not entirely sure how to do this with code though.
I tried getting the y intercept and x intercept but the tangent looked wrong:
function getYIntercept(vertex, slope) {
return vertex.y - (slope * vertex.x);
}
const yIntercept = getYIntercept(point, gradient);
const xIntercept = - yIntercept / (gradient);
g.append('line')
.style('stroke', 'red')
.attr('class', 'tangent')
.attr('x1', xScale(point.x))
.attr('y1', yScale(point.y))
.attr('x2', xScale(xIntercept))
.attr('y2', yScale(yIntercept));
};
How better can I plot this line with the information I have?
Finding the Tangent
Let us start with a function f(x).
Calculate f '(x) (the derivative) for future reference.
Then the user indicates some point (x1, y1).
Using f '(x), the slope at this point is m = f '(x1).
Utilizing the Point-Slope formula, the equation for tangent is y-y1 = m(x-x1)
Solve for y:
y = m(x-x1)+y1
Finding the Intercepts
For the x and y intercepts [denoted here as x0 and y0 respectively], simply use the tangent equation. It may be useful to note that the intercepts are (x0,0) and (0,y0) so plugging in zero for the correct variable allows you to find a intercept.
Find the y intercept, so x=0
Thus y = m(0-x1)+y1
Distributing the m leaves y = -m*x1+y1
So y0 = -m*x1+y1 and the y intercept is ( 0, -m*x1+y1 )
This is all that is needed to graph the tangent. But in case you're are curious about the x intercept as well.
Find the x intercept, so y=0
Thus 0 = m(x-x1)+y1
Distributing the m leaves 0 = m*x - m*x1 + y1
Subtracting the x1 and y1 terms yields m*x1-y1 = m*x
Now divide by m so that [ m*x1-y1 ]/m = x
So x0 = [ m*x1-y1 ]/m and the x intercept is ( [ m*x1-y1 ]/m, 0 )
Specifics for this Case
Here are some issues:
(1, 1) is not a point on the function f(x) = x^2 - 2*x + 1
To solve this, you could simply use only the x-value of the point the user hovers over
Alternatively, you could consider graphing the slope field
The x intercept and y intercept are two distinct points, not the x and y value of one point
Once these issues are resolved, you will be able to properly graph the tangent of any function for which you know the first derivative!

Given f(x) linear function, how to obtain a Quadratic Bezier control point

I've been doing a lot of research on the topic and found a couple of post that where helpful but I just can't get this right.
I am developing a very simple structural analysis app. In this app I need to display a graph showing the internal stress of the beam. The graph is obtained by the formula:
y = (100 * X / 2) * (L - X)
where L is the known length of the beam (lets say its 1 for simplicity). And X is a value between 0 and the Length of be beam. So the final formula would be:
y = (100 * X / 2) * (1 - x) where 0 < X < 1.
Assuming my start and end points are P0 = (0,0) and P2 = (1,0). How can I obtain P2 (control point)?? I have been searching in the Wikipedia page but I am unsure how to obtain the control point from the quadratic bezier curve formula:
B(t) = (1 - t)^2 * P0 + 2*(1 - t)*t * P1 + t^2 * P2
I'm sure it must be such an easy problem to fix… Can anyone help me out?
P.S.: I also found this, How to find the mathematical function defining a bezier curve, which seems to explain how to do the opposite of what I am trying to achieve. I just can't figure out how to turn it around.
We want the quadratic curve defined by y to match the quadratic Bezier curve
defined by B(t).
Among the many points that must match is the peak which occurs at x =
0.5. When x = 0.5,
y = (100 * x / 2) * (1 - x)
100 1 25
y = ---- * --- = ---- = 12.5
4 2 2
Therefore, let's arrange for B(0.5) = (0.5, 12.5):
B(t) = (1-t)^2*(0,0) + 2*(1-t)*t*(Px, Py) + t^2*(1,0)
(0.5, 12.5) = B(0.5) = (0,0) + 2*(0.5)*(0.5)*(Px, Py) + (0.25)*(1,0)
0.5 = 0.5 * Px + 0.25
12.5 = 0.5 * Py
Solving for Px and Py, we get
(Px, Py) = (0.5, 25)
And here is visual confirmation (in Python) that we've found the right point:
# test.py
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 1, 100)
y = (100*x/2)*(1-x)
t = np.linspace(0, 1, 100)
P0 = np.array([0,0])
P1 = np.array([0.5,25])
P2 = np.array([1,0])
B = ((1-t)**2)[:,np.newaxis]*P0 + 2*((1-t)*t)[:,np.newaxis]*P1 + (t**2)[:,np.newaxis]*P2
plt.plot(x, y)
plt.plot(B[:,0], B[:,1])
plt.show()
Running python test.py, we see the two curves overlap:
How did I know to choose t = 0.5 as the parameter value when B(t) reaches its maximum height?
Well, it was mainly based on intuition, but here is a more formal way to prove it:
The y-component of B'(t) equals 0 when B(t) reaches its maximum height. So, taking the derivative of B(t), we see
0 = 2*(1-2t)*Py
t = 0.5 or Py = 0
If Py = 0 then B(t) is a horizontal line from (0,0) to (1,0). Rejecting this degenerate case, we see B(t) reaches its maximum height when t = 0.5.
Your quadratic bezier curve formula has a typo in the middle term. It should be:
B(t) = (1 - t)^2 * P0 + 2 * (1 - t) * t * P1 + t^2 * P2
This means you should take the P1=(1,50) that #unutbu found and divide the coordinates in half to get P1=(.5,25). (This won't matter if you're plotting the parametric equation on your own, but if you want something like LaTeX's \qbezier(0,0)(.5,25)(1,0), then you'll need the corrected point.)
The P1 control point is defined so that the tangent lines at P0 and P2 intersect at P1. Which means that if (P1)x=(P2)x, the graph should be vertical on its righthand side (which you don't want).
In response to your comment, if you have a quadratic y=f(x), then it is symmetrical about its axis (almost tautologically). So the maximum/minimum will occur at the average of the roots (as well as the control point).

Resources