I have this formula
B = tan(atan(A) + C)
where A is the input, B is output and C is a constant. The problem is that sin, cos and tan functions are computationally expensive and also there is quite a big loss of precision along the formula when calculated as 4 byte floats. I am in the process of optimizing my code so is there any way to avoid using these functions even if the total number of calculations is several times higher?
Further background: the numbers A, B and C are the ratio's of x/y coordinate for 3 points on a 2 dimensional plane
According to Wolfram Alpha, tan(atan(A)+C) can be written as (A+tan(C))/(1-A*tan(C)).
You can easily derive this by hand from the tangent sum formula:
tan(a + b) = (tan a + tan b)/(1 - tan a tan b).
If the implementation of tan in your math library is slow or inaccurate it's possible that faster or more precise implementations exist.
I'll presume that your formula is correct. Mark's comment essentially comes down to the idea that C must have units of an angle for the formula to make sense, but if C is a ratio, then it won't have the proper units. Mark has a valid question.
In the end, you will still need to compute a tangent, but there are things you can do to help a bit.
First, apply a simple trig identity, for the tangent of a sum. This, combined with the fact that tan(atan(A)) = A, reduces your formula to
B = (A + tan(C))/(1 - A*tan(C))
Thus you still need to compute ONE tangent, that of C. (Thus precompute tan(C), once.) Nothing will get you around that.
However, there are ways to compute a tangent more efficiently than as a ratio sin(C)/cos(C). For example, a direct series approximation might be better. Or there is a trick using a series for the versine, which is itself more efficient to compute than the tangent series. And for small angles it can be rapidly convergent. You can assure small angles using range reduction tricks for that versine. Other tricks exist too.
atan(A) = atan(x_a/y_a) for some point is the angle between vector (x_a,y_a) and Oy. Because C is a constant, you can precompute some vector c=(x_c,y_c) with unit length and inclined to Oy with angle C. Then cos(atan(A)+C) can be expressed as inner product of these vectors divided by length of a. From cos you can get tan using main identity. In the end a got:
B = sqrt((x_a^2 + y_a^2)/(x_a*x_c + y_a*y_c)^2 - 1)
This might be more effective. Be careful with signs.
Related
I've been trying to get the correct normals for a sphere I'm messing with using a vertex shader. The algorithm can be boiled down simply to
vert.xyz += max(0, sin(time + 0.004*vert.x))*10*normal.xyz
This causes a wave to roll across the sphere.
In order to make my normals correct, I need to transform them as well. I can take the tangent vector at a given x,y,z, get a perpendicular vector (0, -vert.z, vert.y), and then cross the tangent with the perp vector.
I've been having some issue with the math though, and it's become a personal vendetta at this point. I've solved for the derivative hundreds of times but I keep getting it incorrect. How can I get the tangent?
Breaking down the above line, I can make a math function
f(x,y,z) = max(0, sin(time + 0.004*x))*10*Norm(x,y,z) + (x,y,z)
where Norm(..) is Normalize((x,y,z) - CenterOfSphere)
After applying f(x,y,z), unchanged normals
What is the correct f '(x,y,z)?
I've accounted for the weirdness caused by the max in f(...), so that's not the issue.
Edit: The most successful algorithm I have right now is as follows:
Tangent vector.x = 0.004*10*cos(0.004*vert.x + time)*norm.x + 10*sin(0.004*vert.x + time) + 1
Tangent vector.y = 10*sin(0.004*vert.x + time) + 1
Tangent vector.z = 10*sin(0.004*vert.x + time) + 1
2nd Tangent vector.x = 0
2nd Tangent vector.y = -norm.z
2nd Tangent vector.z = norm.y
Normalize both, and perform Cross(Tangent2, Tangent1). Normalize again, and done (it should be Cross(Tangent1, Tangent2), but this seems to have better results... more hints of an issue in my math!).
This yields this
Get tangent/normal by derivate of function can sometimes fail if your surface points are nonlinearly distributed and or some math singularity is present or if you make a math mistake (which is the case in 99.99%). Anyway you can always use the geometric approach:
1. you can get the tangents easy by
U(x,y,z)=f(x+d,y,z)-f(x,y,z);
V(x,y,z)=f(x,y+d,z)-f(x,y,z);
where d is some small enough step
and f(x,y,z) is you current surface point computation
not sure why you use 3 input variables I would use just 2
but therefore if the shifted point is the same as unshifted
use this instead =f(x,y,z+d)-f(x,y,z);
at the end do not forget to normalize U,V size to unit vector
2. next step
if bullet 1 leads to correct normals
then you can simply solve the U,V algebraically
so rewrite U(x,y,z)=f(x+d,y,z)-f(x,y,z); to full equation
by substituting f(x,y,z) with the surface point equation
and simplify
[notes]
sometimes well selected d can simplify normalization to multipliyng by a constant
you should add normals visualization for example like this:
to actually see what is really happening (for debug purposses)
Say I have 2 3D vectors, each describing a direction in 3D space (or a rotation, but I'm not sure if that terminology is correct). How would I calculate the difference between the two vectors as an Euler angle? That is, if I applied the angle to the first vector, it would rotate to equal the other? I understand how Euler angles have issues and are implementation-dependant, but I don't know what the implications of this are on a question such as mine.
To clarify a little, when I say "3D vectors", I'm picturing the "translation" gizmo you get in most 3D modelling packages or in Unity (which is what I'm using).
EDIT: Actually I just reviewed the "vectors" that I'm using, and what I said is not quite correct. I actually have 6 vectors, 3 for each rotation. Each vector is a position in 3D space offset from the centre of rotation. This probably makes an already-difficult question near-impossible, right?
ADDITIONAL INFORMATION: Ok, so I've worked out what I actually want to ask (because this question is really badly done), and it applies more to Unity, so I've asked a more Unity-specific question over on Unity Answers.
I'm don't normally understand mathematical formulae that are posted online, so C++-styled pseudo-code would be by far the most helpful for me.
Any help would be much appreciated, and if my question lacks certain information, please just ask for more :)
If you are going to do 3d you need to understand linear algebra and matrix notation.[1] Affine 4x4 matrices are the basis of space transformations in all 3d applications I've ever seen, (Euler angles just give alternate means to describe that matrix). Even unity uses matrices, although to be able to efficiently do the Euler-Lagrange particle motion equation they prefer to have the decomposed form. A matrix encodes a entire space with 4 vectors. This is conceptually easy in this case (not the only use for matrices), the matrix encodes the directions x y z and offset vector w.
The reason matrix notation is useful is: It becomes possible to manipulate the things like normal math symbols. If you remember from school solving x from:
a * x = b
Divide both sides by a and you get
a/a * x = b /a ->
x = b / a
Now if you have 2 spaces with 3 vectors each you essentially have 2 fully formed spaces at origin. Assuming the vectors span a 3D space (in other words dont point all in one plane, its even better if they are orthogonal to each other in which case you can just use transformation functions directly). That means you have 3 spaces. So your problem is given you know 2 spaces. You need to know the space transform form space A -> space B (its customary to give matrices big letters to denote they are more complex). This is mathematically:
A * X = B
Where * is a matrix multiplications and A, X and B are transformation matrices. So then divide by A, but alas there's no matrix division, fortunately there is inverse and division is multiplication by inverse so that's what we do instead. Also one other note rotations are not commutative so we need to specify on which side we multiply so because A is before X we multiply on the left hand side with inverse of A. So we get:
A^-1 * A * X = A^-1 * B
Where ^-1 denotes matrix inverse. This simplifies to :
I * X = A^-1 * B ->
X = A^-1 * B
X is the rotation space. In unity code this looks like:
X = A.inverse * B
Where X, A and B are Matrix4x4 elements The language you use may have other conventions I'm using the java script reference here. You can covert this matrix to a quaternion and from there to Euler angles an example of this can be found here.
How to form A and B from the vectors? Just put the vector for starting space to A's columns 0-2 and destination spaces correspondingly to B columns[2].
[1] Yes its compulsory, its much simpler than it may seem at first. While you can live quite far without them they aren't any harder to use than saying rotate about x axis fro so and so. Also learn quats.
[2] I should check this, but unity seems to use column matrices so it should be right
PS: By the way if you have noisy data and more then 3 vectors per instance then you can use least squares to average the matrix t a 3 by 3 sub matrix.
I am looking for an (almost everywhere) differentiable function f(p1, p2, p3, p4) that given four points will give me a scale-agnostic measure for co-planarity. It is zero if the four points lie on the same plane and positive otherwise. Scale-agnostic means that, when I uniformly scale all points the planarity measure will return the same.
I came up with something that is quite complex and not easy to optimize. Define u=p2-p1, v=p3-p1, w=p4-p1. Then the planarity measure is:
[(u x v) * w]² / (|u x v|² |w|²)
where x means cross product and '*' means dot product.
The numerator is simply (the square of) the volume of the tetrahedron defined by the four points, and the denominator is a normalizing factor that makes this measure become simply the cosine of an angle. Because angles do not changed under uniform scale, this function satisfies all my requirements.
Does anybody know of something simpler?
Alex.
Edit:
I eventually used an Augmented Lagrangian method to perform optimization, so I don't need it to be scale agnostic. Just using the constraint (u x v) * w = 0 is enough, as the optimization procedure finds the correct Lagrange multiplier to compensate for the scale.
Your methods seems ok, I'd do something like this for efficient implementation:
Take u, v, w as you did
Normalize them: various tricks exist to evaluate the inverse square root efficiently with whatever precision you want, like this jewel. Most modern processors have builtins for this operation.
Take f = |det(u, v, w)| ( = (u x v) . w ). There are fast direct implementations for 3x3 matrices; see #batty's answer to this question.
This amounts to what you do without the squares. It is still homogeneous and almost everywhere differentiable. Take the square of the determinant if you want something differentiable everywhere.
EDIT: #phkahler implicitly suggested using the ratio of the radius of the inscribed sphere to the radius of the circumscribed sphere as a measure of planarity. This is a bounded differentiable function of the points, invariant by scaling. However, this is at least as difficult to compute as what you (and I) suggest. Especially computing the radius of the circumscribed sphere is very sensitive to roundoff errors.
A measure that should be symmetric with respect to point reorderings is:
((u x v).w)^2/(|u||v||w||u-v||u-w||v-w|)
which is proportional to the volume of the tetrahedron squared divided by all 6 edge lengths. It is not simpler than your formula or Alexandre C.'s, but it is not much more complicated. However, it does become unnecessarily singular when any two points coincide.
A better-behaved, order-insensitive formula is:
let a = u x v
b = v x w
c = w x u
(a.w)^2/(|a| + |b| + |c| + |a+b+c|)^3
which is something like the volume of the tetrahedron divided by the surface area, but raised to appropriate powers to make the whole thing scale-insensitive. This is also a bit more complex than your formula, but it works unless all 4 points are collinear.
How about
|(u x v) * w| / |u|^3
(and you can change |x| to (x)^2 if you think it's simpler).
I have been given some work to do with the fractal visualisation of the Mandelbrot set.
I'm not looking for a complete solution (naturally), I'm asking for help with regard to the orbits of complex numbers.
Say I have a given Complex number derived from a point on the complex plane. I now need to iterate over its orbit sequence and plot points according to whether the orbits increase by orders of magnitude or not.
How do I gather the orbits of a complex number? Any guidance is much appreciated (links etc). Any pointers on Math functions needed to test the orbit sequence e.g. Math.pow()
I'm using Java but that's not particularly relevant here.
Thanks again,
Alex
When you display the Mandelbrot set, you simply translate the real and imaginaty planes into x and y coordinates, respectively.
So, for example the complex number 4.5 + 0.27i translates into x = 4.5, y = 0.27.
The Mandelbrot set is all points where the equation Z = Z² + C never reaches a value where |Z| >= 2, but in practice you include all points where the value doesn't exceed 2 within a specific number of iterations, for example 1000. To get the colorful renderings that you usually see of the set, you assign different colors to points outside the set depending on how fast they reach the limit.
As it's complex numbers, the equation is actually Zr + Zi = (Zr + Zi)² + Cr + Ci. You would divide that into two equations, one for the real plane and one for the imaginary plane, and then it's just plain algebra. C is the coordinate of the point that you want to test, and the initial value of Z is zero.
Here's an image from my multi-threaded Mandelbrot generator :)
Actually the Mandelbrot set is the set of complex numbers for which the iteration converges.
So the only points in the Mandelbrot set are that big boring colour in the middle. and all of the pretty colours you see are doing nothing more than representing the rate at which points near the boundary (but the wrong side) spin off to infinity.
In mathspeak,
M = {c in C : lim (k -> inf) z_k = 0 } where z_0 = c, z_(k+1) = z_k^2 + c
ie pick any complex number c. Now to determine whether it is in the set, repeatedly iterate it z_0 = c, z_(k+1) = z_k^2 + c, and z_k will approach either zero or infinity. If its limit (as k tends to infinity) is zero, then it is in. Otherwise not.
It is possible to prove that once |z_k| > 2, it is not going to converge. This is a good exercise in optimisation: IIRC |Z_k|^2 > 2 is sufficient... either way, squaring up will save you the expensive sqrt() function.
Wolfram Mathworld has a nice site talking about the Mandelbrot set.
A Complex class will be most helpful.
Maybe an example like this will stimulate some thought. I wouldn't recommend using an Applet.
You have to know how to do add, subtract, multiply, divide, and power operations with complex numbers, in addition to functions like sine, cosine, exponential, etc. If you don't know those, I'd start there.
The book that I was taught from was Ruel V. Churchill "Complex Variables".
/d{def}def/u{dup}d[0 -185 u 0 300 u]concat/q 5e-3 d/m{mul}d/z{A u m B u
m}d/r{rlineto}d/X -2 q 1{d/Y -2 q 2{d/A 0 d/B 0 d 64 -1 1{/f exch d/B
A/A z sub X add d B 2 m m Y add d z add 4 gt{exit}if/f 64 d}for f 64 div
setgray X Y moveto 0 q neg u 0 0 q u 0 r r r r fill/Y}for/X}for showpage
Given two points, A and B, defined by longitude and latitude I want to determine if another point C is ~between~ A and B. ~between~ is hard for me to define. I don't mean on the line - it almost certainly won't be.
Geometric diagram http://www.freeimagehosting.net/uploads/b5c5ebf480.jpg
In this diagram, point C is ~between~ A and B because it is between the normals of points A and B and the line between them (normals denoted by thin line). Point D is not ~between~ A and B but it is ~between~ B and F.
Another way of saying this is that I want to determine if the triangles ABC and ABD are obtuse or not.
Note that the points will be very close together - within 10s of metres normally.
I'm thinking that the law of haversines may help but I don't know what the inverse of haversine is.
Many thanks for all help.
First, start with translating your points to local tangent plane. We will use the fact that your triangles are much smaller than the earth's radius. (Tangent space is such that equal deltas in each of the two coordinates correspond to equal distances)
This is done by dividing longtitudes by sin(lat):
A_local_x = A_lat_rads;
A_local_y = A_lon_rads/sin(A_lat_rads);
Then,
Compute lengths:
double ABsquared = (A_local_x - B_local_x)*(A_local_x - B_local_x) + (A_local_y - B_local_y)*(A_local_y - B_local_y);
double BCsquared = ..., ACsquared.
Finally:
bool obtuse = (ABsquared+BCsquared < ACsquared) || (ABsquared+ACsquared < BCsquared);
Obtuse means "it is not within the line", as you say. I am not checking whether triangle ABC is obtuse, but whether the angles at B and at A are obtuse. That's it.
note: I haven't tested this code. Please tell me how it works by plugging different points, if there's a bug I will fix it.
If your points are very close—10s of meters could easily qualify—you may be able to approximate it as a 2-d problem, and just calculate the angles CAB, θ and CBA, φ (using dot product). If both θ and φ are less than π/2, you C is "between".
cos(θ) = (AC · AB) / (|AC| |AB|)
If that approximation isn't good enough for you, you will need spherical trigonometry, which is also not too hard.
Note that if I understood your problem correctly, you need to check if the angles CAB and CBA are acute, not that the angle ACB is obtuse or acute.