Your program will be given a list of sprockets, specified as
(x, y, radius) triplets.
The resulting chain drive system is comprised of these sprockets, connected together by a closed taut chain passing over each of them, in order.
Your goal is to produce an infinitely looping animation, showing the system in motion.
For example, given the input
(0, 0, 16), (100, 0, 16), (100, 100, 12), (50, 50, 24), (0, 100, 12)
, the output should look something like
The coordinate system should be such that the x-axis points right, and the y-axis points up. You may assume that the radii are even numbers greater than or equal to 8 (we'll see why this matters later.) You may also assume that there are at least two sprockets, and that the sprockets don't intersect one another. The units of the input are not too critical. All the examples and test cases in this post use pixels as the input units (so, for example, the radius of the middle sprocket in the previous figure is 24 pixels;) try not to deviate too much from these units. In the rest of the challenge, spatial quantities are understood to be given in the same units as the input—make sure to keep the proportions right! The dimensions of the output should be slightly bigger than the bounding box of all the sprockets, big enough so that the entire system is visible. In particular, the absolute positions of the sprockets should not affect the output; only their relative positions should (so, for example, if we shifted all the sprockets in the above example by the same amount, the output would remain the same.)
The chain should be tangent to the sprockets it passes over at all points of contact, and straight everywhere else. The chain should pass over the sprockets such that adjacent chain segments (that is, parts of the chain between two sprockets, that meet at the same sprocket) don't intersect each other.
For example, while the left system above is valid, the middle one is not, since the two adjacent chain segments that pass over the bottom left sprocket intersect. However, note that the right system is valid, since the two intersecting chain segments are not adjacent (this system is produced by a different input than the other two, though.)
To keep things simple(r), you may assume that no sprocket intersects the convex hull of its two neighboring sprockets, or the convex hulls of each of its neighbors and their other neighbor. In other words, the top sprocket in the diagram below may not intersect any of the shaded regions.
Chain segments may intersect sprockets other than the ones they pass over (such as in the last test case). In this case, the chain should always appear in front of the sprockets.
The chain should consist of a series of links of alternating widths. The width of the narrow link should be about 2, and the width of the wide link should be about 5. The length of both types of links should be about equal. The period of the chain, that is, the total length of a wide/narrow pair of links, should be the closest number to 4π that fits an integer number of times in the length of the chain. For example, if the length of the chain is 1,000, then its period should be 12.5, which is the closest number to 4π (12.566...) that fits an integer number of times (80) in 1,000. It's important for the period to fit an integer number of times in the chain's length, so that there are no artifacts at the point where the chain wraps around.
A sprocket of radius R should consist of three concentric parts:
a central axle, which should be a circle of radius about 3;
the sprocket's body, around the axle, which should be a circle of radius about R - 4.5;
and the sprocket's rim, around the body, which should be a circle of radius about
R - 1.5. The rim should also contain the sprocket's teeth, which should have a width of about 4; the teeth's size and spacing should match the the sizes of the chain links, so that they enmesh neatly.
The period of the sprocket's teeth, that is, the distance between two consecutive teeth along the circumference of the sprocket, should match the period of the chain. Since the period is about 4π, and since the radius of the sprocket is guaranteed to be even, the period should fit in the sprocket's circumference an almost-integer number of times, so that there shouldn't be any noticeable artifacts at the point where the sprocket's teeth wrap around.
You may use any combination of colors for the chain, the different parts of the sprocket, and the background, as long as they are easily distinguishable.
The background may be transparent.
The examples in this post use
#202020 for the chain,
#868481 for the sprocket's axle and rim, and
#646361 for the sprocket's body.
The first sprocket in the input list should rotate clockwise; the rest of the sprockets should rotate accordingly. The chain should move at a speed of about 16π (about 50) units per second; the frame rate is up to you, but the animation should look smooth enough.
The animation should loop seamlessly.
Some of the visual attributes and proportions are intentionally specified only roughly—you don't have to match them exactly. Your program's output doesn't have to be a pixel-to-pixel replica of the examples given here, but it should look similar. In particular, the exact proportions of the chain and the sprockets, and the exact shape of the chain's links and sprocket's teeth, are flexible.
The most important points to follow are these:
- The chain should pass over the sprockets, in input order, from the correct direction.
- The chain should be tangent to the sprockets at all points of contact.
- The links of the chain and the teeth of the sprockets should enmesh neatly, at least up to correct spacing and phase.
- The spacing between the links of the chain, and the teeth of the sprockets, should be such that there are no noticeable artifacts at the point where they wrap around.
- The sprockets should rotate in the correct direction.
- The animation should loop seamlessly.
As a final note, while, technically, the goal of this challenge is to write the shortest code, if you feel like getting creative and producing a more elaborate output, by all means, go for it!
Write a program or a function, taking a list of sprockets, and producing a corresponding chain drive system animation, as described above.
Input and Output
You may take the input through the command line, through STDIN, as function arguments, or using an equivalent method. You may use any convenient format for the input, but make sure to specify it in your post.
As output, you may display the animation directly, produce an animation file (e.g., an animated GIF), or produce a sequence of frame files (however, there's a small penalty in this case; see below.) If you use file output, make sure the number of frames is reasonable (the examples in this post use very few frames;) the number of frames doesn't have to be minimal, but you shouldn't produce too many superfluous frames. If you output a sequence of frames, make sure to specify the frame rate in your post.
This is code-golf. The shortest answer, in bytes, wins.
+10% Penalty If your program produces a sequence of frames as output, instead of displaying the animation directly or producing a single animation file, add 10% to your score.
(0, 0, 26), (120, 0, 26)
(100, 100, 60), (220, 100, 14)
(100, 100, 16), (100, 0, 24), (0, 100, 24), (0, 0, 16)
(0, 0, 60), (44, 140, 16), (-204, 140, 16), (-160, 0, 60), (-112, 188, 12), (-190, 300, 30), (30, 300, 30), (-48, 188, 12)
(0, 128, 14), (46.17, 63.55, 10), (121.74, 39.55, 14), (74.71, -24.28, 10), (75.24, -103.55, 14), (0, -78.56, 10), (-75.24, -103.55, 14), (-74.71, -24.28, 10), (-121.74, 39.55, 14), (-46.17, 63.55, 10)
(367, 151, 12), (210, 75, 36), (57, 286, 38), (14, 181, 32), (91, 124, 18), (298, 366, 38), (141, 3, 52), (80, 179, 26), (313, 32, 26), (146, 280, 10), (126, 253, 8), (220, 184, 24), (135, 332, 8), (365, 296, 50), (248, 217, 8), (218, 392, 30)