Many puzzles can simply be created in the app. When a valid tangram is made in free-form mode, it can be saved to a folder that has been configured in the application Preferences. The program does it best to ensure the puzzle is centered and aligned so that the tans’ positions use the simplest form, and for many puzzle where the tans are all oriented in multiples of 45° and lined up at their vertices the resulting puzzle definition can be used without modification. To add these puzzles to the program assets, copy the user puzzle file from your emulator or device to the app/src/main/assets/ folder in your development environment.
Some puzzles may require manual tweaking, especially if their edges don’t line up at the vertices or they are rotated at offsets of 15° or 30° from the normal 45° angles. For these cases I’ve used a vector drawing program with templates of the tans laid out on a grid, and each tan has grid lines and bisecting lines drawn through it to help measure out distances between them, as shown in the example below:
Then measurements are taken by counting out grid points for each coefficient: orthogonal lines count for the \(a\) coefficient, and diagonals count for the \(b\) coefficient. For reference, here are the measurements for the tans in puzzle units:
The long edge is 24 units wide, and the two short edges \(12\sqrt{2}\) units long. Its centroid is 4 units from the bottom edge and 8 units from the right vertex, \(4\sqrt{2}\) units from each short edge and \(8\sqrt{2}\) units from the acute vertices.
The long edge is \(12\sqrt{2}\) units wide, and the two short edges 12 units long. Its centroid is \(2\sqrt{2}\) units from the bottom edge and \(4\sqrt{2}\) units from the right vertex, 4 units from each short edge and 8 units from the acute vertices.
The long edge is 12 units wide, and the two short edges \(6\sqrt{2}\) units long. Its centroid is 2 units from the bottom edge and 4 units from the right vertex, \(2\sqrt{2}\) units from each short edge and \(4\sqrt{2}\) units from the acute vertices.
The edges are \(6\sqrt{2}\) units long. Its centroid is \(3\sqrt{2}\) units from the edges and 6 units from the vertices.
The long edges are 12 units long and the short edges \(6\sqrt{2}\). Its centroid is 3 units from the long edges, 6 units from the short edges, \(3\sqrt{2}\) units from the obtuse vertices, and \(3\sqrt{10}\) units from the acute vertices.
So in the illustration shown above, the total width (ignoring the tilt of the medium triangle) would be 48 units, and the height would be \(12 + 12\sqrt{2}\) units (12 for the large triangles, and \(6\sqrt{2}\) each for the square and small triangle above it which are turned diagonally.)
The coordinate system is oriented with \(x\) going from left (negative) to right (positive), and \(y\) going from top (negative) to bottom (positive). Rotation is therefore defined with positive values going clockwise. Due to the use of \(Q\sqrt{2}\) coefficients rotating tans by 45° involves simple addition and division while swapping the coefficients:
\(a_{x}^{\prime} = b_{x} - b_{y}\)
\(b_{x}^{\prime} = \frac{a_{x}}{2} - \frac{a_{y}}{2}\)
\(a_{y}^{\prime} = b_{x} + b_{y}\)
\(b_{y}^{\prime} = \frac{a_{x}}{2} + \frac{a_{y}}{2}\)
For other angles, it is recommended to change the point of rotation
from the tan’s centroid to a vertex or point along an edge which is
touching another than that is rotated at a multiple of
45°. This is achieved through the optional
pointOfRotation field in the JSON description of the tan, where
the point of rotation is declared relative to the tan’s centroid.
Then its position point is the point of rotation relative to
the whole puzzle. For example, the JSON description of the medium
triangle in the example above, where the top vertex of the unrotated
triangle (\(4\sqrt{2}\) units up from its centroid) is touching the
right vertex of the base large triangle at 12 units right of center
(\(a_x = 12\)) and the bottom which is half the height from the
center (\(a_y = 6, b_y = 6\)), is:
{
"name": "medium_triangle",
"pointOfRotation": {
"xb": 0,
"yb": -4
},
"rotation": -150,
"position": {
"xa": 12,
"ya": 6,
"yb": 6
}
}
If the resulting rotation ends up changing the width or height of the
tangram such that it is not in integer \(Q\sqrt{2}\) space (as is
the case for the previous illustration), you may want to add a bit of
padding to one side to make the majority of tans line up. Several of
the puzzles bundled with this app include an extra size_comment
field describing their alignments.
Alternatively you could calculate the position of the centroid directly. Start with the coefficients best lined up to the nearest 90° angle at the point of rotation and then apply the standard trigonometric transformations to the relative coordinate of the centroid:
\(x^{\prime} = x \cdot cos(\theta) - y \cdot sin(\theta)\)
\(y^{\prime} = x \cdot sin(\theta) + y \cdot cos(\theta)\)
To show how this would work for the earlier example, take the placement of the medium triangle which is tilted -15° from the orthogonal grid: the lower right vertex of the purple large triangle is positioned 12 units right of center (\(a_x = 12\)) and at the bottom which is half the height from center (\(a_y = 6, b_y = 6\)). The centroid of the medium (green) triangle would be 4 units right and up from that vertex if lying flat (\(\Delta a_x = 4, \Delta a_y = -4\)). Plugging those numbers into the rotation formula we get:
\(\Delta a_x ^\prime = 4 cos(-15\unicode{xb0}) + 4 sin(-15\unicode{xb0})\)
\(\Delta a_y ^\prime = 4 sin(-15\unicode{xb0}) - 4 cos(-15\unicode{xb0})\)
which given \(cos(-15\unicode{xb0}) = \frac{\sqrt{6} + \sqrt{2}}{4}\) and \(sin(-15\unicode{xb0}) = \frac{\sqrt{2} - \sqrt{6}}{4}\) evaluate to:
\(\Delta a_x ^\prime = 2\sqrt{2}\)
\(\Delta a_y ^\prime = -2\sqrt{6}\)
Adding those to the point of rotation puts the medium triangle’s position at \(a_x = 12, b_x = 2, a_y = 6 - 2\sqrt{6} \approx 1.1010205, b_y = 6\). Its full rotation is -150°, since its starting orientation is with its right angle at the top. The JSON description of the tan is specified as:
{
"name": "medium_triangle",
"rotation": -150,
"position": {
"xa": 12,
"xb": 2,
"ya": 1.1010205144336438,
"yb": 6
}
}