点云数据转pnts二进制数据

public byte[] getPntsBytes(List<PointModel> pointList, List<PointAttributeTransferModel> attributeTransferList) {

    XYZModel offsetModel = calculateQuantizedVolumeOffset(pointList);
    XYZModel maxOffset = calculateQuantizedVolumeOffsetMax(pointList);
    XYZModel scaleModel = calculateQuantizedVolumeScale(offsetModel, maxOffset);

    //组装头文件
    String magic = "pnts";
    int version = 1;
    int byteLength = 0;
    int featureTableJSONByteLength = 0;
    int featureTableBinaryByteLength = 0;
    int batchTableJSONByteLength = 0;
    int batchTableBinaryByteLength = 0;
    //体文件

    //量化后坐标
    List<PointModel> quantizedList = calculatePositionQuantized(pointList, offsetModel, scaleModel);

    //坐标
    byte[] positionBinary = new byte[0];
    for (PointModel xyzModel : quantizedList) {
        positionBinary = byteMergerByList(positionBinary, short2byte_Little((short) xyzModel.x), short2byte_Little((short) xyzModel.y), short2byte_Little((short) xyzModel.z));
    }
    positionBinary = fillBytesWithZero(positionBinary, 8);

    //颜色
    byte[] colorByteRGB = {(byte) 0, (byte) 0, (byte) 0};
    byte[] colorBinary = new byte[0];
    for (PointModel xyzModel : pointList) {
        colorBinary = byteMergerByList(colorBinary, colorByteRGB);
    }

    //要素表
    FeatureTable featureTable = new FeatureTable();
    featureTable.POINTS_LENGTH = pointList.size();
    featureTable.POSITION_QUANTIZED = new OffsetModel();
    featureTable.POSITION_QUANTIZED.byteOffset = 0;

    //偏移
    if (!ObjectUtils.isEmpty(offsetModel)) {
        featureTable.QUANTIZED_VOLUME_OFFSET = offsetModel.toMatrixArray();
    }

    //缩放
    if (!ObjectUtils.isEmpty(scaleModel)) {
        featureTable.QUANTIZED_VOLUME_SCALE = scaleModel.toMatrixArray();
    }

    //RGB
    featureTable.RGB = new OffsetModel();
    featureTable.RGB.byteOffset = positionBinary.length;

    String featureTableJson = JSON.toJSONString(featureTable);

    byte[] featureTableJsonBytes = featureTableJson.getBytes();
    featureTableJsonBytes = fillBytesWithEmpty(featureTableJsonBytes);
    featureTableJSONByteLength = featureTableJsonBytes.length;


    //批量表
    BatchTable batchTable = transferBatchTableItem(pointList, attributeTransferList);

    byte[] batchTableBinary = new byte[0];

    int byteOffsetIndex = 0;

    //分布式处理+ForkJoin并行处理生成pnts
    List<PNTSProcessModel> processList = new PNTSProcess().process(batchTable.items);

    for (BatchTableItem batchItem : batchTable.items) {
        PNTSProcessModel pntsProcessModel = processList.stream().filter(it -> it.batchTableItem.name.equals(batchItem.name)).findFirst().orElse(null);
        if (!ObjectUtils.isEmpty(pntsProcessModel)) {
            batchTableBinary = byteMergerByList(batchTableBinary, pntsProcessModel.batchTableBinary);
            batchItem.batchTableBaseItem.byteOffset = byteOffsetIndex;
            byteOffsetIndex += pntsProcessModel.byteOffsetIndex;
        }
    }

    String batchTableJSONString = batchTable.toBatchTableJSONString();
    byte[] batchTableJSONBytes = batchTableJSONString.getBytes();
    batchTableJSONBytes = fillBytesWithEmpty(batchTableJSONBytes);
    batchTableJSONByteLength = batchTableJSONBytes.length;

    //batchTableBinary
    batchTableBinary = fillBytesWithZero(batchTableBinary, 8);
    batchTableBinaryByteLength = batchTableBinary.length;


    //计算填充量
    int fillNum = 0;
    int i = 28 + positionBinary.length + colorBinary.length;
    if (i % 8 != 0) {
        fillNum = 8 - i % 8;
    }
    if (fillNum != 0) {
        colorBinary = fillInputBytesWithZero(colorBinary, fillNum);
    }

    //合并
    byte[] featureTableBinary = byteMergerByList(positionBinary, colorBinary);
    featureTableBinaryByteLength = featureTableBinary.length;


    byteLength = 28 + featureTableJSONByteLength + featureTableBinaryByteLength + batchTableJSONByteLength + batchTableBinaryByteLength;

    //组装pnts的二级制文件
    byte[] bytes1 = magic.getBytes();
    byte[] bytes2 = int32ToLHByte(version);
    byte[] bytes3 = int32ToLHByte(byteLength);
    byte[] bytes4 = int32ToLHByte(featureTableJSONByteLength);
    byte[] bytes5 = int32ToLHByte(featureTableBinaryByteLength);
    byte[] bytes6 = int32ToLHByte(batchTableJSONByteLength);
    byte[] bytes7 = int32ToLHByte(batchTableBinaryByteLength);

    byte[] bytes8 = featureTableJsonBytes;
    byte[] bytes9 = featureTableBinary;
    byte[] bytes10 = batchTableJSONBytes;
    byte[] bytes11 = batchTableBinary;

    //合并bytes
    byte[] pntsBinaryBytes = byteMergerByList(bytes1, bytes2, bytes3, bytes4, bytes5, bytes6, bytes7, bytes8, bytes9, bytes10, bytes11);

    return pntsBinaryBytes;
}

