Skip to content

Commit 1b5a51b

Browse files
committed
implement endian-aware reader support
1 parent 63e3a1a commit 1b5a51b

File tree

6 files changed

+218
-5
lines changed

6 files changed

+218
-5
lines changed

pdal/io/NumpyReader.cpp

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <pdal/util/ProgramArgs.hpp>
4242
#include <pdal/util/FileUtils.hpp>
4343
#include <pdal/util/Algorithm.hpp>
44+
#include <pdal/util/Extractor.hpp>
4445

4546
#include "../plang/Environment.hpp"
4647

@@ -407,10 +408,13 @@ void NumpyReader::createFields(PointLayoutPtr layout)
407408
offset = PyLong_AsLong(offset_o);
408409

409410
// Get type.
410-
type = getType((PyArray_Descr *)PySequence_Fast_GET_ITEM(tup, 0),
411-
name);
411+
PyArray_Descr* dt = (PyArray_Descr *)PySequence_Fast_GET_ITEM(tup, 0);
412+
type = getType(dt, name);
413+
414+
char byteorder = dt->byteorder;
415+
int elsize = dt->elsize;
412416
id = registerDim(layout, name, type);
413-
m_fields.push_back({id, type, offset});
417+
m_fields.push_back({id, type, offset, byteorder, elsize});
414418
}
415419
}
416420
}
@@ -510,6 +514,12 @@ void NumpyReader::ready(PointTableRef table)
510514
for (npy_intp i = 0; i < m_ndims; ++i)
511515
log()->get(LogLevel::Debug) << "numpy shape dimension number '" <<
512516
i << "' is '" << m_shape[i] <<"'" << std::endl;
517+
518+
PointLayoutPtr layout = table.layout();
519+
MetadataNode m = layout->toMetadata();
520+
521+
pdal::Utils::toJSON(m, log()->get(LogLevel::Debug3));
522+
513523
}
514524

515525
bool NumpyReader::nextPoint()
@@ -530,12 +540,101 @@ bool NumpyReader::nextPoint()
530540
}
531541

532542

543+
544+
533545
bool NumpyReader::loadPoint(PointRef& point, point_count_t position)
534546
{
535547
using namespace Dimension;
536548

549+
pdal::SwitchableExtractor extractor(p_data, *m_strideptr);
550+
551+
std::vector<char> buf(*m_strideptr,0);
552+
553+
float flt(0.0);
554+
double dbl(0.0);
555+
uint8_t uint8(0);
556+
uint16_t uint16(0);
557+
uint32_t uint32(0);
558+
uint64_t uint64(0);
559+
int8_t int8(0);
560+
int16_t int16(0);
561+
int32_t int32(0);
562+
int64_t int64(0);
563+
537564
for (const Field& f : m_fields)
538-
point.setField(f.m_id, f.m_type, (void*)(p_data + f.m_offset));
565+
{
566+
if (f.m_byteorder == '>')
567+
extractor.switchToBigEndian();
568+
else
569+
extractor.switchToLittleEndian();
570+
571+
if (Dimension::base(f.m_type) == Dimension::BaseType::Floating)
572+
{
573+
if (f.m_elsize == 4)
574+
{
575+
extractor >> flt;
576+
point.setField<float>(f.m_id, flt);
577+
}
578+
else if (f.m_elsize == 8)
579+
{
580+
extractor >> dbl;
581+
point.setField<double>(f.m_id, dbl);
582+
583+
}
584+
}
585+
else if (Dimension::base(f.m_type) == Dimension::BaseType::Signed)
586+
{
587+
if (f.m_elsize == 1)
588+
{
589+
extractor >> int8;
590+
point.setField<int8_t>(f.m_id, int8);
591+
}
592+
if (f.m_elsize == 2)
593+
{
594+
extractor >> int16;
595+
point.setField<int16_t>(f.m_id, int16);
596+
}
597+
if (f.m_elsize == 4)
598+
{
599+
extractor >> int32;
600+
point.setField<int32_t>(f.m_id, int32);
601+
}
602+
if (f.m_elsize == 8)
603+
{
604+
extractor >> int64;
605+
point.setField<int64_t>(f.m_id, int64);
606+
}
607+
}
608+
else if (Dimension::base(f.m_type) == Dimension::BaseType::Unsigned)
609+
{
610+
if (f.m_elsize == 1)
611+
{
612+
extractor >> uint8;
613+
point.setField<uint8_t>(f.m_id, uint8);
614+
}
615+
if (f.m_elsize == 2)
616+
{
617+
extractor >> uint16;
618+
point.setField<uint16_t>(f.m_id, uint16);
619+
}
620+
if (f.m_elsize == 4)
621+
{
622+
extractor >> uint32;
623+
point.setField<uint32_t>(f.m_id, uint32);
624+
}
625+
if (f.m_elsize == 8)
626+
{
627+
extractor >> int64;
628+
point.setField<uint64_t>(f.m_id, uint64);
629+
}
630+
}
631+
else
632+
{
633+
// skip it
634+
extractor.skip(f.m_elsize);
635+
}
636+
637+
}
539638

540639
if (m_storeXYZ)
541640
{

pdal/io/NumpyReader.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ class PDAL_DLL NumpyReader : public Reader, public Streamable
120120
Dimension::Id m_id;
121121
Dimension::Type m_type;
122122
int m_offset;
123+
char m_byteorder;
124+
int m_elsize;
123125
};
124126
std::vector<Field> m_fields;
125127
point_count_t m_index;

pdal/test/NumpyReaderTest.cpp

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ TEST(NumpyReaderTest, NumpyReaderTest_read_array)
9191
EXPECT_EQ(view->layout()->pointSize(), 24u);
9292

9393
EXPECT_EQ(view->getFieldAs<double>(pdal::Dimension::Id::Intensity,5000),
94-
0.5);
94+
0.0);
9595
EXPECT_EQ(view->getFieldAs<uint32_t>(pdal::Dimension::Id::X,5000), 50u);
9696
EXPECT_EQ(view->getFieldAs<uint32_t>(pdal::Dimension::Id::X,5023), 50u);
9797
EXPECT_EQ(view->getFieldAs<uint32_t>(pdal::Dimension::Id::Y,5023), 23u);
@@ -236,3 +236,100 @@ TEST(NumpyReaderTest, threedim_col)
236236
}
237237
}
238238

