Skip to content

Commit

Permalink
Merge branch 'issue-3313' into lazperf
Browse files Browse the repository at this point in the history
  • Loading branch information
abellgithub committed Mar 3, 2021
2 parents 2ae292d + 8b1c597 commit afa281e
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 15 deletions.
12 changes: 9 additions & 3 deletions io/GDALWriter.cpp
Expand Up @@ -202,9 +202,15 @@ int GDALWriter::height() const

void GDALWriter::createGrid(BOX2D bounds)
{
int width = (int)std::floor((bounds.maxx - bounds.minx) / m_edgeLength) + 1;
int height = (int)std::floor((bounds.maxy - bounds.miny) / m_edgeLength) + 1;

// Validating before casting avoids float-cast-overflow undefined behavior.
double d_width = std::floor((bounds.maxx - bounds.minx) / m_edgeLength) + 1;
double d_height = std::floor((bounds.maxy - bounds.miny) / m_edgeLength) + 1;
if (d_width < 0.0 || d_width > (std::numeric_limits<int>::max)())
throwError("Grid width out of range.");
if (d_height < 0.0 || d_height > (std::numeric_limits<int>::max)())
throwError("Grid height out of range.");
int width = static_cast<int>(d_width);
int height = static_cast<int>(d_height);
try
{
m_grid.reset(new GDALGrid(bounds.minx, bounds.miny, width, height, m_edgeLength,
Expand Down
2 changes: 1 addition & 1 deletion io/LasHeader.hpp
Expand Up @@ -222,7 +222,7 @@ class PDAL_DLL LasHeader
}

/// The length in bytes of each point. All points in the file are
/// considered to be fixed in size, and the PointFormatName is used
/// considered to be fixed in size, and the point format is used
/// to determine the fixed portion of the dimensions in the point.
uint16_t pointLen() const
{ return m_pointLen; }
Expand Down
20 changes: 15 additions & 5 deletions io/LasReader.cpp
Expand Up @@ -83,6 +83,7 @@ struct LasReader::Args
bool useEbVlr;
StringList ignoreVLROption;
bool fixNames;
PointId start;
};

struct LasReader::Private
Expand Down Expand Up @@ -119,9 +120,9 @@ void LasReader::addArgs(ProgramArgs& args)
args.add("extra_dims", "Dimensions to assign to extra byte data",
m_args->extraDimSpec);
args.add("compression", "Decompressor to use", m_args->compression, "EITHER");
args.add("use_eb_vlr", "Use extra bytes VLR for 1.0 - 1.3 files",
m_args->useEbVlr);
args.add("use_eb_vlr", "Use extra bytes VLR for 1.0 - 1.3 files", m_args->useEbVlr);
args.add("ignore_vlr", "VLR userid/recordid to ignore", m_args->ignoreVLROption);
args.add("start", "Point at which reading should start (0-indexed).", m_args->start);
args.add("fix_dims", "Make invalid dimension names valid by changing "
"invalid characters to '_'", m_args->fixNames, true);
}
Expand Down Expand Up @@ -270,6 +271,9 @@ void LasReader::initializeLocal(PointTableRef table, MetadataNode& m)
m_p->header.removeVLR(i.m_userId);
}

if (m_args->start > m_p->header.pointCount())
throwError("'start' value of " + std::to_string(m_args->start) + " is too large. "
"File contains " + std::to_string(m_p->header.pointCount()) + " points.");
if (m_p->header.compressed())
handleCompressionOption();
#ifdef PDAL_HAVE_LASZIP
Expand Down Expand Up @@ -321,6 +325,7 @@ void LasReader::ready(PointTableRef table)
handleLaszip(laszip_open_reader_stream(m_p->laszip, *stream,
&compressed));
handleLaszip(laszip_get_point_pointer(m_p->laszip, &m_p->laszipPoint));
handleLaszip(laszip_seek_point(m_p->laszip, m_args->start));
}
#endif

Expand All @@ -329,8 +334,9 @@ void LasReader::ready(PointTableRef table)
{
delete m_p->decompressor;

const LasVLR *vlr = m_p->header.findVlr(LASZIP_USER_ID,
LASZIP_RECORD_ID);
if (m_args->start != 0)
throwError("LAZperf does not support the 'start' option.");
const LasVLR *vlr = m_p->header.findVlr(LASZIP_USER_ID, LASZIP_RECORD_ID);
if (!vlr)
throwError("LAZ file missing required laszip VLR.");
int ebCount = m_p->header.pointLen() - m_p->header.basePointLen();
Expand All @@ -346,7 +352,11 @@ void LasReader::ready(PointTableRef table)
#endif
}
else
stream->seekg(m_p->header.pointOffset());
{
std::istream::pos_type start = m_p->header.pointOffset() +
(m_args->start * m_p->header.pointLen());
stream->seekg(start);
}
}


