×

只需一步,快速开始

扫描二维码登录本站

本帖最后由 YOUKU3D 于 2019-1-8 09:35 编辑

国内朋友对Autodesk Forge的热情愈发高涨,这不仅因为Forge紧密契合了现在蓬勃发展的智慧互联,BIM,工业4.0,施工管理,运营管理,VR/AR行业的旺盛需求,解决了诸多痛点,也是因为Forge诞生于流行的技术框架,能够和众多新颖,高效,安全的开发方式结合,产生好用,好看又能持续带来业务价值的网络和移动应用。


在支持国内客户的过程中,频繁会被问及四类问题:

刚刚接触Forge的朋友,想快速入门,材料,教程;

常见场景的代码样例,常见问题的诊断技巧;

一些综合应用的代码解析;

离线模型的下载和部署;

坦言之,目前中文方面的材料还很有限,而英文的资料有些朋友一开始不是特别清楚从哪里着手,因此我们曾整理过一个在线PPT,帮助朋友们熟悉一些材料,包含了Forge的概览,Forge应用的一小部分样例,Forge现有几个服务技术的资料链接,Forge问题全球的正式支持方式,和国内的咨询方式(微信群和SegmentFault论坛)。想必各位都比较熟悉了。

我们中国区团队在不断的增加中文的材料。今年计划做的进一步工作有:

制作入门和某些专题的视频课程,以帮助大家快速上手。中英文版本;

继续整理一些问答到SegmentFault,方便大家检索;

在线不定期1小时的答疑和研讨,帮助大家消化一些需求,方向上的问题;

继续根据行业的需求点,写一些模拟样例;

继续收集全球的客户应用案例,分享给大家参考;

同时也欢迎各位有兴趣的朋友,分享自己的心得,材料,案例。社区帮助社区,才会让技术的应用生命力更加强大。
【转载整理自CSDN开发论坛】
对于以上提到的4类常见咨询,将以4篇文章陆续介绍。本系列文章旨在和从事Forge具体编程的朋友分享一点体会。如果您还不了解Forge,或者是产品经理,技术架构师,可通过 Forge技术概览 和 Forge应用案例赏析 做初步的了解。希望此系列能对您Forge的开发历程有些许帮助。若您对有特别的建议和意见,请踩一踩 :)
就上文提到的四类常见咨询内容,本文介绍第二类:常见场景的代码样例,常见问题的诊断技巧。
就上文提到的四类常见咨询内容,本文介绍第一类:刚刚接触Forge的朋友,想快速入门,材料,教程。
Forge是云服务集合的平台,云服务都是Restful形式提供的,调用过程大多在网络应用的服务器端完成,所以若您还不了解Restful,请通过网上材料查看一下。无特别推荐,此类信息已经很多了。由于Restful众多开发语言都支持,因此选用您自己擅长或者业务需要的开发方式即可。另外,选用合适业务的方式搭建服务器,部署服务器。现在网上有很多不错的快速部署工具,例如Heroku,Appharbor。当然还有常见的巨头,AWS,Azure,阿里云等。
而通常大家熟悉的Forge Viewer (网页模型浏览和数据查看,业务对接)是一套JavaScript API,属于客户端的API。也就意味着,您需要熟悉JavaScript的编程。使用Forge Viewer,模型要首先用Forge服务转换浏览器支持的格式,也就是说,后面其实包含了几个服务:Authentication (OAuth),Data Management API,Model Derivative API。
建议先用这个测试网站,按照其步骤说明体验大致的步骤。
20170305205523842.png
在去年的Forge Viewer技术研讨会上,我们的同事罗诗亚做过专门的过程讲解,视频清晰度在优酷上被压缩的厉害,可配合她用到的在线PPT查看。其主要的过程和上面提到的测试体验网站类似。当时Forge Viewer和背后几个技术统称为Viewer and Data。只是名字而已。
20170305205642100.png

通过这些材料,逐步熟悉几个主要的概念:申请app, 开发key & secret, token, bucket, urn, translate, viewer 等。有了这个体会后教学基础后,您就可以开始上手练习了。
如果您已经熟悉模型转换的过程,只是更多关注Forge Viewer客户端的开发,则可以先从我们同事吴忠的课件开始。其分支包括了Forge Viewer一些常见开发内容的代码,例如自定义工具条,操作对象,实现拓展(extension)等。虽然此课件用的Node.js搭建的服务,但主要用来得到token,假设不熟悉Node.js也不用担心,主要关注客户端,借鉴到您的应用实现。

20170305205038371.png

