Draw a circle with given curvature - math

I want to draw a circe with given curvature k.
I just need to know the y-coordinate for a given x-coordinate. So i.e. z = 1/k + sqrt(1/k^2 - x^2) is what I would normally use.
The problem is that my k is allowed to become zero. Which means that my circle becomes a line. For a mathematican thats no problem. But for my computer it is. For example when k is minimum double value, y will be infinity, for k == 0 I receive nan for y.
Are there any ways to get this done?

Given such border cases, I would just test the input parameters to see if one of them applies and use separate logic to just draw a horizontal or vertical line as appropriate if a border case applies.
That is a fairly common approach and computationally quite efficient.
When testing for border cases, test k to ensure that:
- k^2 will not overflow the data type in use
- k is not so small that 1/k^2 will underflow the data type in use
In either case, use the appropriate border case logic. Thanks #Godeke for pointing that out.

You gave the formula
y1 = 1/k + sqrt(1/k^2 - x^2) // (1)
which describes the upper half of the circle with radius 1/k and center (0, 1/k). Now for small k these values become very large and will eventually be outside of your drawing are.
The lower half of the circle is given by
y2 = 1/k - sqrt(1/k^2 - x^2) // (2)
For k approaching zero, these values "approach" the line y = 0. But for small values of k, (2) computes the difference of two large numbers. This causes a loss of precision and possible overflow.
But you can rewrite the formula (2) into the equivalent form
y2 = k * x^2 / (1 + sqrt(1 - k^2 * x^2)) // (2a)
Now you can compute the lower half of the circle for small values of k and even for k = 0 without any overflow or precision loss.
For the upper half you always have y1 >= 1/k. So if 1/k is larger than the boundary of your drawing area, you can ignore the upper value. Otherwise you can compute y1 via
y1 = 2/k - y2

Related

Finding distinct numbers in a range, given some step size

I have been trying to come up with some mathematical formula to find the distinct numbers in a given range with a variable step size.
First I tried in 1-D, like in a range [0,10], with a step size of 0.1.
Solution: In between 0.1-1,1.1-2,.......,9.1-10. Every sub-range has 10 numbers, so total #=100. Including 0, we get 100+1=101.
Next is to find the total points in a grid (2D).
Solution: In a grid, with two axes x and y, we need to find the total # points. x is in the range [-10,10] and y in the range [-10,10], with a step size of 0.1.
With 2D it gets complicated, and in higher dimensions and with varying step size, it becomes really messy. I was just wondering if there is a generalized formula or method to find the points.
Grid or the 2D space looks something like this
It's not significantly more complicated in higher dimensions, because the optimal packing in higher dimensions is a grid. Suppose you have x in the closed range [x1, x2] in steps of dx and you have y in the closed range [y1, y2] in steps of dy. Just on the x axis, there are 1 + floor((x2 - x1) / dx) values, and just on the y axis there are 1 + floor((y2 - y1) / dy) values, so in the 2d grid there are
(1 + floor((x2 - x1) / dx)) * (1 + floor((y2 - y1) / dy))
distinct points.
This generalizes to higher dimensions (assuming dx, dy, d... are constant). So just find the number of distinct points in each dimension and multiply those values together to get the number of distinct points in the n-dimensional region.

Efficient way to store 3D normal vector using two floats

