# The Hypocycloid

We build up an SVG image which demonstrates the hypocycloid. We roll a circle of radius r=p/q around the interior of a circle of radius one. Then we put a pen at on the boundary of the rolling circle, and look at the curve drawn.

## Step one: Drawing the curve:

The following draws the hypocycloid when r=1/3, but the code is written in such a way that it will draw any hypocycloid with a small change to the code.

Source of hypocycloid1.svg:Hide line numbers
```01: <svg version="1.1" baseProfile="full"
03:      width="600px" height="600px" viewBox="-300 -300 600 600"
05:
06: <script>
07: // <![CDATA[
08:
09: var svgNS = "http://www.w3.org/2000/svg";
10:
11: var p=1,q=3,r,period;
12:
13: function setup() {
14:    r=1.0*p/q; // radius of small disk
15:    period=2*Math.PI*p; // period of curve
16:    var n=8*q; // number of points to plot
17:    var dt=period/n; // distance between points plotted
18:
19:    var i=0; // index of current point
20:    var t=0; // current point on curve
21:    curve="M 300,0 "; // start of curve
22:    while (i<n) {
23:       curve += "C ";
24:       curve += (curveX(t)+derivativeX(t)/3*dt) + "," + (curveY(t)+derivativeY(t)/3*dt) + " ";
25:       i=i+1;
26:       t=i*period/n;
27:       curve += (curveX(t)-derivativeX(t)/3*dt) + "," + (curveY(t)-derivativeY(t)/3*dt) + " ";
28:       curve += curveX(t) + "," + curveY(t) + " ";
29:    }
30:    document.getElementById("curve").setAttributeNS(null,"d",curve);
31: }
32:
33: function curveX(t) {
34:    return 300*((1-r)*Math.cos(t)+r*Math.cos((r-1)*t/r));
35: }
36:
37: function curveY(t) {
38:    return 300*((1-r)*Math.sin(t)+r*Math.sin((r-1)*t/r));
39: }
40:
41: function derivativeX(t) {
42:    return 300*(r-1)*(Math.sin(t)+Math.sin((1-r)*t/r));
43: }
44:
45: function derivativeY(t) {
46:    return 300*(1-r)*(Math.cos(t)-Math.cos((1-r)*t/r));
47: }
48:
49: // ]]>
50: </script>
51:
52:    <circle cx="0" cy="0" r="300" fill="yellow" stroke-width="0px"/>
53:    <path id="curve" d="M 0,0" stroke="black" fill="none"/>
54:
55: </svg>
56: ```

## Step two: Drawing the curve:

This version adds some code to indicate the values of p and q. We also allow the user to increase and decrease these values.

Source of hypocycloid2.svg:Hide line numbers
```01: <svg version="1.1" baseProfile="full"
03:      width="600px" height="600px" viewBox="-300 -300 600 600"
05:      font-family="Times, serif" font-size="20px">
06:
07: <script>
08: // <![CDATA[
09:
10: var svgNS = "http://www.w3.org/2000/svg";
11:
12: var p=1,q=3,r,period;
13:
14: function setup() {
15:    r=1.0*p/q; // radius of small disk
16:    period=2*Math.PI*p; // period of curve
17:    var n=8*q; // number of points to plot
18:    var dt=period/n; // distance between points plotted
19:
20:    var i=0; // index of current point
21:    var t=0; // current point on curve
22:    curve="M 300,0 "; // start of curve
23:    while (i<n) {
24:       curve += "C ";
25:       curve += (curveX(t)+derivativeX(t)/3*dt) + "," + (curveY(t)+derivativeY(t)/3*dt) + " ";
26:       i=i+1;
27:       t=i*period/n;
28:       curve += (curveX(t)-derivativeX(t)/3*dt) + "," + (curveY(t)-derivativeY(t)/3*dt) + " ";
29:       curve += curveX(t) + "," + curveY(t) + " ";
30:    }
31:    document.getElementById("curve").setAttributeNS(null,"d",curve);
32: }
33:
34: function curveX(t) {
35:    return 300*((1-r)*Math.cos(t)+r*Math.cos((r-1)*t/r));
36: }
37:
38: function curveY(t) {
39:    return 300*((1-r)*Math.sin(t)+r*Math.sin((r-1)*t/r));
40: }
41:
42: function derivativeX(t) {
43:    return 300*(r-1)*(Math.sin(t)+Math.sin((1-r)*t/r));
44: }
45:
46: function derivativeY(t) {
47:    return 300*(1-r)*(Math.cos(t)-Math.cos((1-r)*t/r));
48: }
49:
51:    if (p<q-1) {
52:       p=p+1;
53:       var pText = document.getElementById("p");
54:       pText.firstChild.nodeValue = p;
55:       setup();
56:    }
57: }
58:
59: function pSubtract() {
60:    if (p>1) {
61:       p=p-1;
62:       var pText = document.getElementById("p");
63:       pText.firstChild.nodeValue = p;
64:       setup();
65:    }
66: }
67:
69:    q=q+1;
70:    var qText = document.getElementById("q");
71:    qText.firstChild.nodeValue = q;
72:    setup();
73: }
74:
75: function qSubtract() {
76:    if (q>p+1) {
77:       q=q-1;
78:       var qText = document.getElementById("q");
79:       qText.firstChild.nodeValue = q;
80:       setup();
81:    }
82: }
83:
84: // ]]>
85: </script>
86:
87:    <circle cx="0" cy="0" r="300" fill="yellow" stroke-width="0px"/>
88:    <path id="curve" d="M 0,0" stroke="black" fill="none"/>
89:
90:    <text x="-300" y="-285" fill="black">p=<tspan id="p">1</tspan></text>
91:    <text x="-300" y="-265" fill="blue" text-decoration="underline" cursor="pointer" onclick="pSubtract()">subtract one</text>
93:    <text x="300" y="-285" fill="black" text-anchor="end" >q=<tspan id="q">3</tspan></text>
94:    <text x="300" y="-265" fill="blue" text-decoration="underline" cursor="pointer" text-anchor="end" onclick="qSubtract()">subtract one</text>
96: </svg>
97: ```

