UP | HOME

2.1 マウス操作によるカメラ操作及び指定位置の緯度・経度の取得

マウス操作でカメラの操作や指定した位置の緯度・経度を取得する方法を説明します。

1. サンプルコード

マウス操作でカメラの操作や指定した位置の緯度・経度を取得する CameraControlWithMouse.html 及び2つのJavascriptファイルのサンプルコードです。JavaScriptファイルは、マウスの入力検知を行う CheckInputKeyAndMouse.js とカメラ操作及び指定位置の緯度・経度を取得する CameraControlWithMouse.js の2種類です。 このサンプルコードでは、マウスのホイール操作で、カメラの前進・後進を操作し、Shift+左ドラッグでカメラの回転を操作し、Alt+ドラッグでカメラの高度を操作します。また、クリックした場所の緯度・経度・高度を画面下部に表示します。

1.1. CameraControlWithMouse.html

 1: <!DOCTYPE html>
 2: <html>
 3:     <head>
 4:         <meta charset="utf-8">
 5:         <title>CameraControlWithMouseSample</title>
 6:         <script src="https://resource.mapray.com/mapray-js/v0.9.4/mapray.min.js"></script>
 7:         <link rel="stylesheet" href="https://resource.mapray.com/styles/v1/mapray.css">
 8:         <script src="CameraControlWithMouse.js"></script>
 9:         <script src="CheckInputKeyAndMouse.js"></script>
10:         <style>
11:             html, body {
12:                 height: 100%;
13:                 margin: 0;
14:                 background-color: #E0E0E0;
15:             }
16: 
17:             p{
18:                 font-size:13px;
19:             }
20: 
21:             div#mapray-container {
22:                 display: flex;
23:                 position: relative;
24:                 height: calc(100% - 34px);
25:             }
26: 
27:             div#LongitudeStringBox {
28:                 display: flex;
29:                 background-color: #E0E0E0;
30:                 height: 32px;
31:                 width: 160px;
32:                 float: left;
33:                 border: inset 1px #000000;
34:                 align-items: center;
35:             }
36: 
37:             div#LatitudeStringBox {
38:                 display: flex;
39:                 background-color: #E0E0E0;
40:                 height: 32px;
41:                 width: 160px;
42:                 float: left;
43:                 border: inset 1px #000000;
44:                 align-items: center;
45:             }
46: 
47:             div#HeightStringBox {
48:                 display: flex;
49:                 background-color: #E0E0E0;
50:                 height: 32px;
51:                 width: 160px;
52:                 float: left;
53:                 border: inset 1px #000000;
54:                 align-items: center;
55:             }
56:         </style>
57:     </head>
58: 
59:     <body onload="new CameraControl('mapray-container');">
60:         <div id="mapray-container"></div>
61: 
62:         <div id="LongitudeStringBox">
63:             <p style="margin-left:5px;">Longitude:</p>
64:             <p id="LongitudeValue">0</p>
65:         </div>
66: 
67:         <div id="LatitudeStringBox">
68:             <p style="margin-left:5px;">Latitude:</p>
69:             <p id="LatitudeValue">0</p>
70:         </div>
71: 
72:         <div id="HeightStringBox">
73:             <p style="margin-left:5px;">Height:</p>
74:             <p id="HeightValue">0</p>
75:         </div>
76:     </body>
77: </html>

1.2. CheckInputKeyAndMouse.js

  1: class CheckInput {
  2: 
  3:     constructor(viewer) {
  4:         // マウス、キーのイベントを設定
  5:         var element = viewer.canvas_element;
  6:         var self = this;
  7: 
  8:         this.is_Mouse_Click = false;                // マウスがクリックされたか
  9:         this.mouse_Click_Pos = [0, 0];              // クリックされたマウスの位置
 10:         this.is_Forward = false;                    // 前進するか
 11:         this.is_Backward = false;                   // 後退するか
 12:         this.is_Camera_Turn = false;                // カメラが回るか
 13:         this.is_Camera_Height_Move = false;         // 高度を更新するか
 14:         this.mouse_Move_Pos = [0, 0];               // 左マウスボタンドラッグ時のマウス位置
 15:         this.mouse_Move_Pos_Old = [0, 0];           // 左マウスボタンドラッグ時の1フレーム前の位置
 16:         this.mouse_Right_Move_Pos = [0, 0];         // 右マウスボタンドラッグ時のマウス位置
 17:         this.mouse_Right_Move_Pos_Old = [0, 0];     // 右マウスボタンドラッグ時の1フレーム前の位置
 18: 
 19:         // イベントをセット
 20:         window.addEventListener( "blur", function ( event ) { self._onBlur( event ); }, { passive: false } );
 21:         element.addEventListener( "mousedown", function ( event ) { self._onMouseDown( event ); }, { passive: false } );
 22:         document.addEventListener( "mousemove", function ( event ) { self._onMouseMove( event ); }, { passive: false } );
 23:         document.addEventListener( "mouseup", function ( event ) { self._onMouseUp( event ); }, { passive: false } );
 24:         document.addEventListener( "wheel", function ( event ) { self._onMouseScroll( event ); }, { passive: false } );
 25: 
 26:         // FireFoxのマウスホイールイベント
 27:         window.addEventListener( "DOMMouseScroll", function ( event ) { self._onMouseScroll_FireFox( event ); }, { passive: false } );
 28:     }
 29: 
 30:     IsMouseClick(mousePos) {
 31:         if(this.is_Mouse_Click){
 32:             mousePos[0] = this.mouse_Click_Pos[0];
 33:             mousePos[1] = this.mouse_Click_Pos[1];
 34:             return true;
 35:         } else {
 36:             return false;
 37:         }
 38:     }
 39: 
 40:     IsForward() {
 41:         return this.is_Forward;
 42:     }
 43: 
 44:     IsBackward() {
 45:         return this.is_Backward;
 46:     }
 47: 
 48:     IsCameraTurn(dragVec) {
 49:         if (this.is_Camera_Turn == true) {
 50:             // 前フレームからの移動量を計算
 51:             dragVec[0] = this.mouse_Move_Pos[0] - this.mouse_Move_Pos_Old[0];
 52:             dragVec[1] = this.mouse_Move_Pos[1] - this.mouse_Move_Pos_Old[1];
 53:             return true;
 54:         } else {
 55:             return false;
 56:         }
 57:     }
 58: 
 59:     IsCameraHeightMove(dragVec) {
 60:         if (this.is_Camera_Height_Move == true) {
 61:             // 前フレームからの移動量を計算
 62:             dragVec[0] = this.mouse_Right_Move_Pos[0] - this.mouse_Right_Move_Pos_Old[0];
 63:             dragVec[1] = this.mouse_Right_Move_Pos[1] - this.mouse_Right_Move_Pos_Old[1];
 64:             return true;
 65:         } else {
 66:             return false;
 67:         }
 68:     }
 69: 
 70:     _onMouseDown(event) {
 71:         event.preventDefault();
 72: 
 73:         if (event.button == 0 /* 左ボタン */) {
 74:             if (event.shiftKey) {
 75:                 // カメラ回転ドラッグ開始
 76:                 this.is_Camera_Turn = true;
 77:                 this.mouse_Move_Pos[0] = event.clientX;
 78:                 this.mouse_Move_Pos[1] = event.clientY;
 79:                 this.mouse_Move_Pos_Old[0] = event.clientX;
 80:                 this.mouse_Move_Pos_Old[1] = event.clientY;
 81:             }
 82: 
 83:             if(event.altKey){
 84:                 // カメラ移動ドラッグ開始
 85:                 this.is_Camera_Height_Move = true;
 86:                 this.mouse_Right_Move_Pos[0] = event.clientX;
 87:                 this.mouse_Right_Move_Pos[1] = event.clientY;
 88:                 this.mouse_Right_Move_Pos_Old[0] = event.clientX;
 89:                 this.mouse_Right_Move_Pos_Old[1] = event.clientY;
 90:             }
 91: 
 92:             if (event.shiftKey == false & event.altKey == false) {
 93:                 // クリックされた
 94:                 this.is_Mouse_Click = true;
 95:                 this.mouse_Click_Pos[0] = event.clientX;
 96:                 this.mouse_Click_Pos[1] = event.clientY;
 97:             }
 98:         }
 99:     }
100: 
101:     _onMouseMove(event) {
102:         event.preventDefault();
103: 
104:         if (this.is_Camera_Turn == true) {
105:             // カメラ回転ドラッグ中
106:             this.mouse_Move_Pos_Old[0] = this.mouse_Move_Pos[0];
107:             this.mouse_Move_Pos_Old[1] = this.mouse_Move_Pos[1];
108:             this.mouse_Move_Pos[0] = event.clientX;
109:             this.mouse_Move_Pos[1] = event.clientY;
110:         }
111: 
112:         if (this.is_Camera_Height_Move == true) {
113:             // カメラ移動ドラッグ中
114:             this.mouse_Right_Move_Pos_Old[0] = this.mouse_Right_Move_Pos[0];
115:             this.mouse_Right_Move_Pos_Old[1] = this.mouse_Right_Move_Pos[1];
116:             this.mouse_Right_Move_Pos[0] = event.clientX;
117:             this.mouse_Right_Move_Pos[1] = event.clientY;
118:         }
119:     }
120: 
121:     _onMouseUp(event) {
122:         event.preventDefault();
123: 
124:         if (event.button == 0 /* 左ボタン */) {
125:             // クリック、カメラ回転終了
126:             this.is_Mouse_Click = false;
127:             this.is_Camera_Turn = false;
128:             this.mouse_Click_Pos[0] = 0;
129:             this.mouse_Click_Pos[1] = 0;
130:             this.mouse_Move_Pos[0] = 0;
131:             this.mouse_Move_Pos[1] = 0;
132: 
133:             // カメラ移動終了
134:             this.is_Camera_Height_Move = false;
135:             this.mouse_Right_Move_Pos[0] = 0;
136:             this.mouse_Right_Move_Pos[1] = 0;
137:         }
138:     }
139: 
140:     _onBlur(event) {
141:         event.preventDefault();
142: 
143:         // フォーカスを失った
144:         this.is_Mouse_Click = false;
145:         this.is_Forward = false;
146:         this.is_Backward = false;
147:         this.is_Camera_Turn = false;
148:         this.is_Camera_Height_Move = false;
149:     }
150: 
151:     _onMouseScroll(event) {
152:         event.preventDefault();
153: 
154:         // chromeのホイール移動量検出
155:         if ( event.deltaY < 0) {
156:             this.is_Forward = true;
157:         }else{
158:             this.is_Backward = true;
159:         }
160:     }
161: 
162:     _onMouseScroll_FireFox(event) {
163:         event.preventDefault();
164: 
165:         // FireFoxのホイール移動量検出
166:         if (event.detail < 0) {
167:             this.is_Forward = true;
168:         }else{
169:             this.is_Backward = true;
170:         }
171:     }
172: 
173:     endFrame() {
174:         // フレーム終了時
175:         this.is_Forward = false;
176:         this.is_Backward = false;
177:     }
178: 
179: }

