Visual Gravity 🌌

For every circle on the grid the radius is determined by the distance to randomly placed 'gravity' points.

Log in to post a comment.

// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(-1);

class GridPlot {
    constructor(gridSize, plotSize = 200, origin = [100, 100]) {
        this.gridSize = gridSize;
        this.plotSize = plotSize;
        this.cellSize = plotSize / gridSize;
        this.origin = origin;
        this.count = gridSize * gridSize;
    }
    getCenterByIndex(i) {
        return this.getCenter(
            i % this.gridSize,
            i / this.gridSize | 0
        )
    }
    getCenter(column, row) {
        let t = this.getTopLeft(column, row);
        return [t[0] + (this.cellSize / 2), t[1] + (this.cellSize / 2)];
    }
    getTopLeft(column, row) {
        return [
            (column * this.cellSize) - this.origin[0],
            (row * this.cellSize) - this.origin[1]
        ];
    }
}

// Global code will be evaluated once.
const turtle = new Turtle();
const gp = new GridPlot(50);
const fillPlots = 0 // min=0 max=1 step=1 (Yes, No)
const randomSeed = 0;            // min=0 max=100 step=.1

// Seedable random number generator by David Bau: http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html
!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=s&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=s&f+1],c=c*d+h[s&(h[f]=h[g=s&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&"object"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:"string"==e?a:a+"\0"}function l(a,b){for(var c,d=a+"",e=0;e<d.length;)b[s&e]=s&(c^=19*b[s&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return o?n(o.randomBytes(d)):(a.crypto.getRandomValues(c=new Uint8Array(d)),n(c))}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o,p=c.pow(d,e),q=c.pow(2,f),r=2*q,s=d-1,t=c["seed"+i]=function(a,f,g){var h=[];f=1==f?{entropy:!0}:f||{};var o=l(k(f.entropy?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(f.pass||g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=p,c=0;q>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=r;)a/=2,b/=2,c>>>=1;return(a+c)/b},o,"global"in f?f.global:this==c)};if(l(c[i](),b),g&&g.exports){g.exports=t;try{o=require("crypto")}catch(u){}}else h&&h.amd&&h(function(){return t})}(this,[],Math,256,6,52,"object"==typeof module&&module,"function"==typeof define&&define,"random");
Math.seedrandom('' + randomSeed);


let singularities = [];
for(let i = 0; i < Math.floor(Math.random() * 6) + 2; i++)  {
    singularities.push({
        position: [
            Math.floor((Math.random() * gp.plotSize) - (gp.plotSize / 2)),
            Math.floor((Math.random() * gp.plotSize) - (gp.plotSize / 2))
        ],
        gravity: .04 + (Math.random() * .04)
    });
}

// The walk function will be called until it returns false.
function walk(i) {
    let p = gp.getCenterByIndex(i);
    
    let v = 0;
    singularities.forEach(function(s) { 
        let d = Math.sqrt(distanceSquared(s.position, p));
        v += Math.max(0, (gp.cellSize / 1.7) - (d * s.gravity));//.09));
    });
    
    let r = Math.min(gp.cellSize / 1.5, Math.max(v, .1));
    for(let rr = r; rr > 0; rr -= fillPlots? r: .2) { // fill
        turtle.jump(p[0], p[1] - rr);
        turtle.circle(rr);
    } // end fill
    
    return i < gp.count - 1;
}

function distanceSquared(p1, p2) {
    return Math.pow(p1[0] - p2[0], 2) + Math.pow(p1[1] - p2[1], 2);
}