Get the coordinates of a matrix from its flatten index - math

How can we get the coordinates of a n dimensions matrix from its shape and its flatten index?
I mean, if for example I have the following (2,3) matrix of 2 dimensions:
[ [ 0, 1 ],
[ 2, 3 ],
[ *4*, 5 ] ]
...and I want to find the value of the index in bold from the coordinates [0,2], how can I do?
Or if I have this (2,2,5) matrix of 3 dimensions:
[ [ [ nil, nil ],
[ nil, nil ] ],
[ [ nil, nil ],
[ nil, nil ] ],
[ [ nil, *9* ],
[ nil, nil ] ],
[ [ nil, nil ],
[ nil, nil ] ],
[ [ nil, nil ],
[ nil, nil ] ] ]
...and I know the coordinates that I want have a flatten index value of 9, how can I find the relative coordinates are: [1,0,2]?
If possible, I would like to know a general and simple method, which work on matrix of any shape.
Many thanks for your help.

You can use this simple algorithm:
Let's say you have the matrix A[a][b][c][d] (where a,b,c,d are the dimensions) and the index X.
To get the first coordinate of the index X you simply divide X by b*c*d.
Let it be this next matrix, having the sizes [2][5] and the index X=7
0 1 2 3 4
5 6 7 8 9
You first divide X by the last dimension to find the first coordinate. X/5=1 . Then, from there you move forward and give X the value X%=5 . So you'll have X = 7%5 =2. Now you have to search the coordinates for the remaining dimensions using the same algorithm. If you reach the last dimension , the coordinate will be the remaining X, in this case 2. So the coordinates for X=7 are [1][2] , which is actually the answear.
Again, for the general case, where you have a,b,c,d dimensions.
I'll note with (yd) the y'th dimension.
X=index
(1d)=X/b*c*d
X gets value X % b*c*d
(2d)=X/c*d
X gets value X % c*d
(3d)=X/d
X gets value X % d
(4d)=X
If you had the dimensions [2][2][5] you would get:
X=9;
(1d) = 9/2*5 = 0
X = 9%10 = 9
(2d) = 9/5 = 1
X = 9%5 = 4
(3d) = 4
Result: [0][1][4] is the 9th element.
To get from [0][1][4] to the index 9 , you do the reverse algorithm by multiplying:
X=(1d)*b*c + (2d)*c + 3d = 0 + 1*5 +4 =9

Related

Netlogo Get a pushing force from all neighbours within a distance

For each turtle, I got an agentset called visible-neighbors which are the turtles within a distance.
I wanna get a pulling force on this turtle from each of visible-neighbors. And then sum the forces. For each single pulling force from one neighbor is following the equation force = 1 / distance ^ 2. My idea is to decompose the force to x and y components and then sum the forces on x and y, finally compose the force again.
Here is the code I have at the moment. It's runnable, but for some reasons it doesn't work.
to get-direction-naive
set visible-neighbors (other turtles) in-radius 75 with [ distance myself > 0 ]
ifelse any? visible-neighbors
[let distance-list [distance myself] of visible-neighbors
let x-cors [xcor] of visible-neighbors
let x-diff map [? -> ? - xcor] x-cors
let x-forces (map [ [a b] -> a / (b ^ 3) ] x-diff distance-list)
let x-sum sum x-forces
let y-cors [ycor] of visible-neighbors
let y-diff map [? -> ? - ycor] y-cors
let y-forces (map [ [a b] -> a / (b ^ 3) ] y-diff distance-list)
let y-sum sum y-forces
ifelse y-sum = 0
[ifelse x-sum > 0
[set heading 0]
[set heading 180] ]
[set heading atan x-sum y-sum]
]
[right random 360]
end
Any advices would be appreciated.
What are you finding that isn't working? You want the turtles to be pulled towards each other, is that correct? This seems to set turtles' headings as needed- I think you can drop the two nested ifelse statements, though. Check out this toy version:
to setup
ca
crt 20 [
setxy random-xcor random-ycor
pd
]
reset-ticks
end
to force-pull
ask turtles [
let visible-neighbors other turtles in-radius 10
ifelse any? visible-neighbors [
let distance-list [distance myself] of visible-neighbors
let x-cors [xcor] of visible-neighbors
let x-diff map [ ? -> ? - xcor] x-cors
let x-forces force-calc x-diff distance-list
let x-sum sum x-forces
let y-cors [ycor] of visible-neighbors
let y-diff map [? -> ? - ycor] y-cors
let y-forces force-calc y-diff distance-list
let y-sum sum y-forces
set heading atan x-sum y-sum
let hyp sqrt ( ( x-sum ^ 2 ) + ( y-sum ^ 2 ) )
fd e ^ ( -0.5 * hyp )
] [
right random 360
]
]
tick
end
to-report force-calc [ dif-list dist-list ]
report ( map [ [ a b ] -> a / ( b ^ 3 ) ] dif-list dist-list )
end
It seems to me that the turtles face the calculated heading properly and get drawn together.

