山の位置をARで表示する技術ブログ：ロケーションARの基本

# はじめに
現実世界にデジタル情報を重ね合わせる技術、ロケーションAR。今回は、ユーザーの位置情報を基に山の位置をリアルタイムで表示する方法について説明します。この技術を使えば、観光や登山の際に周囲の山々を簡単に識別することができます。

# 使用技術とライブラリ
このプロジェクトでは、以下の技術とライブラリを使用します：
- **AFRAME**：3DおよびARコンテンツをウェブ上で作成するフレームワーク
- **AR.js**：ウェブベースのARライブラリ
- **Geolib**：地理座標の計算を簡単にするライブラリ
- **JavaScript**：クライアントサイドのスクリプティング
- **HTML**：ウェブページの構造を定義

# HTMLの基本構造
以下は、HTMLの基本構造です。AR.jsとAFRAMEを使用して、ユーザーのカメラビューに方角を示す矢印を配置します。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <title>AR Planet Locator</title>
  <link rel="stylesheet" href="./css/styles.css">
  <script src="https://aframe.io/releases/1.6.0/aframe.min.js"></script>
  <script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/geolib@3.3.4/lib/index.min.js"></script>
  <script src="./js/ar.js"></script>
  <style>
    body, html { margin: 0; overflow: hidden; }
  </style>
</head>
<body>
  <a-scene embedded arjs="sourceType: webcam;">
    <a-camera gps-camera rotation-reader id="camera"></a-camera>
    <!-- 方角の矢印を表示 -->
    <a-entity id="north-arrow" position="0 0 -10.5">
      <a-cone color="red" radius-bottom="0.5" height="2" position="0 1 0" rotation="0 0 0"></a-cone>
      <a-text value="北" scale="4 4 1" position="-0.5 2.8 0" rotation="0 0 0"></a-text>
    </a-entity>
  </a-scene>
</body>
</html>
```

# JavaScriptによる位置計算と表示
`ar.js`ファイルでは、ユーザーの現在位置と山の位置を基に、AR表示を行うための位置計算と描画を行います。

```javascript
AFRAME.registerComponent("rotation-reader", {
  tick: function () {
    const cameraRotation = this.el.object3D.rotation;
    // カメラの回転情報を利用した処理
  },
});

function calculatePosition(targetLatitude, targetLongitude, userLatitude, userLongitude) {
  const distance = 10; // 固定距離（メートル）
  const userPosition = { latitude: userLatitude, longitude: userLongitude };
  const targetPosition = { latitude: targetLatitude, longitude: targetLongitude };
  let bearing = geolib.getRhumbLineBearing(userPosition, targetPosition);
  bearing -= 90; // 方位が90度ずれているため修正
  const x = distance * Math.cos((bearing * Math.PI) / 180);
  const z = distance * Math.sin((bearing *Math.PI) / 180);
  return { x, y: 1, z, bearing };
}

function updateARPosition(userLatitude, userLongitude, mountains) {
  mountains.forEach((mountain) => {
    const { lat, lng, name } = mountain;
    const targetPosition = calculatePosition(lat, lng, userLatitude, userLongitude);
    const pointerEntity = document.createElement("a-entity");
    pointerEntity.setAttribute("position", `${targetPosition.x} ${targetPosition.y} ${targetPosition.z}`);
    const circleEntity = document.createElement("a-entity");
    circleEntity.setAttribute("geometry", "primitive: circle; radius: 0.1");
    circleEntity.setAttribute("material", "color: white");
    circleEntity.setAttribute("position", "0 1 0");
    const lineEntity = document.createElement("a-entity");
    lineEntity.setAttribute("line", `start: 0, 1, 0; end: 0, 3, -2; color: white; linewidth: 20`);
    const textEntity = document.createElement("a-text");
    textEntity.setAttribute("value", name);
    textEntity.setAttribute("color", "white");
    textEntity.setAttribute("position", "0 3.1 -2");
    textEntity.setAttribute("rotation", `0 ${-targetPosition.bearing - 90} 90`);
    textEntity.setAttribute("scale", "3 3 3");
    pointerEntity.appendChild(circleEntity);
    pointerEntity.appendChild(lineEntity);
    pointerEntity.appendChild(textEntity);
    document.querySelector("a-scene").appendChild(pointerEntity);
  });
}

// 初期処理としてupdateARPositionを呼び出す
document.addEventListener("DOMContentLoaded", () => {
  const userLatitude = 35.6895;  // モックデータ
  const userLongitude = 139.6917; // モックデータ
  const mountains = [
    { lat: 35.3606, lng: 138.7274, name: "Mt. Fuji" }, // モックデータ
    { lat: 36.2048, lng: 137.2529, name: "Mt. Yari" }   // モックデータ
  ];
  updateARPosition(userLatitude, userLongitude, mountains);
});
```

# 結論
ロケーションAR技術を活用すれば、ユーザーの位置情報を基に現実世界にデジタル情報を重ね合わせることが可能です。このブログでは、その基本的な実装方法を紹介しました。AR技術を用いることで、観光や登山の際に周囲の山々を簡単に識別でき、ユーザーに新しい体験を提供することができます。