So a few hours ago Jens Monig (of Snap fame - sorry I don't know how to type the accent!) posted a link to a video which someone had made. This version is done in CSS! Jens suggested doing it in GP and/or Snap, and shortly afterwards posted a link to his version.
Not to miss out on the fun, I thought we could do it in Sniff, and to make it even neater, make it run on Arduino!
make i2c device 8
make display oled device
make displayX number
make displayY number
make displayColor number
make displayFlush boolean
The first thing to do is create a display device. I actually tried this on a few devices, but the big tft display was too slow to refresh. I also found a could to bugs that have slipped into Release 20, concerning Arduino displays. We're currently deprecating the drawImage function, and moving to a more powerfull bitmap architecture, and a couple of devices got left behind... sorry! Anyway we're pretty much limited to a small display to be able to get the necessary performance from both the Arduino and the bus transfer, so we went with the classic 128x64 i2c OLED device. As its the only device we need, we can speed the bus up a little - I chose to run the bus at 8x normal speed, which words great with my setup - if it fails for you, drop the speed down until all is OK.
make theta number
make radius number
make centreX number
make centreY number
.make tmpTheta number
.set displayX to centreX+radius*cos of theta
.set displayY to centreY+radius*sin of theta
.tell display to "move"
.set tmpTheta to theta
..change tmpTheta by 5
..set displayX to centreX+radius*cos of tmpTheta
..set displayY to centreY+radius*sin of tmpTheta
..tell display to "draw"
Next we need to draw a semi-circle. Normally I'd avoid using sin/cos when drawing circles. You can also get some good speedup by exploiting symetry, but for something thrown together, this code is simple and obvious.
With that out of the way, the rest is easy:
make circles list of number
.make index number
.set centreX to displayX/2
.set centreY to displayY/2
.set displayFlush to no
..add 0 to circles
..set displayColor to 000
..tell display to "clear"
..set displayColor to 777
..set radius to 3
..repeat length of circles using index
...set theta to item index of circles
...broadcast drawSemiCircle and wait
...change radius by 3
...change theta by index
Display devices have this nice feature that on initialisation they set displayX and displayY to their resolution (did I not tell you that before - sorry! its handy!), so we can easily centre the circles on the display. We want everything to refresh in one go, so we turn flushing off.
We're going to have to circles, so we store the current angle for each of them in a list. We don't really need this as we could calculate the values as we need them, but it does make things easier. Initially they're all lined up. so theta is 0.
Now we loop forever: clear the screen to black then draw each of the semi circles, increasing the radius by 3 each time (10 circles-> max radius of 30, max diameter of 60, just fits nicely!). The optical trick is that as we go out each circle spins faster, so we change its angle by index each time - the inner circle moves by 1 degree, the outer by 10 degrees each frame. The result:
And here it is! If you don't have the hardware to run this on Arduino, then it runs just as well on the desktop - just change the device to a "window" device (remember to "getEvent" every now and then to keep the window server happy), and then tweak the speed/size to suit your taste!