two dimensional identifier that is circular? - math

i need an identifier value that is circular when lerping to the next one. Example:
0,1,2,3
When lerping form any id to the next one in the row, we always get a value between both ids. Except for 3: when lerping to the next id (back to zero) it will be lerped through all ids.
So what i am searching for is something two dimesional for example:
(0,0), (0,1), (1,1), (1,0)
When learping from (1,0) to (0,0) it will lerp fine.
How do I warp this in a function or loop to convert for examle 0,1,2,3,4 to two-dimensional ids?

So you are looking for a function that takes a number k from 0 to N-1 and returns a point on a circle? That's what the trigonometric functions sine and cosine do by definition.
You would transform the number k into the point (x, y) where:
x = cos(k*360°/N)
y = sin(k*360°/N)
(Note that most software libraries take the input in radians and not degrees, if that's your case you would replace 360 degrees with 2*pi, or use a built-in "toRadians" function)

Related

Out of an array of arbitrary unit vectors, what is the most efficient method of finding the two vectors that have the largest angle?

So I'm attempting to make a wall system like the Sims. While it is 3D, it can be simplified to 2D (think a bird's eye view). A wall is defined by two points: a starting point an an ending point and the walls themselves have directions and can be simplified to unit vectors. Walls are also made with rectangular prisms, each of these prisms start at one point and end at another. So, bearing this in mind, sometimes walls have to be extended, otherwise there will be a small gap in the convex corner of the wall
if one of the points is shared between the walls. Any number of walls can be placed in a single position, so all of this in mind, a grid point's data could contain something like this (using Lua), each table represents a vector2, using a table for ease of visualization, this code won't actually work:
local gridPoint = {
{x = 1, y = 0},
{x = 0.7071, y = 0.7071},
{x = 0, y = 1},
{x = 0.7071, y = -0.7071},
}
Here's a visual of what the points might look like, where the intersection is the grid point and the walls are the vectors extending from the intersection, assuming each of the vectors have a length of 1 (excuse my terrible drawing skills). Since dot products flip when greater than 180 degrees, the largest angle would always be <=180.
So now, to get the angle between any two of points, we can just do math.deg(math.acos(v1:dot(v2))) to get the angle between these two points in degrees, where v1 is vector 1, v2 is vector 2, and dot is a function that returns the dot product of v1 and v2.
So up to this point, everything is fine. The issue is that I have to create two loops which goes through every single combination of possible dot products which I'm not sure is the best method of finding the largest angle, this is #gridPoint^2 possible combinations which is fine at lower numbers, but this number of possible combination increases exponentially with each new wall.
Is there an easier way of doing this?
This problem is equivalent to finding of the farthest pair of points, where all the points lie at unit circle.
Sort points - it is simpler to separate points with positive y (angles 0..Pi) into the first list, and points with negative y into the second list,sort them by X-coordinate, then join the first list and reversed second one. This stage takes O(nlogn) time
Then perform searching of the farthest points - fix the first point index (A[i]), walk through the list until squared distance A[i]-A[j+1] becomes less than squared distance A[i]-A[j]. So we find the farthest point A[j] for A[i]. Now increment i and search the farthest point for it - starting from j.
Repeat until j exceeds n.
This stage is linear because we move i and j only in forward direction. Essentially this is a method of rotating calipers, so you can get some implementation elsewhere.

3D rotations of a plane

