From 16851497bc16327b0e43537beb1bedae5ed6cf74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bartoletti?= Date: Thu, 10 Oct 2024 09:23:34 +0200 Subject: [PATCH] fix(wkb): add support for Solid and MultiSolid with correct WKB codes 25/26 Previously, the WKB export did not support `Solid` and `MultiSolid`, as these geometries are not commonly found in existing standards. However, WKT export was already implemented for both types. According to the ISO/IEC 13249-3:2016 standard, the code 102 is assigned to `AffinePlacement`, and while `ST_SOLID` is not instantiable, `SOLID` is the name used in (City)GML, corresponding to `ST_BRepSolid`. Our implementation of `Solid` aligns with `ST_BRepSolid`, which consists of shells (represented as `PolyhedralSurface` in our case; `PolyhedralSurface` + `CompoundSurface` in the standard). However, the WKB code is not officially listed for `BRepSolid`, except for `BRepSolidZ` with the code ` 1025`. This implies that the regular code for `BRepSolid` should be 25 (with 1000 added for the Z coordinate). Additionally, since `MultiSolid` has no existing WKB code, we propose assigning the code 26, as it is currently available. Thus, we move from the previous 101/102 to 25/26, ensuring we use the correct WKB code for `Solid` (BRepSolid). --- src/Geometry.h | 4 ++-- src/detail/io/WkbReader.cpp | 23 +++++++++++++++++++++++ src/detail/io/WkbReader.h | 15 +++++++++++++++ src/detail/io/WkbWriter.cpp | 26 ++++++++++++++++++++++---- test/unit/SFCGAL/io/WkbWriterTest.cpp | 19 +++++++++++++++++++ 5 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/Geometry.h b/src/Geometry.h index f4b445e8..8fa65590 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -81,8 +81,8 @@ enum GeometryType { TYPE_TRIANGLE = 17, //-- not official codes - TYPE_SOLID = 101, - TYPE_MULTISOLID = 102 + TYPE_SOLID = 25, + TYPE_MULTISOLID = 26 }; /** diff --git a/src/detail/io/WkbReader.cpp b/src/detail/io/WkbReader.cpp index 2837514c..0f1beee7 100644 --- a/src/detail/io/WkbReader.cpp +++ b/src/detail/io/WkbReader.cpp @@ -220,4 +220,27 @@ WkbReader::readInnerPolyhedralSurface() -> PolyhedralSurface return result; } +/** + * Read Solid content from wkb + */ +auto +WkbReader::readInnerSolid() -> Solid +{ + std::vector geoms; + try { + const uint32_t numGeoms{read()}; + for (uint32_t i = 0; i < numGeoms; ++i) { + readWkb(); + if (_geometry != nullptr) { + geoms.push_back(_geometry->as()); + } + } + } catch (std::exception &e) { + std::cerr << e.what(); + return {}; + } + SFCGAL::Solid const result{geoms}; + return result; +} + } // namespace SFCGAL::detail::io diff --git a/src/detail/io/WkbReader.h b/src/detail/io/WkbReader.h index df4f1967..2054a47d 100644 --- a/src/detail/io/WkbReader.h +++ b/src/detail/io/WkbReader.h @@ -14,10 +14,12 @@ #include "SFCGAL/MultiLineString.h" #include "SFCGAL/MultiPoint.h" #include "SFCGAL/MultiPolygon.h" +#include "SFCGAL/MultiSolid.h" #include "SFCGAL/Point.h" #include "SFCGAL/Polygon.h" #include "SFCGAL/PolyhedralSurface.h" #include "SFCGAL/PreparedGeometry.h" +#include "SFCGAL/Solid.h" #include "SFCGAL/Triangle.h" #include "SFCGAL/TriangulatedSurface.h" @@ -227,6 +229,13 @@ class SFCGAL_API WkbReader { return std::unique_ptr( readInnerPolyhedralSurface().clone()); + case TYPE_SOLID: + return std::unique_ptr(readInnerSolid().clone()); + + case TYPE_MULTISOLID: + return std::unique_ptr( + readInnerMultiGeometries().clone()); + default: std::ostringstream oss; oss << "WkbWriter: type '" << geometryType << "' is not supported"; @@ -295,6 +304,12 @@ class SFCGAL_API WkbReader { auto readInnerPolyhedralSurface() -> PolyhedralSurface; + /** + * Read Solid content from wkb + */ + auto + readInnerSolid() -> Solid; + /** * actually reading 3D ? */ diff --git a/src/detail/io/WkbWriter.cpp b/src/detail/io/WkbWriter.cpp index 0ac34715..10e069df 100644 --- a/src/detail/io/WkbWriter.cpp +++ b/src/detail/io/WkbWriter.cpp @@ -12,9 +12,11 @@ #include "SFCGAL/MultiLineString.h" #include "SFCGAL/MultiPoint.h" #include "SFCGAL/MultiPolygon.h" +#include "SFCGAL/MultiSolid.h" #include "SFCGAL/Point.h" #include "SFCGAL/Polygon.h" #include "SFCGAL/PolyhedralSurface.h" +#include "SFCGAL/Solid.h" #include "SFCGAL/Triangle.h" #include "SFCGAL/TriangulatedSurface.h" @@ -71,6 +73,14 @@ WkbWriter::writeRec(const Geometry &g, boost::endian::order wkbOrder) writeInner(g.as(), wkbOrder); return; + case TYPE_SOLID: + writeInner(g.as(), wkbOrder); + return; + + case TYPE_MULTISOLID: + writeInner(g.as(), wkbOrder); + return; + default: std::ostringstream oss; oss << "WkbWriter: type '" << g.geometryType() << "' is not supported"; @@ -278,11 +288,19 @@ WkbWriter::writeInner(const M &g, boost::endian::order wkbOrder) // WkbType writeGeometryType(g, wkbOrder); - // Number of Geometries - toByte(static_cast(g.numGeometries()), wkbOrder); + // Number of Geometries/Shells + if constexpr (std::is_same::value) { + toByte(static_cast(g.numShells()), wkbOrder); - for (size_t i = 0; i < g.numGeometries(); i++) { - writeInner(g.geometryN(i).template as(), wkbOrder); + for (size_t i = 0; i < g.numShells(); i++) { + writeRec(g.shellN(i).template as(), wkbOrder); + } + } else { + toByte(static_cast(g.numGeometries()), wkbOrder); + + for (size_t i = 0; i < g.numGeometries(); i++) { + writeRec(g.geometryN(i).template as(), wkbOrder); + } } } diff --git a/test/unit/SFCGAL/io/WkbWriterTest.cpp b/test/unit/SFCGAL/io/WkbWriterTest.cpp index 17c614fc..ce1383be 100644 --- a/test/unit/SFCGAL/io/WkbWriterTest.cpp +++ b/test/unit/SFCGAL/io/WkbWriterTest.cpp @@ -140,4 +140,23 @@ BOOST_AUTO_TEST_CASE(PostgisEWkb) } } } + +BOOST_AUTO_TEST_CASE(SolidWKB) +{ + std::string cube{"SOLID((((0 0 0,0 1 0,1 1 0,1 0 0,0 0 0)),((1 0 0,1 1 0,1 1 " + "1,1 0 1,1 0 0)),((0 1 0,0 1 1,1 1 1,1 1 0,0 1 0)),((0 0 " + "1,0 1 1,0 1 0,0 0 0,0 0 1)),((1 0 1,1 1 1,0 1 1,0 0 1,1 0 " + "1)),((1 0 0,1 0 1,0 0 1,0 0 0,1 0 0))))"}; + + std::unique_ptr g(io::readWkt(cube)); + auto wkbBinary = g->asWkb(); + std::unique_ptr g2(io::readWkb(wkbBinary)); + BOOST_CHECK_EQUAL(g->asText(0), g2->asText(0)); + + /* + wkbBinary = g->asWkb(boost::endian::order::native, true); + std::cerr << wkbBinary << "\n"; + */ +} + BOOST_AUTO_TEST_SUITE_END()