Autodesk Forgeは基本的にはA360などのサーバ上にアップされたBIMデータをウェブAPIを通じて操作できるようにしたもので、疎結合なアーキテクチャとなっています。つまりはビューワは独立に制作することができます。描画のライブラリはAutodeskから提供されており、ライブラリはthreeJSを拡張したものになっているそうです。BIMデータをアップしたときに取得する、Access TokenやデータのURNが既知であれば、HTMLファイルだけで3次元形状をブラウザ上に表示することができます。サーバ側の仕組みとしては、先に述べたAccess Tokenなどを保持したり、データベースと連携したりといったアイデアがあるはずで、それによってアプリケーションの拡張が可能と考えます。
それでは、今回はNodeJS+Expressでクライアントを試作してみます。
準備
BIMデータの準備
まずは、ForgeアプリとBIMのデータの登録を行います。以前のエントリにやり方があるので、参考にしてください。
Access Tokenのみならず、BIMデータの場所を示すURNも必要になります。ここに変換の仕方があるので参考にしてください。これらがきちんと取得していないとまったく動きません。
NodeJS+Express環境の準備
別にクライアントだけでも良いのですが、今後の拡張も鑑みてNodeJS+Expessで作ってみます。ExpressというのはNodeJSで有名なMVCフレームワークです。セットアップについては、ここら辺を参考にしてください。私はVisual Studioのテンプレートを使って作りました。package.jsonとエントリポイントであるapp.jsは以下です。これをnpm startなどとすると、localhost:3000あたりで、アプリが立ち上がります。ちなみに、./routes/index.js内に書かれたルーティングルールでルーティングされます。今回は./views以下のindex.pugにルーティングするようにしています。テンプレートエンジンはPUGです。この辺りはEXPRESSのほぼテンプレなので、説明は割愛します。
{
"name": "forge-express",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node app"
},
"description": "Forge sample using NodeJS + Express",
"dependencies": {
"body-parser": "^1.15.0",
"cookie-parser": "^1.4.0",
"debug": "^2.2.0",
"express": "^4.14.0",
"morgan": "^1.7.0",
"pug": "^2.0.0-beta6",
"serve-favicon": "^2.3.0"
}
}
'use strict';
var debug = require('debug');
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
debug('Express server listening on port ' + server.address().port);
});
基本的なForge Viewerの制作
HTMLのもととなるPUGファイルは、views以下に配置しています。ルート(/)が参照されたら、まずはlayout.pugの内容が出力されるようになってます。ここでは、まずForgeに関係するCSS、JSライブラリを読み込んでいます。最後に読み込んでいるviewer.jsが今回の肝となる部分です。
doctype html
html
head
title= title
meta(name='viewport', content='width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=no')
link(rel='stylesheet', href='/stylesheets/main.css')
link(rel='stylesheet', href='https://developer.api.autodesk.com/modelderivative/v2/viewers/style.min.css', type='text/css')
body
block content
script(src='https://developer.api.autodesk.com/modelderivative/v2/viewers/viewer3D.min.js')
script(src='javascripts/viewer.js')
続いて、上記で参照しているblock contentの部分です。ここは簡単にMyViewerDivというタグがあるだけ。このDIV要素にForgeのビューワが読み込まれます。ついでにCSSも設定しておきます。画面いっぱいに表示できるように変えておきます。
extends layout
block content
div#MyViewerDiv
body {
margin: 0;
}
#MyViewerDiv {
width: 100%;
height: 100%;
margin: 0;
background-color: #F0F8FF;
}
データ表示用のJavascript
先のviewer.jsにBIMデータの読み込み、表示の処理を書き込んでいきます。ここで、準備の項で述べたアクセストークンとURNが必要になります。
var viewerApp;
var options = {
env: 'AutodeskProduction',
getAccessToken: function (onGetAccessToken) {
var accessToken = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
var expireTimeSeconds = 60 * 30;
onGetAccessToken(accessToken, expireTimeSeconds);
}
};
var documentId = 'urn:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
Autodesk.Viewing.Initializer(options, function onInitialized() {
// 読み込みが終わった後に呼ばれるハンドラ。MyViewerDiv内にビューワをロードする。
viewerApp = new Autodesk.Viewing.ViewingApplication('MyViewerDiv');
viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D);
// コンテンツのロードを始める。
viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);
});
function onDocumentLoadSuccess(doc) {
// A document contains references to 3D and 2D viewables.
var viewables = viewerApp.bubble.search({ 'type': 'geometry' });
if (viewables.length === 0) {
console.error('Document contains no viewables.');
return;
}
viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail)
}
function onDocumentLoadFailure(viewerErrorCode) {
console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);
}
function onItemLoadSuccess(viewer, item) {
console.log('onItemLoadSuccess()!');
console.log(viewer);
console.log(item);
console.log('Viewers are equal: ' + (viewer === viewerApp.getCurrentViewer()));
}
function onItemLoadFail(errorCode) {
console.error('onItemLoadFail() - errorCode: ' + errorCode);
}
まず、optionsというオブジェクトをInitializerの引数としています。optionsにはenvとgetAccessTokenという関数がパラメータとしてあるが、後者は自動的にExpireされる前にアクセストークンを更新するような処理となるようです(隠蔽されていてわからない)。実際は、getAccessTokenという関数の代わりに、AccessTokenというパラメータとしても問題はありません。
初期化の処理が終わると、ViewingApplicationがnewされます。その際にビューワをロードするDIV要素を指定しています。
そのあとはviewerApp.k3DやAutodesk.Viewing.Private.GuiViewer3DなどのExtentionを読み込んでから、コンテンツ(BIMデータなど)のロードを始めています。それぞれに失敗した時と、成功した時のハンドラとなる関数を用意しています。
viewer.selectItemを呼び出して成功したら(onItemLoadSuccessが呼ばれたら)、画面に表示されます。
とりあえず、この記事ではここまで。
次回はビューワの柔軟な操作が可能なExtensionsやEvent処理についても説明します。