use super::sampled_contour::*;
use smallvec::*;
use std::ops::{Range};
pub trait SampledSignedDistanceField {
type Contour: SampledContour;
fn field_size(&self) -> ContourSize;
fn distance_at_point(&self, pos: ContourPosition) -> f64;
fn as_contour<'a>(&'a self) -> &'a Self::Contour;
}
impl<'a, T> SampledSignedDistanceField for &'a T
where
T: SampledSignedDistanceField,
{
type Contour = T::Contour;
#[inline] fn field_size(&self) -> ContourSize { (*self).field_size() }
#[inline] fn distance_at_point(&self, pos: ContourPosition) -> f64 { (*self).distance_at_point(pos) }
#[inline] fn as_contour<'b>(&'b self) -> &'b Self::Contour { (*self).as_contour() }
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct ContourFromDistanceField<'a, TDistanceField>(pub &'a TDistanceField)
where
TDistanceField: SampledSignedDistanceField;
impl<'a, TDistanceField> ContourFromDistanceField<'a, TDistanceField>
where
TDistanceField: SampledSignedDistanceField,
{
#[inline]
fn point_is_inside(&self, pos: ContourPosition) -> bool {
self.0.distance_at_point(pos) < 0.0
}
}
impl<'a, TDistanceField> SampledContour for ContourFromDistanceField<'a, TDistanceField>
where
TDistanceField: SampledSignedDistanceField,
{
#[inline]
fn contour_size(&self) -> ContourSize {
self.0.field_size()
}
fn intercepts_on_line(&self, y: f64) -> SmallVec<[Range<f64>; 4]> {
let width = self.contour_size().width();
let y = y.floor() as usize;
let mut ranges = smallvec![];
let mut inside = None;
for x in 0..width {
match (inside, self.point_is_inside(ContourPosition(x, y))) {
(None, true) => { inside = Some(x); },
(Some(start_x), false) => {
inside = None;
ranges.push((start_x as f64)..(x as f64));
}
_ => { }
}
}
if let Some(start_x) = inside {
ranges.push((start_x as f64)..(width as f64));
}
ranges
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct F32SampledDistanceField(pub ContourSize, pub Vec<f32>);
#[derive(Clone, PartialEq, Debug)]
pub struct F64SampledDistanceField(pub ContourSize, pub Vec<f64>);
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct U8SampledDistanceField(pub ContourSize, pub Vec<u8>);
impl SampledSignedDistanceField for F32SampledDistanceField {
type Contour = Self;
#[inline]
fn field_size(&self) -> ContourSize {
self.0
}
#[inline]
fn distance_at_point(&self, pos: ContourPosition) -> f64 {
let width = self.0.0;
let height = self.0.1;
if pos.0 < width && pos.1 < height {
let pos = pos.0 + (pos.1 * width);
self.1[pos] as _
} else {
f64::MAX
}
}
#[inline]
fn as_contour<'a>(&'a self) -> &'a Self::Contour {
self
}
}
impl SampledContour for F32SampledDistanceField {
#[inline] fn contour_size(&self) -> ContourSize { self.field_size() }
#[inline] fn intercepts_on_line(&self, y: f64) -> SmallVec<[Range<f64>; 4]> { ContourFromDistanceField(self).intercepts_on_line(y )}
}
impl SampledSignedDistanceField for F64SampledDistanceField {
type Contour = Self;
#[inline]
fn field_size(&self) -> ContourSize {
self.0
}
#[inline]
fn distance_at_point(&self, pos: ContourPosition) -> f64 {
let width = self.0.0;
let height = self.0.1;
if pos.0 < width && pos.1 < height {
let pos = pos.0 + (pos.1 * width);
self.1[pos]
} else {
f64::MAX
}
}
#[inline]
fn as_contour<'a>(&'a self) -> &'a Self::Contour {
self
}
}
impl SampledContour for F64SampledDistanceField {
#[inline] fn contour_size(&self) -> ContourSize { self.field_size() }
#[inline] fn intercepts_on_line(&self, y: f64) -> SmallVec<[Range<f64>; 4]> { ContourFromDistanceField(self).intercepts_on_line(y )}
}
impl SampledSignedDistanceField for U8SampledDistanceField {
type Contour = Self;
#[inline]
fn field_size(&self) -> ContourSize {
self.0
}
#[inline]
fn distance_at_point(&self, pos: ContourPosition) -> f64 {
let width = self.0.0;
let pos = pos.0 + (pos.1 * width);
(self.1[pos] as f64) - 127.0
}
#[inline]
fn as_contour<'a>(&'a self) -> &'a Self::Contour {
self
}
}
impl SampledContour for U8SampledDistanceField {
#[inline] fn contour_size(&self) -> ContourSize { self.field_size() }
#[inline] fn intercepts_on_line(&self, y: f64) -> SmallVec<[Range<f64>; 4]> { ContourFromDistanceField(self).intercepts_on_line(y )}
}