Parabola in Processing - math

I was transferring tasks from my maths textbook to Processing. One of the problems required the use of a parabola. I decided to write it as a Bézier curve, wrote the code, but something didn't work.
Could anyone please explain to me what I did wrong here?
The code:
def setup():
background(255,255,255)
size(800,800)
rectMode(CENTER)
line(400,0,400,800)
line(0,400,800,400)
#B 0 to know the start and the end points
a=1
x=3
b=0
c=10
translate(width/2, height/2)
noFill()
beginShape()
#Parabola formula
y=-(a*x*x+b*x+c)
#X of the point of the symetry
Sx=(-b)/(2*a)
#Y of the point of the symetry
Sy=-(a*Sx*Sx+b*Sx+c)
#Derivative
Ny=-(800+b)
#Y of the starting point
By=-(a*400*400-b*400+c)
#Y of the end point
Ey=-(a*400*400+b*400+c)
#Y3 Y4
Ty=Ny*(x+400)-By
bezier(-400,By,Sx,Ty,400,Ey,Sx,Ty)
endShape()
noFill()
beginShape()
for i in range (-400,400):
x=i
y=-i
vertex(x,y)
endShape()
(It had to be an 800x800 coordinate plane, a parabola and a straight line.)

Your resulting y coordinates are way too high for the bezier curve.
If you want to draw the curve with line segments, you need to calculate the y coordinates inside the loop:
def setup():
size(400, 400)
background(255,255,255)
rectMode(CENTER)
line(width/2, 0, width/2, height)
line(0, height/2, width, height/2)
translate(width/2, height/2)
a, b, c = 1, 10, -100
scaleX = 0.1;
noFill()
strokeWeight(4)
beginShape(LINES)
for i in range (-400, 400):
x = i * scaleX
y = -(a*x*x +b*x + c)
vertex(i, y)
endShape()

Related

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!

How to find points along arc if given initial point, ending point, random point + precision?

the precision is the number of points I want for my vector, from 0, the initial point of my arc, to the precision I want minus 1.
Code example in c++:
int precision = 20;
double pointInit[3] = {2,5,2};
double pointRandom[3] = {3,7,1};
double pointInit[3] = {0,-3,1};
std::vector<std::array<double,3>> pointArc;
std::array<double, 3> currentPoint;
// Fill the pointArc vector, from 0 (initial point) to precision -1 (ending point)
for (int i = 0 ; i < precision; i++)
{
// Find the value of the current point
// currentPoint[0] = ????;
// currentPoint[1] = ????;
// currentPoint[2] = ????;
pointArc.push_back(currentPoint);
}
EDIT : The arc I'm looking for is a circular arc
Use atan2() to find the angles of the endpoints with respect to the center, subtend the angle between them precision - 1 times, and convert the polar coordinates (use one of the endpoints to get the distance from the center) to rectangular form.
1) translate the three points so that P0 comes to the origin
2) consider the vectors P0P1 and P0P2 and form an orthonormal basis by the Gram-Schmidt process (this is easy)
3) in this new basis, the coordinates of the three points are (0, 0, 0), (X1, 0, 0), (X2, Y2, 0), and you have turned the 3D problem to 2D. (Actually X1=d(P0,P1) and X2, Y2 are obtained from the dot and cross products of P0P2 with P0P1 / X1)
The equation of a 2D circle through the origin is
x² + y² = 2Xc.x + 2Yc.y
Plugging the above coordinates, you easily solve the 2x2 system for Xc and Yc.
X1² = 2Xc.X1
X2² + Y2² = 2Xc.X2 + 2Yc.Y2
4) The parametric equation of the circle is
x = Xc + R cos(t)
y = Yc + R sin(t)
where R²=Xc²+Yc².
You can find the angles t0 and t2 corresponding to the endpoints with tan(t) = (y - Yc) / (x - Xc).
5) interpolate on the angle t0.(1-i/n) + t2.i/n, compute the reduced coordinates x, y from the parametric equation and apply the inverse transforms of 2) and 1).

Scale 3D-Points in Plane

