Skip to content

Instantly share code, notes, and snippets.

@nyurik
Last active February 21, 2022 22:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nyurik/cc47c629ead68a46ae1072149f060495 to your computer and use it in GitHub Desktop.
Save nyurik/cc47c629ead68a46ae1072149f060495 to your computer and use it in GitHub Desktop.
Multidimensional Geo-types with separate Metadata
use num_traits::{Float, Num, NumCast};
use std::fmt::Debug;
trait CoordinateType: Default + Num + Copy + NumCast + PartialOrd + Debug {}
impl<T: Default + Num + Copy + NumCast + PartialOrd + Debug> CoordinateType for T {}
trait CoordNum: CoordinateType {}
impl<T: CoordinateType + Debug> CoordNum for T {}
trait CoordFloat: CoordNum + Float {}
impl<T: CoordNum + Float> CoordFloat for T {}
trait Metadata: Default + Copy + PartialEq + Debug {}
impl<M: Default + Copy + PartialEq + Debug> Metadata for M {}
#[derive(Clone, Copy, Debug)]
struct Coordinate<T: CoordNum, M: Metadata, const D: usize> {
coord: [T; D],
meta: M,
}
impl<T: CoordNum, M: Metadata, const D: usize> Coordinate<T, M, D> {
pub fn new(coord: [T; D], meta: M) -> Self {
Self { coord, meta }
}
}
impl<T: CoordNum, M: Metadata> Coordinate<T, M, 2> {
pub fn get_x(&self) -> T {
self.coord[0]
}
pub fn get_y(&self) -> T {
self.coord[1]
}
}
impl<T: CoordNum, M: Metadata> Coordinate<T, M, 3> {
pub fn get_x(&self) -> T {
self.coord[0]
}
pub fn get_y(&self) -> T {
self.coord[1]
}
pub fn get_z(&self) -> T {
self.coord[2]
}
}
impl<T: CoordNum, M: Metadata, const D: usize> Coordinate<T, M, D> {
pub fn get_metadata(&self) -> M {
self.meta
}
}
impl<T: CoordNum, M: Metadata, const D: usize> Default for Coordinate<T, M, D> {
fn default() -> Self {
Self {
coord: [T::default(); D],
meta: M::default(),
}
}
}
#[derive(Clone, Copy, Debug)]
struct SizedMultipoint<T: CoordNum, M: Metadata, const D: usize, const P: usize> {
coords: [Coordinate<T, M, D>; P],
}
impl<T: CoordNum, M: Metadata, const D: usize, const P: usize> Default
for SizedMultipoint<T, M, D, P>
{
fn default() -> Self {
Self {
coords: [Coordinate::<T, M, D>::default(); P],
}
}
}
#[derive(Default, Clone, Debug)]
struct Multipoint<T: CoordNum, M: Metadata, const D: usize> {
coords: Vec<Coordinate<T, M, D>>,
}
type Point<T, M, const D: usize> = SizedMultipoint<T, M, D, 1>;
type Point2D<T> = Point<T, (), 2>;
type Point2DM<T, M> = Point<T, M, 2>;
type Point3D<T> = Point<T, (), 3>;
type Point3DM<T, M> = Point<T, M, 3>;
type Line<T, M, const D: usize> = SizedMultipoint<T, M, D, 2>;
type Line2D<T> = Line<T, (), 2>;
type Line2DM<T, M> = Line<T, M, 2>;
type Line3D<T> = Line<T, (), 3>;
type Line3DM<T, M> = Line<T, M, 3>;
type Triangle<T, M, const D: usize> = SizedMultipoint<T, M, D, 3>;
type Triangle2D<T> = Triangle<T, (), 2>;
type Triangle2DM<T, M> = Triangle<T, M, 2>;
type Triangle3D<T> = Triangle<T, (), 3>;
type Triangle3DM<T, M> = Triangle<T, M, 3>;
impl<T: CoordNum, M: Metadata, const D: usize> Point<T, M, D> {
pub fn get_coord(self) -> Coordinate<T, M, D> {
self.coords[0]
}
}
impl<T: CoordNum, M: Metadata, const D: usize> Line<T, M, D> {
pub fn get_start(self) -> Coordinate<T, M, D> {
self.coords[0]
}
pub fn get_end(self) -> Coordinate<T, M, D> {
self.coords[1]
}
}
impl<T: CoordNum> Point2D<T> {
pub fn new(x: T, y: T) -> Self {
Self {
coords: [Coordinate::new([x, y], ())],
}
}
}
impl<T: CoordNum> Line2D<T> {
pub fn get_x(self) -> T {
self.coords[0].coord[2]
}
}
impl<T: CoordNum> Point3D<T> {
pub fn new(x: T, y: T, z: T) -> Self {
Self {
coords: [Coordinate::new([x, y, z], ())],
}
}
}
fn test() {
// Create a 2D point
let p = Point2D::<i64>::default();
// Create a 3D point with i64 coordinates, and a char metadata
let p = Point3DM::<i64, char>::default();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment