scene.org File Archive

File download

<root>­/­parties­/­2024­/­sessions24­/­code_graphics/2024_10_31_19_04_11_digitalized-goldenhex-by-soma_arc.txt

File size:
34 917 bytes (34.10K)
File date:
2024-11-19 12:14:03
Download count:
all-time: 11

Preview

class Vec2 {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    add(v) {
        return new Vec2(this.x + v.x, this.y + v.y);
    }

    sub(v) {
        return new Vec2(this.x - v.x, this.y - v.y);
    }

    mult(v) {
        return new Vec2(this.x * v.x, this.y * v.y);
    }

    div(v) {
        return new Vec2(this.x / v.x, this.y / v.y);
    }

    scale(k) {
        return new Vec2(this.x * k, this.y * k);
    }

    length() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    lengthSq() {
        return (this.x * this.x + this.y * this.y);
    }

    normalize() {
        return this.scale(1.0 / this.length());
    }

    eq(v) {
        return Math.abs(this.x - v.x) <= Vec2.EPSILON &&
            Math.abs(this.y - v.y <= Vec2.EPSILON);
    }

    cloneDeeply() {
        return new Vec2(this.x, this.y);
    }

    rotate(rad) {
        return new Vec2(this.x * Math.cos(rad) - this.y * Math.sin(rad),
                        this.x * Math.sin(rad) + this.y * Math.cos(rad));
    }

    static normalize(v) {
        return v.normalize();
    }

    static dot(v1, v2) {
        return v1.x * v2.x + v1.y * v2.y;
    }

    static distance(v1, v2) {
        const l = v1.sub(v2);
        return Math.sqrt(l.x * l.x + l.y * l.y);
    }

    static get EPSILON() {
        return 0.00001;
    }

    getUniformArray() {
        return [this.x, this.y];
    }
}

let maxStep = 2;

class Tri {
    /**
     * @param {Vec2} a
     * @param {Vec2} b
     */
    constructor(a, b) {
        const r = (1.0 + sqrt(5)) / (2 * (2 + sqrt(5)));
        this.r = r;
        this.A = new Vec2(0, 0);
        this.B = new Vec2(1, 0);
        this.C = new Vec2(0.5, sqrt(3) * 0.5);
        this.D = new Vec2(r, 0);
        this.E = new Vec2(1 - r, 0);

        this.F = new Vec2(1 - r * 0.5, sqrt(3) * 0.5 * r);
        this.G = new Vec2((1 - r) * 0.5 + r, (1 - r) * sqrt(3) * 0.5);

        this.H = new Vec2((1 - r) * 0.5, (1 - r) * sqrt(3) * 0.5);
        this.I = new Vec2(r * 0.5, sqrt(3) * 0.5 * r);

        this.J = new Vec2(r * 0.5 + 1 - 2 * r,
                           sqrt(3) * 0.5 * r);
        this.K = new Vec2(r + (1 - 2 * r) * 0.5,
                           (1 - 2 * r) * sqrt(3) * 0.5);
        this.L = new Vec2(1 - r * 0.5 - (1 - 2 * r),
                          sqrt(3) * 0.5 * r);
        this.originalPoints = [this.A, this.B, this.C, this.D, this.E,
                               this.F, this.G, this.H, this.I, this.J,
                               this.K, this.L];


        this.scale = Vec2.distance(a, b);
        const d = b.sub(a)
        this.rad = Math.atan2(d.y, d.x);
        this.nA = a;
        this.nB = b;
        this.nC = this.C.rotate(this.rad).scale(this.scale).add(this.nA);;
        this.nD = this.D.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nE = this.E.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nF = this.F.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nG = this.G.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nH = this.H.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nI = this.I.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nJ = this.J.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nK = this.K.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nL = this.L.rotate(this.rad).scale(this.scale).add(this.nA);

        this.points = [this.nA, this.nB, this.nC, this.nD, this.nE,
                       this.nF, this.nG, this.nH, this.nI, this.nJ,
                       this.nK, this.nL];

        const triangles = [
            [this.nA, this.nD, this.nI],
            [this.nC, this.nH, this.nG],
            [this.nF, this.nE, this.nB],
            [this.nJ, this.nK, this.nL]
        ];

        this.center = this.nA.add(this.nB).add(this.nC).scale(1/3);
        this.area = (this.nA.x * (this.nB.y - this.nC.y) +
                     this.nB.x * (this.nC.y - this.nA.y) +
                     this.nC.x * (this.nA.y - this.nB.y)) * 0.5;
    }

    static area(a, b, c) {
        return (a.x * (b.y - c.y) +
                b.x * (c.y - a.y) +
                c.x * (a.y - b.y))* 0.5;
    }

    triangle(a, b, c, t) {
        triangle(a.x, a.y,
                 b.x, b.y,
                 c.x, c.y);
    }

