Apollonian circle packing: Difference between revisions
From JSXGraph Wiki
A WASSERMANN (talk | contribs) No edit summary |
No edit summary |
||
(36 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
<jsxgraph width="600" height="600" box="box"> | <jsxgraph width="600" height="600" box="box"> | ||
var brd = JXG.JSXGraph.initBoard('box', { | var brd = JXG.JSXGraph.initBoard('box', {boundingbox: [-2, 2, 2, -2]}); | ||
solveQ2 = function(x1,x2,x3,off) { | |||
var | var a, b, c, d; | ||
if ( | a = 0.5; | ||
b = -(x1+x2+x3); | |||
c = x1*x1+x2*x2+x3*x3-0.5*(x1+x2+x3)*(x1+x2+x3)-off; | |||
d = b*b-4*a*c; | |||
if (Math.abs(d)<0.00000001) d = 0.0; | |||
} | return [(-b+Math.sqrt(d))/(2.0*a),(-b-Math.sqrt(d))/(2.0*a)]; | ||
} | |||
a = brd.create('segment',[[0,0],[2,0]],{visible:false}); | |||
p1 = brd.create('glider',[1.3,0,a],{name:'Drag me'}); | |||
b0 = -0.5; | |||
c0 = brd.create('circle',[[0,0],Math.abs(1.0/b0)],{strokeWidth:1}); | |||
c1 = brd.create('circle',[p1,function(){return 2-p1.X();}],{strokeWidth:1}); | |||
c2 = brd.create('circle',[[function(){return p1.X()-2;},0],function(){return p1.X();}],{strokeWidth:1}); | |||
c0.curvature = function(){ return b0;}; // constant | |||
c1.curvature = function(){ return 1/(2-p1.X());}; | |||
c2.curvature = function(){ return 1/(p1.X());}; | |||
thirdCircleX = function() { | |||
var b0,b1,b2,x0,x1,x2, b3,bx3; | |||
b0 = c0.curvature(); | |||
b1 = c1.curvature(); | |||
b2 = c2.curvature(); | |||
x0 = c0.midpoint.X(); | |||
x1 = c1.midpoint.X(); | |||
x2 = c2.midpoint.X(); | |||
b3 = solveQ2(b0,b1,b2,0); | |||
bx3 = solveQ2(b0*x0,b1*x1,b2*x2,2); | |||
return bx3[0]/b3[0]; | |||
} | |||
thirdCircleY = function() { | |||
var b0,b1,b2,y0,y1,y2, b3,by3; | |||
b0 = c0.curvature(); | |||
b1 = c1.curvature(); | |||
b2 = c2.curvature(); | |||
y0 = c0.midpoint.Y(); | |||
y1 = c1.midpoint.Y(); | |||
y2 = c2.midpoint.Y(); | |||
b3 = solveQ2(b0,b1,b2,0); | |||
by3 = solveQ2(b0*y0,b1*y1,b2*y2,2); | |||
return by3[0]/b3[0]; | |||
} | |||
thirdCircleRadius = function() { | |||
var b0,b1,b2, b3,bx3,by3; | |||
b0 = c0.curvature(); | |||
b1 = c1.curvature(); | |||
b2 = c2.curvature(); | |||
b3 = solveQ2(b0,b1,b2,0); | |||
return 1.0/b3[0]; | |||
} | |||
c3 = brd.create('circle',[[thirdCircleX,thirdCircleY],thirdCircleRadius],{strokeWidth:1}); | |||
c3.curvature = function(){ return 1.0/this.radius;}; | |||
otherCirc = function(circs,level) { | |||
var c, fx,fy,fr; | |||
if (level<=0) return; | |||
fx = function() { | |||
var b,x,i; | |||
b = []; | |||
x = []; | |||
for (i=0;i<4;i++) { | |||
b[i] = circs[i].curvature(); | |||
x[i] = circs[i].midpoint.X(); | |||
} | |||
b[4] = 2*(b[0]+b[1]+b[2])-b[3]; | |||
x[4] = (2*(b[0]*x[0]+b[1]*x[1]+b[2]*x[2])-b[3]*x[3])/b[4]; | |||
return x[4]; | |||
} | |||
fy = function() { | |||
var b,y,i; | |||
b = []; | |||
y = []; | |||
for (i=0;i<4;i++) { | |||
b[i] = circs[i].curvature(); | |||
y[i] = circs[i].midpoint.Y(); | |||
} | |||
b[4] = 2*(b[0]+b[1]+b[2])-b[3]; | |||
y[4] = (2*(b[0]*y[0]+b[1]*y[1]+b[2]*y[2])-b[3]*y[3])/b[4]; | |||
return y[4]; | |||
} | |||
fr = function() { | |||
var b,i; | |||
b = []; | |||
for (i=0;i<4;i++) { | |||
b[i] = circs[i].curvature(); | |||
} | } | ||
b[4] = 2*(b[0]+b[1]+b[2])-b[3]; | |||
if ( | if (isNaN(b[4])) { | ||
return 1000.0; | |||
} else { | } else { | ||
return 1/b[4]; | |||
} | } | ||
} | } | ||
c = brd.create('circle',[[fx,fy],fr],{strokeWidth:1,name:'', | |||
fillColor:JXG.hsv2rgb(50*level,0.8,0.8),highlightFillColor:JXG.hsv2rgb(50*level,0.5,0.8),fillOpacity:0.5,highlightFillOpacity:0.5}); | |||
c.curvature = function(){ return 1/this.radius;}; | |||
return | |||
// Recursion | |||
otherCirc([circs[0],circs[1],c,circs[2]],level-1); | |||
otherCirc([circs[0],circs[2],c,circs[1]],level-1); | |||
otherCirc([circs[1],circs[2],c,circs[0]],level-1); | |||
return c; | |||
} | } | ||
//------------------------------------------------------- | |||
brd.suspendUpdate(); | |||
level = 4; | |||
otherCirc([c0,c1,c2,c3],level); | |||
otherCirc([c3,c1,c2,c0],level); | |||
otherCirc([c0,c2,c3,c1],level); | |||
otherCirc([c0,c1,c3,c2],level); | |||
brd.unsuspendUpdate(); | |||
</jsxgraph> | |||
===The underlying JavaScript code=== | |||
<source lang="javascript"> | |||
var brd = JXG.JSXGraph.initBoard('box', {boundingbox: [-2, 2, 2, -2]}); | |||
solveQ2 = function(x1,x2,x3,off) { | solveQ2 = function(x1,x2,x3,off) { | ||
var a, b, c, d; | var a, b, c, d; | ||
Line 47: | Line 137: | ||
} | } | ||
a = brd. | a = brd.create('segment',[[0,0],[2,0]],{visible:false}); | ||
p1 = brd.create('glider',[1.3,0,a],{name:'Drag me'}); | |||
p1 = brd. | |||
b0 = -0.5; | b0 = -0.5; | ||
c0 = brd.create('circle',[[0,0],Math.abs(1.0/b0)],{strokeWidth:1}); | |||
c1 = brd.create('circle',[p1,function(){return 2-p1.X();}],{strokeWidth:1}); | |||
c2 = brd.create('circle',[[function(){return p1.X()-2;},0],function(){return p1.X();}],{strokeWidth:1}); | |||
c0.curvature = function(){ return b0;}; // constant | c0.curvature = function(){ return b0;}; // constant | ||
c1.curvature = function(){ return 1/(2-p1.X());}; | c1.curvature = function(){ return 1/(2-p1.X());}; | ||
Line 101: | Line 184: | ||
} | } | ||
c3 = brd.create('circle',[[thirdCircleX,thirdCircleY],thirdCircleRadius],{strokeWidth:1}); | |||
c3.curvature = function(){ return 1.0/this.radius;}; | c3.curvature = function(){ return 1.0/this.radius;}; | ||
otherCirc = function(circs,level) { | otherCirc = function(circs,level) { | ||
var | var c, fx,fy,fr; | ||
if (level<=0) return; | if (level<=0) return; | ||
fx = function() { | fx = function() { | ||
Line 141: | Line 223: | ||
} | } | ||
b[4] = 2*(b[0]+b[1]+b[2])-b[3]; | b[4] = 2*(b[0]+b[1]+b[2])-b[3]; | ||
return 1/b[4]; | if (isNaN(b[4])) { | ||
return 1000.0; | |||
} else { | |||
return 1/b[4]; | |||
} | |||
} | } | ||
c = brd.create('circle',[[fx,fy],fr],{strokeWidth:1,name:'', | |||
fillColor:JXG.hsv2rgb(50*level,0.8,0.8),highlightFillColor:JXG.hsv2rgb(50*level,0.5,0.8),fillOpacity:0.5,highlightFillOpacity:0.5}); | |||
c.curvature = function(){ return 1/this.radius;}; | c.curvature = function(){ return 1/this.radius;}; | ||
// Recursion | |||
otherCirc([circs[0],circs[1],c,circs[2]],level-1); | otherCirc([circs[0],circs[1],c,circs[2]],level-1); | ||
otherCirc([circs[0],circs[2],c,circs[1]],level-1); | otherCirc([circs[0],circs[2],c,circs[1]],level-1); | ||
Line 161: | Line 248: | ||
otherCirc([c0,c1,c3,c2],level); | otherCirc([c0,c1,c3,c2],level); | ||
brd.unsuspendUpdate(); | brd.unsuspendUpdate(); | ||
</ | </source> | ||
===References=== | |||
* [http://www.ams.org/featurecolumn/archive/kissing.html http://www.ams.org/featurecolumn/archive/kissing.html] | |||
* [http://arxiv.org/abs/math.MG/0101066 Jeffrey C. Lagarias, Colin L. Mallows, Allan R. Wilks: Beyond the Descartes circle theorem] | |||
* [http://en.wikipedia.org/wiki/Apollonian_gasket http://en.wikipedia.org/wiki/Apollonian_gasket] | |||
* [http://mathworld.wolfram.com/ApollonianGasket.html Weisstein, Eric W. "Apollonian Gasket." From MathWorld--A Wolfram Web Resource] | |||
* [http://mathworld.wolfram.com/SoddyCircles.html Weisstein, Eric W. "Soddy Circles." From MathWorld--A Wolfram Web Resource] | |||
[[Category:Examples]] | [[Category:Examples]] | ||
[[Category:Geometry]] | [[Category:Geometry]] |
Latest revision as of 09:34, 7 June 2011
The underlying JavaScript code
var brd = JXG.JSXGraph.initBoard('box', {boundingbox: [-2, 2, 2, -2]});
solveQ2 = function(x1,x2,x3,off) {
var a, b, c, d;
a = 0.5;
b = -(x1+x2+x3);
c = x1*x1+x2*x2+x3*x3-0.5*(x1+x2+x3)*(x1+x2+x3)-off;
d = b*b-4*a*c;
if (Math.abs(d)<0.00000001) d = 0.0;
return [(-b+Math.sqrt(d))/(2.0*a),(-b-Math.sqrt(d))/(2.0*a)];
}
a = brd.create('segment',[[0,0],[2,0]],{visible:false});
p1 = brd.create('glider',[1.3,0,a],{name:'Drag me'});
b0 = -0.5;
c0 = brd.create('circle',[[0,0],Math.abs(1.0/b0)],{strokeWidth:1});
c1 = brd.create('circle',[p1,function(){return 2-p1.X();}],{strokeWidth:1});
c2 = brd.create('circle',[[function(){return p1.X()-2;},0],function(){return p1.X();}],{strokeWidth:1});
c0.curvature = function(){ return b0;}; // constant
c1.curvature = function(){ return 1/(2-p1.X());};
c2.curvature = function(){ return 1/(p1.X());};
thirdCircleX = function() {
var b0,b1,b2,x0,x1,x2, b3,bx3;
b0 = c0.curvature();
b1 = c1.curvature();
b2 = c2.curvature();
x0 = c0.midpoint.X();
x1 = c1.midpoint.X();
x2 = c2.midpoint.X();
b3 = solveQ2(b0,b1,b2,0);
bx3 = solveQ2(b0*x0,b1*x1,b2*x2,2);
return bx3[0]/b3[0];
}
thirdCircleY = function() {
var b0,b1,b2,y0,y1,y2, b3,by3;
b0 = c0.curvature();
b1 = c1.curvature();
b2 = c2.curvature();
y0 = c0.midpoint.Y();
y1 = c1.midpoint.Y();
y2 = c2.midpoint.Y();
b3 = solveQ2(b0,b1,b2,0);
by3 = solveQ2(b0*y0,b1*y1,b2*y2,2);
return by3[0]/b3[0];
}
thirdCircleRadius = function() {
var b0,b1,b2, b3,bx3,by3;
b0 = c0.curvature();
b1 = c1.curvature();
b2 = c2.curvature();
b3 = solveQ2(b0,b1,b2,0);
return 1.0/b3[0];
}
c3 = brd.create('circle',[[thirdCircleX,thirdCircleY],thirdCircleRadius],{strokeWidth:1});
c3.curvature = function(){ return 1.0/this.radius;};
otherCirc = function(circs,level) {
var c, fx,fy,fr;
if (level<=0) return;
fx = function() {
var b,x,i;
b = [];
x = [];
for (i=0;i<4;i++) {
b[i] = circs[i].curvature();
x[i] = circs[i].midpoint.X();
}
b[4] = 2*(b[0]+b[1]+b[2])-b[3];
x[4] = (2*(b[0]*x[0]+b[1]*x[1]+b[2]*x[2])-b[3]*x[3])/b[4];
return x[4];
}
fy = function() {
var b,y,i;
b = [];
y = [];
for (i=0;i<4;i++) {
b[i] = circs[i].curvature();
y[i] = circs[i].midpoint.Y();
}
b[4] = 2*(b[0]+b[1]+b[2])-b[3];
y[4] = (2*(b[0]*y[0]+b[1]*y[1]+b[2]*y[2])-b[3]*y[3])/b[4];
return y[4];
}
fr = function() {
var b,i;
b = [];
for (i=0;i<4;i++) {
b[i] = circs[i].curvature();
}
b[4] = 2*(b[0]+b[1]+b[2])-b[3];
if (isNaN(b[4])) {
return 1000.0;
} else {
return 1/b[4];
}
}
c = brd.create('circle',[[fx,fy],fr],{strokeWidth:1,name:'',
fillColor:JXG.hsv2rgb(50*level,0.8,0.8),highlightFillColor:JXG.hsv2rgb(50*level,0.5,0.8),fillOpacity:0.5,highlightFillOpacity:0.5});
c.curvature = function(){ return 1/this.radius;};
// Recursion
otherCirc([circs[0],circs[1],c,circs[2]],level-1);
otherCirc([circs[0],circs[2],c,circs[1]],level-1);
otherCirc([circs[1],circs[2],c,circs[0]],level-1);
return c;
}
//-------------------------------------------------------
brd.suspendUpdate();
level = 4;
otherCirc([c0,c1,c2,c3],level);
otherCirc([c3,c1,c2,c0],level);
otherCirc([c0,c2,c3,c1],level);
otherCirc([c0,c1,c3,c2],level);
brd.unsuspendUpdate();
References
- http://www.ams.org/featurecolumn/archive/kissing.html
- Jeffrey C. Lagarias, Colin L. Mallows, Allan R. Wilks: Beyond the Descartes circle theorem
- http://en.wikipedia.org/wiki/Apollonian_gasket
- Weisstein, Eric W. "Apollonian Gasket." From MathWorld--A Wolfram Web Resource
- Weisstein, Eric W. "Soddy Circles." From MathWorld--A Wolfram Web Resource