## Step three: Drawing the curve:

This version adds animation of the circle rolling around.

Source of hypocycloid3.svg:Hide line numbers
```001: <svg version="1.1" baseProfile="full"
003:      width="610px" height="610px" viewBox="-305 -305 610 610"
005:      font-family="Times, serif" font-size="20px">
006:
007: <script>
008: // <![CDATA[
009:
010: var svgNS = "http://www.w3.org/2000/svg";
011:
012: var p=1,q=3,r,period;
013:
014: function setup() {
015:    r=1.0*p/q; // radius of small disk
016:    period=2*Math.PI*p; // period of curve
017:    var n=8*q; // number of points to plot
018:    var dt=period/n; // distance between points plotted
019:
020:    var i=0; // index of current point
021:    var t=0; // current point on curve
022:    curve="M 300,0 "; // start of curve
023:    while (i<n) {
024:       curve += "C ";
025:       curve += (curveX(t)+derivativeX(t)/3*dt) + "," + (curveY(t)+derivativeY(t)/3*dt) + " ";
026:       i=i+1;
027:       t=i*period/n;
028:       curve += (curveX(t)-derivativeX(t)/3*dt) + "," + (curveY(t)-derivativeY(t)/3*dt) + " ";
029:       curve += curveX(t) + "," + curveY(t) + " ";
030:    }
031:    document.getElementById("curve").setAttributeNS(null,"d",curve);
032:    startAnimation();
033: }
034:
035: function curveX(t) {
036:    return 300*((1-r)*Math.cos(t)+r*Math.cos((r-1)*t/r));
037: }
038:
039: function curveY(t) {
040:    return 300*((1-r)*Math.sin(t)+r*Math.sin((r-1)*t/r));
041: }
042:
043: function derivativeX(t) {
044:    return 300*(r-1)*(Math.sin(t)+Math.sin((1-r)*t/r));
045: }
046:
047: function derivativeY(t) {
048:    return 300*(1-r)*(Math.cos(t)-Math.cos((1-r)*t/r));
049: }
050:
052:    if (p<q-1) {
053:       p=p+1;
054:       var pText = document.getElementById("p");
055:       pText.firstChild.nodeValue = p;
056:       setup();
057:    }
058: }
059:
060: function pSubtract() {
061:    if (p>1) {
062:       p=p-1;
063:       var pText = document.getElementById("p");
064:       pText.firstChild.nodeValue = p;
065:       setup();
066:    }
067: }
068:
070:    q=q+1;
071:    var qText = document.getElementById("q");
072:    qText.firstChild.nodeValue = q;
073:    setup();
074: }
075:
076: function qSubtract() {
077:    if (q>p+1) {
078:       q=q-1;
079:       var qText = document.getElementById("q");
080:       qText.firstChild.nodeValue = q;
081:       setup();
082:    }
083: }
084:
085: // Global animation variables:
086: var positionsPerPeriod, currentPosition, rolling, point, speed=600, timeout=null;
087:
088: function startAnimation() {
089:    currentPosition=0;
090:    positionsPerPeriod=p*speed;
091:    rolling=document.getElementById("rolling");
092:    point=document.getElementById("point");
093:    rolling.setAttributeNS(null,"r",300*r);
094:    if (timeout!=null) {
095:       clearTimeout(timeout);
096:    }
097:    timeout=setTimeout(animationStep,20);
098: }
099:
100: function stopAnimation() {
101:    if (timeout!=null) {
102:       clearTimeout(timeout);
103:    }
104: }
105:
106: function animationStep() {
107:    var theta=2*Math.PI*currentPosition/speed;
108:    rolling.setAttributeNS(null,"cx",300*(1-r)*Math.cos(theta));
109:    rolling.setAttributeNS(null,"cy",300*(1-r)*Math.sin(theta));
110:    point.setAttributeNS(null,"cx",curveX(theta));
111:    point.setAttributeNS(null,"cy",curveY(theta));
112:    currentPosition=currentPosition+1;
113:    if (currentPosition==positionsPerPeriod) {
114:       currentPosition=0;
115:    }
116:    timeout=setTimeout(animationStep,20);
117: }
118: // ]]>
119: </script>
120:         <g transform="scale(1,-1)">
121:            <circle cx="0" cy="0" r="300" fill="yellow" stroke-width="0px"/>
122:       <circle id="rolling" cx="200" cy="0" r="100" stroke-width="0px" fill="red"/>
123:       <path id="curve" d="M 0,0" stroke="black" fill="none"/>
124:       <circle id="point" cx="300" cy="0" r="3" fill="blue" stroke-width="0.5px"/>
125:         </g>
126:    <text x="-300" y="-285" fill="black">p=<tspan id="p">1</tspan></text>
127:    <text x="-300" y="-265" fill="blue" text-decoration="underline" cursor="pointer" onclick="pSubtract()">subtract one</text>