Skip to content

Commit

Permalink
Write bits dimensions to a special PDAL dimension.
Browse files Browse the repository at this point in the history
  • Loading branch information
abellgithub committed Dec 7, 2023
1 parent b150b25 commit 8154c0a
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 197 deletions.
1 change: 0 additions & 1 deletion bu/CopcSupport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

#include "../untwine/Common.hpp"
#include "../untwine/FileDimInfo.hpp"
#include "../untwine/Las.hpp"

namespace untwine
{
Expand Down
2 changes: 2 additions & 0 deletions bu/PointAccessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class PointAccessor

size_t size()
{
// start() returns the number of points in the file infos before the last one.
// adding numPoints() provides the total number of points.
if (m_fileInfos.empty())
return 0;
else
Expand Down
62 changes: 12 additions & 50 deletions bu/Processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <random>

#include "../untwine/GridKey.hpp"
#include "../untwine/Las.hpp"

#include <pdal/PDALUtils.hpp>
#include <pdal/StageFactory.hpp>
Expand Down Expand Up @@ -330,7 +329,6 @@ Processor::writeOctantCompressed(const OctantInfo& o, Index& index, IndexIter po
// there's no reason why it should change. We should modify things to use a single
// layout.

Dimension::IdList lasDims = pdrfDims(m_b.pointFormatId);
DimInfoList dims = m_b.dimInfo;
m_extraDims.clear();
for (FileDimInfo& fdi : dims)
Expand All @@ -346,7 +344,7 @@ Processor::writeOctantCompressed(const OctantInfo& o, Index& index, IndexIter po
else
stats.push_back({fdi.dim, Stats(fdi.name, Stats::EnumType::NoEnum, false)});
}
if (!Utils::contains(lasDims, fdi.dim))
if (isExtraDim(fdi))
m_extraDims.push_back(DimType(fdi.dim, fdi.type));
}
table.finalize();
Expand Down Expand Up @@ -530,7 +528,7 @@ void Processor::createChunk(const VoxelKey& key, pdal::PointViewPtr view)
for (PointId idx = 0; idx < view->size(); ++idx)
{
PointRef point(*view, idx);
fillPointBuf(point, buf);
fillPointBuf(point, buf, layout->findDim(UntwineBitsDimName));
compressor.compress(buf.data());
}
std::vector<unsigned char> chunk = compressor.done();
Expand All @@ -546,14 +544,13 @@ void Processor::createChunk(const VoxelKey& key, pdal::PointViewPtr view)
throw FatalError("Failure writing to '" + m_b.opts.outputName + "'.");
}

void Processor::fillPointBuf(pdal::PointRef& point, std::vector<char>& buf)
void Processor::fillPointBuf(pdal::PointRef& point, std::vector<char>& buf,
pdal::Dimension::Id bitsDim)
{
using namespace pdal;

LeInserter ostream(buf.data(), buf.size());

// We only write PDRF 6, 7, or 8.
bool has14PointFormat = true;
bool hasTime = true; // m_lasHeader.hasTime();
bool hasColor = m_b.pointFormatId == 7 || m_b.pointFormatId == 8;
bool hasInfrared = m_b.pointFormatId == 8;
Expand Down Expand Up @@ -589,51 +586,16 @@ void Processor::fillPointBuf(pdal::PointRef& point, std::vector<char>& buf)
ostream << z;

ostream << point.getFieldAs<uint16_t>(Id::Intensity);

uint8_t scanChannel = point.getFieldAs<uint8_t>(Id::ScanChannel);
uint8_t scanDirectionFlag = point.getFieldAs<uint8_t>(Id::ScanDirectionFlag);
uint8_t edgeOfFlightLine = point.getFieldAs<uint8_t>(Id::EdgeOfFlightLine);
uint8_t classification = point.getFieldAs<uint8_t>(Id::Classification);

if (has14PointFormat)
{
uint8_t bits = returnNumber | (numberOfReturns << 4);
ostream << bits;

uint8_t classFlags;
if (point.hasDim(Id::ClassFlags))
classFlags = point.getFieldAs<uint8_t>(Id::ClassFlags);
else
classFlags = classification >> 5;
bits = (classFlags & 0x0F) |
((scanChannel & 0x03) << 4) |
((scanDirectionFlag & 0x01) << 6) |
((edgeOfFlightLine & 0x01) << 7);
ostream << bits;
}
else
{
uint8_t bits = returnNumber | (numberOfReturns << 3) |
(scanDirectionFlag << 6) | (edgeOfFlightLine << 7);
ostream << bits;
}

ostream << classification;
ostream << (uint8_t)(returnNumber | (numberOfReturns << 4));
ostream << point.getFieldAs<uint8_t>(bitsDim);
ostream << point.getFieldAs<uint8_t>(Id::Classification);

uint8_t userData = point.getFieldAs<uint8_t>(Id::UserData);
if (has14PointFormat)
{
// Guaranteed to fit if scan angle rank isn't wonky.
int16_t scanAngleRank =
static_cast<int16_t>(std::round(
point.getFieldAs<float>(Id::ScanAngleRank) / .006f));
ostream << userData << scanAngleRank;
}
else
{
int8_t scanAngleRank = point.getFieldAs<int8_t>(Id::ScanAngleRank);
ostream << scanAngleRank << userData;
}
// Guaranteed to fit if scan angle rank isn't wonky.
int16_t scanAngleRank =
static_cast<int16_t>(std::round(
point.getFieldAs<float>(Id::ScanAngleRank) / .006f));
ostream << userData << scanAngleRank;

ostream << point.getFieldAs<uint16_t>(Id::PointSourceId);

Expand Down
2 changes: 1 addition & 1 deletion bu/Processor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class Processor
void writeEptFile(const std::string& filename, pdal::PointViewPtr view);
void createChunk(const VoxelKey& key, pdal::PointViewPtr view);
void sortChunk(pdal::PointViewPtr view);
void fillPointBuf(pdal::PointRef& point, std::vector<char>& buf);
void fillPointBuf(pdal::PointRef& point, std::vector<char>& buf, pdal::Dimension::Id bitsDim);

VoxelInfo m_vi;
const BaseInfo& m_b;
Expand Down
57 changes: 37 additions & 20 deletions epf/Epf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "Reprocessor.hpp"
#include "Writer.hpp"
#include "../untwine/Common.hpp"
#include "../untwine/Las.hpp"

#include <cmath>
#include <filesystem>
Expand All @@ -32,7 +31,6 @@
#include <pdal/util/FileUtils.hpp>
#include <pdal/util/ProgramArgs.hpp>


namespace
{

Expand Down Expand Up @@ -100,6 +98,24 @@ std::vector<std::string> directoryList(const std::string& dir)
}
#endif

pdal::Dimension::Type getDimensionType(const std::string& name)
{
using namespace pdal;

if (name == untwine::UntwineBitsDimName)
return untwine::UntwineBitsType;

Dimension::Type type = Dimension::Type::Double;
try
{
type = Dimension::defaultType(Dimension::id(name));
}
catch (pdal_error&)
{}

return type;
}

} // unnamed namespace

namespace untwine
Expand All @@ -117,7 +133,6 @@ Epf::Epf(BaseInfo& common) : m_b(common), m_pool(NumFileProcessors)
Epf::~Epf()
{}


void Epf::run(ProgressWriter& progress)
{
using namespace pdal;
Expand Down Expand Up @@ -148,21 +163,15 @@ void Epf::run(ProgressWriter& progress)
for (const FileDimInfo& fdi : fi.dimInfo)
allDimNames.insert(fdi.name);

// Create an OUTPUT layout.
// Register the dimensions, either as the default type or double if we don't know
// what it is.
PointLayoutPtr layout(new PointLayout());
for (const std::string& dimName : allDimNames)
for (std::string dimName : allDimNames)
{
Dimension::Type type;
try
{
type = Dimension::defaultType(Dimension::id(dimName));
}
catch (pdal::pdal_error&)
{
type = Dimension::Type::Double;
}
layout->registerOrAssignDim(dimName, type);
if (isUntwineBitsDim(dimName))
dimName = UntwineBitsDimName;
layout->registerOrAssignDim(dimName, getDimensionType(dimName));
}
layout->finalize();

Expand All @@ -171,9 +180,20 @@ void Epf::run(ProgressWriter& progress)
{
for (FileDimInfo& di : fi.dimInfo)
{
di.dim = layout->findDim(di.name);
di.type = layout->dimType(di.dim);
di.offset = layout->dimOffset(di.dim);
// If this dimension is one of the bit dimensions, set the shift and offset accordingly.
int bitPos = getUntwineBitPos(di.name);
if (bitPos != -1)
{
di.type = UntwineBitsType;
di.offset = layout->dimOffset(layout->findDim(UntwineBitsDimName));
di.shift = bitPos;
}
else
{
Dimension::Id dim = layout->findDim(di.name);
di.type = layout->dimType(dim);
di.offset = layout->dimOffset(dim);
}
}
}

Expand Down Expand Up @@ -274,15 +294,12 @@ void Epf::fillMetadata(const pdal::PointLayoutPtr layout)
else
m_b.pointFormatId = 6;

const Dimension::IdList& lasDims = pdrfDims(m_b.pointFormatId);
for (Dimension::Id id : layout->dims())
{
FileDimInfo di;
di.name = layout->dimName(id);
di.type = layout->dimType(id);
di.offset = layout->dimOffset(id);
di.dim = id;
di.extraDim = !Utils::contains(lasDims, id);
m_b.pointSize += pdal::Dimension::size(di.type);
m_b.dimInfo.push_back(di);
}
Expand Down
43 changes: 40 additions & 3 deletions epf/FileProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,31 @@ namespace untwine
namespace epf
{

namespace
{

// The dimension IDs need to come from the *source* layout because it's possible in the
// case of user-defined dimensions that the IDs could vary for the same-named dimension
// in different input files. The "dim" field represents the ID of the dimension
// we're reading from. "offset" is the corresponding notion in the output packed point data.
void setDimensions(pdal::PointLayoutPtr layout, FileInfo& fi, int& classflagsOffset)
{
for (FileDimInfo& di : fi.dimInfo)
{
di.dim = layout->findDim(di.name);
assert(di.dim != pdal::Dimension::Id::Unknown);

// If we have a bit offset, then we're really writing to the classflags field in the
// output point. Fetch that offset and set it. We will probably do this several
// times (once for each bit), but the value should always be the same.
if (di.shift != -1)
classflagsOffset = di.offset;
}
}

} // unnamed namespace


FileProcessor::FileProcessor(const FileInfo& fi, size_t pointSize, const Grid& grid,
Writer *writer, ProgressWriter& progress) :
m_fi(fi), m_cellMgr(pointSize, writer), m_grid(grid), m_progress(progress)
Expand All @@ -42,6 +67,7 @@ void FileProcessor::run()
pdal::Stage *s = factory.createStage(m_fi.driver);
s->setOptions(opts);

int classflagsOffset;
PointCount count = 0;

// We need to move the data from the PointRef to some output buffer. We copy the data
Expand All @@ -54,14 +80,24 @@ void FileProcessor::run()
Cell *cell = m_cellMgr.get(VoxelKey());

pdal::StreamCallbackFilter f;
f.setCallback([this, &count, &cell](pdal::PointRef& point)
f.setCallback([this, &count, &cell, &classflagsOffset](pdal::PointRef& point)
{
// Write the data into the point buffer in the cell. This is the *last*
// cell buffer that we used. We're hoping that it's the right one.
Point p = cell->point();
uint8_t untwineBits = 0;
for (const FileDimInfo& fdi : m_fi.dimInfo)
point.getField(reinterpret_cast<char *>(p.data() + fdi.offset),
fdi.dim, fdi.type);
{
if (fdi.shift == -1)
point.getField(reinterpret_cast<char *>(p.data() + fdi.offset),
fdi.dim, fdi.type);
else
untwineBits |= (point.getFieldAs<uint8_t>(fdi.dim) << fdi.shift);
}

// We pack all the bitfields into classflags.
if (untwineBits)
memcpy(p.data() + classflagsOffset, &untwineBits, 1);

// Find the actual cell that this point belongs in. If it's not the one
// we chose, copy the data to the correct cell.
Expand Down Expand Up @@ -95,6 +131,7 @@ void FileProcessor::run()
try
{
f.prepare(t);
setDimensions(t.layout(), m_fi, classflagsOffset);
f.execute(t);
}
catch (const pdal::pdal_error& err)
Expand Down
Loading

0 comments on commit 8154c0a

Please sign in to comment.