Apollonian circle packing: Difference between revisions
From JSXGraph Wiki
A WASSERMANN (talk | contribs) No edit summary  | 
				No edit summary  | 
				||
| (35 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===  | ===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://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