/// Read a field from a PointView and write its value as formatted for output /// to the DB schema to the location as requested. /// \param[in] view PointView to read from. /// \param[in] pos Location in which to store field value. /// \param[in] id ID of the dimension to read. /// \param[in] idx Index of point to read. /// \return Size of field as read. size_t DbWriter::readField(const PointView& view, char *pos, Dimension::Id::Enum id, PointId idx) { using namespace Dimension; DimType& dt = m_dimMap[(int)id]; size_t size = Dimension::size(dt.m_type); // Using the ID instead of a dimType as the arugment hides the complication // of the "type" of the dimension to retrieve in the case of location // scaling. view.getField(pos, id, dt.m_type, idx); auto iconvert = [pos](const XForm& xform, Dimension::Id::Enum dim) { double d; int32_t i; memcpy(&d, pos, sizeof(double)); d = (d - xform.m_offset) / xform.m_scale; if (!Utils::numericCast(d, i)) { std::ostringstream oss; oss << "Unable to convert double to int32 for packed DB output: "; oss << Dimension::name(dim) << ": (" << d << ")."; throw pdal_error(oss.str()); } memcpy(pos, &i, sizeof(int32_t)); }; if (m_locationScaling) { // For X, Y or Z. if (id == Id::X) { iconvert(m_xXform, Id::X); size = sizeof(int32_t); } else if (id == Id::Y) { iconvert(m_yXform, Id::Y); size = sizeof(int32_t); } else if (id == Id::Z) { iconvert(m_zXform, Id::Z); size = sizeof(int32_t); } } return size; }
size_t DbWriter::readField(const PointView& view, char *pos, DimType dimType, PointId idx) { using namespace Dimension; size_t size = Dimension::size(dimType.m_type); view.getField(pos, dimType.m_id, dimType.m_type, idx); auto iconvert = [pos](const XForm& xform) { double d; int32_t i; memcpy(&d, pos, sizeof(double)); d = (d - xform.m_offset) / xform.m_scale; i = boost::numeric_cast<int32_t>(lround(d)); memcpy(pos, &i, sizeof(int32_t)); }; if (m_locationScaling) { // For X, Y or Z. if (dimType.m_id == Id::X) { iconvert(m_xXform); size = sizeof(int32_t); } else if (dimType.m_id == Id::Y) { iconvert(m_yXform); size = sizeof(int32_t); } else if (dimType.m_id == Id::Z) { iconvert(m_zXform); size = sizeof(int32_t); } } return size; }
point_count_t LasWriter::fillWriteBuf(const PointView& view, PointId startId, std::vector<char>& buf) { point_count_t blocksize = buf.size() / m_lasHeader.pointLen(); blocksize = std::min(blocksize, view.size() - startId); bool hasColor = m_lasHeader.hasColor(); bool hasTime = m_lasHeader.hasTime(); PointId lastId = startId + blocksize; static const size_t maxReturnCount = m_lasHeader.maxReturnCount(); LeInserter ostream(buf.data(), buf.size()); for (PointId idx = startId; idx < lastId; idx++) { // we always write the base fields using namespace Dimension; uint8_t returnNumber(1); uint8_t numberOfReturns(1); if (view.hasDim(Id::ReturnNumber)) { returnNumber = view.getFieldAs<uint8_t>(Id::ReturnNumber, idx); if (returnNumber < 1 || returnNumber > maxReturnCount) m_error.returnNumWarning(returnNumber); } if (view.hasDim(Id::NumberOfReturns)) numberOfReturns = view.getFieldAs<uint8_t>( Id::NumberOfReturns, idx); if (numberOfReturns == 0) m_error.numReturnsWarning(0); if (numberOfReturns > maxReturnCount) { if (m_discardHighReturnNumbers) { // If this return number is too high, pitch the point. if (returnNumber > maxReturnCount) continue; numberOfReturns = maxReturnCount; } else m_error.numReturnsWarning(numberOfReturns); } double xOrig = view.getFieldAs<double>(Id::X, idx); double yOrig = view.getFieldAs<double>(Id::Y, idx); double zOrig = view.getFieldAs<double>(Id::Z, idx); double x = (xOrig - m_xXform.m_offset) / m_xXform.m_scale; double y = (yOrig - m_yXform.m_offset) / m_yXform.m_scale; double z = (zOrig - m_zXform.m_offset) / m_zXform.m_scale; ostream << boost::numeric_cast<int32_t>(lround(x)); ostream << boost::numeric_cast<int32_t>(lround(y)); ostream << boost::numeric_cast<int32_t>(lround(z)); uint16_t intensity = 0; if (view.hasDim(Id::Intensity)) intensity = view.getFieldAs<uint16_t>(Id::Intensity, idx); ostream << intensity; uint8_t scanDirectionFlag(0); if (view.hasDim(Id::ScanDirectionFlag)) scanDirectionFlag = view.getFieldAs<uint8_t>( Id::ScanDirectionFlag, idx); uint8_t edgeOfFlightLine(0); if (view.hasDim(Id::EdgeOfFlightLine)) edgeOfFlightLine = view.getFieldAs<uint8_t>( Id::EdgeOfFlightLine, idx); uint8_t bits = returnNumber | (numberOfReturns<<3) | (scanDirectionFlag << 6) | (edgeOfFlightLine << 7); ostream << bits; uint8_t classification = 0; if (view.hasDim(Id::Classification)) classification = view.getFieldAs<uint8_t>(Id::Classification, idx); ostream << classification; int8_t scanAngleRank = 0; if (view.hasDim(Id::ScanAngleRank)) scanAngleRank = view.getFieldAs<int8_t>(Id::ScanAngleRank, idx); ostream << scanAngleRank; uint8_t userData = 0; if (view.hasDim(Id::UserData)) userData = view.getFieldAs<uint8_t>(Id::UserData, idx); ostream << userData; uint16_t pointSourceId = 0; if (view.hasDim(Id::PointSourceId)) pointSourceId = view.getFieldAs<uint16_t>(Id::PointSourceId, idx); ostream << pointSourceId; if (hasTime) { double t = 0.0; if (view.hasDim(Id::GpsTime)) t = view.getFieldAs<double>(Id::GpsTime, idx); ostream << t; } if (hasColor) { uint16_t red = 0; uint16_t green = 0; uint16_t blue = 0; if (view.hasDim(Id::Red)) red = view.getFieldAs<uint16_t>(Id::Red, idx); if (view.hasDim(Id::Green)) green = view.getFieldAs<uint16_t>(Id::Green, idx); if (view.hasDim(Id::Blue)) blue = view.getFieldAs<uint16_t>(Id::Blue, idx); ostream << red << green << blue; } Everything e; for (auto& dim : m_extraDims) { view.getField((char *)&e, dim.m_dimType.m_id, dim.m_dimType.m_type, idx); ostream.put(dim.m_dimType.m_type, e); } using namespace Dimension; m_summaryData.addPoint(xOrig, yOrig, zOrig, returnNumber); } return blocksize; }