    quad(a, b, c, d, t) {
        quad(a.x, a.y,
             b.x, b.y,
             c.x, c.y,
             d.x, d.y);
    }

    draw(i) {
        if(i % 3 === 0) {
            fill(0);
            //stroke(1)
            this.triangle(this.nA, this.nD, this.nI, 0);
            this.triangle(this.nC, this.nH, this.nG, 0);
            this.triangle(this.nF, this.nE, this.nB, 0);

            this.triangle(this.nJ, this.nK, this.nL);
            //stroke(0);
            fill(1);
            this.quad(this.nH, this.nI, this.nD, this.nK);
            fill(1);
            this.quad(this.nD, this.nE, this.nF, this.nL);
            fill(1);
            this.quad(this.nH, this.nJ, this.nF, this.nG);   
        } else if(i % 3 === 1) {
            fill(1);
            //stroke(0)
            this.triangle(this.nA, this.nD, this.nI, 0);
            this.triangle(this.nC, this.nH, this.nG, 0);
            this.triangle(this.nF, this.nE, this.nB, 0);
            
            this.triangle(this.nJ, this.nK, this.nL);

            fill(0);
            //stroke(1);
            this.quad(this.nH, this.nI, this.nD, this.nK);
            //stroke(0);
            fill(1);
            this.quad(this.nD, this.nE, this.nF, this.nL);
            fill(0);
            //stroke(0);
            this.quad(this.nH, this.nJ, this.nF, this.nG);            
        } else if (i % 3 === 2){
            fill(1);
            //stroke(1)
            this.triangle(this.nA, this.nD, this.nI, 0);
            this.triangle(this.nC, this.nH, this.nG, 0);
            fill(0);
            this.triangle(this.nF, this.nE, this.nB, 0);
            fill(0, 1, 0)
            this.triangle(this.nJ, this.nK, this.nL);
            //stroke(0);
            fill(0, 0, 1);
            this.quad(this.nH, this.nI, this.nD, this.nK);
            fill(1);
            this.quad(this.nD, this.nE, this.nF, this.nL);
            fill(0, 0, 1);
            this.quad(this.nH, this.nJ, this.nF, this.nG); 
        }
    }

    drawBase() {
        fill(1);
        this.triangle(this.nA, this.nB, this.nC);
    }

    rotate(rad) {
        const preA = this.nA.cloneDeeply();
        this.nA = this.nA.sub(preA).rotate(rad).add(preA);
        this.nB = this.nB.sub(preA).rotate(rad).add(preA);
        this.nC = this.nC.sub(preA).rotate(rad).add(preA);
        this.nD = this.nD.sub(preA).rotate(rad).add(preA);
        this.nE = this.nE.sub(preA).rotate(rad).add(preA);
        this.nF = this.nF.sub(preA).rotate(rad).add(preA);
        this.nG = this.nG.sub(preA).rotate(rad).add(preA);
        this.nH = this.nH.sub(preA).rotate(rad).add(preA);
        this.nI = this.nI.sub(preA).rotate(rad).add(preA);
        this.nJ = this.nJ.sub(preA).rotate(rad).add(preA);
        this.nK = this.nK.sub(preA).rotate(rad).add(preA);
        this.nL = this.nL.sub(preA).rotate(rad).add(preA);
        return this;
    }

    translate(v) {
        this.nA = this.nA.add(v);
        this.nB = this.nB.add(v);
        this.nC = this.nC.add(v);
        this.nD = this.nD.add(v);
        this.nE = this.nE.add(v);
        this.nF = this.nF.add(v);
        this.nG = this.nG.add(v);
        this.nH = this.nH.add(v);
        this.nI = this.nI.add(v);
        this.nJ = this.nJ.add(v);
        this.nK = this.nK.add(v);
        this.nL = this.nL.add(v);
        return this;
    }

    translated(v) {
        const newTri = new Tri(new Vec2(0, 0), new Vec2(0, 0));
        newTri.nA = this.nA.add(v);
        newTri.nB = this.nB.add(v);
        newTri.nC = this.nC.add(v);
        newTri.nD = this.nD.add(v);
        newTri.nE = this.nE.add(v);
        newTri.nF = this.nF.add(v);
        newTri.nG = this.nG.add(v);
        newTri.nH = this.nH.add(v);
        newTri.nI = this.nI.add(v);
        newTri.nJ = this.nJ.add(v);
        newTri.nK = this.nK.add(v);
        newTri.nL = this.nL.add(v);
        return newTri;
    }

    next() {
        return [
            new Tri(this.nA, this.nD, this.nI),
            new Tri(this.nH, this.nG, this.nC),
            new Tri(this.nE, this.nB, this.nF),
            new Parallelogram(this.nJ, this.nF),
            new Parallelogram(this.nI, this.nD),
            new Parallelogram(this.nE, this.nF),
            new Tri(this.nJ, this.nK)
        ];
    }
}

