It's amazing how often finding an interesting gif online can lead down an enourmous rabbit hole. My immediate instinct on seeing clever or satisfying animated gifs is "How did they do it?", very closely followed by "So how would I do it?". Usually this involves an extremely conservative time estimate which is inevitably exceeded as I get wrapped up in the project and add features, but commonly there is something interesting beneath the surface that makes it all worth it.
My most recent project of this kind concerns "Lissajous Curves". These are the paths drawn by pendulums in 3 dimensions, but can be more aptly described as the path drawn by two oscillators of differing frequencies with each driving the movement in a single axis. This is the cause of the diagonal of circles, since this is when the oscillators have the same frequency (Pressing "D" in the sketch shows that any given row all have the same y-value and any given column has the same x-value).
I decided that I wanted to make this as expandable as possible, so created a Curve class that could be tiled as much as needed. Every frame each curve simply steps to the next point, based on the incremented angles, and adds that point to an array from which the curve is drawn. This led me to my first optimisation, which I initially thought would be easy to implement. I was very wrong (that is not to say the actual code is not simple, but getting there took some time).
My immediate fix for this, to allow me to see the patterns of hundreds at a time, was to stop wiping the screen each time and drawing everything from scratch but instead just drawing each point as a small circle and letting them fill up over time. This worked okay, but didn't have great resolution and took a while to make a continuous shape. The solution suggested by a friend was to draw a line segment every frame instead, and so after a brief change to record the previous position as well as the updated one, the "simple" version (Pressing "O" in the sketch) that exists now was born. This has a much higher resolution and is almost indentical to the proper version with the white points.
After completing that section, I turned my attention back to the standard "mode". Since it is adding points every frame, the array steadily grows, and so the program began to lag after 10 seconds or so. This was, I thought, to be simply fixed by removing points as soon as it begins to overlap itself. I could also just stop adding to array, but this seemed a more foolproof option since it meant I could alter the original array and the curve would keep being drawn. Figuring out when each curve started to overlap itself was the obstacle, and I was thwarted by Javascripts managment of floating point arithmetic. After some empirical testing, it seemed like the curve started drawing over itself when both the x-axis oscillator and y-axis oscillator had remainder 0 when divided by 2*Pi. However, when I tried to program this is it never fired. I tried increasingly heuristic attempts before going back to that original test and actually checking the result. Instead of getting 0, I was actually getting numbers in the region of 0.0000001. In the end the simplest fix was just allowing a small margin of error proportional to the speed at which the angle increases (the faster cuvres get more leeway).
This also meant I could add the "colour" feature that signifies when a curve is "finished" by it changing colour (Pressing "C" in the sketch).
The last thing I added was the ability to use other shapes instead of circle as the basis. I had come across a great sketch showing how to map the standard parametric for drawing a circle onto polygons (https://www.openprocessing.org/sketch/89602), and so decided to add that here and see what other patterns can be created (Pressing Up and Down arrows changes the polygon number with the circles as 0). As the number of sides increases, the curves unsurprisingly tend towards those seen when circles are used, but the square for example gives a very modern/geometric version of the usual curves.
コメント