Skip to content

Commit

Permalink
Create C++ GeometryGraph from a Rust GeometryGraph
Browse files Browse the repository at this point in the history
  • Loading branch information
Notgnoshi committed Feb 25, 2024
1 parent 39a56c2 commit 2f06dcc
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 33 deletions.
25 changes: 25 additions & 0 deletions generative/cxxbridge/geometry_graph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include "generative/generative/cxxbridge/coord_ffi.rs.h"
#include <generative/noding/geometry-graph.h>

#include <geos/geom/Coordinate.h>
#include <geos/geom/GeometryFactory.h>
#include <rust/cxx.h>

#include <vector>
Expand Down Expand Up @@ -46,3 +48,26 @@ class GeometryGraphShim
private:
generative::noding::GeometryGraph m_inner;
};

[[nodiscard]] std::unique_ptr<GeometryGraphShim>
from_nodes_edges(rust::Slice<const CoordShim> nodes, rust::Slice<const GraphEdge> edges) noexcept
{
auto factory = geos::geom::GeometryFactory::create();
auto graph = generative::noding::GeometryGraph(*factory);

for (const auto& node : nodes)
{
const auto coord = geos::geom::CoordinateXY{node.x, node.y};
// Ignore the created node's index, because we're creating them in the order of the nodes
// slice, which the edges slice requires in order to be valid.
const auto index = graph.add_node(coord);
(void)index;
}

for (const auto& edge : edges)
{
graph.add_edge(edge.src, edge.dst);
}

return std::make_unique<GeometryGraphShim>(std::move(graph));
}
5 changes: 5 additions & 0 deletions generative/cxxbridge/geometry_graph_ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ pub mod ffi {

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

fn from_nodes_edges(
nodes: &[CoordShim],
edges: &[GraphEdge],
) -> UniquePtr<GeometryGraphShim>;
}

impl UniquePtr<GeometryGraphShim> {}
Expand Down
23 changes: 22 additions & 1 deletion generative/cxxbridge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,26 @@ mod noder_ffi;

pub use coord_ffi::ffi::{CoordShim, GraphEdge, LineStringShim, PolygonShim};
pub use geometry_collection::GeometryCollectionShim;
pub use geometry_graph_ffi::ffi::GeometryGraphShim;
pub use geometry_graph_ffi::ffi::{from_nodes_edges, GeometryGraphShim};
pub use noder_ffi::ffi::node;

pub fn to_ffi_graph<Direction: petgraph::EdgeType>(
graph: &crate::graph::GeometryGraph<Direction>,
) -> cxx::UniquePtr<GeometryGraphShim> {
let nodes: Vec<_> = graph
.node_weights()
.map(|w| CoordShim { x: w.0.x, y: w.0.y })
.collect();
let mut edges = Vec::with_capacity(graph.edge_count());
for i in 0..graph.edge_count() {
let edge = graph
.edge_endpoints(petgraph::graph::EdgeIndex::new(i))
.unwrap();
edges.push(GraphEdge {
src: edge.0.index(),
dst: edge.1.index(),
});
}

from_nodes_edges(&nodes, &edges)
}
51 changes: 24 additions & 27 deletions generative/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,32 @@ pub type GeometryGraph<Direction = petgraph::Undirected> =
petgraph::Graph<NodeData, EdgeWeight, Direction, NodeIndex>;