239+
240+
TEST(NumpyReaderTest, threedim_row_script)
241+
{
242+
StageFactory f;
243+
244+
Options opts;
245+
opts.add("filename", Support::datapath("threedim.py"));
246+
opts.add("order", "row");
247+
opts.add("function", "load");
248+
opts.add("module", "threedim");
249+
opts.add("fargs", Support::datapath("threedim.npy"));
250+
251+
NumpyReader reader;
252+
reader.setOptions(opts);
253+
254+
PointTable table;
255+
256+
reader.prepare(table);
257+
258+
PointViewSet viewSet = reader.execute(table);
259+
PointViewPtr view = *viewSet.begin();
260+
PointLayoutPtr layout = view->layout();
261+
Dimension::Id health = layout->findDim("Health");
262+
Dimension::Id foo = layout->findDim("Foo");
263+
264+
EXPECT_EQ(view->size(), 24u);
265+
int ex = 0;
266+
int ey = 0;
267+
int ez = 0;
268+
for (PointId id = 0; id < view->size(); ++id)
269+
{
270+
int f = view->getFieldAs<int>(foo, id);
271+
int h = view->getFieldAs<int>(health, id);
272+
int i = view->getFieldAs<int>(Dimension::Id::Intensity, id);
273+
int x = view->getFieldAs<int>(Dimension::Id::X, id);
274+
int y = view->getFieldAs<int>(Dimension::Id::Y, id);
275+
int z = view->getFieldAs<int>(Dimension::Id::Z, id);
276+
EXPECT_EQ(f, ((int)id / 12) % 2);
277+
EXPECT_EQ(h, ((int)id / 4) % 3);
278+
EXPECT_EQ(i, (int)id % 4);
279+
EXPECT_EQ(x, ex);
280+
EXPECT_EQ(y, ey);
281+
EXPECT_EQ(z, ez);
282+
// Array is 2 x 3 x 4
283+
ez++;
284+
if (ez == 4)
285+
{
286+
ez = 0;
287+
ey++;
288+
if (ey == 3)
289+
{
290+
ey = 0;
291+
ex++;
292+
}
293+
}
294+
}
295+
}
296+
297+
TEST(NumpyReaderTest, four_floats_script)
298+
{
299+
StageFactory f;
300+
301+
Options opts;
302+
opts.add("filename", Support::datapath("four-floats.py"));
303+
opts.add("order", "row");
304+
opts.add("function", "load");
305+
opts.add("module", "four_floats");
306+
opts.add("fargs", Support::datapath("four-floats-be.bin"));
307+
308+
NumpyReader reader;
309+
reader.setOptions(opts);
310+
311+
PointTable table;
312+
313+
reader.prepare(table);
314+
315+
PointViewSet viewSet = reader.execute(table);
316+
PointViewPtr view = *viewSet.begin();
317+
PointLayoutPtr layout = view->layout();
318+
319+
EXPECT_EQ(view->size(), 10u);
320+
int ex = 0;
321+
int ey = 0;
322+
int ez = 0;
323+
int factor = 10;
324+
for (PointId id = 0; id < view->size(); ++id)
325+
{
326+
int t = view->getFieldAs<int>(Dimension::Id::GpsTime, id);
327+
int x = view->getFieldAs<int>(Dimension::Id::X, id);
328+
int y = view->getFieldAs<int>(Dimension::Id::Y, id);
329+
int z = view->getFieldAs<int>(Dimension::Id::Z, id);
330+
EXPECT_EQ(x, (int)id * 1 * factor);
331+
EXPECT_EQ(y, (int)id * 2 * factor);
332+
EXPECT_EQ(z, (int)id * 3 * factor);
333+
EXPECT_EQ(t, (int)id * 4 * factor);
334+
}
335+
}

pdal/test/data/four-floats-be.bin

160 Bytes
Binary file not shown.

pdal/test/data/four-floats.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import numpy as np
2+
3+
4+
dtype = np.dtype([('X', '>f4'), ('Y', '>f4'), ('Z', '>f4'), ('GPSTime', '>f4')])
5+
6+
def load(filename):
7+
data = open(filename, 'rb').read()
8+
array = np.frombuffer(data, dtype=dtype)
9+
10+
return array

pdal/test/data/threedim.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import numpy as np
2+
3+
def load(filename):
4+
array = np.load(filename)
5+
return array

0 commit comments

Comments
 (0)