First, the way of representing the digits has to be defined. In this answer, I shall use a low resolution image representing each digit. The image is a $10 \times 12$ binary image like this image representing the digit $4$:

Each $2 \times 2$ pixels represent a clock, so we have $\frac{10}{2}\times \frac{12}{2} = 5\times 6 = 30$ clocks. Each pointer have a limited number of directions it can point at, in particular, it can have an angle $0, \frac{\pi}{2}, \pi, \frac{3}{2}\pi$. By looking at each four pixels of each clock we can determine the orientation of its pointers. Since we have four pixels, then we have $2^4=16$ possible combination, however, if the image is inverted, nothing changes, making the number of possible orientations to be $8$. We can encode the the four pixels in a 4-bit number where each bit represents a pixel. Then one can compute a look up table for each possible 4-bit number that stores the orientation of each pointer. By looking at the reference image, we can find that LUT to be:
p1 = [undetermined, 0 , pi/2, 0 , pi , undetermined, pi/2 , 0 ]
p2 = [undetermined, pi/2, pi , pi, 1.5*pi , undetermined, 1.5*pi, 1.5*pi]
Where p1
and p2
stores the orientation of the first and second pointer such that the index of each orientation is the 4-bit number that characterizes each combination. The undetermined indicates that all pixels are identical or that the first and third or the second and fourth quadrants are similar contrary to the others and thus no orientation can be determined.
In Animation Nodes, I will read the image as a single channel using the expression:
bpy.data.images[imageName].pixels[:][::4]
Where [:]
copies the image values and [::4]
get us every fourth element because we only need the first channel. (From RGBA
we only need R
) Then, I am going to get the width and height of the image using the expression:
width = bpy.data.images[imageName].size[0]
height = bpy.data.images[imageName].size[1]
Then, I am going to encode the pixels in the 4-bit number clock
by using the following code:
LUT = []
for h in range(height // 2):
for w in range(width // 2):
clock = 0
if pixels[(h * 2 + 1) * width + w * 2 + 1]: clock |= 1
if pixels[(h * 2 + 1) * width + w * 2 ]: clock |= 2
if pixels[h * 2 * width + w * 2 ]: clock |= 4
if pixels[h * 2 * width + w * 2 + 1 ]: clock |= 8
LUT.append(clock)
Since the width and height is double the number of clocks, we loop over only have of them. We initialize the 4-bit number to be zero and for each pixel, check if it is equal to a non zero and if yes, set its corresponding bit to one using the or
operator. Then we append the 4-bit number to a list and return it. We only computed $8$ of the combinations, the other $8$ are identical to those computed as we said except their order is reversed, we could either invert the 4-bit number if it surpassed $8$ or combine the list to itself head to head which we shall do because it is easier.
The next step is to evaluate the LUT at the previously computed numbers, forming an Euler from that and constructing a matrix list along the points of a uniform grid. Those matrices represents the orientation of the pointers and their locations and a simple grid mesh can be transformed along them creating the pointers we need.

