diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e8b955e..c377cefa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed +- **\[Python/C++\]** Point and Points objects no longer depend on an internal scale or offset. XYZ coordinates are stored as doubles internally, and converted into integers using scale and offset only when packing or unpacking. + ## [2.3.1] - 2022-04-14 ### Fixed diff --git a/cpp/include/copc-lib/las/point.hpp b/cpp/include/copc-lib/las/point.hpp index 740e3e32..a8dd05c6 100644 --- a/cpp/include/copc-lib/las/point.hpp +++ b/cpp/include/copc-lib/las/point.hpp @@ -13,8 +13,7 @@ namespace copc::las class Point { public: - Point(const int8_t &point_format_id, const Vector3 &scale = Vector3::DefaultScale(), - const Vector3 &offset = Vector3::DefaultOffset(), const uint16_t &eb_byte_size = 0); + Point(const int8_t &point_format_id, const uint16_t &eb_byte_size = 0); Point(const LasHeader &header); Point(const Point &other); @@ -22,24 +21,15 @@ class Point #pragma region XYZ // XYZ Scaled - double X() const { return ApplyScale(x_, scale_.x, offset_.x); } - void X(const double &x) { x_ = RemoveScale(x, scale_.x, offset_.x); } + double X() const { return x_scaled_; } + void X(const double &x) { x_scaled_ = x; } - double Y() const { return ApplyScale(y_, scale_.y, offset_.y); } - void Y(const double &y) { y_ = RemoveScale(y, scale_.y, offset_.y); } + double Y() const { return y_scaled_; } + void Y(const double &y) { y_scaled_ = y; } - double Z() const { return ApplyScale(z_, scale_.z, offset_.z); } - void Z(const double &z) { z_ = RemoveScale(z, scale_.z, offset_.z); } + double Z() const { return z_scaled_; } + void Z(const double &z) { z_scaled_ = z; } - // XYZ Unscaled - int32_t UnscaledX() const { return x_; } - void UnscaledX(const int32_t &x) { x_ = x; } - - int32_t UnscaledY() const { return y_; } - void UnscaledY(const int32_t &y) { y_ = y; } - - int32_t UnscaledZ() const { return z_; } - void UnscaledZ(const int32_t &z) { z_ = z; } #pragma endregion XYZ uint16_t Intensity() const { return intensity_; } @@ -219,9 +209,6 @@ class Point int8_t PointFormatId() const { return point_format_id_; } uint16_t EbByteSize() const; - Vector3 Scale() const { return scale_; } - Vector3 Offset() const { return offset_; } - bool operator==(const Point &other) const; bool operator!=(const Point &other) const { return !(*this == other); }; @@ -231,13 +218,13 @@ class Point static std::shared_ptr Unpack(std::istream &in_stream, const int8_t &point_format_id, const Vector3 &scale, const Vector3 &offset, const uint16_t &eb_byte_size); - void Pack(std::ostream &out_stream) const; + void Pack(std::ostream &out_stream, const Vector3 &scale, const Vector3 &offset) const; void ToPointFormat(const int8_t &point_format_id); protected: - int32_t x_{}; - int32_t y_{}; - int32_t z_{}; + double x_scaled_{}; + double y_scaled_{}; + double z_scaled_{}; uint16_t intensity_{}; uint8_t returns_{}; uint8_t flags_{}; @@ -258,8 +245,6 @@ class Point private: uint32_t point_record_length_; int8_t point_format_id_; - Vector3 scale_; - Vector3 offset_; }; } // namespace copc::las diff --git a/cpp/include/copc-lib/las/points.hpp b/cpp/include/copc-lib/las/points.hpp index 0a41761e..fa1c0767 100644 --- a/cpp/include/copc-lib/las/points.hpp +++ b/cpp/include/copc-lib/las/points.hpp @@ -18,8 +18,7 @@ namespace copc::las class Points { public: - Points(const int8_t &point_format_id, const Vector3 &scale, const Vector3 &offset, - const uint16_t &eb_byte_size = 0); + Points(const int8_t &point_format_id, const uint16_t &eb_byte_size = 0); Points(const LasHeader &header); // Will create Points object given a points vector Points(const std::vector> &points); @@ -47,15 +46,14 @@ class Points void AddPoints(std::vector> points); // Point functions - std::shared_ptr CreatePoint() - { - return std::make_shared(point_format_id_, scale_, offset_, EbByteSize()); - } + std::shared_ptr CreatePoint() { return std::make_shared(point_format_id_, EbByteSize()); } void ToPointFormat(const int8_t &point_format_id); // Pack/unpack - std::vector Pack() const; - void Pack(std::ostream &out_stream) const; + std::vector Pack(const LasHeader &header) const; + std::vector Pack(const Vector3 &scale, const Vector3 &offset) const; + void Pack(std::ostream &out_stream, const Vector3 &scale, const Vector3 &offset) const; + void Pack(std::ostream &out_stream, const LasHeader &header) const; static Points Unpack(const std::vector &point_data, const int8_t &point_format_id, const uint16_t &eb_byte_size, const Vector3 &scale, const Vector3 &offset); static Points Unpack(const std::vector &point_data, const LasHeader &header); @@ -114,57 +112,6 @@ class Points points_[i]->Z(in[i]); } - std::vector UnscaledX() const - { - std::vector out; - out.resize(Size()); - std::transform(points_.begin(), points_.end(), out.begin(), - [](const std::shared_ptr &p) { return p->UnscaledX(); }); - return out; - } - void UnscaledX(const std::vector &in) - { - if (in.size() != Size()) - throw std::runtime_error("UnscaledX setter array must be same size as Points array!"); - - for (unsigned i = 0; i < points_.size(); ++i) - points_[i]->UnscaledX(in[i]); - } - - std::vector UnscaledY() const - { - std::vector out; - out.resize(Size()); - std::transform(points_.begin(), points_.end(), out.begin(), - [](const std::shared_ptr &p) { return p->UnscaledY(); }); - return out; - } - void UnscaledY(const std::vector &in) - { - if (in.size() != Size()) - throw std::runtime_error("UnscaledY setter array must be same size as Points array!"); - - for (unsigned i = 0; i < points_.size(); ++i) - points_[i]->UnscaledY(in[i]); - } - - std::vector UnscaledZ() const - { - std::vector out; - out.resize(Size()); - std::transform(points_.begin(), points_.end(), out.begin(), - [](const std::shared_ptr &p) { return p->UnscaledZ(); }); - return out; - } - void UnscaledZ(const std::vector &in) - { - if (in.size() != Size()) - throw std::runtime_error("UnscaledZ setter array must be same size as Points array!"); - - for (unsigned i = 0; i < points_.size(); ++i) - points_[i]->UnscaledZ(in[i]); - } - std::vector Classification() const { std::vector out; @@ -279,8 +226,6 @@ class Points std::vector> points_; int8_t point_format_id_; uint32_t point_record_length_; - Vector3 scale_; - Vector3 offset_; }; } // namespace copc::las #endif // COPCLIB_LAS_POINTS_H_ diff --git a/cpp/include/copc-lib/utils.hpp b/cpp/include/copc-lib/utils.hpp new file mode 100644 index 00000000..3d011456 --- /dev/null +++ b/cpp/include/copc-lib/utils.hpp @@ -0,0 +1,12 @@ +#ifndef COPCLIB_UTILS_H_ +#define COPCLIB_UTILS_H_ + +#include + +namespace copc +{ + +bool AreClose(double a, double b, double epsilon) { return fabs(a - b) < epsilon; } + +} // namespace copc +#endif // COPCLIB_UTILS_H_ diff --git a/cpp/src/io/copc_writer_public.cpp b/cpp/src/io/copc_writer_public.cpp index 9eb6d012..ef33802f 100644 --- a/cpp/src/io/copc_writer_public.cpp +++ b/cpp/src/io/copc_writer_public.cpp @@ -107,7 +107,7 @@ Node Writer::AddNode(const VoxelKey &key, const las::Points &points, const Voxel points.PointRecordLength() != config_->LasHeader()->PointRecordLength()) throw std::runtime_error("Writer::AddNode: New points must be of same format and size."); - std::vector uncompressed_data = points.Pack(); + std::vector uncompressed_data = points.Pack(*config_->LasHeader()); return AddNode(key, uncompressed_data, page_key); } diff --git a/cpp/src/io/laz_writer.cpp b/cpp/src/io/laz_writer.cpp index b6bbabd6..e98eab7e 100644 --- a/cpp/src/io/laz_writer.cpp +++ b/cpp/src/io/laz_writer.cpp @@ -22,7 +22,7 @@ void LazWriter::WritePoints(const las::Points &points) points.PointRecordLength() != config_->LasHeader().PointRecordLength()) throw std::runtime_error("LazWriter::WritePoints: New points must be of same format and size."); - std::vector uncompressed_data = points.Pack(); + std::vector uncompressed_data = points.Pack(config_->LasHeader()); WriteChunk(uncompressed_data); } diff --git a/cpp/src/las/point.cpp b/cpp/src/las/point.cpp index 2ac7c29b..bb78b47a 100644 --- a/cpp/src/las/point.cpp +++ b/cpp/src/las/point.cpp @@ -1,9 +1,9 @@ #include "copc-lib/las/point.hpp" +#include "copc-lib/utils.hpp" namespace copc::las { -Point::Point(const int8_t &point_format_id, const Vector3 &scale, const Vector3 &offset, const uint16_t &eb_byte_size) - : scale_(scale), offset_(offset), point_format_id_(point_format_id) +Point::Point(const int8_t &point_format_id, const uint16_t &eb_byte_size) : point_format_id_(point_format_id) { if (point_format_id < 6 || point_format_id > 8) throw std::runtime_error("Point: Point format must be 6-8"); @@ -16,16 +16,13 @@ Point::Point(const int8_t &point_format_id, const Vector3 &scale, const Vector3 extra_bytes_.resize(eb_byte_size, 0); } -Point::Point(const LasHeader &header) - : Point(header.PointFormatId(), header.Scale(), header.Offset(), header.EbByteSize()) -{ -} +Point::Point(const LasHeader &header) : Point(header.PointFormatId(), header.EbByteSize()) {} -Point::Point(const Point &other) : Point(other.point_format_id_, other.Scale(), other.Offset(), other.EbByteSize()) +Point::Point(const Point &other) : Point(other.point_format_id_, other.EbByteSize()) { - x_ = other.x_; - y_ = other.y_; - z_ = other.z_; + x_scaled_ = other.x_scaled_; + y_scaled_ = other.y_scaled_; + z_scaled_ = other.z_scaled_; intensity_ = other.intensity_; returns_ = other.returns_; flags_ = other.flags_; @@ -56,8 +53,8 @@ bool Point::operator==(const Point &other) const { if (point_format_id_ != other.point_format_id_ || point_record_length_ != other.point_record_length_) return false; - if (x_ != other.UnscaledX() || y_ != other.UnscaledY() || z_ != other.UnscaledZ() || - intensity_ != other.Intensity()) + if (!AreClose(X(), other.X(), 0.000001) || !AreClose(Y(), other.Y(), 0.000001) || + !AreClose(Z(), other.Z(), 0.000001) || intensity_ != other.Intensity()) return false; if (returns_ != other.ReturnsBitField()) return false; @@ -83,11 +80,11 @@ bool Point::Within(const Box &box) const { return box.Contains(Vector3(X(), Y(), std::shared_ptr Point::Unpack(std::istream &in_stream, const int8_t &point_format_id, const Vector3 &scale, const Vector3 &offset, const uint16_t &eb_byte_size) { - std::shared_ptr p = std::make_shared(point_format_id, scale, offset, eb_byte_size); + std::shared_ptr p = std::make_shared(point_format_id, eb_byte_size); - p->x_ = unpack(in_stream); - p->y_ = unpack(in_stream); - p->z_ = unpack(in_stream); + p->x_scaled_ = ApplyScale(unpack(in_stream), scale.x, offset.x); + p->y_scaled_ = ApplyScale(unpack(in_stream), scale.y, offset.y); + p->z_scaled_ = ApplyScale(unpack(in_stream), scale.z, offset.z); p->intensity_ = unpack(in_stream); p->returns_ = unpack(in_stream); p->flags_ = unpack(in_stream); @@ -114,12 +111,12 @@ std::shared_ptr Point::Unpack(std::istream &in_stream, const int8_t &poin return p; } -void Point::Pack(std::ostream &out_stream) const +void Point::Pack(std::ostream &out_stream, const Vector3 &scale, const Vector3 &offset) const { // Point - pack(x_, out_stream); - pack(y_, out_stream); - pack(z_, out_stream); + pack(RemoveScale(x_scaled_, scale.x, offset.x), out_stream); + pack(RemoveScale(y_scaled_, scale.y, offset.y), out_stream); + pack(RemoveScale(z_scaled_, scale.z, offset.z), out_stream); pack(intensity_, out_stream); pack(returns_, out_stream); pack(flags_, out_stream); @@ -157,7 +154,7 @@ std::string Point::ToString() const { std::stringstream ss; ss << "Point: " << std::endl; - ss << "\tX: " << x_ << ", Y: " << y_ << ", Z: " << z_ << std::endl; + ss << "\tX: " << x_scaled_ << ", Y: " << y_scaled_ << ", Z: " << z_scaled_ << std::endl; ss << "\tIntensity: " << intensity_ << std::endl; ss << "\tReturn Number: " << static_cast(ReturnNumber()) << ", Number of Returns: " << static_cast(NumberOfReturns()) << std::endl; diff --git a/cpp/src/las/points.cpp b/cpp/src/las/points.cpp index da5ff075..57e34b1c 100644 --- a/cpp/src/las/points.cpp +++ b/cpp/src/las/points.cpp @@ -7,8 +7,7 @@ namespace copc::las { -Points::Points(const int8_t &point_format_id, const Vector3 &scale, const Vector3 &offset, const uint16_t &eb_byte_size) - : point_format_id_(point_format_id), scale_(scale), offset_(offset) +Points::Points(const int8_t &point_format_id, const uint16_t &eb_byte_size) : point_format_id_(point_format_id) { if (point_format_id < 0 || point_format_id > 10) throw std::runtime_error("Point format must be 0-10."); @@ -16,10 +15,7 @@ Points::Points(const int8_t &point_format_id, const Vector3 &scale, const Vector point_record_length_ = PointByteSize(point_format_id, eb_byte_size); } -Points::Points(const LasHeader &header) - : Points(header.PointFormatId(), header.Scale(), header.Offset(), header.EbByteSize()) -{ -} +Points::Points(const LasHeader &header) : Points(header.PointFormatId(), header.EbByteSize()) {} Points::Points(const std::vector> &points) { @@ -28,8 +24,6 @@ Points::Points(const std::vector> &points) point_record_length_ = points[0]->PointRecordLength(); point_format_id_ = points[0]->PointFormatId(); - scale_ = points[0]->Scale(); - offset_ = points[0]->Offset(); AddPoints(points); } @@ -91,7 +85,7 @@ Points Points::Unpack(const std::vector &point_data, const int8_t &point_f auto ss = std::istringstream(std::string(point_data.begin(), point_data.end())); // Go through each Point to unpack the data from the stream - Points points(point_format_id, scale, offset, eb_byte_size); + Points points(point_format_id, eb_byte_size); points.Reserve(point_count); // Unpack points @@ -103,16 +97,23 @@ Points Points::Unpack(const std::vector &point_data, const int8_t &point_f return points; } -void Points::Pack(std::ostream &out_stream) const +void Points::Pack(std::ostream &out_stream, const LasHeader &header) const +{ + Pack(out_stream, header.Scale(), header.Offset()); +} + +void Points::Pack(std::ostream &out_stream, const Vector3 &scale, const Vector3 &offset) const { for (const auto &point : points_) - point->Pack(out_stream); + point->Pack(out_stream, scale, offset); } -std::vector Points::Pack() const +std::vector Points::Pack(const LasHeader &header) const { return Pack(header.Scale(), header.Offset()); } + +std::vector Points::Pack(const Vector3 &scale, const Vector3 &offset) const { std::stringstream out; - Pack(out); + Pack(out, scale, offset); auto ostr = out.str(); return std::vector(ostr.begin(), ostr.end()); } diff --git a/example/example-laz-writer.cpp b/example/example-laz-writer.cpp index e2d5da79..3a013788 100644 --- a/example/example-laz-writer.cpp +++ b/example/example-laz-writer.cpp @@ -35,9 +35,9 @@ las::Points RandomPoints(const las::LasHeader &header, int number_points) // The use of las::Point constructor is strongly discouraged, instead use las::Points::CreatePoint auto point = points.CreatePoint(); // point has getters/setters for all attributes - point->UnscaledX(rand_x(gen)); - point->UnscaledY(rand_y(gen)); - point->UnscaledZ(rand_z(gen)); + point->X(header.ApplyScaleX(rand_x(gen))); + point->Y(header.ApplyScaleY(rand_y(gen))); + point->Z(header.ApplyScaleZ(rand_z(gen))); points.AddPoint(point); } diff --git a/example/example-writer.cpp b/example/example-writer.cpp index 4d0c0e09..43b54c78 100644 --- a/example/example-writer.cpp +++ b/example/example-writer.cpp @@ -220,9 +220,9 @@ las::Points RandomPoints(const VoxelKey &key, const las::LasHeader &header, int // The use of las::Point constructor is strongly discouraged, instead use las::Points::CreatePoint auto point = points.CreatePoint(); // point has getters/setters for all attributes - point->UnscaledX(rand_x(gen)); - point->UnscaledY(rand_y(gen)); - point->UnscaledZ(rand_z(gen)); + point->X(header.ApplyScaleX(rand_x(gen))); + point->Y(header.ApplyScaleY(rand_y(gen))); + point->Z(header.ApplyScaleZ(rand_z(gen))); // For visualization purposes point->PointSourceId(key.d + key.x + key.y + key.z); diff --git a/example/example_writer.py b/example/example_writer.py index 224db993..54ad2d91 100644 --- a/example/example_writer.py +++ b/example/example_writer.py @@ -212,17 +212,17 @@ def RandomPoints(key, las_header, number_points): # Create a point with a given point format point = points.CreatePoint() # point has getters/setters for all attributes - point.X = random.randint( - las_header.RemoveScaleX(max(las_header.min.x, minx)), - las_header.RemoveScaleX(min(las_header.max.x, minx + step)), + point.x = random.uniform( + max(las_header.min.x, minx), + min(las_header.max.x, minx + step), ) - point.Y = random.randint( - las_header.RemoveScaleY(max(las_header.min.y, miny)), - las_header.RemoveScaleY(min(las_header.max.y, miny + step)), + point.y = random.uniform( + max(las_header.min.y, miny), + min(las_header.max.y, miny + step), ) - point.Z = random.randint( - las_header.RemoveScaleZ(max(las_header.min.z, minz)), - las_header.RemoveScaleZ(min(las_header.max.z, minz + step)), + point.z = random.uniform( + max(las_header.min.z, minz), + min(las_header.max.z, minz + step), ) # For visualization purposes diff --git a/python/bindings.cpp b/python/bindings.cpp index d6a6d4ae..95579bc1 100644 --- a/python/bindings.cpp +++ b/python/bindings.cpp @@ -216,12 +216,6 @@ PYBIND11_MODULE(_core, m) py::overload_cast(&las::Point::Y)) .def_property("z", py::overload_cast<>(&las::Point::Z, py::const_), py::overload_cast(&las::Point::Z)) - .def_property("X", py::overload_cast<>(&las::Point::UnscaledX, py::const_), - py::overload_cast(&las::Point::UnscaledX)) - .def_property("Y", py::overload_cast<>(&las::Point::UnscaledY, py::const_), - py::overload_cast(&las::Point::UnscaledY)) - .def_property("Z", py::overload_cast<>(&las::Point::UnscaledZ, py::const_), - py::overload_cast(&las::Point::UnscaledZ)) .def_property("intensity", py::overload_cast<>(&las::Point::Intensity, py::const_), py::overload_cast(&las::Point::Intensity)) .def_property("returns_bit_field", py::overload_cast<>(&las::Point::ReturnsBitField, py::const_), @@ -294,8 +288,8 @@ PYBIND11_MODULE(_core, m) }; py::class_(m, "Points") - .def(py::init(), - py::arg("point_format_id"), py::arg("scale"), py::arg("offset"), py::arg("eb_byte_size") = 0) + .def(py::init(), + py::arg("point_format_id"), py::arg("eb_byte_size") = 0) .def(py::init> &>(), py::arg("points")) .def(py::init()) .def_property("x", py::overload_cast<>(&las::Points::X, py::const_), @@ -304,12 +298,6 @@ PYBIND11_MODULE(_core, m) py::overload_cast &>(&las::Points::Y)) .def_property("z", py::overload_cast<>(&las::Points::Z, py::const_), py::overload_cast &>(&las::Points::Z)) - .def_property("X", py::overload_cast<>(&las::Points::UnscaledX, py::const_), - py::overload_cast &>(&las::Points::UnscaledX)) - .def_property("Y", py::overload_cast<>(&las::Points::UnscaledY, py::const_), - py::overload_cast &>(&las::Points::UnscaledY)) - .def_property("Z", py::overload_cast<>(&las::Points::UnscaledZ, py::const_), - py::overload_cast &>(&las::Points::UnscaledZ)) .def_property("classification", py::overload_cast<>(&las::Points::Classification, py::const_), py::overload_cast &>(&las::Points::Classification)) .def_property("point_source_id", py::overload_cast<>(&las::Points::PointSourceId, py::const_), @@ -330,7 +318,9 @@ PYBIND11_MODULE(_core, m) .def("ToPointFormat", &las::Points::ToPointFormat, py::arg("point_format_id")) .def("Within", &las::Points::Within, py::arg("box")) .def("GetWithin", &las::Points::GetWithin, py::arg("box")) - .def("Pack", py::overload_cast<>(&las::Points::Pack, py::const_)) + .def("Pack", py::overload_cast(&las::Points::Pack, py::const_)) + .def("Pack", py::overload_cast(&las::Points::Pack, py::const_)) .def("Unpack", py::overload_cast &, const las::LasHeader &>(&las::Points::Unpack)) .def("Unpack", py::overload_cast &, const int8_t &, const uint16_t &, const Vector3 &, const Vector3 &>(&las::Points::Unpack)) diff --git a/test/hierarchy_test.cpp b/test/hierarchy_test.cpp index d409a7b7..e1ff1861 100644 --- a/test/hierarchy_test.cpp +++ b/test/hierarchy_test.cpp @@ -23,7 +23,7 @@ TEST_CASE("Packing Test", "[Hierarchy] ") // Pack loaded points into stream ostringstream oss; - points.Pack(oss); + points.Pack(oss, reader.CopcConfig().LasHeader()); // Write stream into vector to compare with point_data vector point_data_write; diff --git a/test/point_test.cpp b/test/point_test.cpp index 969557eb..41e52b77 100644 --- a/test/point_test.cpp +++ b/test/point_test.cpp @@ -5,11 +5,19 @@ #include #include #include +#include using namespace copc::las; using namespace std; using Catch::Matchers::WithinAbs; +Point PackAndUnpack(Point p, copc::Vector3 scale, copc::Vector3 offset) +{ + std::stringstream out; + p.Pack(out, scale, offset); + return *Point::Unpack(out, p.PointFormatId(), scale, offset, p.EbByteSize()); +} + TEST_CASE("Point tests", "[Point]") { SECTION("Point Format Initialization") @@ -30,12 +38,12 @@ TEST_CASE("Point tests", "[Point]") { auto point6 = Point(6); // Position - point6.UnscaledX(std::numeric_limits::max()); - point6.UnscaledY(std::numeric_limits::max()); - point6.UnscaledZ(std::numeric_limits::max()); - REQUIRE(point6.UnscaledX() == std::numeric_limits::max()); - REQUIRE(point6.UnscaledY() == std::numeric_limits::max()); - REQUIRE(point6.UnscaledZ() == std::numeric_limits::max()); + point6.X(0.05); + point6.Y(1.11); + point6.Z(-9.99); + REQUIRE_THAT(point6.X(), WithinAbs(0.05, 0.000001)); + REQUIRE_THAT(point6.Y(), WithinAbs(1.11, 0.000001)); + REQUIRE_THAT(point6.Z(), WithinAbs(-9.99, 0.000001)); // Intensity point6.Intensity(std::numeric_limits::max()); @@ -270,19 +278,19 @@ TEST_CASE("Point tests", "[Point]") // Atributes - point.UnscaledX(4); + point.X(4); REQUIRE(point != point_other); - point_other.UnscaledX(4); + point_other.X(4); REQUIRE(point == point_other); - point.UnscaledY(4); + point.Y(4); REQUIRE(point != point_other); - point_other.UnscaledY(4); + point_other.Y(4); REQUIRE(point == point_other); - point.UnscaledZ(4); + point.Z(4); REQUIRE(point != point_other); - point_other.UnscaledZ(4); + point_other.Z(4); REQUIRE(point == point_other); point.Intensity(4); @@ -385,7 +393,7 @@ TEST_CASE("Point tests", "[Point]") REQUIRE(point.ExtraBytes().empty()); REQUIRE(point.EbByteSize() == 0); - point = Point(6, {}, {}, 5); + point = Point(6, 5); REQUIRE(point.PointFormatId() == 6); REQUIRE(point.PointRecordLength() == 30 + 5); REQUIRE(point.EbByteSize() == 5); @@ -397,11 +405,11 @@ TEST_CASE("Point tests", "[Point]") SECTION("Operator =") { - auto point = Point(8, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 2); + auto point = Point(8, 2); - point.UnscaledX(4); - point.UnscaledY(4); - point.UnscaledZ(4); + point.X(4); + point.Y(4); + point.Z(4); point.GPSTime(4.0); point.Red(4.0); @@ -419,30 +427,31 @@ TEST_CASE("Point tests", "[Point]") { std::stringstream ss; - auto orig_point = - Point(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 2); // use two extra bytes - orig_point.UnscaledX(20); - orig_point.UnscaledY(-20); - orig_point.UnscaledZ(100000); + auto scale = copc::Vector3::DefaultScale(); + auto offset = copc::Vector3::DefaultOffset(); + auto orig_point = Point(6, 2); // use two extra bytes + orig_point.X(20); + orig_point.Y(-20); + orig_point.Z(100000); orig_point.ScanAngle(2000); // Format 6 auto point = orig_point; - point.Pack(ss); + point.Pack(ss, scale, offset); auto point_other = *Point::Unpack(ss, 6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), point.EbByteSize()); REQUIRE(point == point_other); // Format 7 point.ToPointFormat(7); - point.Pack(ss); + point.Pack(ss, scale, offset); point_other = *Point::Unpack(ss, 7, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), point.EbByteSize()); REQUIRE(point == point_other); // Format 8 point.ToPointFormat(8); - point.Pack(ss); + point.Pack(ss, scale, offset); point_other = *Point::Unpack(ss, 8, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), point.EbByteSize()); REQUIRE(point == point_other); @@ -454,114 +463,122 @@ TEST_CASE("Point tests", "[Point]") SECTION("No scale and offset") { - auto point = Point(pfid, {1, 1, 1}, {0, 0, 0}); + auto point = Point(pfid); - point.UnscaledX(4); - point.UnscaledY(4); - point.UnscaledZ(4); + point.X(4); + point.Y(4.5); + point.Z(-0.1); - REQUIRE(point.X() == 4); - REQUIRE(point.Y() == 4); - REQUIRE(point.Z() == 4); + auto test_point = PackAndUnpack(point, copc::Vector3(1, 1, 1), copc::Vector3(0, 0, 0)); - point.X(5); - point.Y(6); - point.Z(7); - - REQUIRE(point.UnscaledX() == 5); - REQUIRE(point.UnscaledY() == 6); - REQUIRE(point.UnscaledZ() == 7); + REQUIRE(test_point.X() == 4); + REQUIRE(test_point.Y() == 5); + REQUIRE(test_point.Z() == 0); } SECTION("Scale test") { - auto point = Point(pfid, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset()); + auto point = Point(pfid); + + point.X(0.01); + point.Y(0.02); + point.Z(0.03); - point.UnscaledX(1); - point.UnscaledY(2); - point.UnscaledZ(3); + auto test_point = PackAndUnpack(point, copc::Vector3(1, 1, 1), copc::Vector3(0, 0, 0)); - REQUIRE(point.X() == 0.01); - REQUIRE(point.Y() == 0.02); - REQUIRE(point.Z() == 0.03); + REQUIRE(test_point.X() == 0); + REQUIRE(test_point.Y() == 0); + REQUIRE(test_point.Z() == 0); - point.X(200); - point.Y(300); - point.Z(400); + test_point = PackAndUnpack(point, copc::Vector3(0.01, 0.01, 0.01), copc::Vector3(0, 0, 0)); - REQUIRE(point.UnscaledX() == 200 * 100); - REQUIRE(point.UnscaledY() == 300 * 100); - REQUIRE(point.UnscaledZ() == 400 * 100); + REQUIRE(test_point.X() == 0.01); + REQUIRE(test_point.Y() == 0.02); + REQUIRE(test_point.Z() == 0.03); } SECTION("Offset test") { copc::Vector3 scale = {1, 1, 1}; copc::Vector3 offset = {50001.456, 4443.123, -255.001}; - auto point = Point(pfid, scale, offset); - - point.UnscaledX(0); - point.UnscaledY(-800); - point.UnscaledZ(3); - - REQUIRE(point.X() == 0 + offset.x); - REQUIRE(point.Y() == -800 + offset.y); - REQUIRE(point.Z() == 3 + offset.z); + auto point = Point(pfid); point.X(50502.888); point.Y(4002.111); point.Z(-80.5); - // static_cast(std::round((value - offset) / scale)); - REQUIRE(point.UnscaledX() == 501); // 50502.888 - 50001.456 = 501.432 - REQUIRE(point.UnscaledY() == -441); - REQUIRE(point.UnscaledZ() == 175); // -80.5 - -255.001 = 255.001 - 80.5 = 175 - - // (value * scale) + offset - REQUIRE_THAT(point.X(), WithinAbs(50502.456, 0.000001)); - REQUIRE_THAT(point.Y(), WithinAbs(4002.123, 0.000001)); - REQUIRE_THAT(point.Z(), WithinAbs(-80.001, 0.000001)); + auto test_point = PackAndUnpack(point, scale, offset); + REQUIRE_THAT(test_point.X(), WithinAbs(50502.456, 0.000001)); + REQUIRE_THAT(test_point.Y(), WithinAbs(4002.123, 0.000001)); + REQUIRE_THAT(test_point.Z(), WithinAbs(-80.001, 0.000001)); } SECTION("Scale and Offset test") { - auto point = Point(pfid, {0.001, 0.001, 0.001}, {50001.456, 4443.123, -255.001}); + copc::Vector3 scale = {0.001, 0.001, 0.001}; + copc::Vector3 offset = {50001.456, 4443.123, -255.001}; + auto point = Point(pfid); - point.UnscaledX(0); - point.UnscaledY(-800); - point.UnscaledZ(300532); + point.X(50502.888); + point.Y(4002.111); + point.Z(-80.5); - REQUIRE_THAT(point.X(), WithinAbs(50001.456, 0.000001)); - REQUIRE_THAT(point.Y(), WithinAbs(4442.323, 0.000001)); - REQUIRE_THAT(point.Z(), WithinAbs(45.531, 0.000001)); + auto test_point = PackAndUnpack(point, scale, offset); + REQUIRE_THAT(test_point.X(), WithinAbs(50502.888, 0.000001)); + REQUIRE_THAT(test_point.Y(), WithinAbs(4002.111, 0.000001)); + REQUIRE_THAT(test_point.Z(), WithinAbs(-80.5, 0.000001)); + } + SECTION("Change Scale test") + { + copc::Vector3 offset = {50001.456, 4443.123, -255.001}; + copc::Vector3 scale = {0.001, 0.001, 0.001}; + copc::Vector3 new_scale = {1, 1, 1}; + // This tests the case that we want to change the point's scale when we pack it + auto point = Point(pfid); point.X(50502.888); point.Y(4002.111); point.Z(-80.5); - // static_cast(std::round((value - offset) / scale)); - REQUIRE(point.UnscaledX() == 501432); - REQUIRE(point.UnscaledY() == -441012); - REQUIRE(point.UnscaledZ() == 174501); - // (value * scale) + offset REQUIRE_THAT(point.X(), WithinAbs(50502.888, 0.000001)); REQUIRE_THAT(point.Y(), WithinAbs(4002.111, 0.000001)); REQUIRE_THAT(point.Z(), WithinAbs(-80.5, 0.000001)); + + // When we pack the points, that's when we unscale the internally stored double. + // so we end up with: + // UnscaledX = static_cast(std::round((50502.888 - 50001.456) / 1)) = 501 + // UnscaledY = static_cast(std::round((4002.111 - 4443.123) / 1)) = -441 + // UnscaledZ = static_cast(std::round((-80.5 - -255.001) / 1)) = 175 + + // Then when we unpack the points, we do the inverse: + // (value * scale) + offset + // X = 501 * 1 + 50001.456 = 50502.456 + // Y = -441 * 1 + 4443.123 = 4002.123 + // Z = 175 * 1 + -255.001 = -80.001 + auto test_point = PackAndUnpack(point, new_scale, offset); + + REQUIRE_THAT(test_point.X(), WithinAbs(50502.456, 0.0001)); + REQUIRE_THAT(test_point.Y(), WithinAbs(4002.123, 0.0001)); + REQUIRE_THAT(test_point.Z(), WithinAbs(-80.001, 0.0001)); } + // todo: add change offset and change offset/scale tests SECTION("Precision checks") { { - auto point = Point(pfid, {0.000001, 0.000001, 0.000001}, {0, 0, 0}); - - REQUIRE_THROWS(point.X(50501132.888123)); + auto point = Point(pfid); + point.X(50501132.888123); + std::stringstream out; + REQUIRE_THROWS(point.Pack(out, {0.000001, 0.000001, 0.000001}, {0, 0, 0})); } { - auto point = Point(pfid, {1, 1, 1}, {-8001100065, 0, 0}); - REQUIRE_THROWS(point.X(0)); + auto point = Point(pfid); + point.X(0); + std::stringstream out; + REQUIRE_THROWS(point.Pack(out, {1, 1, 1}, {-8001100065, 0, 0})); } } } SECTION("Within") { - auto point = Point(6, {1, 1, 1}, copc::Vector3::DefaultOffset()); + auto point = Point(6); point.X(5); point.Y(5); diff --git a/test/point_test.py b/test/point_test.py index 28ab0ac1..7e251e6d 100644 --- a/test/point_test.py +++ b/test/point_test.py @@ -4,36 +4,38 @@ import pytest +def pack_and_unpack(p, scale, offset): + points = copc.Points(p.point_format_id, p.EbByteSize()) + points.AddPoint(p) + return copc.Points.Unpack( + points.Pack(scale, offset), p.point_format_id, p.EbByteSize(), scale, offset + )[0] + + def test_constructor(): point = copc.Points( point_format_id=6, - scale=copc.Vector3.DefaultScale(), - offset=copc.Vector3.DefaultOffset(), eb_byte_size=0, ).CreatePoint() assert point.HasRgb() is False assert point.HasNir() is False - point_ext = copc.Points( - 8, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point_ext = copc.Points(8).CreatePoint() assert point_ext.HasRgb() is True assert point_ext.HasNir() is True def test_point(): - point6 = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point6 = copc.Points(6).CreatePoint() # Position - point6.X = 2147483647 - point6.Y = 2147483647 - point6.Z = 2147483647 - assert point6.X == 2147483647 - assert point6.Y == 2147483647 - assert point6.Z == 2147483647 + point6.x = 2147483647 + point6.y = 2147483647 + point6.z = 2147483647 + assert point6.x == 2147483647 + assert point6.y == 2147483647 + assert point6.z == 2147483647 # intensity point6.intensity = 65535 @@ -154,9 +156,7 @@ def test_point(): # ToString str(point6) - point7 = copc.Points( - 7, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point7 = copc.Points(7).CreatePoint() point7.rgb = [65535, 65535, 65535] assert point7.red == 65535 @@ -168,9 +168,7 @@ def test_point(): point7.nir = 65535 assert point7.nir - point8 = copc.Points( - 8, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point8 = copc.Points(8).CreatePoint() point8.nir = 65535 assert point8.nir == 65535 @@ -178,9 +176,7 @@ def test_point(): def test_point_conversion(): - point = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point = copc.Points(6).CreatePoint() assert point.gps_time == 0 assert point.scanner_channel == 0 @@ -209,12 +205,8 @@ def test_point_conversion(): def test_operators_equal(): # Format 0 - point = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() - point_other = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point = copc.Points(6).CreatePoint() + point_other = copc.Points(6).CreatePoint() assert point == point_other # Format 7 @@ -231,19 +223,19 @@ def test_operators_equal(): # Atributes - point.X = 4 + point.x = 4 assert point != point_other - point_other.X = 4 + point_other.x = 4 assert point == point_other - point.Y = 4 + point.y = 4 assert point != point_other - point_other.Y = 4 + point_other.y = 4 assert point == point_other - point.Z = 4 + point.z = 4 assert point != point_other - point_other.Z = 4 + point_other.z = 4 assert point == point_other point.intensity = 4 @@ -338,9 +330,7 @@ def test_operators_equal(): def test_extra_byte(): - point = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point = copc.Points(6).CreatePoint() assert point.point_format_id == 6 assert point.point_record_length == 30 with pytest.raises(RuntimeError): @@ -350,8 +340,6 @@ def test_extra_byte(): point = copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=5, ).CreatePoint() assert point.point_format_id == 6 @@ -367,14 +355,12 @@ def test_extra_byte(): def test_operator_copy(): point = copc.Points( 8, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=2, ).CreatePoint() - point.X = 4 - point.Y = 4 - point.Z = 4 + point.x = 4 + point.y = 4 + point.z = 4 point.gps_time = 4.0 point.red = 4 @@ -392,110 +378,98 @@ def test_scaled_xyz(): pfid = 8 # No scale and offset - point = copc.Points(pfid, scale=[1, 1, 1], offset=[0, 0, 0]).CreatePoint() - - point.X = 4 - point.Y = 4 - point.Z = 4 + point = copc.Points(pfid).CreatePoint() - assert point.x == 4 - assert point.y == 4 - assert point.z == 4 + point.x = 4 + point.y = 4.5 + point.z = -0.1 - point.x = 5 - point.y = 6 - point.z = 7 - - assert point.X == 5 - assert point.Y == 6 - assert point.Z == 7 + test_point = pack_and_unpack(point, [1, 1, 1], [0, 0, 0]) + assert test_point.x == 4 + assert test_point.y == 5 + assert test_point.z == 0 # Scale test - point = copc.Points( - pfid, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset() - ).CreatePoint() + point = copc.Points(pfid).CreatePoint() + + point.x = 0.01 + point.y = 0.02 + point.z = 0.03 - point.X = 1 - point.Y = 2 - point.Z = 3 + test_point = pack_and_unpack(point, [1, 1, 1], [0, 0, 0]) + assert test_point.x == 0 + assert test_point.y == 0 + assert test_point.z == 0 - assert point.x == 0.01 - assert point.y == 0.02 - assert point.z == 0.03 + test_point = pack_and_unpack(point, [0.01, 0.01, 0.01], [0, 0, 0]) - point.x = 200 - point.y = 300 - point.z = 400 + assert test_point.x == 0.01 + assert test_point.y == 0.02 + assert test_point.z == 0.03 - assert point.X == 200 * 100 - assert point.Y == 300 * 100 - assert point.Z == 400 * 100 # Offset test scale = [1, 1, 1] offset = copc.Vector3([50001.456, 4443.123, -255.001]) - point = copc.Points(pfid, scale, offset).CreatePoint() - - point.X = 0 - point.Y = -800 - point.Z = 3 - - assert point.x == 0 + offset.x - assert point.y == -800 + offset.y - assert point.z == 3 + offset.z + point = copc.Points(pfid).CreatePoint() point.x = 50502.888 point.y = 4002.111 point.z = -80.5 - assert point.X == 501 # 50502.888 - 50001.456 = 501.432 - assert point.Y == -441 - assert point.Z == 175 # -80.5 - -255.001 = 255.001 - 80.5 = 175 + test_point = pack_and_unpack(point, scale, offset) - # (value * scale) + offset - assert point.x == pytest.approx(50502.456, 0.000001) - assert point.y == pytest.approx(4002.123, 0.000001) - assert point.z == pytest.approx(-80.001, 0.000001) + assert test_point.x == pytest.approx(50502.456, 0.000001) + assert test_point.y == pytest.approx(4002.123, 0.000001) + assert test_point.z == pytest.approx(-80.001, 0.000001) # Scale and Offset test - point = copc.Points( - pfid, scale=[0.001, 0.001, 0.001], offset=[50001.456, 4443.123, -255.001] - ).CreatePoint() + scale = [0.001, 0.001, 0.001] + offset = [50001.456, 4443.123, -255.001] + point = copc.Points(pfid).CreatePoint() - point.X = 0 - point.Y = -800 - point.Z = 300532 + point.x = 50502.888 + point.y = 4002.111 + point.z = -80.5 - assert point.x == pytest.approx(50001.456, 0.000001) - assert point.y == pytest.approx(4442.323, 0.000001) - assert point.z == pytest.approx(45.531, 0.000001) + test_point = pack_and_unpack(point, scale, offset) + assert test_point.x == pytest.approx(50502.888, 0.000001) + assert test_point.y == pytest.approx(4002.111, 0.000001) + assert test_point.z == pytest.approx(-80.5, 0.000001) + + # Change scale test + offset = [50001.456, 4443.123, -255.001] + scale = [0.001, 0.001, 0.001] + new_scale = [1, 1, 1] + point = copc.Points(pfid).CreatePoint() point.x = 50502.888 point.y = 4002.111 point.z = -80.5 - assert point.X == 501432 - assert point.Y == -441012 - assert point.Z == 174501 - - # (value * scale) + offset - assert point.x == pytest.approx(50502.888, 0.000001) - assert point.y == pytest.approx(4002.111, 0.000001) - assert point.z == pytest.approx(-80.5, 0.000001) + test_point = pack_and_unpack(point, new_scale, offset) + assert test_point.x == pytest.approx(50502.456, 0.000001) + assert test_point.y == pytest.approx(4002.123, 0.000001) + assert test_point.z == pytest.approx(-80.001, 0.000001) # Precision checks - point = copc.Points(pfid, [0.000001, 0.000001, 0.000001], [0, 0, 0]).CreatePoint() - + points = copc.Points(pfid) + point = points.CreatePoint() + point.x = 50501132.888123 + points.AddPoint(point) with pytest.raises(RuntimeError): - point.x = 50501132.888123 + points.Pack([0.000001, 0.000001, 0.000001], [0, 0, 0]) - point = copc.Points(pfid, [1, 1, 1], [-8001100065, 0, 0]).CreatePoint() + points = copc.Points(pfid) + point = points.CreatePoint() + point.x = 0 + points.AddPoint(point) with pytest.raises(RuntimeError): - point.x = 0 + points.Pack([1, 1, 1], [-8001100065, 0, 0]) def test_within(): - point = copc.Points(6, (1, 1, 1), copc.Vector3.DefaultOffset()).CreatePoint() + point = copc.Points(6).CreatePoint() point.x = 5 point.y = 5 diff --git a/test/points_test.cpp b/test/points_test.cpp index 11956825..d186535b 100644 --- a/test/points_test.cpp +++ b/test/points_test.cpp @@ -14,16 +14,16 @@ TEST_CASE("Points tests", "[Point]") { SECTION("Points constructors") { - auto points = Points(6, {1, 1, 1}, {0, 0, 0}, 4); + auto points = Points(6, 4); REQUIRE(points.PointFormatId() == 6); REQUIRE(points.PointRecordLength() == 34); REQUIRE(points.Get().empty()); auto point_vec = std::vector>(); auto point1 = points.CreatePoint(); - point1->UnscaledX(11); - point1->UnscaledY(11); - point1->UnscaledZ(11); + point1->X(11.1); + point1->Y(11.2); + point1->Z(11.3); point_vec.push_back(point1); auto point2 = points.CreatePoint(); @@ -37,74 +37,69 @@ TEST_CASE("Points tests", "[Point]") REQUIRE(points.PointRecordLength() == 34); for (const auto &point : points.Get()) REQUIRE(point->PointFormatId() == 6); - REQUIRE(points.Get(0)->UnscaledX() == 11); - REQUIRE(points.Get(0)->UnscaledY() == 11); - REQUIRE(points.Get(0)->UnscaledZ() == 11); + REQUIRE(points.Get(0)->X() == 11.1); + REQUIRE(points.Get(0)->Y() == 11.2); + REQUIRE(points.Get(0)->Z() == 11.3); points.ToString(); } SECTION("Adding Point to Points") { - auto points = Points(6, {1, 1, 1}, {0, 0, 0}, 0); + auto points = Points(6, 0); auto point = points.CreatePoint(); - point->UnscaledX(11); - point->UnscaledY(11); - point->UnscaledZ(11); + point->X(11.1); + point->Y(11.2); + point->Z(11.3); points.AddPoint(point); REQUIRE(points.Get().size() == 1); - REQUIRE(points.Get(0)->UnscaledX() == 11); - REQUIRE(points.Get(0)->UnscaledY() == 11); - REQUIRE(points.Get(0)->UnscaledZ() == 11); + REQUIRE(points.Get(0)->X() == 11.1); + REQUIRE(points.Get(0)->Y() == 11.2); + REQUIRE(points.Get(0)->Z() == 11.3); point = points.CreatePoint(); - point->UnscaledX(22); - point->UnscaledY(22); - point->UnscaledZ(22); + point->X(22.5); + point->Y(22.6); + point->Z(22.7); points.AddPoint(point); REQUIRE(points.Get().size() == 2); - REQUIRE(points.Get(1)->UnscaledX() == 22); - REQUIRE(points.Get(1)->UnscaledY() == 22); - REQUIRE(points.Get(1)->UnscaledZ() == 22); + REQUIRE(points.Get(1)->X() == 22.5); + REQUIRE(points.Get(1)->Y() == 22.6); + REQUIRE(points.Get(1)->Z() == 22.7); // Test check on point format - point = std::make_shared(7, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 0); + point = std::make_shared(7, 0); REQUIRE_THROWS(points.AddPoint(point)); // Test check on extra bytes - point = std::make_shared(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 1); + point = std::make_shared(6, 1); REQUIRE_THROWS(points.AddPoint(point)); } SECTION("Adding Points to Points") { - auto points = Points(std::vector>( - 10, std::make_shared(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 4))); - auto points_other = Points(std::vector>( - 10, std::make_shared(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 4))); + auto points = Points(std::vector>(10, std::make_shared(6, 4))); + auto points_other = Points(std::vector>(10, std::make_shared(6, 4))); points.AddPoints(points_other); REQUIRE(points.Get().size() == 20); // Test check on point format - points_other = Points(std::vector>( - 10, std::make_shared(7, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 4))); + points_other = Points(std::vector>(10, std::make_shared(7, 4))); REQUIRE_THROWS(points.AddPoints(points_other)); // Test check on extra bytes - points_other = Points(std::vector>( - 10, std::make_shared(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 1))); + points_other = Points(std::vector>(10, std::make_shared(6, 1))); REQUIRE_THROWS(points.AddPoints(points_other)); } SECTION("Points format conversion") { - auto points = Points(std::vector>( - 10, std::make_shared(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 4))); + auto points = Points(std::vector>(10, std::make_shared(6, 4))); points.ToPointFormat(7); REQUIRE(points.PointFormatId() == 7); @@ -118,7 +113,7 @@ TEST_CASE("Points tests", "[Point]") SECTION("Points Group Accessors") { - auto points = Points(7, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 4); + auto points = Points(7, 4); // generate points int num_points = 2000; @@ -142,9 +137,6 @@ TEST_CASE("Points tests", "[Point]") auto X = points.X(); auto Y = points.Y(); auto Z = points.Z(); - auto UnscaledX = points.UnscaledX(); - auto UnscaledY = points.UnscaledY(); - auto UnscaledZ = points.UnscaledZ(); auto classification = points.Classification(); auto point_source_id = points.PointSourceId(); auto red = points.Red(); @@ -155,11 +147,6 @@ TEST_CASE("Points tests", "[Point]") REQUIRE(X[i] == i); REQUIRE(Y[i] == i * 3); REQUIRE(Z[i] == i - 80); - REQUIRE(UnscaledX[i] == int32_t((i - copc::Vector3::DefaultOffset().x) / copc::Vector3::DefaultScale().x)); - REQUIRE(UnscaledY[i] == - int32_t(((i * 3) - copc::Vector3::DefaultOffset().y) / copc::Vector3::DefaultScale().y)); - REQUIRE(UnscaledZ[i] == - int32_t(((i - 80) - copc::Vector3::DefaultOffset().z) / copc::Vector3::DefaultScale().z)); REQUIRE(classification[i] == i * 255 / num_points); REQUIRE(point_source_id[i] == i * 255 / num_points); REQUIRE(red[i] == i * 4); @@ -183,9 +170,6 @@ TEST_CASE("Points tests", "[Point]") REQUIRE_THROWS(points.X(Xn)); REQUIRE_THROWS(points.Y(Yn)); REQUIRE_THROWS(points.Z(Zn)); - REQUIRE_THROWS(points.UnscaledX(UnscaledXn)); - REQUIRE_THROWS(points.UnscaledY(UnscaledYn)); - REQUIRE_THROWS(points.UnscaledZ(UnscaledZn)); REQUIRE_THROWS(points.Classification(classification_n)); REQUIRE_THROWS(points.PointSourceId(point_source_id_n)); REQUIRE_THROWS(points.Red(red_n)); @@ -239,12 +223,6 @@ TEST_CASE("Points tests", "[Point]") REQUIRE(p->X() == i * 50 + 8); REQUIRE(p->Y() == i + 800); REQUIRE(p->Z() == i * 4); - REQUIRE(p->UnscaledX() == - int32_t(((i * 50 + 8) - copc::Vector3::DefaultOffset().x) / copc::Vector3::DefaultScale().x)); - REQUIRE(p->UnscaledY() == - int32_t(((i + 800) - copc::Vector3::DefaultOffset().y) / copc::Vector3::DefaultScale().y)); - REQUIRE(p->UnscaledZ() == - int32_t(((i * 4) - copc::Vector3::DefaultOffset().z) / copc::Vector3::DefaultScale().z)); REQUIRE(p->Classification() == i * 255 / 2000); REQUIRE(p->PointSourceId() == i * 255 / 2000); REQUIRE(p->Red() == i * 4); @@ -257,12 +235,6 @@ TEST_CASE("Points tests", "[Point]") REQUIRE(last_point->X() == 1); REQUIRE(last_point->Y() == 2); REQUIRE(last_point->Z() == 3); - REQUIRE(last_point->UnscaledX() == - int32_t((1 - copc::Vector3::DefaultOffset().x) / copc::Vector3::DefaultScale().x)); - REQUIRE(last_point->UnscaledY() == - int32_t((2 - copc::Vector3::DefaultOffset().y) / copc::Vector3::DefaultScale().y)); - REQUIRE(last_point->UnscaledZ() == - int32_t((3 - copc::Vector3::DefaultOffset().z) / copc::Vector3::DefaultScale().z)); REQUIRE(last_point->Classification() == 255); REQUIRE(last_point->PointSourceId() == 255); REQUIRE(last_point->Red() == num_points * 4); @@ -272,7 +244,7 @@ TEST_CASE("Points tests", "[Point]") SECTION("Points Indexers") { - auto points = Points(6, copc::Vector3::DefaultScale(), copc::Vector3::DefaultOffset(), 4); + auto points = Points(6, 4); // generate points int num_points = 2000; @@ -367,7 +339,7 @@ TEST_CASE("Points tests", "[Point]") SECTION("Within") { - auto points = Points(6, {1, 1, 1}, copc::Vector3::DefaultOffset()); + auto points = Points(6); std::random_device rd; std::mt19937 gen(rd()); @@ -397,7 +369,7 @@ TEST_CASE("Points tests", "[Point]") SECTION("GetWithin") { - auto points = Points(6, {1, 1, 1}, copc::Vector3::DefaultOffset()); + auto points = Points(6); std::random_device rd; std::mt19937 gen(rd()); diff --git a/test/points_test.py b/test/points_test.py index 4bc226b9..4ff74a96 100644 --- a/test/points_test.py +++ b/test/points_test.py @@ -4,35 +4,27 @@ def test_points_constructor(): - points = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset(), 4 - ) + points = copc.Points(6, 4) assert points.point_format_id == 6 assert points.point_record_length == 34 assert len(points) == 0 point1 = copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint() - point1.X = 11 - point1.Y = 11 - point1.Z = 11 + point1.x = 11.1 + point1.y = 11.2 + point1.z = 11.3 point_list = [ point1, copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint(), copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint(), ] @@ -42,54 +34,47 @@ def test_points_constructor(): assert points.point_record_length == 34 for point in points: assert point.point_format_id == 6 - assert points[0].Y == 11 - assert points[0].Z == 11 + assert points[0].x == 11.1 + assert points[0].y == 11.2 + assert points[0].z == 11.3 str(points) def test_adding_point_to_points(): - points = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset(), 0 - ) + points = copc.Points(6, 0) point = copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=0, ).CreatePoint() - point.X = 11 - point.Y = 11 - point.Z = 11 + point.x = 11.1 + point.y = 11.2 + point.z = 11.3 points.AddPoint(point) assert len(points) == 1 - assert points[0].X == 11 - assert points[0].Y == 11 - assert points[0].Z == 11 + assert points[0].x == 11.1 + assert points[0].y == 11.2 + assert points[0].z == 11.3 point = copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=0, ).CreatePoint() - point.X = 22 - point.Y = 22 - point.Z = 22 + point.x = 22.5 + point.y = 22.6 + point.z = 22.7 points.AddPoint(point) assert len(points) == 2 - assert points[1].X == 22 - assert points[1].Y == 22 - assert points[1].Z == 22 + assert points[1].x == 22.5 + assert points[1].y == 22.6 + assert points[1].z == 22.7 # Test check on point format point = copc.Points( 7, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=0, ).CreatePoint() with pytest.raises(RuntimeError): @@ -98,8 +83,6 @@ def test_adding_point_to_points(): # Test check on extra bytes point = copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=1, ).CreatePoint() with pytest.raises(RuntimeError): @@ -111,8 +94,6 @@ def test_adding_points_to_points(): [ copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint() for _ in range(10) @@ -122,8 +103,6 @@ def test_adding_points_to_points(): [ copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint() for _ in range(10) @@ -139,8 +118,6 @@ def test_adding_points_to_points(): [ copc.Points( 7, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint() for _ in range(10) @@ -154,8 +131,6 @@ def test_adding_points_to_points(): [ copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=1, ).CreatePoint() for _ in range(10) @@ -170,8 +145,6 @@ def test_points_format_conversion(): [ copc.Points( 6, - copc.Vector3.DefaultScale(), - copc.Vector3.DefaultOffset(), eb_byte_size=4, ).CreatePoint() for _ in range(10) @@ -191,9 +164,7 @@ def test_points_format_conversion(): def test_points_iterator(): - points = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset(), 4 - ) + points = copc.Points(6, 4) # generate points num_points = 2000 @@ -212,9 +183,7 @@ def test_points_iterator(): def test_points_group_accessors(): - points = copc.Points( - 7, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset(), 4 - ) + points = copc.Points(7, 4) # generate points num_points = 2000 @@ -237,18 +206,6 @@ def test_points_group_accessors(): assert points.x[i] == i assert points.y[i] == i * 3 assert points.z[i] == i - 80 - assert ( - points.X[i] - == (i - copc.Vector3.DefaultOffset().x) / copc.Vector3.DefaultScale().x - ) - assert ( - points.Y[i] - == (i * 3 - copc.Vector3.DefaultOffset().y) / copc.Vector3.DefaultScale().y - ) - assert ( - points.Z[i] - == (i - 80 - copc.Vector3.DefaultOffset().z) / copc.Vector3.DefaultScale().z - ) assert points.classification[i] == i * 255 // num_points assert points.point_source_id[i] == i * 255 // num_points assert points.red[i] == i * 4 @@ -290,21 +247,6 @@ def test_points_group_accessors(): assert p.y == i + 800 assert p.z == i * 4 - assert ( - p.X - == (i * 50 + 8 - copc.Vector3.DefaultOffset().x) - / copc.Vector3.DefaultScale().x - ) - assert ( - p.Y - == (i + 800 - copc.Vector3.DefaultOffset().y) - / copc.Vector3.DefaultScale().y - ) - assert ( - p.Z - == (i * 4 - copc.Vector3.DefaultOffset().z) / copc.Vector3.DefaultScale().z - ) - # test negative indices last_point = points[-1] assert last_point.x == 1 @@ -314,7 +256,7 @@ def test_points_group_accessors(): def test_within(): - points = copc.Points(6, (1, 1, 1), copc.Vector3.DefaultOffset()) + points = copc.Points(6) # generate points for i in range(2000): @@ -337,7 +279,7 @@ def test_within(): def test_get_within(): - points = copc.Points(6, (1, 1, 1), copc.Vector3.DefaultOffset()) + points = copc.Points(6) # generate points for i in range(2000): @@ -353,9 +295,7 @@ def test_get_within(): def test_points_accessors(): - points = copc.Points( - 7, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset(), 4 - ) + points = copc.Points(7, 4) # generate points num_points = 2000 @@ -411,9 +351,7 @@ def test_points_accessors(): def test_points_indexer_setter(): - points = copc.Points( - 6, copc.Vector3.DefaultScale(), copc.Vector3.DefaultOffset(), 4 - ) + points = copc.Points(6, 4) # generate points num_points = 2000 diff --git a/test/reader_node_test.cpp b/test/reader_node_test.cpp index 216f0062..9861a965 100644 --- a/test/reader_node_test.cpp +++ b/test/reader_node_test.cpp @@ -76,9 +76,9 @@ TEST_CASE("GetPoints Test", "[Reader] ") REQUIRE(points.size() == hier_entry.point_count); // Getters - REQUIRE(points[0]->UnscaledX() == -113822); - REQUIRE(points[0]->UnscaledY() == -118589); - REQUIRE(points[0]->UnscaledZ() == -221965); + REQUIRE_THAT(points[0]->X(), Catch::Matchers::WithinAbs(636767.32, 0.01)); + REQUIRE_THAT(points[0]->Y(), Catch::Matchers::WithinAbs(850024.01, 0.01)); + REQUIRE_THAT(points[0]->Z(), Catch::Matchers::WithinAbs(514.24, 0.01)); REQUIRE(points[0]->Intensity() == 11); REQUIRE(points[0]->NumberOfReturns() == 3); REQUIRE(points[0]->ReturnNumber() == 1); @@ -99,9 +99,9 @@ TEST_CASE("GetPoints Test", "[Reader] ") REQUIRE_THROWS(points[0]->Nir()); // Setters - points[0]->UnscaledX(std::numeric_limits::max()); - points[0]->UnscaledY(std::numeric_limits::max()); - points[0]->UnscaledZ(std::numeric_limits::max()); + points[0]->X(11.1); + points[0]->Y(11.2); + points[0]->Z(11.3); points[0]->Intensity(std::numeric_limits::max()); points[0]->NumberOfReturns(7); points[0]->ReturnNumber(7); @@ -117,9 +117,9 @@ TEST_CASE("GetPoints Test", "[Reader] ") points[0]->Blue(std::numeric_limits::max()); REQUIRE_THROWS(points[0]->Nir(std::numeric_limits::max())); - REQUIRE(points[0]->UnscaledX() == std::numeric_limits::max()); - REQUIRE(points[0]->UnscaledY() == std::numeric_limits::max()); - REQUIRE(points[0]->UnscaledZ() == std::numeric_limits::max()); + REQUIRE(points[0]->X() == 11.1); + REQUIRE(points[0]->Y() == 11.2); + REQUIRE(points[0]->Z() == 11.3); REQUIRE(points[0]->Intensity() == std::numeric_limits::max()); REQUIRE(points[0]->NumberOfReturns() == 7); REQUIRE(points[0]->ReturnNumber() == 7); diff --git a/test/writer_test.cpp b/test/writer_test.cpp index 1ed4e30e..75d0cf22 100644 --- a/test/writer_test.cpp +++ b/test/writer_test.cpp @@ -204,9 +204,9 @@ TEST_CASE("Writer Config Tests", "[Writer]") // Check that we can add a point of new format auto new_points = las::Points(*copy_writer.CopcConfig()->LasHeader()); auto new_point = new_points.CreatePoint(); - new_point->UnscaledX(10); - new_point->UnscaledY(15); - new_point->UnscaledZ(20); + new_point->X(10); + new_point->Y(15); + new_point->Z(20); new_point->GPSTime(1.5); new_point->Red(25); new_point->Nir(30); @@ -235,9 +235,9 @@ TEST_CASE("Writer Config Tests", "[Writer]") // Check that the written point is read correctly auto points = reader.GetPoints(VoxelKey::RootKey()); REQUIRE(points.Size() == 1); - REQUIRE(points[0]->UnscaledX() == 10); - REQUIRE(points[0]->UnscaledY() == 15); - REQUIRE(points[0]->UnscaledZ() == 20); + REQUIRE(points[0]->X() == 10); + REQUIRE(points[0]->Y() == 15); + REQUIRE(points[0]->Z() == 20); REQUIRE(points[0]->GPSTime() == 1.5); REQUIRE(points[0]->Red() == 25); REQUIRE(points[0]->Nir() == 30); @@ -596,7 +596,7 @@ TEST_CASE("Writer Pages", "[Writer]") REQUIRE(!writer.FindNode(VoxelKey::InvalidKey()).IsValid()); REQUIRE(!writer.FindNode(VoxelKey(5, 4, 3, 2)).IsValid()); auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); points.AddPoint(points.CreatePoint()); // Add a node with root key as page writer.AddNode(VoxelKey(1, 1, 1, 1), points, VoxelKey::RootKey()); @@ -616,7 +616,7 @@ TEST_CASE("Writer Pages", "[Writer]") Writer writer(out_stream, {6}); auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); points.AddPoint(points.CreatePoint()); writer.AddNode(VoxelKey(1, 1, 1, 1), points, VoxelKey(1, 1, 1, 1)); @@ -644,7 +644,7 @@ TEST_CASE("Writer Pages", "[Writer]") Writer writer(out_stream, {6}); auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); points.AddPoint(points.CreatePoint()); writer.AddNode(VoxelKey(3, 4, 4, 4), points, VoxelKey(2, 2, 2, 2)); @@ -801,7 +801,7 @@ TEST_CASE("Check Spatial Bounds", "[Writer]") auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); auto point = points.CreatePoint(); point->X(9); @@ -823,7 +823,7 @@ TEST_CASE("Check Spatial Bounds", "[Writer]") auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); auto point = points.CreatePoint(); point->X(10); @@ -845,7 +845,7 @@ TEST_CASE("Check Spatial Bounds", "[Writer]") auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); auto point = points.CreatePoint(); point->X(10); @@ -867,7 +867,7 @@ TEST_CASE("Check Spatial Bounds", "[Writer]") auto header = *writer.CopcConfig()->LasHeader(); - las::Points points(header.PointFormatId(), header.Scale(), header.Offset()); + las::Points points(header.PointFormatId()); auto point = points.CreatePoint(); point->X(0.1); diff --git a/test/writer_test.py b/test/writer_test.py index 2accac22..1ba295b6 100644 --- a/test/writer_test.py +++ b/test/writer_test.py @@ -237,7 +237,7 @@ def test_writer_pages(): # Root Page header = writer.copc_config.las_header - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) points.AddPoint(points.CreatePoint()) # Add a node with root key as page writer.AddNode((1, 1, 1, 1), points, copc.VoxelKey.RootKey()) @@ -253,7 +253,7 @@ def test_writer_pages(): writer = copc.FileWriter(file_path, copc.CopcConfigWriter(6)) header = writer.copc_config.las_header - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) points.AddPoint(points.CreatePoint()) writer.AddNode((1, 1, 1, 1), points, page_key=(1, 1, 1, 1)) @@ -279,7 +279,7 @@ def test_writer_pages(): writer = copc.FileWriter(file_path, copc.CopcConfigWriter(6)) header = writer.copc_config.las_header - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) points.AddPoint(points.CreatePoint()) writer.AddNode((3, 4, 4, 4), points, page_key=(2, 2, 2, 2)) @@ -405,9 +405,9 @@ def test_writer_copy_and_update(): new_points = copc.Points(writer.copc_config.las_header) new_point = new_points.CreatePoint() - new_point.X = 10 - new_point.Y = 15 - new_point.Z = 20 + new_point.x = 10 + new_point.y = 15 + new_point.z = 20 new_point.gps_time = 1.5 new_point.red = 25 new_point.nir = 30 @@ -441,9 +441,9 @@ def test_writer_copy_and_update(): # Check that the written point is read correctly points = reader.GetPoints(copc.VoxelKey.RootKey()) assert len(points) == 1 - assert points[0].X == 10 - assert points[0].Y == 15 - assert points[0].Z == 20 + assert points[0].x == 10 + assert points[0].y == 15 + assert points[0].z == 20 assert points[0].gps_time == 1.5 assert points[0].red == 25 assert points[0].nir == 30 @@ -706,7 +706,7 @@ def test_check_spatial_bounds(): ## Checks on las header bounds - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) point = points.CreatePoint() # point has getters/setters for all attributes @@ -728,7 +728,7 @@ def test_check_spatial_bounds(): header = writer.copc_config.las_header - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) point = points.CreatePoint() point.x = 10 @@ -748,7 +748,7 @@ def test_check_spatial_bounds(): header = writer.copc_config.las_header - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) point = points.CreatePoint() point.x = 10 @@ -767,7 +767,7 @@ def test_check_spatial_bounds(): writer = copc.FileWriter(file_path, cfg) header = writer.copc_config.las_header - points = copc.Points(header.point_format_id, header.scale, header.offset) + points = copc.Points(header.point_format_id) point = points.CreatePoint() point.x = 0.1