diff --git a/CHANGELOG.md b/CHANGELOG.md index 163c4e23..1402a61c 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] +### Added +- **\[C++\]** Add output operator (<<) overrides for classes with ToString methods + ## [2.4.1] - 2022-09-13 ### Changed diff --git a/cpp/include/copc-lib/copc/extents.hpp b/cpp/include/copc-lib/copc/extents.hpp index 6742e050..cbdf4796 100644 --- a/cpp/include/copc-lib/copc/extents.hpp +++ b/cpp/include/copc-lib/copc/extents.hpp @@ -36,6 +36,11 @@ class CopcExtent CopcExtent(const CopcExtent &other); std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, CopcExtent const &value) + { + os << value.ToString(); + return os; + } // Operators bool operator==(const CopcExtent &other) const @@ -202,6 +207,11 @@ class CopcExtents static size_t ByteSize(int8_t point_format_id, uint16_t num_eb_items); std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, CopcExtents const &value) + { + os << value.ToString(); + return os; + } private: int8_t point_format_id_; diff --git a/cpp/include/copc-lib/copc/info.hpp b/cpp/include/copc-lib/copc/info.hpp index 3dbada25..1895444b 100644 --- a/cpp/include/copc-lib/copc/info.hpp +++ b/cpp/include/copc-lib/copc/info.hpp @@ -21,6 +21,11 @@ class CopcInfo lazperf::copc_info_vlr ToLazPerf(const CopcExtent &gps_time) const; std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, CopcInfo const &value) + { + os << value.ToString(); + return os; + } double center_x{0}; double center_y{0}; diff --git a/cpp/include/copc-lib/geometry/box.hpp b/cpp/include/copc-lib/geometry/box.hpp index 6274b0b0..9a6a00f0 100644 --- a/cpp/include/copc-lib/geometry/box.hpp +++ b/cpp/include/copc-lib/geometry/box.hpp @@ -42,6 +42,11 @@ class Box bool Within(const Box &box) const; std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, Box const &value) + { + os << value.ToString(); + return os; + } double x_min{}; double y_min{}; diff --git a/cpp/include/copc-lib/geometry/vector3.hpp b/cpp/include/copc-lib/geometry/vector3.hpp index e61a6c5f..c19b61a9 100644 --- a/cpp/include/copc-lib/geometry/vector3.hpp +++ b/cpp/include/copc-lib/geometry/vector3.hpp @@ -42,6 +42,11 @@ struct Vector3 ss << "(" << x << ", " << y << ", " << z << ")"; return ss.str(); } + friend std::ostream &operator<<(std::ostream &os, Vector3 const &value) + { + os << value.ToString(); + return os; + } bool operator==(Vector3 other) const { return x == other.x && y == other.y && z == other.z; } bool operator!=(Vector3 other) const { return !(*this == other); } diff --git a/cpp/include/copc-lib/hierarchy/entry.hpp b/cpp/include/copc-lib/hierarchy/entry.hpp index aa10e4fc..cb4eaba0 100644 --- a/cpp/include/copc-lib/hierarchy/entry.hpp +++ b/cpp/include/copc-lib/hierarchy/entry.hpp @@ -30,6 +30,11 @@ class Entry << ", is_valid=" << IsValid(); return ss.str(); } + friend std::ostream &operator<<(std::ostream &os, Entry const &value) + { + os << value.ToString(); + return os; + } void Pack(std::ostream &out_stream) { diff --git a/cpp/include/copc-lib/hierarchy/key.hpp b/cpp/include/copc-lib/hierarchy/key.hpp index e33b4b87..3b6d6ef9 100644 --- a/cpp/include/copc-lib/hierarchy/key.hpp +++ b/cpp/include/copc-lib/hierarchy/key.hpp @@ -43,6 +43,11 @@ class VoxelKey bool IsValid() const { return d >= 0 && x >= 0 && y >= 0 && z >= 0; } std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, VoxelKey const &value) + { + os << value.ToString(); + return os; + } // Returns the corresponding key depending on direction [0,7] VoxelKey Bisect(const uint64_t &direction) const; diff --git a/cpp/include/copc-lib/las/header.hpp b/cpp/include/copc-lib/las/header.hpp index 40abcabd..a7dc819b 100644 --- a/cpp/include/copc-lib/las/header.hpp +++ b/cpp/include/copc-lib/las/header.hpp @@ -50,6 +50,11 @@ class LasHeader bool eb_flag, bool extended_stats_flag) const; std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, LasHeader const &value) + { + os << value.ToString(); + return os; + } // Getters/Setters for protected attributes diff --git a/cpp/include/copc-lib/las/point.hpp b/cpp/include/copc-lib/las/point.hpp index a8dd05c6..9e3c53f2 100644 --- a/cpp/include/copc-lib/las/point.hpp +++ b/cpp/include/copc-lib/las/point.hpp @@ -215,6 +215,11 @@ class Point bool Within(const Box &box) const; std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, Point const &value) + { + os << value.ToString(); + return os; + } 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); diff --git a/cpp/include/copc-lib/las/points.hpp b/cpp/include/copc-lib/las/points.hpp index fa1c0767..ff76f283 100644 --- a/cpp/include/copc-lib/las/points.hpp +++ b/cpp/include/copc-lib/las/points.hpp @@ -59,6 +59,11 @@ class Points static Points Unpack(const std::vector &point_data, const LasHeader &header); std::string ToString() const; + friend std::ostream &operator<<(std::ostream &os, Points const &value) + { + os << value.ToString(); + return os; + } // Getters and setters std::vector X() const diff --git a/cpp/src/io/copc_reader.cpp b/cpp/src/io/copc_reader.cpp index c3f79ccd..a316a343 100644 --- a/cpp/src/io/copc_reader.cpp +++ b/cpp/src/io/copc_reader.cpp @@ -338,10 +338,10 @@ bool Reader::ValidateSpatialBounds(bool verbose) std::cout << "Validating Spatial Bounds" << std::endl; std::cout << "File info:" << std::endl; std::cout << "\tPoint Count: " << header.PointCount() << std::endl; - std::cout << "\tScale: " << header.Scale().ToString() << std::endl; - std::cout << "\tOffset: " << header.Offset().ToString() << std::endl; - std::cout << "\tMin Bounds: " << header.min.ToString() << std::endl; - std::cout << "\tMax Bounds: " << header.max.ToString() << std::endl; + std::cout << "\tScale: " << header.Scale() << std::endl; + std::cout << "\tOffset: " << header.Offset() << std::endl; + std::cout << "\tMin Bounds: " << header.min << std::endl; + std::cout << "\tMax Bounds: " << header.max << std::endl; std::cout << std::endl << "Validating bounds..." << std::endl << std::endl; } @@ -354,8 +354,8 @@ bool Reader::ValidateSpatialBounds(bool verbose) is_valid = false; if (!verbose) return false; - std::cout << "Node " << node.key.ToString() << " is outside of las header bounds (" - << header.Bounds().ToString() << ")." << std::endl; + std::cout << "Node " << node.key << " is outside of las header bounds (" << header.Bounds() << ")." + << std::endl; total_points_outside_header_bounds += node.point_count; } else @@ -372,8 +372,8 @@ bool Reader::ValidateSpatialBounds(bool verbose) if (!verbose) return false; std::cout << "Point (" << point->X() << "," << point->Y() << "," << point->Z() << ") from node " - << node.key.ToString() << " is outside of las header bounds (" - << header.Bounds().ToString() << ")." << std::endl; + << node.key << " is outside of las header bounds (" << header.Bounds() << ")." + << std::endl; total_points_outside_header_bounds++; } } @@ -388,8 +388,7 @@ bool Reader::ValidateSpatialBounds(bool verbose) if (!verbose) return false; std::cout << "Point (" << point->X() << "," << point->Y() << "," << point->Z() - << ") is outside of node " << node.key.ToString() << " bounds (" << box.ToString() << ")." - << std::endl; + << ") is outside of node " << node.key << " bounds (" << box << ")." << std::endl; total_points_outside_node_bounds++; } } diff --git a/cpp/src/las/header.cpp b/cpp/src/las/header.cpp index 36abed87..dccd2910 100644 --- a/cpp/src/las/header.cpp +++ b/cpp/src/las/header.cpp @@ -174,10 +174,10 @@ std::string LasHeader::ToString() const ss << "\tPoint Format ID: " << static_cast(point_format_id_) << std::endl; ss << "\tPoint Record Length: " << point_record_length_ << std::endl; ss << "\tPoint Count: " << point_count_ << std::endl; - ss << "\tScale: " << scale_.ToString() << std::endl; - ss << "\tOffset: " << offset_.ToString() << std::endl; - ss << "\tMax: " << max.ToString() << std::endl; - ss << "\tMin: " << min.ToString() << std::endl; + ss << "\tScale: " << scale_ << std::endl; + ss << "\tOffset: " << offset_ << std::endl; + ss << "\tMax: " << max << std::endl; + ss << "\tMin: " << min << std::endl; ss << "\tEVLR Offset: " << evlr_offset_ << std::endl; ss << "\tEVLR count: " << evlr_count_ << std::endl; ss << "\tPoints By Return:" << std::endl; diff --git a/test/box_test.cpp b/test/box_test.cpp index e7a16fa3..9a32f599 100644 --- a/test/box_test.cpp +++ b/test/box_test.cpp @@ -37,6 +37,13 @@ TEST_CASE("Box constructor", "[Box]") REQUIRE_THROWS(Box(2, 0, 0, 1, 1, 1)); REQUIRE_THROWS(Box(0, 2, 0, 1, 1, 1)); REQUIRE_THROWS(Box(0, 0, 2, 1, 1, 1)); + + SECTION("Box ToString") + { + box.ToString(); + std::stringstream ss; + ss << box; + } } SECTION("Vector3 constructor") diff --git a/test/copc_config_test.cpp b/test/copc_config_test.cpp index 9e6876d3..2f42f31c 100644 --- a/test/copc_config_test.cpp +++ b/test/copc_config_test.cpp @@ -128,6 +128,14 @@ TEST_CASE("CopcConfigWriter", "[CopcConfigWriter]") { CopcInfo copc_info; copc_info.spacing = test_spacing; + + SECTION("CopcInfo ToString") + { + copc_info.ToString(); + std::stringstream ss; + ss << copc_info; + } + CopcExtents copc_extents(point_format_id, num_eb_items); copc_extents.Intensity()->minimum = test_intensity_min; copc_extents.Intensity()->maximum = test_intensity_max; diff --git a/test/extents_test.cpp b/test/extents_test.cpp index 027a5c96..09b9ddaf 100644 --- a/test/extents_test.cpp +++ b/test/extents_test.cpp @@ -27,6 +27,13 @@ TEST_CASE("COPC Extent", "[CopcExtent]") REQUIRE(extent != other); REQUIRE_THROWS(CopcExtent(1, 0)); + + SECTION("ToString") + { + extent.ToString(); + std::stringstream ss; + ss << extent; + } } TEST_CASE("COPC Extents", "[CopcExtents]") diff --git a/test/key_test.cpp b/test/key_test.cpp index b7367c41..8575d241 100644 --- a/test/key_test.cpp +++ b/test/key_test.cpp @@ -20,6 +20,13 @@ TEST_CASE("Voxel Key checks key validity", "[Key]") REQUIRE(VoxelKey(1, 1, 1, 1).IsValid() == true); } +TEST_CASE("VoxelKey ToString", "[Key]") +{ + VoxelKey(1, 1, 1, 1).ToString(); + std::stringstream ss; + ss << VoxelKey(1, 1, 1, 1); +} + TEST_CASE("GetParent Checks", "[Key]") { REQUIRE(VoxelKey(-1, -1, -1, -1).GetParent().IsValid() == false); diff --git a/test/las_header_test.cpp b/test/las_header_test.cpp index ff6569b8..f6efe76b 100644 --- a/test/las_header_test.cpp +++ b/test/las_header_test.cpp @@ -94,7 +94,12 @@ TEST_CASE("Test reader and conversions", "[LasHeader]") REQUIRE(las_header_origin.EvlrOffset() == las_header.EvlrOffset()); REQUIRE(las_header_origin.EvlrCount() == las_header.EvlrCount()); - las_header_origin.ToString(); + SECTION("LasHeader ToString") + { + las_header_origin.ToString(); + std::stringstream ss; + ss << las_header_origin; + } } } diff --git a/test/point_test.cpp b/test/point_test.cpp index 41e52b77..1170ca5b 100644 --- a/test/point_test.cpp +++ b/test/point_test.cpp @@ -199,6 +199,13 @@ TEST_CASE("Point tests", "[Point]") REQUIRE(point.Green() == 0); REQUIRE(point.Blue() == 0); REQUIRE(point.Nir() == 0); + + SECTION("Point ToString") + { + point.ToString(); + std::stringstream ss; + ss << point; + } } SECTION("Point conversion") diff --git a/test/points_test.cpp b/test/points_test.cpp index d186535b..b5b14364 100644 --- a/test/points_test.cpp +++ b/test/points_test.cpp @@ -41,7 +41,12 @@ TEST_CASE("Points tests", "[Point]") REQUIRE(points.Get(0)->Y() == 11.2); REQUIRE(points.Get(0)->Z() == 11.3); - points.ToString(); + SECTION("Points ToString") + { + points.ToString(); + std::stringstream ss; + ss << points; + } } SECTION("Adding Point to Points") diff --git a/test/reader_test.cpp b/test/reader_test.cpp index bd8bc17a..a00be704 100644 --- a/test/reader_test.cpp +++ b/test/reader_test.cpp @@ -134,6 +134,13 @@ TEST_CASE("FindKey Check", "[Reader]") REQUIRE(hier_entry.IsValid() == true); REQUIRE(hier_entry.key == key); REQUIRE(hier_entry.point_count == 12021); + + SECTION("Node ToString") + { + hier_entry.ToString(); + std::stringstream ss; + ss << hier_entry; + } } } diff --git a/test/vector3_test.cpp b/test/vector3_test.cpp index 1610be7f..a9453360 100644 --- a/test/vector3_test.cpp +++ b/test/vector3_test.cpp @@ -31,6 +31,13 @@ TEST_CASE("Vector3", "[Vector3]") REQUIRE(vec.x == 0.0); REQUIRE(vec.y == 0.0); REQUIRE(vec.z == 0.0); + + SECTION("Vector3 ToString") + { + vec.ToString(); + std::stringstream ss; + ss << vec; + } } SECTION("Vector3 Operators") {