I need to store 3D normal vectors, that is vectors (x, y, z) such that x^2 + y^2 + z^2 = 1. But due to space constraints I can only use 2 floats to store it.
So by storing only x and y, the third component can be computed as sqrt(1 - x^2 - y^2), i.e. one square root, two products and two subtractions.
What would be the most efficient way to store the vectors, so that reading them is as fast as possible, and if possible without bias towards one spatial direction?
Edit
Now using the values (a, b) with a = x - y and b = x + y.
You could satisfy your space constraint by storing the vectors via spherical coordinates. As is well known, each point on the unit sphere, i.e., each unit vector, has at least one pair of spherical coordinates characterizing it.
Or if you want something convoluted: The complex square function maps the unit disk to a double cover of it. So you could use the left half-disk for the upper half-sphere and the right half-disk for the lower half-sphere.
SphereFromDisk(a,b)
a2=a*a; b2=b*b; r2=a2+b2; // assert r2 <= 1
x = a2 - b2;
y = 2*a*b
z = sqrt(1-r2*r2)
if(a<0 or (a=0 and b<0) z=-z
return (x,y,z)

Calculating the distance between 2 points in 2D Space?

So the formula is basically:
xd = x2-x1
yd = y2-y1
Distance = sqrt(xd * xd + yd * yd)
But surely the formula has to be different depending on whether something is above, below, left, or right of the other object?
Like, if I have a sprite in the middle of the screen, and an enemy somewhere below, would that require changing the "x2-x1" (Let's just say the player sprite is x1, enemy is x2) the other way around if the enemy was above instead?
Distance in the sense you describe above will always be a positive value. The sum of the square of real numbers will always be positive, and the square root of a positive number will also always be positive. So, it doesn't matter whether you define xd = x2-x1 or xd = x1-x2. They only differ by their sign and so both have the same absolute value which means they both square to the same value.
So, there aren't really any special cases here. The formulation of the distance measure accommodates all of the concerns you raise.
Math.Sqrt(Math.Pow (a.X-b.X, 2) + Math.Pow (a.Y-b.Y, 2));
Try this. It should work!
yes, you are very right. In my case, I have to calculate distance between two points in 2D. I put x1 for swarm,x2 for intruder along X-Axis and y1 for intruder and y2 for swarm along Y-Axis.
d=sqrt((swarm(de,1) - (intruderX)).^2 + (swarm(de,2)-intruderY).^2);
[Distance is not calculated accurately, I want when intruder comes inside the circle of any swarm particle, it must be detected][1], some times, intruder comes inside the circle but not be detected. This is my problem. Anyone, who solve my problem, will be very grateful to them.
for de = 1:Ndrones
d = sqrt((swarm(de,1) - (intruderX)).^2 + (swarm(de,2)-intruderY).^2);
if(d<=rad) % intruder has been detected
x = intruderX;
y = intruderY;
title('Intruder Detected');
text(x,y+5,sprintf('Intruder'));
text(500,900,sprintf('Iterations: %.2f',iter));
plot(swarm(:,1),swarm(:,2));
for i=1:Ndrones
swarm(:, 9) = 100; %restart the minimum calculation
end
return;
end
end % end of de loop
[1]: http://i.stack.imgur.com/SBP27.png

Simple math formula verification (normalize 0-100)

How do I normalize any given number between 0 and 100?
The min is 0 and the max has no bounds (it's the search volume for a keyword).
normalized = (x-min(x))/(max(x)-min(x)) won't work since I have no definition of max.
Arcus tangens
Algebraically, you might start with some function that has poles, e.g. tan, and use its inverse, atan. That inverse will never exceed a given limit, namely π/2 in this case. Then you can use a formula of the kind
f(x) = 100 * 2/π * atan(x - min)
If that doesn't produce “nice” results for small inputs, you might want to preprocess the inputs:
f(x) = 100 * 2/π * atan(a*(x - min))
for some suitably chosen a. Making a larger than one increases values, while for 0 < a < 1 you get smaller values. According to a comment, the latter is what you'd most likely want.
You could even add a power in there:
f(x) = 100 * 2/π * atan(a*(x - min)^b) = 100 * 2/π * atan(pow(a*(x - min), b))
for some positive parameter b. Having two parameters to tweak gives you more freedom in adjusting the function to your needs. But to decide on what would be good fits, you might have to decide up front as to what values you'd expect for various inputs. A bit like in this question, although there the input range is not unbounded.
Stereographic projection
If you prefer geometric approaches: you can imagine your input as the positive half of the x axis, namely the ray from (0,0) to (∞,0). Then imagine a circle with center (0,1) and radius 1 sitting on that line. If you connect the point (0,2) with any point on the ray, the connecting line will intersect the circle in one other point. That way you can map the ray onto the right half of the circle. Now take either the angle as seen from the center of the circle, or the y coordinate of the point on the circle, or any other finite value like this, normalize input and output properly, and you have a function matching your requirements. You can also work out a formula for this, and atan will likely play a role in that.

Projecting to a 2D Plane for Barycentric Calculations

I have three vertices which make up a plane/polygon in 3D Space, v0, v1 & v2.
To calculate barycentric co-ordinates for a 3D point upon this plane I must first project both the plane and point into 2D space.
After trawling the web I have a good understanding of how to calculate barycentric co-ordinates in 2D space, but I am stuck at finding the best way to project my 3D points into a suitable 2D plane.
It was suggested to me that the best way to achieve this was to "drop the axis with the smallest projection". Without testing the area of the polygon formed when projected on each world axis (xy, yz, xz) how can I determine which projection is best (has the largest area), and therefore is most suitable for calculating the most accurate barycentric co-ordinate?
Example of computation of barycentric coordinates in 3D space as requested by the OP. Given:
3D points v0, v1, v2 that define the triangle
3D point p that lies on the plane defined by v0, v1 and v2 and inside the triangle spanned by the same points.
"x" denotes the cross product between two 3D vectors.
"len" denotes the length of a 3D vector.
"u", "v", "w" are the barycentric coordinates belonging to v0, v1 and v2 respectively.
triArea = len((v1 - v0) x (v2 - v0)) * 0.5
u = ( len((v1 - p ) x (v2 - p )) * 0.5 ) / triArea
v = ( len((v0 - p ) x (v2 - p )) * 0.5 ) / triArea
w = ( len((v0 - p ) x (v1 - p )) * 0.5 ) / triArea
=> p == u * v0 + v * v1 + w * v2
The cross product is defined like this:
v0 x v1 := { v0.y * v1.z - v0.z * v1.y,
v0.z * v1.x - v0.x * v1.z,
v0.x * v1.y - v0.y * v1.x }
WARNING - Almost every thing I know about using barycentric coordinates, and using matrices to solve linear equations, was learned last night because I found this question so interesting. So the following may be wrong, wrong, wrong - but some test values I have put in do seem to work.
Guys and girls, please feel free to rip this apart if I screwed up completely - but here goes.
Finding barycentric coords in 3D space (with a little help from Wikipedia)
Given:
v0 = (x0, y0, z0)
v1 = (x1, y1, z1)
v2 = (x2, y2, z2)
p = (xp, yp, zp)
Find the barycentric coordinates:
b0, b1, b2 of point p relative to the triangle defined by v0, v1 and v2
Knowing that:
xp = b0*x0 + b1*x1 + b2*x2
yp = b0*y0 + b1*y1 + b2*y2
zp = b0*z0 + b1*z1 + b2*z2
Which can be written as
[xp] [x0] [x1] [x2]
[yp] = b0*[y0] + b1*[y1] + b2*[y2]
[zp] [z0] [z1] [z2]
or
[xp] [x0 x1 x2] [b0]
[yp] = [y0 y1 y2] . [b1]
[zp] [z0 z1 z2] [b2]
re-arranged as
-1
[b0] [x0 x1 x2] [xp]
[b1] = [y0 y1 y2] . [yp]
[b2] [z0 z1 z2] [zp]
the determinant of the 3x3 matrix is:
det = x0(y1*z2 - y2*z1) + x1(y2*z0 - z2*y0) + x2(y0*z1 - y1*z0)
its adjoint is
[y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1]
[y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2]
[y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0]
giving:
[b0] [y1*z2-y2*z1 x2*z1-x1*z2 x1*y2-x2*y1] [xp]
[b1] = ( [y2*z0-y0*z2 x0*z2-x2*z0 x2*y0-x0*y2] . [yp] ) / det
[b2] [y0*z1-y1*z0 x1*z0-x0*z1 x0*y1-x1*y0] [zp]
If you need to test a number of points against the triangle, stop here. Calculate the above 3x3 matrix once for the triangle (dividing it by the determinant as well), and then dot product that result to each point to get the barycentric coords for each point.
If you are only doing it once per triangle, then here is the above multiplied out (courtesy of Maxima):
b0 = ((x1*y2-x2*y1)*zp+xp*(y1*z2-y2*z1)+yp*(x2*z1-x1*z2)) / det
b1 = ((x2*y0-x0*y2)*zp+xp*(y2*z0-y0*z2)+yp*(x0*z2-x2*z0)) / det
b2 = ((x0*y1-x1*y0)*zp+xp*(y0*z1-y1*z0)+yp*(x1*z0-x0*z1)) / det
That's quite a few additions, subtractions and multiplications - three divisions - but no sqrts or trig functions. It obviously does take longer than the pure 2D calcs, but depending on the complexity of your projection heuristics and calcs, this might end up being the fastest route.
As I mentioned - I have no idea what I'm talking about - but maybe this will work, or maybe someone else can come along and correct it.
Update: Disregard, this approach does not work in all cases
I think I have found a valid solution to this problem.
NB: I require a projection to 2D space rather than working with 3D Barycentric co-ordinates as I am challenged to make the most efficient algorithm possible. The additional overhead incurred by finding a suitable projection plane should still be smaller than the overhead incurred when using more complex operations such as sqrt or sin() cos() functions (I guess I could use lookup tables for sin/cos but this would increase the memory footprint and defeats the purpose of this assignment).
My first attempts found the delta between the min/max values on each axis of the polygon, then eliminated the axis with the smallest delta. However, as suggested by #PeterTaylor there are cases where dropping the axis with the smallest delta, can yeild a straight line rather than a triangle when projected into 2D space. THIS IS BAD.
Therefore my revised solution is as follows...
Find each sub delta on each axis for the polygon { abs(v1.x-v0.x), abs(v2.x-v1.x), abs(v0.x-v2.x) }, this results in 3 scalar values per axis.
Next, multiply these scaler values to compute a score. Repeat this, calculating a score for each axis. (This way any 0 deltas force the score to 0, automatically eliminating this axis, avoiding triangle degeneration)
Eliminate the axis with the lowest score to form the projection, e.g. If the lowest score is in the x-axis, project onto the y-z plane.
I have not had time to unit test this approach but after preliminary tests it seems to work rather well. I would be eager to know if this is in-fact the best approach?
After much discussion there is actually a pretty simple way to solve the original problem of knowing which axis to drop when projecting to 2D space. The answer is described in 3D Math Primer for Graphics and Game Development as follows...
"A solution to this dilemma is to
choose the plane of projection so as
to maximize the area of the projected
triangle. This can be done by
examining the plane normal; the
coordinate that has the largest
absolute value is the coordinate that
we will discard. For example, if the
normal is [–1, 0, 0], then we would
discard the x values of the vertices
and p, projecting onto the yz plane."
My original solution which involved computing a score per axis (using sub deltas) is flawed as it is possible to generate a zero score for all three axis, in which case the axis to drop remains undetermined.
Using the normal of the collision plane (which can be precomputed for efficiency) to determine which axis to drop when projecting into 2D is therefore the best approach.
To project a point p onto the plane defined by the vertices v0, v1 & v2 you must calculate a rotation matrix. Let us call the projected point pd
e1 = v1-v0
e2 = v2-v0
r = normalise(e1)
n = normalise(cross(e1,e2))
u = normalise(n X r)
temp = p-v0
pd.x = dot(temp, r)
pd.y = dot(temp, u)
pd.z = dot(temp, n)
Now pd can be projected onto the plane by setting pd.z=0
Also pd.z is the distance between the point and the plane defined by the 3 triangles. i.e. if the projected point lies within the triangle, pd.z is the distance to the triangle.
Another point to note above is that after rotation and projection onto this plane, the vertex v0 lies is at the origin and v1 lies along the x axis.
HTH
I'm not sure that the suggestion is actually the best one. It's not too hard to project to the plane containing the triangle. I assume here that p is actually in that plane.
Let d1 = sqrt((v1-v0).(v1-v0)) - i.e. the distance v0-v1.
Similarly let d2 = sqrt((v2-v0).(v2-v0))
v0 -> (0,0)
v1 -> (d1, 0)
What about v2? Well, you know the distance v0-v2 = d2. All you need is the angle v1-v0-v2. (v1-v0).(v2-v0) = d1 d2 cos(theta). Wlog you can take v2 as having positive y.
Then apply a similar process to p, with one exception: you can't necessarily take it as having positive y. Instead you can check whether it has the same sign of y as v2 by taking the sign of (v1-v0)x(v2-v0) . (v1-v0)x(p-v0).
As an alternative solution, you could use a linear algebra solver on the matrix equation for the tetrahedral case, taking as the fourth vertex of the tetrahedron v0 + (v1-v0)x(v2-v0) and normalising if necessary.
You shouldn't need to determine the optimal area to find a decent projection.
It's not strictly necessary to find the "best" projection at all, just one that's good enough, and that doesn't degenerate to a line when projected into 2D.
EDIT - algorithm deleted due to degenerate case I hadn't thought of

Resources