Skip to content

Commit

Permalink
Node the GeometryCollectionShim and return a GeometryGraphShim
Browse files Browse the repository at this point in the history
  • Loading branch information
Notgnoshi committed Feb 25, 2024
1 parent 55a3715 commit a1d3b3c
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 10 deletions.
4 changes: 4 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ fn main() {
for cpp_header in glob::glob(format!("{allow_dir}/**/*.h").as_str()).unwrap() {
println!("cargo:rerun-if-changed={}", cpp_header.unwrap().display());
}
for cpp_header in glob::glob(format!("{allow_dir}/**/*.hpp").as_str()).unwrap() {
println!("cargo:rerun-if-changed={}", cpp_header.unwrap().display());
}
}

let out_dir = std::env::var("OUT_DIR").unwrap();
Expand Down Expand Up @@ -85,6 +88,7 @@ fn main() {
let cxxbridge_sources = [
"generative/cxxbridge/coord_ffi.rs",
"generative/cxxbridge/geometry_collection_ffi.rs",
"generative/cxxbridge/geometry_graph_ffi.rs",
"generative/cxxbridge/noder_ffi.rs",
];
cxx_build::bridges(cxxbridge_sources)
Expand Down
7 changes: 7 additions & 0 deletions generative/cxxbridge/coord_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ pub mod ffi {
vec: Vec<LineStringShim>,
}
impl Vec<PolygonShim> {}

#[derive(Debug, Clone, Copy, PartialEq)]
struct GraphEdge {
src: usize,
dst: usize,
}
impl Vec<GraphEdge> {}
}