class Parallelogram {
    /**
     * @param {Vec2} a
     * @param {Vec2} b
     * @param {Vec2} d
     */
    constructor(a, b, d) {
        const t = (1 + sqrt(5)) * 0.5;
        const r = 1 / (t + 1);
        this.r = r;

        this.A = new Vec2(0, 0);
        this.B = new Vec2(1, 0);

        this.C = new Vec2(-1/(2 * t) + 1, sqrt(3) / (2 * t));
        this.D = new Vec2(-1/(2 * t), sqrt(3) / (2 * t));

        this.E = new Vec2(r, 0);
        this.G = this.C.sub(new Vec2(r, 0));
        this.F = new Vec2(-1/(2 * t) + 1 + r / (2 * t),sqrt(3) * (1 - r) / (2 * t));

        this.H = new Vec2(-r/(2 * t), sqrt(3) * r / (2 * t));
        this.I = this.H.add(new Vec2(r / t, 0))
        this.J = this.E.add(this.C.sub(this.F))
        this.K = this.J.add(new Vec2(r / t, 0))
        
        this.L = this.F.add(this.H.sub(this.I))
        this.M = this.G.add(this.F.sub(this.C));
        this.N = this.M.sub(new Vec2(r / t, 0));

        this.originalPoints = [this.A, this.B, this.C, this.D, this.E,
                               this.F, this.G, this.H, this.I, this.J,
                               this.K, this.L];

        this.scale = Vec2.distance(a, b);
        const ab = b.sub(a);
        this.rad = Math.atan2(ab.y, ab.x);
        this.nA = a.cloneDeeply();
        this.nB = b;
        this.nC = this.C.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nD = this.D.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nE = this.E.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nF = this.F.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nG = this.G.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nH = this.H.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nI = this.I.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nJ = this.J.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nK = this.K.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nL = this.L.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nM = this.M.rotate(this.rad).scale(this.scale).add(this.nA);
        this.nN = this.N.rotate(this.rad).scale(this.scale).add(this.nA);

        this.center = this.nA.add(this.nC).add(this.nB).add(this.nD).scale(1/4);
        this.area = Tri.area(this.nA, this.nB, this.nD) + Tri.area(this.nD, this.nB, this.nC);
    }

    triangle(a, b, c, t) {
        triangle(a.x, a.y,
                 b.x, b.y,
                 c.x, c.y);
    }

    quad(a, b, c, d, t) {
        quad(a.x, a.y,
             b.x, b.y,
             c.x, c.y,
             d.x, d.y);
    }
    
    draw(i) {
        if(i % 3 === 0) {
            fill(0, 1, 0);
            //stroke(255);
            this.quad(this.nA, this.nE, this.nJ, this.nH);
            fill(0);
            this.quad(this.nG, this.nM, this.nF, this.nC);
            fill(0);
            this.quad(this.nG, this.nN, this.nE, this.nK);
            //stroke(0);
            fill(1);
            this.quad(this.nD, this.nH, this.nI, this.nG);
            fill(1);
            this.quad(this.nE, this.nB, this.nF, this.nL);

            fill(1, 0, 0);

            this.triangle(this.nN, this.nI, this.nJ);
            fill(1, 0, 0)

            this.triangle(this.nM, this.nK, this.nL);
        } else if(i % 3 === 1) {
            fill(0);
            //stroke(255);
            this.quad(this.nA, this.nE, this.nJ, this.nH);
            fill(0);
            this.quad(this.nG, this.nM, this.nF, this.nC);
            //stroke(0);
            fill(1);
            this.quad(this.nG, this.nN, this.nE, this.nK);
            
            fill(1, 0, 0);
            this.quad(this.nD, this.nH, this.nI, this.nG);
            fill(1);
            this.quad(this.nE, this.nB, this.nF, this.nL);

            fill(0, 0, 0);

            this.triangle(this.nN, this.nI, this.nJ);
            fill(0, 0, 0)

            this.triangle(this.nM, this.nK, this.nL);
        } else if(i % 3 === 2) {
            fill(0);
            //stroke(255);
            this.quad(this.nA, this.nE, this.nJ, this.nH);
            fill(1, 0, 0);
            this.quad(this.nG, this.nM, this.nF, this.nC);
            //stroke(0);
            fill(1);
            this.quad(this.nG, this.nN, this.nE, this.nK);
            
            fill(1, 0, 0);
            this.quad(this.nD, this.nH, this.nI, this.nG);
            fill(1);
            this.quad(this.nE, this.nB, this.nF, this.nL);

            fill(1);

            this.triangle(this.nN, this.nI, this.nJ);
            fill(0, 0, 0)

            this.triangle(this.nM, this.nK, this.nL);
        }
    }

