import Loader from "./Loader" import GeoMath from "./GeoMath"; import Orientation from "./Orientation"; import CredentialMode from "./CredentialMode"; import ModelContainer from "./ModelContainer"; import MarkerLineEntity from "./MarkerLineEntity"; import PathEntity from "./PathEntity"; import TextEntity from "./TextEntity"; import ModelEntity from "./ModelEntity"; import PolygonEntity from "./PolygonEntity"; import GltfTool from "./gltf/Tool"; import Resource, { URLResource, ResourceType } from "./Resource"; /** * @summary シーンの読み込み * @memberof mapray */ class SceneLoader extends Loader { /** * @desc * <p>url で指定したシーンデータの読み込みを開始し、scene にエンティティを構築する。</p> * <p>読み込みが終了したとき options.callback を呼び出す。</p> * @param {mapray.Scene} scene 読み込み先のシーン * @param {string} resource シーンリソース * @param {object} [options] オプション集合 * @param {mapray.Loader.TransformCallback} [options.transform] リソース要求変換関数 * @param {mapray.Loader.EntityCallback} [options.onEntity] エンティティコールバック * @param {mapray.SceneLoader.FinishCallback} [options.callback] 終了コールバック関数 */ constructor( scene, resource, options={} ) { if ( resource instanceof Resource ) { // OK } else if ( typeof resource === "string" ) { resource = new URLResource(resource, { type: "json", transform: options.transform }); } else { throw new Error( "Unsupported Resource: " + resource ); } super( scene, resource, { onEntity: options.onEntity, onLoad: options.callback } ); this._glenv = scene.glenv; this._references = {}; this._finished = false; } /** * @summary オブジェクト参照を取得 * @desc * <p>注意: シーンの読み込みが終了したことを確認してからこのメソッドを呼び出すこと。</p> * @param {string} id 識別子 * @return {?(mapray.ModelContainer|mapray.Entity)} オブジェクト */ getReference( id ) { var ref = this._references[id]; return (ref !== undefined) ? ref : null; } /** * @summary オブジェクト参照を設定 * @desc * <p>オブジェクト item を識別子 id で参照できるように this に設定する。</p> * @param {string} id 識別子 * @param {mapray.ModelContainer|mapray.Entity} item オブジェクト * @private */ _setReference( id, item ) { // 参照を設定 this._references[id] = item; } /** * @summary 読み込み処理の実態。継承クラスによって実装される。 * @private */ _load() { return ( this._resource.load( { type: ResourceType.JSON } ) .then( oscene => { // JSON データの取得に成功 this._check_cancel(); return this._load_object( oscene ); } ) ); } /** * JSON シーンオブジェクトを解析 * @private */ _load_object( oscene ) { return ( Promise.resolve() .then( () => { return this._load_model_register( oscene ); } ) .then( () => { return this._postload_object( oscene ); }) ); } /** * 残りのオブジェクトを読み込む * @private */ _postload_object( oscene ) { if ( this.status !== Loader.Status.LOADING ) return; this._load_entity_list( oscene ); } /** * @private */ _load_model_register( oscene ) { var model_register = oscene["model_register"]; if ( !model_register ) return; var keys = Object.keys( model_register ); var asyncTasks = []; for ( var i = 0; i < keys.length; ++i ) { var id = keys[i]; var model = model_register[id]; asyncTasks.push( this._load_model_container( oscene, id, model ) ); } return Promise.all( asyncTasks ); } /** * @private */ _load_model_container( oscene, id, model ) { var url = model.link; if ( !this._resource.resolveResourceSupported() ) return Promise.reject(new Error("Sub Resource is not supported")); const gltf_resource = this._resource.resolveResource( url ); return ( gltf_resource.load( { type: ResourceType.JSON } ) .then( json => { // モデルデータの取得に成功 this._check_cancel(); // データを解析して gltf.Content を構築 return GltfTool.load( json, { base_resource: gltf_resource, binary_type: ResourceType.BINARY, image_type: ResourceType.IMAGE, supported_extensions: ModelContainer.getSupportedExtensions_glTF() } ); } ) .then( content => { // モデルデータの構築に成功 var container = new ModelContainer( this._scene, content ); if ( model.offset_transform ) { var matrix = SceneLoader.parseOffsetTransform( model.offset_transform ); container.setOffsetTransform( matrix ); } this._setReference( id, container ); } ) ); } /** * @private */ _load_entity_list( oscene ) { var entity_list = oscene["entity_list"]; if ( !entity_list ) return; var scene = this._scene; for ( var i = 0; i < entity_list.length; ++i ) { var item = entity_list[i]; var type = item.type; var entity = null; switch ( type ) { case "markerline": entity = new MarkerLineEntity( scene, { json: item, refs: this._references } ); break; case "path": entity = new PathEntity( scene, { json: item, refs: this._references } ); break; case "text": entity = new TextEntity( scene, { json: item, refs: this._references } ); break; case "model": entity = new ModelEntity( scene, { json: item, refs: this._references } ); break; case "polygon": entity = new PolygonEntity( scene, { json: item, refs: this._references } ); break; default: console.error( "mapray: unknown entity type: " + type ); break; } if ( entity ) { this._onEntity( this, entity, item ); var id = item.id; if ( id ) { this._setReference( id, entity ); } } } } /** * スキーマ <OFFSET-TRANSFORM> のオブジェクトを解析 * * @param {object} offset_transform <OFFSET-TRANSFORM> オブジェクト * @return {mapray.Matrix} オフセット変換行列 * @package */ static parseOffsetTransform( offset_transform ) { var ot = offset_transform; // <OFFSET-TRANSFORM-PARAMS> var translate = ot.translate || [0, 0, 0]; var orientation = new Orientation( ot.heading, ot.tilt, ot.roll ); var scale = (ot.scale !== undefined) ? ot.scale : [1, 1, 1]; // <PARAM-SCALE3> if ( typeof scale == 'number' ) { // スケールをベクトルに正規化 scale = [scale, scale, scale]; } // scale -> orientation -> translate 順の変換 var matrix = GeoMath.createMatrix(); orientation.getTransformMatrix( scale, matrix ); matrix[12] = translate[0]; matrix[13] = translate[1]; matrix[14] = translate[2]; return matrix; } } /** * @summary 終了コールバック * @callback FinishCallback * @desc * <p>シーンの読み込みが終了したときに呼び出される関数の型である。</p> * @param {mapray.SceneLoader} loader 読み込みを実行したローダー * @param {boolean} isSuccess 成功したとき true, 失敗したとき false * @memberof mapray.SceneLoader */ SceneLoader._defaultHeaders = {}; export default SceneLoader;