You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在Autodesk Viewer SDK中加载本地PDF后,如何获取选中元素的原始坐标/向量数据并程序化绘制Polyline

在Autodesk Viewer SDK中加载本地PDF后,如何获取选中元素的原始坐标/向量数据并程序化绘制Polyline

我完全理解你遇到的问题——PDF导入Viewer之后,并不会像传统BIM模型那样生成完整的属性数据库(Property Database)和实例树(Instance Tree)结构,所有图形元素都会被拆解成几何片段(Fragments),所以用getPropertyDb()的方式肯定拿不到数据。咱们换个思路,直接从Fragment List里提取原始几何坐标,再用Edit2D Extension绘制Polyline就行。

一、先搞懂PDF在Viewer中的存储逻辑

当你加载PDF页面到Viewer时,Viewer会把PDF的每个图形元素(比如线条、多边形)转换成THREE.js的Mesh,然后打包成Fragment。每个Fragment对应一个或多个dbId,但这些dbId只是片段的关联标识,没有BIM模型那样的属性数据。所以我们需要直接从Fragment中提取顶点数据。

二、具体实现步骤

1. 监听选择事件,定位选中元素的关联Fragment

在你的ApsViewerManager的事件绑定逻辑里,添加选择事件监听,通过InstanceTree和FragmentList找到选中dbId对应的Fragment:

class ApsViewerManager {
    // ... 其他已有代码 ...

    attachViewerEvents() {
        const viewer = this.viewer;
        const self = this;

        viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, async (event) => {
            if (event.selections.length === 0) return; // 无选中元素则跳过
            const selectedDbId = event.selections[0].dbIdArray[0]; // 取第一个选中元素
            const model = viewer.model;
            const instanceTree = model.getInstanceTree();
            const fragmentList = model.getFragmentList();

            // 遍历当前dbId关联的所有Fragment
            instanceTree.enumNodeFragments(selectedDbId, (fragId) => {
                self.extractGeometryFromFragment(fragmentList, fragId);
            }, false);
        });
    }
}

2. 从Fragment中提取原始顶点坐标

添加一个方法,直接从Fragment中提取THREE.js的几何体顶点,并转换成Viewer世界坐标(适配Edit2D的绘制空间):

class ApsViewerManager {
    // ... 其他已有代码 ...

    extractGeometryFromFragment(fragmentList, fragId) {
        const geometry = fragmentList.getGeometry(fragId);
        if (!geometry) {
            console.warn("无法获取当前Fragment的几何数据");
            return;
        }

        // 获取Fragment的世界矩阵,用于将局部顶点转换为世界坐标
        const worldMatrix = new THREE.Matrix4();
        fragmentList.getWorldMatrix(fragId, worldMatrix);

        const positions = geometry.attributes.position.array;
        const worldCoords = [];

        // 遍历所有顶点,转换为世界坐标(PDF是2D,可忽略Z轴)
        for (let i = 0; i < positions.length; i += 3) {
            const localPoint = new THREE.Vector3(positions[i], positions[i+1], positions[i+2]);
            const worldPoint = localPoint.applyMatrix4(worldMatrix);
            // 若发现Y轴方向反转,可改为 y: -worldPoint.y
            worldCoords.push({ x: worldPoint.x, y: worldPoint.y });
        }

        // 至少2个点才能绘制Polyline
        if (worldCoords.length >= 2) {
            this.drawPolylineWithEdit2D(worldCoords);
        }
    }
}

3. 用Edit2D Extension程序化绘制Polyline

最后,用你已经加载的Edit2D实例,调用官方API绘制Polyline:

class ApsViewerManager {
    // ... 其他已有代码 ...

    async drawPolylineWithEdit2D(coords) {
        if (!this.edit2d) {
            console.error("Edit2D Extension未加载");
            return;
        }

        // 创建Polyline路径
        const polylinePath = new Autodesk.Edit2D.PolylinePath();
        coords.forEach(coord => {
            polylinePath.addPoint(new Autodesk.Edit2D.Point(coord.x, coord.y));
        });

        // 设置线条样式(可根据需求自定义)
        const style = new Autodesk.Edit2D.Style();
        style.setStrokeColor(new THREE.Color(0xff0000)); // 红色
        style.setStrokeWidth(3); // 线宽3px

        // 添加到Viewer中
        const drawnShape = await this.edit2d.addShape(polylinePath, style);
        console.log("程序化绘制的Polyline已添加:", drawnShape);
    }
}

三、适配你的PDF加载逻辑

把上述代码整合到你的ApsViewerManager后,加载PDF的逻辑可以保持不变,只需要确保在初始化Viewer后调用attachViewerEvents绑定事件即可:

// 你的PDF加载逻辑(已适配)
async loadLocalPdf(url, page = 1) {
    const options = {
        accessToken: "",
        useCredentials: false,
        env: 'Local'
    };
    await Autodesk.Viewing.Initializer(options, async () => {
        const htmlDiv = document.querySelector(this.containerSelector);
        this.viewer = new Autodesk.Viewing.GuiViewer3D(htmlDiv);
        this.attachViewerEvents(); // 绑定选择事件
        const startedCode = this.viewer.start(null, options);
        if (startedCode > 0) {
            this.report_error('Failed to create Viewer', {startCode: startedCode});
            return;
        }
        // 加载所需扩展
        this.edit2d = await this.viewer.loadExtension('Autodesk.Edit2D', {enableArcs: true});
        await this.viewer.loadExtension('Autodesk.PDF');
        // 加载PDF页面
        await this.viewer.loadModel(url, {page: page});
    });
}

四、可能遇到的小问题及解决

  1. Polyline位置偏移:如果发现绘制的线条和选中的线条位置上下颠倒,把提取坐标的Y轴取反即可:worldCoords.push({ x: worldPoint.x, y: -worldPoint.y });
  2. 多个Fragment的情况:复杂PDF图形可能对应多个Fragment,你可以选择合并所有Fragment的顶点,或者只处理第一个Fragment(根据业务需求调整)。
  3. Edit2D权限问题:确保Edit2D Extension已正确加载,并且Viewer处于可编辑状态(默认加载后是允许添加形状的)。

这样就能实现你要的功能:选中PDF里的线条,提取原始坐标,再程序化绘制一条新的Polyline。如果还有细节问题,随时调整样式或坐标转换逻辑就行~

火山引擎 最新活动