    drawBase() {
        this.quad(this.nA, this.nB, this.nC, this.nD);
    }

    rotate(rad) {
        const preA = this.nA.cloneDeeply();
        this.nA = this.nA.sub(preA).rotate(rad).add(preA);
        this.nB = this.nB.sub(preA).rotate(rad).add(preA);
        this.nC = this.nC.sub(preA).rotate(rad).add(preA);
        this.nD = this.nD.sub(preA).rotate(rad).add(preA);
        this.nE = this.nE.sub(preA).rotate(rad).add(preA);
        this.nF = this.nF.sub(preA).rotate(rad).add(preA);
        this.nG = this.nG.sub(preA).rotate(rad).add(preA);
        this.nH = this.nH.sub(preA).rotate(rad).add(preA);
        this.nI = this.nI.sub(preA).rotate(rad).add(preA);
        this.nJ = this.nJ.sub(preA).rotate(rad).add(preA);
        this.nK = this.nK.sub(preA).rotate(rad).add(preA);
        this.nL = this.nL.sub(preA).rotate(rad).add(preA);
        this.nM = this.nM.sub(preA).rotate(rad).add(preA);
        this.nN = this.nN.sub(preA).rotate(rad).add(preA);
        return this;
    }

    translate(v) {
        this.nA = this.nA.add(v);
        this.nB = this.nB.add(v);
        this.nC = this.nC.add(v);
        this.nD = this.nD.add(v);
        this.nE = this.nE.add(v);
        this.nF = this.nF.add(v);
        this.nG = this.nG.add(v);
        this.nH = this.nH.add(v);
        this.nI = this.nI.add(v);
        this.nJ = this.nJ.add(v);
        this.nK = this.nK.add(v);
        this.nL = this.nL.add(v);
        this.nM = this.nM.add(v);
        this.nN = this.nN.add(v);
        return this;
    }

    translated(v) {
        const newP = new Parallelogram(new Vec2(0, 0), new Vec2(0, 2), new Vec2(0, 0));
        newP.nA = this.nA.add(v);
        newP.nB = this.nB.add(v);
        newP.nC = this.nC.add(v);
        newP.nD = this.nD.add(v);
        newP.nE = this.nE.add(v);
        newP.nF = this.nF.add(v);
        newP.nG = this.nG.add(v);
        newP.nH = this.nH.add(v);
        newP.nI = this.nI.add(v);
        newP.nJ = this.nJ.add(v);
        newP.nK = this.nK.add(v);
        newP.nL = this.nL.add(v);
        newP.nM = this.nM.add(v);
        newP.nN = this.nN.add(v);
        return newP;
    }

    next() {
        return [
            new Parallelogram(this.nA, this.nE),
            new Parallelogram(this.nN, this.nE),
            new Parallelogram(this.nM, this.nF),
            new TrapezoidA(this.nI, this.nG),
            new TrapezoidA(this.nL, this.nE),
            new Tri(this.nK, this.nL),
            new Tri(this.nI, this.nJ, this.nK)
        ]
    }
}

class TrapezoidA {
    constructor(a, b) {
        this.baseP = new Parallelogram(a, b);
        this.topTri = new Tri(this.baseP.nD, this.baseP.nC);
        this.center = this.baseP.nA.add(this.baseP.nB).add(this.topTri.nA).add(this.topTri.nC).scale(1/4);
        this.area = this.topTri.area + this.baseP.area;
    }

    triangle(a, b, c) {
        triangle(a.x, a.y,
                 b.x, b.y,
                 c.x, c.y);
    }

    quad(a, b, c, d) {
        quad(a.x, a.y,
             b.x, b.y,
             c.x, c.y,
             d.x, d.y);
    }

    drawBase() {
        this.quad(this.baseP.nA, this.baseP.nB, this.topTri.nC, this.topTri.nA);
    }

