Use the range slider to change the degree of subdivision in this geodesic sphere. The base shape, visible when subdivision is disabled, is the icosahedron. Built with the d3.geodesic plugin.
| !function(){function n(n){return d3.merge(e.map(function(t){var o=r(t[0],t[1]),u=r(t[0],t[2]),i=[];i.push([t[0],o(1/n),u(1/n)]);for(var a=1;n>a;++a){for(var e=r(o(a/n),u(a/n)),c=r(o((a+1)/n),u((a+1)/n)),f=0;a>=f;++f)i.push([e(f/a),c(f/(a+1)),c((f+1)/(a+1))]);for(var f=0;a>f;++f)i.push([e(f/a),c((f+1)/(a+1)),e((f+1)/a)])}return i}))}function t(t){function r(n,t){var r;(n[0]<t[0]||n[0]==t[0]&&(n[1]<t[1]||n[1]==t[1]&&n[2]<t[2]))&&(r=n,n=t,t=r),u[n.map(o)+" "+t.map(o)]=[n,t]}function o(n){return d3.round(n,4)}var u={};return n(t).forEach(function(n){r(n[0],n[1]),r(n[1],n[2]),r(n[2],n[0])}),d3.values(u)}function r(n,t){var r=n[0],o=n[1],u=n[2],i=t[0]-r,a=t[1]-o,e=t[2]-u;return function(n){return[r+n*i,o+n*a,u+n*e]}}function o(n){var t=n[0],r=n[1],o=n[2];return[Math.atan2(r,t)*i,Math.acos(o/Math.sqrt(t*t+r*r+o*o))*i-90]}var u=1.618033988749895,i=180/Math.PI,a=[[1,u,0],[-1,u,0],[1,-u,0],[-1,-u,0],[0,1,u],[0,-1,u],[0,1,-u],[0,-1,-u],[u,0,1],[-u,0,1],[u,0,-1],[-u,0,-1]],e=[[0,1,4],[1,9,4],[4,9,5],[5,9,3],[2,3,7],[3,2,5],[7,10,2],[0,8,10],[0,4,8],[8,2,10],[8,4,5],[8,5,2],[1,0,6],[11,1,6],[3,9,11],[6,10,7],[3,11,7],[11,6,7],[6,0,10],[9,1,11]].map(function(n){return n.map(function(n){return a[n]})});d3.geodesic={multipolygon:function(t){return{type:"MultiPolygon",coordinates:n(~~t).map(function(n){return n=n.map(o),n.push(n[0]),n=[n]})}},polygons:function(n){return d3.geodesic.multipolygon(~~n).coordinates.map(function(n){return{type:"Polygon",coordinates:n}})},multilinestring:function(n){return{type:"MultiLineString",coordinates:t(~~n).map(function(n){return n.map(o)})}}}}(); |
| <!DOCTYPE html> | |
| <meta charset="utf-8"> | |
| <style> | |
| #subdivision { | |
| position: absolute; | |
| top: 20px; | |
| left: 20px; | |
| } | |
| #subdivision input { | |
| width: 200px; | |
| } | |
| </style> | |
| <div id="subdivision"> | |
| <input type="range" min="1" max="12" value="8"> | |
| <output name="subdivision"></output> | |
| </div> | |
| <script src="//d3js.org/d3.v3.min.js"></script> | |
| <script src="d3.geodesic.min.js"></script> | |
| <script> | |
| var width = 960, | |
| height = 500; | |
| var velocity = [.010, .005], | |
| t0 = Date.now(); | |
| var projection = d3.geo.orthographic() | |
| .scale(height / 2 - 10); | |
| var canvas = d3.select("body").append("canvas") | |
| .attr("width", width) | |
| .attr("height", height); | |
| var context = canvas.node().getContext("2d"); | |
| context.strokeStyle = "#000"; | |
| context.lineWidth = .5; | |
| var faces; | |
| var output = d3.select("output"); | |
| var input = d3.select("input") | |
| .on("input", function() { geodesic(+this.value); }) | |
| .on("change", function() { geodesic(+this.value); }) | |
| .each(function() { geodesic(+this.value); }); | |
| d3.timer(function() { | |
| var time = Date.now() - t0; | |
| projection.rotate([time * velocity[0], time * velocity[1]]); | |
| redraw(); | |
| }); | |
| function redraw() { | |
| context.clearRect(0, 0, width, height); | |
| faces.forEach(function(d) { | |
| d.polygon[0] = projection(d[0]); | |
| d.polygon[1] = projection(d[1]); | |
| d.polygon[2] = projection(d[2]); | |
| if (d.visible = d.polygon.area() > 0) { | |
| context.fillStyle = d.fill; | |
| context.beginPath(); | |
| drawTriangle(d.polygon); | |
| context.fill(); | |
| } | |
| }); | |
| context.beginPath(); | |
| faces.forEach(function(d) { | |
| if (d.visible) { | |
| drawTriangle(d.polygon); | |
| } | |
| }); | |
| context.stroke(); | |
| } | |
| function drawTriangle(triangle) { | |
| context.moveTo(triangle[0][0], triangle[0][1]); | |
| context.lineTo(triangle[1][0], triangle[1][1]); | |
| context.lineTo(triangle[2][0], triangle[2][1]); | |
| context.closePath(); | |
| } | |
| function geodesic(subdivision) { | |
| output.text(subdivision); | |
| faces = d3.geodesic.polygons(subdivision).map(function(d) { | |
| d = d.coordinates[0]; | |
| d.pop(); // use an open polygon | |
| d.fill = d3.hsl(d[0][0], 1, .5) + ""; | |
| d.polygon = d3.geom.polygon(d.map(projection)); | |
| return d; | |
| }); | |
| redraw(); | |
| } | |
| </script> |
maxogden
commented
Jul 9, 2012
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
BLOWIN MY MIND