Applying fast inverse to concatenated 4x4 affine transforms?

Is it possible to apply the fast inverse of a matrix to a concatenation of pure rotation and translation matrices, eg M = T2*R1*T1*R1?
If I have a rotation and translation stored in a 4x4 homogeneous column order matrix I can say:
M1 = [ R1 t1 ] given by [ 1 t1 ] * [ R1 0 ]
[ 0 1 ] [ 0 1 ] [ 0 1 ]
and
inv(M1) = [inv(R1) inv(R1)*-t1 ] given by [ 1 -t1 ] * [ inv(R1) 0 ]
[ 0 1 ] [ 1 1 ] * [ 0 1 ]
and since R1 is rotation only we know inv(R1) = transpose(R1) so we can simply say:
inv(M1) = [transp(R1) transp(R1)*-t1 ]
[ 0 1 ]
and now given some other similar rotation and translation matrix M2, if we say the concatenation of the the two in the form MFinal = M2 * M1 = T2*R1*T1*R1
can we say that
inv(MFinal) = [transp(MFinalRot) transp(MFinalRot)*-tfinal ]
[ 0 1 ]
where MFinalRot is the rotation part of the 4x4 matrix?
Additionally what if the order were more arbitrary for example MFinal2 = R3*T3 * T2*R2*T1*R1 , but still only individually rotations and translations?
Yes, if your 4x4 matrix is the concatenation of pure rotation and translation matrices, you should be able to compute a fast inverse as:
fast_inverse( [R1 t1] ) = [transpose(R1) transpose(R1)*(-t1)]
[0 1] [ 0 1 ]
This is because the 3x3 rotation matrix (R1 in your code), will be a product of the input rotation matrices only, so it should itself be a rotation matrix, and its transpose should be its inverse.
If any of your concatenated matrices are scaling matrices, or if the bottom row is not [0 0 0 1], then this is not true any more.
Also note that: in practice, if you multiply enough matrices together, floating point error may cause them to "drift" some, so that they may not be as close to a proper rotation matrix as a freshly-generated one. Depending on how you use it, this may not be a problem -- but if it is, you can "re-orthonormalize" it, as below:
orth(Vec3 a, Vec3 b): // return value orthogonal to b
return (a - (dot(a,b)/dot(b,b)) * b)
re_orthonormalize(Mat3x3 Rin):
Vec3 x = Rin.x;
Vec3 y = orth(Rin.y, x);
Vec3 z = orth(orth(Rin.z, x), y);
return Mat3x3(normalize(x),normalize(y),normalize(z))
As long as your input isn't too far off, this should give you a proper rotation matrix.
To see how the re_orthonormalize code works, first take the dot product of the orth output with its b input. Because the dot product is linear, we have:
dot(a - (dot(a,b)/dot(b,b)*b, b)
== dot(a,b) - (dot(a,b)/dot(b,b)) * dot(b,b)
== dot(a,b) - dot(a,b)
== 0
So, if a and b are already mostly orthogonal, ortho(a,b) adds a small amount of b to make sure the dot product really is 0.
That means in re_orthonormalize, y is exactly orthogonal to x. The tricky bit is making sure that z is orthogonal to both x and y. This only works because we have already made sure x is exactly orthogonal to y, so adding a little bit of y doesn't stop orth(Rin.z, x) from being orthogonal to x.
The inverse of the product (P=AB) of two square matrices is in general Inv(B)*Inv(A). Rotations and translations will commute. In general you have to unwind the operations in the reverse of the order in which they were applied.
In this case though, R1*T1*R2*T2=R1*R2*T1*T2 and you can then compute the inverse of the concatenation as the inverse of the composition of the individual rotations and translations.
So yes, this is sound for pure rotations and translations.

Netlogo Flocking Model Code Explanation

I'm investigating the flocking model of netlogo. It has the following code that is strange. What does this code do mathematically?
If I would see this in mathematical notations I would understand this. I suppose this is how trigonometry gets implemented in netlogo ?
to heading
turn-towards average-heading max-align-turn
end
to-report average-heading
let x-component sum [dx] of flock
let y-component sum [dy] of flock
ifelse x-component = 0 and y-component = 0
[ report heading ]
[ report atan x-component y-component ]
end
to turn-towards [new-heading max-turn]
turn-at-most (subtract-headings new-heading heading) max-turn
end
to turn-at-most [turn max-turn]
ifelse abs turn > max-turn
[ ifelse turn > 0
[ rt max-turn ]
[ lt max-turn ] ]
[ rt turn ]
end
to-report average-heading
let x-component sum [dx] of flock
let y-component sum [dy] of flock
ifelse x-component = 0 and y-component = 0
[ report heading ]
[ report atan x-component y-component ]
end
dy and dy are the sine and cosine of the turtles headings so what we are looking at is
The procedure reports
The arctangent of the sum of the sines of the turtle-headings , sum of the cosines of the turtle-headings.
it is so the mean heading of the set of angles obviously if we just up the headings and divide by the number of turtles we end up with a lot of problems.

Converting a recursive formula back to the original explicit formula?

There is a generic formula Z^N = A(Z)^N+1 + B(Z)^N+1 . This formula is used to convert a given recursive function back to its original explicit form :
Recursive Formulas :
1) R(0) = 1, R(n) = (1/3) R(n-1), n = 1, 2, ...
2) P(0) = 1, P(1) = 1/3, P(n) = (4/3) P(n-1) - (1/3) P(n-2), n = 2, 3, ...
3) Q(0) = 1, Q(1) = 1/3, Q(n) = (10/3) Q(n-1) - Q(n-2), n = 2, 3, ...
Then, it suggests that "difference formulas" of the form :
2) P(n) = A(1/3^n) + B
3) Q(n) = A(1/3^n) + B * 3^n
represent the general solution.
Then the "difference functions" are to be substituted into the "recursive functions" to obtain root of A, B which completes the proof that the recursive function is indeed a representation of the original sequence {Xn} = {1/3^n} = 1, 1/3, 1/9, ...
My Question is where the difference formulas come from? I would appreciate a reference to the subject in any major text-book in calculus or numerical methods like Swokowski, Fink, or Chapra.
It's just a bit of freshman algebra. Let's take example 3 for instance:
Q(n+2) = (10/3)Q(n+1) + (-1)Q(n)
Q(n+1) = ( 1)Q(n+1) + ( 0)Q(n)
That second equation seems silly, but it allows us to write the following matrix equation:
[ Q(n+2) ] = [ 10/3 -1 ][ Q(n+1) ]
[ Q(n+1) ] = [ 1 0 ][ Q(n) ]
This is the 2-dimensional analogue of a recurrence like v(n+1) = a*v(n) which has an easy solution v(n) = a^n * v(0). We can apply the same logic to our matrix equation to obtain:
[ Q(n+1) ] = [ 10/3 -1 ]^n [ 1/3 ]
[ Q(n) ] = [ 1 0 ] [ 1 ]
Let's call that 2 x 2 matrix in the middle that we're raising to the nth power, A.Now how do we quickly compute powers of square matrices? When they're diagonalizable, it's easy. The eigenvalues of that 2x2 matrix are the roots of its characteristic polynomial:
det(A - xI) = (10/3 - x)(0 - x) - (1)(-1) = (x - 1/3)(x - 3)
This tells us that there's some invertible 2 x 2 matrix P (consisting of the eigenvectors of A) such that:
[ Q(n+1) ] = P [ 1/3 0 ]^n P^-1 [ 1/3 ]
[ Q(n) ] = [ 0 3 ] [ 1 ]
and so:
[ Q(n+1) ] = P [ 1/3^n 0 ] P^-1 [ 1/3 ]
[ Q(n) ] = [ 0 3^n ] [ 1 ]
From this we easily deduce that for some constants a and b:
Q(n) = a(1/3^n) + b(3^n)
We could explicitly figure out what they are by finding the eigenvectors of A, constructing the matrices P and P^-1, multiplying those three 2 x 2 matrices with the 2 x 1 vector on the right, and actually extracting the expression for Q(n) from that. But it's easier to just look at the equation, realize that it'll result in something of the form Q(n) = a(1/3^n) + b(3^n) and actually just solve for a and b via back-substitution.