I have some points (3D) all on the same (known) plane. Now I want to scale these points within the plane as opposed to the whole 3D space.
Is there some quick solution for this e.g. a modified scaling matrix?
Can someone help me?
Thanks.
EDIT: I'm more looking for an idea/pseudocode how to do this. If you want use MatLab or some convenient language
Your plane can be known by three non-collinear points P0, P1, P2, or by its implicit equation,
A.x + B.y + C.z + D = 0
In the first case, consider the vector P0P1 and normalize it (U = P0P1/|P0P1|). Then compute a second vector orthogonal with the first, V = P0P2 - (P0P2.U).U and normalize it.
In the second case you can take the three intersection points with the axes, (-D/A, 0, 0), (0, -D/B, 0), (0, 0, -D/C) and you are back in the first case (but mind degenerate cases).
Use the two vectors to compute the desired 2D coordinates of any point P = (X, Y, Z) by the dot products
(x, y) = (P.U, P.V)
(This transform is a rotation that makes P0P1 parallel to the x axis and brings P0P1P2 in the plane xy.)

How to compute opposite view from a quaternion rotation?

I have a quaternion rotation, as usually described by 4 values: a b c d.
Lets say it transforms the x axis so that i look at some object from the front. Now i want to change this rotation so i look at the object from the back.
So basicly i want to change the viewpoint from front to back, but do that using this rotation.
How can the opposite rotation be computed?
Learning from the wikipedia page, it seems that if you want to perform a 180° rotation around the z axis, then the corresponding Quaternion rotation would simply be:
0 0 0 1
The key here is the formula , where (w,x,y,z) = (a,b,c,d).
Indeed, since cos(90°) = 0 and sin(90°) = 1, then replacing alpha with 180° and u with (0, 0, 1), gives you (0, 0, 0, 1).
Edit: As Christian has pointed out, the up direction need not be z, but may be any unit vector u = (x,y,z) (otherwise normalize it by dividing by its norm). In that case, the corresponding 180° quaterion rotation would be
0 x y z
Now to apply this rotation in order to move around the object, say you have the position an the direction vetors of your camera c_pos and c_dir, then simply (left) conjugate it by q = (0 x y z), and move the camera position accordingly. Something like
c_dir = q * c_dir * q^-1
c_pos = 2 * o_pos - c_pos
where o_pos is the position of the object, and c_dir should be converted to a quaternion with 0 real part.
In my case, hel me this..
original quat (x y z w)
opposite oriented quat (y -x w -z)

Drawing a plane