1.3. CameraControlWithMouse.js

  1: var GeoMath = mapray.GeoMath;
  2: 
  3: class CameraControl extends mapray.RenderCallback{
  4: 
  5:     constructor(container) {
  6:         super();
  7: 
  8:         // Access Tokenを設定
  9:         var accessToken = "<your access token here>";
 10: 
 11:         // Viewerを作成する
 12:         new mapray.Viewer(container, {
 13:             render_callback: this,
 14:             image_provider: this.createImageProvider(),
 15:             dem_provider: new mapray.CloudDemProvider(accessToken)
 16:         });
 17: 
 18:         // 球面座標系(経度、緯度、高度)で視点の初期値を設定。座標は富士山から7kmほど南西の場所
 19:         this.camera_Pos = { longitude: 138.668035, latitude: 35.290262, height: 5500.0 };
 20:         this.camera_Vec = [0, 0, 0];                // カメラの前進後退方向
 21:         this.camera_Turn_Angle = 145;               // ターン角度
 22:         this.camera_Pitch = 20;                     // 仰俯角
 23:         this.camera_Move_Correction = 30;           // 前進後退の補正値
 24:         this.camera_Turn_Correction = 0.1;          // ターン、仰俯角の補正値
 25:         this.camera_Height_Correction = 0.5;        // 高度更新の補正値
 26: 
 27:         // 入力検知クラス
 28:         this.input_Checker = new CheckInput(this.viewer);
 29: 
 30:         this.SetCamera();
 31:     }
 32: 
 33:     // フレーム毎に呼ばれるメソッド
 34:     onUpdateFrame(delta_time)  // override
 35:     {
 36:         // カメラ回転
 37:         var turn_Drag_Vec = [0, 0];
 38:         if (this.input_Checker.IsCameraTurn(turn_Drag_Vec)) {
 39:             this.TurnCamera(turn_Drag_Vec);
 40:         }
 41: 
 42:         // カメラの高度変更
 43:         var height_Move_Drag_Vec = [0, 0];
 44:         if (this.input_Checker.IsCameraHeightMove(height_Move_Drag_Vec)) {
 45:             this.UpdateCameraHeight(height_Move_Drag_Vec);
 46:         }
 47: 
 48:         // カメラ前進
 49:         if (this.input_Checker.IsForward()) {
 50:             this.ForwardCameraPos();
 51:         }
 52: 
 53:         // カメラ後退
 54:         if (this.input_Checker.IsBackward()) {
 55:             this.BackwardCameraPos();
 56:         }
 57: 
 58:         this.SetCamera();
 59: 
 60:         var click_Pos = [0, 0];
 61: 
 62:         // 緯度経度高度表示
 63:         if (this.input_Checker.IsMouseClick(click_Pos)) {
 64:             this.SetClickPosLongitudeAndLatitudeAndHeight(click_Pos);
 65:         }
 66: 
 67:         this.input_Checker.endFrame();
 68:     }
 69: 
 70:     // 画像プロバイダを生成
 71:     createImageProvider() {
 72:         return new mapray.StandardImageProvider("https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/", ".jpg", 256, 2, 18);
 73:     }
 74: 
 75:     SetCamera() {
 76:         // カメラ位置の設定
 77: 
 78:         // 球面座標から地心直交座標へ変換
 79:         var camera_geoPoint = new mapray.GeoPoint( this.camera_Pos.longitude, this.camera_Pos.latitude, this.camera_Pos.height );
 80:         var camera_Pos_Gocs = camera_geoPoint.getMlocsToGocsMatrix( GeoMath.createMatrix() );
 81: 
 82:         var camera_End_Pos_Mat = GeoMath.createMatrix();
 83:         GeoMath.setIdentity(camera_End_Pos_Mat);
 84: 
 85:         // カメラの位置をY軸方向に移動させる
 86:         camera_End_Pos_Mat[13] = -1;
 87: 
 88:         // z軸でcamera_Turn_Angle分回転させる回転行列を求める
 89:         var turn_Mat = GeoMath.rotation_matrix([0, 0, 1], this.camera_Turn_Angle, GeoMath.createMatrix());
 90: 
 91:         // x軸でcamera_Pitch分回転させる回転行列を求める
 92:         var pitch_Mat = GeoMath.rotation_matrix([1, 0, 0], this.camera_Pitch, GeoMath.createMatrix());
 93: 
 94:         // カメラの位置にX軸の回転行列をかける
 95:         GeoMath.mul_AA(pitch_Mat, camera_End_Pos_Mat, camera_End_Pos_Mat);
 96: 
 97:         // カメラの位置にZ軸の回転行列をかける
 98:         GeoMath.mul_AA(turn_Mat, camera_End_Pos_Mat, camera_End_Pos_Mat);
 99: 
100:         // 視線方向を定義
101:         var cam_Start_Pos = GeoMath.createVector3([0, 0, 0]);
102:         var camera_End_Pos = GeoMath.createVector3([camera_End_Pos_Mat[12], camera_End_Pos_Mat[13], camera_End_Pos_Mat[14]]);
103: 
104:         // 視点、注視点ベクトルとZ軸で外積をして垂直な軸を求める
105:         var tmp_closs_vec = GeoMath.cross3(camera_End_Pos, GeoMath.createVector3([0, 0, -1]), GeoMath.createVector3());
106:         GeoMath.normalize3(tmp_closs_vec, tmp_closs_vec);
107: 
108:         // 視点、注視点ベクトルと垂直な軸で外積をしてアップベクトルを求める
109:         var cam_Up = GeoMath.cross3(camera_End_Pos, tmp_closs_vec, GeoMath.createVector3());
110: 
111:         // ビュー変換行列を作成
112:         var view_To_Home = GeoMath.createMatrix();
113:         GeoMath.lookat_matrix(cam_Start_Pos, camera_End_Pos, cam_Up, view_To_Home);
114: 
115:         // カメラの位置と視線方向からカメラの姿勢を変更
116:         var view_To_Gocs = this.viewer.camera.view_to_gocs;
117:         GeoMath.mul_AA(camera_Pos_Gocs, view_To_Home, view_To_Gocs);
118: 
119:         // カメラの視線方向を取得
120:         this.camera_Vec = [view_To_Gocs[8], view_To_Gocs[9], view_To_Gocs[10]];
121: 
122:         // カメラのnear、farの設定
123:         this.viewer.camera.near = 30;
124:         this.viewer.camera.far = 500000;
125:     }
126: 
127:     SetClickPosLongitudeAndLatitudeAndHeight(clickPos) {
128:         // キャンバス座標のレイを取得
129:         var ray = this.viewer.camera.getCanvasRay(clickPos, new mapray.Ray());
130: 
131:         // レイと地表の交点を求める
132:         var clossPoint = this.viewer.getRayIntersection(ray);
133: 
134:         if (clossPoint != null) {
135:             // 交点を球面座標系に変換する
136:             var closs_geoPoint = new mapray.GeoPoint();
137:             closs_geoPoint.setFromGocs( clossPoint );
138: 
139:             // UIを更新する
140:             document.getElementById( "LongitudeValue" ).innerText = closs_geoPoint.longitude.toFixed(6);
141:             document.getElementById( "LatitudeValue" ).innerText = closs_geoPoint.latitude.toFixed(6);
142:             document.getElementById( "HeightValue" ).innerText = closs_geoPoint.height.toFixed(6);
143:         }
144:     }
145: 
146:     ForwardCameraPos() {
147:         // 球面座標から地心直交座標へ変換
148:         var camera_geoPoint = new mapray.GeoPoint( this.camera_Pos.longitude, this.camera_Pos.latitude, this.camera_Pos.height );
149:         var camera_Pos_Gocs = camera_geoPoint.getMlocsToGocsMatrix( GeoMath.createMatrix() );
150: 
151:         // 地心直交座標の平行移動成分を変更
152:         camera_Pos_Gocs[12] -= this.camera_Vec[0] * this.camera_Move_Correction;
153:         camera_Pos_Gocs[13] -= this.camera_Vec[1] * this.camera_Move_Correction;
154:         camera_Pos_Gocs[14] -= this.camera_Vec[2] * this.camera_Move_Correction;
155: 
156:         // 地心直交座標を球面座標に変換する
157:         var next_camera_geoPoint = new mapray.GeoPoint();
158:         next_camera_geoPoint.setFromGocs( [camera_Pos_Gocs[12], camera_Pos_Gocs[13], camera_Pos_Gocs[14]] );
159: 
160:         this.camera_Pos.longitude = next_camera_geoPoint.longitude;
161:         this.camera_Pos.latitude = next_camera_geoPoint.latitude;
162:         this.camera_Pos.height = next_camera_geoPoint.height;
163:     }
164: 
165:     BackwardCameraPos() {
166:         // 球面座標から地心直交座標へ変換
167:         var camera_geoPoint = new mapray.GeoPoint( this.camera_Pos.longitude, this.camera_Pos.latitude, this.camera_Pos.height );
168:         var camera_Pos_Gocs = camera_geoPoint.getMlocsToGocsMatrix( GeoMath.createMatrix() );
169: 
170:         // 地心直交座標の平行移動成分を変更
171:         camera_Pos_Gocs[12] += this.camera_Vec[0] * this.camera_Move_Correction;
172:         camera_Pos_Gocs[13] += this.camera_Vec[1] * this.camera_Move_Correction;
173:         camera_Pos_Gocs[14] += this.camera_Vec[2] * this.camera_Move_Correction;
174: 
175:         // 地心直交座標を球面座標に変換する
176:         var next_camera_geoPoint = new mapray.GeoPoint();
177:         next_camera_geoPoint.setFromGocs( [camera_Pos_Gocs[12], camera_Pos_Gocs[13], camera_Pos_Gocs[14]] );
178: 
179:         this.camera_Pos.longitude = next_camera_geoPoint.longitude;
180:         this.camera_Pos.latitude = next_camera_geoPoint.latitude;
181:         this.camera_Pos.height = next_camera_geoPoint.height;
182:     }
183: 
184:     TurnCamera(drag_Vec) {
185:         // ターン、仰俯角の角度の更新量決定
186:         var add_Turn_Angle = drag_Vec[0] * this.camera_Turn_Correction;
187:         var add_Pitch = drag_Vec[1] * this.camera_Turn_Correction;
188: 
189:         // 更新量が少なかったら0にする
190:         if (add_Turn_Angle > -0.3 & add_Turn_Angle < 0.3) {
191:             add_Turn_Angle = 0;
192:         }
193: 
194:         if (add_Pitch > -0.3 & add_Pitch < 0.3) {
195:             add_Pitch = 0;
196:         }
197: 
198:         // ターン、仰俯角の角度更新
199:         this.camera_Turn_Angle -= add_Turn_Angle;
200:         this.camera_Pitch += add_Pitch;
201:     }
202: 
203:     UpdateCameraHeight(drag_Vec) {
204:         // 高度の変更量決定
205:         var add_Height = drag_Vec[1] * this.camera_Height_Correction;
206: 
207:         // 値が小さい場合0にする
208:         if (add_Height > -1 & add_Height < 1) {
209:             add_Height = 0;
210:         }
211: 
212:         // カメラ座標の高度を更新する
213:         this.camera_Pos.height -= add_Height;
214:     }
215: 
216: }

