此篇博客原著为 Autodesk ADN 的梁晓冬,以下以我简称。
我的同事创作了一些关于如何在一个 Forge Viewer 实例里聚合多模型的博客,例如:
- Aggregating multiple models in the Viewer
- Preparing your viewing application for multi-model workflows
- Preparing your viewing application for multi-model workflows - Part 2: Model Loader
这些示例多半是一次聚合一个模型到 viewer 里,照这里面的思路是很容易将其改写成透过一个回圈(Loop)在 Viewer 载入任意个数模型的。但模型载入程序并不是同步执行的(载入文档、viewable和几何等动作在 Viewer
里都是异步的),我们没办法知道哪一个模型是第一个被完整载入,和下个一个完全载入的是谁;而在一些应用场景里是有可能需要在一个序列(Sequeuence)聚合多个模型。
所以我花了一些时间研究如何使用 JavaScript Promise 这个机制,基本上 Promise 提供了一个灵活的机制可以用来管理这些单元程序。为了建立一个 Promise 的序列,我找到了一篇有用的讨论串和他的测试例子:
https://stackoverflow.com/que...
根据这个基础,我写了一个测试工程 https://jsfiddle.net/xiaodong...,这个工程主要是用来展示如何透过一个序列将各楼层的模型一个一个载入,这工程的部份代码如下所示:
//replace with your own urns this.urn_model1 = <model1 urn>; this.urn_model2 = <model2 urn>; this.urn_model3 = <model3 urn>; this.urn_model4 = <model4 urn>; //model info array this.modelArray = [{ modelName: 'urn_model1',urn: urn_model1,modelObj: null },{ modelName: 'urn_model2',urn: urn_model2,{ modelName: 'urn_model3',urn: urn_model3,{ modelName: 'urn_model4',urn: urn_model4,modelObj: null } ]; //viewer object this.viewer = null; function start() { //replace with your own token var token = < your token > ; //option to initialize viewer. var options = { env: 'AutodeskProduction',accessToken: token }; //It looks the static function of Viewer does not support ES6 //still use ES5 Autodesk.Viewing.Initializer(options,function onInitialized() { //get the viewer div var viewerDiv = document.getElementById('myViewer'); //initialize the viewer object viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv,{}); //load model one by one in sequence globalPromise(modelArray); }); } //load model by promise globalPromise = (modelArray) => { var _this = this; //each promise function //input the index of model array function promiseEachModel(index) { return new Promise((resolve,reject) => { var modelName = modelArray[index].modelName; var _index = index; //when the document is loaded function _onDocumentLoadSuccess(doc) { console.log(modelName + ': Document Load Succeeded!'); _this.globalDocumentLoad(doc,_onLoadModelSuccess,_onLoadModelError); }; //when the document Failed to be loaded function _onDocumentLoadFailure(viewerErrorCode) { console.error(modelName + ': Document Load Failure,errorCode:' + viewerErrorCode); } //when the model is loaded function _onLoadModelSuccess(model) { console.log(modelName + ': Load Model Succeeded!'); //delegate geometry loaded event _this.viewer.addEventListener( Autodesk.Viewing.GEOMETRY_LOADED_EVENT,_onGeometryLoaded); //map this item with the corresponding model in case of use modelArray[index].modelObj = model }; function _onLoadModelError(viewerErrorCode) { console.error(modelName + ': Load Model Error,errorCode:' + viewerErrorCode); //any error reject(modelName + ' Loading Failed!' + viewerErrorCode); } function _onGeometryLoaded(evt) { //_this.globalGeometryLoaded(modelName,evt.model); _this.viewer.removeEventListener( Autodesk.Viewing.GEOMETRY_LOADED_EVENT,_onGeometryLoaded); console.log(modelName + ' Geometry Loaded!'); resolve(modelName + ' Geometry Loaded!'); } //load the model Autodesk.Viewing.Document.load( modelArray[index].urn,_onDocumentLoadSuccess,_onDocumentLoadFailure); }); //end of new promise } //end of each promise function //build the index array var indexArr = [0,1,2,3]; //proces each promise //refer to http://jsfiddle.net/jfriend00/h3zaw8u8/ function processArray(array,fn) { var results = []; return array.reduce(function(p,item) { return p.then(function() { return fn(item).then(function(data) { results.push(data); return results; }); }); },Promise.resolve()); } //start to process processArray(indexArr,promiseEachModel).then(function(result) { console.log(result); },function(reason) { console.log(reason); }); } //end of function globalPromise //when document is being loaded globalDocumentLoad = (doc,_onLoadModelError) => { //get available viewables var viewables = Autodesk.Viewing.Document.getSubItemsWithProperties( doc.getRootItem(),{ 'type': 'geometry' },true); if (viewables.length === 0) { console.error('Document contains no viewables.'); return; } // Choose the first avialble viewables var initialViewable = viewables[0]; var svfUrl = doc.getViewablePath(initialViewable); var mat = new THREE.Matrix4(); //input the transformation var loadOptions = { placementTransform: mat,globalOffset: { x: 0,y: 0,z: 0 },// to align the models sharedPropertyDbPath: doc.getPropertyDbPath() }; //if this is the first model if (doc.myPath == this.urn_model1) { //load the first model this.viewer.start(svfUrl,loadOptions,_onLoadModelError); } else { //other models this.viewer.loadModel(svfUrl,_onLoadModelError); } } start();