I want to draw a plane which is given by the equation: Ax+By+Cz+D=0.
I first tried to draw him by setting x,y and then get z from the equation. this did not work fine because there are some planes like 0x+0y+z + 0 = 0 and etc...
my current solution is this:
- draw the plane on ZY plane by giving 4 coordinates which goes to infinity.
- find out to rotation that should be done in order to bring the normal of the given plane(a,b,c) to lay
on z axis.
- find the translation that should be done in order for that plane be on x axis.
- make the exactly opposite transformation to those rotation and to this translation hence i will get the
plane in his place.
ok
this is a great thing but I can make the proper math calculations(tried a lot of times...) with the dot product and etc....
can someone help me in understanding the exact way it should be done OR give me some formula in which I will put ABCD and get the right transformation?
You will want the following transformation matrix:
[ x0_x y0_x z0_x o_x ]
M = [ x0_y y0_y z0_y o_y ]
[ x0_z y0_z z0_z o_z ]
[ 0 0 0 1 ]
Here, z0 is the normal of your plane, and o is the origin of your plane, and x0 and y0 are two vectors within your plane orthogonal to z0 that define the rotation and skew of your projection.
Then any point (x,y) on your XY plane can be projected to a point (p_x, p_y, p_z) your new plane with the following:
(p_x, p_y, p_z, w) = M * (x, y, 0, 1)
now, z0 in your transformation matrix is easy, that's the normal of your plane and that is simply n = normalize(a,b,c).
In choosing the rest however you have distinctly more freedom. For the origin you could take the point that the plane intersects the Z axis, unless of course the plane is parallel to the Z axis, in which case you need something else.
So e.g.
if (c != 0) { //plane intersects Z axis
o_x = 0;
o_y = 0;
o_z = -d/c;
}
else if (b != 0) { // plane intersects Y axis
o_x = 0;
o_y = -d/b;
o_z = 0;
}
else { // plane must intersect the X axis
o_x = -d/a;
o_y = 0;
o_z = 0;
}
In practice you may want to prefer a different test than (c != 0), because with that test it will succeed even is c is very very small but just different from zero, leading your origin to be at say, x=0, y=0, z=10e100 which would probably not be desirable. So some test like (abs(c) > threshold) is probably preferable. However you could of course take an entirely different point in the plane to put the origin, perhaps the point closest to the origin of your original coordinate system, which would be:
o = n * (d / sqrt(a^2 + b^2 + c^2))
Then finally we need to figure out an x0 and y0. Which could be any two linearly independent vectors that are orthogonal to z0.
So first, let's choose a vector in the XY plane for our x0 vector:
x0 = normalize(z0_y, -z0_x, 0)
Now, this fails if your z0 happens to be of the form (0, 0, z0_z) so we need a special case for that:
if (z0_x == 0 && z0_y == 0) {
x0 = (1, 0, 0)
}
else {
x0 = normalize(z0_y, -z0_x, 0)
}
Finally let's say we do not want skew and choose y0 to be orthogonal to both x0, and y0, then, using the crossproduct
y0 = normalize(x0_y*y0_z-x0_z*y0_y, x0_z*y0_x-x0_z*y0_z, x0_x*y0_y-x0_y*y0_x)
Now you have all to fill your transformation matrix.
Disclaimer: Appropriate care should be taken when using floating point representations for your numbers, simple (foo == 0) tests are not sufficient in those cases. Read up on floating point math before you start implementing stuff.
Edit: renamed some variables for clarity
Is this what you're asking?
Transforming a simple plane like the xy plane to your plane is fairly simple:
your plane is Ax+By+Cz+D=0
the xy plane is simply z=0. i.e. A=B=D=0, while C=whatever you want. We'll say 1 for simplicity's sake.
When you have a plane in this form, the normal of the plane is defined by the vector (A,B,C)
so you want a rotation that will take you from (0,0,1) to (A,B,C)*
*Note that this will only work if {A,B,C} is unitary. so you may have to divide A B and C each by sqrt(A^2+B^2+C^2).
rotating around just two of the axes can get your from any direction to any other direction, so we'll pick x and y;
here are the rotation matrices for rotations by a about the x axis, and b about the y axis.
Rx := {{1, 0, 0}, {0, Cos[a], Sin[a]}, {0, -Sin[a], Cos[a]}}
Ry := {{Cos[b], 0, -Sin[b]}, {0, 1, 0}, {Sin[b], 0, Cos[b]}}
if we do a rotation about x, followed by a rotation about y, of the vector normal to the xy plane, (0,0,1), we get:
Ry.Rx.{0,0,1} = {-Cos[a] Sin[b], Sin[a], Cos[a] Cos[b]}
which are your A B C values.
i.e.
A = -Cos[a]Sin[b]
B = Sin[a]
C = Cos[a]Cos[b]
From here, it's simple.
a = aSin[B]
so now A = -Cos[aSin[B]]Sin[b]
Cos[aSin[x]] = sqrt(1-x^2)
so:
A = -Sqrt[1-B^2] * Sin[b]
b = aSin[-A/sqrt[1-B^2]]
a = aSin[B] (rotation about x axis)
b = aSin[-A/sqrt[1-B^2]] (rotation about y axis)
So we now have the angles about the x and y axes we need to rotate by.
After this, you just need to shift your plane up or down until it matches the one you already have.
The plane you have at the moment, (after those two rotations) is going to be Ax+By+Cz=0.
the plane you want is Ax+Bx+Cz+D=0. To find out d, we will see where the z axis crosses your plane.
i.e. Cz+D=0 -> z = -D/C
So we transform your z in Ax+By+Cz=0 by -D/C to give:
Ax+By+C(z+D/C) = Ax+By+Cz+D=0. Oh would you look at that!
It turns out you don't have to do any extra maths once you have the angles to rotate by!
The two angles will give you A,B, and C. To get D you just copy it from what you had.
Hope that's of some help, I'm not entirely sure how you plan on actually drawing the plane though...
Edited to fix some horrible formatting. hopefully it's better now.

Resources