most beautiful.
epitrochoid, hypotrochoids, cycloids, animation.
Wolfram Language code.
math, geometry.
Clear[hypotrochoidAnimate]
hypotrochoidAnimate::usage = "
hypotrochoidAnimate[{a,b,h}]
generates a list of graphics that trace out a hypotrochoid by rolling \
a circle inside another.
a is the radius of the fixed circle.
b is the radius of the rolling circle.
a > b.
h is the distance from the tracing point to the center of the rolling \
circle.
hypotrochoidAnimate[{a,b,h}, {tMin, tMax}]
start at tMin, stop at tMax.
{tMin, tMax} control the number of rotations.
hypotrochoidAnimate[{a,b,h}, {tMin, tMax, tStep}]
using tStep.
hypotrochoidAnimate[ {1, 1/4, 1/4}, {0, 2 Pi, 2 Pi/10} ]
If not specified, an internal algorithm will figure out the number of \
rotations so that the curve is closed.
tStep control the number of frames indirectly.
0 <= tMin <= tMax < Infinity.
Options:
NumberOfFrames-> Automatic
LastFrameOnly -> False
example:
ListAnimate @ hypotrochoidAnimate[ {1, 1/4, 1/4} ]
ListAnimate @ hypotrochoidAnimate[ {1, 1/4, 1/4}, {0, Pi, 0.2 } ]
hypotrochoidAnimate[ {1, 1/4, 1/4}, LastFrameOnly -> True ]
hypotrochoidAnimate[ {1, 1/4, 1/4}, {0, Pi}, LastFrameOnly -> True ]
ListAnimate @ hypotrochoidAnimate[ {1, 3/4, 3/4}, NumberOfFrames -> \
100 ]
hypotrochoidAnimate[ {1, 2/5, 1}, LastFrameOnly -> True, \
NumberOfFrames -> Automatic]
hypotrochoidAnimate[ {1, 1/3, 1/3}, LastFrameOnly -> True, \
NumberOfFrames -> 120]
Created: 2026-03-01
Version: 2026-03-01
";
Options[hypotrochoidAnimate] =
Join[{NumberOfFrames -> Automatic, LastFrameOnly -> False},
Options[Graphics]];
hypotrochoidAnimate[{a_, b_, h_}, tRange_List : Automatic,
opts : OptionsPattern[]] :=
Block[{nOfFrames, tMin, tMax, tStep, xmargin, tRangeList,
tracingPointF, pointListGP, staticGP, movingGP,
lastFrameGP},(*todo.set the number of frames such that the tracing \
point traveled after tStep is constant like 0.3*)
nOfFrames =
If[OptionValue@NumberOfFrames === Automatic,
Min[400, ((Numerator@Rationalize[b/a, 0]) (15*4))],
OptionValue@NumberOfFrames];
{tMin, tMax, tStep} =
Which[tRange === Automatic, {0,
N@Numerator@Rationalize[N@b/a, 0] 2 Pi,
N@(tMax - tMin)/(nOfFrames - 1)}, Length@tRange === 3, N@tRange,
True, N@{First@tRange,
Last@tRange, (tMax - tMin)/(nOfFrames - 1)}];
xmargin = (a Max[0, h - b]) 1.05;
tRangeList = N@Range[tMin, tMax, tStep];
tracingPointF =
Compile[{x}, {(a - b) Cos[x]
h Cos[-(a - b)/b x], (a - b) Sin[x] h Sin[-(a - b)/b x]}];
pointListGP = Map[Function[Point@tracingPointF@#], tRangeList];
staticGP = {Hue[.65, 1, .7], Thickness[.007], Circle[{0, 0}, a]};
movingGP =
Function[
Block[{xcenter = (a - b) {Cos[tMin (# - 1) tStep],
Sin[tMin (# - 1) tStep]} // N}, {Hue[.17],
Disk[xcenter, b], Hue[.65, 1, .7], Thickness[.008],
Circle[xcenter, b], Line[{xcenter, pointListGP[[#, 1]]}],
Hue[0], PointSize[.02], pointListGP[[#]]}]];
Table[Graphics[{staticGP, movingGP@nn, Hue[0],
Take[pointListGP, nn]}, FilterRules[{opts}, Options[Graphics]],
AspectRatio -> Automatic, Axes -> True,
PlotRange -> ({{-1, 1}, {-1, 1}} xmargin)], {nn,
Evaluate@If[OptionValue@LastFrameOnly, Length@tRangeList, 1],
Length@tRangeList}]]
(*s------------------------------*)
ListAnimate@hypotrochoidAnimate[{1, 1/4, 1/4}]
ListAnimate@hypotrochoidAnimate[{1, 1/4, 1/4}, {0, Pi, 0.2}]
hypotrochoidAnimate[{1, 1/4, 1/4}, LastFrameOnly -> True]
hypotrochoidAnimate[{1, 1/4, 1/4}, {0, Pi}, LastFrameOnly -> True]
ListAnimate@hypotrochoidAnimate[{1, 3/4, 3/4}, NumberOfFrames -> 100]
hypotrochoidAnimate[{1, 2/5, 1}, LastFrameOnly -> True,
NumberOfFrames -> Automatic]
hypotrochoidAnimate[{1, 1/3, 1/3}, LastFrameOnly -> True,
NumberOfFrames -> 120]