I'm doing something where I have a plane in a coord sys A with a set of points already on it. I also have a normal vector in space N. How can I rotate the points on coord sys A so that the underlying plane will have the same normal direction as N?
Wondering if any one has a good idea on how to do this. Thanks
If you have, or can easily compute, the normal vector to the plane that your points are currently in, I think the easiest way to do this will be to rotate around the axis common to the two planes. Here's how I'd go about it:
Let M be the vector normal to your current plane, and N be the vector normal to the plane you want to rotate into. If M == N you can stop now and leave the original points unchanged.
Calculate the rotation angle as
costheta = dot(M,N)/(norm(M)*norm(N))
Calculate the rotation axis as
axis = unitcross(M, N)
where unitcross is a function that performs the cross product and normalizes it to a unit vector, i.e. unitcross(a, b) = cross(a, b) / norm(cross(a, b)). As user1318499 pointed out in a comment, this step can cause an error if M == N, unless your implementation of unitcross returns (0,0,0) when a == b.
Compute the rotation matrix from the axis and angle as
c = costheta
s = sqrt(1-c*c)
C = 1-c
rmat = matrix([ x*x*C+c x*y*C-z*s x*z*C+y*s ],
[ y*x*C+z*s y*y*C+c y*z*C-x*s ]
[ z*x*C-y*s z*y*C+x*s z*z*C+c ])
where x, y, and z are the components of axis. This formula is described on Wikipedia.
For each point, compute its corresponding point on the new plane as
newpoint = dot(rmat, point)
where the function dot performs matrix multiplication.
This is not unique, of course; as mentioned in peterk's answer, there are an infinite number of possible rotations you could make that would transform the plane normal to M into the plane normal to N. This corresponds to the fact that, after you take the steps described above, you can then rotate the plane around N, and your points will be in different places while staying in the same plane. (In other words, each rotation you can make that satisfies your conditions corresponds to doing the procedure described above followed by another rotation around N.) But if you don't care where in the plane your points wind up, I think this rotation around the common axis is the simplest way to just get the points into the plane you want them in.
If you don't have M, but you do have the coordinates of the points in your starting plane relative to an origin in that plane, you can compute the starting normal vector from two points' positions x1 and x2 as
M = cross(x1, x2)
(you can also use unitcross here but it doesn't make any difference). If you have the points' coordinates relative to an origin that is not in the plane, you can still do it, but you'll need three points' positions:
M = cross(x3-x1, x3-x2)
A single vector (your normal - N) will not be enough. You will need another two vectors for the other two dimensions. (Imagine that your 3D space could still rotate/spin around the normal vector, and you need another 2 vectors to nail it down). Once you have the normal and another one on the plane, the 3rd one should be easy to find (left- or right-handed depending on your system).
Make sure all three are normalized (length of 1) and put them in a matrix; use that matrix to transform any point in your 3D space (use matrix multiplication). This should give you the new coordinates.
I'm thinking make a unit vector [0,0,1] and use the dot-product along two planes to find the angle of difference, and shift all your points by those angles. This is assuming you want the z-axis to align with the normal vector, else just use [1,0,0] or [0,1,0] for x and y respectively.

How to find the two opposite normals or two segments?

I have a two segments AB and CD (in red). These two segments are facing each others. They are not completely parallel but will never be perpendicular to each others either.
From that, I need to find the two normals of these segments (in blue) that oppose each others (i.e. the two normals are outside ABCD). I know how to calculate the normals of the segments but obviously each segment has two normals, and I cannot figure out how to programmatically select the ones I need. Any suggestion?
Calculate the vector v between the midpoints of the two segments, pointing from AB to CD. Now the projection of the desired normal to AB onto v must be negative and the projection of the desired normal to CD onto v must be positive. So just calculate the normals, check against v, and negate the normals if needed to make them satisfy the condition.
Here it is in Python:
# use complex numbers to define minimal 2d vector datatype
def vec2d(x,y): return complex(x,y)
def rot90(v): return 1j * v
def inner_prod(u, v): return (u * v.conjugate()).real
def outward_normals(a, b, c, d):
n1 = rot90(b - a)
n2 = rot90(d - c)
mid = (c + d - a - b) / 2
if inner_prod(n1, mid) > 0:
n1 = -n1
if inner_prod(n2, mid) < 0:
n2 = -n2
return n1, n2
Note that I assume the endpoints define lines meeting the conditions in the problem. Nor do I check for the edge case when the lines have the same midpoint; the notion of "outside" doesn't apply in that case.
I think there are two cases to consider:
Case 1: Intersection between lines occurs outside the endpoints of either segment.
In this case the midpoint method suggested by #Michael J. Barber will work for sure. So form a vector between the midpoints of the segments, compute the dot product of your normal vectors with this midpoint vector and check the sign.
If you're computing the normal for lineA, the dot product of the normal with the vector midB -> midA should be +ve.
Case 2: Intersection between lines occurs inside the endpoints of one segment.
In this case form a vector between either one of the endpoints of the segment that does not enclose the intersection point and the intersection point itself.
The dot product of the normal for the segment that does enclose the intersection point and this new vector should be +ve.
You can find the outward normal for the other segment by requiring that the dot product between the two normals is -ve (which would only be ambiguous in the case of perpendicular segments).
I've assumed that the segments are not co-linear or actually intersecting.
Hope this helps.
You can reduce the four combinations for the signs as follows:
Calculate the dot product of the normals, a negative sign indicates that both show outside or inside.
As I suppose that your normals have unit lenght, you can detect parallelity if the dot product has magnitude one. A positive value indicates that both show in the same direction, a negative value says that both show in different directions.
It the normals are not parallel: parametrize lines as x(t) = x0 + t * n for a normal n and calculate the t for which both intersect. A negative t will indicate that both show outside. It is enough if you do this for one of the normals, as you reduced your combinations from 4 to 2 in step 1.
If both normals are parralel: Calculate the time t for which the normals hit the midpoint between of your segments. As in 2. is enough if you do this for one of the normals, as you reduced your combinations from 4 to 2 in step 1.

Calculating the Length of Intersections (through a 2d grid)

I have a line that I must do calculations on for each grid square the line passes through.
I have used the Superline algorithm to get all these grid squares. This gives me an array of X,Y coordinates to check.
Now, here is where I am stuck, I need to be able to calculate the distance traveled through each of the grid squares... As in, on a line not on either 90 degree or 45 degree angles, each grid square accommodates a different 'length' of the total line.
Image example here, need 10 reputation to post images
As you can see, some squares have much more 'line length' in them than others - this is what I need to find.
How do I work this out for each grid square? I've been at this for a while and request the help of the Stack Overflowers!
There may be some clever way to do this that is faster and easier, but you could always hack through it like this:
You know the distance formula: s=sqrt((x2-x1)^2+(y2-y1)^2). To apply this, you must find the x and y co-ordinates of the points where the line intersects the edges of each grid cell. You can do this by plugging the x and y co-ordinates of the boundaries of the cell into the equation of the line and solve for x or y as appropriate.
That is, each cell extends from some point (x0,y0) to (x0+1,y0+1). So we need to find y(x0), y(x0+1), x(y0), and x(y0+1). For each of these, the x or y value found may or may not be within the ranges for that co-ordinate for that cell. Specifically, two of them will be and two won't. The two that are correspond to the edges that the line passes through, and the two that aren't are edges that it doesn't pass through.
Okay, maybe this sounds pretty confusing, so let's work through an example.
Let's say your line has the equation x=2/3 * y. You want to know where it intersects the edges of the cell extending from (1,0) to (2,1).
Plug in x=1 and you get y=2/3. 2/3 is in the legal range for y -- 0 to 1 -- so (1,2/3) is a point on the edge where the line intersects this cell. Namely, the left edge.
Plug in x=2 and you get y=4/3. 4/3 is outside the range for y. So the line does not pass through the right edge.
Plug in y=0 and you get x=0. 0 is not in the range for x, so the line does not pass through the bottom edge.
Plug in y=1 and you get x=3/2. 3/2 is in the legal range for x, so (3/2,1) is another intersection point, on the top edge.
Thus, the two points where the line intersects the edges of the cell are (1,2/3) and (3/2,1). Plug these into the distance formula and you'll get the length of the line segement through this cell, namely sqrt((1-3/2)^2+(2/3-1)^2)=sqrt(1/4+1/9)=sqrt(13/36). You can approximate that to any desired level of precision.
To do this in a program you'd need something like: (I'll use pseudo code because I don't know what language you're using)
// Assuming y=mx+b
function y(x)
return mx+b
function x(y)
return (y-b)/m
// cellx, celly are co-ordinates of lower left corner of cell
// Upper right must therefore be cellx+1, celly+1
function segLength(cellx, celly)
// We'll create two arrays pointx and pointy to hold co-ordinates of intersect points
// n is index into these arrays
// In an object-oriented language, we'd create an array of point objects, but whatever
n=0
y1=y(cellx)
if y1>=celly and y1<=celly+1
pointx[n]=cellx
pointy[n]=y1
n=n+1
y2=y(cellx+1)
if y2>=celly and y2<=celly+1
pointx[n]=cellx+1
pointy[n]=y2
n=n+1
x1=x(celly)
if x1>=cellx and x1<=cellx+1
pointx[n]=x1
pointy[n]=celly
n=n+1
x2=x(celly+1)
if x2>=cellx and x2<=cellx+1
pointx[n]=x2
pointy[n]=celly+1
n=n+1
if n==0
return "Error: line does not intersect this cell"
else if n==2
return sqrt((pointx[0]-pointx[1])^2+(pointy[0]-pointy[1])^2)
else
return "Error: Impossible condition"
Well, I'm sure you could make the code a little cleaner, but that's the idea.
have a look at Siddon's algorithm: "Fast calculation of the exact radiological path for a three-dimensional CT array"
unfortunately you need a subscription to read the original paper, but it is fairly well described in this paper
Siddon's algorithm is an O(n) algorithm for finding the length of intersection of a line with each pixel/voxel in a regular 2d/3d grid.
Use the Euclidean Distance.
sqrt((x2-x1)^2 + (y2-y1)^2)
This gives the actual distance in units between points (x1,y1) and (x2,y2)
You can fairly simply find this for each square.
You have the slope of the line m = (y2-y1)/(x2-x1).
You have the starting point:
(x1,y2)
What is the y position at x1 + 1? (i.e. starting at the next square)
Assuming you set your starting point to 0 the equation of this line is simply:
y_n = mx_n
so y_n = (y2-y1)/(x2-x1) * x_n
Then the coordinates at the first square are (x1,y1) and at the nth point:
(1, ((y2-y1)/(x2-x1))*1)
(2, ((y2-y1)/(x2-x1))*2)
(3, ((y2-y1)/(x2-x1))*3)
...
(n, ((y2-y1)/(x2-x1))*n)
Then the distance through the nth square is:
sqrt((x_n+1 - x_n)^2 + (y_n+1 - y_n)^2)

