1 Rotations of Widelands map Table of contents: 1. Short introduction ............................................................................................................................ 2 a) Basic map: two coordinate systems ............................................................................................. 2 b) Goal ............................................................................................................................................. 2 c) How to do that? ........................................................................................................................... 2 d) Short description of used notation. .............................................................................................. 2 2. Math calculations ............................................................................................................................ 3 a) Matrix multiplication ................................................................................................................... 3 b) Creating rotation matrix .............................................................................................................. 3 3. Connections between coordinate systems ....................................................................................... 3 a) Cartesian to zig-zag coordinates .................................................................................................. 4 b) Zig-zag to Cartesian coordinates ................................................................................................. 4 c) Rotate a point or vector in Cartesian plane ................................................................................. 4 d) Rotation of vector on zig-zag plane............................................................................................. 5 4. Testing the results in shapes ............................................................................................................ 6 5. Conclusion ....................................................................................................................................... 6 2 1. Short introduction a) Basic map: two coordinate systems Widelands maps are triangle-base shaped. It means that if we go up or down, we can choose 2 ways: up-right and up-left with 60° between the directions. But our calculations don’t work with that coordinate system. We used to work with square-shaped coordinate system (Cartesian one). It is orthonormal coordinates system where laws of math are not so complicated (we learn at school about basic geometry there, because it is easy one). b) Goal My goal is to create working universal rotation model. It should work for any angle and any point. Rotations in Cartesian coordinate system are quite well described, but in triangle-base shaped one are not. (Ok, they are, but it is not described in every geometry book). The discussion about the usage of the work is on page https://wl.widelands.org/forum/topic/1634/ . c) How to do that? At first we need some “small bricks” from whole problem: get analytic transformation between the coordinates. Then we should see if it possible to rotate casual zigzag coordinates and find the closest rotation result- if it is not possible to rotate. At last we should test the solution on some points and shapes to see if there are any problems with the solution. For example I will try to get functions that explain how to get from one coordinate system to another: f1(x1,y1) F2(x2,y2) d) Short description of used notation. In some places there are code parts. This is not any exact programming language, but only an idea how to work with calculations in any language. The index of any array there begins from 0. 3 2. Math calculations a) Matrix multiplication This is one of basics matrix operation. In this case we will use vector (2 row array) and 2 x 2 matrix (or array, as you want). In result we get an vector (2 row array). matrixMultiply ( vector , matrix ) { resultVector = { 0 , 0 } resultVector[0] = vector[0] * matrix[0][0] + vector[1] * matrix[1][0] resultVector[1] = vector[0] * matrix[0][1] + vector[1] * matrix[1][1] return resultVector } b) Creating rotation matrix Also something from math: definition of rotation matrix in our 2- dimensional plane: cos( ) sin( ) , where α is the angle of rotation. sin( ) cos( ) createRotationMatrix( angle ){ rotationMatrix = {{ 0 , 0 } , { 0 , 0 }} rotationMatrix[0][0] = cos(angle) rotationMatrix[1][1] = rotationMatrix[0][0] rotationMatrix[0][1] = sin(angle) rotationMatrix[1][0] = - rotationMatrix[0][1] return rotationMatrix } 3. Connections between coordinate systems All coordinate systems can be displayed on 2-dimension Cartesian plane. Square plane has the same coordinates, so we don’t have to make any other calculations to this place. Another thing is with zig-zag coordinates. If we say that point (0,0) is in zig-zag coordinates (0,0) and first up is to the right we can make a formula (tested): x2 x1 1 y 3 mod( y1 ,2) , y2 1 . Mod is a math modulo function1. 2 2 http://en.wikipedia.org/wiki/Modulo_operation 4 a) Cartesian to zig-zag coordinates Then we can make a function (vector to vector): squareToZigzag( squareVector ) { zigzagVector = { 0 , 0 } zigzagVector[0] = squareVector[0] + mod(squareVector[1] , 2.0) / 2.0 zigzagVector[1] = squareVector[1] * sqrt(3.0) / 2.0 return zigzagVector } b) Zig-zag to Cartesian coordinates Also it is useful to know backwards formula: zigzagToSquare( zigzagVector ) { squareVector = { 0 , 0 } squareVector[0] = zigzagVector[0]mod(2.0 * zigzagVector[1] / sqrt(3.0) , 2.0) / 2.0 squareVector[1] = zigzagVector[1] * 2.0 / sqrt (3.0) return squareVector } c) Rotate a point or vector in Cartesian plane At first we have to remember that our plane is descrete. It means that we can’t have point with coordinate (0.3, 1.8). The nearest point is (0, 2). So if we rotate point or vector we have to round the result to the nearest vertex. Another thing is calculating sin and cosine functions. We can calculate it every time or calculate it before rotations and then use values in correct place. That will make calculations faster. Here I will calculate the rotation for every point (easier to understand what is doing here). rotateOneVectorCartesian( cartesianVector , angle ){ rotationMatrix = createRotationMatrix(angle) rotatedVector = matrixMultiply(cartesianVector,rotationMatrix) //round floating-point value to integer value rotatedVector[0] = round(rotatedVector[0]) rotatedVector[1] = round(rotatedVector[1]) return rotatedVector } 5 d) Rotation of vector on zig-zag plane. Here rounding is a bit more complex. One way (I’ve discovered) is to rotate the values of vector in Cartesian dimensions (ex.: (1/2, √3/2)), then convert the dimensions into square-shaped dimensions, round the values there, and convert back into zig-zag plane: rotateOneVectorZigzag( zigzagVector , angle ){ rotationMatrix = createRotationMatrix(angle) rotatedVector = matrixMultiply(cartesianVector,rotationMatrix) cartesianVector = zigzagToSquare(rotatedVector) cartesianVector[0] = round(cartesianVector[0]) cartesianVector[1] = round(cartesianVector[1]) rotatedVector = squareToZigzag(cartesianVector) return rotatedVector } This formula can work with vector or point- the same calculations are in both cases. 6 4. Testing the results in shapes Using Wolfram Mathematica 10.0 I’ve tested the formula in 2 shapes: triangle and square. Both cases divided into two possibilities: only vertices of shapes and all points inside the shape. I’ve tested all the angles for rotations: 30, 45, 60, 90, 120 and 180 degrees. Some of the results are down here: Square shape, 120 degree: Triangle shape, 90 degree: 5. Conclusion The formula works property, but it has some small problem with angles that aren’t the multiplication of 60 degrees. Interpolation is needed to make a stable feature of rotating any part of map in Widelands.