public class PointModel {
    public double x;
    public double y;
    public double z;
    public double value;
}

public class PointAttributeTransferModel {
    /**
     * input文件对应输入字段名称
     */
    public String inputKey;
    /**
     * PointModel对应字段
     */
    public Field field;
    /**
     * Pnts输出字段名称
     */
    public String outputKey;

    public PointAttributeTransferModel(String outputKey, Field field, String inputKey){
        this.outputKey = outputKey;
        this.field = field;
        this.inputKey = inputKey;
    }
}
public static XYZModel calculateQuantizedVolumeOffset(List<PointModel> points) {
    double minX = Double.MAX_VALUE;
    double minY = Double.MAX_VALUE;
    double minZ = Double.MAX_VALUE;

    // Find minimum values for each dimension
    for (PointModel point : points) {
        minX = Math.min(minX, point.x);
        minY = Math.min(minY, point.y);
        minZ = Math.min(minZ, point.z);
    }

    // Calculate quantized volume offset
    XYZModel offsetModel = new XYZModel(minX, minY, minZ);
    return offsetModel;
}

public static XYZModel calculateQuantizedVolumeOffsetMax(List<PointModel> points) {
    double maxX = -Double.MAX_VALUE;
    double maxY = -Double.MAX_VALUE;
    double maxZ = -Double.MAX_VALUE;

    // Find minimum values for each dimension
    for (PointModel point : points) {
        maxX = Math.max(maxX, point.x);
        maxY = Math.max(maxY, point.y);
        maxZ = Math.max(maxZ, point.z);
    }

    // Calculate quantized volume offset
    XYZModel offsetModel = new XYZModel(maxX, maxY, maxZ);
    return offsetModel;
}

public static XYZModel calculateQuantizedVolumeScale(XYZModel quantizedVolumeOffset, XYZModel maxOffset) {
    double[] range = {maxOffset.x - quantizedVolumeOffset.x, maxOffset.y - quantizedVolumeOffset.y, maxOffset.z - quantizedVolumeOffset.z};
    double offsetQuantizedX = range[0] > 1 ? range[0] / 1 : 1;
    double offsetQuantizedY = range[1] > 1 ? range[1] / 1 : 1;
    double offsetQuantizedZ = range[2] > 1 ? range[2] / 1 : 1;
    // Calculate quantized volume scale

    XYZModel scaleModel = new XYZModel(offsetQuantizedX, offsetQuantizedY, offsetQuantizedZ);

    return scaleModel;
}

public List<PointModel> calculatePositionQuantized(List<PointModel> points, XYZModel quantizedVolumeOffset, XYZModel quantizedScaleModel) {
    List<PointModel> positionQuantizedList = new ArrayList<>();
    for (PointModel point : points) {
        int xQuantized = (int) Math.floor(((point.x - quantizedVolumeOffset.x) / quantizedScaleModel.x * 65535));
        int yQuantized = (int) Math.floor(((point.y - quantizedVolumeOffset.y) / quantizedScaleModel.y * 65535));
        int zQuantized = (int) Math.floor(((point.z - quantizedVolumeOffset.z) / quantizedScaleModel.z * 65535));

        //short xQuantized = (short) ((point.x - quantizedVolumeOffset.x) / quantizedScaleModel.x * 65535);
        //short yQuantized = (short) ((point.y - quantizedVolumeOffset.y) / quantizedScaleModel.y * 65535);
        //short zQuantized = (short) ((point.z - quantizedVolumeOffset.z) / quantizedScaleModel.z * 65535);

        PointModel positionQuantized = new PointModel();
        positionQuantized.x = xQuantized;
        positionQuantized.y = yQuantized;
        positionQuantized.z = zQuantized;

        positionQuantizedList.add(positionQuantized);
    }
    return positionQuantizedList;
}