    draw(i) {
        if(i % 3 === 0) {
            // 下部
            fill(1); // para
            this.quad(this.baseP.nA, this.baseP.nE, this.baseP.nJ, this.baseP.nH);
            fill(0);
            this.quad(this.baseP.nG, this.baseP.nN, this.baseP.nE, this.baseP.nK);
            fill(1);// trapezoid -> ZD
            this.quad(this.baseP.nD, this.baseP.nH, this.baseP.nI, this.baseP.nG);
            fill(1);// trapezoid -> ZT
            this.quad(this.baseP.nE, this.baseP.nB, this.baseP.nF, this.baseP.nL);

            fill(1, 0, 0)
            this.triangle(this.baseP.nN, this.baseP.nI, this.baseP.nJ);
            this.triangle(this.baseP.nM, this.baseP.nK, this.baseP.nL);

            // 上部

            // parallelogram
            fill(1, 0, 0);
            this.quad(this.topTri.nH, this.topTri.nI, this.topTri.nD, this.topTri.nK);
            fill(0, 1, 0);
            this.quad(this.topTri.nD, this.topTri.nE, this.topTri.nF, this.topTri.nL);
            fill(1);// trapezoid -> ZD
            this.quad(this.topTri.nF, this.topTri.nC, this.topTri.nH, this.topTri.nJ);
            fill(1, 0, 0);
            this.triangle(this.topTri.nA, this.topTri.nD, this.topTri.nI);
            fill(0)
            this.triangle(this.topTri.nJ, this.topTri.nK, this.topTri.nL);

            // 上部と底部にまたがるtrapezoid
            fill(1);// trapezoid -> ZD
            this.quad(this.topTri.nE, this.baseP.nM, this.baseP.nF, this.topTri.nF);
        } else if(i % 3 === 1) {
            // 下部
            fill(0, 1, 0); // para
            this.quad(this.baseP.nA, this.baseP.nE, this.baseP.nJ, this.baseP.nH);
            fill(0);
            this.quad(this.baseP.nG, this.baseP.nN, this.baseP.nE, this.baseP.nK);
            fill(0);// trapezoid -> ZD
            this.quad(this.baseP.nD, this.baseP.nH, this.baseP.nI, this.baseP.nG);
            fill(1);// trapezoid -> ZT
            this.quad(this.baseP.nE, this.baseP.nB, this.baseP.nF, this.baseP.nL);

            fill(1, 0, 0)
            this.triangle(this.baseP.nN, this.baseP.nI, this.baseP.nJ);
            fill(0, 1, 0)
            this.triangle(this.baseP.nM, this.baseP.nK, this.baseP.nL);

            // 上部

            // parallelogram
            fill(1);
            this.quad(this.topTri.nH, this.topTri.nI, this.topTri.nD, this.topTri.nK);
            fill(1);
            this.quad(this.topTri.nD, this.topTri.nE, this.topTri.nF, this.topTri.nL);
            fill(1);// trapezoid -> ZD
            this.quad(this.topTri.nF, this.topTri.nC, this.topTri.nH, this.topTri.nJ);
            fill(1, 0, 0);
            this.triangle(this.topTri.nA, this.topTri.nD, this.topTri.nI);
            fill(0)
            this.triangle(this.topTri.nJ, this.topTri.nK, this.topTri.nL);

            // 上部と底部にまたがるtrapezoid
            fill(1);// trapezoid -> ZD
            this.quad(this.topTri.nE, this.baseP.nM, this.baseP.nF, this.topTri.nF);
        } else if(i % 3 === 2) {
            // 下部
            fill(1); // para
            this.quad(this.baseP.nA, this.baseP.nE, this.baseP.nJ, this.baseP.nH);
            fill(0);
            this.quad(this.baseP.nG, this.baseP.nN, this.baseP.nE, this.baseP.nK);
            fill(0, 1, 0);// trapezoid -> ZD
            this.quad(this.baseP.nD, this.baseP.nH, this.baseP.nI, this.baseP.nG);
            fill(1);// trapezoid -> ZT
            this.quad(this.baseP.nE, this.baseP.nB, this.baseP.nF, this.baseP.nL);

            fill(1, 0, 0)
            this.triangle(this.baseP.nN, this.baseP.nI, this.baseP.nJ);
            fill(1)
            this.triangle(this.baseP.nM, this.baseP.nK, this.baseP.nL);

            // 上部

            // parallelogram
            fill(0, 0, 1);
            this.quad(this.topTri.nH, this.topTri.nI, this.topTri.nD, this.topTri.nK);
            fill(0);
            this.quad(this.topTri.nD, this.topTri.nE, this.topTri.nF, this.topTri.nL);
            fill(1, 0, 0);// trapezoid -> ZD
            this.quad(this.topTri.nF, this.topTri.nC, this.topTri.nH, this.topTri.nJ);
            fill(1, 0, 0);
            this.triangle(this.topTri.nA, this.topTri.nD, this.topTri.nI);
            fill(0, 0, 1)
            this.triangle(this.topTri.nJ, this.topTri.nK, this.topTri.nL);

            // 上部と底部にまたがるtrapezoid
            fill(1);// trapezoid -> ZD
            this.quad(this.topTri.nE, this.baseP.nM, this.baseP.nF, this.topTri.nF);
        }

    }

    rotate(rad) {
        const origin = this.baseP.nA.cloneDeeply();
        const prevBasePnD = this.baseP.nD.cloneDeeply();
        this.baseP = this.baseP.translate(origin.scale(-1)).rotate(rad).translate(origin);
        this.topTri = this.topTri.translate(prevBasePnD.scale(-1)).rotate(rad).translate(this.baseP.nD);
        return this;
    }

    translate(v) {
        this.baseP.translate(v);
        this.topTri.translate(v);
        return this;
    }

