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.

image of a circle
Your browser did not display the SVG image. It is showing a standard image as a fallback.
Source of hypocycloid1.svg:Hide line numbers
01: <svg version="1.1" baseProfile="full"
02:      xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
03:      width="600px" height="600px" viewBox="-300 -300 600 600" 
04:      onload="setup()">
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.

image of a circle
Your browser did not display the SVG image. It is showing a standard image as a fallback.
Source of hypocycloid2.svg:Hide line numbers
01: <svg version="1.1" baseProfile="full"
02:      xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
03:      width="600px" height="600px" viewBox="-300 -300 600 600" 
04:      fill="black" onload="setup()"
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: 
50: function pAdd() {
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: 
68: function qAdd() {
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>
92:    <text x="-300" y="-245" fill="blue" text-decoration="underline" cursor="pointer" onclick="pAdd()">add 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>
95:    <text x="300" y="-245" fill="blue" text-decoration="underline" cursor="pointer" text-anchor="end" onclick="qAdd()">add one</text>
96: </svg>
97: 

Step three: Drawing the curve:

This version adds animation of the circle rolling around.

image of a circle
Your browser did not display the SVG image. It is showing a standard image as a fallback.
Source of hypocycloid3.svg:Hide line numbers
001: <svg version="1.1" baseProfile="full"
002:      xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
003:      width="610px" height="610px" viewBox="-305 -305 610 610" 
004:      fill="black" onload="setup()"
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: 
051: function pAdd() {
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: 
069: function qAdd() {
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>
128:    <text x="-300" y="-245" fill="blue" text-decoration="underline" cursor="pointer" onclick="pAdd()">add one</text>
129:    <text x="300" y="-285" fill="black" text-anchor="end" >q=<tspan id="q">3</tspan></text>
130:    <text x="300" y="-265" fill="blue" text-decoration="underline" cursor="pointer" text-anchor="end" onclick="qSubtract()">subtract one</text>
131:    <text x="300" y="-245" fill="blue" text-decoration="underline" cursor="pointer" text-anchor="end" onclick="qAdd()">add one</text>
132: </svg>
133: 

This presentation is part of a SVG Tutorial for Mathematics Students.


© 2013 by W. Patrick Hooper. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. Creative Commons License Valid XHTML 1.0 Strict Valid CSS!