/// Fill a buffer with point data specified by the dimension list. /// \param[in] dims List of dimensions/types to retrieve. /// \param[in] idx Index of point to get. /// \param[in] buf Pointer to buffer to fill. void getPackedData(const DimTypeList& dims, char *buf) const { for (auto di = dims.begin(); di != dims.end(); ++di) { getField(buf, di->m_id, di->m_type); buf += Dimension::size(di->m_type); } }
DimTypeList XMLSchema::dimTypes() const { DimTypeList dimTypes; for (auto di = m_dims.begin(); di != m_dims.end(); ++di) dimTypes.push_back(di->m_dimType); return dimTypes; }
/// Load the point buffer from memory whose arrangement is specified /// by the dimension list. /// \param[in] dims Dimension/types of data in packed order /// \param[in] idx Index of point to write. /// \param[in] buf Packed data buffer. void setPackedPoint(const DimTypeList& dims, PointId idx, const char *buf) { for (auto di = dims.begin(); di != dims.end(); ++di) { setField(di->m_id, di->m_type, idx, (const void *)buf); buf += Dimension::size(di->m_type); } }
DimTypeList DbReader::dbDimTypes() const { DimTypeList dimTypes; for (auto di = m_dims.begin(); di != m_dims.end(); ++di) dimTypes.push_back(di->m_dimType); return dimTypes; }
DimTypeList PointLayout::dimTypes() const { DimTypeList dimTypes; const Dimension::IdList& ids = dims(); for (auto ii = ids.begin(); ii != ids.end(); ++ii) dimTypes.push_back(DimType(*ii, dimType(*ii))); return dimTypes; }
TEST(Compression, types) { using namespace Dimension; Type types[] = { Type::Unsigned8, Type::Unsigned16, Type::Unsigned32, Type::Unsigned64, Type::Signed8, Type::Signed16, Type::Signed32, Type::Signed64, Type::Float, Type::Double }; // Size is 42. std::default_random_engine generator; std::uniform_int_distribution<int> dist(std::numeric_limits<int>::min()); char pts[3][42]; // Fill three "points" with some random data. char *c = &pts[0][0]; for (size_t i = 0; i < 3 * 42; ++i) { int v = dist(generator); memcpy(c++, &v, sizeof(char)); } DimTypeList dimTypes; for (auto ti = std::begin(types); ti != std::end(types); ++ti) dimTypes.push_back(DimType(Dimension::Id::Unknown, *ti)); std::vector<unsigned char> rawBuf; LazPerfBuf b(rawBuf); LazPerfCompressor<LazPerfBuf> compressor(b, dimTypes); for (size_t i = 0; i < 50; i++) { compressor.compress(pts[0], 42); compressor.compress(pts[1], 42); compressor.compress(pts[2], 42); } compressor.done(); LazPerfBuf b2(rawBuf); LazPerfDecompressor<LazPerfBuf> decompressor(b2, dimTypes); char oPts[3][42]; for (size_t i = 0; i < 50; ++i) { decompressor.decompress(oPts[0], 42); decompressor.decompress(oPts[1], 42); decompressor.decompress(oPts[2], 42); EXPECT_EQ(memcmp(pts[0], oPts[0], 42), 0); EXPECT_EQ(memcmp(pts[1], oPts[1], 42), 0); EXPECT_EQ(memcmp(pts[2], oPts[2], 42), 0); memset(oPts[0], 0, 42); memset(oPts[1], 0, 42); memset(oPts[2], 0, 42); } }
void Block::update(XMLSchema *s) { using namespace Dimension; m_point_size = 0; // Wipe the size to reset m_num_remaining = num_points; m_schema.setOrientation(s->orientation()); DimTypeList dims = s->dimTypes(); for (auto di = dims.begin(); di != dims.end(); ++di) { if (di->m_id == Id::X || di->m_id == Id::Y || di->m_id == Id::Z) m_schema.setXForm(di->m_id, di->m_xform); m_point_size += Dimension::size(di->m_type); } }
DimTypeList schemaToDims(const Json::Value& json) { DimTypeList output; // XYZ might be natively stored as integral values, typically when the // disk-storage for Entwine is scaled/offset. Since we're abstracting // this out, always ask for XYZ as doubles. auto isXyz([](Dimension::Id id) { return id == Dimension::Id::X || id == Dimension::Id::Y || id == Dimension::Id::Z; }); if (!json.isNull() && json.isArray()) { for (const auto& jsonDim : json) { const Dimension::Id id( Dimension::id(jsonDim["name"].asString())); const int baseType( Utils::toNative( Dimension::fromName(jsonDim["type"].asString()))); const int size(jsonDim["size"].asUInt64()); const Dimension::Type type( isXyz(id) ? Dimension::Type::Double : static_cast<Dimension::Type>(baseType | size)); output.emplace_back(id, type); } } return output; }
point_count_t OciReader::readDimMajor(PointView& view, BlockPtr block, point_count_t numPts) { using namespace Dimension; point_count_t numRemaining = block->numRemaining(); PointId startId = view.size(); point_count_t blockRemaining = numRemaining; point_count_t numRead = 0; DimTypeList dims = dbDimTypes(); for (auto di = dims.begin(); di != dims.end(); ++di) { PointId nextId = startId; char *pos = seekDimMajor(*di, block); blockRemaining = numRemaining; numRead = 0; while (numRead < numPts && blockRemaining > 0) { writeField(view, pos, *di, nextId); pos += Dimension::size(di->m_type); if (di->m_id == Id::PointSourceId && m_updatePointSourceId) view.setField(Id::PointSourceId, nextId, block->obj_id); if (m_cb && di == dims.rbegin().base() - 1) m_cb(view, nextId); nextId++; numRead++; blockRemaining--; } } block->setNumRemaining(blockRemaining); return numRead; }
DimTypeList DbWriter::dimTypes(PointTableRef table) { using namespace Dimension; PointLayoutPtr layout = table.layout(); if (m_outputDims.empty()) return layout->dimTypes(); DimTypeList dims; for (std::string& s : m_outputDims) { DimType dt = layout->findDimType(s); if (dt.m_id == Id::Unknown) { std::ostringstream oss; oss << "Invalid dimension '" << s << "' specified for " "'output_dims' option."; throw pdal_error(oss.str()); } dims.push_back(dt); } return dims; }
TEST(Compression, types) { using namespace Dimension; Type types[] = { Type::Unsigned8, Type::Unsigned16, Type::Unsigned32, Type::Unsigned64, Type::Signed8, Type::Signed16, Type::Signed32, Type::Signed64, Type::Float, Type::Double }; // Size is 42. std::default_random_engine generator; std::uniform_int_distribution<int> dist((std::numeric_limits<int>::min)()); char pts[3][42]; // Fill three "points" with some random data. char *c = &pts[0][0]; for (size_t i = 0; i < 3 * 42; ++i) { int v = dist(generator); memcpy(c++, &v, sizeof(char)); } DimTypeList dimTypes; for (auto ti = std::begin(types); ti != std::end(types); ++ti) dimTypes.push_back(DimType(Dimension::Id::Unknown, *ti)); std::vector<unsigned char> rawBuf; auto cb = [&rawBuf](char *buf, size_t bufsize) { unsigned char *ubuf = reinterpret_cast<unsigned char *>(buf); rawBuf.insert(rawBuf.begin(), ubuf, ubuf + bufsize); }; LazPerfCompressor compressor(cb, dimTypes); for (size_t i = 0; i < 50; i++) { compressor.compress(pts[0], 42); compressor.compress(pts[1], 42); compressor.compress(pts[2], 42); } compressor.done(); char oPts[3][42]; PointId id = 0; auto cb2 = [&pts, &oPts, &id](char *buf, size_t bufsize) { memcpy(oPts[id++], buf, bufsize); if (id == 3) { EXPECT_EQ(memcmp(pts[0], oPts[0], 42), 0); EXPECT_EQ(memcmp(pts[0], oPts[0], 42), 0); EXPECT_EQ(memcmp(pts[2], oPts[2], 42), 0); memset(oPts[0], 0, 42); memset(oPts[1], 0, 42); memset(oPts[2], 0, 42); id = 0; } }; LazPerfDecompressor(cb2, dimTypes, 50 * 3). decompress(reinterpret_cast<const char *>(rawBuf.data()), rawBuf.size()); }
TEST(LasReaderTest, extraBytes) { PointTable table; PointLayoutPtr layout(table.layout()); Options readOps; readOps.add("filename", Support::datapath("las/extrabytes.las")); LasReader reader; reader.setOptions(readOps); reader.prepare(table); DimTypeList dimTypes = layout->dimTypes(); EXPECT_EQ(dimTypes.size(), (size_t)24); Dimension::Id color0 = layout->findProprietaryDim("Colors0"); EXPECT_EQ(layout->dimType(color0), Dimension::Type::Unsigned16); Dimension::Id color1 = layout->findProprietaryDim("Colors1"); EXPECT_EQ(layout->dimType(color1), Dimension::Type::Unsigned16); Dimension::Id color2 = layout->findProprietaryDim("Colors2"); EXPECT_EQ(layout->dimType(color2), Dimension::Type::Unsigned16); Dimension::Id flag0 = layout->findProprietaryDim("Flags0"); EXPECT_EQ(layout->dimType(flag0), Dimension::Type::Signed8); Dimension::Id flag1 = layout->findProprietaryDim("Flags1"); EXPECT_EQ(layout->dimType(flag1), Dimension::Type::Signed8); Dimension::Id time2 = layout->findDim("Time"); EXPECT_EQ(layout->dimType(time2), Dimension::Type::Unsigned64); PointViewSet viewSet = reader.execute(table); EXPECT_EQ(viewSet.size(), (size_t)1); PointViewPtr view = *viewSet.begin(); Dimension::Id red = layout->findDim("Red"); Dimension::Id green = layout->findDim("Green"); Dimension::Id blue = layout->findDim("Blue"); Dimension::Id returnNum = layout->findDim("ReturnNumber"); Dimension::Id numReturns = layout->findDim("NumberOfReturns"); Dimension::Id intensity = layout->findDim("Intensity"); Dimension::Id time = layout->findDim("GpsTime"); for (PointId idx = 0; idx < view->size(); ++idx) { ASSERT_EQ(view->getFieldAs<uint16_t>(red, idx), view->getFieldAs<uint16_t>(color0, idx)); ASSERT_EQ(view->getFieldAs<uint16_t>(green, idx), view->getFieldAs<uint16_t>(color1, idx)); ASSERT_EQ(view->getFieldAs<uint16_t>(blue, idx), view->getFieldAs<uint16_t>(color2, idx)); ASSERT_EQ(view->getFieldAs<uint16_t>(flag0, idx), view->getFieldAs<uint16_t>(returnNum, idx)); ASSERT_EQ(view->getFieldAs<uint16_t>(flag1, idx), view->getFieldAs<uint16_t>(numReturns, idx)); // Time was written truncated rather than rounded. ASSERT_NEAR(view->getFieldAs<double>(time, idx), view->getFieldAs<double>(time2, idx), 1.0); } }