Skip to content

Instantly share code, notes, and snippets.

@nitaku
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nitaku/ee6cc32a90cc7d1b6fec to your computer and use it in GitHub Desktop.
Save nitaku/ee6cc32a90cc7d1b6fec to your computer and use it in GitHub Desktop.
Properties of archimedean spirals
# random spiral parameters
randint = (n) -> Math.round( Math.random()*n )
# WARNING the following assumes a=0
a = 0
D = 8 + randint(16)
b = D/(2*Math.PI)
COILS = 2 + randint(6)
THETA = 2*Math.PI * COILS
# angle samples per turn (not good for large spirals!)
SAMPLES = 48
number_of_points = Math.ceil( THETA/(2*Math.PI) * SAMPLES ) + 1
points = d3.range(0, number_of_points).map (i) ->
theta = i*2*Math.PI/SAMPLES
# PI/2 is subtracted from angles to have the spiral end at the top
return {theta: theta-Math.PI/2, r: a + b*theta}
WIDTH = 960
HEIGHT = 500
svg = d3.select('body').append('svg')
.attr
width: WIDTH
height: HEIGHT
.append('g')
.attr
transform: "translate(#{WIDTH/2},#{HEIGHT/2})"
# draw the radius
radius = a + b * THETA
svg.append('circle')
.attr
class: 'radius_indicator'
r: radius
# draw axes
svg.append('line')
.attr
class: 'axis'
x1: -WIDTH
x2: WIDTH
svg.append('line')
.attr
class: 'axis'
y1: -HEIGHT
y2: HEIGHT
# draw the spiral
line_generator = d3.svg.line()
.x((d) -> d.r * Math.cos(d.theta))
.y((d) -> d.r * Math.sin(d.theta))
.interpolate('linear')
spiral = svg.append('path')
.datum(points)
.attr
class: 'spiral'
d: line_generator
# compute the length
s = Math.PI * D * COILS*COILS
svg_s = spiral[0][0].getTotalLength()
# draw the parameters
svg.append('text')
.text("a = #{a}")
.attr
class: 'label'
x: -WIDTH/2+20
y: -HEIGHT/2+20
dy: '0.35em'
svg.append('text')
.text("b ≈ #{d3.format('.3f')(b)}")
.attr
class: 'label'
x: -WIDTH/2+20
y: -HEIGHT/2+45
dy: '0.35em'
svg.append('text')
.text("D = 2πb = #{D}")
.attr
class: 'label'
x: -WIDTH/2+20
y: +HEIGHT/2-45
dy: '0.35em'
svg.append('text')
.text("n = #{COILS}")
.attr
class: 'label'
x: -WIDTH/2+20
y: +HEIGHT/2-20
dy: '0.35em'
svg.append('text')
.text("r ≈ #{d3.format('.0f')(radius)}")
.attr
class: 'label'
x: radius + 10
dy: '-0.25em'
svg.append('text')
.text("s ≈ #{d3.format(',.0f')(s)}")
.style({fill: 'black'})
.attr
class: 'label'
x: 6
y: -radius
dy: '-0.25em'
svg.append('text')
.text("E ≈ #{d3.format(',.3f')(svg_s-s)}")
.style({fill: 'brown', 'font-size': '14px'})
.attr
class: 'label'
x: 6
y: -radius - 20
dy: '-0.25em'
svg {
background-color: white;
}
.spiral {
fill: none;
stroke: black;
stroke-width: 2px;
}
.radius_indicator {
fill: none;
stroke: gray;
stroke-dasharray: 3 6;
}
.axis {
fill: none;
stroke: lightgray;
stroke-dasharray: 24 6 2 6;
shape-rendering: crispEdges;
}
.label {
fill: gray;
font-family: Georgia;
font-style: italic;
font-size: 20px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="Properties of archimedean spirals" />
<title>Properties of archimedean spirals</title>
<link rel="stylesheet" href="index.css">
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script src="index.js"></script>
</body>
</html>
(function() {
var COILS, D, HEIGHT, SAMPLES, THETA, WIDTH, a, b, line_generator, number_of_points, points, radius, randint, s, spiral, svg, svg_s;
randint = function(n) {
return Math.round(Math.random() * n);
};
a = 0;
D = 8 + randint(16);
b = D / (2 * Math.PI);
COILS = 2 + randint(6);
THETA = 2 * Math.PI * COILS;
SAMPLES = 48;
number_of_points = Math.ceil(THETA / (2 * Math.PI) * SAMPLES) + 1;
points = d3.range(0, number_of_points).map(function(i) {
var theta;
theta = i * 2 * Math.PI / SAMPLES;
return {
theta: theta - Math.PI / 2,
r: a + b * theta
};
});
WIDTH = 960;
HEIGHT = 500;
svg = d3.select('body').append('svg').attr({
width: WIDTH,
height: HEIGHT
}).append('g').attr({
transform: "translate(" + (WIDTH / 2) + "," + (HEIGHT / 2) + ")"
});
radius = a + b * THETA;
svg.append('circle').attr({
"class": 'radius_indicator',
r: radius
});
svg.append('line').attr({
"class": 'axis',
x1: -WIDTH,
x2: WIDTH
});
svg.append('line').attr({
"class": 'axis',
y1: -HEIGHT,
y2: HEIGHT
});
line_generator = d3.svg.line().x(function(d) {
return d.r * Math.cos(d.theta);
}).y(function(d) {
return d.r * Math.sin(d.theta);
}).interpolate('linear');
spiral = svg.append('path').datum(points).attr({
"class": 'spiral',
d: line_generator
});
s = Math.PI * D * COILS * COILS;
svg_s = spiral[0][0].getTotalLength();
svg.append('text').text("a = " + a).attr({
"class": 'label',
x: -WIDTH / 2 + 20,
y: -HEIGHT / 2 + 20,
dy: '0.35em'
});
svg.append('text').text("b ≈ " + (d3.format('.3f')(b))).attr({
"class": 'label',
x: -WIDTH / 2 + 20,
y: -HEIGHT / 2 + 45,
dy: '0.35em'
});
svg.append('text').text("D = 2πb = " + D).attr({
"class": 'label',
x: -WIDTH / 2 + 20,
y: +HEIGHT / 2 - 45,
dy: '0.35em'
});
svg.append('text').text("n = " + COILS).attr({
"class": 'label',
x: -WIDTH / 2 + 20,
y: +HEIGHT / 2 - 20,
dy: '0.35em'
});
svg.append('text').text("r ≈ " + (d3.format('.0f')(radius))).attr({
"class": 'label',
x: radius + 10,
dy: '-0.25em'
});
svg.append('text').text("s ≈ " + (d3.format(',.0f')(s))).style({
fill: 'black'
}).attr({
"class": 'label',
x: 6,
y: -radius,
dy: '-0.25em'
});
svg.append('text').text("E ≈ " + (d3.format(',.3f')(svg_s - s))).style({
fill: 'brown',
'font-size': '14px'
}).attr({
"class": 'label',
x: 6,
y: -radius - 20,
dy: '-0.25em'
});
}).call(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment