VWorld의 지오코딩 API 사용 코드

VWorld에서 제공하는 지오코딩 OpenAPI는 하루에 최대 3만건까지 자유롭게 변환할 수 있습니다. 아래는 VWorld의 지오코딩 API를 사용하는 코드입니다.

async function geocoding(url) {
    const req = await fetch(url);
    return req.json();
}

async function doGeocoding(address) {
    const result = await geocoding("http://api.vworld.kr/req/address?service=address"
        + "&request=getcoord"
        + "&address=" + encodeURI(address) + "&type=road"
        + "&key=##09F585-13##-38##-##36-####6A0C####");

    console.log(result);
}

doGeocoding('서울시 성동구 아차산로7나길 18');

실행 결과는 JSON 형식으로 다음과 같이 콘솔에 표시됩니다.

VWorld의 지오코딩 API는 입력한 주소가 도로명 주소인지 지번 주소인지를 명확히 지정해줘야 합니다. 즉, 호출 URL에 type에 road와 parcel을 지정해야 하며 각각 도로명주소 및 지번주소를 의미합니다. 추후에는 이러한 주소에 대한 구분을 사람이 직접 구분해야 하는 번거러움이 없기를 기대합니다.

three.js의 scene 구성 요소들 확인하기

3차원에서는 다양한 3차원 객체가 Scene Graph 형태로 구성되어 있습니다. 렌더링하는 결과에 따라 그 형태가 매우 복잡하게 구성될 수 있는데.. Scene Graph의 구성 요소를 확인하기 위한 간단한 함수입니다.

dumpVec3(v3, precision = 3) {
    return `${v3.x.toFixed(precision)}, ${v3.y.toFixed(precision)}, ${v3.z.toFixed(precision)}`;
}

dumpObject(obj, lines = [], isLast = true, prefix = '') {
    const localPrefix = isLast ? '└─' : '├─';
    lines.push(`${prefix}${prefix ? localPrefix : ''}${obj.name || '*no-name*'} [${obj.type}]`);
    const dataPrefix = obj.children.length
        ? (isLast ? '  │ ' : '│ │ ')
        : (isLast ? '    ' : '│   ');
    lines.push(`${prefix}${dataPrefix} pos: ${this.dumpVec3(obj.position)}`);
    lines.push(`${prefix}${dataPrefix} rot: ${this.dumpVec3(obj.rotation)}`);
    lines.push(`${prefix}${dataPrefix} scl: ${this.dumpVec3(obj.scale)}`);
    const newPrefix = prefix + (isLast ? '  ' : '│ ');
    const lastNdx = obj.children.length - 1;
    obj.children.forEach((child, ndx) => {
        const isLast = ndx === lastNdx;
        this.dumpObject(child, lines, isLast, newPrefix);
    });
    return lines;
}

사용은 다음과 같습니다.

console.log(this.dumpObject(root).join('\n'));

결과 예는 다음과 같습니다.

*no-name* [Scene]
  │  pos: 0.000, 0.000, 0.000
  │  rot: 0.000, 0.000, 0.000
  │  scl: 1.000, 1.000, 1.000
  ├─*no-name* [DirectionalLight]
  │    pos: -250.000, 800.000, -850.000
  │    rot: 0.000, 0.000, 0.000
  │    scl: 1.000, 1.000, 1.000
  ├─*no-name* [Object3D]
  │    pos: -550.000, 40.000, -450.000
  │    rot: 0.000, 0.000, 0.000
  │    scl: 1.000, 1.000, 1.000

... 

  ├─*no-name* [Object3D]
  │ │  pos: 571.897, -76.040, -1163.608
  │ │  rot: 0.000, 0.000, 0.000
  │ │  scl: 1.000, 1.000, 1.000
  │ └─CAR_03_3 [Object3D]
  │   │  pos: 0.000, 33.000, 0.000
  │   │  rot: 0.000, 3.142, 0.000
  │   │  scl: 1.500, 1.500, 1.500
  │   └─CAR_03_3_World_ap_0 [Mesh]
  │        pos: 0.000, 0.000, 0.000
  │        rot: 0.000, 0.000, 0.000
  │        scl: 1.000, 1.000, 1.000
  └─*no-name* [Line]
       pos: 0.000, -621.000, 0.000
       rot: 0.000, 0.000, 0.000
       scl: 100.000, 100.000, 100.000

matter.js를 이용한 강체 시뮬레이션

matter.js 라이브러리를 이용하여 구현하고자 하는 결과는 아래와 같습니다.

먼저 HTML 코드입니다.

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="style_matter.js.css">
    <script src="decomp.js"></script>
    <script src="pathseg.js"></script>
    <script src="matter.0.16.1.js"></script>
    <script src="app_matter.js.js" defer></script>
</head>
<body>
    <div></div>
</body>
</html> 

지형은 SVG 데이터를 통해 좌표를 뽑아오는데 이를 위해 matter.js 이외에도 decomp.js와 pathseg.js 라이브러리가 필요합니다. div 요소에 강체 시뮬레이션의 결과가 표시됩니다. 다음은 CSS입니다.

* {
    outline: none;
    padding: 0;
    margin: 0;
}
    
body {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100%;
    height: 100vh;
}

div 요소를 화면 중심에 놓기 위한 것이 전부입니다. 이제 js 코드를 살펴보겠습니다.

먼저 아래의 코드로 기본 코드를 작성합니다.

const engine = Matter.Engine.create();
const world = engine.world;

const render = Matter.Render.create({
    element: document.querySelector("div"),
    engine: engine,
    options: {
        width: 800,
        height: 600,
        wireframes: false,
        background: 'black'
    }
});

Matter.Render.run(render);

const runner = Matter.Runner.create();
Matter.Runner.run(runner, engine);

다음으로 지형과 지형 속에 사각형 물체를 구성하는 코드입니다.

fetch("./terrain.svg")
    .then((response) => { return response.text(); })
    .then((raw) => { return (new window.DOMParser()).parseFromString(raw, "image/svg+xml"); })
    .then(function(root) {
        const paths = Array.prototype.slice.call(root.querySelectorAll('path'));
        const vertices = paths.map((path) => { return Matter.Svg.pathToVertices(path, 30); });
        const terrain = Matter.Bodies.fromVertices(400, 350, vertices, {
            isStatic: true,
            render: {
                fillStyle: '#2c3e50',
                strokeStyle: '#2c3e50',
                lineWidth: 1,
            }
        }, true);

        Matter.World.add(world, terrain);

        const bodyOptions = {
            frictionAir: 0.1, 
            friction: 0.5,
            restitution: 0.1
        };
        
        Matter.World.add(world, Matter.Composites.stack(100, 200, 40, 10, 15, 15, (x, y) => {
            if (Matter.Query.point([terrain], { x: x, y: y }).length === 0) {
                return Matter.Bodies.polygon(x, y, 4, 10, bodyOptions);
            }
        }));
    }
);

끝으로 마우스를 통해 사각형 객체를 드레그하여 옮길 수 있도록 합니다.

const mouse = Matter.Mouse.create(render.canvas),
mouseConstraint = Matter.MouseConstraint.create(engine, {
    mouse: mouse,
    constraint: {
        stiffness: 0.2,
        render: {
            visible: false
        }
    }
});

Matter.World.add(world, mouseConstraint);

matter.js는 매우 정교한 강체 시뮬레이션에는 적합하지 않으나 시각적인 면에서 다양한 물리 효과를 2차원에서 폭넓게 응용할 수 있다는 점이 매우 큰 장점입니다.

아래는 필요한 코드와 데이터 전체를 다운로드 받을 수 있는 링크입니다.

Javascript 객체(object)의 키(key)와 값(value)을 배열로 얻기

만약 다음과 같은 자바스크립트 객체가 있다고 할 때..

const obj = {
  a: 'Dip2K',
  b: 30,
  c: true,
  d: {}
};

obj 객체를 구성하는 전체 키를 배열로 얻는 코드는 다음과 같습니다.

console.log(Object.keys(obj)); 
// Array ["a", "b", "c", "d"]

다시 obj 객체를 구성하는 전체 값을 배열로 얻는 코드는 다음과 같구요.

console.log(Object.values(obj)); 
// Array ["Dip2K", 30, true, Object {  }]

배열에 대해서 각 구성 항목을 참조하는 코드는 다음과 같습니다.

for(i of Object.values(obj)) {
    console.log(i);
}

/* 
"Dip2K"
30
true
Object {  }
*/