diff --git a/io/private/las/Utils.cpp b/io/private/las/Utils.cpp index 74c670bb51..6f843f9788 100644 --- a/io/private/las/Utils.cpp +++ b/io/private/las/Utils.cpp @@ -682,11 +682,27 @@ void V14BaseLoader::load(PointRef& point, const char *buf, int bufsize) void V14BaseLoader::pack(const PointRef& point, char *buf, int bufsize) { LeInserter ostream(buf, bufsize); - int32_t xi = (int32_t)m_scaling.m_xXform.toScaled(point.getFieldAs(Dimension::Id::X)); - int32_t yi = (int32_t)m_scaling.m_yXform.toScaled(point.getFieldAs(Dimension::Id::Y)); - int32_t zi = (int32_t)m_scaling.m_zXform.toScaled(point.getFieldAs(Dimension::Id::Z)); - ostream << xi << yi << zi; + auto converter = [](double val, Dimension::Id dim) -> int32_t + { + int32_t i(0); + + if (!Utils::numericCast(val, i)) + throw std::runtime_error("Unable to convert scaled value (" + + Utils::toString(val) + ") to " + "int32 for dimension '" + Dimension::name(dim) ); + return i; + }; + + double xOrig = point.getFieldAs(Dimension::Id::X); + double yOrig = point.getFieldAs(Dimension::Id::Y); + double zOrig = point.getFieldAs(Dimension::Id::Z); + + int32_t x = converter(m_scaling.m_xXform.toScaled(xOrig), Dimension::Id::X); + int32_t y = converter(m_scaling.m_yXform.toScaled(yOrig), Dimension::Id::Y); + int32_t z = converter(m_scaling.m_zXform.toScaled(zOrig), Dimension::Id::Z); + + ostream << x << y << z; uint16_t intensity = point.getFieldAs(Dimension::Id::Intensity); int returnNum = point.getFieldAs(Dimension::Id::ReturnNumber); diff --git a/test/unit/io/CopcWriterTest.cpp b/test/unit/io/CopcWriterTest.cpp index 453377764a..e2cc8ea337 100644 --- a/test/unit/io/CopcWriterTest.cpp +++ b/test/unit/io/CopcWriterTest.cpp @@ -36,6 +36,8 @@ #include +#include +#include #include #include #include @@ -195,4 +197,56 @@ TEST(CopcWriterTest, srsUTM) EXPECT_TRUE(Utils::startsWith(data, "PROJCS[\"NAD83 / UTM zone 15N\"")); } +TEST(CopcWriterTest, scaling) +{ + using namespace Dimension; + + const std::string FILENAME(Support::temppath("copc_scaling.las")); + PointTable table; + + table.layout()->registerDims({Id::X, Id::Y, Id::Z}); + + BufferReader bufferReader; + + PointViewPtr view(new PointView(table)); + view->setField(Id::X, 0, 1406018.497); + view->setField(Id::Y, 0, 4917487.174); + view->setField(Id::Z, 0, 62.276); + bufferReader.addView(view); + + Options writerOps; + writerOps.add("filename", FILENAME); + writerOps.add("offset_x", "1000000"); + writerOps.add("scale_x", "0.001"); + writerOps.add("offset_y", "5000000"); + writerOps.add("scale_y", "0.001"); + writerOps.add("offset_z", "0"); + writerOps.add("scale_z", "0.001"); + + CopcWriter writer; + writer.setOptions(writerOps); + writer.setInput(bufferReader); + + writer.prepare(table); + writer.execute(table); + + Options readerOps; + readerOps.add("filename", FILENAME); + + PointTable readTable; + + LasReader reader; + reader.setOptions(readerOps); + + reader.prepare(readTable); + PointViewSet viewSet = reader.execute(readTable); + EXPECT_EQ(viewSet.size(), 1u); + view = *viewSet.begin(); + EXPECT_EQ(view->size(), 1u); + EXPECT_NEAR(1406018.497, view->getFieldAs(Id::X, 0), .00001); + EXPECT_NEAR(4917487.174, view->getFieldAs(Id::Y, 0), .00001); + EXPECT_NEAR(62.276, view->getFieldAs(Id::Z, 0), .00001); + FileUtils::deleteFile(FILENAME); +} + } // namespace pdal