public static byte[] byteMergerByList(byte[]... bytes) {
    int totalLength = 0;
    for (byte[] array : bytes) {
        totalLength += array.length;
    }
    ByteBuffer buffer = ByteBuffer.allocate(totalLength);
    for (byte[] array : bytes) {
        buffer.put(array);
    }
    return buffer.array();
}

public static byte[] fillBytesWithZero(byte[] featureTableBinary, int fillBoundary) {
    int length = featureTableBinary.length;
    int remain = length % fillBoundary;
    Short s = 0;
    if (remain != 0) {
        int fillNum = fillBoundary - remain;
        for (int i = 0; i < fillNum; i++) {
            featureTableBinary = byteMergerByList(featureTableBinary, int8ToLHByte(s));
        }
    }
    return featureTableBinary;
}

public static byte[] fillInputBytesWithZero(byte[] featureTableBinary, int fillNum) {
    Short s = 0;
    for (int i = 0; i < fillNum; i++) {
        featureTableBinary = byteMergerByList(featureTableBinary, int8ToLHByte(s));
    }
    return featureTableBinary;
}

public static byte[] int8ToLHByte(int n) {
    byte[] b = new byte[1];
    b[0] = (byte) (n & 0xff);
    return b;
}

public class FeatureTable {
    public int POINTS_LENGTH;
    public OffsetModel POSITION_QUANTIZED;
    public List<Double> QUANTIZED_VOLUME_OFFSET;
    public List<Double> QUANTIZED_VOLUME_SCALE;
    public OffsetModel RGB;
}

public static byte[] fillBytesWithEmpty(byte[] featureTableJsonBytes) {
    int length = featureTableJsonBytes.length;
    int remain = length % 8;
    String emptyStr = " ";
    if (remain != 0) {
        int fillNum = 8 - remain;
        for (int i = 0; i < fillNum; i++) {
            featureTableJsonBytes = byteMergerByList(featureTableJsonBytes, emptyStr.getBytes());
        }
    }
    return featureTableJsonBytes;
}

public BatchTable transferBatchTableItem(List<PointModel> pointList, List<PointAttributeTransferModel> attributeTransferList) {
    BatchTable batchTable = new BatchTable();
    batchTable.items = new ArrayList<>();
    List<FiledNameAndType> pointModelFiledNames = getFiledName(new PointModel());
    for (PointAttributeTransferModel pointAttributeTransferModel : attributeTransferList) {
        String enumKey = pointAttributeTransferModel.field.getName().toLowerCase();
        List<FiledNameAndType> collect = pointModelFiledNames.stream().filter(it -> it.filedName.equals(enumKey)).collect(Collectors.toList());

        BatchTableItem batchTableItem = new BatchTableItem();
        batchTableItem.batchTableBaseItem = new BatchTableBaseItem();
        batchTableItem.batchTableBaseItem.byteOffset = 0;
        batchTableItem.batchTableBaseItem.componentType = ObjectUtils.isEmpty(collect) ? "DOUBLE" : collect.get(0).filedType.toUpperCase();
        batchTableItem.batchTableBaseItem.type = "SCALAR";
        batchTableItem.name = pointAttributeTransferModel.outputKey;
        List<Object> valueList = extractColumn(pointList, "enumKey");
        batchTableItem.dataList = valueList;
        batchTable.items.add(batchTableItem);
    }
    return batchTable;
}

public static List<FiledNameAndType> getFiledName(Object o) {
    List<FiledNameAndType> retList = new ArrayList<>();
    Field[] fields = o.getClass().getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        FiledNameAndType filedNameAndType = new FiledNameAndType();
        String filedName = fields[i].getName();
        String filedType = fields[i].getType().toString();
        filedNameAndType.filedName = filedName;
        filedNameAndType.filedType = filedType;
        retList.add(filedNameAndType);
    }
    return retList;
}

public static <T> List<T> extractColumn(List<PointModel> pointList, String fieldName) {
    return pointList.stream()
            .map(point -> {
                try {
                    return (T) PointModel.class.getField(fieldName).get(point);
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            })
            .collect(Collectors.toList());
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值