I would like to be able to increase / decrease a variable in a non-linear, for example based on a curved line such as:
then in the linear case if the time (T) is 0, the variable (v) will be 0, and then T = 5 v = 0.5, T = 10 v = 1 while in the case of a curved line will have T = 0 v = 0, T = 5 v = 0.8, T = 10 v = 1.
No matter the programming language, I want to understand the theory to do a thing. I do not want a simple exponential or logarithmic function, I wish I could do this thing also with custom curves. thank you.
Please have a look at "calculus" and "finite differences".
What you're after is the derivative of a general function or a finite difference approximation.
If your variable y = f(x), then the first derivative of the function w.r.t. x can be thought of as the slope of the function at that point:
dy/dx = f'(x)
You can use this to approximate the increment in y for a given increment in x:
dy = f'(x)*dx
Your example y = ln(x) would look like:
f'(ln(x)) = 1/x
Rearranging:
dy = dx/x
If you know the value of your function at a point x0
y0 = f(x0)
and you want the value at another point x1
x1 = x0 + dx
You can approximate the value at a point x1 = x0 + dx by:
y1 = y0 + f'(x)*dx
Bonus points: do you evauate the derivative at x0 (explicit), x1 (implicit), or an intermediate point?
Related
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.
I'm trying to write a decay formula, which is based on the ratio between x and y, assuming always that y > x. The formula needs to have a lower limit of 0.25, and an upper limit of 1.0.
As the ratio between the two numbers decreases, the formula gets closers to 1, as the ratio increases, the formula gets closer to 0.25. The result of the formula is being used as a scalar.
If possible, I'd also like to toggle the rate at which the scalar approaches its limits.
Any guidance is much appreciated, as I'm ripping my hair out right now!
This is an example:
take in account -1/x with x = [0, +inf] then it has f(x) = [-inf, 0]. so now let's take in account 1-1/x with x = [0, +inf] it has f(x) = [-inf, 1], but f(x)=0 <=> x=1.
So now we move the function 1 to the left, so we get f(x) = 1-(1/(x+1)).
now we need to map it in [0.25, 1], so we do the same thing, but instead of 1 we use 0.75, and we get
f(x) = 3/4 - 1/[x + (4/3)]
that has a domain of [0,+inf], f(x)=0 <=> x=0 and an image of [0,0.75], so now we are missing only the offset of 0.25, with which, we get
f(x) = 3/4 - 1/[x + (4/3)] + 1/4
and if we sum up the pieces we get
f(x) = 1 - 1/[x + (4/3)] + 1/4
so now we have the right function, we just need to figure out what to put as x
we want that when x/y = 1 => 0 (to have f(0)= 0.25) and x/y = 0 => +inf (to have f(+inf)= 1), and we achieve that using (y/x)-1
At the end we get:
f(x,y) = 1 - 1/[((y/x)-1) + (4/3)] + 1/4
To manipulate the velocity, put the coefficient in front of the "old", with which you get:
f(x,y) = 1 - 1/[velocity*((y/x)-1) + (4/3)] + 1/4
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!
I have line segment with start s(x1,y1) and end e(x2,y2). I have calculated distance between s and e by using euclidean distance
d = sqrt((x1-x2)(x1-x2) + (y1-y2)(y1-y2))
How to find out point on the line segment at distance d1 (0 < d1< d)?
The main theme of linearity is that everything is proportional.
d1 is d1/d fraction of the way from 0 to d.
Therefore, the point, p, that you are looking for is the same fraction of
the way from s to e. So let r = d1/d. Then
p = (x1 + r*(x2-x1), y1 + r*(y2-y1))
Notice that when r equals 0, p is (x1 + 0*(x2-x1), y1 + 0*(y2-y1)) = (x1, y1) = s. And when r equals 1, p is e = (x2, y2). As r goes from 0 to 1, p goes from s to t linearly -- that is, as a linear function of r.
parametric Line is defined like this:
x(t)=x1+(x2-x1)*t;
y(t)=y1+(y2-y1)*t;
where t is parameter in range <0.0,1.0>
if t=0.0 then the result is giving point (x1,y1)
if t=1.0 then the result is giving point (x2,y2)
So if you need point at d distance from start then:
D=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
x(d)=x1+(x2-x1)*d/D;
y(d)=y1+(y2-y1)*d/D;
where D is line length
and d is distance from start point
I'm trying to generate some axis vectors from parameters commonly used to specify crystallographic unit cells. These parameters consist of the length of the three axes: a,b,c and the angles between them: alpha,beta,gamma. By convention alpha is the angle between the b and c axes, beta is between a and c, and gamma between a and b.
Now getting vector representations for the first two is easy. I can arbitrarily set the the a axis to the x axis, so a_axis = [a,0,0]. I then need to rotate b away from a by the angle gamma, so I can stay in the x-y plane to do so, and b_axis = [b*cos(gamma),b*sin(gamma),0].
The problem is the third vector. I can't figure out a nice clean way to determine it. I've figured out some different interpretations but none of them have panned out. One is imagining the there are two cones around the axes axis_a and axis_b whose sizes are specified by the angles alpha and beta. The intersection of these cones create two lines, the one in the positive z direction can be used as the direction for axis_c, of length c.
Does someone know how I should go about determining the axis_c?
Thanks.
The angle alpha between two vectors u,v of known length can be found from their inner (dot) product <u,v>:
cos(alpha) = <u,v>/(||u|| ||v||)
That is, the cosine of alpha is the inner product of the two vectors divided by the product of their lengths.
So the z-component of your third can be any nonzero value. Scaling any or all of the axis vectors after you get the angles right won't change the angles, so let's assume (say) Cz = 1.
Now the first two vectors might as well be A = (1,0,0) and B = (cos(gamma),sin(gamma),0). Both of these have length 1, so the two conditions to satisfy with choosing C are:
cos(alpha) = <B,C>/||C||
cos(beta) = <A,C>/||C||
Now we have only two unknowns, Cx and Cy, to solve for. To keep things simple I'm going to just refer to them as x and y, i.e. C = (x,y,1). Thus:
cos(alpha) = [cos(gamma)*x + sin(gamma)*y]/sqrt(x^2 + y^2 + 1)
cos(beta) = x/(sqrt(x^2 + y^2 + 1)
Dividing the first equation by the second (assuming beta not a right angle!), we get:
cos(alpha)/cos(beta) = cos(gamma) + sin(gamma)*(y/x)
which is a linear equation to solve for the ratio r = y/x. Once you have that, substituting y = rx in the second equation above and squaring gives a quadratic equation for x:
cos^2(beta)*((1+r^2)x^2 + 1) = x^2
cos^2(beta) = (1 - cos^2(beta)*(1 + r^2))x^2
x^2 = cos^2(beta)/[(1 - cos^2(beta)*(1 + r^2))]
By squaring the equation we introduced an artifact root, corresponding to choosing the sign of x. So check the solutions for x you get from this in the "original" second equation to make sure you get the right sign for cos(beta).
Added:
If beta is a right angle, things are simpler than the above. x = 0 is forced, and we have only to solve the first equation for y:
cos(alpha) = sin(gamma)*y/sqrt(y^2 + 1)
Squaring and multiplying away the denominator gives a quadratic for y, similar to what we did before. Remember to check your choice of a sign for y:
cos^2(alpha)*(y^2 + 1) = sin^2(gamma)*y^2
cos^2(alpha) = [sin^2(gamma) - cos^2(alpha)]*y^2
y^2 = cos^2(alpha)/[sin^2(gamma) - cos^2(alpha)]
Actually if one of the angles alpha, beta, gamma is a right angle, it might be best to label that angle gamma (between the first two vectors A,B) to simplify the computation.
Here is a way to find all Cx, Cy, Cz (first two are the same as in the other answer), given that A = (Ax,0,0), B = (Bx, By, 0), and assuming that |C| = 1
1) cos(beta) = AC/(|A||C|) = AxCx/|A| => Cx = |A|cos(beta)/Ax = cos(beta)
2) cos(alpha) = BC/(|B||C|) = (BxCx+ByCy)/|B| => Cy = (|B|cos(alpha)-Bx cos(beta))/By
3) To find Cz let O be the point at (0,0,0), T the point at (Cx,Cy,Cz), P be the projection of T on Oxy and Q be the projection of T on Ox. So P is the point at (Cx,Cy,0) and Q is the point at (Cx,0,0). Thus from the right angle triangle OQT we get
tan(beta) = |QT|/||OQ| = |QT|/Cx
and from the right triangle TPQ we get |TP|^2 + |PQ|^2 = |QT|^2. So
Cz = |TP| = sqrt(|QT|^2 - |PQ|^2) = sqrt( Cx^2 tan(beta)^2 - Cy^2 )
I'm not sure if this is correct but I might as well take a shot. Hopefully I won't get a billion down votes...
I'm too lazy to scale the vectors by the necessary amounts, so I'll assume they are all normalized to have a length of 1. You can make some simple modifications to the calculation to account for the varying sizes. Also, I'll use * to represent the dot product.
A = (1, 0, 0)
B = (cos(g), sin(g), 0)
C = (Cx, Cy, Cz)
A * C = cos(beta) //This is just a definition of the dot product. I'm assuming that the magnitudes are 1, so I can skip that portion, and you said that beta was the angle between A and C.
A * C = Cx //I did this by multiplying each corresponding value, and the Cy and Cz were ignored because they were being multiplied by 0
cos(beta) = Cx //Combine the previous two equations
B * C = cos(alpha)
B * C = Cx*cos(g) + Cy*sin(g) = cos(beta) * cos(g) + Cy*sin(g)
(cos(alpha) - cos(beta) * cos(g))/(sin(g)) = Cy
To be honest, I'm not sure how to get the z component of vector C, but I would expect it to be one more relatively easy step. If I can figure it out, I'll edit my post.