也推荐另外一个类似的课程系列(全英文),用的Node.js + WebPack进行讲解。涵盖了以下内容:
viewer-offline将Forge转换的网页浏览数据部署到自己服务器,通常叫做离线查看(offline)进行查看。这属于中级课程,可先略过
viewer-barebone:无需服务器端代码,需要通过其它工具产生token和模型的urn,填写到JavaScript代码中,实现模型的加载
viewer+server:服务器端完成token的产生工作,其它内容(例如模型上传,转换)通过其它工具完成,填写到JavaScript代码中,实现模型的加载
viewer+server+oss: 服务器端完成token的产生和模型上传工作,其它内容(例如模型转换)通过其它工具完成,实现模型的加载
viewer+server+oss+derivatives: 服务器端完成后端所有工作(token的产生,模型上传,模型转换),客户端实现模型的加载
如果您是想开始Forge其它云服务的过程,例如云端设计自动化(Design Automation),则可以先通过此在线PPT熟悉主要的概念和流程:app,开发key & secret, token,Activity,WorkItem,AppPackage等。此材料链接到了一些英文材料,也可按照指南参考。
其它的服务例如BIM 360, Reality Capture(照片建模)等服务,还在beta阶段。等正式发布了,我们会介绍有关材料。
当有了一定Forge基础后,例如Forge Viewer以及背后的转换过程服务,具体的使用中,必然会遇到这样或那样的问题,先看看是后端的问题(例如token,上传,模转换),还是前端(Forge Viewer)的问题和需求。
对于后端的问题,首先通过StackOverflow(SO), 在autodesk-forge标签下看看有无相关的讨论。还有细化的标签,例如:
autodesk-designautomation:云端设计自动化(DesignAutomation)
autodesk-data-managemen:模型上传下载(DataManagement
autodesk-model-derivative: 模型转换和数据提取服务(ModelDerivative)
在SegmentFault上也有autodesk-forge标签,不方便英文交流的朋友可发帖在这里,我们也会陆续的贴一些常见问题,便于大家中文查询。目前只有一个autodesk-forge标签。
20170305210525706.png
对已前端,例如Forge Viewer,虽然SO上有autodesk-viewer标签,但更建议上Autodesk-Forge的Github代码库查询已经有的代码样例,看看是否已经有代码实现了您需要的场景。两个工具特别推荐:
Forge Viewer 测试器:此代码有对应的测试网站。包括了多个基本Viewer操作的场景,例如:改变构件颜色,操作相机,操作视图状态,构件可见性,查找构件等等,更酷的是,对应的代码也直接可以显示出来,方便理解和测试。
另外一个代码库是Viewer 功能扩展包,这里包含了几十个Viewer的可能需要的应用场景,实现较为综合的功能,例如,变换构件位置(旋转,),导入额外的模型数据,为构件贴图,获取构件的三角面片等等,所以,请务必在这里先查查是否有代码样例了。
为了让这些扩展的功能得以生动体现,我们还部署了一个测试网站,,加载一个模型,有个按钮弹出扩展管理对话框,点击某个扩展,就可以去操作对应的功能,如果有兴趣,点击source,即能导向对应的源代码。

20170305211053366.png
假设这些地方没看到样例,或者您是遇到特定的问题,错误了,和上面类似,在SO或SegmentFault上查询。
或者这些都没找到头绪,由于是客户端代码,可以尝试重载一些Viewer提供的方法(Viewer3D.js),达到自己的需求。非常建议大家可以多分析和调试Viewer3D.js,它基本上是基于Three.js做了封装工作,其内容都是看得到的,尤其做离线版过程的时候,完全可以自己定制和扩展很多内容。
下载Viewer3D.js, 最简单的方式就是在浏览器敲进去地址,例如:
20170305211423139.png
https://developer.api.autodesk.c ... viewers/viewer3D.js  这样获取当前版本,另存下来即可

https://developer.api.autodesk.c ... /viewer3D.js?v=2.7.*,这样获取某特定版本,另存下
---------------------
就上文提到的四类常见咨询内容,本文介绍第三类: 一些综合应用的代码解析。
可能您有一些综合的需求,不是三两个功能能够描述,那么先在Forge样例库里这里查看是否有合适的综合样例,这里的样例都有对应的源代码。因为综合,所以很难用简单的描述来讲解怎么搭建这样的需求来满足您的需要。建议找到代码中核心的部分,看看其流程和思路,过滤出一些单元功能模块,函数,慢慢的嫁接到您的应用程序。
20170305213145274.png
有时,可能您是在其他客户的样例中看到某些不错的应用,但没有源码,毕竟这是客户自己的知识产权。对于后端过程,算法,那无法看到。而前端的应用,则可以在浏览器调试窗口看到下载到本地的代码,找到核心部分,分析其思路,再写出自己的代码。友情提醒:不要随意拷贝拿来用,注意代码的版权声明。有时Js代码做了压缩或混淆,可以通过一些工具得到略微格式化的代码,便于阅读。例如:http://tool.oschina.net/codeformat/js/
20170305213030506.png


就上文提到的四类常见咨询内容,本文介绍第四类:离线模型的下载和部署。
这是个经典问题,主要和Forge模型上载,转换,网页查看模型几个API有关,尤其国内朋友最为关心。所以单独提出来介绍。
默认情况下,Forge转换后的数据放在Forge云端(目前在AWS美国),所以就有网络访问性能的考虑。转换后的数据在云端都有唯一的地址,Forge也允许下载,对于obj,stl等格式,下载很直接,这里有两篇文章介绍:
转换模型为OBJ并下载
转换模型为STL并下载
而挑战是SVF格式,也就支持网页浏览的格式。SVF不是单一文件,是一个数据包,包括了构件几何信息,属性包,有一个.svf的清单文件(二维模型是.F2D)。而Forge Viewer的JavaScript库对此数据进行解析和渲染。例如,下图是前面提到的Forge Viewer 课程系列(全英文)中使用到的离线数据包。目前,SVF数据格式并没有文档说明,不过,只要按清单文件下载到这些数据,用Viewer3D.js和其辅助*.js解析加载即可,倒不用一定要知道数据格式。而使用Forge Viewer相关js代码前提是数据包是由Forge的数据提取和转换服务而来。
20170305213845205.png
而我们部门也提供了一个工具http://extract.autodesk.io/ ,专门用来上传,下载离线SVF包,而且这个工具还给您搭建了一个很简单的测试框架(Node.js和PHP两种)。
20170305224335924.png
很多朋友对于这个工具实现的转换下载非常感兴趣,但该工具很综合,流程较为复杂,不太容易弄清楚其逻辑。而由于相关下载过程现在并不是发布的云服务,所以没有文档以说明,所以我们的建议是,如果咱不能能研究清楚逻辑,就直接使用其转换结果即可,不用花太多时间在这上面。等待文档完善,或对应的SDK封装了下载端口,使用就更为方便了。
但是此工具网站是公开的,请不要上载您的机密模型,假设不慎上载了,可以通过删除按钮及时删掉。更建议把其源代码下载部署,在您的本地端去上载转换,这样。您的模型只需要和Forge云服务通信,保证了只有您能访问这些模型数据。
最后,注意:使用Forge Viewer客户端的JavaScript代码,必须是从Forge数据提取和转换服务得到的的数据。
作者:autodeskinventorapi
来源:CSDN
原文:https://blog.csdn.net/autodeskin ... le/details/60478620
版权声明:本文为博主原创文章,转载请附上博文链接!
关于Autodesk Forge Viewer的离线实现,官方已经允许将SVF及相关文档导出,允许用户将SVF等文档部署到私有服务器上,但是本文讨论的是另外一种需求,我们遇见的客户需求是,用户在移动环境中,可能无法接入网络(例如在矿井、仓库等无网络环境)或者不允许大的数据传输等情况,这时我们需要考虑将SVF等文件持久化到手机Sqlite数据库、手机设备的文件系统、浏览器的储存对象(LocalStorage)中。
实现的思路是:
修改Viewer的前端代码,在线模式下,将Viewer像服务器发送的请求返回结果实现本地的持久化。
开发环境:APP是利用Cordova开发的,前端框架使用的是Sencha Touch。
  1. <font size="3"><p>wgs.js</p><p>            worker.addEventListenerWithIntercept = function (listener) {</p><p><span style="white-space:pre">                                </span>var me = this;</p><p><span style="white-space:pre">                                </span>//这里APP是利用Cordova开发的,前端框架使用的是Sencha Touch</p><p><span style="white-space:pre">                                </span>var forgeFileStore  = Ext.getStore('forgeFileStore');</p><p><span style="white-space:pre">                                </span></p><p>                var callbackFn = function callbackFn(ew) {</p><p>                    if (worker.checkEvent(ew)) return;</p><p><span style="white-space:pre">                                        </span>//Online时储存worker传过来的svf文件到手机。</p><p><span style="white-space:pre">                                        </span>if(ew.data.debug == "response"){</p><p><span style="white-space:pre">                                                </span>forgeFileStore.addFile(ew.data.ckMessage.url);</p><p><span style="white-space:pre">                                        </span>}else if(ew.data.debug == "request"){</p><p><span style="white-space:pre">                                                </span>forgeFileStore.addCount(ew.data.ckMessage.url);</p><p><span style="white-space:pre">                                        </span>}</p><p>                    listener(ew);</p><p>                };</p><p>                if (!interceptListeners) interceptListeners = [];</p><p>                interceptListeners.push({ arg: listener, callback: callbackFn });</p><p>                worker.addEventListener('message', callbackFn, false);<span style="white-space:pre">                </span></p><p>                return callbackFn;</p><p>            };</p><div>
  2. </div></font>
复制代码
在离线模式下,将Web请求修改为读取持久化的数据实现离线的目标
  1. <font size="3">wgs.js
  2.                                         this.WORKER_FETCHING_SCRIPT = true;
  3.                                         var forgeFileStore  = Ext.getStore('forgeFileStore');
  4.                                         if(!forgeFileStore.deviceIsOnline){
  5.                                                 _this.WORKER_FETCHING_SCRIPT = false;
  6.                                                 window.URL = window.URL || window.webkitURL;
  7.                                                 var callbacks = _this.WORKER_FETCHING_CALLBACKS.concat();
  8.                                                 _this.WORKER_FETCHING_CALLBACKS = [];
  9.                                                 for (var i = 0; i < callbacks.length; ++i) {
  10.                                                         callbacks[i].successCB && callbacks[i].successCB();
  11.                                                 };
  12.                                                 _this.WORKER_OFFLINEDATA_URL = forgeFileStore.getStaticFiles(scriptURL);
  13.                                         }else{
  14.                                                 xhr.send();
  15.                                         }</font>
复制代码
经过上述的对Viewer的相关定制,可实现Viewer真正的单机离线应用。
大家如果参加过我们的活动,你应该已经听过看过不少关于View and Data Web Service的例子里,如果还没有的话,请看看下面这几篇:
http://www.cnblogs.com/junqilian/category/594048.html
如果你已经了解了Viewer,那有没有兴趣练练手,把这样酷的三维模型嵌入到你自己的网页中呢?那么开始练练手吧。
•体验代码资料下载:http://pan.baidu.com/s/15zZMQ
在下载解压缩后你应该可以看到下面的目录结构,其中handsout.docx 是联系参考文档,FirstViewerWebApp是一个未完成的半成品,你可以在这个基础之上继续工作,如果遇到问题,可以参考FirstViewerWebApp_Completed 工程的实现。
微信图片_20190108092440.png
好了,开始演练吧。
除此之外,你可以重点看一下下面两个例子,
我们本着开放共享的精神向大家开放源代码,也希望得到大家的帮助,您可以fork我们repo,如果您发现示例代码中有bug或者您有更好的改进,希望您也能提交pull request反馈给我们,让我们把这些示例更完善。
致谢!
作者:峻祁连
邮箱:junqilian@163.com
出处:http://junqilian.cnblogs.com
转载请保留此信息。





了解Autodesk Forge
通过我们的快速入门指南,了解身份验证,数据管理,文件翻译和模型渲染的基础知识。
它是什么?
Forge使公司能够利用设计和工程数据来开发定制软件应用程序以及用于制造,媒体/娱乐,建筑,工程和施工的连接工作流程。

l  直接在浏览器中查看3D模型:Viewer允许您直接在浏览器中以50多种格式嵌入,交互和检索有关设计文件的元数据,而无需安装额外的软件。
l  集中管理数据:Data Management API允许您通过A360,Fusion和对象存储服务访问您的数据。
l  将您的设计文件转换为可发挥其潜力的格式:使用模型衍生API为50种不同的行业标准格式的查看器准备文件,提取几何图形,检索元数据等等。
本教程中的内容是什么?
l  开始编码之前:创建并激活您的帐户。
l  工具:创建使用Autodesk Forge的Web应用程序所需的开发工具。
l  OAuth:关于安全性和身份验证的几句话。
l  以下教程的分步教程:
2  查看您的模型:在网络上上传和展示3D模型。
2  查看BIM 360和Fusion模型:访问并在您自己的web应用程序上显示BIM 360和Fusion模型。
2  运行和调试:在本地执行代码并提示和技巧。
2  查看器扩展:将按钮和面板添加到查看器。
2  部署:AWS,Heroku和AppHarbor分步部署。
准备好开始了吗?

开始编码之前
Autodesk帐户

您的Autodesk Forge帐户是您的主要身份。

创建您的Forge帐户
进入Forge开发者门户网站,点击“注册”按钮创建一个帐户或“登录”以使用现有帐户。如果您创建了新帐户,请务必点击验证电子邮件中将发送给您的链接。
激活订阅
在使用任何付费API(例如ModelDerivative)之前,您需要激活您的试用版。 在右上角,你会看到你的名字。 点击展开菜单并转到我的订阅。 在打开的页面上,点击START FREE TRIAL。 而已。
创建一个应用
在右上角,你会看到你的名字。 点击展开菜单并转到我的应用程序。 点击“创建应用程序”按钮。

选择你要使用的API(你可以选择所有的现在)。 输入您的应用程序名称和描述,然后输入回调URL:http://localhost:3000 / api / forge / callback / oauth(本教程不会使用此回调,但这是在其他Autodesk Forge示例wink上使用的URL)

一旦你建立了一个应用程序,你将在你新创建的应用程序页面中看到一个客户端ID和客户端密码。您将在所有其他OAuth流程中使用这些流程,并且最终完成本网站上的所有其他教程!

Ø  不要分享你的客户秘密,这应该保密。
工具
本节介绍如何准备机器以使用Autodesk Forge或任何其他云API。 如果您已经有了偏好设置的IDE,则可以跳至验证。

选择你的语言:NodeJS | .NET | 转到| PHP |Java的

安装NodeJS引擎来运行你的代码。 安装NPM依赖关系管理器来安装软件包。

现在我们需要一个IDE来编写代码。 有很多选项,本教程将使用Visual Studio代码。

对于本教程,请使用所有默认安装选项。
OAuth
OAuth,尤其是OAuth2,是整个Forge平台中用于基于标记的身份验证和授权的开放标准。
两腿与三腿
了解有关双腿使用的详细信息查看您的模型教程和View BIM 360和Fusion模型教程中使用的三腿工作流程。

领域
范围是在令牌上设置的权限,该令牌可以用作该令牌的上下文。例如,具有data:read范围的令牌可以读取Forge生态系统内的数据,并可用于需要该范围的那些端点。没有这个范围的令牌将被拒绝访问这些端点。(单个端点参考页列出了所需的范围。)

范围有两个主要功能:

隐私和控制:在三足鼎立的情况下,它们充当一种机制来请求和确保以特定方式代表最终用户行事的权限。
安全性:无论是双腿还是三腿,他们都可以确保如果您失去对令牌的控制权,就不会误用它来访问不属于它的资源。
学到更多

公共和内部令牌
本教程将使用两种类型的访问令牌:public和internal。公共用于Viewer,它运行并需要客户端上的访问令牌。这种情况有一个特殊的范围:可见:读。

现在在服务器端,我们需要启用写入,所以内部将使用bucket:create,bucket:read,data:read,data:create和data:write。

不知道要遵循哪个教程?

回答这个问题:你想访问和查看的文件在哪里?

如果在您的电脑或其他地方,然后查看您的模型。如果模型在任何BIM 360(团队,设计或文档)或Fusion Team上,则查看BIM 360和Fusion模型。

查看您的模型

本教程将指导您使用以下用户界面创建Web应用程序:在左侧列出您的存储桶和对象,在右侧使用3D查看器查看它们。
要查看您的模型,您需要执行以下步骤:

创建一个服务器<<首次开发者? 你应该从这里开始眨眼
认证
上传到OSS
翻译文件
在查看器中显示
创建一个服务器
您的客户ID和密码应受到保护并保密,因为您的所有文件都将被绑定到您的帐户。 对于Web应用程序,请将其保存在服务器上。本节演示如何准备创建本地开发服务器。

创建一个新项目(NodeJS)

在你的机器上创建一个文件夹,不要使用空格并避免使用特殊字符。对于本教程,我们使用forgesample。

打开可视代码,然后进入菜单文件并选择打开(MacOS)或打开文件夹(Windows)并选择新创建的文件夹。

现在我们需要终端,进入菜单视图>>集成终端。 窗口应该出现在底部。 键入以下命令并按照步骤进行操作。 为了与其他Forge示例保持一致,在提示输入点时:使用start.js。

npm init

这将创建package.json文件,该文件定义了我们项目将使用的包。 学到更多。

安装软件包
默认情况下,NodeJS项目为空,所以我们需要使用npm install来安装一些软件包。让我们从一个基本的express服务器,用于JSON处理的body-parser,用于文件上传的Muller,当然还有Autodesk Forge开始。

Run one npminstall at a time. 一次运行一个npm安装。

npm install express --save
npm install forge-apis --save
npm install multer --save
npm install cookie-session --save
npm install body-parser –save

The --save parameterindicates that it should be saved on the package.json file. --save参数表明它应该保存在package.json文件中。

最后打开package.json,并在“脚本”中添加“start”:“node start.js”行。 现在你的文件夹应该有一个node_modules文件夹,你的package.json应该是这样的:

{
  "name": "forgesample",
  "version": "1.0.0",
  "description": "",
  "main": "start.js",
  "scripts": {
    "start": "node start.js",
    "test": "echo \"Error: no test specified\"&& exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.2",
    "cookie-session": "^2.0.0-beta.3",
    "express": "^4.16.2",
    "forge-apis": "^0.4.1",
    "multer": "^1.3.0"
  }
}

The version number (e.g.forge-apis 0.4.1) may vary, this was the latest version when tutorial wascreated. 版本号(例如forge-apis 0.4.1)可能会有所不同,这是创建教程时的最新版本。

文件和文件夹
要创建新文件夹或文件,请右键单击左侧的“资源管理器”区域,然后选择新建文件夹或新建文件。

为了与其他Forge示例保持一致,请为所有服务器端文件创建一个/ server /文件夹,为所有客户端文件创建一个/ www /。

在这一点上,你的项目应该是这样的:
file:///C:/TEMP/msohtmlclip1/01/clip_image002.jpg
launch.json
这个文件向VisualCode指出我们应该如何运行我们的项目。 转到菜单Debug >> AddConfiguration ...,然后在顶部出现的Select Environment小窗口上选择NodeJS,并在创建的/.vscode/launch.json文件中输入以下内容:

Note you need to enter your ForgeClient ID & Secret at theindicated space. 请注意,您需要在指定的位置输入您的Forge客户ID和密码。

{    // Use IntelliSense to learn about possible attributes.    // Hover to view descriptions of existing attributes.    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387    "version": "0.2.0",    "configurations": [        {            "type": "node",            "request": "launch",            "name": "Launch Program",            "program": "${workspaceFolder}/start.js",            "env": {                "FORGE_CLIENT_ID": "your id here",                "FORGE_CLIENT_SECRET": "your secret here",                "FORGE_CALLBACK_URL": "http://localhost:3000/api/forge/callback/oauth"            }        }    ]}
It's important to define ID & Secret as environment variables so our project can, later, bedeployed online. More on this later, on Deployment. IDSecret定义为环境变量非常重要,这样我们的项目可以稍后在线部署。 稍后将在部署上详细介绍。

start.js
在根文件夹中,使用以下命令创建/start.js文件:

File names are case-sensitive for somedeployments, like Heroku. For this tutorial, let's use lower-case. 文件名对于某些部署区分大小写,如Heroku 对于本教程,我们使用小写。

'use strict'; var app = require('./server/server'); // start servervar server = app.listen(app.get('port'), function () {  if (process.env.FORGE_CLIENT_ID == null || process.env.FORGE_CLIENT_SECRET == null)    console.log('*****************\nWARNING: Forge Client ID & Client Secret not defined as environment variables.\n*****************');   console.log('Starting at ' + (new Date()).toString());  console.log('Server listening on port ' + server.address().port);});
这个文件的目的是确保我们运行的服务器是我们所期望的。 稍后再说。
server.js
现在,在/ server /文件夹下,创建一个名为server.js的文件:
'use strict';

var express =require('express');
var app = express();

// prepare server routing
app.use('/', express.static(__dirname + '/../www')); // redirect static calls
app.set('port', process.env.PORT || 3000); // main port

// cookie-based session
var cookieSession =require('cookie-session')
app.use(cookieSession({
    name:'forgesession',
    keys:['forgesecurekey'],
    secureprocess.env.NODE_ENV == 'production'),
    maxAge:14 * 24 * 60 * 60 * 1000 // 14 days, same as refresh token
}))

// prepare our API endpoint routing
loadRoute('./oauthtoken');
// viewmodels sample
loadRoute('./oss');
loadRoute('./modelderivative');
// view hub models sample
loadRoute('./datamanagement');
loadRoute('./user');

function loadRoute(path) {
    try {
       require.resolve(path);
        var m = require(path);
       app.use('/', m);
    } catch (e) { }
}

module.exports = app;

此文件启动快速服务器并提供静态文件(例如html)并路由API请求。

config.js
在/ server /下创建一个名为config.js的文件,其中包含以下内容:
'use strict';

// Autodesk Forge configuration
module.exports = {
  // set environment variables or hard-code here
credentials: {
   client_id: process.env.FORGE_CLIENT_ID,
   client_secret: process.env.FORGE_CLIENT_SECRET,
   callback_url: process.env.FORGE_CALLBACK_URL
  },

  // Required scopes for your application on server-side
scopeInternal: ['bucket:create', 'bucket:read', 'data:read','data:create', 'data:write'],
  // Required scope of the token sent to the client
scopePublic: ['viewables:read']
};

我们在这里定义ENV变量,在运行我们的Express服务器时,这些变量的值将用于连接我们需要的不同Autodesk Forge服务。

最后我们看到有两个关于范围的定义。 内部范围为我们的访问令牌提供了使用ForgeWeb服务(服务器端)的不同服务的正确权限。 本教程致力于使用查看器,我们只需要公开的“可查看:读取”范围。

项目已准备就绪! 此时你的项目应该有:
file:///C:/TEMP/msohtmlclip1/01/clip_image003.png
package-lock.json是由Visual Code创建的,不用担心。

OAuth 2腿

在正式的OAuth术语中,要在Forge平台上完成双重身份验证,需要使用“客户端证书”授予类型。

这意味着您的应用程序直接与Forge平台进行通信以进行身份验证和访问资源。如果它是一个Web应用程序,最终用户不会直接意识到这些服务器到服务器之间的通信,因为它们都没有通过Web浏览器传递。 学到更多。

访问Forge上的任何资源都需要身份验证。 双腿令牌授予访问您的应用程序信息的权限。

验证(NodeJS)
对于基本的OAuth实现,我们需要2个文件。
oauthtoken.js
创建一个/server/oauthtoken.js文件。 该文件负责创建快速路由器以公开端点。
'use strict';

// web framework
var express =require('express');
var router =express.Router();

// Forge NPM
var forgeSDK =require('forge-apis');

// actually perform the token operation
var oauth = require('./oauth');

// Endpoint to return a 2-legged access token
router.get('/api/forge/oauth/token', function (req, res) {
   oauth.getTokenPublic().then(function (credentials) {
       res.json({ access_token: credentials.access_token, expires_in:credentials.expires_in });
    }).catch(function (error) {
       console.log('Error at OAuth Token:');
       console.log(error);
       res.status(500).json(error);
    });
});

module.exports = router;

oauth.js
现在创建一个/server/oauth.js文件,它实际上会向Forge请求访问令牌。 这将在本教程的其他部分重复使用。
'use strict';

// Forge NPM
var forgeSDK =require('forge-apis');

// Forge config information, such as client IDand secret
var config =require('./config');

// Cache of the access tokens
var _cached = [];

module.exports = {
    getTokenPublic:function () {
        return this.OAuthRequest(config.scopePublic, 'public');
    },

   getTokenInternal: function () {
        return this.OAuthRequest(config.scopeInternal, 'internal');
    },

   OAuthRequest: function (scopes, cache) {
        var client_id = config.credentials.client_id;
        var client_secret =config.credentials.client_secret;
        var forgeOAuth = this.OAuthClient(scopes);

        return new Promise(function (resolve, reject) {
           if (_cached[cache] != null && _cached[cache].expires_at > (new Date()).getTime()) {
               resolve(_cached[cache]);
               return;
           }

           var client_id =config.credentials.client_id;
           var client_secret = config.credentials.client_secret;

           //new forgeSDK.AuthClientTwoLegged(client_id,client_secret, scopes);
           forgeOAuth.authenticate()
               .then(function (credentials) {
                    _cached[cache] =credentials;
                    var now = new Date();
                    _cached[cache].expires_at =(now.setSeconds(now.getSeconds() + credentials.expires_in));
                    resolve(_cached[cache]);
               })
               .catch(function (error) {
                    console.log('Error at OAuthAuthenticate:');
                    console.log(error);
                    reject(error)
               });
        })
    },

   OAuthClient: function(scopes) {
        var client_id = config.credentials.client_id;
        var client_secret =config.credentials.client_secret;
        if (scopes == undefined) scopes =config.scopeInternal;
        return new forgeSDK.AuthClientTwoLegged(client_id, client_secret, scopes);
    }
}

为了避免为每个最终用户请求获取新的访问令牌,这会增加不必要的延迟,我们将它们缓存在全局变量中。 请注意,我们仍然需要在expires_in秒后刷新它

在用户之间共享访问令牌仅在这种情况下有效,其中所有用户都访问相同的信息(双腿)。如果您的应用使用的是每用户数据(3段),请勿使用此方法。

数据管理(OSS)
在OSS中,文件以桶形式存储为对象。 除了为您的应用程序提供从更广泛的Forge生态系统下载数据的功能外,它还提供了管理应用程序自己的存储桶和对象(包括创建,列出,删除,上传和下载)的功能。

每个存储桶还具有确定对象保留时间的保留策略:

l  瞬态:类似高速缓存的存储只持续24小时,对于短暂物体很理想。 对于本教程,让我们使用这个策略。
l  临时:保存30天的存储。
l  持久性:存储在删除之前一直存在。
在本节中,让我们创建几个端点来创建存储桶,上传文件和列出存储桶和对象。

上传文件到OSS(NodeJS)
在这一部分,我们实际上需要3个特征:
1.     创建桶
2.     列出存储桶和对象(文件)
3.     上传对象(文件)
oss.js
使用以下内容创建/server/oss.js文件:
'use strict'; // web frameworkvar express = require('express');var router = express.Router(); // Forge NPMvar forgeSDK = require('forge-apis'); // handle json requestsvar bodyParser = require('body-parser');var jsonParser = bodyParser.json(); // actually perform the token operationvar oauth = require('./oauth'); // Return list of buckets (id=#) or list of objects (id=bucketKey)router.get('/api/forge/oss/buckets', function (req, res) {    var id = req.query.id;    if (id === '#') { // root        // in this case, let's return all buckets        var bucketsApi = new forgeSDK.BucketsApi();        oauth.getTokenInternal().then(function (credentials) {            bucketsApi.getBuckets({ limit: 100 }, oauth.OAuthClient(), credentials).then(function (buckets) {                var list = [];                buckets.body.items.forEach(function (bucket) {                    list.push({                        id: bucket.bucketKey,                        text: bucket.bucketKey,                        type: 'bucket',                        children: true                    })                })                res.json(list);            });        }).catch(function (error) {            console.log('Error at Get Buckets:');            console.log(error);            res.status(500).json(error);        });    }    else {        // as we have the id (bucketKey), let's return all objects        var objectsApi = new forgeSDK.ObjectsApi();        oauth.getTokenInternal().then(function (credentials) {            objectsApi.getObjects(id, {}, oauth.OAuthClient(), credentials).then(function (objects) {                var list = [];                objects.body.items.forEach(function (object) {                    list.push({                        id: object.objectId.toBase64(),                        text: object.objectKey,                        type: 'object',                        children: false                    })                })                res.json(list);            });        }).catch(function (error) {            console.log('Error at Get Objects:');            console.log(error);            res.status(500).json(error);        });    }}); // Create a new bucket router.post('/api/forge/oss/buckets', jsonParser, function (req, res) {    oauth.getTokenInternal().then(function (credentials) {        var bucketsApi = new forgeSDK.BucketsApi();        var postBuckets = new forgeSDK.PostBucketsPayload();        postBuckets.bucketKey = req.body.bucketKey;        postBuckets.policyKey = "transient"; // expires in 24h         bucketsApi.createBucket(postBuckets, {}, oauth.OAuthClient(), credentials).then(function (buckets) {            res.status(200).end();        }).catch(function (error) {            if (error.statusCode && error.statusCode == 409)                res.status(409).end();            else {                console.log('Error at OSS Create Bucket:');                console.log(error);                res.status(500).json(error);            }        });    });}); // handle file uploadvar multer = require('multer')var upload = multer({ dest: './tmp' }) // Receive a file from the client and upload to the bucketrouter.post('/api/forge/oss/objects', upload.single('fileToUpload'), function (req, res) {    oauth.getTokenInternal().then(function (credentials) {        var bucketKey = req.body.bucketKey;        var fs = require('fs');        fs.readFile(req.file.path, function (err, filecontent) {            var objects = new forgeSDK.ObjectsApi();            objects.uploadObject(bucketKey, req.file.originalname, filecontent.length, filecontent, {}, oauth.OAuthClient(), credentials)                .then(function (object) {                    res.end();                }).catch(function (error) {                    console.log('Error at Upload Object:');                    console.log(error);                    res.status(500).end();                });        })    });}); String.prototype.toBase64 = function () {    return new Buffer(this).toString('base64');}; module.exports = router;
当我们计划支持jsTree时,我们的GEToss / buckets需要返回句柄id querystring参数,并在id =#时返回桶,并且给定bucketKey的对象作为id = bucketKey传递。 上传端点使用Muller包来处理文件上传。它将文件保存在我们的服务器上(例如在/ tmp /文件夹下),以便稍后上传到伪造文件。

注意我们如何重用/server/oauth.js文件在所有函数上调用.getTokenInternal()。

可以将客户端(浏览器)上的文件直接上传到Autodesk Forge,但需要向客户端提供一个写入启用的访问令牌,该令牌不是安全的。

翻译文件

模型衍生API使用户能够以不同的格式表示和共享他们的设计,并提取有价值的元数据。

在这一节中,让我们调用POST Job开始翻译过程。 请注意,此端点是异步的,并启动在后台运行的进程,而不是保持打开的HTTP连接直到完成。

翻译模型(NodeJS)

要翻译一个文件,我们只需要一个端点。

modelderivative.js
使用以下内容创建/server/modelderivative.js文件:
'use strict'; // web frameworkvar express = require('express');var router = express.Router(); // Forge NPMvar forgeSDK = require('forge-apis'); // handle json requestsvar bodyParser = require('body-parser');var jsonParser = bodyParser.json(); // actually perform the token operationvar oauth = require('./oauth'); // Create a new bucket router.post('/api/forge/modelderivative/jobs', jsonParser, function (req, res) {    oauth.getTokenInternal().then(function (credentials) {        // prepare the translation job payload        var postJob = new forgeSDK.JobPayload();        postJob.input = new forgeSDK.JobPayloadInput();        postJob.input.urn = req.body.objectName;        postJob.output = new forgeSDK.JobPayloadOutput(            [new forgeSDK.JobSvfOutputPayload()]        );        postJob.output.formats[0].type = 'svf';        postJob.output.formats[0].views = ['2d', '3d'];         // create the derivative API         var derivativesApi = new forgeSDK.DerivativesApi();        // post the job        derivativesApi.translate(postJob, {}, oauth.OAuthClient(), credentials)            .then(function (data) {                res.status(200).end();            }).catch(function (e) {                console.log('Error at Model Derivative job:');                console.log(e);                res.status(500).json({ error: e.error.body })            });    });}); module.exports = router;
作业端点接收bucketKey和objectName并发布翻译作业以提取模型的2D和3D视图。

总结一下,在这一点上你的NodeJS项目应该是这样的:

file:///C:/TEMP/msohtmlclip1/01/clip_image004.png
查看器
Viewer是一个客户端库,因此是纯HTML5和JavaScript。 但是每个服务器端实现都有一些提示:

客户端文件(NodeJS)
我们的NodeJS服务器被配置为从/www /文件夹提供文件。 让我们这样组织吧:

l  / www /:.html
l  / www / js:.js
l  / www / css:.css
下图显示了它(在下一节创建文件之后)
file:///C:/TEMP/msohtmlclip1/01/clip_image005.png
查看器(客户端)

让我们在客户端创建我们需要的4个文件:

index.html
这是您的应用的入口点。 对于此示例,我们将使用jQuery进行DOM操作,使用Bootstrap进行样式设置,并使用jsTree列出存储桶和对象。 所有这些图书馆都来自CDN(内容交付网络)。

当然,还有Autodesk Forge查看器库:viewer3d.min.js,three.min.js和style.min.css。

创建一个index.html文件:
<!DOCTYPE html><html><head>  <title>Autodesk Forge Tutorial</title>  <meta charset="utf-8" />  <!-- Common packages: jQuery, Bootstrap, jsTree -->  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>  <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>  <script src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" />  <!-- Autodesk Forge Viewer files -->  <link rel="stylesheet" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/style.min.css?v=v4.0" type="text/css">  <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/three.min.js"></script>  <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/viewer3D.min.js?v=v4.0"></script>  <!-- this project files -->  <link href="css/main.css" rel="stylesheet" />  <script src="js/ForgeTree.js"></script>  <script src="js/ForgeViewer.js"></script></head><body>  <!-- Fixed navbar by Bootstrap: https://getbootstrap.com/examples/navbar-fixed-top/ -->  <nav class="navbar navbar-default navbar-fixed-top">    <div class="container-fluid">      <ul class="nav navbar-nav left">        <li>          <a href="http://developer.autodesk.com" target="_blank">            <img alt="Autodesk Forge" src="//developer.static.autodesk.com/images/logo_forge-2-line.png" height="20">          </a>        </li>      </ul>    </div>  </nav>  <!-- End of navbar -->  <div class="container-fluid fill">    <div class="row fill">      <div class="col-sm-4 fill">        <div class="panel panel-default fill">          <div class="panel-heading" data-toggle="tooltip">            Buckets & Objects            <span id="refreshBuckets" class="glyphicon glyphicon-refresh" style="cursor: pointer"></span>            <button class="btn btn-xs btn-info" style="float: right" id="showFormCreateBucket" data-toggle="modal" data-target="#createBucketModal">              <span class="glyphicon glyphicon-folder-close"></span> New bucket            </button>          </div>          <div id="appBuckets">            tree here          </div>        </div>      </div>      <div class="col-sm-8 fill">        <div id="forgeViewer"></div>      </div>    </div>  </div>  <form id="uploadFile" method='post' enctype="multipart/form-data">    <input id="hiddenUploadField" type="file" name="theFile" style="visibility:hidden" />  </form>  <!-- Modal Create Bucket -->  <div class="modal fade" id="createBucketModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">    <div class="modal-dialog" role="document">      <div class="modal-content">        <div class="modal-header">          <button type="button" class="close" data-dismiss="modal" aria-label="Cancel">            <span aria-hidden="true">×</span>          </button>          <h4 class="modal-title" id="myModalLabel">Create new bucket</h4>        </div>        <div class="modal-body">          <input type="text" id="newBucketKey" class="form-control"> For demonstration purposes, objects (files) are           NOT automatically translated. After you upload, right click on          the object and select "Translate".        </div>        <div class="modal-footer">          <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>          <button type="button" class="btn btn-primary" id="createNewBucket">Go ahead, create the bucket</button>        </div>      </div>    </div>  </div></body></html>
main.css
CSS是一种描述HTML文档样式的语言。在W3Schools了解更多信息。 对于本教程,使用以下命令在css文件夹下创建一个main.css:

html, body {  min-height: 100%;  height: 100%;} .fill {  height: calc(100vh - 100px);} body {  padding-top: 60px; /* space for the top nav bar */  margin-right: 30px;} #appBuckets {  overflow: auto;  width: 100%;  height: calc(100vh - 150px);} #forgeViewer {  width: 100%;}
ForgeTree.js
该文件将处理列出您所有存储桶的树视图。 在js文件夹下,使用以下内容创建一个ForgeTree.js文件:


$(document).ready(function () {
prepareAppBucketTree();
$('#refreshBuckets').click(function () {
   $('#appBuckets').jstree(true).refresh();
  });

$('#createNewBucket').click(function () {
   createNewBucket();
  });

$('#createBucketModal').on('shown.bs.modal', function () {
   $("#newBucketKey").focus();
  })
});

function createNewBucket() {
  var bucketKey = $('#newBucketKey').val();
  var policyKey = $('#newBucketPolicyKey').val();
jQuery.post({
    url:'/api/forge/oss/buckets',
    contentType: 'application/json',
    data:JSON.stringify({ 'bucketKey': bucketKey, 'policyKey': policyKey }),
   success: function(res) {
     $('#appBuckets').jstree(true).refresh();
     $('#createBucketModal').modal('toggle');
    },
    error: function (err) {
      if (err.status == 409)
       alert('Bucket already exists - 409: Duplicated')
     console.log(err);
    }
  });
}

functionprepareAppBucketTree() {
$('#appBuckets').jstree({
    'core':{
     'themes': { "icons": true },
      'data': {
       "url": '/api/forge/oss/buckets',
       "dataType": "json",
       'multiple': false,
       "data": function (node) {
          return { "id": node.id };
        }
      }
    },
   'types': {
     'default': {
       'icon': 'glyphicon glyphicon-question-sign'
      },
      '#':{
       'icon': 'glyphicon glyphicon-cloud'
      },
     'bucket': {
       'icon': 'glyphicon glyphicon-folder-open'
      },
     'object': {
       'icon': 'glyphicon glyphicon-file'
      }
    },
   "plugins": ["types", "state","sort", "contextmenu"],
   contextmenu: { items: autodeskCustomMenu }
}).on('loaded.jstree', function () {
   $('#appBuckets').jstree('open_all');
}).bind("activate_node.jstree", function (evt, data) {
    if (data != null && data.node != null && data.node.type == 'object') {
     $("#forgeViewer").empty();
      var urn = data.node.id;
     getForgeToken(function (access_token) {
       jQuery.ajax({
         url: 'https://developer.api.autodesk.com/modelderivative/v2/designdata/'+ urn + '/manifest',
         headers: { 'Authorization': 'Bearer ' + access_token },
         success: function(res) {
           if (res.status ==='success') launchViewer(urn);
           else$("#forgeViewer").html('The translation job still running: ' +res.progress + '. Please try again in a moment.');
         },
         error: function (err) {
           var msgButton = 'This fileis not translated yet! ' +
              '<button class="btn btn-xsbtn-info"><spanclass="glyphicon glyphicon-eye-open"></span> ' +
             'Start translation</button>'
           $("#forgeViewer").html(msgButton);
          }
        });
      })
    }
  });
}

functionautodeskCustomMenu(autodeskNode) {
  var items;

  switch (autodeskNode.type) {
    case "bucket":
      items= {
       uploadFile: {
         label: "Upload file",
         action: function() {
           var treeNode = $('#appBuckets').jstree(true).get_selected(true)[0];
           uploadFile(treeNode);
         },
         icon: 'glyphicon glyphicon-cloud-upload'
        }
      };
      break;
    case "object":
      items= {
       translateFile: {
         label: "Translate",
         action: function() {
           var treeNode =$('#appBuckets').jstree(true).get_selected(true)[0];
           translateObject(treeNode);
         },
         icon: 'glyphicon glyphicon-eye-open'
        }
      };
      break;
  }

  return items;
}

function uploadFile(node) {
$('#hiddenUploadField').click();
$('#hiddenUploadField').change(function () {
    if (this.files.length == 0) return;
    var file = this.files[0];
    switch (node.type) {
      case 'bucket':
        var formData = new FormData();
       formData.append('fileToUpload', file);
       formData.append('bucketKey', node.id);

       $.ajax({
         url: '/api/forge/oss/objects',
         data: formData,
         processData: false,
         contentType: false,
         type: 'POST',
         success: function(data) {
           $('#appBuckets').jstree(true).refresh_node(node);
          }
        });
        break;
    }
  });
}

functiontranslateObject(node) {
  $("#forgeViewer").empty();
  if (node == null) node = $('#appBuckets').jstree(true).get_selected(true)[0];
  var bucketKey = node.parents[0];
  var objectKey = node.id;
jQuery.post({
    url:'/api/forge/modelderivative/jobs',
   contentType: 'application/json',
    data:JSON.stringify({ 'bucketKey': bucketKey, 'objectName': objectKey }),
   success: function(res) {
     $("#forgeViewer").html('Translation started! Please try againin a moment.');
    },
  });
}

ForgeViewer.js
现在这个文件将处理Viewer初始化。 以下代码基于Autodesk Forge Viewer基本应用程序。 在js文件夹下,使用以下命令创建一个ForgeViewer.js文件:
var viewerApp; function launchViewer(urn) {  var options = {    env: 'AutodeskProduction',    getAccessToken: getForgeToken  };  var documentId = 'urn:' + urn;  Autodesk.Viewing.Initializer(options, function onInitialized() {    viewerApp = new Autodesk.Viewing.ViewingApplication('forgeViewer');    viewerApp.registerViewer(viewerApp.k3D, Autodesk.Viewing.Private.GuiViewer3D);    viewerApp.loadDocument(documentId, onDocumentLoadSuccess, onDocumentLoadFailure);  });} function onDocumentLoadSuccess(doc) {  // We could still make use of Document.getSubItemsWithProperties()  // However, when using a ViewingApplication, we have access to the **bubble** attribute,  // which references the root node of a graph that wraps each object from the Manifest JSON.  var viewables = viewerApp.bubble.search({ 'type': 'geometry' });  if (viewables.length === 0) {    console.error('Document contains no viewables.');    return;  }   // Choose any of the available viewables  viewerApp.selectItem(viewables[0].data, onItemLoadSuccess, onItemLoadFail);} function onDocumentLoadFailure(viewerErrorCode) {  console.error('onDocumentLoadFailure() - errorCode:' + viewerErrorCode);} function onItemLoadSuccess(viewer, item) {  // item loaded, any custom action?} function onItemLoadFail(errorCode) {  console.error('onItemLoadFail() - errorCode:' + errorCode);} function getForgeToken(callback) {  jQuery.ajax({    url: '/api/forge/oauth/token',    success: function (res) {      callback(res.access_token, res.expires_in)    }  });}

总结一下:在用户界面你的应用应该有4个文件:

l  index.html
l  main.css
l  ForgeTree.js
l  ForgeViewer.js
可以了,好了? 现在是时候运行应用程序了!


本地运行和调试

现在你的应用程序已准备就绪,是时候运行了。 这是我们可以测试并检查可能的错误的地方(通过调试)。 并检查提示和技巧。

使用样本
下一节将向您展示如何运行您的应用程序。 当它在浏览器上打开时,点击New Bucket创建您的存储桶(该名称在所有Forge帐户中应该是唯一的)。 右键单击新创建的存储桶并选择上传文件(这会触发OSS上传过程)。然后展开桶树节点并右键单击该文件,选择Translate(这将触发模型微分作业)。 一会儿你的文件应该准备好了,再次点击该文件在查看器上显示它。

运行和调试(NodeJS)

转到菜单调试并选择开始调试。 “调试控制台”选项卡应显示在底部,如下所示:
file:///C:/TEMP/msohtmlclip1/01/clip_image007.png
打开浏览器并转到http://localhost:3000







查看器扩展

扩展提供了一种机制来编写与查看器交互的自定义代码。 每个扩展应该向扩展管理器注册自己,提供一个唯一的字符串ID,然后用它在运行时加载或卸载扩展。 学到更多。

本教程将指导您为Viewer创建一个扩展。

对于本教程,您需要使用Viewer的应用程序,例如查看您的模型或查看BIM 360和Fusion模型教程。 无论文件托管在何处,查看器都是一样的。

准备开始编码?






forge中文教程word版本.rar

404.11 KB, 下载次数: 0, 下载积分: 贡献值 -1

售价: 5 金币  [记录]  [购买]

YOUKU3D

写了 1299 篇文章,拥有财富 0,被 5 人关注

www.XinBIM.com
转播转播 分享淘帖 踩!踩!
回复

使用道具

评论

使用高级模式,上传图片!
您需要登录后才可以回帖 登录 | 立即注册
B Color Link Quote Code Smilies
返回顶部