You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需Forge Viewer通过服务端API创建BIM 360 Pushpin问题?

无需前端Viewer,批量创建BIM 360带Pushpin的问题

我明白你想要纯服务端批量生成数百个关联文档的Pushpin问题,不用每次打开Viewer——这完全可行,核心是用Model Derivative API获取必要的图纸信息,再程序化构造Pushpin的位置和视图状态参数。下面一步步拆解:

一、获取图纸GUID(sheetGuid)

对于BIM 360中的2D图纸,sheetGuid其实是该文档衍生出来的2D视图的GUID,可以通过Model Derivative API从服务端获取:

  • 首先调用GET /modelderivative/v2/designdata/{urn}/metadata,获取文档的元数据结构,拿到根节点的guid(记为modelGuid)。
  • 接着调用GET /modelderivative/v2/designdata/{urn}/metadata/{modelGuid}/views,这个接口会返回该文档所有的视图列表——2D图纸对应的就是type为2d的条目,它的guid就是你需要的sheetGuid。

如果是3D模型,is3D设为true,sheetGuid可以直接用模型根节点的guid。

二、程序化生成position和viewerState

1. issue.position(Pushpin位置)

对于2D图纸,position是一个包含x、y、z的对象:

  • z值固定为0即可(因为是2D平面)
  • x和y可以基于图纸的边界范围计算:
    从GET /modelderivative/v2/designdata/{urn}/metadata/{modelGuid}/views/{sheetGuid}接口可以拿到图纸的boundingBox(包含min和max坐标),比如取中心位置:
    const boundingBox = viewData.boundingBox;
    const position = {
      x: (boundingBox.min.x + boundingBox.max.x) / 2,
      y: (boundingBox.min.y + boundingBox.max.y) / 2,
      z: 0
    };
    
    如果有具体的点位需求,也可以直接传入自定义的坐标值(只要在图纸范围内即可)。

对于3D模型,position就是模型空间中的三维坐标,同样可以通过模型的边界或自定义点位生成。

2. issue.viewerState(视图状态)

视图状态是描述Viewer视角的JSON对象,对于2D图纸,你可以程序化构造一个基础的状态,确保Pushpin位置在视图中心:

const viewerState = {
  type: '2d',
  viewport: {
    name: 'Default View',
    zoom: 1,
    position: { x: 0, y: 0 },
    target: { x: position.x, y: position.y, z: 0 }
  },
  seedUrn: '<你的文档URN>',
  sheetGuid: sheetGuid
};

如果需要更精准的视角,也可以参考Viewer中导出的viewerState结构,调整zoom、position等参数即可。

三、Node.js代码示例

下面是完整的服务端流程示例,包含获取sheetGuid、构造参数、调用问题创建接口:

const axios = require('axios');

// 配置参数
const FORGE_CLIENT_ID = '你的Client ID';
const FORGE_CLIENT_SECRET = '你的Client Secret';
const CONTAINER_ID = 'BIM 360项目的Container ID';
const DOCUMENT_URN = 'BIM 360文档的URN(注意要Base64编码)';

// 第一步:获取访问令牌
async function getAccessToken() {
  const response = await axios.post(
    'https://developer.api.autodesk.com/authentication/v2/token',
    new URLSearchParams({
      grant_type: 'client_credentials',
      scope: 'data:read data:write bucket:create bucket:read'
    }),
    {
      auth: {
        username: FORGE_CLIENT_ID,
        password: FORGE_CLIENT_SECRET
      }
    }
  );
  return response.data.access_token;
}

// 第二步:获取图纸的sheetGuid
async function getSheetGuid(accessToken) {
  // 获取模型元数据
  const metadataRes = await axios.get(
    `https://developer.api.autodesk.com/modelderivative/v2/designdata/${DOCUMENT_URN}/metadata`,
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );
  const modelGuid = metadataRes.data.data.metadata[0].guid;

  // 获取视图列表
  const viewsRes = await axios.get(
    `https://developer.api.autodesk.com/modelderivative/v2/designdata/${DOCUMENT_URN}/metadata/${modelGuid}/views`,
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );
  // 取第一个2D视图的guid作为sheetGuid(根据你的需求调整)
  const sheetView = viewsRes.data.data.find(view => view.type === '2d');
  return sheetView.guid;
}

// 第三步:创建Pushpin问题
async function createPushpinIssue(accessToken, sheetGuid, position, viewerState) {
  const issueData = {
    title: '批量生成的Pushpin问题',
    description: '通过服务端API自动创建的关联文档问题',
    status: 'open',
    issueType: 'quality',
    position: {
      type: 'TwoDVectorPushpin',
      sheetMetadata: {
        is3D: false,
        sheetGuid: sheetGuid,
        sheetName: '图纸名称(可从元数据获取)'
      },
      pushpinAttributes: {
        location: position,
        viewerState: viewerState
      }
    }
  };

  const response = await axios.post(
    `https://developer.api.autodesk.com/issues/v1/containers/${CONTAINER_ID}/quality-issues`,
    issueData,
    { headers: { Authorization: `Bearer ${accessToken}` } }
  );
  return response.data;
}

// 主流程
async function run() {
  try {
    const token = await getAccessToken();
    const sheetGuid = await getSheetGuid(token);

    // 获取图纸边界,构造position
    const viewRes = await axios.get(
      `https://developer.api.autodesk.com/modelderivative/v2/designdata/${DOCUMENT_URN}/metadata/${sheetGuid}/views/${sheetGuid}`,
      { headers: { Authorization: `Bearer ${token}` } }
    );
    const boundingBox = viewRes.data.data.boundingBox;
    const position = {
      x: (boundingBox.min.x + boundingBox.max.x) / 2,
      y: (boundingBox.min.y + boundingBox.max.y) / 2,
      z: 0
    };

    // 构造viewerState
    const viewerState = {
      type: '2d',
      viewport: {
        zoom: 1,
        position: { x: 0, y: 0 },
        target: { x: position.x, y: position.y, z: 0 }
      },
      seedUrn: DOCUMENT_URN,
      sheetGuid: sheetGuid
    };

    // 批量创建示例(这里循环创建10个,你可以调整为数百个)
    for (let i = 0; i < 10; i++) {
      const issue = await createPushpinIssue(token, sheetGuid, position, viewerState);
      console.log(`创建成功的问题ID: ${issue.id}`);
    }
  } catch (error) {
    console.error('出错了:', error.response?.data || error.message);
  }
}

run();

注意事项:

  • 确保你的Client ID拥有data:read和data:write的权限,并且已经关联到目标BIM 360项目。
  • 批量创建时建议加入适当的延迟,避免触发API速率限制。

内容的提问来源于stack exchange,提问作者Ahmad Hisham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:59:27