impl From<geo::Coord> for ffi::CoordShim {
Expand Down
3 changes: 2 additions & 1 deletion generative/cxxbridge/geometry_collection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ get_geos_geoms_from_rust(const GeometryCollectionShim& rust_geoms,
for (const auto& point : points)
{
const auto coord = geos::geom::CoordinateXY{point.x, point.y};
factory->createPoint(coord);
auto geos_point = factory->createPoint(coord);
geos_geoms.push_back(std::move(geos_point));
}

const auto linestrings = rust_geoms.get_linestrings();
Expand Down
48 changes: 48 additions & 0 deletions generative/cxxbridge/geometry_graph.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once
#include "generative/generative/cxxbridge/coord_ffi.rs.h"
#include <generative/noding/geometry-graph.h>

#include <rust/cxx.h>

#include <vector>

class GeometryGraphShim
{
public:
explicit GeometryGraphShim(generative::noding::GeometryGraph&& graph) :
m_inner(std::move(graph))
{
}

[[nodiscard]] rust::Vec<CoordShim> nodes() const noexcept
{
const auto& cxx_nodes = m_inner.get_nodes();
rust::Vec<CoordShim> rust_nodes;
rust_nodes.reserve(cxx_nodes.size());

for (const auto& node : cxx_nodes)
{
auto rust_node = CoordShim{node.coord().x, node.coord().y};
rust_nodes.emplace_back(rust_node);
}

return rust_nodes;
}

[[nodiscard]] rust::Vec<GraphEdge> edges() const noexcept
{
const auto& cxx_edges = m_inner.get_edge_pairs();
rust::Vec<GraphEdge> rust_edges;
rust_edges.reserve(cxx_edges.size());
for (const auto& edge : cxx_edges)
{
auto rust_edge = GraphEdge{edge.first.index, edge.second.index};
rust_edges.emplace_back(rust_edge);
}

return rust_edges;
}

private:
generative::noding::GeometryGraph m_inner;
};
15 changes: 15 additions & 0 deletions generative/cxxbridge/geometry_graph_ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#[cxx::bridge]
pub mod ffi {
unsafe extern "C++" {
include!("geometry_graph.hpp");

type GeometryGraphShim;
type CoordShim = crate::cxxbridge::CoordShim;
type GraphEdge = crate::cxxbridge::GraphEdge;

fn nodes(self: &GeometryGraphShim) -> Vec<CoordShim>;
fn edges(self: &GeometryGraphShim) -> Vec<GraphEdge>;
}

impl UniquePtr<GeometryGraphShim> {}
}
5 changes: 4 additions & 1 deletion generative/cxxbridge/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
mod coord_ffi;
mod geometry_collection;
mod geometry_collection_ffi;
mod geometry_graph_ffi;
mod noder_ffi;

pub use coord_ffi::ffi::{CoordShim, LineStringShim, PolygonShim};
pub use coord_ffi::ffi::{CoordShim, GraphEdge, LineStringShim, PolygonShim};
pub use geometry_collection::GeometryCollectionShim;
pub use geometry_graph_ffi::ffi::GeometryGraphShim;
pub use noder_ffi::ffi::node;
28 changes: 26 additions & 2 deletions generative/cxxbridge/noder.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
#pragma once
#include "generative/generative/cxxbridge/geometry_collection_ffi.rs.h"
#include "generative/generative/cxxbridge/geometry_graph_ffi.rs.h"
#include "geometry_collection.hpp"
#include <generative/noding/geometry-graph.h>
#include <generative/noding/geometry-noder.h>

inline void _compile_tester(const GeometryCollectionShim& rust_geoms) noexcept
#include <geos/noding/snap/SnappingNoder.h>

#include <memory>

[[nodiscard]] inline std::unique_ptr<GeometryGraphShim>
node(const GeometryCollectionShim& rust_geoms, double tolerance) noexcept
{
const auto geos_geoms = copy_rust_collection_to_geos(rust_geoms);
std::cerr << "Noding: " << geos_geoms->toString() << std::endl;

auto noded = std::unique_ptr<geos::geom::Geometry>(nullptr);
if (tolerance == 0.0)
{
noded = generative::noding::GeometryNoder::node(*geos_geoms, nullptr);
} else
{
auto noder = std::make_unique<geos::noding::snap::SnappingNoder>(tolerance);
noded = generative::noding::GeometryNoder::node(*geos_geoms, std::move(noder));
}
std::cerr << "Noded: " << noded->toString() << std::endl;
auto graph = generative::noding::GeometryGraph(*noded);

auto graph_shim = std::make_unique<GeometryGraphShim>(std::move(graph));

return graph_shim;
}
65 changes: 59 additions & 6 deletions generative/cxxbridge/noder_ffi.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,75 @@
#[cxx::bridge]
mod ffi {
pub mod ffi {
unsafe extern "C++" {
include!("noder.hpp");

type GeometryCollectionShim = crate::cxxbridge::GeometryCollectionShim;
type GeometryGraphShim = crate::cxxbridge::GeometryGraphShim;

fn _compile_tester(geoms: &GeometryCollectionShim);
/// Node the given collection of geometries
///
/// # Safety
///
/// The noding is done by either a geos SnappingNoder or IteratedNoder, both of which have
/// some gotchas.
///
/// * The IteratedNoder can throw topology exceptions if it doesn't converge by MAX_ITERS
/// * The SnappingNoder doesn't handle isolated POINTs
unsafe fn node(
geoms: &GeometryCollectionShim,
tolerance: f64,
) -> UniquePtr<GeometryGraphShim>;
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::cxxbridge::{CoordShim, GraphEdge};

#[test]
fn test_compile_tester() {
let collection = geo::GeometryCollection::default();
let collection = crate::cxxbridge::GeometryCollectionShim(collection);
ffi::_compile_tester(&collection);
fn test_noder_doesnt_crash() {
let empty = crate::cxxbridge::GeometryCollectionShim::new(Vec::new());
let tolerance = 0.001;
let graph = unsafe { ffi::node(&empty, tolerance) };

assert!(!graph.is_null());
}

#[test]
fn test_noder_isolated_points() {
let geoms = [geo::Point::new(0.0, 0.0), geo::Point::new(0.0, 1.0)];
let geoms: Vec<_> = geoms.into_iter().map(geo::Geometry::Point).collect();
let geoms = crate::cxxbridge::GeometryCollectionShim::new(geoms);

let tolerance = 0.0;
let graph = unsafe { ffi::node(&geoms, tolerance) };
assert!(!graph.is_null());

let nodes = graph.nodes();
let expected = [CoordShim { x: 0.0, y: 0.0 }, CoordShim { x: 0.0, y: 1.0 }];
assert_eq!(nodes, expected);

let edges = graph.edges();
assert!(edges.is_empty());
}

#[test]
fn test_noder_linestring() {
let line: geo::LineString = vec![(0.0, 0.0), (0.00001, 0.0), (2.0, 0.0)].into();
let geoms = vec![geo::Geometry::LineString(line)];
let geoms = crate::cxxbridge::GeometryCollectionShim::new(geoms);

let tolerance = 0.0001;
let graph = unsafe { ffi::node(&geoms, tolerance) };
assert!(!graph.is_null());

let nodes = graph.nodes();
let expected = [CoordShim { x: 0.0, y: 0.0 }, CoordShim { x: 2.0, y: 0.0 }];
assert_eq!(nodes, expected);

let edges = graph.edges();
let expected = [GraphEdge { src: 0, dst: 1 }];
assert_eq!(edges, expected);
}
}
30 changes: 30 additions & 0 deletions tests/geometry-noder-tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,36 @@

using generative::io::from_wkt;

TEST(GeometryNoderTests, TwoPoints)
{
const std::unique_ptr<geos::geom::Geometry> geometries = from_wkt(
// clang-format off
"GEOMETRYCOLLECTION("
"POINT(1 1),"
"POINT(0 1)"
")"
// clang-format on
);
ASSERT_TRUE(geometries);
const std::unique_ptr<geos::geom::Geometry> expected = from_wkt(
// clang-format off
"GEOMETRYCOLLECTION("
"POINT(1 1),"
"POINT(0 1)"
")"
// clang-format on
);
ASSERT_TRUE(expected);

const std::unique_ptr<geos::geom::Geometry> noded =
generative::noding::GeometryNoder::node(*geometries);
ASSERT_TRUE(noded);
std::cerr << noded->toString() << std::endl;

EXPECT_EQ(noded->getGeometryType(), expected->getGeometryType());
EXPECT_TRUE(noded->equals(expected.get()));
}

TEST(GeometryNoderTests, DisjointPoint)
{
const std::unique_ptr<geos::geom::Geometry> geometries = from_wkt(
Expand Down

0 comments on commit a1d3b3c

Please sign in to comment.