    translated(v) {
        const newT = new TrapezoidA(new Vec2(0, 0), new Vec2(0, 0));
        newT.baseP = this.baseP.translated(v);
        newT.topTri = this.topTri.translated(v);
        return newT;
    }

    next() {
        return [
            new Parallelogram(this.baseP.nA, this.baseP.nE),
            new Parallelogram(this.baseP.nN, this.baseP.nE),
            new TrapezoidA(this.baseP.nI, this.baseP.nG),
            new TrapezoidB(this.baseP.nL, this.baseP.nE),
            new Tri(this.baseP.nK, this.baseP.nL),
            new Tri(this.baseP.nI, this.baseP.nJ, this.baseP.nK),

            new TrapezoidA(this.baseP.nM, this.baseP.nF),

            new Tri(this.topTri.nA, this.topTri.nD, this.topTri.nI),
            new TrapezoidA(this.topTri.nJ, this.topTri.nF),
            new Parallelogram(this.topTri.nI, this.topTri.nD),
            new Parallelogram(this.topTri.nE, this.topTri.nF),
            new Tri(this.topTri.nJ, this.topTri.nK)
        ];
    }
}

class TrapezoidB {
    constructor(a, b) {
        this.baseP = new Parallelogram(a, b, null, null);
        this.topTri = new Tri(this.baseP.nD, this.baseP.nC);
        this.center = this.baseP.nA.add(this.baseP.nB).add(this.topTri.nA).add(this.topTri.nC).scale(1/4);
        this.area = this.topTri.area + this.baseP.area;
    }

    triangle(a, b, c) {
        triangle(a.x, a.y,
                 b.x, b.y,
                 c.x, c.y);
    }

    quad(a, b, c, d) {
        quad(a.x, a.y,
             b.x, b.y,
             c.x, c.y,
             d.x, d.y);
    }

    drawBase() {
        this.quad(this.baseP.nA, this.baseP.nB, this.topTri.nC, this.topTri.nA);
    }

    draw(i) {
        if(i % 3 === 0) {
            // 下部
            fill(0);
            this.quad(this.baseP.nA, this.baseP.nE, this.baseP.nJ, this.baseP.nH);
            fill(1); // trapezoid
            this.quad(this.baseP.nD, this.baseP.nH, this.baseP.nI, this.baseP.nG);
            fill(1);// trapezoid

            this.quad(this.baseP.nE, this.baseP.nB, this.baseP.nF, this.baseP.nL);
            fill(0); // parallelogram
            this.quad(this.baseP.nG, this.baseP.nN, this.baseP.nE, this.baseP.nK);
            fill(1, 0, 0);
            this.triangle(this.baseP.nN, this.baseP.nI, this.baseP.nJ);
            fill(0, 0, 1);
            this.triangle(this.baseP.nM, this.baseP.nK, this.baseP.nL);

            // 上部
            fill(1); // trapezoid ZD
            this.quad(this.topTri.nA, this.topTri.nD, this.topTri.nK, this.topTri.nH)
            fill(1, 0, 0);
            this.triangle(this.topTri.nJ, this.topTri.nK, this.topTri.nL);
            fill(0); // para
            this.quad(this.topTri.nD, this.topTri.nE, this.topTri.nF, this.topTri.nL);
            fill(0, 1, 0); // trapezoid ZT
            this.quad(this.topTri.nF, this.topTri.nC, this.topTri.nH, this.topTri.nJ);

            fill(0);
            // 上部と底部にまたがるtrapezoid
            this.quad(this.topTri.nE, this.baseP.nM, this.baseP.nF, this.topTri.nF);
        } else if (i % 3 === 1){
            // 下部
            fill(1);
            this.quad(this.baseP.nA, this.baseP.nE, this.baseP.nJ, this.baseP.nH);
            fill(1, 0, 0); // trapezoid
            this.quad(this.baseP.nD, this.baseP.nH, this.baseP.nI, this.baseP.nG);
            fill(0,0,1);// trapezoid

            this.quad(this.baseP.nE, this.baseP.nB, this.baseP.nF, this.baseP.nL);
            fill(0); // parallelogram
            this.quad(this.baseP.nG, this.baseP.nN, this.baseP.nE, this.baseP.nK);
            fill(1);
            this.triangle(this.baseP.nN, this.baseP.nI, this.baseP.nJ);
            this.triangle(this.baseP.nM, this.baseP.nK, this.baseP.nL);

            // 上部
            fill(1); // trapezoid ZD
            this.quad(this.topTri.nA, this.topTri.nD, this.topTri.nK, this.topTri.nH)
            fill(1, 0, 0);
            this.triangle(this.topTri.nJ, this.topTri.nK, this.topTri.nL);
            fill(0); // para
            this.quad(this.topTri.nD, this.topTri.nE, this.topTri.nF, this.topTri.nL);
            fill(1); // trapezoid ZT
            this.quad(this.topTri.nF, this.topTri.nC, this.topTri.nH, this.topTri.nJ);

            fill(1);
            // 上部と底部にまたがるtrapezoid
            this.quad(this.topTri.nE, this.baseP.nM, this.baseP.nF, this.topTri.nF);
        } else if (i % 3 === 2){
            // 下部
            fill(0);
            this.quad(this.baseP.nA, this.baseP.nE, this.baseP.nJ, this.baseP.nH);
            fill(1, 0, 0); // trapezoid
            this.quad(this.baseP.nD, this.baseP.nH, this.baseP.nI, this.baseP.nG);
            fill(1);// trapezoid

            this.quad(this.baseP.nE, this.baseP.nB, this.baseP.nF, this.baseP.nL);
            fill(0, 1, 0); // parallelogram
            this.quad(this.baseP.nG, this.baseP.nN, this.baseP.nE, this.baseP.nK);
            fill(1);
            this.triangle(this.baseP.nN, this.baseP.nI, this.baseP.nJ);
            fill(0, 0, 1);
            this.triangle(this.baseP.nM, this.baseP.nK, this.baseP.nL);

            // 上部
            fill(1); // trapezoid ZD
            this.quad(this.topTri.nA, this.topTri.nD, this.topTri.nK, this.topTri.nH)
            fill(1, 0, 0);
            this.triangle(this.topTri.nJ, this.topTri.nK, this.topTri.nL);
            fill(0); // para
            this.quad(this.topTri.nD, this.topTri.nE, this.topTri.nF, this.topTri.nL);
            fill(1); // trapezoid ZT
            this.quad(this.topTri.nF, this.topTri.nC, this.topTri.nH, this.topTri.nJ);

            fill(0);
            // 上部と底部にまたがるtrapezoid
            this.quad(this.topTri.nE, this.baseP.nM, this.baseP.nF, this.topTri.nF);
        }

    }

