diff --git a/include/pdal/PointBuffer.hpp b/include/pdal/PointBuffer.hpp index 20d8309e71..a12fbe2be9 100644 --- a/include/pdal/PointBuffer.hpp +++ b/include/pdal/PointBuffer.hpp @@ -267,7 +267,7 @@ class PDAL_DLL PointBuffer private: template - void convertAndSet(Dimension::Id::Enum dim, PointId idx, T_IN in); + bool convertAndSet(Dimension::Id::Enum dim, PointId idx, T_IN in); inline void setFieldInternal(Dimension::Id::Enum dim, PointId pointIndex, const void *value); @@ -479,26 +479,54 @@ inline T PointBuffer::getFieldAs(Dimension::Id::Enum dim, } + template -void PointBuffer::convertAndSet(Dimension::Id::Enum dim, PointId idx, T_IN in) +bool PointBuffer::convertAndSet(Dimension::Id::Enum dim, PointId idx, T_IN in) { +// This mess, instead of just using boost::numeric_cast, is here to: +// 1) Prevent the throwing of exceptions. The entrance/exit of the try +// block seemed somewhat expensive. +// 2) Round to nearest instead of truncation without rounding before +// invoking the converter. +// + using namespace boost; + static bool ok; + + struct RangeHandler + { + void operator() (numeric::range_check_result r) + { + ok = (r == numeric::cInRange); + } + }; + T_OUT out; + typedef numeric::conversion_traits conv_traits; + typedef numeric::numeric_cast_traits cast_traits; + typedef numeric::converter< + T_OUT, + T_IN, + conv_traits, + RangeHandler, + numeric::RoundEven, + numeric::raw_converter, + typename cast_traits::range_checking_policy> + localConverter; + #ifdef PDAL_COMPILER_MSVC // warning C4127: conditional expression is constant #pragma warning(push) #pragma warning(disable:4127) #endif + ok = true; // This is an optimization. if (std::is_same::value == true) out = in; else - { - if (std::is_integral::value == true) - out = boost::numeric_cast(lround(in)); - else - out = boost::numeric_cast(in); - } + out = localConverter::convert(in); + if (!ok) + return false; #ifdef PDAL_COMPILER_MSVC // warning C4127: conditional expression is constant @@ -506,6 +534,7 @@ void PointBuffer::convertAndSet(Dimension::Id::Enum dim, PointId idx, T_IN in) #endif setFieldInternal(dim, idx, (void *)&out); + return true; } @@ -514,45 +543,44 @@ void PointBuffer::setField(Dimension::Id::Enum dim, PointId idx, T val) { Dimension::Detail *dd = m_context.dimDetail(dim); - try { - switch (dd->type()) - { - case Dimension::Type::Float: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Double: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Signed8: - setFieldInternal(dim, idx, &val); - break; - case Dimension::Type::Signed16: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Signed32: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Signed64: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Unsigned8: - setFieldInternal(dim, idx, &val); - break; - case Dimension::Type::Unsigned16: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Unsigned32: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::Unsigned64: - convertAndSet(dim, idx, val); - break; - case Dimension::Type::None: - val = 0; - break; - } + bool ok = true; + switch (dd->type()) + { + case Dimension::Type::Float: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Double: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Signed8: + setFieldInternal(dim, idx, &val); + break; + case Dimension::Type::Signed16: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Signed32: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Signed64: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Unsigned8: + setFieldInternal(dim, idx, &val); + break; + case Dimension::Type::Unsigned16: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Unsigned32: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::Unsigned64: + ok = convertAndSet(dim, idx, val); + break; + case Dimension::Type::None: + val = 0; + break; } - catch (boost::numeric::bad_numeric_cast& ) + if (!ok) { std::ostringstream oss; oss << "Unable to set data and convert as requested: "; diff --git a/include/pdal/RawPtBuf.hpp b/include/pdal/RawPtBuf.hpp index e7aab1ea5a..fc32b18da7 100644 --- a/include/pdal/RawPtBuf.hpp +++ b/include/pdal/RawPtBuf.hpp @@ -84,6 +84,10 @@ class RawPtBuf if (m_numPts != 0) throw pdal_error("Can't set point size after points have " "been added."); + + //NOTE - I tried forcing all points to be aligned on 8-byte boundaries + // in case this would matter to the optimized memcpy, but it made + // no difference. No sense wasting space for no difference. m_pointSize = size; }