Hexagons

Hexagons everywhere.

#hexagons #escher

Log in to post a comment.

const size = 20; // min=10, max=100, step=1
const width = .3; // min=0.1, max=0.35, step=0.001
const innerCube = .2; // min=0.0, max=0.35, step=0.001
const addHatching = 0; // min=0, max=1, step=1 (No, Yes)

const turtle = new Turtle();
let   polys;

function createHexagon(p) {
    const [x, y] = p, h = Math.sqrt(3)/4;
    return { 
        center: [x*.75, y*2*h + ((x % 2 != 0) ? 0:h)],
        points: [[0,-h], [3/8,-h/2], [3/8,h/2], [0,h], [-3/8,h/2], [-3/8,-h/2]]
    };
}

function walk(i) {
    polys = new Polygons();
     
    const s = (200/size|0)+10;
    const y = Math.floor(i/(s*2))-s;
    const x = (i % (s*2)) - s;
    
    const h = createHexagon([x,y]);
    const c = scale(h.center, size), p = h.points.map(p => add(scale(p, size * 1.2),c));
    
    const up = Math.random() > .95;
    const order = up ? [1, 3, 5, 0, 2, 4] : [0, 2, 4, 1, 3, 5];
    
    const lr = width;
    const lc = innerCube;
    
    order.forEach( (j, index) => {
        const p0 = p[j], 
              pp = p[(j + 5) % 6], 
              pn = p[(j + 1) % 6];
        
        const o = sub(lerp(c, p0, lc), c);      
              
        drawPolygon( [lerp(p0, pp, lr), p0, add(c, o), add(lerp(c, pp, lr), o)], j === 0 || j=== 1 ? 1 :  j === 2 || j=== 3 ? -1 : 0);
        drawPolygon( [p0, lerp(p0, pn, lr), add(lerp(c, pn, lr), o), add(c, o)], j === 3 || j=== 4 ? 1 :  j === 0 || j=== 5 ? -1 : 0);

        if (index === 2 && innerCube > 0) {
            // draw innerCube
            const o = up ? 0 : 1, s = 2*lc + lr;
            drawPolygon( [lerp(c, p[0+o], s), lerp(c, p[1+o], s), lerp(c, p[2+o], s), c], -1, false);
            drawPolygon( [lerp(c, p[2+o], s), lerp(c, p[3+o], s), lerp(c, p[4+o], s), c], 0, false);
            drawPolygon( [lerp(c, p[4+o], s), lerp(c, p[(5+o)%6], s), lerp(c, p[0+o], s), c], 1, false);
        }

    });
    
    return i < s*s*4;
}

function drawPolygon(cp, h, hideFirstOuterLine = true) {
    const poly = polys.create();
    poly.addPoints(...cp);
    poly.addOutline(hideFirstOuterLine ? 1 : 0);
    if (h && addHatching) {
        poly.addHatching(h * Math.PI/4, 0.75 - 0.25 * h);
    }
    polys.draw(turtle, poly);
}

// 
// 2D Vector math
//

function scale(a,b) { return [a[0]*b,a[1]*b]; }
function add(a,b) { return [a[0]+b[0],a[1]+b[1]]; }
function sub(a,b) { return [a[0]-b[0],a[1]-b[1]]; }
function lerp(a,b,t) { return [a[0]*(1-t)+b[0]*t,a[1]*(1-t)+b[1]*t]; }


////////////////////////////////////////////////////////////////
// Polygon Clipping utility code - Created by Reinder Nijhoff 2019
// https://turtletoy.net/turtle/a5befa1f8d
////////////////////////////////////////////////////////////////
function Polygons(){let t=[];const s=class{constructor(){this.cp=[],this.dp=[],this.aabb=[]}addPoints(...t){let s=1e5,e=-1e5,h=1e5,i=-1e5;(this.cp=[...this.cp,...t]).forEach(t=>{s=Math.min(s,t[0]),e=Math.max(e,t[0]),h=Math.min(h,t[1]),i=Math.max(i,t[1])}),this.aabb=[(s+e)/2,(h+i)/2,(e-s)/2,(i-h)/2]}addSegments(...t){t.forEach(t=>this.dp.push(t))}addOutline(i=0){for(let t=i,s=this.cp.length;t<s;t++)this.dp.push(this.cp[t],this.cp[(t+1)%s])}draw(t){for(let s=0,e=this.dp.length;s<e;s+=2)t.jump(this.dp[s]),t.goto(this.dp[s+1])}addHatching(t,e){const h=new s;h.cp.push([-1e5,-1e5],[1e5,-1e5],[1e5,1e5],[-1e5,1e5]);const i=Math.sin(t)*e,n=Math.cos(t)*e,a=200*Math.sin(t),p=200*Math.cos(t);for(let t=.5;t<150/e;t++)h.dp.push([i*t+p,n*t-a],[i*t-p,n*t+a]),h.dp.push([-i*t+p,-n*t-a],[-i*t-p,-n*t+a]);h.boolean(this,!1),this.dp=[...this.dp,...h.dp]}inside(t){let s=0;for(let e=0,h=this.cp.length;e<h;e++)this.segment_intersect(t,[.13,-1e3],this.cp[e],this.cp[(e+1)%h])&&s++;return 1&s}boolean(t,s=!0){if(s&&Math.abs(this.aabb[0]-t.aabb[0])-(t.aabb[2]+this.aabb[2])>=0&&Math.abs(this.aabb[1]-t.aabb[1])-(t.aabb[3]+this.aabb[3])>=0)return this.dp.length>0;const e=[];for(let h=0,i=this.dp.length;h<i;h+=2){const i=this.dp[h],n=this.dp[h+1],a=[];for(let s=0,e=t.cp.length;s<e;s++){const h=this.segment_intersect(i,n,t.cp[s],t.cp[(s+1)%e]);!1!==h&&a.push(h)}if(0===a.length)s===!t.inside(i)&&e.push(i,n);else{a.push(i,n);const h=n[0]-i[0],p=n[1]-i[1];a.sort((t,s)=>(t[0]-i[0])*h+(t[1]-i[1])*p-(s[0]-i[0])*h-(s[1]-i[1])*p);for(let h=0;h<a.length-1;h++)(a[h][0]-a[h+1][0])**2+(a[h][1]-a[h+1][1])**2>=.001&&s===!t.inside([(a[h][0]+a[h+1][0])/2,(a[h][1]+a[h+1][1])/2])&&e.push(a[h],a[h+1])}}return(this.dp=e).length>0}segment_intersect(t,s,e,h){const i=(h[1]-e[1])*(s[0]-t[0])-(h[0]-e[0])*(s[1]-t[1]);if(0===i)return!1;const n=((h[0]-e[0])*(t[1]-e[1])-(h[1]-e[1])*(t[0]-e[0]))/i,a=((s[0]-t[0])*(t[1]-e[1])-(s[1]-t[1])*(t[0]-e[0]))/i;return n>=0&&n<=1&&a>=0&&a<=1&&[t[0]+n*(s[0]-t[0]),t[1]+n*(s[1]-t[1])]}};return{list:()=>t,create:()=>new s,draw:(s,e,h=!0)=>{for(let s=0;s<t.length&&e.boolean(t[s]);s++);e.draw(s),h&&t.push(e)}}}