2. htmlのサンプルコードの詳細

htmlのサンプルコードの詳細を以下で解説します。

2.1. htmlの文字コード設定

4行目でhtmlの文字コードを設定します。このサンプルコードでは、utf-8を設定します。

4: <meta charset="utf-8">

2.2. タイトルの設定

5行目でタイトルを設定します。このサンプルコードでは、CameraControlWithMouseSampleを設定します。

5: <title>CameraControlWithMouseSample</title>

2.3. JavaScriptファイルのパス設定

6~9行目で参照するJavaScript及びスタイルシートのパスを設定します。このサンプルコードでは、maprayのJavaScriptファイル、スタイルシート、カメラを操作するJavaScriptファイル( CameraControlWithMouse.js )、マウスの入力を検知するJavaScriptファイル( CheckInputKeyAndMouse.js )を設定します。

6: <script src="https://resource.mapray.com/mapray-js/v0.9.4/mapray.min.js"></script>
7: <link rel="stylesheet" href="https://resource.mapray.com/styles/v1/mapray.css">
8: <script src="CameraControlWithMouse.js"></script>
9: <script src="CheckInputKeyAndMouse.js"></script>

2.4. スタイルの設定

10~56行目で表示する要素のスタイルを設定します。このサンプルコードでは、下記のスタイルを設定します。

  • html
  • body
  • p
  • div#mapray-container(地図表示部分)
  • div#LongitudeStringBox(経度表示部分)
  • div#LatitudeStringBox(緯度表示部分)
  • div#HeightStringBox(高度表示部分)
