자바스크립트로 만델브로트 집합을 구현해 보았다.

만델브로트 집합

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Mandelbrot</title>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <style>
        canvas {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div align='center'>
    <canvas id="canvas"></canvas>
</div>

<script language="JavaScript">
    // Start: 2022.02.02
    // Update: 2022.02.02

    let cvs;
    let canvas;
    let bufCanvas;
    let bufCtx;

    function InitCanvas() {
        height = window.innerHeight;
        width = window.innerWidth;

        canvas = document.getElementById("canvas");
        canvas.width = width;
        canvas.height = height;
        cvs = canvas.getContext("2d");

        bufCanvas = document.createElement("canvas");
        bufCanvas.width = canvas.width;
        bufCanvas.height = canvas.height;
        bufCtx = bufCanvas.getContext("2d");
    }

    function _draw() {
        let imageData = bufCtx.createImageData(canvas.width, canvas.height);
        const MAX_COUNT = 255;

        // X = -3.0 ~ 3.0
        // Y = -2.0 ~ 2.0
        // Z = X + Yi

        let mx = -3.0;
        let my = -2.0;
        let mw = 6.0;
        let mh = 4.0;
        let scaleX = mw / imageData.width;
        let scaleY = mh / imageData.height;

        for (let i = 0; i < imageData.height; i++) {
            for (let j = 0; j < imageData.width; j++) {

                let c = 0;
                let x = mx + j * scaleX;
                let y = my + i * scaleY;
                let sx = x;
                let sy = y;

                for (c = 0; c < MAX_COUNT; c++) {
                    if (x**2 + y**2 > 4) {
                        break;
                    }
                    let nx = x**2 - y**2;
                    let ny = 2 * x * y;
                    x = nx + sx;
                    y = ny + sy;
                }

                let pos = 4 * (i * imageData.width + j);

                imageData.data[pos+0] = c;
                imageData.data[pos+1] = c;
                imageData.data[pos+2] = c;
                imageData.data[pos+3] = 255;
            }
        }

        bufCtx.putImageData(imageData, 0, 0);
    }

    function OnDraw() {
        _draw();
        cvs.beginPath();
        cvs.clearRect(0, 0, canvas.width, canvas.height);
        cvs.drawImage(bufCanvas, 0, 0);
    }

    function onLoadPage() {
        InitCanvas();
        OnDraw();
    }

    window.onload = onLoadPage();
</script>
</body>
</html>
Posted by chobocho
Coding/JavsScript 삽질기2022. 1. 20. 00:12
Sphere

 


 

소스는 아래와 같다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sphere</title>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <style>
        canvas {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div align='center'>
    <canvas id="canvas"></canvas>
</div>
<script language="JavaScript">
    // Start: 2022.01.16
    // Update: 2022.01.18

    let cvs;
    let canvas;
    let bufCanvas;
    let bufCtx;
    let thetaX = 0;
    let thetaZ = 0;

    let maxSize = 0;
    let dimen = 12;
    let ox = 0;
    let oy = 0;
    let R1 = 1;  // 원의 반지름
    let R2 = 1;  // 회전 중심과의 거리
    let R3 = 1;
    let ZZ2 = 5000;

    let SIN = [];
    let COS = [];

    function InitValue() {
        for (let i = 0; i < 628; i++) {
            SIN[i] = Math.sin(i / 100);
            COS[i] = Math.cos(i / 100);
        }
    }

    function InitCanvas() {
        height = window.innerHeight;
        width = window.innerWidth;

        console.log(">Width:", width);
        console.log(">Heigth:", height);

        canvas = document.getElementById("canvas");
        canvas.width = width;
        canvas.height = height;
        cvs = canvas.getContext("2d");

        bufCanvas = document.createElement("canvas");
        bufCanvas.width = canvas.width;
        bufCanvas.height = canvas.height;
        bufCtx = bufCanvas.getContext("2d");

        maxSize = canvas.height < canvas.width ? canvas.height : canvas.width;

        ox = canvas.width / 2;
        oy = canvas.height / 2;
        R1 = maxSize/20;  // 원의 반지름
        R2 = maxSize/10;  // 회전 중심과의 거리
        R3 = maxSize/10;
    }

    function drawCircle(x, y, c, r) {
        if (c <= 0 || c >= 255){
            console.log(c);
        }

        bufCtx.beginPath();
        bufCtx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
        bufCtx.strokeStyle = "rgb(255, 255, 255)";
        bufCtx.arc(x, y, r, 0, Math.PI * 2);
        bufCtx.stroke();
        bufCtx.fill();
        bufCtx.closePath();
    }

    function _draw() {
        if (maxSize == 0) {
            return;
        }
        // 카메라와 스크린의 거리를 z'라 하고, 그 투영되는 상을 x',y'
        // z:x = z':x'
        // z:y = z':y'
        // x' = xz'/z, y' = yz'/z
        // z' = z1
        // x', y' = xz1/z, yz1/z
        // z의 최대거리 z2 = 1000이라 하면
        // x' <= (height/2 * 0.8) (화면 중앙 위치, 마진 0.1)
        // x 의 최대 값은 R1 + R2
        // x' = Z1(R1+R2)/z2 = height * 0.4
        // Z1 = Z2 * height * 0.4 / (R1+R2)

        let points = [];
        _drawDoughnut(points);
        _drawSphere(points);

        bufCtx.strokeStyle = "black";
        bufCtx.fillStyle = "black";
        bufCtx.fillRect(0, 0, canvas.width, canvas.height);
        points.forEach(e => drawCircle(e[0], e[1], e[2], 1));

        thetaX = (thetaX + 2) % 629;
        thetaZ = (thetaZ + 2) % 629;
    }


    function _drawDoughnut(points) {
        // 카메라와 스크린의 거리를 z'라 하고, 그 투영되는 상을 x',y'
        // z:x = z':x'
        // z:y = z':y'
        // x' = xz'/z, y' = yz'/z
        // z' = z1
        // x', y' = xz1/z, yz1/z
        // z의 최대거리 z2 = 5000이라 하면
        // x' <= (height/2 * 0.8) (화면 중앙 위치, 마진 0.1)
        // x 의 최대 값은 R1 + R2
        // x' = Z1(R1+R2)/z2 = height * 0.4
        // Z1 = Z2 * height * 0.4 / (R1+R2)
        let ZZ1 = maxSize * ZZ2 * 0.4 / (R1 + R2);

        for (let i = 0; i < 628; i += dimen) {
            let x1 = COS[i] * R1 + R2;
            let y1 = SIN[i] * R1;
            let nx1 = COS[i];
            let ny1 = SIN[i];

            for (let j = 0; j < 628; j += dimen) {
                // Y축 회전
                let x2 = x1 * COS[j];
                let y2 = y1;
                let z2 = x1 * SIN[j];

                let nx2 = nx1 * COS[j];
                let ny2 = ny1;
                let nz2 = nx1 * SIN[j];

                // X축 회전
                let x3 = x2;
                let y3 = y2 * COS[thetaX] - z2 * SIN[thetaX];
                let z3 = y2 * SIN[thetaX] + z2 * COS[thetaX];

                let nx3 = nx2;
                let ny3 = ny2 * COS[thetaX] - nz2 * SIN[thetaX];
                let nz3 = ny2 * SIN[thetaX] + nz2 * COS[thetaX];

                // Z축 회전
                let x4 = x3 * COS[thetaZ] - y3 * SIN[thetaZ];
                let y4 = x3 * SIN[thetaZ] + y3 * COS[thetaZ];
                let z4 = ZZ2 * 2 + z3;

                let nx4 = nx3 * COS[thetaZ] - ny3 * SIN[thetaZ];
                let ny4 = nx3 * SIN[thetaZ] + ny3 * COS[thetaZ];
                let nz4 = nz3;

                // 법선 벡터 (nx4, ny4, nz)와 광원의 백터 내적 계산
                // 광원 위치는 (0, 0, -1)
                let lx = 0;
                let ly = 0;
                let lz = -1;
                let light = nx4 * lx + ny4 * ly + nz4 * lz;

                if (light > 0) {
                    let color = Math.round(light * 255);

                    // x' = xz'/z, y' = yz'/z
                    let xp = Math.floor(x4 * ZZ1 / z4);
                    let yp = Math.floor(-y4 * ZZ1 / z4);

                    points.push([xp + ox, yp + oy, 255-color]);
                }
            }
        }
    }


    function _drawSphere(points) {
        // 카메라와 스크린의 거리를 z'라 하고, 그 투영되는 상을 x',y'
        // z:x = z':x'
        // z:y = z':y'
        // x' = xz'/z, y' = yz'/z
        // z' = z1
        // x', y' = xz1/z, yz1/z
        // z의 최대거리 z2 = 1000이라 하면
        // x' <= (height/2 * 0.8) (화면 중앙 위치, 마진 0.1)
        // x 의 최대 값은 R1 + R2
        // x' = Z1(R1+R2)/z2 = height * 0.4
        // Z1 = Z2 * height * 0.4 / (R1+R2)

        ZZ1 = maxSize * ZZ2 * 0.4 / (R1 + R2 + R3);

        for (let i = 0; i < 628; i += dimen) {
            let x1 = COS[i] * R1;
            let y1 = SIN[i] * R1;
            let nx1 = COS[i];
            let ny1 = SIN[i];

            for (let j = 0; j < 628; j += dimen) {
                // Y축 회전
                let x2 = x1 * COS[j];
                let y2 = y1;
                let z2 = x1 * SIN[j];

                let nx2 = nx1 * COS[j];
                let ny2 = ny1;
                let nz2 = nx1 * SIN[j];

                // Z축 회전
                let x3 = x2 * COS[thetaX] - y2 * SIN[thetaX];
                let y3 = x2 * SIN[thetaX] + y2 * COS[thetaX];
                let z3 = z2;

                let nx3 = nx2 * COS[thetaX] - ny2 * SIN[thetaX];
                let ny3 = nx2 * SIN[thetaX] + ny2 * COS[thetaX];
                let nz3 = nz2;

                // X축 회전
                let x4 = x3 + R2 + R3;
                let y4 = y3 * COS[thetaX] - z3 * SIN[thetaX];
                let z4 = y3 * SIN[thetaX] + z3 * COS[thetaX];

                let nx4 = nx3;
                let ny4 = ny3 * COS[thetaX] - nz3 * SIN[thetaX];
                let nz4 = ny3 * SIN[thetaX] + nz3 * COS[thetaX];

                // Z축 시계 방향 회전
                let x5 = x4 * COS[thetaZ] + y4 * SIN[thetaZ];
                let y5 = -x4 * SIN[thetaZ] + y4 * COS[thetaZ];
                let z5 = ZZ2 + z4;

                let nx5 = nx4 * COS[thetaZ] + ny4 * SIN[thetaZ];
                let ny5 = -nx4 * SIN[thetaZ] + ny4 * COS[thetaZ];
                let nz5 = nz4;

                // 법선 벡터 (nx4, ny4, nz)와 광원의 백터 내적 계산
                // 광원 위치는 (0, 0, -1)
                let lx = 0;
                let ly = 0;
                let lz = -1;
                let light = nx5 * lx + ny5 * ly + nz5 * lz;

                if (light > 0) {
                    let color = Math.round(light * 255);

                    // x' = xz'/z, y' = yz'/z
                    let xp = Math.floor(x5 * ZZ1 / z5);
                    let yp = Math.floor(-y5 * ZZ1 / z5);

                    points.push([xp + ox, yp + oy, 255-color]);
                }
            }
        }
    }

    function OnDraw() {
        _draw();

        cvs.clearRect(0, 0, canvas.width, canvas.height);
        cvs.drawImage(bufCanvas, 0, 0);
    }


    function onLoadPage() {
        InitValue();
        InitCanvas();
        OnDraw();
        setInterval(OnDraw, 50);
    }

    window.onload = onLoadPage();
</script>
</body>
</html>
Posted by chobocho
Coding/JavsScript 삽질기2022. 1. 19. 10:25

유튜브에서본 회전 하는 3D 도넛을 구현해 보았다.

3D doughnut

코드는 아래와 같다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>3D doughnut</title>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <style>
        canvas {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div align='center'>
    <canvas id="canvas"></canvas>
</div>
<script language="JavaScript">
    // Start: 2022.01.16
    // Update: 2022.01.18

    let cvs;
    let canvas;
    let bufCanvas;
    let bufCtx;
    let thetaX = 127;
    let thetaZ = 0;

    function InitCanvas() {
        height = window.innerHeight;
        width = window.innerWidth;

        canvas = document.getElementById("canvas");
        canvas.width = width;
        canvas.height = height;
        cvs = canvas.getContext("2d");

        bufCanvas = document.createElement("canvas");
        bufCanvas.width = canvas.width;
        bufCanvas.height = canvas.height;
        bufCtx = bufCanvas.getContext("2d");
    }

    function drawCircle(x, y, c, r) {
        if (c <= 0 || c >= 255){
            console.log(c);
        }

        bufCtx.beginPath();
        bufCtx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
        bufCtx.strokeStyle = "rgb(255, 255, 255)";
        bufCtx.arc(x, y, r, 0, Math.PI * 2);
        bufCtx.stroke();
        bufCtx.fill();
        bufCtx.closePath();
    }

    function _draw() {
        let maxSize = canvas.height < canvas.width ? canvas.height : canvas.width;
        let dimen = 8;
        let ox = canvas.width / 2;
        let oy = canvas.height / 2;

        let R1 = maxSize/20;  // 원의 반지름
        let R2 = maxSize/10;  // Y축으로 회전하기 위한 반경

        // 카메라와 스크린의 거리를 z'라 하고, 그 투영되는 상을 x',y'
        // z:x = z':x'
        // z:y = z':y'
        // x' = xz'/z, y' = yz'/z
        // z' = z1
        // x', y' = xz1/z, yz1/z
        // z의 최대거리 z2 = 5000이라 하면
        // x' <= (height/2 * 0.8) (화면 중앙 위치, 마진 0.1)
        // x 의 최대 값은 R1 + R2
        // x' = Z1(R1+R2)/z2 = height * 0.4
        // Z1 = Z2 * height * 0.4 / (R1+R2)

        let ZZ2 = 5000;
        let ZZ1 = maxSize * ZZ2 * 0.4 / (R1 + R2);

        let points = [];

        for (let i = 0; i < 628; i += dimen) {
            let x1 = Math.cos(i/100) * R1 + R2;
            let y1 = Math.sin(i/100) * R1;
            let nx1 = Math.cos(i/100);
            let ny1 = Math.sin(i/100);

            for (let j = 0; j < 628; j += dimen) {
                // Y축 회전
                let x2 = x1 * Math.cos(j/100);
                let y2 = y1;
                let z2 = x1 * Math.sin(j/100);

                let nx2 = nx1 * Math.cos(j/100);
                let ny2 = ny1;
                let nz2 = nx1 * Math.sin(j/100);

                // X축 회전
                let x3 = x2;
                let y3 = y2 * Math.cos(thetaX/100) - z2 * Math.sin(thetaX/100);
                let z3 = y2 * Math.sin(thetaX/100) + z2 * Math.cos(thetaX/100);

                let nx3 = nx2;
                let ny3 = ny2 * Math.cos(thetaX/100) - nz2 * Math.sin(thetaX/100);
                let nz3 = ny2 * Math.sin(thetaX/100) + nz2 * Math.cos(thetaX/100);

                // Z축 회전
                let x4 = x3 * Math.cos(thetaZ/100) - y3 * Math.sin(thetaZ/100);
                let y4 = x3 * Math.sin(thetaZ/100) + y3 * Math.cos(thetaZ/100);
                let z4 = ZZ2 + z3;

                let nx4 = nx3 * Math.cos(thetaZ/100) - ny3 * Math.sin(thetaZ/100);
                let ny4 = nx3 * Math.sin(thetaZ/100) + ny3 * Math.cos(thetaZ/100);
                let nz4 = nz3;

                // 법선 벡터 (nx4, ny4, nz)와 광원의 백터 내적 계산
                // 광원 위치는 (0, 0, -1)
                let lx = 0;
                let ly = 0;
                let lz = -1;
                let light = nx4 * lx + ny4 * ly + nz4 * lz;

                if (light > 0) {
                    let color = Math.round(light * 255);

                    // x' = xz'/z, y' = yz'/z
                    let xp = Math.floor(x4 * ZZ1 / z4);
                    let yp = Math.floor(-y4 * ZZ1 / z4);

                    points.push([xp + ox, yp + oy, 255-color]);
                }
            }
        }

        bufCtx.beginPath();
        bufCtx.strokeStyle = "black";
        bufCtx.fillStyle = "black";
        bufCtx.fill();

        bufCtx.fillRect(0, 0, canvas.width, canvas.height);
        bufCtx.closePath();
        bufCtx.stroke();

        points.forEach(e => drawCircle(e[0], e[1], e[2], 1));

        thetaX = (thetaX + 2) % 629;
        thetaZ = (thetaZ + 2) % 629;
    }

    function OnDraw() {
        _draw();

        cvs.beginPath();
        cvs.clearRect(0, 0, canvas.width, canvas.height);
        cvs.drawImage(bufCanvas, 0, 0);

        console.log(">OnDraw()");
    }


    function onLoadPage() {
        InitCanvas();
        OnDraw();
        setInterval(OnDraw, 50);
    }

    window.onload = onLoadPage();
</script>
</body>
</html>

 

 

Posted by chobocho
Coding/JavsScript 삽질기2022. 1. 19. 01:08

유튜브에서 회전하는 도넛 영상을 보고, 회전하는 구를 그려 보았다.

Sphere

1. 난해하게 만든 전체 소스는 아래와 같다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sphere</title>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <style>
        canvas {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div align='center'>
    <canvas id="canvas"></canvas>
</div>
<script language="JavaScript">
    // Start: 2022.01.18
    // Update: 2022.01.19

    let cvs;
    let canvas;
    let bufCanvas;
    let bufCtx;
    let thetaX = 0;
    let thetaZ = 0;

    let SIN = [];
    let COS = [];

    function InitValue() {
        for (let i = 0; i < 628; i++) {
            SIN[i] = Math.sin(i / 100);
            COS[i] = Math.cos(i / 100);
        }
    }
    
    function InitCanvas() {
        height = window.innerHeight;
        width = window.innerWidth;

        console.log(">Width:", width);
        console.log(">Heigth:", height);

        canvas = document.getElementById("canvas");
        canvas.width = width;
        canvas.height = height;
        cvs = canvas.getContext("2d");

        bufCanvas = document.createElement("canvas");
        bufCanvas.width = canvas.width;
        bufCanvas.height = canvas.height;
        bufCtx = bufCanvas.getContext("2d");
    }

    function drawCircle(x, y, c, r) {
        bufCtx.beginPath();
        bufCtx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
        bufCtx.strokeStyle = "rgb(255, 255, 255)";
        bufCtx.arc(x, y, r, 0, Math.PI * 2);
        bufCtx.stroke();
        bufCtx.fill();
        bufCtx.closePath();
    }

    function _draw() {
        let maxSize = canvas.height < canvas.width ? canvas.height : canvas.width;
        let dimen = 8;
        let ox = canvas.width / 2;
        let oy = canvas.height / 2;
        let R1 = maxSize/20;
        let ZZ1 = maxSize * 1000 * 0.4 / R1;

        let points = [];

        for (let i = 0; i < 628; i += dimen) {
            let a = COS[i];
            let b = SIN[i];

            for (let j = 0; j < 628; j += dimen) {
                let c = COS[j];
                let d = SIN[j];
                let e = COS[thetaX];
                let f = SIN[thetaX];
                let g = COS[thetaZ];
                let h = SIN[thetaZ];

                let k = b * R1 * e - a * R1 * d * f;
                let x4 = a * R1 * c * g - k * h;
                let y4 = a * R1 * c * h + k * g;
                let z4 = ZZ1 / (1000 + b * R1 * f + a * R1 * d * e);
                let light = (b * f + a * d * e);

                if (light > 0) {
                    let color = Math.round(light * 255);
                    let xp = Math.floor(x4 * z4 + ox);
                    let yp = Math.floor(-y4 * z4 + oy);
                    points.push([xp, yp, 255-color]);
                }
            }
        }

        bufCtx.strokeStyle = "black";
        bufCtx.fillStyle = "black";
        bufCtx.fillRect(0, 0, canvas.width, canvas.height);
        points.forEach(e => drawCircle(e[0], e[1], e[2], 1));

        thetaX = (thetaX + 2) % 629;
        thetaZ = (thetaZ + 2) % 629;
    }

    function OnDraw() {
        let startTime = new Date();
        _draw();

        cvs.clearRect(0, 0, canvas.width, canvas.height);
        cvs.drawImage(bufCanvas, 0, 0);

        console.log("Elapsed time: " + (new Date() - startTime));
    }


    function onLoadPage() {
        InitValue();
        InitCanvas();
        OnDraw();
        setInterval(OnDraw, 50);
    }

    window.onload = onLoadPage();
</script>
</body>
</html>

 

 


1. HTML로 구를 그리기 위한 기본적인 뼈대를 작성한다.

아래 코드에서 _drawSphere()를 채워 나갑니다.

하기 HTML 코드는 좋은 예제가 아닙니다. HTML 관련은 인터넷에 있는 좋은 코드를 참고 하시기 바랍니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sphere</title>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <style>
        canvas {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div align='center'>
    <canvas id="canvas"></canvas>
</div>
<script language="JavaScript">
    let cvs;
    let canvas;
    let bufCanvas;
    let bufCtx;

    function InitCanvas() {
        height = window.innerHeight;
        width = window.innerWidth;

        console.log(">Width:", width);
        console.log(">Heigth:", height);

        canvas = document.getElementById("canvas");
        canvas.width = width;
        canvas.height = height;
        cvs = canvas.getContext("2d");

        bufCanvas = document.createElement("canvas");
        bufCanvas.width = canvas.width;
        bufCanvas.height = canvas.height;
        bufCtx = bufCanvas.getContext("2d");
    }

    function _drawSphere() {

    }

    function OnDraw() {
        let startTime = new Date();

        bufCtx.strokeStyle = "black";
        bufCtx.fillStyle = "black";
        bufCtx.fillRect(0, 0, canvas.width, canvas.height);

        _drawSphere();

        cvs.clearRect(0, 0, canvas.width, canvas.height);
        cvs.drawImage(bufCanvas, 0, 0);
        console.log("Elapsed time: " + (new Date() - startTime));
    }


    function onLoadPage() {
        InitCanvas();
        OnDraw();
        setInterval(OnDraw, 50);
    }

    window.onload = onLoadPage();
</script>
</body>
</html>

 

2. 원 그리기

원점을 기준으로 지름 r인 원은 아래 수식으로 표현 할 수 있습니다.

이때, x, y는 아래와 같이 구 할 수 있습니다.


원래 작성한 코드는 아래와 같다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sphere</title>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <style>
        canvas {
            height: 100%;
            width: 100%;
        }
    </style>
</head>
<body>
<div align='center'>
    <canvas id="canvas"></canvas>
</div>
<script language="JavaScript">
    // Start: 2022.01.16
    // Update: 2022.01.18

    let cvs;
    let canvas;
    let bufCanvas;
    let bufCtx;
    let thetaX = 0;
    let thetaZ = 0;

    function InitCanvas() {
        height = window.innerHeight;
        width = window.innerWidth;

        console.log(">Width:", width);
        console.log(">Heigth:", height);

        canvas = document.getElementById("canvas");
        canvas.width = width;
        canvas.height = height;
        cvs = canvas.getContext("2d");

        bufCanvas = document.createElement("canvas");
        bufCanvas.width = canvas.width;
        bufCanvas.height = canvas.height;
        bufCtx = bufCanvas.getContext("2d");
    }

    function drawCircle(x, y, c, r) {

        bufCtx.beginPath();
        bufCtx.fillStyle = "rgb(" + c + "," + c + "," + c + ")";
        bufCtx.strokeStyle = "rgb(255, 255, 255)";
        bufCtx.arc(x, y, r, 0, Math.PI * 2);
        bufCtx.stroke();
        bufCtx.fill();
        bufCtx.closePath();
    }

    function _draw() {
        let maxSize = canvas.height < canvas.width ? canvas.height : canvas.width;
        let dimen = 8;
        let ox = canvas.width / 2;
        let oy = canvas.height / 2;
        let R1 = maxSize/20;  // 원의 반지름

        // 카메라와 스크린의 거리를 z'라 하고, 그 투영되는 상을 x',y'
        // z:x = z':x'
        // z:y = z':y'
        // x' = xz'/z, y' = yz'/z
        // z' = z1
        // x', y' = xz1/z, yz1/z
        // z의 최대거리 z2 = 1000이라 하면
        // x' <= (height/2 * 0.8) (화면 중앙 위치, 마진 0.1)
        // x 의 최대 값은 R1 + R2
        // x' = Z1(R1+R2)/z2 = height * 0.4
        // Z1 = Z2 * height * 0.4 / (R1+R2)

        let ZZ2 = 1000;
        let ZZ1 = maxSize * ZZ2 * 0.4 / R1;

        let points = [];

        for (let i = 0; i < 628; i += dimen) {
            let x1 = Math.cos(i/100) * R1;
            let y1 = Math.sin(i/100) * R1;
            let nx1 = Math.cos(i/100);
            let ny1 = Math.sin(i/100);

            for (let j = 0; j < 628; j += dimen) {
                // Y축 회전
                let x2 = x1 * Math.cos(j/100);
                let y2 = y1;
                let z2 = x1 * Math.sin(j/100);

                let nx2 = nx1 * Math.cos(j/100);
                let ny2 = ny1;
                let nz2 = nx1 * Math.sin(j/100);

                // X축 회전
                let x3 = x2;
                let y3 = y2 * Math.cos(thetaX/100) - z2 * Math.sin(thetaX/100);
                let z3 = y2 * Math.sin(thetaX/100) + z2 * Math.cos(thetaX/100);

                let nx3 = nx2;
                let ny3 = ny2 * Math.cos(thetaX/100) - nz2 * Math.sin(thetaX/100);
                let nz3 = ny2 * Math.sin(thetaX/100) + nz2 * Math.cos(thetaX/100);

                // Z축 회전
                let x4 = x3 * Math.cos(thetaZ/100) - y3 * Math.sin(thetaZ/100);
                let y4 = x3 * Math.sin(thetaZ/100) + y3 * Math.cos(thetaZ/100);
                let z4 = ZZ2 + z3;

                let nx4 = nx3 * Math.cos(thetaZ/100) - ny3 * Math.sin(thetaZ/100);
                let ny4 = nx3 * Math.sin(thetaZ/100) + ny3 * Math.cos(thetaZ/100);
                let nz4 = nz3;

                // 법선 벡터 (nx4, ny4, nz)와 광원의 백터 내적 계산
                // 광원 위치는 (0, 0, -1)
                let lx = 0;
                let ly = 0;
                let lz = -1;
                let light = nx4 * lx + ny4 * ly + nz4 * lz;

                if (light > 0) {
                    let color = Math.round(light * 255);
                    
                    // x' = xz'/z, y' = yz'/z
                    let xp = Math.floor(x4 * ZZ1 / z4);
                    let yp = Math.floor(-y4 * ZZ1 / z4);

                    points.push([xp + ox, yp + oy, 255-color]);
                }
            }
        }

        bufCtx.strokeStyle = "black";
        bufCtx.fillStyle = "black";
        bufCtx.fillRect(0, 0, canvas.width, canvas.height);
        points.forEach(e => drawCircle(e[0], e[1], e[2], 1));

        thetaX = (thetaX + 2) % 629;
        thetaZ = (thetaZ + 2) % 629;
    }

    function OnDraw() {
        _draw();

        cvs.clearRect(0, 0, canvas.width, canvas.height);
        cvs.drawImage(bufCanvas, 0, 0);
    }


    function onLoadPage() {
        InitCanvas();
        OnDraw();
        setInterval(OnDraw, 50);
    }

    window.onload = onLoadPage();
</script>
</body>
</html>
Posted by chobocho
Coding/Java 삽질기2021. 10. 24. 18:08

TextView에서 한 줄에 표시되는 글자수를 계산 하는 코드

var textView: TextView = findViewById(R.id.textView)
val COL : Int = Math.round(textView.width / textView.paint.measureText("가나다라마.") * 6)

그런데 OnCreate에서 위 함수를 사용하면 0이 나온다.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.textviewer)
      
        val vto: ViewTreeObserver = textView.getViewTreeObserver()
        vto.addOnGlobalLayoutListener {

            if (getWidthCount < 1) {
                getWidthCount++

                val COL : Int = Math.round(textView.width / textView.paint.measureText("가나다라마.") * 6)
                Log.i(TAG, "getWidth:" + COL)
            }
        }
    }

이 경우 위와 같이, 코드를 추가해 주면 된다.

Posted by chobocho
Coding/Java 삽질기2021. 10. 17. 13:38

Unit test에서 Test sample 파일을 읽어서 테스트 하는 방법

1. test 폴더에 resources 폴더를 만들고 테스트 파일을 넣는다

2. 아래와 같이 코드를 작성한다.

    @Test
    public void encrypt() throws URISyntaxException {
        File file = new File(getClass().getResource("/1.txt").toURI());
        assert(file != null);
        URL unavailableURL = getClass().getResource("/unavilable.txt");
        assert(unavailableURL == null);
    }

Posted by chobocho
Coding/JavsScript 삽질기2021. 10. 16. 13:54
Coding/Tip2021. 10. 16. 13:52

오늘날짜 입력: Ctrl + ;

'Coding > Tip' 카테고리의 다른 글

[DOSBOX] 창 크기 조절 방법  (0) 2023.01.27
[Android studio] 사용 팁  (0) 2020.04.13
사무직을 위한 Git 활용 법  (0) 2018.10.27
Posted by chobocho
Coding/Python 삽질기2021. 6. 21. 23:46

기차표 예매를 위하여 줄을 섰을 때, 이들 중 생일이 같은 사람이 존재 할 확률은 얼마일까?

계산을 해보면, 23명 이상 일 때 부터 50%가 넘어가고, 57명이 넘어가면 99%가 넘어간다.

 

 

파이썬으로 짜보면 아래와 같다.

import matplotlib.pyplot as plt

prev = 1
result = [0]
for m in range(57):
    prev = prev * (365-m)/365
    result.append(1-prev)

x = [ n for n in range(len(result))]

plt.scatter(x, result)
plt.axvline(x=23, color='RED', linestyle='-', linewidth=0.2)
plt.axhline(y=0.5, color='RED', linestyle='-', linewidth=0.2)
plt.show()

Posted by chobocho
Coding/CPP 삽질기2021. 6. 8. 22:21

오픈 챗에서 누구나 다 해보는 "별 그리기" 문제를 물어 보길래, 한 번 짜봤다.

#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    char star[] = "*****";

    for (int i = 0; i < strlen(star); i++) {
         printf("%s\n", &star[strlen(star)-i-1]);
    }

    return 0;
}

 

chobocho@Chobocho-Mint:~/github/cpp_study/src/sandbox$ ./a.out
*
**
***
****
*****

'Coding > CPP 삽질기' 카테고리의 다른 글

[ChatGPT에게 묻다] Fast sqrt 함수  (0) 2023.02.26
Stack과 Heap  (0) 2021.02.25
[C] Binary search  (0) 2020.12.06
Posted by chobocho