今、センサで計測した距離と角度からthree.jsの3次元上に点を打つというのをやっている。
しかし、やる前は簡単そうに思えたが、意外と理解しておかないと難しい内容だったためまとめておく。
#やりたいこと
センサで距離と角度を計測してローカルにcsvファイルとして保存している。
そのファイルを読み込んで配列に格納し、座標に変換して点オブジェクトを作る。
#コード
まずコードを示しておく。
<html>
<head>
<style>
div#WebGL-area{
width: 900px;
height: 600px;
}
</style>
<script type="text/javascript" src="../three.js-master/build/three.min.js"></script>
<script type="text/javascript" src="js/OrbitControls.js"></script>
<script type="text/javascript">
//CSVファイルを読み込む関数getCSV()の定義
function getCSV() {
return new Promise((resolve, reject) => {
var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成、サーバと非同期通信するためのAPI
req.open("get", "test.csv", true); // アクセスするファイルを指定
req.onload = () => {
if (req.readyState === 4 && req.status === 0) {
resolve(convertCSVtoArray(req.responseText));
} else {
reject(new Error(req.statusText));
}
};
req.onerror = () => {
reject(new Error(req.statusText));
};
req.send(null); // HTTPリクエストの発行
});
}
// 読み込んだCSVデータを二次元配列に変換する関数convertCSVtoArray()の定義
function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される
var result = []; // 最終的な二次元配列を入れるための配列
var tmp = str.split("\n"); // 改行を区切り文字として行を要素とした配列を生成
// 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成
for(var i=0;i<tmp.length;++i){
result[i] = tmp[i].split(',');
}
alert(result[0][1])
return result;
}
async function init() {
///////////////////オブジェクト初期化///////////////////
// 座標軸を表示
var axes = new THREE.AxisHelper(100); //引数は線の長さ
scene.add(axes);
//形状オブジェクトの宣言と生成
var geometry= new THREE.Geometry();
//頂点座標データの追加
var data=[];
data = await getCSV();
for(var i=0;i<1000;i++){
geometry.vertices[i]= new THREE.Vector3((data[i][0] * Math.cos( data[i][1] * (Math.PI / 180) ))/2,0,(data[i][0] * Math.sin( data[i][1] * (Math.PI / 180) ))/2);
}
//材質オブジェクトの宣言と生成
var material=new THREE.ParticleBasicMaterial({color: 0xFF0000, size: 5.0});
//点オブジェクトの生成
particles = new THREE.ParticleSystem(geometry,material);
//点オブジェクトのシーンへの追加
scene.add(particles)
//////////////////描画関数の定義//////////////////////
render();
function render() {
controls.update(); //再描画
requestAnimationFrame(render); //アニメーション実装時など、再描画が頻繁に行われる処理に使えるメソッド
renderer.render(scene, camera);
}
}
window.onload = init
</script>
</head>
<body>
<div id="WebGL-area"></div>
</body>
</html>
#解説
###はじめに
ブラウザ上でファイルを指定するのならファイルAPIと呼ばれるものを使えばいけそうだが、プログラム内で完結させようとするとAjax(非同期通信)を使わなければいけないみたい。
Ajaxを使う経験がほとんどなかったから今回苦しんだ。
###Promise
Ajaxを簡潔に記述するために使うべきなのが、「promise」。
これを使うことで人によって書き方が変わるということがほとんどないらしい。
今回は引数にresolveとrejectを指定しているのでどちらかをreturnするようになっている。
###Ajaxの基本的な流れ
-
XMLHttpRequest()
XMLHttpRequest()はサーバと非同期通信するためのAPI。まずはじめにインスタンス作成。 -
req.open()
req.open(method,url,async)でアクセス場所とメソッドの指定。
method: リクエストタイプで GET か POST。
url: サーバ上のファイルの場所。
async: true (非同期) or false (同期)。 -
req.onload かreq.onerror
req.onload:受信が成功した時に呼び出されるイベント
req.onerror:受信が失敗した時に呼び出されるイベント -
req.send()
HTTPリクエストの発行
###readyStateとstatusの値
https://www.sejuku.net/blog/30245
ここに簡単にまとめられているので参考にしてください。
今回は、ローカルファイルにアクセスしているため、成功すればhttpの時の200が返ってくるのではなく0が返ってくるみたいです。