Skip to content

Commit

Permalink
More flexible handling for transformation matrix (#2569)
Browse files Browse the repository at this point in the history
* Temp checkin.

* Initial check-in.

* Make TransformationFilter more generic.

* Add doFilter().

* Remove extra "public".

* More PDAL_DLL.

* Remove accidentally added files.
  • Loading branch information
abellgithub committed Jun 20, 2019
1 parent 105a1a2 commit 7d6b575
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 58 deletions.
79 changes: 57 additions & 22 deletions filters/TransformationFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,68 +48,103 @@ static StaticPluginInfo const s_info

CREATE_STATIC_STAGE(TransformationFilter, s_info)

std::string TransformationFilter::getName() const { return s_info.name; }
TransformationFilter::Transform::Transform()
{}


TransformationFilter::Transform::Transform(
const TransformationFilter::Transform::ArrayType& arr) : m_vals(arr)
{}

TransformationMatrix transformationMatrixFromString(const std::string& s)

std::istream& operator>>(std::istream& in,
pdal::TransformationFilter::Transform& xform)
{
std::istringstream iss(s);
TransformationMatrix matrix{{ 0 }};
double entry;
TransformationMatrix::size_type i = 0;
while (iss >> entry)

size_t i = 0;
while (in >> entry)
{
if (i + 1 > matrix.size())
if (i + 1 > xform.Size)
{
std::stringstream msg;
msg << "Too many entries in transformation matrix, should be "
<< matrix.size();
<< xform.Size;
throw pdal_error("filters.transformation: " + msg.str());
}
matrix[i++] = entry;
xform[i++] = entry;
}

if (i != matrix.size())
if (i != xform.Size)
{
std::stringstream msg;
msg << "Too few entries in transformation matrix: "
<< i
<< " (should be "
<< matrix.size()
<< ")";

<< i << " (should be " << xform.Size << ")";
throw pdal_error("filters.transformation: " + msg.str());
}
in.clear();

return matrix;
return in;
}


std::ostream& operator<<(std::ostream& out,
const pdal::TransformationFilter::Transform& xform)
{
for (size_t r = 0; r < xform.RowSize; ++r)
{
for (size_t c = 0; c < xform.ColSize; ++c)
{
if (c != 0)
out << " ";
out << xform[r * xform.ColSize + c];
}
out << "\n";
}
return out;
}


TransformationFilter::TransformationFilter() : m_matrix(new Transform)
{}


TransformationFilter::~TransformationFilter()
{}


std::string TransformationFilter::getName() const { return s_info.name; }

void TransformationFilter::addArgs(ProgramArgs& args)
{
args.add("matrix", "Transformation matrix", m_matrixSpec).setPositional();
args.add("matrix", "Transformation matrix", *m_matrix).setPositional();
}


void TransformationFilter::initialize()
void TransformationFilter::doFilter(PointView& view,
const TransformationFilter::Transform& matrix)
{
m_matrix = transformationMatrixFromString(m_matrixSpec);
*m_matrix = matrix;
filter(view);
}


bool TransformationFilter::processOne(PointRef& point)
{
Transform& matrix = *m_matrix;

double x = point.getFieldAs<double>(Dimension::Id::X);
double y = point.getFieldAs<double>(Dimension::Id::Y);
double z = point.getFieldAs<double>(Dimension::Id::Z);

point.setField(Dimension::Id::X,
x * m_matrix[0] + y * m_matrix[1] + z * m_matrix[2] + m_matrix[3]);
x * matrix[0] + y * matrix[1] + z * matrix[2] + matrix[3]);

point.setField(Dimension::Id::Y,
x * m_matrix[4] + y * m_matrix[5] + z * m_matrix[6] + m_matrix[7]);
x * matrix[4] + y * matrix[5] + z * matrix[6] + matrix[7]);

point.setField(Dimension::Id::Z,
x * m_matrix[8] + y * m_matrix[9] + z * m_matrix[10] + m_matrix[11]);
x * matrix[8] + y * matrix[9] + z * matrix[10] + matrix[11]);
return true;
}

