something for the hoodie pattern?

Came back to this after a long time.

For some reason, the tiles have straight lines.
This commit is contained in:
Christian Lawson-Perfect 2025-05-07 11:32:22 +01:00
parent e800edc47e
commit c34514e939
2 changed files with 49 additions and 32 deletions

View file

@ -27,32 +27,39 @@ textarea {
</head> </head>
<body> <body>
<section id="drawing"> <section id="drawing">
<svg viewBox="-9 -68 162 27" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="0 0 190 195" xmlns="http://www.w3.org/2000/svg">
<defs> <defs>
<path id="spectre" <path id="spectre"
d="M 0 1 C 0.6 0.6699999999999999 0.6 0.32999999999999996 0 0 C 0.33 -0.6 0.67 -0.6 1 0 C 1.684615242270663 0.014211616751135248 1.854615242270663 -0.2802370205355739 1.5 -0.8660254037844386 C 2.0857883832488646 -1.2206406460551018 2.380237020535574 -1.0506406460551019 2.366025403784439 -0.36602540378443865 C 1.7660254037844387 -0.03602540378443864 1.7660254037844387 0.3039745962155614 2.366025403784439 0.6339745962155614 C 2.696025403784439 0.033974596215561426 3.0360254037844387 0.033974596215561426 3.366025403784439 0.6339745962155614 C 3.011410161513776 1.2197629794644262 3.1814101615137758 1.5142116167511352 3.866025403784439 1.5 C 3.880237020535574 2.184615242270663 3.5857883832488646 2.354615242270663 3 2 C 3.014211616751135 1.3153847577293367 2.719762979464426 1.1453847577293368 2.133974596215561 1.5 C 2.4885898384862246 2.085788383248865 2.3185898384862247 2.3802370205355743 1.6339745962155614 2.3660254037844393 C 1.3039745962155613 1.7660254037844392 0.9639745962155614 1.7660254037844392 0.6339745962155614 2.3660254037844393 C 0.3039745962155614 2.9660254037844394 -0.03602540378443864 2.9660254037844394 -0.3660254037844386 2.3660254037844393 C -0.011410161513775163 1.7802370205355742 -0.18141016151377531 1.4857883832488645 -0.866025403784439 1.5 C -0.8802370205355741 0.8153847577293366 -0.5857883832488648 0.6453847577293367 0 1" d="M 0 1 C 0.6 0.6699999999999999 0.6 0.32999999999999996 0 0 C 0.33 -0.6 0.67 -0.6 1 0 C 1.684615242270663 0.014211616751135248 1.854615242270663 -0.2802370205355739 1.5 -0.8660254037844386 C 2.0857883832488646 -1.2206406460551018 2.380237020535574 -1.0506406460551019 2.366025403784439 -0.36602540378443865 C 1.7660254037844387 -0.03602540378443864 1.7660254037844387 0.3039745962155614 2.366025403784439 0.6339745962155614 C 2.696025403784439 0.033974596215561426 3.0360254037844387 0.033974596215561426 3.366025403784439 0.6339745962155614 C 3.011410161513776 1.2197629794644262 3.1814101615137758 1.5142116167511352 3.866025403784439 1.5 C 3.880237020535574 2.184615242270663 3.5857883832488646 2.354615242270663 3 2 C 3.014211616751135 1.3153847577293367 2.719762979464426 1.1453847577293368 2.133974596215561 1.5 C 2.4885898384862246 2.085788383248865 2.3185898384862247 2.3802370205355743 1.6339745962155614 2.3660254037844393 C 1.3039745962155613 1.7660254037844392 0.9639745962155614 1.7660254037844392 0.6339745962155614 2.3660254037844393 C 0.3039745962155614 2.9660254037844394 -0.03602540378443864 2.9660254037844394 -0.3660254037844386 2.3660254037844393 C -0.011410161513775163 1.7802370205355742 -0.18141016151377531 1.4857883832488645 -0.866025403784439 1.5 C -0.8802370205355741 0.8153847577293366 -0.5857883832488648 0.6453847577293367 0 1"
stroke="currentColor" stroke="black"
stroke-width="0.1" stroke-width="0.1"
stroke-opacity="0.5" stroke-opacity="1"
stroke-linejoin="round" stroke-linejoin="round"
fill="currentColor"></path> fill="currentColor"></path>
</defs> </defs>
<g id="board" style="transform: translate(0,-120px) rotate(90deg)"></g> <g id="board"></g>
<text x="86" fill="white" y="-45" font-size="8px">The Aperiodical</text>
</svg> </svg>
</section> </section>
<section id="controls"> <section id="controls">
<fieldset> <fieldset>
<legend>Viewbox</legend> <legend>Viewbox</legend>
<label for="vx1">min x</label> <label for="ox">min x</label>
<input type="range" min="-500" max="500" value="-9" id="vx1"> <input type="number" min="-500" max="500" value="0" id="ox">
<label for="vy1">min y</label> <output for="ox"></output>
<input type="range" min="-500" max="500" value="-68" id="vy1"> <label for="oy">min y</label>
<label for="vx2">max x</label> <input type="number" min="-500" max="500" value="0" id="oy">
<input type="range" min="-500" max="500" value="153" id="vx2"> <output for="oy"></output>
<label for="vy2">max y</label> <label for="width">max x</label>
<input type="range" min="-500" max="500" value="-41" id="vy2"> <input type="number" min="-500" max="500" value="190" id="width">
<output for="width"></output>
<label for="height">max y</label>
<input type="number" min="-500" max="500" value="190" id="height">
<output for="height"></output>
<label for="scale">Piece scale</label>
<input type="range" min="0" max="1" value="1" step="0.01" id="scale">
<output for="scale"></output>
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Colours</legend> <legend>Colours</legend>

View file

@ -185,10 +185,9 @@ class Shape
const [a,c,e,b,d,f] = S; const [a,c,e,b,d,f] = S;
const matS = [a,b,c,d,e,f].map(p=>p.toFixed(3)); const matS = [a,b,c,d,e,f].map(p=>p.toFixed(3));
const s = `<use href="#spectre" transform="matrix(${matS.join(',')})"/>`; //const s = `<use href="#spectre" transform="matrix(${matS.join(',')}) "/>`;
//const points = this.pts.map(({x,y}) => `${x.toFixed(3)},${y.toFixed(3)}`).join(' '); const points = this.pts.map(({x,y}) => `${x.toFixed(3)},${y.toFixed(3)}`).join(' ');
/*
const tp = this.pts[0]; const tp = this.pts[0];
var s = `<path transform="matrix(${matS.join(',')})" d="M ${tp.x} ${tp.y}`; var s = `<path transform="matrix(${matS.join(',')})" d="M ${tp.x} ${tp.y}`;
@ -198,15 +197,14 @@ class Shape
const b = this.pts[idx+1]; const b = this.pts[idx+1];
const c = this.pts[idx+2]; const c = this.pts[idx+2];
s = s + ` C ${a.x} ${a.y} ${b.x} ${b.y} ${c.x} ${c.y}`; s = s + ` L ${c.x} ${c.y}`;
} }
s = s + `" s = s + `"
stroke="currentColor" stroke="white"
stroke-width="0.1" stroke-width="0.1"
stroke-opacity="0.2" stroke-opacity="1"
fill="currentColor" />`; fill="currentColor" />`;
*/
stream.push( s ); stream.push( s );
} }
@ -252,14 +250,10 @@ class Meta
const {minx,miny,maxx,maxy} = this.bounds(S); const {minx,miny,maxx,maxy} = this.bounds(S);
const [a,c,e,b,d,f] = S; const [a,c,e,b,d,f] = S;
const matS = [a,b,c,d,e,f].map(p=>p.toFixed(3)); const matS = [a,b,c,d,e,f];//.map(p=>p.toFixed(3));
stream.push(`<g transform="matrix(${matS.join(',')})">`);
const quad_points = this.quad.map(({x,y}) => `${x},${y}`).join(' ');
// stream.push(`<polygon fill="blue" fill-opacity="0.2" points="${quad_points}"></polygon>`);
for( let g of this.geoms ) { for( let g of this.geoms ) {
g.geom.streamSVG( g.xform, stream ); g.geom.streamSVG( mul(S,g.xform), stream );
} }
stream.push('</g>');
} }
@ -581,6 +575,10 @@ function hexToHSL(H) {
let last_num_iterations; let last_num_iterations;
function get_settings() { function get_settings() {
Array.from(document.querySelectorAll('input[type="range"]')).forEach(i => {
const o = document.querySelector(`output[for="${i.id}"]`);
o.textContent = i.value;
});
return Object.fromEntries( return Object.fromEntries(
Array.from(document.querySelectorAll('input,textarea')).map(i => [i.id, i.type=='number' ? i.valueAsNumber : i.value]) Array.from(document.querySelectorAll('input,textarea')).map(i => [i.id, i.type=='number' ? i.valueAsNumber : i.value])
); );
@ -609,7 +607,7 @@ function rebuild() {
for(let c of g.children) { for(let c of g.children) {
visit(c, t+Math.random()*10-5); visit(c, t+Math.random()*10-5);
} }
if(g.tagName=='use') { if(g.tagName=='path') {
const b = g.getBoundingClientRect(); const b = g.getBoundingClientRect();
const x = (b.x - viewbox.x) / viewbox.width; const x = (b.x - viewbox.x) / viewbox.width;
const y = (b.y - viewbox.y) / viewbox.height; const y = (b.y - viewbox.y) / viewbox.height;
@ -623,13 +621,20 @@ function rebuild() {
function finish() { function finish() {
const svg = document.querySelector('svg'); const svg = document.querySelector('svg');
const viewbox = svg.getBoundingClientRect(); const viewbox = svg.getBoundingClientRect();
Array.from(document.querySelectorAll('#board g,use')).filter(g=>{ Array.from(document.querySelectorAll('#board use, #board path')).filter(g=>{
const b = g.getBoundingClientRect(); const b = g.getBoundingClientRect();
return (b.x+b.width<viewbox.x || b.y+b.height<viewbox.y || b.x>viewbox.x+viewbox.width || b.y>viewbox.y+viewbox.height); return (b.x<viewbox.x || b.y<viewbox.y || b.x+b.width>viewbox.x+viewbox.width || b.y+b.height>viewbox.y+viewbox.height);
}).forEach(g => g.parentElement.removeChild(g)) }).forEach(g => g.parentElement.removeChild(g))
Array.from(svg.querySelectorAll('text')).forEach(text => {
text.parentElement.removeChild(text); const transforms = Array.from(document.querySelectorAll('#board use')).map(g=>{
const {a,b,c,d,e,f} = g.transform.baseVal[0].matrix;
return [
[a,c,0,e],
[b,d,0,f],
[0,0,1,0]
];
}); });
console.log(transforms);
navigator.clipboard.writeText(svg.outerHTML); navigator.clipboard.writeText(svg.outerHTML);
} }
@ -637,7 +642,12 @@ function setup() {
const settings = get_settings(); const settings = get_settings();
const svg = document.querySelector('svg'); const svg = document.querySelector('svg');
//const bounds = sys.bounds(ident); //const bounds = sys.bounds(ident);
svg.setAttribute('viewBox',`${settings.vx1} ${settings.vy1} ${settings.vx2-settings.vx1} ${settings.vy2-settings.vy1}`); svg.setAttribute('viewBox',`${settings.ox - settings.width/2} ${settings.oy - settings.height/2} ${settings.width} ${settings.height}`);
const mx = spectre.map(p=>p.x).reduce((a,b)=>a+b)/spectre.length;
const my = spectre.map(p=>p.y).reduce((a,b)=>a+b)/spectre.length;
console.log(Math.max(...spectre.map(p=>p.x)) - Math.min(...spectre.map(p=>p.x)));
console.log(Math.max(...spectre.map(p=>p.y)) - Math.min(...spectre.map(p=>p.y)));
document.getElementById('spectre').setAttribute('transform',`translate(${mx},${my}) scale(${settings.scale}) translate(${-mx},${-my})`);
if(settings.num_iterations != last_num_iterations) { if(settings.num_iterations != last_num_iterations) {
rebuild(); rebuild();