Adapted from labs.jawharkodadi.com/moroccan_zellige_v2/ by Jawhar Kodadi.
Moroccan Zellige ✴️ (variation)
Moroccan Zellige ✴️ (variation)
Moroccan Zellige ✴️ (variation)
Moroccan Zellige ✴️ (variation)
Log in to post a comment.
const gridSize = 8; //min=5 max=20 step=1 const gridMargin = -18; //min=-50 max=50 step=1 const shapePoints = 16; //min=4 max=30 step=2 const pointDistance = .24; //min=0 max=3 step=.01 const shapeSize = 1.22; //min=.01 max=10 step=.01 const shapeRotation = 0; //min=0 max=360 step=1 // You can find the Turtle API reference here: https://turtletoy.net/syntax Canvas.setpenopacity(1); // Global code will be evaluated once. const turtle = new Turtle(); const grid = (new Grid(gridSize, 0, 200 - gridMargin - gridMargin)); const gridIterator = grid.iterator(); const template = Array .from({length: shapePoints}) .map((v, i, a) => [[ (i%2 == 0? 1: 1-pointDistance) * shapeSize, 2 * Math.PI * i / (a.length) + Math.PI * shapeRotation / 180 ]].map(b => [b[0] * Math.sin(b[1]), b[0] * -Math.cos(b[1])]).pop()) .map(pt => scale2(pt, grid.cellSize / 2)) function walk(i) { const cellItem = gridIterator.next(); if(cellItem.done) return false; template.forEach((pt, i, a) => { turtle.jump(add2(cellItem.value.center, pt)); turtle.goto(add2(cellItem.value.center, a[(i+1)%a.length])); }); return true; } //////////////////////////////////////////////////////////////// // Square Grid utility code - Created by Jurgen Westerhof 2023 // https://turtletoy.net/turtle/4633bef396 //////////////////////////////////////////////////////////////// function Grid(size, spacing, canvasSize = 200, location = [0, 0], cellProperties = {}) { function add2(a, b) { return [a[0]+b[0], a[1]+b[1]]; } class Grid { constructor(size, spacing, canvasSize, location, cellProperties) { this.size = size;this.spacing = spacing;this.cellProperties = cellProperties;this.iterateMax = this.size**2 - 1; this.canvasSize = canvasSize;this.location = location;this.cellSize = (Math.max(0.1, (canvasSize - (size-1)*spacing)) / size); } getCellByIndex(i) {const col = i % this.size;const row = i / this.size | 0;return this.getCellByCoord(col, row);} getCellByCoord(col, row) {const vertice = (i) => (i + .5) * this.cellSize + i * this.spacing - this.canvasSize / 2;return {center: add2(this.location, [vertice(col), vertice(row)]),column: col,row: row,index: row * this.size + col,size: this.cellSize,spacing: this.spacing,properties: this.cellProperties,};} *iterator() {for(let i = 0; i <= this.iterateMax; i++) {yield this.getCellByIndex(i);}} } return new Grid(size, spacing, canvasSize, location, cellProperties); } //////////////////////////////////////////////////////////////// // 2D Vector Math utility code - Created by several Turtletoy users //////////////////////////////////////////////////////////////// function norm2(a) { return scale2(a, 1/len2(a)); } function add2(a, b) { return [a[0]+b[0], a[1]+b[1]]; } function sub2(a, b) { return [a[0]-b[0], a[1]-b[1]]; } function mul2(a, b) { return [a[0]*b[0], a[1]*b[1]]; } function scale2(a, s) { return mul2(a, [s,s]); } function lerp2(a,b,t) { return [a[0]*(1-t) + b[0]*t, a[1]*(1-t) + b[1]*t]; } function lenSq2(a) { return a[0]**2+a[1]**2; } function len2(a) { return Math.sqrt(lenSq2(a)); } function rot2(a) { return [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a)]; } function trans2(m, a) { return [m[0]*a[0]+m[2]*a[1], m[1]*a[0]+m[3]*a[1]]; } //Matrix(2x1) x Matrix(2x2) function dist2(a,b) { return Math.hypot(...sub2(a,b)); } function dot2(a,b) { return a[0]*b[0]+a[1]*b[1]; } function cross2(a,b) { return a[0]*b[1] - a[1]*b[0]; } function multiply2(a2x2, a) { return [(a[0]*a2x2[0])+(a[1]*a2x2[1]),(a[0]*a2x2[2])+(a[1]*a2x2[3])]; } //Matrix(2x2) x Matrix(1x2) function intersect_info2(as, ad, bs, bd) { const d = [bs[0] - as[0], bs[1] - as[1]]; const det = bd[0] * ad[1] - bd[1] * ad[0]; if(det === 0) return false; const res = [(d[1] * bd[0] - d[0] * bd[1]) / det, (d[1] * ad[0] - d[0] * ad[1]) / det]; return [...res, add2(as, scale2(ad, res[0]))]; } function intersect_ray2(a, b, c, d) { const i = intersect_info2(a, b, c, d); return i === false? i: i[2]; } function segment_intersect2(a,b,c,d, inclusive = true) { const i = intersect_info2(a, sub2(b, a), c, sub2(d, c)); if(i === false) return false; const t = inclusive? 0<=i[0]&&i[0]<=c&&0<=i[1]&&i[1]<=1: 0<i[0]&&i[0]<1&&0<i[1]&&i[1]<1; return t?i[2]:false; } function eq2(a,b) { return a[0]==b[0]&&a[1]==b[1]; } function clamp2(a, tl, br) { return [Math.max(Math.min(br[0], a[0]), tl[0]), Math.max(Math.min(br[1], a[1]), tl[1])]; }