#[cfg(feature = "cxx-bindings")]
mod wrapper {
use super::*;
use crate::cxxbridge::{GeometryGraphShim, GraphEdge};
impl<Direction: petgraph::EdgeType> From<&crate::cxxbridge::GeometryGraphShim>
for GeometryGraph<Direction>
{
fn from(ffi_graph: &crate::cxxbridge::GeometryGraphShim) -> GeometryGraph<Direction> {
let nodes = ffi_graph.nodes();
// The edges are indices into the nodes array.
let edges = ffi_graph.edges();

impl<Direction: petgraph::EdgeType> From<&GeometryGraphShim> for GeometryGraph<Direction> {
fn from(ffi_graph: &GeometryGraphShim) -> GeometryGraph<Direction> {
let nodes = ffi_graph.nodes();
// The edges are indices into the nodes array.
let edges = ffi_graph.edges();
let mut graph = GeometryGraph::default();
graph.reserve_exact_nodes(nodes.len());
graph.reserve_exact_edges(edges.len());

let mut graph = GeometryGraph::default();
graph.reserve_exact_nodes(nodes.len());
graph.reserve_exact_edges(edges.len());

for (_cxx_node_index, node) in nodes.iter().enumerate() {
let point = Point::new(node.x, node.y);
// We rely on the implementation detail of petgraph::Graph that when you insert nodes in
// order, the node indices are generated in the same order.
let _node_index = graph.add_node(point);
debug_assert_eq!(_node_index.index(), _cxx_node_index);
}
for edge in &edges {
let GraphEdge { src, dst } = edge;
let src = petgraph::graph::NodeIndex::new(*src);
let dst = petgraph::graph::NodeIndex::new(*dst);
let _edge_index = graph.add_edge(src, dst, ());
}

graph
for (_cxx_node_index, node) in nodes.iter().enumerate() {
let point = Point::new(node.x, node.y);
// We rely on the implementation detail of petgraph::Graph that when you insert nodes in
// order, the node indices are generated in the same order.
let _node_index = graph.add_node(point);
debug_assert_eq!(_node_index.index(), _cxx_node_index);
}
for edge in &edges {
let crate::cxxbridge::GraphEdge { src, dst } = edge;
let src = petgraph::graph::NodeIndex::new(*src);
let dst = petgraph::graph::NodeIndex::new(*dst);
let _edge_index = graph.add_edge(src, dst, ());
}

graph
}
}
4 changes: 4 additions & 0 deletions generative/include/generative/noding/geometry-graph.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ class GeometryGraph
//! @note The nodes at the indices @p src and @p dst must exist.
void add_edge(std::size_t src, std::size_t dst);

//! @brief Add the given node to the graph.
//! @returns the index of the created node.
[[nodiscard]] std::size_t add_node(geos::geom::CoordinateXY coord) noexcept;

[[nodiscard]] std::vector<std::pair<const Node&, const Node&>> get_edge_pairs() const;

//! @brief Get the graph edges.
Expand Down
22 changes: 17 additions & 5 deletions generative/noding/geometry-graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "generative/geometry-flattener.h"
#include "generative/io/wkt.h"

#include <geos/geom/Coordinate.h>
#include <geos/geom/CoordinateSequence.h>
#include <geos/geom/Geometry.h>
#include <geos/geom/LineString.h>
Expand All @@ -29,6 +30,18 @@ GeometryGraph::GeometryGraph(std::vector<GeometryGraph::Node>&& nodes,
{
}

std::size_t GeometryGraph::add_node(geos::geom::CoordinateXY coord) noexcept
{
const auto new_index = m_nodes.size();

auto point = m_factory.createPoint(coord);
auto node = GeometryGraph::Node(new_index, std::move(point));

m_nodes.push_back(std::move(node));

return new_index;
}

void GeometryGraph::add_edge(std::size_t src, std::size_t dst)
{
m_nodes[src].adjacencies.emplace(dst);
Expand Down Expand Up @@ -81,12 +94,11 @@ GeometryGraph::find_or_insert(Nodes_t& inserted_coords, const geos::geom::Coordi
// This isn't a coordinate we know about.
if (iter == inserted_coords.end())
{
auto point = std::unique_ptr<geos::geom::Point>(m_factory.createPoint(coord));
GeometryGraph::Node new_node(m_nodes.size(), std::move(point));
LOG4CPLUS_TRACE(s_logger, "Adding new node " << new_node.index << "\t" << new_node.point);
auto result = inserted_coords.emplace(coord, new_node.index);
const auto new_index = this->add_node(coord);
LOG4CPLUS_TRACE(s_logger,
"Adding new node " << new_index << "\t" << m_nodes[new_index].point);
auto result = inserted_coords.emplace(coord, new_index);
iter = result.first;
m_nodes.push_back(std::move(new_node));
}

return m_nodes.at(iter->second);
Expand Down
4 changes: 4 additions & 0 deletions generative/noding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ where
(&*ffi_graph).into()
}

pub fn polygonize<Direction: petgraph::EdgeType>(graph: &GeometryGraph<Direction>) {
let ffi_graph = cxxbridge::to_ffi_graph(graph);
}

#[cfg(test)]
mod tests {
use geo::Point;
Expand Down

0 comments on commit 2f06dcc

Please sign in to comment.