Cloudini-encode with the lossless (NONE first-stage + ZSTD) path so the round-trip is exact — this test validates our reconstruction, not Cloudini's compression quality. width == 0 means "unorganized": pts.size() x 1.
| 47 | // is exact — this test validates our reconstruction, not Cloudini's compression quality. |
| 48 | // width == 0 means "unorganized": pts.size() x 1. |
| 49 | std::vector<uint8_t> encodeCloudini(const std::vector<Pt>& pts, uint32_t width = 0, uint32_t height = 1) { |
| 50 | Cloudini::EncodingInfo info; |
| 51 | info.width = width != 0 ? width : static_cast<uint32_t>(pts.size()); |
| 52 | info.height = height; |
| 53 | info.point_step = sizeof(Pt); |
| 54 | info.encoding_opt = Cloudini::EncodingOptions::NONE; |
| 55 | info.compression_opt = Cloudini::CompressionOption::ZSTD; |
| 56 | info.fields = { |
| 57 | {"x", 0, Cloudini::FieldType::FLOAT32, std::nullopt}, |
| 58 | {"y", 4, Cloudini::FieldType::FLOAT32, std::nullopt}, |
| 59 | {"z", 8, Cloudini::FieldType::FLOAT32, std::nullopt}, |
| 60 | {"intensity", 12, Cloudini::FieldType::FLOAT32, std::nullopt}, |
| 61 | }; |
| 62 | Cloudini::PointcloudEncoder encoder(info); |
| 63 | Cloudini::ConstBufferView input(reinterpret_cast<const uint8_t*>(pts.data()), pts.size() * sizeof(Pt)); |
| 64 | std::vector<uint8_t> out; |
| 65 | encoder.encode(input, out); |
| 66 | return out; |
| 67 | } |
| 68 | |
| 69 | // Draco-encode POSITION (x,y,z) + one GENERIC (intensity) attribute, sequential |
| 70 | // (lossless float) so positions round-trip closely. When generic_meta_name is given, |