mod container;
pub(in crate) mod geometry;
mod mutation;
mod payload;
mod storage;
mod view;
pub use self::payload::{ArcPayload, EdgePayload, FacePayload, VertexPayload};
pub use self::storage::{ArcKey, EdgeKey, FaceKey, VertexKey};
pub use self::view::{
ArcNeighborhood, ArcView, EdgeView, FaceNeighborhood, FaceView, InteriorPathView,
OrphanArcView, OrphanEdgeView, OrphanFaceView, OrphanVertexView, VertexView,
};
use arrayvec::ArrayVec;
use decorum::R64;
use itertools::{Itertools, MinMaxResult};
use num::{Integer, NumCast, ToPrimitive, Unsigned};
use smallvec::SmallVec;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::FromIterator;
use typenum::{self, NonZero};
use crate::buffer::{BufferError, Flat, IndexBuffer, MeshBuffer};
use crate::geometry::convert::{FromGeometry, FromInteriorGeometry, IntoGeometry};
use crate::geometry::{Geometry, Triplet};
use crate::graph::container::alias::OwnedCore;
use crate::graph::container::{Bind, Consistent, Core};
use crate::graph::mutation::{Mutate, Mutation};
use crate::graph::storage::alias::*;
use crate::graph::storage::convert::alias::*;
use crate::graph::storage::convert::{AsStorage, AsStorageMut};
use crate::graph::storage::{OpaqueKey, Storage};
use crate::graph::view::convert::IntoView;
use crate::primitive::decompose::IntoVertices;
use crate::primitive::index::{FromIndexer, HashIndexer, IndexVertices, Indexer};
use crate::primitive::{self, Arity, Map, Polygonal, Quad};
use crate::{FromRawBuffers, FromRawBuffersWithArity};
pub use Selector::ByIndex;
pub use Selector::ByKey;
#[derive(Debug, Fail, PartialEq)]
pub enum GraphError {
#[fail(display = "required topology not found")]
TopologyNotFound,
#[fail(display = "conflicting topology found")]
TopologyConflict,
#[fail(display = "topology malformed")]
TopologyMalformed,
#[fail(
display = "conflicting arity; expected {}, but got {}",
expected, actual
)]
ArityConflict { expected: usize, actual: usize },
#[fail(display = "arity is non-constant")]
ArityNonConstant,
}
impl From<BufferError> for GraphError {
fn from(_: BufferError) -> Self {
GraphError::TopologyMalformed
}
}
trait OptionExt<T> {
fn expect_consistent(self) -> T;
}
impl<T> OptionExt<T> for Option<T> {
fn expect_consistent(self) -> T {
self.expect("internal error: graph consistency violated")
}
}
trait ResultExt<T, E> {
fn expect_consistent(self) -> T
where
E: Debug;
}
impl<T, E> ResultExt<T, E> for Result<T, E> {
fn expect_consistent(self) -> T
where
E: Debug,
{
self.expect("internal error: graph consistency violated")
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Selector<K> {
ByKey(K),
ByIndex(usize),
}
impl<K> Selector<K> {
pub fn key_or_else<E, F>(self, f: F) -> Result<K, GraphError>
where
E: Into<GraphError>,
F: Fn(usize) -> Result<K, E>,
{
match self {
Selector::ByKey(key) => Ok(key),
Selector::ByIndex(index) => f(index).map_err(|error| error.into()),
}
}
pub fn index_or_else<E, F>(self, f: F) -> Result<usize, GraphError>
where
E: Into<GraphError>,
F: Fn(K) -> Result<usize, E>,
{
match self {
Selector::ByKey(key) => f(key).map_err(|error| error.into()),
Selector::ByIndex(index) => Ok(index),
}
}
}
impl<K> From<K> for Selector<K>
where
K: OpaqueKey,
{
fn from(key: K) -> Self {
Selector::ByKey(key)
}
}
impl<K> From<usize> for Selector<K> {
fn from(index: usize) -> Self {
Selector::ByIndex(index)
}
}
pub enum GraphArity {
Constant(usize),
NonConstant(usize, usize),
}
pub struct MeshGraph<G = Triplet<R64>>
where
G: Geometry,
{
core: OwnedCore<G>,
}
impl<G> MeshGraph<G>
where
G: Geometry,
{
pub fn new() -> Self {
MeshGraph::from(
Core::empty()
.bind(VertexStorage::<G>::new())
.bind(ArcStorage::<G>::new())
.bind(EdgeStorage::<G>::new())
.bind(FaceStorage::<G>::new()),
)
}
pub fn empty() -> Self {
MeshGraph::from(
Core::empty()
.bind(VertexStorage::<G>::empty())
.bind(ArcStorage::<G>::empty())
.bind(EdgeStorage::<G>::empty())
.bind(FaceStorage::<G>::empty()),
)
}
pub fn from_mesh_buffer<A, N, H>(buffer: MeshBuffer<Flat<A, N>, H>) -> Result<Self, GraphError>
where
A: NonZero + typenum::Unsigned,
N: Copy + Integer + NumCast + Unsigned,
H: Clone + IntoGeometry<G::Vertex>,
{
let arity = buffer.arity().unwrap();
let (indices, vertices) = buffer.into_raw_buffers();
MeshGraph::from_raw_buffers_with_arity(indices, vertices, arity)
}
pub fn vertex_count(&self) -> usize {
self.as_vertex_storage().len()
}
pub fn vertex(&self, key: VertexKey) -> Option<VertexView<&Self, G>> {
(key, self).into_view()
}
pub fn vertex_mut(&mut self, key: VertexKey) -> Option<VertexView<&mut Self, G>> {
(key, self).into_view()
}
pub fn vertices(&self) -> impl Clone + Iterator<Item = VertexView<&Self, G>> {
self.as_vertex_storage()
.keys()
.map(move |key| (*key, self).into_view().unwrap())
}
pub fn orphan_vertices(&mut self) -> impl Iterator<Item = OrphanVertexView<G>> {
self.as_vertex_storage_mut()
.iter_mut()
.map(|(key, source)| (*key, source).into_view().unwrap())
}
pub fn arc_count(&self) -> usize {
self.as_arc_storage().len()
}
pub fn arc(&self, key: ArcKey) -> Option<ArcView<&Self, G>> {
(key, self).into_view()
}
pub fn arc_mut(&mut self, key: ArcKey) -> Option<ArcView<&mut Self, G>> {
(key, self).into_view()
}
pub fn arcs(&self) -> impl Clone + Iterator<Item = ArcView<&Self, G>> {
self.as_arc_storage()
.keys()
.map(move |key| (*key, self).into_view().unwrap())
}
pub fn orphan_arcs(&mut self) -> impl Iterator<Item = OrphanArcView<G>> {
self.as_arc_storage_mut()
.iter_mut()
.map(|(key, source)| (*key, source).into_view().unwrap())
}
pub fn edge_count(&self) -> usize {
self.as_edge_storage().len()
}
pub fn edge(&self, key: EdgeKey) -> Option<EdgeView<&Self, G>> {
(key, self).into_view()
}
pub fn edge_mut(&mut self, key: EdgeKey) -> Option<EdgeView<&mut Self, G>> {
(key, self).into_view()
}
pub fn edges(&self) -> impl Clone + Iterator<Item = EdgeView<&Self, G>> {
self.as_edge_storage()
.keys()
.map(move |key| (*key, self).into_view().unwrap())
}
pub fn orphan_edges(&mut self) -> impl Iterator<Item = OrphanEdgeView<G>> {
self.as_edge_storage_mut()
.iter_mut()
.map(|(key, source)| (*key, source).into_view().unwrap())
}
pub fn face_count(&self) -> usize {
self.as_face_storage().len()
}
pub fn face(&self, key: FaceKey) -> Option<FaceView<&Self, G>> {
(key, self).into_view()
}
pub fn face_mut(&mut self, key: FaceKey) -> Option<FaceView<&mut Self, G>> {
(key, self).into_view()
}
pub fn faces(&self) -> impl Clone + Iterator<Item = FaceView<&Self, G>> {
self.as_face_storage()
.keys()
.map(move |key| (*key, self).into_view().unwrap())
}
pub fn orphan_faces(&mut self) -> impl Iterator<Item = OrphanFaceView<G>> {
self.as_face_storage_mut()
.iter_mut()
.map(|(key, source)| (*key, source).into_view().unwrap())
}
pub fn arity(&self) -> GraphArity {
match self.faces().map(|face| face.arity()).minmax() {
MinMaxResult::OneElement(arity) => GraphArity::Constant(arity),
MinMaxResult::MinMax(min, max) => GraphArity::NonConstant(min, max),
_ => GraphArity::Constant(0),
}
}
pub fn triangulate(&mut self) {
let faces = self.as_face_storage().keys().cloned().collect::<Vec<_>>();
for face in faces {
self.face_mut(face).unwrap().triangulate();
}
}
pub fn to_mesh_buffer_by_vertex<A, N, H>(&self) -> Result<MeshBuffer<Flat<A, N>, H>, GraphError>
where
G::Vertex: IntoGeometry<H>,
A: NonZero + typenum::Unsigned,
N: Copy + Integer + NumCast + Unsigned,
{
self.to_mesh_buffer_by_vertex_with(|vertex| vertex.geometry.clone().into_geometry())
}
pub fn to_mesh_buffer_by_vertex_with<A, N, H, F>(
&self,
mut f: F,
) -> Result<MeshBuffer<Flat<A, N>, H>, GraphError>
where
A: NonZero + typenum::Unsigned,
N: Copy + Integer + NumCast + Unsigned,
F: FnMut(VertexView<&Self, G>) -> H,
{
let (keys, vertices) = {
let mut keys = HashMap::with_capacity(self.vertex_count());
let mut vertices = Vec::with_capacity(self.vertex_count());
for (n, vertex) in self.vertices().enumerate() {
keys.insert(vertex.key(), n);
vertices.push(f(vertex));
}
(keys, vertices)
};
let indices = {
let arity = Flat::<A, N>::ARITY.unwrap();
let mut indices = Vec::with_capacity(arity * self.face_count());
for face in self.faces() {
if face.arity() != arity {
return Err(GraphError::ArityConflict {
expected: arity,
actual: face.arity(),
});
}
for vertex in face.vertices() {
indices.push(N::from(keys[&vertex.key()]).unwrap());
}
}
indices
};
MeshBuffer::<Flat<_, _>, _>::from_raw_buffers(indices, vertices)
.map_err(|error| error.into())
}
pub fn to_mesh_buffer_by_face<A, N, H>(&self) -> Result<MeshBuffer<Flat<A, N>, H>, GraphError>
where
G::Vertex: IntoGeometry<H>,
A: NonZero + typenum::Unsigned,
N: Copy + Integer + NumCast + Unsigned,
{
self.to_mesh_buffer_by_face_with(|_, vertex| vertex.geometry.clone().into_geometry())
}
pub fn to_mesh_buffer_by_face_with<A, N, H, F>(
&self,
mut f: F,
) -> Result<MeshBuffer<Flat<A, N>, H>, GraphError>
where
A: NonZero + typenum::Unsigned,
N: Copy + Integer + NumCast + Unsigned,
F: FnMut(FaceView<&Self, G>, VertexView<&Self, G>) -> H,
{
let vertices = {
let arity = Flat::<A, N>::ARITY.unwrap();
let mut vertices = Vec::with_capacity(arity * self.face_count());
for face in self.faces() {
if face.arity() != arity {
return Err(GraphError::ArityConflict {
expected: arity,
actual: face.arity(),
});
}
for vertex in face.vertices() {
vertices.push(f(face, vertex));
}
}
vertices
};
MeshBuffer::<Flat<_, _>, _>::from_raw_buffers(
(0..vertices.len()).map(|index| N::from(index).unwrap()),
vertices,
)
.map_err(|error| error.into())
}
}
impl<G> AsStorage<VertexPayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage(&self) -> &Storage<VertexPayload<G>> {
self.core.as_vertex_storage()
}
}
impl<G> AsStorage<ArcPayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage(&self) -> &Storage<ArcPayload<G>> {
self.core.as_arc_storage()
}
}
impl<G> AsStorage<EdgePayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage(&self) -> &Storage<EdgePayload<G>> {
self.core.as_edge_storage()
}
}
impl<G> AsStorage<FacePayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage(&self) -> &Storage<FacePayload<G>> {
self.core.as_face_storage()
}
}
impl<G> AsStorageMut<VertexPayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage_mut(&mut self) -> &mut Storage<VertexPayload<G>> {
self.core.as_vertex_storage_mut()
}
}
impl<G> AsStorageMut<ArcPayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage_mut(&mut self) -> &mut Storage<ArcPayload<G>> {
self.core.as_arc_storage_mut()
}
}
impl<G> AsStorageMut<EdgePayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage_mut(&mut self) -> &mut Storage<EdgePayload<G>> {
self.core.as_edge_storage_mut()
}
}
impl<G> AsStorageMut<FacePayload<G>> for MeshGraph<G>
where
G: Geometry,
{
fn as_storage_mut(&mut self) -> &mut Storage<FacePayload<G>> {
self.core.as_face_storage_mut()
}
}
impl<G> Consistent for MeshGraph<G> where G: Geometry {}
impl<G> Default for MeshGraph<G>
where
G: Geometry,
{
fn default() -> Self {
MeshGraph::empty()
}
}
impl<A, N, H, G> From<MeshBuffer<Flat<A, N>, H>> for MeshGraph<G>
where
A: NonZero + typenum::Unsigned,
N: Copy + Integer + NumCast + Unsigned,
H: Clone + IntoGeometry<G::Vertex>,
G: Geometry,
{
fn from(buffer: MeshBuffer<Flat<A, N>, H>) -> Self {
MeshGraph::from_mesh_buffer(buffer).unwrap_or_else(|_| Self::default())
}
}
impl<G> From<OwnedCore<G>> for MeshGraph<G>
where
G: Geometry,
{
fn from(core: OwnedCore<G>) -> Self {
MeshGraph { core }
}
}
impl<G, H> FromInteriorGeometry<MeshGraph<H>> for MeshGraph<G>
where
G: Geometry,
G::Vertex: FromGeometry<H::Vertex>,
G::Arc: FromGeometry<H::Arc>,
G::Edge: FromGeometry<H::Edge>,
G::Face: FromGeometry<H::Face>,
H: Geometry,
{
fn from_interior_geometry(graph: MeshGraph<H>) -> Self {
let MeshGraph { core, .. } = graph;
let (vertices, arcs, edges, faces) = core.into_storage();
let core = Core::empty()
.bind(
vertices
.map_values_into(|vertex| VertexPayload::<G>::from_interior_geometry(vertex)),
)
.bind(arcs.map_values_into(|arc| ArcPayload::<G>::from_interior_geometry(arc)))
.bind(edges.map_values_into(|edge| EdgePayload::<G>::from_interior_geometry(edge)))
.bind(faces.map_values_into(|face| FacePayload::<G>::from_interior_geometry(face)));
MeshGraph::from(core)
}
}
impl<G, P> FromIndexer<P, P> for MeshGraph<G>
where
G: Geometry,
P: Map<usize> + primitive::Topological,
P::Output: IntoVertices,
P::Vertex: IntoGeometry<G::Vertex>,
{
type Error = GraphError;
fn from_indexer<I, N>(input: I, indexer: N) -> Result<Self, Self::Error>
where
I: IntoIterator<Item = P>,
N: Indexer<P, P::Vertex>,
{
let mut mutation = Mutation::mutate(MeshGraph::new());
let (indices, vertices) = input.into_iter().index_vertices(indexer);
let vertices = vertices
.into_iter()
.map(|vertex| mutation.insert_vertex(vertex.into_geometry()))
.collect::<Vec<_>>();
for face in indices {
let perimeter = face
.into_vertices()
.into_iter()
.map(|index| vertices[index])
.collect::<ArrayVec<[_; Quad::<usize>::ARITY]>>();
mutation.insert_face(&perimeter, Default::default())?;
}
mutation.commit()
}
}
impl<G, P> FromIterator<P> for MeshGraph<G>
where
G: Geometry,
P: Map<usize> + primitive::Topological,
P::Output: IntoVertices,
P::Vertex: Clone + Eq + Hash + IntoGeometry<G::Vertex>,
{
fn from_iter<I>(input: I) -> Self
where
I: IntoIterator<Item = P>,
{
Self::from_indexer(input, HashIndexer::default()).unwrap_or_else(|_| Self::default())
}
}
impl<P, G, H> FromRawBuffers<P, H> for MeshGraph<G>
where
P: IntoVertices + Polygonal,
P::Vertex: Integer + ToPrimitive + Unsigned,
G: Geometry,
H: IntoGeometry<G::Vertex>,
{
type Error = GraphError;
fn from_raw_buffers<I, J>(indices: I, vertices: J) -> Result<Self, Self::Error>
where
I: IntoIterator<Item = P>,
J: IntoIterator<Item = H>,
{
let mut mutation = Mutation::mutate(MeshGraph::new());
let vertices = vertices
.into_iter()
.map(|vertex| mutation.insert_vertex(vertex.into_geometry()))
.collect::<Vec<_>>();
for face in indices {
let mut perimeter = SmallVec::<[_; 4]>::with_capacity(face.arity());
for index in face.into_vertices() {
let index = <usize as NumCast>::from(index).unwrap();
perimeter.push(
*vertices
.get(index)
.ok_or_else(|| GraphError::TopologyNotFound)?,
);
}
mutation.insert_face(&perimeter, Default::default())?;
}
mutation.commit()
}
}
impl<N, G, H> FromRawBuffersWithArity<N, H> for MeshGraph<G>
where
N: Integer + ToPrimitive + Unsigned,
G: Geometry,
H: IntoGeometry<G::Vertex>,
{
type Error = GraphError;
fn from_raw_buffers_with_arity<I, J>(
indices: I,
vertices: J,
arity: usize,
) -> Result<Self, Self::Error>
where
I: IntoIterator<Item = N>,
J: IntoIterator<Item = H>,
{
let mut mutation = Mutation::mutate(MeshGraph::new());
let vertices = vertices
.into_iter()
.map(|vertex| mutation.insert_vertex(vertex.into_geometry()))
.collect::<Vec<_>>();
for face in &indices
.into_iter()
.map(|index| <usize as NumCast>::from(index).unwrap())
.chunks(arity)
{
let face = face.collect::<Vec<_>>();
if face.len() != arity {
return Err(GraphError::ArityConflict {
expected: arity,
actual: face.len(),
});
}
let mut perimeter = SmallVec::<[_; 4]>::with_capacity(arity);
for index in face {
perimeter.push(
*vertices
.get(index)
.ok_or_else(|| GraphError::TopologyNotFound)?,
);
}
mutation.insert_face(&perimeter, Default::default())?;
}
mutation.commit()
}
}
impl<G> Into<OwnedCore<G>> for MeshGraph<G>
where
G: Geometry,
{
fn into(self) -> OwnedCore<G> {
let MeshGraph { core, .. } = self;
core
}
}
#[cfg(test)]
mod tests {
use nalgebra::{Point3, Vector3};
use num::Zero;
use crate::buffer::U3;
use crate::geometry::*;
use crate::graph::*;
use crate::primitive::decompose::*;
use crate::primitive::generate::*;
use crate::primitive::sphere::UvSphere;
use crate::*;
#[test]
fn collect_topology_into_mesh() {
let graph = UvSphere::new(3, 2)
.polygons_with_position() .collect::<MeshGraph<Point3<f32>>>();
assert_eq!(5, graph.vertex_count());
assert_eq!(18, graph.arc_count());
assert_eq!(6, graph.face_count());
}
#[test]
fn iterate_mesh_topology() {
let mut graph = UvSphere::new(4, 2)
.polygons_with_position() .collect::<MeshGraph<Point3<f32>>>();
assert_eq!(6, graph.vertices().count());
assert_eq!(24, graph.arcs().count());
assert_eq!(8, graph.faces().count());
for vertex in graph.vertices() {
assert_eq!(4, vertex.incoming_arcs().count());
}
for mut vertex in graph.orphan_vertices() {
vertex.geometry += Vector3::zero();
}
}
#[test]
fn non_manifold_error_deferred() {
let graph = UvSphere::new(32, 32)
.polygons_with_position()
.triangulate()
.collect::<MeshGraph<Point3<f32>>>();
graph
.to_mesh_buffer_by_face_with::<U3, usize, _, _>(|_, vertex| vertex.geometry)
.unwrap();
}
#[test]
fn error_on_non_manifold_mesh() {
let graph = MeshGraph::<Point3<i32>>::from_raw_buffers_with_arity(
vec![0u32, 1, 2, 0, 1, 3, 0, 1, 4],
vec![(0, 0, 1), (0, 0, -1), (1, 0, 0), (0, 1, 0), (1, 1, 0)],
3,
);
assert_eq!(graph.err().unwrap(), GraphError::TopologyConflict);
}
#[test]
fn read_write_geometry_ref() {
struct ValueGeometry;
impl Geometry for ValueGeometry {
type Vertex = Point3<f32>;
type Arc = ();
type Edge = ();
type Face = f32;
}
let mut graph = UvSphere::new(4, 4)
.polygons_with_position()
.collect::<MeshGraph<ValueGeometry>>();
let value = 3.14;
for mut face in graph.orphan_faces() {
face.geometry = value;
}
for face in graph.faces() {
assert_eq!(value, face.geometry);
}
}
}