10: <style>
11:     html, body {
12:         height: 100%;
13:         margin: 0;
14:         background-color: #E0E0E0;
15:     }
16: 
17:     p{
18:         font-size:13px;
19:     }
20: 
21:     div#mapray-container {
22:         display: flex;
23:         position: relative;
24:         height: calc(100% - 34px);
25:     }
26: 
27:     div#LongitudeStringBox {
28:         display: flex;
29:         background-color: #E0E0E0;
30:         height: 32px;
31:         width: 160px;
32:         float: left;
33:         border: inset 1px #000000;
34:         align-items: center;
35:     }
36: 
37:     div#LatitudeStringBox {
38:         display: flex;
39:         background-color: #E0E0E0;
40:         height: 32px;
41:         width: 160px;
42:         float: left;
43:         border: inset 1px #000000;
44:         align-items: center;
45:     }
46: 
47:     div#HeightStringBox {
48:         display: flex;
49:         background-color: #E0E0E0;
50:         height: 32px;
51:         width: 160px;
52:         float: left;
53:         border: inset 1px #000000;
54:         align-items: center;
55:     }
56: </style>

2.5. loadイベントの処理

画面を表示する時に、カメラを操作するクラスを生成します。そのため、59行目でページの読み込み時に、地図表示部分のブロックのidからカメラを操作するクラスのインスタンスを生成します。 カメラを操作するはJavaScriptのサンプルコードの詳細で説明します。

59: <body onload="new CameraControl('mapray-container');">

2.6. 地図表示部分の指定

60行目で地図表示部分のブロックを記述します。 詳細はヘルプページ『緯度経度によるカメラ位置の指定』を参照してください。

60: <div id="mapray-container"></div>

2.7. クリック位置の緯度・経度・高度表示のUI

62~75行目で緯度・経度・高度を表示するブロックを記述します。それぞれのブロックの中には、該当する数値を表示する領域を用意します。

62: <div id="LongitudeStringBox">
63:     <p style="margin-left:5px;">Longitude:</p>
64:     <p id="LongitudeValue">0</p>
65: </div>
66: 
67: <div id="LatitudeStringBox">
68:     <p style="margin-left:5px;">Latitude:</p>
69:     <p id="LatitudeValue">0</p>
70: </div>
71: 
72: <div id="HeightStringBox">
73:     <p style="margin-left:5px;">Height:</p>
74:     <p id="HeightValue">0</p>
75: </div>

3. JavaScriptのサンプルコードの詳細(マウスの入力検知)

マウスの入力を検知するJavaScriptのサンプルコードの詳細を以下で解説します。

3.1. クラス

1~179行目で、マウスの入力を検知するクラスを定義します。クラス内の各メソッドの詳細は以降で解説します。

class CheckInput {

  //中略

}

3.2. コンストラクタ

3~28行目がマウスの入力を検知するクラスのコンストラクタです。 まず、マウスの入力検知に関する初期値を下記のように設定します。

  • クリックしたかどうか ⇒ false - クリックした画面の位置 ⇒ 全て0
  • 前進中かどうか ⇒ false - 後進中かどうか ⇒ false
  • 回転中かどうか ⇒ false - 高度変更中かどうか ⇒ false
  • 回転時のマウス位置 ⇒ 全て0
  • 回転時の1フレーム前のマウス位置 ⇒ 全て0
  • 高度変更時のマウス位置 ⇒ 全て0
  • 高度変更時の1フレーム前のマウス位置 ⇒ 全て0

そして、マウスのイベントとして下記の内容を設定します。

  • フォーカスが外れた時のイベント(20行目)
  • マウスのボタンが押された時のイベント(21行目)
  • マウスが移動した時のイベント(22行目)
  • マウスのボタンが離された時のイベント(23行目)
  • マウスホイールが動いた時のイベント(24行目)
  • FireFox用のマウスホイールが動いた時のイベント(27行目)
 3: constructor(viewer) {
 4:     // マウス、キーのイベントを設定
 5:     var element = viewer.canvas_element;
 6:     var self = this;
 7: 
 8:     this.is_Mouse_Click = false;                // マウスがクリックされたか
 9:     this.mouse_Click_Pos = [0, 0];              // クリックされたマウスの位置
10:     this.is_Forward = false;                    // 前進するか
11:     this.is_Backward = false;                   // 後退するか
12:     this.is_Camera_Turn = false;                // カメラが回るか
13:     this.is_Camera_Height_Move = false;         // 高度を更新するか
14:     this.mouse_Move_Pos = [0, 0];               // 左マウスボタンドラッグ時のマウス位置
15:     this.mouse_Move_Pos_Old = [0, 0];           // 左マウスボタンドラッグ時の1フレーム前の位置
16:     this.mouse_Right_Move_Pos = [0, 0];         // 右マウスボタンドラッグ時のマウス位置
17:     this.mouse_Right_Move_Pos_Old = [0, 0];     // 右マウスボタンドラッグ時の1フレーム前の位置
18: 
19:     // イベントをセット
20:     window.addEventListener( "blur", function ( event ) { self._onBlur( event ); }, { passive: false } );
21:     element.addEventListener( "mousedown", function ( event ) { self._onMouseDown( event ); }, { passive: false } );
22:     document.addEventListener( "mousemove", function ( event ) { self._onMouseMove( event ); }, { passive: false } );
23:     document.addEventListener( "mouseup", function ( event ) { self._onMouseUp( event ); }, { passive: false } );
24:     document.addEventListener( "wheel", function ( event ) { self._onMouseScroll( event ); }, { passive: false } );
25: 
26:     // FireFoxのマウスホイールイベント
27:     window.addEventListener( "DOMMouseScroll", function ( event ) { self._onMouseScroll_FireFox( event ); }, { passive: false } );
28: }