    rotate(rad) {
        const origin = this.baseP.nA.cloneDeeply();
        const prevBasePnD = this.baseP.nD.cloneDeeply();
        this.baseP = this.baseP.translate(origin.scale(-1)).rotate(rad).translate(origin);
        this.topTri = this.topTri.translate(prevBasePnD.scale(-1)).rotate(rad).translate(this.baseP.nD);
        return this;
    }

    translate(v) {
        this.baseP.translate(v);
        this.topTri.translate(v);
        return this;
    }

    translated(v) {
        const newT = new TrapezoidB(new Vec2(0, 0), new Vec2(0, 0));
        newT.baseP = this.baseP.translated(v);
        newT.topTri = this.topTri.translated(v);
        return newT;
    }

    next() {
        return [
            new Parallelogram(this.baseP.nA, this.baseP.nE),
            new Parallelogram(this.baseP.nN, this.baseP.nE),
            new TrapezoidA(this.baseP.nI, this.baseP.nG),
            new TrapezoidB(this.baseP.nL, this.baseP.nE),
            new Tri(this.baseP.nK, this.baseP.nL),
            new Tri(this.baseP.nI, this.baseP.nJ, this.baseP.nK),

            new TrapezoidA(this.topTri.nK, this.topTri.nH),
            new Parallelogram(this.topTri.nE, this.topTri.nF),
            new Tri(this.topTri.nJ, this.topTri.nK),
            
            // 接合部
            new TrapezoidA(this.baseP.nM, this.baseP.nF),
            // 頂点
            new TrapezoidB(this.topTri.nJ, this.topTri.nF),
        ];
    }
}

