点云二进制文件(pnts)读取流程(附详细代码)

        在利用Cesium加载点云数据时,我们需要对点云数据进行切片,生成pnts格式。该类型切片文件是二进制文件,我们该如何读取其内容呢?该篇文章简单介绍一下我的理解。

1.pnts二进制文件组织格式

        首先我们需要知道pnts二进制文件的组织格式,先贴一个官网链接:3dTiles-PointCloudBatchTable

        一个点云数据切片由header(28个字节,固定的,每个字段占四个字节)+body两部分组成,每一部分数据的组织形式也是固定的,如下图所示。


        

        点云切片数据body中的数据组织形式如下图所示。

        要素表中存储的是该切片中每个点的位置信息和颜色信息批处理表中存储的是切片中点的特定属性信息,例如name,classification,intensity等等(生成点云数据切片时可以自己定义存储哪些属性信息)。

 2.pnts二进制文件读取(代码)

// 获取点击位置的点云切片
let content = cesiumViewer.scene.pick(event.position).content;
let url = content.url;
this.axios.get(url, {
    // 返回数据类型是arraybuffer
    responseType: “arraybuffer“
}).then(res => {
    this.processPntsData(res.data);
})

processPntsData(arrayBuffer) {
    let uint8Array = new Uint8Array(arrayBuffer);
    // 获取magic
    let magic = Cesium.getMagic(uint8Array);

    // header中每个字段占四个字节
    let sizeOfUint32 = 4;

    let byteOffset = 0;
    byteOffset += sizeOfUint32;  // Skip magic

    // 将二进制转换成DataView,可以读写
    let view = new DataView(arrayBuffer);
    let version = view.getUint32(byteOffset, true);

    // 继续往下移动
    byteOffset += sizeOfUint32;  // Skip version
    //得到byteLength的长度
    let byteLength = view.getUint32(byteOffset, true);

    // 继续往下移动
    byteOffset += sizeOfUint32;  // Skip byteLength
    // 得到featuretableJSON字节长度
    let featureTableJsonByteLength = view.getUint32(byteOffset, true);

    // 继续往下移动
    byteOffset += sizeOfUint32;
    // 得到featuretable 二进制字节长度
    let featureTableBinaryByteLength = view.getUint32(byteOffset, true);
    // 得到bathTableJson字节长度
    let batchTableJSONByteLength = view.getUint32(20, true);
    // 得到bathTable 二进制字节长度
    let batchTableBinaryByteLength = view.getUint32(24, true);

    // 下面开始获取body的内容,从第28个字节开始,因为pnts的头部长度为28

    // 获得featuretable中的featuretablejson
    let featureTableArray = new Uint8Array(arrayBuffer, 28, featureTableJsonByteLength);
    // Uint8ArrayToString二进制转String
    let featureTableStr = this.Uint8ArrayToString(featureTableArray);
    let featureTableJSON = JSON.parse(featureTableStr);
    
    // 获取pnts中存储的该切片所有点的位置值
    let featureTableBinary = new Uint8Array(arrayBuffer, 28 + featureTableJsonByteLength, featureTableBinaryByteLength);
    let featureTable = new Cesium.Cesium3DTileFeatureTable(featureTableJSON, featureTableBinary);
    // Cesium执行getPropertyArray进行二进制文件读取必须要传入点云的总长度!但featureTable中该值是0!所以我们必须手动设置!
    // 利用了点云切片pnts的全局语义值(所有点都具有的全局属性)。
    let pointsLength = featureTable.getGlobalProperty(“POINTS_LENGTH“);
    featureTable.featuresLength = pointsLength;
    let positions = featureTable.getPropertyArray('POSITION', Cesium.ComponentDatatype.FLOAT, 3);
    
    // 获取batchtablejSON
    let batchTableArray = new Uint8Array(arrayBuffer, 28 + featureTableJsonByteLength + featureTableBinaryByteLength, batchTableJSONByteLength);
    let batchTableStr = this.Uint8ArrayToString(batchTableArray);
    let batchTableJSON = JSON.parse(batchTableStr);

    // 获取batchtable存储的属性值
    let batchTableBinary = new Uint8Array(arrayBuffer, 28 + featureTableJsonByteLength + featureTableBinaryByteLength + batchTableJSONByteLength, batchTableBinaryByteLength);
},

3. 点云数据的全局语义

        这些语义定义了所有点的全局属性,我们可以直接调用这些属性,例如上方代码中我们获取点云中点的数量,可以使用:

let pointsLength = featureTable.getGlobalProperty(“POINTS_LENGTH“);
源码链接 

 4.注意事项:Padding!!!

        二进制属性应以字节偏移量(byteoffset)开始,该字节偏移量是属性组件类型componentType大小(以字节为单位)的倍数。例如,组件类型为FLOAT的属性每个元素有4字节,因此应该从4的倍数开始偏移。前面的二进制属性需要填充任何值的额外字节,以满足此要求。

        如果不满足上述要求,利用Cesium相关函数获取batchTable中的属性值时是会报错的

上述就是读取二进制文件的流程,下期更新点云切片数据坐标转换成经纬度坐标的流程~欢迎大家多多交流~

本文学习参考自:Cesium之las数据生成3dtiles并选取单个点云_las转3dtiles-CSDN博客

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值