Revit 与 Forge 查看器共享坐标

问题描述 投票:0回答:3

在 Forge 坐标和 Revit 的 shared 坐标之间进行转换的正确过程是什么?我知道有 globalOffset,但是它引用了 Revit 项目内部坐标系还是共享坐标?

autodesk-forge autodesk-viewer
3个回答
4
投票

2021 年 6 月 11 日更新

现在我的 MultipleModelUtil.js 支持我在下面分享的对齐方式。此外,我们可以轻松地告诉 Forge Viewer 使用 By 共享坐标 来聚合模型。这是代码片段,您可以查看here以了解支持的对齐方式

const util = new MultipleModelUtil( viewer );

util.options = {
  alignment: MultipleModelAlignmentType.ShareCoordinates
};

const models = [
  { name: '1.rvt', urn: 'urn:dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLlNpaHgxOTVuUVJDMHIyWXZUSVRuZFE_dmVyc2lvbj0x' },
  { name: '2.rvt', urn: 'urn:dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLldVRHJ4ajZ6UTBPLTRrbWZrZ3ZoLUE_dmVyc2lvbj0x' },
  { name: '3.rvt', urn: 'urn:dXJuOmFkc2sud2lwcHJvZDpmcy5maWxlOnZmLjRyZW5HRTNUU25xNHhYaW5xdWtyaWc_dmVyc2lvbj0x' }
];

util.processModels( models );

==================

首先,Forge Viewer 支持以下 3 种 Revit 链接方式,您可以看一下第 3 种(通过共享坐标)。

  1. 原点到原点:将第一个模型的
    globalOffset
    应用到其他模型上。检查 MultipleModelUtil/MultipleModelUtil.js 的演示
  2. 中心到中心:查看器的默认方式。
  3. 通过共享坐标:设置applyRefpoint:true并将
    globalOffset
    设置为
    refPoint
    这个方法就是您正在寻找的方法。

refPoint
是 Revit 内部坐标系内的 Revit 测量点位置。可通过 AecModelData 访问它。同时,您可以利用 AggregateView 来使用此对齐选项。下面是一个讲述如何使用 AggregateView 的例子: https://gist.github.com/yiskang/c404af571ba4d631b5929c777503891e

如果您想直接在 Viewer 类中使用此逻辑,这里有一个代码片段:

let globalOffset = null;

const aecModelData = bubbleNode.getAecModelData();
const tf = aecModelData && aecModelData.refPointTransformation; // Matrix4x3 as array[12]
const refPoint = tf ? { x: tf[9], y: tf[10], z: 0.0 } : { x: 0, y: 0, z: 0 };

// Check if the current globalOffset is sufficiently close to the refPoint to avoid inaccuracies.
const MaxDistSqr = 4.0e6;
const distSqr    = globalOffset && THREE.Vector3.prototype.distanceToSquared.call(refPoint, globalOffset);
if (!globalOffset || distSqr > MaxDistSqr) {
    globalOffset = new THREE.Vector3().copy(refPoint);
}

viewer.loadDocumentNode(doc, bubbleNode, { applyRefpoint: true, globalOffset: globalOffset, keepCurrentModels: true });

bubbleNode
可以是以下任一:

bubbleNode = doc.getRoot().getDefaultGeometry()

//Or

const viewables = viewerDocument.getRoot().search({'type':'geometry'});
bubbleNode = viewables[0];

要获得

AecModelData
,请参考我的要点:https://gist.github.com/yiskang/c404af571ba4d631b5929c777503891e#file-index-html-L67

// Call this line before using AecModelData
await doc.downloadAecModelData();

// doc.downloadAecModelData(() => resolve(doc));

有关 AecModelData 的详细信息,请参阅此处:https://forge.autodesk.com/blog/consume-aec-data-which-are-model-derivative-api


1
投票

我还发现成功地将

refPointTransformation
输入到矩阵 4 中。

这样,模型的方向也被考虑在内。 (这是基于Eason的回答)。

const bubbleNode = doc.getRoot().getDefaultGeometry();
await doc.downloadAecModelData();
const aecModelData = bubbleNode.getAecModelData();
const tf = aecModelData && aecModelData.refPointTransformation;
const matrix4 = new THREE.Matrix4()
  .makeBasis(
    new THREE.Vector3(tf[0], tf[1], tf[2]),
    new THREE.Vector3(tf[3], tf[4], tf[5]),
    new THREE.Vector3(tf[6], tf[7], tf[8])
  )
  .setPosition(new THREE.Vector3(tf[9], tf[10], tf[11]))

viewer.loadDocumentNode(doc, viewables, {
  placementTransform: matrix4,
  keepCurrentModels: true,
  globalOffset: {
    "x": 0,
    "y": 0,
    "z": 0
  },
  applyRefpoint: true,
  applyScaling: 'ft',
})

0
投票

Jonathan Chang 的答案是使用 Revit 共享坐标的一个很好的选择,但如果坐标远离零,我建议将坐标转换为更接近零,以更好地渲染并避免出现问题。

Promise.all(
docs.map(({ urn, name }) => {
  return new Promise((resolve, reject) => {
    Autodesk.Viewing.Document.load(
      `urn:${urn}`,
      async (Document) => {
        Document.downloadAecModelData(() => {
          resolve({
            doc: Document,
            name,
          });
        });
      },
      () => console.error("Failed fetching Forge manifest")
    );
  });
})).then((docs) => {
Promise.all(
  docs.map(async ({ doc }) => {
    const bubbleNode = doc.getRoot().getDefaultGeometry();
    const aecModelData = bubbleNode.getAecModelData();
    if (aecModelData) {
      const tf = aecModelData.refPointTransformation;
      return { x: tf[9], y: tf[10], z: tf[11] };
    }
  })
).then((refs) => {
  const points = refs.filter((el) => el !== undefined);
  const refPosition = points.reduce(
    (p, c, i, arr) => {
      const div = i + 1 === arr.length ? arr.length : 1;
      return {
        x: (p.x + c.x) / div,
        y: (p.y + c.y) / div,
        z: (p.z + c.z) / div,
      };
    },
    { x: 0, y: 0, z: 0 }
  );
  docs.forEach(async ({ doc, name }) => {
    const bubbleNode = doc.getRoot().getDefaultGeometry();
    const aecModelData = bubbleNode.getAecModelData();
    const tf = aecModelData && aecModelData.refPointTransformation;
    const matrix4 = new THREE.Matrix4()
      .makeBasis(
        new THREE.Vector3(tf[0], tf[1], tf[2]),
        new THREE.Vector3(tf[3], tf[4], tf[5]),
        new THREE.Vector3(tf[6], tf[7], tf[8])
      )
      .setPosition(
        new THREE.Vector3(
          tf[9] - refPosition.x,
          tf[10] - refPosition.y,
          tf[11] - refPosition.z
        )
      );

    viewer.loadDocumentNode(doc, bubbleNode, {
      placementTransform: matrix4,
      keepCurrentModels: true,
      globalOffset: {
        x: 0,
        y: 0,
        z: 0,
      },
      applyRefpoint: true,
      applyScaling: "ft",
    });
  });
});});

在这个基于 Jonathan 代码的示例中,我使用了多个模型并加载每个人的 refPointTransformation 来使用这些点(例如基点)将模型拖动到接近于零的位置,有一些讨论指出使用带有位置的 globalOffset 但在数字很大的情况下,这可能会导致效果不佳在查看器中渲染。

© www.soinside.com 2019 - 2024. All rights reserved.