How do you calculate the reflex angle given two vectors in 3D space?

I want to calculate the angle between two vectors a and b. Lets assume these are at the origin. This can be done with
theta = arccos(a . b / |a| * |b|)
However arccos gives you the angle in [0, pi], i.e. it will never give you an angle greater than 180 degrees, which is what I want. So how do you find out when the vectors have gone past the 180 degree mark? In 2D I would simply let the sign of the y-component on one of the vectors determine what quadrant the vector is in. But what is the easiest way to do it in 3D?
EDIT: I wanted to keep the question general but here we go. I'm programming this in c and the code I use to get the angle is theta = acos(dot(a, b)/mag(a)*mag(b)) so how would you programmatically determine the orientation?
This works in 2D because you have a plane defined in which you define the rotation.
If you want to do this in 3D, there is no such implicit 2D plane. You could transform your 3D coordinates to a 2D plane going through all three points, and do your calculation inside this plane.
But, there are of course two possible orientations for the plane, and that will affect which angles will be > 180 or smaller.
I came up with the following solution that takes advantage of the direction change of the cross product of the two vectors:
Make a vector n = a X b and normalize it. This vector is normal to the plane spanned by a and b.
Whenever a new angle is calculated compare it with the old normal. In the comparison, treat the old and the current normals as points and compute the distance between them. If this distance is 2 the normal (i.e. the cross product a X b has flipped).
You might want to have a threshold for the distance as the distance after a flip might be shorter than 2, depending on how the vectors a and b are oriented and how often you update the angle.
One solution that you could use:
What you effectively need to do is create a plane that one of the vectors is coplanar to.
Getting the cross product of both vectors will create a plane, then is you get the normal of this plane, you can get the angle between this and the vector you need to get the signed angle for, and you can use the angle to determine the sign.
If the angle is greater than 90 degrees, then it is below the created plane; less than 90 degrees, and it is above.
Depending on cost of calculations, the dot product can be used at this stage instead of the angle.
Just make sure that you always calculate the normals by the same order of vectors.
This is useable more easily if you're using the XYZ axes, and that's what you're comparing against, since you already have the vectors needed for the plane.
There are possbly more efficient solutions, but this is one I came up with.
Edit: clarification of created vectors
a X b = p. This is perpendicular to both a and b.
Then, do either:
a X p or b X p to create another vector that is the normal to the plane created by the 2 vectors. Choice of vector depends on which you're trying to find the angle for.
Strictly speaking, two 3D vectors always have two angles between them - one below or equal to 180, the other over or equal to 180. Arccos gives you one of them, you can get the other by subtracting from 360. Think of it that way: imagine two lines intersect. You have 4 angles there - 2 of one value, 2 of another. What's the angle between the lines? No single answer. Same here. Without some kind of extra criteria, you can not, in theory, tell which of the two angle values should be taken into account.
EDIT: So what you really need is an arbitrary example of fixing an orientation. Here's one: we look from the positive Z direction. If the plane between the two vectors contains the Z axis, we look from the positive Y direction. If the plane is YZ, we look from the positive X direction. I'll think how to express this in coordinate form, then edit again.

Resources