tk555 diary

プログラミング、もしくはそれ以外のこと書きます。

【p5js】近くから見ると青海波、遠くから見るとアインシュタイン

ってのをやりたかったけど、近くから見てもアインシュタイン

f:id:tk55513:20210918073917p:plain
うっすらアインシュタイン
f:id:tk55513:20210918074201p:plain
くっきりアインシュタイン


以下ソース

const p = {
    height: 1500,
    r: 100,
    dr:12,
    dt:5,
    ds:3,
    get strokeMax(){
        return this.strokeMin+this.ds;
    },
    get strokeMin(){
        return this.dr;
    }
}
let img;
function preload(){
    img=loadImage('data:image/jpeg;base64/*省略*/');
}
function setup() {
    angleMode(DEGREES);
    console.assert(p.dr*cos(p.dt/2)>2*p.strokeMax,'probably circle hit line')
    p['width']=img.width*p.height/img.height;
    createCanvas(p.width,p.height);
    background(220);
    for (let y = 0; y <= p.height + 100; y += p.r) {
        for (let x = 0; x <= p.width+100; x += p.r * sqrt(3)) {
            multiCircle(x,y);
        }
        const y_ = y + p.r / 2;
        for (let x = sqrt(3) * p.r / 2; x <= p.width+100; x += p.r * sqrt(3)) {
            multiCircle(x,y_);
        }
    }
    save('albert.png');
}

function draw() {

}
const multiCircle = (centerX, centerY) => {
    const dr=p.dr;
    for (let r = p.r; r > 0; r -= dr) {
        oneCircle(centerX, centerY, r);
    }
}
const oneCircle = (centerX, centerY, size) => {
    let theta = 150;
    const dt = p.dt;
    let x = centerX - size * cos(theta);
    let y = centerY - size * sin(theta);
    for (; theta > 30; theta -= dt) {
        const xx = centerX - size * cos(theta - dt);
        const yy = centerY - size * sin(theta - dt);
        const gray=color2Gray(-getAveGray((x+xx)/2,(y+yy)/2,2,2));
        strokeWeight(gray2Weight(gray));
        stroke(color(44,96,gray2narrow(gray)));
        line(x, y, xx, yy);
        [x, y] = [xx, yy];
    }
    noStroke();
    circle(centerX, centerY, (size*cos(dt/2)) *2);
    stroke(color(44,96,255));
    // stroke(1);
}
const getGray=(color)=>{
    return (color[0]+color[1]+color[2])/3.0;
}
const getAveGray=(centerX,centerY,dx,dy)=>{
    let sumGray=0.0;
    for(let x=centerX-dx;x<=centerX+dx;x+=1){
        for(let y=centerY-dy;y<=centerY+dy;y+=1){
            sumGray+=getGray(img.get(convertPos(x),convertPos(y)));
        }
    }
    return sumGray/((dx*2)*(dy*2));
}

const convertPos=(x)=>{
    return x*img.height/p.height;
}
const color2Gray=(x)=>{
    return map(x,-255,0,0,255);
}
const gray2Weight=(x)=>{
    return map(x,0,255,p.strokeMin,p.strokeMax);
}
const gray2narrow=(x)=>{
    return map(x,0,255,230,255);
}