From af8794411b4ad593dee7dcc82792087ff4d765f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bartoletti?= Date: Tue, 3 Oct 2023 10:52:15 +0200 Subject: [PATCH] Add a new version of extrude_straigth_skeleton to generate building with roof --- src/algorithm/extrude.cpp | 28 ++++++-- src/algorithm/extrude.h | 2 + src/algorithm/straightSkeleton.cpp | 16 +++++ src/algorithm/straightSkeleton.h | 10 ++- src/capi/sfcgal_c.cpp | 41 ++++++++++-- src/capi/sfcgal_c.h | 12 +++- .../SFCGAL/algorithm/StraightSkeletonTest.cpp | 66 +++++++++++++++++++ 7 files changed, 157 insertions(+), 18 deletions(-) diff --git a/src/algorithm/extrude.cpp b/src/algorithm/extrude.cpp index cc0da855..6a305f4a 100644 --- a/src/algorithm/extrude.cpp +++ b/src/algorithm/extrude.cpp @@ -38,7 +38,8 @@ extrude(const Point &g, const Kernel::Vector_3 &v) -> LineString *; auto extrude(const LineString &g, const Kernel::Vector_3 &v) -> PolyhedralSurface *; auto -extrude(const Polygon &g, const Kernel::Vector_3 &v) -> Solid *; +extrude(const Polygon &g, const Kernel::Vector_3 &v, bool addTop = true) + -> Solid *; auto extrude(const Triangle &g, const Kernel::Vector_3 &v) -> Solid *; @@ -120,7 +121,7 @@ extrude(const LineString &g, const Kernel::Vector_3 &v) -> PolyhedralSurface * /// /// auto -extrude(const Polygon &g, const Kernel::Vector_3 &v) -> Solid * +extrude(const Polygon &g, const Kernel::Vector_3 &v, bool addTop) -> Solid * { if (g.isEmpty()) { return new Solid(); @@ -142,11 +143,12 @@ extrude(const Polygon &g, const Kernel::Vector_3 &v) -> Solid * polyhedralSurface.addPolygon(bottom); // "top" - Polygon top(bottom); - top.reverse(); - translate(top, v); - polyhedralSurface.addPolygon(top); - + if (addTop) { + Polygon top(bottom); + top.reverse(); + translate(top, v); + polyhedralSurface.addPolygon(top); + } // exterior ring and interior rings extruded for (size_t i = 0; i < bottom.numRings(); i++) { std::unique_ptr boundaryExtruded( @@ -391,5 +393,17 @@ extrude(const Geometry &g, const double &dx, const double &dy, const double &dz) return extrude(g, Kernel::FT(dx), Kernel::FT(dy), Kernel::FT(dz)); } +SFCGAL_API auto +extrude(const Polygon &g, const double &height) -> std::unique_ptr +{ + + if (!std::isfinite(height)) { + BOOST_THROW_EXCEPTION(NonFiniteValueException( + "trying to extrude with non finite value in direction")); + } + + return std::unique_ptr( + extrude(g, Kernel::Vector_3(0.0, 0.0, height), false)); +} } // namespace algorithm } // namespace SFCGAL diff --git a/src/algorithm/extrude.h b/src/algorithm/extrude.h index 79264963..e426e47b 100644 --- a/src/algorithm/extrude.h +++ b/src/algorithm/extrude.h @@ -111,6 +111,8 @@ SFCGAL_API std::unique_ptr SFCGAL_API std::unique_ptr extrude(const Geometry &g, const Kernel::Vector_3 &v); +SFCGAL_API std::unique_ptr + extrude(const Polygon &g, const double &height); } // namespace algorithm } // namespace SFCGAL diff --git a/src/algorithm/straightSkeleton.cpp b/src/algorithm/straightSkeleton.cpp index 594af3bc..1db7b996 100644 --- a/src/algorithm/straightSkeleton.cpp +++ b/src/algorithm/straightSkeleton.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -412,5 +414,19 @@ extrudeStraightSkeleton(const Geometry &g, double height) return result; } +auto +extrudeStraightSkeleton(const Geometry &g, double building_height, + double roof_height) + -> std::unique_ptr +{ + std::unique_ptr roof{ + extrudeStraightSkeleton(g, roof_height)}; + translate(*roof, 0.0, 0.0, building_height); + std::unique_ptr building(extrude(g.as(), building_height)); + std::unique_ptr result{ + new PolyhedralSurface(building->as().exteriorShell())}; + result->addPolygons(*roof); + return result; +}; } // namespace algorithm } // namespace SFCGAL diff --git a/src/algorithm/straightSkeleton.h b/src/algorithm/straightSkeleton.h index 48443a69..49f29087 100644 --- a/src/algorithm/straightSkeleton.h +++ b/src/algorithm/straightSkeleton.h @@ -5,8 +5,10 @@ #ifndef _SFCGAL_ALGORITHM_STRAIGHTSKELETON_H_ #define _SFCGAL_ALGORITHM_STRAIGHTSKELETON_H_ +#include +#include +#include #include - #include namespace SFCGAL { @@ -96,6 +98,12 @@ extrudedStraightSkeleton(const Polygon &g, double height) SFCGAL_API auto extrudeStraightSkeleton(const Geometry &g, double height) -> std::unique_ptr; + +SFCGAL_API auto +extrudeStraightSkeleton(const Geometry &g, double building_height, + double roof_height) + -> std::unique_ptr; + } // namespace algorithm } // namespace SFCGAL diff --git a/src/capi/sfcgal_c.cpp b/src/capi/sfcgal_c.cpp index 55c3c813..df83687c 100644 --- a/src/capi/sfcgal_c.cpp +++ b/src/capi/sfcgal_c.cpp @@ -1171,8 +1171,8 @@ sfcgal_geometry_has_validity_flag(const sfcgal_geometry_t *geom) -> int } extern "C" auto -sfcgal_geometry_extrude_straight_skeleton(const sfcgal_geometry_t *geom, double height) - -> sfcgal_geometry_t * +sfcgal_geometry_extrude_straight_skeleton(const sfcgal_geometry_t *geom, + double height) -> sfcgal_geometry_t * { const auto *g1 = reinterpret_cast(geom); std::unique_ptr polys; @@ -1190,6 +1190,29 @@ sfcgal_geometry_extrude_straight_skeleton(const sfcgal_geometry_t *geom, double return polys.release(); } +extern "C" auto +sfcgal_geometry_extrude_polygon_straight_skeleton(const sfcgal_geometry_t *geom, + double building_height, + double roof_height) + -> sfcgal_geometry_t * +{ + const auto *g1 = reinterpret_cast(geom); + std::unique_ptr polys; + + try { + polys = SFCGAL::algorithm::extrudeStraightSkeleton(*g1, building_height, + roof_height); + } catch (std::exception &e) { + SFCGAL_WARNING("During straight_extrude_skeleton_distance(A):"); + SFCGAL_WARNING(" with A: %s", + ((const SFCGAL::Geometry *)(geom))->asText().c_str()); + SFCGAL_ERROR("%s", e.what()); + return nullptr; + } + + return polys.release(); +} + extern "C" auto sfcgal_geometry_straight_skeleton_distance_in_m(const sfcgal_geometry_t *geom) -> sfcgal_geometry_t * @@ -1279,7 +1302,6 @@ sfcgal_geometry_optimal_alpha_shapes(const sfcgal_geometry_t *geom, return result.release(); } - extern "C" sfcgal_geometry_t * sfcgal_y_monotone_partition_2(const sfcgal_geometry_t *geom) { @@ -1287,7 +1309,8 @@ sfcgal_y_monotone_partition_2(const sfcgal_geometry_t *geom) std::unique_ptr result; try { - result = SFCGAL::algorithm::partition_2(g1->as(), SFCGAL::algorithm::y_monotone); + result = SFCGAL::algorithm::partition_2(g1->as(), + SFCGAL::algorithm::y_monotone); } catch (std::exception &e) { SFCGAL_WARNING("During y_monotone_partition_2(A):"); SFCGAL_WARNING(" with A: %s", @@ -1306,7 +1329,8 @@ sfcgal_approx_convex_partition_2(const sfcgal_geometry_t *geom) std::unique_ptr result; try { - result = SFCGAL::algorithm::partition_2(g1->as(), SFCGAL::algorithm::approx_convex); + result = SFCGAL::algorithm::partition_2(g1->as(), + SFCGAL::algorithm::approx_convex); } catch (std::exception &e) { SFCGAL_WARNING("During approx_convex_partition_2(A):"); SFCGAL_WARNING(" with A: %s", @@ -1325,7 +1349,9 @@ sfcgal_greene_approx_convex_partition_2(const sfcgal_geometry_t *geom) std::unique_ptr result; try { - result = SFCGAL::algorithm::partition_2(g1->as(), SFCGAL::algorithm::greene_approx_convex); + result = + SFCGAL::algorithm::partition_2(g1->as(), + SFCGAL::algorithm::greene_approx_convex); } catch (std::exception &e) { SFCGAL_WARNING("During greene_approx_convex_partition_2(A):"); SFCGAL_WARNING(" with A: %s", @@ -1343,7 +1369,8 @@ sfcgal_optimal_convex_partition_2(const sfcgal_geometry_t *geom) std::unique_ptr result; try { - result = SFCGAL::algorithm::partition_2(g1->as(), SFCGAL::algorithm::optimal_convex); + result = SFCGAL::algorithm::partition_2(g1->as(), + SFCGAL::algorithm::optimal_convex); } catch (std::exception &e) { SFCGAL_WARNING("During optimal_convex_partition_2(A):"); SFCGAL_WARNING(" with A: %s", diff --git a/src/capi/sfcgal_c.h b/src/capi/sfcgal_c.h index 3334055b..27319156 100644 --- a/src/capi/sfcgal_c.h +++ b/src/capi/sfcgal_c.h @@ -57,7 +57,7 @@ typedef enum { // TYPE_SURFACE = 14, //abstract SFCGAL_TYPE_POLYHEDRALSURFACE = 15, SFCGAL_TYPE_TRIANGULATEDSURFACE = 16, - SFCGAL_TYPE_TRIANGLE = 17, + SFCGAL_TYPE_TRIANGLE = 17, //-- not official codes SFCGAL_TYPE_SOLID = 101, @@ -989,7 +989,12 @@ sfcgal_geometry_straight_skeleton_distance_in_m(const sfcgal_geometry_t *geom); * @ingroup capi */ SFCGAL_API sfcgal_geometry_t * -sfcgal_geometry_extrude_straight_skeleton(const sfcgal_geometry_t *geom, double height); +sfcgal_geometry_extrude_straight_skeleton(const sfcgal_geometry_t *geom, + double height); +SFCGAL_API sfcgal_geometry_t * +sfcgal_geometry_extrude_polygon_straight_skeleton(const sfcgal_geometry_t *geom, + double building_height, + double roof_height); /** * Returns the approximate medial axis for the given Polygon @@ -1075,7 +1080,8 @@ SFCGAL_API sfcgal_geometry_t * sfcgal_approx_convex_partition_2(const sfcgal_geometry_t *geom); /** - * Returns the greene approximal convex partition of a geometry (polygon without hole) + * Returns the greene approximal convex partition of a geometry (polygon without + * hole) * @pre isValid(geom) == true * @post isValid(return) == true * @ingroup capi diff --git a/test/unit/SFCGAL/algorithm/StraightSkeletonTest.cpp b/test/unit/SFCGAL/algorithm/StraightSkeletonTest.cpp index 1c20abd1..db2515d8 100644 --- a/test/unit/SFCGAL/algorithm/StraightSkeletonTest.cpp +++ b/test/unit/SFCGAL/algorithm/StraightSkeletonTest.cpp @@ -351,4 +351,70 @@ BOOST_AUTO_TEST_CASE(testExtrudeStraightSkeletonPolygonWithHole) BOOST_CHECK_EQUAL(out->asText(2), expectedWKT); } +BOOST_AUTO_TEST_CASE(testExtrudeStraightSkeletonGenerateBuilding) +{ + + std::unique_ptr g( + io::readWkt("POLYGON (( 0 0, 5 0, 5 5, 4 5, 4 4, 0 4, 0 0 ), (1 1, 1 2, " + "2 2, 2 1, 1 1))")); + std::unique_ptr out( + algorithm::extrudeStraightSkeleton(*g, 9.0, 2.0)); + std::string expectedWKT( + "POLYHEDRALSURFACE Z(((0.00 0.00 0.00,0.00 4.00 0.00,4.00 4.00 0.00,4.00 " + "5.00 0.00,5.00 5.00 0.00,5.00 0.00 0.00,0.00 0.00 0.00),(1.00 1.00 " + "0.00,2.00 1.00 0.00,2.00 2.00 0.00,1.00 2.00 0.00,1.00 1.00 " + "0.00)),((0.00 0.00 0.00,0.00 0.00 9.00,0.00 4.00 9.00,0.00 4.00 " + "0.00,0.00 0.00 0.00)),((0.00 4.00 0.00,0.00 4.00 9.00,4.00 4.00 " + "9.00,4.00 4.00 0.00,0.00 4.00 0.00)),((4.00 4.00 0.00,4.00 4.00 " + "9.00,4.00 5.00 9.00,4.00 5.00 0.00,4.00 4.00 0.00)),((4.00 5.00 " + "0.00,4.00 5.00 9.00,5.00 5.00 9.00,5.00 5.00 0.00,4.00 5.00 " + "0.00)),((5.00 5.00 0.00,5.00 5.00 9.00,5.00 0.00 9.00,5.00 0.00 " + "0.00,5.00 5.00 0.00)),((5.00 0.00 0.00,5.00 0.00 9.00,0.00 0.00 " + "9.00,0.00 0.00 0.00,5.00 0.00 0.00)),((1.00 1.00 0.00,1.00 1.00 " + "9.00,2.00 1.00 9.00,2.00 1.00 0.00,1.00 1.00 0.00)),((2.00 1.00 " + "0.00,2.00 1.00 9.00,2.00 2.00 9.00,2.00 2.00 0.00,2.00 1.00 " + "0.00)),((2.00 2.00 0.00,2.00 2.00 9.00,1.00 2.00 9.00,1.00 2.00 " + "0.00,2.00 2.00 0.00)),((1.00 2.00 0.00,1.00 2.00 9.00,1.00 1.00 " + "9.00,1.00 1.00 0.00,1.00 2.00 0.00)),((4.00 5.00 9.00,5.00 5.00 " + "9.00,4.00 4.00 9.00,4.00 5.00 9.00)),((2.00 1.00 9.00,5.00 0.00 " + "9.00,0.00 0.00 9.00,2.00 1.00 9.00)),((5.00 5.00 9.00,5.00 0.00 " + "9.00,4.00 4.00 9.00,5.00 5.00 9.00)),((2.00 1.00 9.00,0.00 0.00 " + "9.00,1.00 1.00 9.00,2.00 1.00 9.00)),((1.00 2.00 9.00,1.00 1.00 " + "9.00,0.00 0.00 9.00,1.00 2.00 9.00)),((0.00 4.00 9.00,2.00 2.00 " + "9.00,1.00 2.00 9.00,0.00 4.00 9.00)),((0.00 4.00 9.00,1.00 2.00 " + "9.00,0.00 0.00 9.00,0.00 4.00 9.00)),((4.00 4.00 9.00,5.00 0.00 " + "9.00,2.00 2.00 9.00,4.00 4.00 9.00)),((4.00 4.00 9.00,2.00 2.00 " + "9.00,0.00 4.00 9.00,4.00 4.00 9.00)),((2.00 2.00 9.00,5.00 0.00 " + "9.00,2.00 1.00 9.00,2.00 2.00 9.00)),((0.50 2.50 9.50,0.00 0.00 " + "9.00,0.50 0.50 9.50,0.50 2.50 9.50)),((1.00 3.00 10.00,0.00 4.00 " + "9.00,0.50 2.50 9.50,1.00 3.00 10.00)),((0.50 2.50 9.50,0.00 4.00 " + "9.00,0.00 0.00 9.00,0.50 2.50 9.50)),((2.50 0.50 9.50,5.00 0.00 " + "9.00,3.50 1.50 10.50,2.50 0.50 9.50)),((0.00 0.00 9.00,5.00 0.00 " + "9.00,2.50 0.50 9.50,0.00 0.00 9.00)),((0.50 0.50 9.50,0.00 0.00 " + "9.00,2.50 0.50 9.50,0.50 0.50 9.50)),((4.50 3.50 9.50,5.00 5.00 " + "9.00,4.50 4.50 9.50,4.50 3.50 9.50)),((3.50 2.50 10.50,3.50 1.50 " + "10.50,4.50 3.50 9.50,3.50 2.50 10.50)),((4.50 3.50 9.50,5.00 0.00 " + "9.00,5.00 5.00 9.00,4.50 3.50 9.50)),((3.50 1.50 10.50,5.00 0.00 " + "9.00,4.50 3.50 9.50,3.50 1.50 10.50)),((5.00 5.00 9.00,4.00 5.00 " + "9.00,4.50 4.50 9.50,5.00 5.00 9.00)),((4.50 4.50 9.50,4.00 4.00 " + "9.00,4.50 3.50 9.50,4.50 4.50 9.50)),((4.50 4.50 9.50,4.00 5.00 " + "9.00,4.00 4.00 9.00,4.50 4.50 9.50)),((3.00 3.00 10.00,0.00 4.00 " + "9.00,1.00 3.00 10.00,3.00 3.00 10.00)),((3.50 2.50 10.50,4.50 3.50 " + "9.50,3.00 3.00 10.00,3.50 2.50 10.50)),((3.00 3.00 10.00,4.00 4.00 " + "9.00,0.00 4.00 9.00,3.00 3.00 10.00)),((4.50 3.50 9.50,4.00 4.00 " + "9.00,3.00 3.00 10.00,4.50 3.50 9.50)),((2.00 1.00 9.00,1.00 1.00 " + "9.00,0.50 0.50 9.50,2.00 1.00 9.00)),((2.50 0.50 9.50,2.00 1.00 " + "9.00,0.50 0.50 9.50,2.50 0.50 9.50)),((1.00 1.00 9.00,1.00 2.00 " + "9.00,0.50 2.50 9.50,1.00 1.00 9.00)),((0.50 0.50 9.50,1.00 1.00 " + "9.00,0.50 2.50 9.50,0.50 0.50 9.50)),((1.00 3.00 10.00,2.00 2.00 " + "9.00,3.00 3.00 10.00,1.00 3.00 10.00)),((0.50 2.50 9.50,1.00 2.00 " + "9.00,1.00 3.00 10.00,0.50 2.50 9.50)),((1.00 3.00 10.00,1.00 2.00 " + "9.00,2.00 2.00 9.00,1.00 3.00 10.00)),((2.00 2.00 9.00,2.00 1.00 " + "9.00,2.50 0.50 9.50,2.00 2.00 9.00)),((3.50 2.50 10.50,3.00 3.00 " + "10.00,3.50 1.50 10.50,3.50 2.50 10.50)),((3.50 1.50 10.50,2.00 2.00 " + "9.00,2.50 0.50 9.50,3.50 1.50 10.50)),((3.00 3.00 10.00,2.00 2.00 " + "9.00,3.50 1.50 10.50,3.00 3.00 10.00)))"); + BOOST_CHECK_EQUAL(out->asText(2), expectedWKT); +} + BOOST_AUTO_TEST_SUITE_END()