pixel coordinates on diamond

I got an image with a couple of diamond put side by side like on the image below
The only coordinates I know on the image are the top corners (green text).
When I click on the image I get the coordinates of that point, but I'm not able to get which diamond I'm on.
For example I click on the red dot, how do I know that x:260, y:179 = the top diamond ?
And the blue belongs to the left ? etc...
Thank you very much for your help.
EDIT:
I finally used Canvas, but I think SVG would have worked as well for what I needed to do.
I see two possible approaches: direct check whether a point is inside a diamond and using affine transformations. I will describe both.
Direct point position check
To determine whether a point is inside a diamond you have to check its deviation from the middle point of a diamond. You have to put the X and Y deviations in proportion with the X and Y extents of the diamond, you will get two factors. For all points inside the diamond the sum of the modulo values for these factors is smaller or equal 1. In code this looks like this:
var dx = Math.abs(coords[0] - middle[0]);
var dy = Math.abs(coords[1] - middle[1]);
if (dx / size[0] + dy / size[1] <= 1)
alert("Inside diamond");
else
alert("Outside diamond");
So all you have to do now is determining the middle point for each diamond (size is the same in all cases) and checking whether the point you are testing is located inside them.
Working example: http://jsfiddle.net/z98hr/
Affine transformations
Using affine transformations you can change the corner coordinates of your top diamond into (0,0), (1,0), (0,1) and (1,1). If you then apply the same transformation to the point you need to test, determining which diamond it belongs to becomes trivial.
First you will need a translation vector to move the (225,2) point into the origin of coordinates. Let's say that you have four coordinates determining your top diamond (left and right coordinate, top and bottom coordinate):
var topDiamond = [[113, 2], [337, 227]];
Then the translation vector to move the top point of the diamond to the zero coordinate would be:
var translationVector = [-(topDiamond[0][0] + topDiamond[1][0]) / 2,
-topDiamond[0][1]];
You can apply it to the original coordinates like this:
function add(vector1, vector2)
{
return [vector1[0] + vector2[0], vector1[1] + vector2[1]];
}
topDiamond = [add(topDiamond[0], translationVector),
add(topDiamond[1], translationVector)];
Then you will need a rotation matrix:
var angle = -Math.atan2(topDiamond[1][1] - topDiamond[0][1],
topDiamond[1][0] - topDiamond[0][0]);
var rotMatrix = [[Math.cos(angle), -Math.sin(angle)],
[Math.sin(angle), Math.cos(angle)]];
After the multiplication with this matrix the points (225,2) and (337,114.5) are aligned on the X axis. But what you have now is a trapeze, you now need a horizontal shear transformation to get the other side of the diamond aligned on the Y axis:
function multiply(matrix, vector)
{
return [matrix[0][0] * vector[0] + matrix[0][1] * vector[1],
matrix[1][0] * vector[0] + matrix[1][1] * vector[1]];
}
var point = [topDiamond[0][0], (topDiamond[0][1] + topDiamond[1][1]) / 2];
point = multiply(rotMatrix, point);
var shearMatrix = [[1, -point[0] / point[1]], [0, 1]];
After multiplication with this matrix you have a rectangle now. Now you only need a scaling matrix to make sure that the X and Y coordinates of the corners have the value 0 and 1:
point = multiply(shearMatrix, point);
var point2 = [topDiamond[1][0], (topDiamond[0][1] + topDiamond[1][1]) / 2];
point2 = multiply(rotMatrix, point2);
point2 = multiply(shearMatrix, point2);
var scaleMatrix = [[1/point2[0], 0], [0, 1/point[1]]];
And there you have it, now you can apply these transformations to any point:
alert(
multiply(scaleMatrix,
multiply(shearMatrix,
multiply(rotMatrix,
add(translationVector, [260, 179])
)
)
)
);
This gives you 0.94,0.63 - both values are in the (0..1) range meaning that it is the top diamond. With [420,230] as input you get 1.88,0.14 - X in (1..2) range and Y in 0..1 range means right diamond. And so on.
Working example: http://jsfiddle.net/FzWHe/
In the retrospective, this was probably too much work for a simple geometrical figure like a diamond.
Essentially, what you have there is possibly an isometric view of 4 tiles (based on your comment about the diamonds appearing as trapezoids).
One quick way of doing this is to create 2 lines that are parallel with the "axes" of the "diamonds" (but still are crossing with each other...this is important as well). In the example image given, that would mean two lines that are vertical to each other but rotated by 45 degrees. In the isometric case, the lines will not be vertical to each other but at some other angle depending on your view.
Once you have these two lines you can create a "hitTest()" function that will be taking the coordinates of the point that was clicked and will be evaluating the two line equations. You are not really interested on the actual number returned by the line equations but only the signs. The sign shows you which side of the line does your point resides.
This means that your "diamonds" will correspond to these sign pairs (one sign for each line equation) [-,-], [-,+], [+,-], [+,+].
(Please note that the sign depends on the way that the line was defined, in other words for a given point P, the sign from some line equation (L) will be different if the line was defined as running "from left to right" or "from right to left", or more generally the sign will be the reverse for reciprocal directions.)
A bit more information about the form of the line equation you need can be obtained from here
Using matrices, you can derive a quick formula for which diamond is selected.
You want a transformation from (x,y) into "diamond-space". That is, a coordinate system where (0,0) is the top diamond, (1,0) is the one below to the right, and (0,1) below to the left.
A * x = y
where A is the transformation, x is the image coordinates, and y is the diamond-coordinates. To deal with the translation ((0,0) not being the same point in both spaces), you can add another row to the vectors, which is always 1.
You can transform multiple vectors at the same time, by putting them beside each other, so they form a matrix.
[ a b dx ] [ 225 337 113 ] [ 0 1 0 ]
[ c d dy ] * [ 2 114 114 ] = [ 0 0 1 ]
[ 0 0 1 ] [ 1 1 1 ] [ 1 1 1 ]
^ ^ ^-left ^-^-^--- new coordinates for each point
| '-right
'-top diamond
To solve for the coefficients in the first matrix, you need to divide by the second matrix (or multiply by the inverse).
[ a b dx ] [ 0 1 0 ] [ 225 337 113 ]^-1
[ c d dy ] = [ 0 0 1 ] * [ 2 114 114 ]
[ 0 0 1 ] [ 1 1 1 ] [ 1 1 1 ]
The result is:
[ a b dx ] [ (1/224) (1/224) (-227/224) ]
[ c d dy ] = [ (-1/224) (1/224) (223/224) ]
[ 0 0 1 ] [ 0 0 1 ]
To put this into program code:
function getDiamond(x, y) {
return [(x + y - 227) / 224, (-x + y + 223) / 224];
}
Example:
> getDiamond(260,179); // red
[0.9464285714285714, 0.6339285714285714]
> getDiamond(250,230); // green
[1.1294642857142858, 0.90625]
> getDiamond(189,250); // blue
[0.9464285714285714, 1.2678571428571428]
> getDiamond(420,230); // yellow
[1.8883928571428572, 0.14732142857142858]
If you look at the integer parts, you can see which diamond the coordinate corresponds to. The red one is at (0.94, 0.63) which is in region (0,0) pretty close to the edge of (1,0).
NB. The blue and green points in OP is drawn in the wrong location (or given wrong coordinates), so the result of my function places them in a different relative location.
If you do the calculations symbolically, you end up with this:
[ a b dx ] [ (y2 - y0)/M -(x2 - x0)/M -(x0*y2 - y0*x2)/M ]
[ c d dy ] = [-(y1 - y0)/M (x1 - x0)/M (x0*y1 - y0*x1)/M ]
[ 0 0 1 ] [ 0 0 1 ]
where M = x1*y2 - x2*y1 - y0*x1 + y0*x2 + x0*y1 - x0*y2.
Point 0 being the position of top diamond, point 1 being the position of right diamond, and point 2 being the position of left diamond.
Here is a function to calculate this:
function DiamondMaker(topx,topy, leftx,lefty, rightx,righty)
{
var M = topx*lefty - topx*righty +
leftx*righty - leftx*topy +
rightx*topy - rightx*lefty;
var a = -(topy - righty)/M;
var b = (topx - rightx)/M;
var dx = -(topx*righty - topy*rightx)/M;
var c = (topy - lefty)/M;
var d = -(topx - leftx)/M;
var dy = (topx*lefty - topy*leftx)/M;
return function(x, y) {
return [a * x + b * y + dx, c * x + d * y + dy];
};
}
var getDiamond = DiamondMaker(225,2, 337,114, 113,114);
// (same example as before)
All you need - just stady what is roration. Here is link: http://en.wikipedia.org/wiki/Rotation_(mathematics)
You should rotate you point in order to make sides of squares in parrallel with coordinate's grid. Point of rotaion should be 1 corner of dimonds you will threat as 0,0 diamond. After rotaion you can easily define how many daimond you point away from 0,0

Resources