Expand Down
4 changes: 2 additions & 2 deletions io/LasWriter.cpp
Expand Up @@ -725,7 +725,7 @@ bool LasWriter::processOne(PointRef& point)
{
if (scale.m_auto)
log()->get(LogLevel::Warning) << "Auto scale for " << name <<
"requested in stream mode. Using value of 1.0." << std::endl;
" requested in stream mode. Using value of 1.0." << std::endl;
};

doScale(m_scaling.m_xXform.m_scale, "X");
Expand All @@ -739,7 +739,7 @@ bool LasWriter::processOne(PointRef& point)
{
offset.m_val = val;
log()->get(LogLevel::Warning) << "Auto offset for " << name <<
"requested in stream mode. Using value of " <<
" requested in stream mode. Using value of " <<
offset.m_val << "." << std::endl;
}
};
Expand Down
2 changes: 1 addition & 1 deletion pdal/pdal_config.hpp
Expand Up @@ -52,7 +52,7 @@ enum class Feature
ZSTD,
ZLIB,
LZMA,
LIBXML2,
LIBXML2
};

PDAL_DLL bool hasFeature(Feature f);
Expand Down
1 change: 1 addition & 0 deletions pdal_features.hpp.in
Expand Up @@ -29,6 +29,7 @@
#cmakedefine PDAL_HAVE_ZLIB
#cmakedefine PDAL_HAVE_LZMA
#cmakedefine PDAL_HAVE_LIBXML2
#define PDAL_LAS_START

/*
* Debug or Release build?
Expand Down
6 changes: 3 additions & 3 deletions test/unit/filters/FerryFilterTest.cpp
Expand Up @@ -119,10 +119,10 @@ TEST(FerryFilterTest, test_ferry_copy_json)
double x = view->getFieldAs<double>(state_plane_x, 0);
double y = view->getFieldAs<double>(state_plane_y, 0);

EXPECT_DOUBLE_EQ(-117.2501328350574, lon);
// proj 5 will consider +ellps=GRS80 +towgs84=0,0,0 to be slighly different
// than +datum=WGS84 and return 49.341077823260804.
EXPECT_NEAR(49.341077824192915, lat, 1e-9);
// than +datum=WGS84
EXPECT_NEAR(-117.25013, lon, 1e-4);
EXPECT_NEAR(49.34107, lat, 1e-4);
EXPECT_DOUBLE_EQ(637012.24, x);
EXPECT_DOUBLE_EQ(849028.31, y);
}
Expand Down
61 changes: 61 additions & 0 deletions test/unit/io/LasReaderTest.cpp
Expand Up @@ -41,6 +41,7 @@
#include <pdal/Streamable.hpp>
#include <io/LasHeader.hpp>
#include <io/LasReader.hpp>
#include <pdal/util/FileUtils.hpp>
#include "Support.hpp"

using namespace pdal;
Expand Down Expand Up @@ -551,3 +552,63 @@ TEST(LasReaderTest, SyntheticPoints)

EXPECT_EQ(ClassLabel::CreatedNeverClassified | ClassLabel::Synthetic, outView->getFieldAs<uint8_t>(Id::Classification, 0));
}

TEST(LasReaderTest, Start)
{
// Create a LAZ file that increments XYZ
std::string source = Support::temppath("increment.laz");
StageFactory f;
{
Stage *faux = f.createStage("readers.faux");
Options opts;
opts.add("mode", "ramp");
opts.add("bounds", "([0, 69999],[100,70099],[500,70499])");
opts.add("count", 70000);
faux->setOptions(opts);

Stage *las = f.createStage("writers.las");
Options opts2;
opts2.add("filename", source);
las->setOptions(opts2);
las->setInput(*faux);

PointTable t;
las->prepare(t);
las->execute(t);
}

{
Stage *las = f.createStage("readers.las");
Options opts;
opts.add("filename", source);
opts.add("start", 62520);
las->setOptions(opts);

PointTable t;
las->prepare(t);
PointViewSet s = las->execute(t);
PointViewPtr v = *s.begin();
EXPECT_EQ(v->getFieldAs<int>(Dimension::Id::X, 0), 62520);
EXPECT_EQ(v->getFieldAs<int>(Dimension::Id::Y, 0), 62620);
EXPECT_EQ(v->getFieldAs<int>(Dimension::Id::Z, 0), 63020);
}

{
Stage *las = f.createStage("readers.las");
Options opts;
opts.add("filename", source);
opts.add("start", 2525);
las->setOptions(opts);

PointTable t;
las->prepare(t);
PointViewSet s = las->execute(t);
PointViewPtr v = *s.begin();
EXPECT_EQ(v->getFieldAs<int>(Dimension::Id::X, 0), 2525);
EXPECT_EQ(v->getFieldAs<int>(Dimension::Id::Y, 0), 2625);
EXPECT_EQ(v->getFieldAs<int>(Dimension::Id::Z, 0), 3025);
}

// Delete the created file.
FileUtils::deleteFile(source);
}

0 comments on commit afa281e

Please sign in to comment.