Autodesk forge 如何使用衍生工具脱机使用forge viewer
参考这篇文章,[,我知道派生api提供的文件“GET:urn/manifest/:派生EURN”对于脱机查看来说已经足够了。但是在脱机查看器中使用与输入相同的内容不起作用。在上分析现有示例文件的演示表明下载的bubble还有其他文件,如bin/pack/zip/json,使用C#Api从何处获取这些文件?上载示例文件并使用模型提取器返回错误(“无法获取/extract/1906495 seatdwf.zip”)[根据建议,已尝试3月24日的extract.autodesk.io版本,但无效。] 请指导如何使用C#下载脱机查看所需的文件Autodesk forge 如何使用衍生工具脱机使用forge viewer,autodesk-forge,autodesk-model-derivative,Autodesk Forge,Autodesk Model Derivative,参考这篇文章,[,我知道派生api提供的文件“GET:urn/manifest/:派生EURN”对于脱机查看来说已经足够了。但是在脱机查看器中使用与输入相同的内容不起作用。在上分析现有示例文件的演示表明下载的bubble还有其他文件,如bin/pack/zip/json,使用C#Api从何处获取这些文件?上载示例文件并使用模型提取器返回错误(“无法获取/extract/1906495 seatdwf.zip”)[根据建议,已尝试3月24日的extract.autodesk.io版本,但无效。]
提前感谢。以下是我从extract.autodesk.io中编写的提取器的ES6+异步版本中的Node.js版本:
import BaseSvc from './BaseSvc'
import archiver from 'archiver'
import Forge from 'forge-apis'
import request from 'request'
import mkdirp from 'mkdirp'
import Zip from 'node-zip'
import Zlib from 'zlib'
import path from 'path'
import _ from 'lodash'
import fs from 'fs'
export default class ExtractorSvc extends BaseSvc {
/////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////
constructor (config) {
super (config)
this.derivativesAPI = new Forge.DerivativesApi()
}
/////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////
name () {
return 'ExtractorSvc'
}
/////////////////////////////////////////////////////////
// Create directory async
//
/////////////////////////////////////////////////////////
mkdirpAsync (dir) {
return new Promise((resolve, reject) => {
mkdirp(dir, (error) => {
return error
? reject (error)
: resolve()
})
})
}
/////////////////////////////////////////////////////////
// download all URN resources to target directory
// (unzipped)
//
/////////////////////////////////////////////////////////
download (getToken, urn, directory) {
return new Promise (async (resolve, reject) => {
// make sure target dir exists
await this.mkdirpAsync (directory)
// get token, can be object token or an async
// function that returns the token
const token = ((typeof getToken == 'function')
? await getToken()
: getToken)
// get URN top level manifest
const manifest =
await this.derivativesAPI.getManifest (
urn, {}, {autoRefresh:false}, token)
// harvest derivatives
const derivatives = await this.getDerivatives (
getToken, manifest.body)
// format derivative resources
const nestedDerivatives = derivatives.map((item) => {
return item.files.map((file) => {
const localPath = path.resolve(
directory, item.localPath)
return {
basePath: item.basePath,
guid: item.guid,
mime: item.mime,
fileName: file,
urn: item.urn,
localPath
}
})
})
// flatten resources
const derivativesList = _.flattenDeep(
nestedDerivatives)
// creates async download tasks for each
// derivative file
const downloadTasks = derivativesList.map(
(derivative) => {
return new Promise(async(resolve) => {
const urn = path.join(
derivative.basePath,
derivative.fileName)
const data = await this.getDerivative(
getToken, urn)
const filename = path.resolve(
derivative.localPath,
derivative.fileName)
await this.saveToDisk(data, filename)
resolve(filename)
})
})
// wait for all files to be downloaded
const files = await Promise.all(downloadTasks)
resolve(files)
})
}
/////////////////////////////////////////////////////////
// Parse top level manifest to collect derivatives
//
/////////////////////////////////////////////////////////
parseManifest (manifest) {
const items = []
const parseNodeRec = (node) => {
const roles = [
'Autodesk.CloudPlatform.DesignDescription',
'Autodesk.CloudPlatform.PropertyDatabase',
'Autodesk.CloudPlatform.IndexableContent',
'leaflet-zip',
'thumbnail',
'graphics',
'preview',
'raas',
'pdf',
'lod',
]
if (roles.includes(node.role)) {
const item = {
guid: node.guid,
mime: node.mime
}
const pathInfo = this.getPathInfo(node.urn)
items.push (Object.assign({}, item, pathInfo))
}
if (node.children) {
node.children.forEach ((child) => {
parseNodeRec (child)
})
}
}
parseNodeRec({
children: manifest.derivatives
})
return items
}
/////////////////////////////////////////////////////////
// Collect derivatives for SVF
//
/////////////////////////////////////////////////////////
getSVFDerivatives (getToken, item) {
return new Promise(async(resolve, reject) => {
try {
const svfPath = item.urn.slice (
item.basePath.length)
const files = [svfPath]
const data = await this.getDerivative (
getToken, item.urn)
const pack = new Zip (data, {
checkCRC32: true,
base64: false
})
const manifestData =
pack.files['manifest.json'].asNodeBuffer()
const manifest = JSON.parse (
manifestData.toString('utf8'))
if (manifest.assets) {
manifest.assets.forEach((asset) => {
// Skip SVF embedded resources
if (asset.URI.indexOf('embed:/') === 0) {
return
}
files.push(asset.URI)
})
}
return resolve(
Object.assign({}, item, {
files
}))
} catch (ex) {
reject (ex)
}
})
}
/////////////////////////////////////////////////////////
// Collect derivatives for F2D
//
/////////////////////////////////////////////////////////
getF2dDerivatives (getToken, item) {
return new Promise(async(resolve, reject) => {
try {
const files = ['manifest.json.gz']
const manifestPath = item.basePath +
'manifest.json.gz'
const data = await this.getDerivative (
getToken, manifestPath)
const manifestData = Zlib.gunzipSync(data)
const manifest = JSON.parse (
manifestData.toString('utf8'))
if (manifest.assets) {
manifest.assets.forEach((asset) => {
// Skip SVF embedded resources
if (asset.URI.indexOf('embed:/') === 0) {
return
}
files.push(asset.URI)
})
}
return resolve(
Object.assign({}, item, {
files
}))
} catch (ex) {
reject (ex)
}
})
}
/////////////////////////////////////////////////////////
// Get all derivatives from top level manifest
//
/////////////////////////////////////////////////////////
getDerivatives (getToken, manifest) {
return new Promise(async(resolve, reject) => {
const items = this.parseManifest(manifest)
const derivativeTasks = items.map((item) => {
switch (item.mime) {
case 'application/autodesk-svf':
return this.getSVFDerivatives(
getToken, item)
case 'application/autodesk-f2d':
return this.getF2dDerivatives(
getToken, item)
case 'application/autodesk-db':
return Promise.resolve(
Object.assign({}, item, {
files: [
'objects_attrs.json.gz',
'objects_vals.json.gz',
'objects_offs.json.gz',
'objects_ids.json.gz',
'objects_avs.json.gz',
item.rootFileName
]}))
default:
return Promise.resolve(
Object.assign({}, item, {
files: [
item.rootFileName
]}))
}
})
const derivatives = await Promise.all(
derivativeTasks)
return resolve(derivatives)
})
}
/////////////////////////////////////////////////////////
// Generate path information from URN
//
/////////////////////////////////////////////////////////
getPathInfo (encodedURN) {
const urn = decodeURIComponent(encodedURN)
const rootFileName = urn.slice (
urn.lastIndexOf ('/') + 1)
const basePath = urn.slice (
0, urn.lastIndexOf ('/') + 1)
const localPathTmp = basePath.slice (
basePath.indexOf ('/') + 1)
const localPath = localPathTmp.replace (
/^output\//, '')
return {
rootFileName,
localPath,
basePath,
urn
}
}
/////////////////////////////////////////////////////////
// Get derivative data for specific URN
//
/////////////////////////////////////////////////////////
getDerivative (getToken, urn) {
return new Promise(async(resolve, reject) => {
const baseUrl = 'https://developer.api.autodesk.com/'
const url = baseUrl +
`derivativeservice/v2/derivatives/${urn}`
const token = ((typeof getToken == 'function')
? await getToken()
: getToken)
request({
url,
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token.access_token,
'Accept-Encoding': 'gzip, deflate'
},
encoding: null
}, (err, response, body) => {
if (err) {
return reject(err)
}
if (body && body.errors) {
return reject(body.errors)
}
if ([200, 201, 202].indexOf(
response.statusCode) < 0) {
return reject(response)
}
return resolve(body || {})
})
})
}
/////////////////////////////////////////////////////////
// Save data to disk
//
/////////////////////////////////////////////////////////
saveToDisk (data, filename) {
return new Promise(async(resolve, reject) => {
await this.mkdirpAsync(path.dirname(filename))
const wstream = fs.createWriteStream(filename)
const ext = path.extname(filename)
wstream.on('finish', () => {
resolve()
})
if (typeof data === 'object' && ext === '.json') {
wstream.write(JSON.stringify(data))
} else {
wstream.write(data)
}
wstream.end()
})
}
/////////////////////////////////////////////////////////
// Create a zip
//
/////////////////////////////////////////////////////////
createZip (rootDir, zipfile, zipRoot, files) {
return new Promise((resolve, reject) => {
try {
const output = fs.createWriteStream(zipfile)
const archive = archiver('zip')
output.on('close', () => {
resolve()
})
archive.on('error', (err) => {
reject(err)
})
archive.pipe(output)
if (files) {
files.forEach((file) => {
try {
const rs = fs.createReadStream(file)
archive.append(rs, {
name:
`${zipRoot}/${file.replace(rootDir, '')}`
})
} catch(ex){
console.log(ex)
}
})
} else {
archive.bulk([ {
expand: false,
src: [rootDir + '/*']
}])
}
archive.finalize()
} catch (ex) {
reject(ex)
}
})
}
}
以下是我从extract.autodesk.io编写的提取器的ES6+async中的一个清晰注释Node.js版本:
import BaseSvc from './BaseSvc'
import archiver from 'archiver'
import Forge from 'forge-apis'
import request from 'request'
import mkdirp from 'mkdirp'
import Zip from 'node-zip'
import Zlib from 'zlib'
import path from 'path'
import _ from 'lodash'
import fs from 'fs'
export default class ExtractorSvc extends BaseSvc {
/////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////
constructor (config) {
super (config)
this.derivativesAPI = new Forge.DerivativesApi()
}
/////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////
name () {
return 'ExtractorSvc'
}
/////////////////////////////////////////////////////////
// Create directory async
//
/////////////////////////////////////////////////////////
mkdirpAsync (dir) {
return new Promise((resolve, reject) => {
mkdirp(dir, (error) => {
return error
? reject (error)
: resolve()
})
})
}
/////////////////////////////////////////////////////////
// download all URN resources to target directory
// (unzipped)
//
/////////////////////////////////////////////////////////
download (getToken, urn, directory) {
return new Promise (async (resolve, reject) => {
// make sure target dir exists
await this.mkdirpAsync (directory)
// get token, can be object token or an async
// function that returns the token
const token = ((typeof getToken == 'function')
? await getToken()
: getToken)
// get URN top level manifest
const manifest =
await this.derivativesAPI.getManifest (
urn, {}, {autoRefresh:false}, token)
// harvest derivatives
const derivatives = await this.getDerivatives (
getToken, manifest.body)
// format derivative resources
const nestedDerivatives = derivatives.map((item) => {
return item.files.map((file) => {
const localPath = path.resolve(
directory, item.localPath)
return {
basePath: item.basePath,
guid: item.guid,
mime: item.mime,
fileName: file,
urn: item.urn,
localPath
}
})
})
// flatten resources
const derivativesList = _.flattenDeep(
nestedDerivatives)
// creates async download tasks for each
// derivative file
const downloadTasks = derivativesList.map(
(derivative) => {
return new Promise(async(resolve) => {
const urn = path.join(
derivative.basePath,
derivative.fileName)
const data = await this.getDerivative(
getToken, urn)
const filename = path.resolve(
derivative.localPath,
derivative.fileName)
await this.saveToDisk(data, filename)
resolve(filename)
})
})
// wait for all files to be downloaded
const files = await Promise.all(downloadTasks)
resolve(files)
})
}
/////////////////////////////////////////////////////////
// Parse top level manifest to collect derivatives
//
/////////////////////////////////////////////////////////
parseManifest (manifest) {
const items = []
const parseNodeRec = (node) => {
const roles = [
'Autodesk.CloudPlatform.DesignDescription',
'Autodesk.CloudPlatform.PropertyDatabase',
'Autodesk.CloudPlatform.IndexableContent',
'leaflet-zip',
'thumbnail',
'graphics',
'preview',
'raas',
'pdf',
'lod',
]
if (roles.includes(node.role)) {
const item = {
guid: node.guid,
mime: node.mime
}
const pathInfo = this.getPathInfo(node.urn)
items.push (Object.assign({}, item, pathInfo))
}
if (node.children) {
node.children.forEach ((child) => {
parseNodeRec (child)
})
}
}
parseNodeRec({
children: manifest.derivatives
})
return items
}
/////////////////////////////////////////////////////////
// Collect derivatives for SVF
//
/////////////////////////////////////////////////////////
getSVFDerivatives (getToken, item) {
return new Promise(async(resolve, reject) => {
try {
const svfPath = item.urn.slice (
item.basePath.length)
const files = [svfPath]
const data = await this.getDerivative (
getToken, item.urn)
const pack = new Zip (data, {
checkCRC32: true,
base64: false
})
const manifestData =
pack.files['manifest.json'].asNodeBuffer()
const manifest = JSON.parse (
manifestData.toString('utf8'))
if (manifest.assets) {
manifest.assets.forEach((asset) => {
// Skip SVF embedded resources
if (asset.URI.indexOf('embed:/') === 0) {
return
}
files.push(asset.URI)
})
}
return resolve(
Object.assign({}, item, {
files
}))
} catch (ex) {
reject (ex)
}
})
}
/////////////////////////////////////////////////////////
// Collect derivatives for F2D
//
/////////////////////////////////////////////////////////
getF2dDerivatives (getToken, item) {
return new Promise(async(resolve, reject) => {
try {
const files = ['manifest.json.gz']
const manifestPath = item.basePath +
'manifest.json.gz'
const data = await this.getDerivative (
getToken, manifestPath)
const manifestData = Zlib.gunzipSync(data)
const manifest = JSON.parse (
manifestData.toString('utf8'))
if (manifest.assets) {
manifest.assets.forEach((asset) => {
// Skip SVF embedded resources
if (asset.URI.indexOf('embed:/') === 0) {
return
}
files.push(asset.URI)
})
}
return resolve(
Object.assign({}, item, {
files
}))
} catch (ex) {
reject (ex)
}
})
}
/////////////////////////////////////////////////////////
// Get all derivatives from top level manifest
//
/////////////////////////////////////////////////////////
getDerivatives (getToken, manifest) {
return new Promise(async(resolve, reject) => {
const items = this.parseManifest(manifest)
const derivativeTasks = items.map((item) => {
switch (item.mime) {
case 'application/autodesk-svf':
return this.getSVFDerivatives(
getToken, item)
case 'application/autodesk-f2d':
return this.getF2dDerivatives(
getToken, item)
case 'application/autodesk-db':
return Promise.resolve(
Object.assign({}, item, {
files: [
'objects_attrs.json.gz',
'objects_vals.json.gz',
'objects_offs.json.gz',
'objects_ids.json.gz',
'objects_avs.json.gz',
item.rootFileName
]}))
default:
return Promise.resolve(
Object.assign({}, item, {
files: [
item.rootFileName
]}))
}
})
const derivatives = await Promise.all(
derivativeTasks)
return resolve(derivatives)
})
}
/////////////////////////////////////////////////////////
// Generate path information from URN
//
/////////////////////////////////////////////////////////
getPathInfo (encodedURN) {
const urn = decodeURIComponent(encodedURN)
const rootFileName = urn.slice (
urn.lastIndexOf ('/') + 1)
const basePath = urn.slice (
0, urn.lastIndexOf ('/') + 1)
const localPathTmp = basePath.slice (
basePath.indexOf ('/') + 1)
const localPath = localPathTmp.replace (
/^output\//, '')
return {
rootFileName,
localPath,
basePath,
urn
}
}
/////////////////////////////////////////////////////////
// Get derivative data for specific URN
//
/////////////////////////////////////////////////////////
getDerivative (getToken, urn) {
return new Promise(async(resolve, reject) => {
const baseUrl = 'https://developer.api.autodesk.com/'
const url = baseUrl +
`derivativeservice/v2/derivatives/${urn}`
const token = ((typeof getToken == 'function')
? await getToken()
: getToken)
request({
url,
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token.access_token,
'Accept-Encoding': 'gzip, deflate'
},
encoding: null
}, (err, response, body) => {
if (err) {
return reject(err)
}
if (body && body.errors) {
return reject(body.errors)
}
if ([200, 201, 202].indexOf(
response.statusCode) < 0) {
return reject(response)
}
return resolve(body || {})
})
})
}
/////////////////////////////////////////////////////////
// Save data to disk
//
/////////////////////////////////////////////////////////
saveToDisk (data, filename) {
return new Promise(async(resolve, reject) => {
await this.mkdirpAsync(path.dirname(filename))
const wstream = fs.createWriteStream(filename)
const ext = path.extname(filename)
wstream.on('finish', () => {
resolve()
})
if (typeof data === 'object' && ext === '.json') {
wstream.write(JSON.stringify(data))
} else {
wstream.write(data)
}
wstream.end()
})
}
/////////////////////////////////////////////////////////
// Create a zip
//
/////////////////////////////////////////////////////////
createZip (rootDir, zipfile, zipRoot, files) {
return new Promise((resolve, reject) => {
try {
const output = fs.createWriteStream(zipfile)
const archive = archiver('zip')
output.on('close', () => {
resolve()
})
archive.on('error', (err) => {
reject(err)
})
archive.pipe(output)
if (files) {
files.forEach((file) => {
try {
const rs = fs.createReadStream(file)
archive.append(rs, {
name:
`${zipRoot}/${file.replace(rootDir, '')}`
})
} catch(ex){
console.log(ex)
}
})
} else {
archive.bulk([ {
expand: false,
src: [rootDir + '/*']
}])
}
archive.finalize()
} catch (ex) {
reject(ex)
}
})
}
}
extract.autodesk.io问题在几分钟前已修复,您是否可以重试并确认可以下载?或者将导致问题的模型指向我,thx@PhilippeLeefsma,感谢您的及时回复。我可以从extract.autodesk.io live demo的更新版本下载bubbles。但是,从github,翻译过程失败,错误为:“Get/api/projects//progress"404未找到,进度请求失败。此错误在我尝试翻译的所有文件中都很常见,而不是在特定文件中。Node.js服务器上报告的错误为:extract-autodesk-io-2017z52bf5fsa9e17ahxtcraalcq9ercudgg present!由于字符限制,请查看下一篇评论文章部分完成可视化\uu-air.dwg 399147 visualization at离子天线{错误:eNote:没有这样的文件或目录,请打开'D:\Cad Viewer\extract.autodesk.io-master_13july\extract.autodesk.io master\data\399147 visualization aerialdg.json'错误号:-4058,代码:'eNote',系统调用:'open',路径:'D:\\Cad Viewer\\extract.autodesk.io-master u 13july\\extract.autodesk.io master data\\399147 visualization aerialdg.json'}在浏览目录时,我发现了名为“399147 visualization-_aerialdwg.job.json”的文件已创建。消息extract-autodesk-io-2017z52bf5fsa9e17ahxtcraalcq9ercudgg present!不是错误,它表示已创建存储桶,并且安装正确。接下来,您是否对文件夹/data/?和最后一个具有写权限,但理论上可以,进度取决于获取清单,但清单可能还不存在如果Forge translation尚未启动,则会出现此错误。但系统应处理此错误,extract.autodesk.io问题在几分钟前已修复,您能否重试并确认您可以下载?或者将导致问题的模型指向我,thx@PhilippeLeefsma,谢谢你的及时回复。我可以下载bubbles from extract.autodesk.io live demo的更新版本。但是,从github部署示例项目时,翻译过程失败,错误为:“Get/api/projects//progress”404未找到,进度请求失败。此错误在我尝试翻译的所有文件中都很常见,而不是在特定文件中。Node.js服务器上报告的错误为:extract-autodesk-io-2017z52bf5fsa9e17ahxtcraalcq9ercudgg present!由于字符限制,请查看下一篇评论文章部分完成可视化\uu-air.dwg 399147 visualization at离子天线{错误:eNote:没有这样的文件或目录,请打开'D:\Cad Viewer\extract.autodesk.io-master_13july\extract.autodesk.io master\data\399147 visualization aerialdg.json'错误号:-4058,代码:'eNote',系统调用:'open',路径:'D:\\Cad Viewer\\extract.autodesk.io-master u 13july\\extract.autodesk.io master data\\399147 visualization aerialdg.json'}在浏览目录时,我发现了名为“399147 visualization-_aerialdwg.job.json”的文件已创建。消息extract-autodesk-io-2017z52bf5fsa9e17ahxtcraalcq9ercudgg present!不是错误,它表示已创建存储桶,并且安装正确。接下来,您是否对文件夹/data/?和最后一个具有写权限,但理论上可以,进度取决于获取清单,但清单可能还不存在如果伪造的翻译还没有开始,那么就会出现这个错误。但是系统应该处理它,