3.3. クリック状態の取得

30~38行目がクリック状態の取得メソッドです。このメソッドはクリックしたかどうかを返し、クリックされている場合は、引数のmousePosにクリックされた位置を格納します。

30: IsMouseClick(mousePos) {
31:     if(this.is_Mouse_Click){
32:         mousePos[0] = this.mouse_Click_Pos[0];
33:         mousePos[1] = this.mouse_Click_Pos[1];
34:         return true;
35:     }else{
36:         return false;
37:     }
38: }

3.4. カメラの前進状態の取得

40~42行目がカメラの前進状態の取得メソッドです。このメソッドは、カメラが前進中かどうかを返します。

40: IsForward() {
41:     return this.is_Forward;
42: }

3.5. カメラの後進状態の取得

44~46行目がカメラの後進状態の取得メソッドです。このメソッドは、カメラが後進中かどうかを返します。

44: IsBackward() {
45:     return this.is_Backward;
46: }

3.6. カメラの回転状態の取得

48~57行目がカメラの回転状態の取得メソッドです。このメソッドは、カメラが回転中かどうかを返し、回転中の場合は、現在のマウス位置と1フレーム前のマウス位置からマウスの移動方向を求め、引数のdragVecに格納します。

48: IsCameraTurn(dragVec) {
49:     if (this.is_Camera_Turn == true) {
50:         // 前フレームからの移動量を計算
51:         dragVec[0] = this.mouse_Move_Pos[0] - this.mouse_Move_Pos_Old[0];
52:         dragVec[1] = this.mouse_Move_Pos[1] - this.mouse_Move_Pos_Old[1];
53:         return true;
54:     } else {
55:         return false;
56:     }
57: }

3.7. カメラの高度変更フラグの取得

59~68行目がカメラの高度変更状態の取得メソッドです。このメソッドは、カメラが高度変更中かどうかを返し、高度変更中の場合は、現在のマウス位置と1フレーム前のマウス位置から移動方向を求め、引数のdragVecに格納します。

59: IsCameraHeightMove(dragVec) {
60:     if (this.is_Camera_Height_Move == true) {
61:         // 前フレームからの移動量を計算
62:         dragVec[0] = this.mouse_Right_Move_Pos[0] - this.mouse_Right_Move_Pos_Old[0];
63:         dragVec[1] = this.mouse_Right_Move_Pos[1] - this.mouse_Right_Move_Pos_Old[1];
64:         return true;
65:     } else {
66:         return false;
67:     }
68: }

3.8. マウスのボタンが押された時のイベント

70~99行目がマウスのボタンが押されたときのイベントメソッドです。このメソッドでは、マウスの左ボタンとShiftキー、Altキーの組み合わせで対応する操作を決定します。 まず、マウスの左ボタンとShiftキーの組み合わせで、カメラの回転操作に対する設定を下記のように行います。

  • 回転中かどうか ⇒ true
  • 回転時のマウス位置 ⇒ 現在のマウス位置
  • 回転時の1フレーム前のマウス位置 ⇒ 現在のマウス位置

次に、マウスの左ボタンとAltキーの組み合わせで、カメラの高度変更操作に対する設定を下記のように行います。

  • 高度変更中かどうか ⇒ true
  • 高度変更時のマウス位置 ⇒ 現在のマウス位置
  • 高度変更時の1フレーム前のマウス位置 ⇒ 現在のマウス位置

最後に、マウスの左ボタンが押されていて、Shiftキー、Altキーの両方が押されていないときは、以下の設定を行います。

  • クリックしたかどうか ⇒ true
  • クリックした画面の位置 ⇒ 現在のマウス位置
70: _onMouseDown(event) {
71:     event.preventDefault();
72: 
73:     if (event.button == 0 /* 左ボタン */) {
74:         if (event.shiftKey) {
75:             // カメラ回転ドラッグ開始
76:             this.is_Camera_Turn = true;
77:             this.mouse_Move_Pos[0] = event.clientX;
78:             this.mouse_Move_Pos[1] = event.clientY;
79:             this.mouse_Move_Pos_Old[0] = event.clientX;
80:             this.mouse_Move_Pos_Old[1] = event.clientY;
81:         }
82: 
83:         if(event.altKey){
84:             // カメラ移動ドラッグ開始
85:             this.is_Camera_Height_Move = true;
86:             this.mouse_Right_Move_Pos[0] = event.clientX;
87:             this.mouse_Right_Move_Pos[1] = event.clientY;
88:             this.mouse_Right_Move_Pos_Old[0] = event.clientX;
89:             this.mouse_Right_Move_Pos_Old[1] = event.clientY;
90:         }
91: 
92:         if (event.shiftKey == false & event.altKey == false) {
93:             // クリックされた
94:             this.is_Mouse_Click = true;
95:             this.mouse_Click_Pos[0] = event.clientX;
96:             this.mouse_Click_Pos[1] = event.clientY;
97:         }
98:     }
99: }

3.9. マウスが移動した時のイベント

101~119行目がマウスが移動した時のイベントメソッドです。このメソッドは、カメラが回転中か高度変更中の場合に、マウス位置を更新する処理を行います。 まず、カメラが回転中の場合は、下記の設定を行います。

  • 回転時の1フレーム前のマウス位置 ⇒ 回転時のマウス位置
  • 回転時のマウス位置 ⇒ 現在のマウス位置

そして、カメラが高度変更中の場合は、下記の設定を行います。

  • 高度変更時の1フレーム前のマウス位置 ⇒ 高度変更時のマウス位置
  • 高度変更時のマウス位置 ⇒ 現在のマウス位置
101: _onMouseMove(event) {
102:     event.preventDefault();
103: 
104:     if (this.is_Camera_Turn == true) {
105:         // カメラ回転ドラッグ中
106:         this.mouse_Move_Pos_Old[0] = this.mouse_Move_Pos[0];
107:         this.mouse_Move_Pos_Old[1] = this.mouse_Move_Pos[1];
108:         this.mouse_Move_Pos[0] = event.clientX;
109:         this.mouse_Move_Pos[1] = event.clientY;
110:     }
111: 
112:     if (this.is_Camera_Height_Move == true) {
113:         // カメラ移動ドラッグ中
114:         this.mouse_Right_Move_Pos_Old[0] = this.mouse_Right_Move_Pos[0];
115:         this.mouse_Right_Move_Pos_Old[1] = this.mouse_Right_Move_Pos[1];
116:         this.mouse_Right_Move_Pos[0] = event.clientX;
117:         this.mouse_Right_Move_Pos[1] = event.clientY;
118:     }
119: }

3.10. マウスのボタンが離された時のイベント