let level0;
let level1 = [];
let level2 = [];
//let level3 = [];
let level3 = [[], [], []];
let level4 = [[], [], []];
let level5 = [[], [], []];
let l3, l4;
function setup() {
    const w = 1920;
    const h = 1080
    createCanvas(windowWidth, windowHeight);
    background(100);
    translate(0, height);
    const s = 1000;
    scale(s, -s);

    strokeWeight(0.01/s);
    noStroke();
    level0 = new Tri(new Vec2(0, 0),
                     new Vec2(1, 0));
    //t.draw();
    level1 = level0.next();

    for(const ll of level1) {
        if(ll.center.y > level0.center.y) {
            ll.dir = 'top'
        } else if(ll.center.x < level0.center.x) {
            ll.dir = 'left'
        } else {
            ll.dir = 'right';
        }
    }

    let level2Tmp = [];
    for(const ll of level1) {
        level2Tmp = level2Tmp.concat(ll.next());
    }

    for(const ll of level2Tmp) {
        if(ll.center.y > level0.center.y) {
            ll.dir = 'top'
        } else if(ll.center.x < level0.center.x) {
            ll.dir = 'left'
        } else {
            ll.dir = 'right';
        }
        level2.push(ll);
        // if(ll.area > 1 / s) {
        //     level2.push(ll);
        // }
    }

    let level3Tmp = [];
    for(const ll of level2) {
        level3Tmp = level3Tmp.concat(ll.next());
    }
    l3 = level3Tmp;

    for(const ll of level3Tmp) {
        
        if(ll.center.y > level0.center.y) {
            ll.dir = 'top'
            level3[0].push(ll);
        } else if(ll.center.x < level0.center.x) {
            ll.dir = 'left'
            level3[1].push(ll);
        } else {
            ll.dir = 'right';
            level3[2].push(ll);
        }
    }

    let level4Tmp = []
    for(const ll of level3Tmp) {
        if(ll.area < 20/s) {
            continue;
        }
        level4Tmp = level4Tmp.concat(ll.next());
    }
    l4 = level4Tmp;

    for(const ll of level4Tmp) {
        if(ll.center.y > level0.center.y) {
            ll.dir = 'top'
            level4[0].push(ll);
        } else if(ll.center.x < level0.center.x) {
            ll.dir = 'left'
            level4[1].push(ll);
        } else {
            ll.dir = 'right';
            level4[2].push(ll);
        }
    }

    // let level5Tmp = []
    // for(const ll of level4Tmp) {
    //     if(ll.area < 1/s) {
    //         continue;
    //     }
    //     level5Tmp = level5Tmp.concat(ll.next());
    // }

    // for(const ll of level5Tmp) {
    //     if(ll.center.y > level0.center.y) {
    //         ll.dir = 'top'
    //         level5[0].push(ll);
    //     } else if(ll.center.x < level0.center.x) {
    //         ll.dir = 'left'
    //         level5[1].push(ll);
    //     } else {
    //         ll.dir = 'right';
    //         level5[2].push(ll);
    //     }
    // }

    // for(const ll of l) {
    //     ll.draw();
    // }
    // for(const ll of l) {
    //     for(const ll2 of ll.next()) {
    //         for(const tra of ll2.next()) {
    //             tra.draw();
    //         }
    //     }
    // }
    // const [t2, t3, t4] = t.nextTriangles();
    // t2.draw();
    // t3.draw();
    // t4.draw();

    frameRate(10);
}

function mix(x, y, a) {
    return x(1-a)+y*a;
}

function clamp(value, min, max) {
    return Math.min(Math.max(value, min), max);
}
//w: start time
//s: duration
function scene(t, w, s) {
    return clamp(t - w, 0.0, s) / s;
}

function expEasingIn(t){
    return Math.pow( 2., 13. * (t - 1.) );
}

function expEasingOut(t) {
    return -Math.pow( 2., -10. * t) + 1.;
}

function circEasingInOut(t){
    t /= .5;
    if (t < 1.) return -.5 * (Math.sqrt(1. - t*t) - 1.);
    t -= 2.;
    return .5 * (Math.sqrt(1. - t*t) + 1.);
}

function circEasingIn(t){
	return -  (Math.sqrt(1. - t*t) - 1.);
}

let frame = 0;

function draw() {
    colorMode(RGB, 1, 1, 1)
    const t = Math.floor(frame/5) % 3;//0//frame * 0.2;
    //console.log(t);
    background(1);
    translate(-200 -width, height);
    const s = 2000;
    scale(s, -s*1.01);

    //strokeWeight(1/s);
    noStroke();
    //const nv = level0.translated(new Vec2(width / s -(width / s) * expEasingIn(scene(t, 0, 1.5)), 0));
    //fill(0, 1, 1);

    push();
    translate(2, 0);
    for(const ll of level1) {
        ll.draw(t);
    }
    for(const ll of level2) {
        ll.draw(t);
    }
    for(const ll of l3) {
        ll.draw(t);
    }
    for(const ll of l4) {
        ll.draw(t);
    }
    rotate(PI/3);
    for(const ll of level1) {
        ll.draw(t);
    }
    for(const ll of level2) {
        ll.draw(t);
    }
    for(const ll of l3) {
        ll.draw(t);
    }
    for(const ll of l4) {
        ll.draw(t);
    }
    pop();
    //    rotate(PI / 2)

    translate(1, 0)
    push();
    rotate(PI/3)
    rotate(-PI/3)
    level0.draw();
    for(const ll of level1) {
        ll.draw(t);
    }
    for(const ll of level2) {
        ll.draw(t);
    }
    for(const ll of l3) {
        ll.draw(t);
    }
    for(const ll of l4) {
        ll.draw(t);
    }
    pop();
    rotate(-PI/3)
    translate(-1, 0)
    level0.draw();
    for(const ll of level1) {
        ll.draw(t);
    }
    for(const ll of level2) {
        ll.draw(t);
    }
    for(const ll of l3) {
        ll.draw(t);
    }
    for(const ll of l4) {
        ll.draw(t);
    }

    frame++;
}