I have an opengl arbitrary rotation matrix and would like to remove the X & Y axis, leaving me with only the Z axis?
Is this possible? Any pointers on how to do it?
Just thinking out loud here, but can't you use the matrix to rotate a vector like (1,0,0), then do atan2(y,x) to see how much it's rotated and then build a new matrix to rotate through the Z axis by that much?
In a rotation that is only around the z-axis, the z axis should remain unchanged. So the above recommendation is sort of the reverse of what you want.
Let's assume you have an arbitrary OpenGL matrix:
| r_xx r_xy r_xz t_x |
| r_yx r_yy r_yz t_y |
M = | r_zx r_zy r_zz t_z |
| 0 0 0 1 |
Where the t_i elements are translations and the r_jk elements are components of rotation. You want a matrix that looks like this:
| cos(th) sin(th) 0 t_x |
|-sin(th) cos(th) 0 t_y |
| 0 0 1 t_z |
| 0 0 0 1 |
Unless the matrix has scaling factors or is close to a singularity, you should be able to get this by just zeroing out the z parts of the matrix and then re-normalizing the columns. Since an OpenGL matrix is column major order:
double xLen = sqrt(M[0]*M[0] + M[1]*M[1]); // Singularity if either of these
double yLen = sqrt(M[4]*M[4] + M[5]*M[5]); // is equal to zero.
M[0]/=xLen; M[1]/=xLen; M[2]=0; // Set the x column
M[4]/=yLen; M[5]/=yLen; M[6]=0; // Set the y column
M[8]=0; M[9]=0; M[10]=1; // Set the z column
//Don't change the translation column
Related
This is a reverse question of the following:
Determine position of number in a grid of numbers centered around 0 and increasing in spiral
The two modalities are:
index -> coordinate (done, see question above)
coordinate -> index (my question)
The part I'm stuck on is getting the sector from a raw coordinate without a massive ugly branch of logic.
Is there a simple arithmetic way to determine the sector? How would you reverse this function to take a coordinate pair and return the index?
This is a Ulam spiral it has some interesting properties if you draw the positions of prime numbers on the spiral.
25|26|27|28|29|30
24| 9|10|11|12|31
23| 8| 1| 2|13|32
22| 7| 0| 3|14|33
21| 6| 5| 4|15|34
20|19|18|17|16|35
........ |36
The first thing to note is the position of the square numbers. These lie on the diagonals, with odd squares in the upper left diagonal and even squares in the lower right diagonal.
25| | | | |
| 9| | | |
| | 1| | |
| | 0| | |
| | | 4| |
| | | |16|
........ |36
Lets look at the diagonals these have coordinates (x,y)
(-2,3)| | | | | (3,3)
| (-1,2)| | | (2,2)|
| | (0,1)| (1,1)| |
| | (0,0)| | |
|(-1,-1)| |(1,-1)| |
(-2,-2)| | | |(2,-2)|
| | | | |(3,-3)
First note the diagonals, if y>=0 and x=1-y we are on the top left diagonal and the value is (2 y-1)^2 or (1-2x)^2.
If y<0 and x=-y we are on the bottom right diagonal and the value is (2x)^2=4x^2 or (-2y)^2 = 4y^2.
We are on a horizontal rows at the top if y>=0 and x >= 1-y, xpos=x+y-1. The value will be (2 y-1)^2 + pos.
Horizontal rows at the bottom have y<0 and x >=y , x<=-y. The number of steps to the left of the square number is pos=-x-y. The value is 4y^2+pos.
Similar calculations work for the vertical rows. This can all be encoded in the function
function spiral(x,y) {
var pos,squ;
// Horizontal row at top
if(y>=0 && ( x >= 1-y && x<y ) ) {
pos = x+y-1;
squ = (2 *y-1)*(2*y-1);
// Horizontal row at bottom
} else if( y < 0 && ( x >= y && x<= -y ) ) {
pos = -x-y;
squ = 4*y*y;
// Vertical row on right
} else if( x >0 ) {
pos = -x-y;
squ = 4*x*x;
// Vertical row on left
} else {
squ = (1-2*x)*(1-2*x);
pos = x+y-1;
}
return squ+pos;
}
I've a javascript implementation at fiddle. This does the spiral for numbers upto 99.
A slightly simpler function is
spiral = function(x,y) {
var res;
var u = x+y;
var v = x-y;
if(u>0) {
if(v>=0) {
x <<= 1;
res = x*(x-1) + v;
} else {
y <<= 1;
res = y*(y-1) + v;
}
} else {
if(v<0) {
x <<= 1;
res = -x*(1-x) - v;
} else {
y <<= 1;
res = -y*(1-y) - v;
}
}
return res;
}
Here u,v tell you how far you move in diagonal directions. The signs of two numbers tell you which sector you are in. We can get the base number for each horizontal/vertical edge by finding the values on the line x=y. Going to the north east these are 2, 12, 30 (i.e. 1*2, 3*4, 5*6) and to the southwest they are 6, 20, 42, (i.e. 2*3, 4*5, 6*7). The equations for these are 2*x*(2*x-1) and -2*x*(1-2*x) or the same using y. To get the index for each point we simple add or subtract v to these.
This uses 1 multiplication, 2 comparisons, 1 bit shift and 4 additions. It might be possible to remove one of the additions, but I pretty sure you need a multiplication and 2 comparisons.
This is going to be a very late answer, but I'm going to answer it anyways since I've had this exact issue myself and never really found a solid fix for the issues I've had with other answers. Here's a complimentary answer to all the other ones out there, because why not:
Here's some psuedocode for the solution I found:
// n is the number in the spiral at (x, y)
// m is an intermediate step towards calculating n
m = 2 * max(abs(x), abs(y)) - (x > -y) // this relies on booleans being evaluated as 0 or 1
n = m^2 + abs(x + (-1)^m * floor((m + 1) / 2)) + abs(y - (-1)^m * floor(m / 2))
In Python 3: (Latest tested in 3.7.0)
import math
def number_in_spiral(x, y):
m = 2 * max(abs(x), abs(y)) - (x > -y)
return m * m + abs(x + pow(-1, m) * math.floor((m + 1) / 2)) + \
abs(y - pow(-1, m) * math.floor(m / 2))
In JavaScript:
function number_in_spiral(x, y)
{
var m = 2 * Math.max(Math.abs(x), Math.abs(y)) - (x > -y);
return m * m + Math.abs(x + Math.pow(-1, m) * Math.floor((m + 1) / 2)) +
Math.abs(y - Math.pow(-1, m) * Math.floor(m / 2));
}
Just remember that y in this formula increases upwards, which isn't ideal in a lot of cases. In that case, either multiply the input y with -1, or substitute y with -y in every instance in the formula.
I hope this can be useful to someone. If not, it'll at least be useful to me when I inevitably return to this problem 4 years from now.
Consider the number of steps you take without changing direction. You will find that sequence to be 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, … The pattern should be obvious. Now after four such straight edges you are approximately back in the same corner. So you can find indices for the lines connecting these corners:
c0: 0, 1+1+2+2, …+3+3+4+4, …+5+5+6+6, …+7+7+8+8, …
c1: 1, …+1+2+2+3, …+3+4+4+5, …
c2: 1+1, …
c3: 1+1+2, …
For each of these, you can write a formula. The first would be something like this:
c0[i] = sum((2*i - 1) + (2*i - 1) + (2*i) + (2*i)) = sum(8*i - 2)
Now ask Wolfram Alpha. It will tell you that
c0[i] = 4i² + 2i
So if someone gives you an index n, you can solve for the last time you visited that edge line by solving the above equation for i, taking the positive solution, then rounding that down to the an integer. You can either do the same for the other edge lines, or accept to do one whole turn around the center in the worst case. Where a whole turn means four staright segments, you don't want to go field by field.
Wolfram Alpha also prints the first few elements of the sequence: 6,20,42,72,110. You can use that to look this up in OEIS, and find A002943 where one comment reads
Write 0,1,2,... in clockwise spiral; sequence gives numbers on one of 4 diagonals.
But I can assure you, it works for counter-clockwise spirals just the same…
I'm making a quad tree to hold values for a large square grid. Many regions of the grid are filled with the same value so instead of holding the same value in many nodes I hold one node that tells the function looking for values anywhere in that region that the value is the one that node holds. When lots of nodes together are very different I put them in a single node that holds an array of those values to cut out the overhead of having many middle-man nodes.
For simplicity I'll use byte sized examples, but my grid is much larger. A 16x16 gird of 256 values might look like this:
[ root ] <----16x16
/ | | \
/ [1][1] [64] <-+--8x8
[ node ] <-+
/ | | \
/[16][16][16] <-+--4x4
[ node ] <-+
| | | \
[1][1][1] [4] <----2x2
These values change frequently during the course of my application so the arrays in leaf nodes have to get divided and concatenated a lot. I started out using a standard 2D array but realized that if I try to take out a quadrant of that array it'd be grabbing data from many places because I'm essentially asking for one half of one half of the 1D arrays in the 2D arrays. My solution was to nest quadrants inside larger quadrants so that dividing a 1D array into quarters would give you the values for the four nested quadrants.
I've arranged them top to bottom, left to right. These grids illustrate the allocation scheme on two scales that remains consistent across all scales.
0 1 0 1 2 3
0 | 0| 1| 0 | 0 | 1 |
1 | 2| 3| 1 |_____|_____|
2 | 2 | 3 |
3 |_____|_____|
Here is what it'd look like if you printed the index of the 1D array out onto a 2D grid.
0 1 2 3 4 5 6
0 | 0| 1| 4| 5|16|17|20|
1 | 2| 3| 6| 7|18|19|
2 | 8| 9|12|13|
3 |10|11|14|15|
4 |32|33|
5 |34|35|
6 |40| etc.
So of course now that I've got a solution to cutting up the grid I've just made it annoying to retrieve anything from it. Here is how I currently get the index of the 1D array from (x, y) co-ords.
uint index( uint x, uint y ){
uint l = sqrt(array.length);
uint index;
uint chunk = array.length;
while ( l > 1 ){
l /= 2;
chunk /= 2;
if( y >= l ){
y -= l;
index += chunk;
}
chunk /= 2;
if( x >= l ){
x -= l;
index += chunk;
}
}
return index;
}
It works but it's painful... while thinking about it after I'd written it, it occurred to me that I was manipulating bits at a high level. So it should theoretically be possible to look at the bits of (x, y) directly to determine bits of the index for the array without doing as much work.
I've been trying to work out what I need to do in binary by looking at x, y, and index binary together, but I'm not having any luck deriving a method beyond "If x ends in 1, the index is odd".
N7 N6 N5 N4 N3 N2 N1 N0
x 5 |--|--|--|--|00|00|01|01|
y 1 |--|--|--|--|00|00|00|01|
Index 17 |00|00|00|00|00|01|00|01|
N7 N6 N5 N4 N3 N2 N1 N0
x 1 |--|--|--|--|00|00|00|01|
y 6 |--|--|--|--|00|00|01|10|
Index 41 |00|00|00|00|01|00|10|01|
I'm certain that the x y values can tell me which quadrant the index is in with x giving me east or west and y giving me north or south at any scale. I think I might need to make a bit mask or something, idk, I've never had to deal with bits directly outside of college, well, beyond bit-flags. So if someone can help me out with what I can do to get the index that'd be a huge help!
Can you tell me an easy way to draw graph(2+x, sin(x), cos(x+3)/3.....) in PS format?
For example, I want to draw f(x) = 2+x, with the following values:
Table of values:
Value of X = -5 | -4 | -3 | -2 | -1 | -0 | 1 .....
Value of Y = -3 | -2 | -1 | 0 | 1 | 2 | 3 .....
How to draw this graph? Draw lineto, draw polygon or use curve command?
What do you think is the best solution?
There are a number of different ways you can do this. If you have a set of coordinates to plot, you can put them in an array, and draw the points while iterating through the array.
/XValues [ -5 -4 -3 -2 -1 0 1 ] def % eg. XValues 0 get ==> -5
/YValues [ -3 -2 -1 0 1 2 3 ] def % YValues 0 get ==> -3
XValues 0 get YValues 0 get % X[0] Y[0]
moveto % move to first point
1 1 XValues length 1 sub { % i push integer i = 1 .. length(XValues)-1 on each iteration
XValues % i XVal push X array
1 index % i XVal i copy i from stack
get % i x get ith X value from array
YValues % i x YVal
2 index % i x YVal i i is 1 position deeper now, so 2 index instead of 1
get % i x y
lineto % i line to next point
pop % discard index variable
} for
Now, of course in Postscript the origin is at the bottom left corner by default, and 72 points make an inch. So these values (-5, -4, -2, etc) are not even going to be visible. So you usually want to start by translating to the center of where you want to draw the graph.
/Center { 300 400 } def % roughly the middle of US letter-size paper
Center translate
Then you want to scale the coordinate system so the graph features are visible. Scalefactor = DesiredSize / ExistingSize.
You could scan the dataset to find the existing size.
/Xmin 1000000 def % really high
/Xmax -1000000 def % really low
XValues { % x forall pushes each X value
dup Xmin lt { % x lower than Xmin?
dup /Xmin exch def % x set Xmin
} if % x
dup Xmax gt { % x higher than Xmax?
/Xmax exch def % set Xmax
}{ % x else (lower than Xmax)
pop % discard X value
} ifelse
} forall
/Datasize Xmax Xmin sub def % X size is (Xmax-Xmin)
6 72 mul DataSize div % scalefactor 6*72/(Xmax-Xmin)
dup % scalefactor scalefactor use same scaling for x and y
scale
But there's a snag when you're doing line-drawing. The width of the lines you draw also depend upon the current coordinate space, so if you scale up the space by a large factor, your lines will become undesirably wide. You can either unscale back to the normal space after you describe the path but before you call stroke. Or, fix the linewidth at the same time you scale.
Since we know how much we've increased the line width (it's the same scaling factor), we can adjust the linewidth graphics parameter in the inverse direction.
1 % push 1 for division
6 72 mul DataSize div % 1 scalefactor 6*72/(Xmax-Xmin)
dup dup % 1 scalefactor scalefactor scalefactor
scale % 1 scalefactor
div % 1/scalefactor
currentlinewidth mul setlinewidth % adjust line width
Now, since this is a graph of a function, we don't actually need the tables of values. We can calculate values on the fly by evaluating the function.
/func { 3 add cos 3 div } def % f(x) = cos(3+x)/3 define function y=f(x)
/Xini -5 def % named loop control parameters
/Xfin 1 def
/Xstep 1 def
Xini dup dup func moveto % moveto first point
Xstep add Xstep Xfin { % x
dup % x x
func % x f(x)
lineto % line to next point
} for
stroke
Finally, if you can take the derivative of the function (create a function which calculates the slope of the original function at each point), then you can use my answer over on TeX.SE to draw the graph with many curve segments instead of lines.
Given a point in 3D space, how can I calculate a matrix in homogeneous coordinates which will project that point into the plane z == d, where the origin is the centre of projection.
OK, let's try to sort this out, expanding on Emmanuel's answer.
Assuming that your view vector is directly along the Z axis, all dimensions must be scaled by the ratio of the view plane distance d to the original z coordinate. That ratio is trivially d / z, giving:
x' = x * (d / z)
y' = y * (d / z)
z' = z * (d / z) ( = d)
In homogenous coordinates, it's usual to start with P = [x, y, z, w] where w == 1 and the transformation is done thus:
P' = M * P
The result will have w != 1, and to get the real 3D coordinates we normalise the homogenous vector by dividing the whole thing by its w component.
So, all we need is a matrix that given [x, y, z, 1] gives us [x * d, y * d, z * d, z], i.e.
| x' | = | d 0 0 0 | * | x |
| y' | = | 0 d 0 0 | * | y |
| z' | = | 0 0 d 0 | * | z |
| w' | = | 0 0 1 0 | * | 1 |
which once normalised (by dividing by w' == z) gives you:
[ x * d / z, y * d / z, d, 1 ]
per the first set of equations above
I guess the projection you mean, as Beta says, consists in the intersection between:
the line formed by the origin O(0, 0, 0) and the point P(a, b, c) to be transformed
and the plane z=d
If I'm right, then let's have a look at the equation of this line, given by the vectorial product OP ^ OM = 0 (let's remind that the equation of a line between 2 given points A and B is given by AB ^ AM = 0, with M(x, y, z); this is a vectorial product, so all are vectors: 0 represents the null vector, AB is the vector AB, etc):
bz - cy = 0
cx - az = 0
cz - bx = 0
With z = d, we then have only 2 linearily independent equations:
bd = cy
cx = ad
So this projection converts a point P(a, b, c) into a point P'(ad/c, bd/c, d). For homogeneous coordinates that gives:
P'(ad/c, bd/c, d) = P'(ad/c, bd/c, cd/c)
= P'(ad/c: bd/c: cd/c: 1)
= P'(a: b: c: d/c)
EDIT : the matrix I 1st found was:
1, 0, 0, 0
0, 1, 0, 0
A = 0, 0, 1, 0
0, 0, 0, d/c
but it uses c which is the a coordinate of the point P !! This is nonsense, I couldn't find an expression of A that does not use these coordinates. I may not be familiar enough with homogeneous coordinates.
the homogeneous transformation matrix is (Euler roll-pitch-yaw):
|r1 r2 r3 dx|
|r4 r5 r6 dy|
|r7 r8 r9 dz|
|px py pz sf|
r1-9 are the elements of the combined rotation matrix: Rx*Ry*Rz (work it out)
dx dy and dz are displacement vector (d) elements
px py and pz are the perspective vector (p) elements
sf is the scaling factor
from here on, if you use the inverse of this, you get your projection as a perspective in any arbitrary plane by feeding rotations of your target plane, as well as it's position of origin wrt the reference one in (keep perspective vector at 0 0 0 and sf=1 for pure kinematics), you get T->T* = T1. Get T1^-1 (for kinematics, this is simply R' (transposed,), horizontal concatenated by -R'*d, then vertical concatenated simply by 0 0 0 1).
can have multiple planes e.g. a,b,c as a chain, in which case T1 = Ta*Tb*Tc*...
then, v(new) = (T1^-1)*v(old), job done.
I have a small question about vector and matrix.
Suppose a vector V = {v1, v2, ..., vn}. I generate a n-by-n distance matrix M defined as:
M_ij = | v_i - v_j | such that i,j belong to [1, n].
That is, each element M_ij in the square matrix is the absolute distance of two elements in V.
For example, I have a vector V = {1, 3, 3, 5}, the distance matrix will be
M=[
0 2 2 4;
2 0 0 2;
2 0 0 2;
4 2 2 0; ]
It seems pretty simple. Now comes to the question. Given such a matrix M, how to obtain the initial V?
Thank you.
Based on some answer for this question, it seems that the answer is not unique. So, now suppose that all the initial vector has been normalized to 0 mean and 1 variance. The question is: Given such a symmetric distance matrix M, how to decide the initial normalized vector?
You can't. To give you an idea of why, consider these two cases:
V1 = {1,2,3}
M1 = [ 0 1 2 ; 1 0 1 ; 2 1 0 ]
V2 = {3,4,5}
M2 = [ 0 1 2 ; 1 0 1 ; 2 1 0 ]
As you can see, a single M could be the result of more than one V. Therefore, you can't map backwards.
There is no way to determine the answer uniquely, since the distance matrix is invariant to adding a constant to all elements and to multiplying all the values by -1. Assuming that element 1 is equal to 0, and that the first nonzero element is positive, however, you can find an answer. Here is the pseudocode:
# Assume v[1] is 0
v[1] = 0
# e is value of first non-zero vector element
e = 0
# ei is index of first non-zero vector element
ei = 0
for i = 2...n:
# if all vector elements have been 0 so far
if e == 0:
# get the current distance from element 1 and its index
# this new element may still be 0
e = d[1,i]
ei = i
v[i] = e
elseif d[1,i] == d[ei,i] + v[ei]: # v[i] <= v[1]
# v[i] is to the left of v[1] (assuming v[ei] > v[1])
v[i] = -d[1,i]
else:
# some other case; v[i] is to the right of v[1]
v[i] = d[1,i]
I don't think it is possible to find the original vector, but you can find a translation of the vector by taking the first row of the matrix.
If you let M_ij = | v_i - v_j | and you translate all v_k for k\in [1,n] you will get
M_ij = | v-i + 1 - v_j + 1 |
= | v_i - v_j |
Hence, just take the first row as the vector and find one initial point to translate the vector to.
Correction:
Let v_1 = 0, and let l_k = | v_k | for k\in [2,n] and p_k the parity of v_k
Let p_1 = 1
for(int i = 2; i < n; i++)
if( | l_i - l_(i+1) | != M_i(i+1) )
p_(i+1) = - p_i
else
p_(i+1) = p_i
doing this for all v_k for k\in [2,n] in order will show the parity of each v_k in respect to the others
Then you can find a translation of the original vector with the same or opposite direction
Update (For Normalized vector):
Let d = Sqrt(v_1^2 + v_2^2 + ... + v_n^2)
Vector = {0, v_1 / d, v_2 / d, ... , v_n / d}
or
{0, -v_1 / d, -v_2 / d, ... , -v_n / d}