121~138行目がマウスのボタンが離された時のイベントメソッドです。このメソッドは、各種カメラ操作を終了させる処理を行います。そのため、下記の設定(初期化)を行います。

  • クリックしたかどうか ⇒ false
  • クリックした画面の位置 ⇒ 全て0
  • 回転中かどうか ⇒ false
  • 高度変更中かどうか ⇒ false
  • 回転時のマウス位置 ⇒ 全て0
  • 高度変更時のマウス位置 ⇒ 全て0
121: _onMouseUp(event) {
122:     event.preventDefault();
123: 
124:     if (event.button == 0 /* 左ボタン */) {
125:         // クリック、カメラ回転終了
126:         this.is_Mouse_Click = false;
127:         this.is_Camera_Turn = false;
128:         this.mouse_Click_Pos[0] = 0;
129:         this.mouse_Click_Pos[1] = 0;
130:         this.mouse_Move_Pos[0] = 0;
131:         this.mouse_Move_Pos[1] = 0;
132: 
133:         // カメラ移動終了
134:         this.is_Camera_Height_Move = false;
135:         this.mouse_Right_Move_Pos[0] = 0;
136:         this.mouse_Right_Move_Pos[1] = 0;
137:     }
138: }

3.11. フォーカスが外れた時のイベント

140~149行目がフォーカスが外れた時のイベントメソッドです。画面のフォーカスが外れた時に呼ばれます。このサンプルコードでは、以下の変数を初期化します。

  • クリックしたかどうか ⇒ false
  • 前進中かどうか ⇒ false
  • 後進中かどうか ⇒ false
  • 回転中かどうか ⇒ false
  • 高度変更中かどうか ⇒ false
140: _onBlur(event) {
141:     event.preventDefault();
142: 
143:     // フォーカスを失った
144:     this.is_Mouse_Click = false;
145:     this.is_Forward = false;
146:     this.is_Backward = false;
147:     this.is_Camera_Turn = false;
148:     this.is_Camera_Height_Move = false;
149: }

3.12. マウスホイールが動いた時のイベント

151~160行目がマウスホイールが動いた時のイベントメソッドです。このサンプルコードでは、マウスホイールを前に動かすと前進中とし、後ろに動かすと後進中とします。

151: _onMouseScroll(event) {
152:     event.preventDefault();
153: 
154:     // chromeのホイール移動量検出
155:     if ( event.deltaY < 0) {
156:         this.is_Forward = true;
157:     }else{
158:         this.is_Backward = true;
159:     }
160: }

3.13. マウスホイールが動いた時のスクロールイベント(FireFox用)

162~171行目がFireFox用のマウスホイールが動いた時のイベントメソッドです。このメソッドは、このサンプルコードでは、マウスホイールのスクロールイベントメソッドと同様の動きとしますが、マウスホイールの移動量を表す変数が異なります。

162: _onMouseScroll_FireFox(event) {
163:     event.preventDefault();
164: 
165:     // FireFoxのホイール移動量検出
166:     if (event.detail < 0) {
167:         this.is_Forward = true;
168:     }else{
169:         this.is_Backward = true;
170:     }
171: }

3.14. フレーム終了時のリセット

173~177行目がフレーム終了時のリセットメソッドです。このメソッドは、前進中の状態、後進中の状態を初期化します。

173: endFrame() {
174:     // フレーム終了時
175:     this.is_Forward = false;
176:     this.is_Backward = false;
177: }

4. JavaScriptのサンプルコードの詳細(カメラの操作)

カメラを操作するJavaScriptのサンプルコードの詳細を以下で解説します。

4.1. クラスとグローバル変数

3~216行目で、カメラを操作するクラスを定義します。カメラをマウスで操作するために、カメラを操作するクラスはmapray.RenderCallbackクラスを継承します。 1行目のグローバル変数は、数学関連の関数または定数を定義するユーティリティークラスです。

var GeoMath = mapray.GeoMath;

class CameraControl extends mapray.RenderCallback{

  //中略

}

4.2. コンストラクタ

5~31行目がカメラを操作するクラスのコンストラクタです。 まず、引数として渡されるブロックのidに対して、mapray.Viewerを作成します。Mapray.Viewerのベース地図の画像プロバイダは、画像プロバイダの生成メソッドで取得した画像プロバイダを設定します。mapray.Viewerの作成の詳細は、ヘルプページ『カメラのアニメーション』を参照してください。 次に、カメラ操作に関する初期値を下記のように設定します。

  • カメラの位置 ⇒ 緯度・経度が富士山から7kmほど南西の場所、高度は5500m
  • カメラの視線方向 ⇒ 全て0
  • カメラの回転角度 ⇒ 145度
  • カメラの仰俯角 ⇒ 30度
  • 前進、後進時の移動量の補正値 ⇒ 30倍
  • カメラの回転角度、仰俯角更新時の補正値 ⇒ 0.1倍
  • カメラの高度更新時の補正値 ⇒ 0.5倍
  • マウスの入力を検知するクラス ⇒ 作成したViewerを使ったインスタンス

最後に、カメラの位置・向きの設定メソッドを呼び出します。

 5: constructor(container) {
 6:     super();
 7: 
 8:     // Access Tokenを設定
 9:     var accessToken = "<your access token here>";
10: 
11:     // Viewerを作成する
12:     new mapray.Viewer(container, {
13:         render_callback: this,
14:         image_provider: this.createImageProvider(),
15:         dem_provider: new mapray.CloudDemProvider(accessToken)
16:     });
17: 
18:     // 球面座標系(経度、緯度、高度)で視点の初期値を設定。座標は富士山から7kmほど南西の場所
19:     this.camera_Pos = { longitude: 138.668035, latitude: 35.290262, height: 5500.0 };
20:     this.camera_Vec = [0, 0, 0];                // カメラの前進後退方向
21:     this.camera_Turn_Angle = 145;               // ターン角度
22:     this.camera_Pitch = 20;                     // 仰俯角
23:     this.camera_Move_Correction = 30;           // 前進後退の補正値
24:     this.camera_Turn_Correction = 0.1;          // ターン、仰俯角の補正値
25:     this.camera_Height_Correction = 0.5;        // 高度更新の補正値
26: 
27:     // 入力検知クラス
28:     this.input_Checker = new CheckInput(this.viewer);
29: 
30:     this.SetCamera();
31: }

4.3. フレームレンダリング前のコールバックメソッド(カメラ姿勢の更新処理)

34~68行目がフレームレンダリング前のコールバックメソッドです。このサンプルコードでは、カメラの操作モードに応じてカメラ姿勢の更新を行います。 まず、37~40行目でカメラが回転中の場合は、カメラの回転角度の更新メソッドを呼び出し、カメラの回転角度を更新します。 同様に、43~56行目で、カメラ高度の変更処理、カメラの前進処理、カメラの後進処理をそれぞれ呼び出し、カメラ姿勢を更新します。 そして、58行目でカメラの位置・向きの設定メソッドを呼びだし、最終的なカメラ姿勢に更新します。 また、63~65行目では、マウスをクリックした時に、その地点の緯度・経度・高度を画面に表示させるメソッドを呼び出し、画面に表示される緯度・経度・高度を変更します。 最後に、フレーム終了時のリセットメソッドを呼びだし、カメラ姿勢の更新処理を終了します。