Expand Down
49 changes: 33 additions & 16 deletions filters/TransformationFilter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,34 +44,51 @@
namespace pdal
{

// Transformation matrices are assumed to be stored in row-major order
typedef std::array<double, 16> TransformationMatrix;


TransformationMatrix
PDAL_DLL transformationMatrixFromString(const std::string& s);


class PDAL_DLL TransformationFilter : public Filter, public Streamable
{
public:
TransformationFilter() : Filter()
{}
class Transform;

TransformationFilter();
~TransformationFilter();
TransformationFilter& operator=(const TransformationFilter&) = delete;
TransformationFilter(const TransformationFilter&) = delete;

std::string getName() const;
void doFilter(PointView& view, const Transform& matrix);

private:
TransformationFilter& operator=(const TransformationFilter&); // not implemented
TransformationFilter(const TransformationFilter&); // not implemented

virtual void addArgs(ProgramArgs& args);
virtual void initialize();
virtual bool processOne(PointRef& point);
virtual void filter(PointView& view);

std::string m_matrixSpec;
TransformationMatrix m_matrix;
std::unique_ptr<Transform> m_matrix;
};

class TransformationFilter::Transform
{
public:
static const size_t RowSize = 4;
static const size_t ColSize = 4;
static const size_t Size = RowSize * ColSize;
typedef double ValueType;
typedef std::array<ValueType, Size> ArrayType;

PDAL_DLL Transform();
PDAL_DLL Transform(const ArrayType& arr);

PDAL_DLL double operator[](size_t off) const
{ return m_vals[off]; }
PDAL_DLL double& operator[](size_t off)
{ return m_vals[off]; }

private:
ArrayType m_vals;

PDAL_DLL friend std::istream& operator>>(std::istream& in,
pdal::TransformationFilter::Transform& xform);
PDAL_DLL friend std::ostream& operator<<(std::ostream& out,
const pdal::TransformationFilter::Transform& xform);
};

} // namespace pdal
60 changes: 40 additions & 20 deletions test/unit/filters/TransformationFilterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,40 +71,60 @@ TEST(TransformationMatrix, create)
}


TEST(TransformationMatrix, FromString)
TEST(TransformationMatrix, init)
{
auto check = [](const TransformationFilter::Transform& m)
{
EXPECT_DOUBLE_EQ(1, m[0]);
EXPECT_DOUBLE_EQ(0, m[1]);
EXPECT_DOUBLE_EQ(0, m[2]);
EXPECT_DOUBLE_EQ(0, m[3]);
EXPECT_DOUBLE_EQ(0, m[4]);
EXPECT_DOUBLE_EQ(1, m[5]);
EXPECT_DOUBLE_EQ(0, m[6]);
EXPECT_DOUBLE_EQ(0, m[7]);
EXPECT_DOUBLE_EQ(0, m[8]);
EXPECT_DOUBLE_EQ(0, m[9]);
EXPECT_DOUBLE_EQ(1, m[10]);
EXPECT_DOUBLE_EQ(0, m[11]);
EXPECT_DOUBLE_EQ(0, m[12]);
EXPECT_DOUBLE_EQ(0, m[13]);
EXPECT_DOUBLE_EQ(0, m[14]);
EXPECT_DOUBLE_EQ(1, m[15]);
};

std::string s = "1 0 0 0\n0 1 0 0\n0 0 1 0\n0 0 0 1";
TransformationMatrix m = transformationMatrixFromString(s);
EXPECT_DOUBLE_EQ(1, m[0]);
EXPECT_DOUBLE_EQ(0, m[1]);
EXPECT_DOUBLE_EQ(0, m[2]);
EXPECT_DOUBLE_EQ(0, m[3]);
EXPECT_DOUBLE_EQ(0, m[4]);
EXPECT_DOUBLE_EQ(1, m[5]);
EXPECT_DOUBLE_EQ(0, m[6]);
EXPECT_DOUBLE_EQ(0, m[7]);
EXPECT_DOUBLE_EQ(0, m[8]);
EXPECT_DOUBLE_EQ(0, m[9]);
EXPECT_DOUBLE_EQ(1, m[10]);
EXPECT_DOUBLE_EQ(0, m[11]);
EXPECT_DOUBLE_EQ(0, m[12]);
EXPECT_DOUBLE_EQ(0, m[13]);
EXPECT_DOUBLE_EQ(0, m[14]);
EXPECT_DOUBLE_EQ(1, m[15]);
TransformationFilter::Transform m;

std::stringstream iss(s);
iss >> m;
check(m);

TransformationFilter::Transform n { { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 } };
check(n);
}


TEST(TransformationMatrix, TooShort)
{
std::string s = "1 0 0 0\n0 1 0 0\n0 0 1 0\n0 0 0";
EXPECT_THROW(transformationMatrixFromString(s), pdal_error);
TransformationFilter::Transform m;
std::stringstream iss(s);

EXPECT_THROW(iss >> m, pdal_error);
}


TEST(TransformationMatrix, TooLong)
{
std::string s = "1 0 0 0\n0 1 0 0\n0 0 1 0\n0 0 0 1 0";
EXPECT_THROW(transformationMatrixFromString(s), pdal_error);
TransformationFilter::Transform m;
std::stringstream iss(s);

EXPECT_THROW(iss >> m, pdal_error);
}


Expand Down

0 comments on commit 7d6b575

Please sign in to comment.