#![deny(missing_docs)]
use data_stream::{
FromStream, ToStream, collections::SizeSettings, default_settings::PortableSettings,
from_stream, to_stream,
};
use inner_space::{InnerSpace, VectorSpace, distance};
use touch_selection::Selectable;
use std::{
fs::File,
io::{Read, Result, Write},
ops::Sub,
path::Path,
};
#[derive(Clone, Debug)]
pub struct PointObject<P, O> {
pub points: Vec<P>,
pub options: O,
}
impl<P, O> PointObject<P, O> {
pub fn new(points: Vec<P>, options: O) -> Self {
Self { points, options }
}
}
impl<P, O> PointObject<P, O> {
pub fn save(&self, path: &Path) -> Result<()>
where
P: ToStream<PortableSettings>,
O: ToStream<PortableSettings>,
{
let mut file = File::create(path)?;
to_stream::<PortableSettings, _, _>(self, &mut file)
}
pub fn load(path: &Path) -> Result<Self>
where
P: FromStream<PortableSettings>,
O: FromStream<PortableSettings>,
{
let mut file = File::open(path)?;
from_stream::<PortableSettings, _, _>(&mut file)
}
}
impl<S: SizeSettings, P: ToStream<S>, O: ToStream<S>> ToStream<S> for PointObject<P, O> {
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
to_stream::<S, _, _>(&self.points, stream)?;
to_stream::<S, _, _>(&self.options, stream)
}
}
impl<S: SizeSettings, P: FromStream<S>, O: FromStream<S>> FromStream<S> for PointObject<P, O> {
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
Ok(Self {
points: from_stream::<S, _, _>(stream)?,
options: from_stream::<S, _, _>(stream)?,
})
}
}
pub trait SelectSettings<P: Sub>
where
P::Output: InnerSpace,
{
fn grab_distance(&self) -> <P::Output as VectorSpace>::Scalar;
fn connect(&mut self, _points: &[P], _index: usize, _selected: &[usize]) {}
fn special(&mut self, _points: &[P], _index: usize, _selected: &[usize]) {}
}
impl<P: Copy + Sub, O: SelectSettings<P>> Selectable for PointObject<P, O>
where
P::Output: InnerSpace,
{
type Position = P;
type Index = usize;
fn add(&mut self, pos: P, index: Option<usize>) -> usize {
let index = index.unwrap_or(self.points.len());
self.points.push(pos);
index
}
fn get(&self, pos: P) -> Option<usize> {
let grab_distance = self.options.grab_distance();
let mut found = None;
for (point_index, point) in self.points.iter().enumerate() {
let current_distance = distance(*point, pos);
if current_distance < grab_distance
&& found.is_none_or(|(_, last_distance)| current_distance < last_distance)
{
found = Some((point_index, current_distance));
}
}
found.map(|(index, _)| index)
}
fn connect(&mut self, index: usize, selected: &[usize]) {
self.options.connect(&self.points, index, selected);
}
fn special(&mut self, index: usize, selected: &[usize]) {
self.options.special(&self.points, index, selected);
}
}
pub struct Layer<P, O> {
pub objects: Vec<PointObject<P, O>>,
}
impl<P, O> Default for Layer<P, O> {
fn default() -> Self {
Self {
objects: Vec::new(),
}
}
}
impl<P, O> Layer<P, O> {
pub fn new() -> Self {
Self {
objects: Vec::new(),
}
}
}
impl<S: SizeSettings, P: ToStream<S>, O: ToStream<S>> ToStream<S> for Layer<P, O> {
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
to_stream::<S, _, _>(&self.objects, stream)
}
}
impl<S: SizeSettings, P: FromStream<S>, O: FromStream<S>> FromStream<S> for Layer<P, O> {
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
Ok(Self {
objects: from_stream::<S, _, _>(stream)?,
})
}
}