34: onUpdateFrame(delta_time)  // override
35: {
36:     // カメラ回転
37:     var turn_Drag_Vec = [0, 0];
38:     if (this.input_Checker.IsCameraTurn(turn_Drag_Vec)) {
39:         this.TurnCamera(turn_Drag_Vec);
40:     }
41: 
42:     // カメラの高度変更
43:     var height_Move_Drag_Vec = [0, 0];
44:     if (this.input_Checker.IsCameraHeightMove(height_Move_Drag_Vec)) {
45:         this.UpdateCameraHeight(height_Move_Drag_Vec);
46:     }
47: 
48:     // カメラ前進
49:     if (this.input_Checker.IsForward()) {
50:         this.ForwardCameraPos();
51:     }
52: 
53:     // カメラ後退
54:     if (this.input_Checker.IsBackward()) {
55:         this.BackwardCameraPos();
56:     }
57: 
58:     this.SetCamera();
59: 
60:     var click_Pos = [0, 0];
61: 
62:     // 緯度経度高度表示
63:     if (this.input_Checker.IsMouseClick(click_Pos)) {
64:         this.SetClickPosLongitudeAndLatitudeAndHeight(click_Pos);
65:     }
66: 
67:     this.input_Checker.endFrame();
68: }

4.4. 画像プロバイダの生成

71~73行目が画像プロバイダの生成メソッドです。生成した画像プロバイダを返します。 画像プロバイダの生成の詳細は、ヘルプページ『緯度経度によるカメラ位置の指定』を参照してください。

71: createImageProvider() {
72:     return new mapray.StandardImageProvider("https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/", ".jpg", 256, 2, 18);
73: }

4.5. カメラの位置・向きの設定

75~125行目がカメラの位置・向きの設定メソッドです。 まず、79~80行目のgetMlocsToGocsMatrix関数で、カメラ位置の緯度・経度・高度を地心直交座標系で表現したカメラ位置を表す変換行列を計算します。 次に、ビュー変換行列を作成します。まず、82~86行目で相対注視点を表す変換行列を単位行列に初期化し、相対注視点がY軸の負の方向になるように、Y軸方向に移動します。その後、89~92行目で、現在の回転角度に対応する回転行列(Z軸回りの回転行列)、カメラの仰俯角に対応する回転行列(X軸回りの回転行列)を生成し、95~98行目で、相対注視点を表す変換行列にそれぞれの回転行列を掛け合わせることで、相対注視点を表す変換行列を作成します。そして、101~109行目で、原点と求めた相対注視点から上方向ベクトルを求め、112~113行目で、原点、求めた相対注視点、カメラの上方向ベクトルを利用して、最終的なビュー変換行列を作成します。 そして、116~117行目で、これまでに求めたカメラ位置を表す変換行列と、ビュー変換行列を掛け合わせることで、最終的なカメラ姿勢を計算します。 最後に、120行目で、視線方向ベクトルを更新し、122~123行目でカメラの投影範囲を設定し、現在のカメラ視線を最新の状態に更新します。

 75: SetCamera() {
 76:     // カメラ位置の設定
 77: 
 78:     // 球面座標から地心直交座標へ変換
 79:     var camera_geoPoint = new mapray.GeoPoint( this.camera_Pos.longitude, this.camera_Pos.latitude, this.camera_Pos.height );
 80:     var camera_Pos_Gocs = camera_geoPoint.getMlocsToGocsMatrix( GeoMath.createMatrix() );
 81: 
 82:     var camera_End_Pos_Mat = GeoMath.createMatrix();
 83:     GeoMath.setIdentity(camera_End_Pos_Mat);
 84: 
 85:     // カメラの位置をY軸方向に移動させる
 86:     camera_End_Pos_Mat[13] = -1;
 87: 
 88:     // z軸でcamera_Turn_Angle分回転させる回転行列を求める
 89:     var turn_Mat = GeoMath.rotation_matrix([0, 0, 1], this.camera_Turn_Angle, GeoMath.createMatrix());
 90: 
 91:     // x軸でcamera_Pitch分回転させる回転行列を求める
 92:     var pitch_Mat = GeoMath.rotation_matrix([1, 0, 0], this.camera_Pitch, GeoMath.createMatrix());
 93: 
 94:     // カメラの位置にX軸の回転行列をかける
 95:     GeoMath.mul_AA(pitch_Mat, camera_End_Pos_Mat, camera_End_Pos_Mat);
 96: 
 97:     // カメラの位置にZ軸の回転行列をかける
 98:     GeoMath.mul_AA(turn_Mat, camera_End_Pos_Mat, camera_End_Pos_Mat);
 99: 
100:     // 視線方向を定義
101:     var cam_Start_Pos = GeoMath.createVector3([0, 0, 0]);
102:     var camera_End_Pos = GeoMath.createVector3([camera_End_Pos_Mat[12], camera_End_Pos_Mat[13], camera_End_Pos_Mat[14]]);
103: 
104:     // 視点、注視点ベクトルとZ軸で外積をして垂直な軸を求める
105:     var tmp_closs_vec = GeoMath.cross3(camera_End_Pos, GeoMath.createVector3([0, 0, -1]), GeoMath.createVector3());
106:     GeoMath.normalize3(tmp_closs_vec, tmp_closs_vec);
107: 
108:     // 視点、注視点ベクトルと垂直な軸で外積をしてアップベクトルを求める
109:     var cam_Up = GeoMath.cross3(camera_End_Pos, tmp_closs_vec, GeoMath.createVector3());
110: 
111:     // ビュー変換行列を作成
112:     var view_To_Home = GeoMath.createMatrix();
113:     GeoMath.lookat_matrix(cam_Start_Pos, camera_End_Pos, cam_Up, view_To_Home);
114: 
115:     // カメラの位置と視線方向からカメラの姿勢を変更
116:     var view_To_Gocs = this.viewer.camera.view_to_gocs;
117:     GeoMath.mul_AA(camera_Pos_Gocs, view_To_Home, view_To_Gocs);
118: 
119:     // カメラの視線方向を取得
120:     this.camera_Vec = [view_To_Gocs[8], view_To_Gocs[9], view_To_Gocs[10]];
121: 
122:     // カメラのnear、farの設定
123:     this.viewer.camera.near = 30;
124:     this.viewer.camera.far = 500000;
125: }

4.6. クリックした位置の緯度・経度・高度表示

127~143行目がクリックした位置の緯度・経度・高度表示メソッドです。このサンプルコードでは、クリックした位置から視線方向に伸ばした直線と地表面の交点を求め、その位置の緯度・経度・高度を画面に表示します。 まず、129行目のgetCanvasRay関数で、クリックした位置から視線方向に伸ばした直線(レイ)を取得します。次に、132行目で行目のgetRayIntersection関数で、先ほど取得したレイと地表の交点を取得します。最後に、136~137行目のsetFromGocs関数で、先ほど取得した交点の緯度・経度・高度を計算し、140~142行目で、その緯度・経度・高度を対応したテキストに設定します。

127: SetClickPosLongitudeAndLatitudeAndHeight(clickPos) {
128:     // キャンバス座標のレイを取得
129:     var ray = this.viewer.camera.getCanvasRay(clickPos, new mapray.Ray());
130: 
131:     // レイと地表の交点を求める
132:     var clossPoint = this.viewer.getRayIntersection(ray);
133: 
134:     if (clossPoint != null) {
135:         // 交点を球面座標系に変換する
136:         var closs_geoPoint = new mapray.GeoPoint();
137:         closs_geoPoint.setFromGocs( clossPoint );
138: 
139:         // UIを更新する
140:         document.getElementById( "LongitudeValue" ).innerText = closs_geoPoint.longitude.toFixed(6);
141:         document.getElementById( "LatitudeValue" ).innerText = closs_geoPoint.latitude.toFixed(6);
142:         document.getElementById( "HeightValue" ).innerText = closs_geoPoint.height.toFixed(6);
143:     }
144: }

4.7. カメラ位置の前進

146~163行目がカメラ位置の前進メソッドです。このサンプルコードでは、カメラの位置が視線方向に移動します。 まず、148~149行目のgetMlocsToGocsMatrix関数で、カメラ位置の地心直交座標への変換行列を作成します。次に、152~154行目で、視線方向ベクトルと前進、後退時の移動量の補正値を使って、前進させたカメラ位置を求めます。最後に、157~158行目のsetFromGocs関数で前進させたカメラ位置の球面座標を計算し、160~162行目でその座標をカメラ位置へ反映します。

146: ForwardCameraPos() {
147:     // 球面座標から地心直交座標へ変換
148:     var camera_geoPoint = new mapray.GeoPoint( this.camera_Pos.longitude, this.camera_Pos.latitude, this.camera_Pos.height );
149:     var camera_Pos_Gocs = camera_geoPoint.getMlocsToGocsMatrix( GeoMath.createMatrix() );
150: 
151:     // 地心直交座標の平行移動成分を変更
152:     camera_Pos_Gocs[12] -= this.camera_Vec[0] * this.camera_Move_Correction;
153:     camera_Pos_Gocs[13] -= this.camera_Vec[1] * this.camera_Move_Correction;
154:     camera_Pos_Gocs[14] -= this.camera_Vec[2] * this.camera_Move_Correction;
155: 
156:     // 地心直交座標を球面座標に変換する
157:     var next_camera_geoPoint = new mapray.GeoPoint();
158:     next_camera_geoPoint.setFromGocs( [camera_Pos_Gocs[12], camera_Pos_Gocs[13], camera_Pos_Gocs[14]] );
159: 
160:     this.camera_Pos.longitude = next_camera_geoPoint.longitude;
161:     this.camera_Pos.latitude = next_camera_geoPoint.latitude;
162:     this.camera_Pos.height = next_camera_geoPoint.height;
163: }

4.8. カメラ位置の後進

165~182行目がカメラ位置の後進メソッドです。このサンプルコードでは、カメラの位置が視線の逆方向に移動します。 このメソッドは、前述したカメラ位置の前進メソッドを逆方向に動くようにしたメソッドです。

165: BackwardCameraPos() {
166:     // 球面座標から地心直交座標へ変換
167:     var camera_geoPoint = new mapray.GeoPoint( this.camera_Pos.longitude, this.camera_Pos.latitude, this.camera_Pos.height );
168:     var camera_Pos_Gocs = camera_geoPoint.getMlocsToGocsMatrix( GeoMath.createMatrix() );
169: 
170:     // 地心直交座標の平行移動成分を変更
171:     camera_Pos_Gocs[12] += this.camera_Vec[0] * this.camera_Move_Correction;
172:     camera_Pos_Gocs[13] += this.camera_Vec[1] * this.camera_Move_Correction;
173:     camera_Pos_Gocs[14] += this.camera_Vec[2] * this.camera_Move_Correction;
174: 
175:     // 地心直交座標を球面座標に変換する
176:     var next_camera_geoPoint = new mapray.GeoPoint();
177:     next_camera_geoPoint.setFromGocs( [camera_Pos_Gocs[12], camera_Pos_Gocs[13], camera_Pos_Gocs[14]] );
178: 
179:     this.camera_Pos.longitude = next_camera_geoPoint.longitude;
180:     this.camera_Pos.latitude = next_camera_geoPoint.latitude;
181:     this.camera_Pos.height = next_camera_geoPoint.height;
182: }

4.9. カメラの回転角度の更新

184~201行目がカメラの回転角度の更新メソッドです。このサンプルコードでは、ドラッグした方向によってカメラの回転角度と仰俯角を更新します。 まず、186~187行目でドラッグした方向とカメラの回転角度、仰俯角更新時の補正値を使って、カメラの回転角度と仰俯角の更新量を求めます。次に。先ほど求めた更新量の絶対値が0.3よりも小さい場合は、190~196行目で更新量を0にします。最後に、199~200行目でカメラの回転角度と仰俯角の更新量を使って、カメラの角度を更新します。

184: TurnCamera(drag_Vec) {
185:     // ターン、仰俯角の角度の更新量決定
186:     var add_Turn_Angle = drag_Vec[0] * this.camera_Turn_Correction;
187:     var add_Pitch = drag_Vec[1] * this.camera_Turn_Correction;
188: 
189:     // 更新量が少なかったら0にする
190:     if (add_Turn_Angle > -0.3 & add_Turn_Angle < 0.3) {
191:         add_Turn_Angle = 0;
192:     }
193: 
194:     if (add_Pitch > -0.3 & add_Pitch < 0.3) {
195:         add_Pitch = 0;
196:     }
197: 
198:     //ターン、仰俯角の角度更新
199:     this.camera_Turn_Angle -= add_Turn_Angle;
200:     this.camera_Pitch += add_Pitch;
201: }

4.10. カメラの高度の更新

203~214行目がカメラの高度の更新メソッドです。このサンプルコードでは、ドラッグした方向によってカメラの高度を更新します。 まず、205行目でドラッグした方向とカメラの高度更新時の補正値を使って、カメラの高度の更新量を求めます。次に、先ほど求めた更新量の絶対値が1よりも小さい場合は、208~210行目で更新量を0にします。最後に、213行目でカメラの高度の更新量を使って、高度を更新します。

203: UpdateCameraHeight(drag_Vec) {
204:     // 高度の変更量決定
205:     var add_Height = drag_Vec[1] * this.camera_Height_Correction;
206: 
207:     // 値が小さい場合0にする
208:     if (add_Height > -1 & add_Height < 1) {
209:         add_Height = 0;
210:     }
211: 
212:     // カメラ座標の高度を更新する
213:     this.camera_Pos.height -= add_Height;
214: }

5. 出力イメージ

このサンプルコードの初期状態の出力イメージは下図のようになります。 SampleImageMouseControl.png

初期状態から以下の操作を行った時の出力イメージは以下のようになります。

・画面中央付近へのクリック SampleImageMouseControl_centerClick.png

・カメラの前進 SampleImageMouseControl_wheelUp.png

・カメラの後進 SampleImageMouseControl_wheelDown.png

・カメラの左回転 SampleImageMouseControl_rotLeft.png

・カメラの右回転 SampleImageMouseControl_rotRight.png

・カメラの上回転 SampleImageMouseControl_rotUp.png

・カメラの下回転 SampleImageMouseControl_rotDown.png

・カメラの高度の上昇 SampleImageMouseControl_heightUp.png

・カメラの高度の下降 SampleImageMouseControl_heightDown.png