use crate::draw::properties::spatial::{dimension, orientation, position};
use crate::draw::properties::{
spatial, ColorScalar, Draw, Drawn, IntoDrawn, Primitive, Rgba, SetColor, SetDimensions,
SetOrientation, SetPosition,
};
use crate::draw::{self, Drawing};
use crate::geom::{self, Vector2};
use crate::math::BaseFloat;
#[derive(Clone, Debug)]
pub struct Ellipse<S = geom::scalar::Default> {
spatial: spatial::Properties<S>,
color: Option<Rgba>,
resolution: Option<usize>,
}
impl<S> Ellipse<S>
where
S: BaseFloat,
{
pub fn radius(self, radius: S) -> Self {
let side = radius * (S::one() + S::one());
self.w_h(side, side)
}
pub fn resolution(mut self, resolution: usize) -> Self {
self.resolution = Some(resolution);
self
}
}
impl<S> IntoDrawn<S> for Ellipse<S>
where
S: BaseFloat,
{
type Vertices = draw::mesh::vertex::IterFromPoint2s<geom::ellipse::TriangleVertices<S>, S>;
type Indices = geom::ellipse::TriangleIndices;
fn into_drawn(self, draw: Draw<S>) -> Drawn<S, Self::Vertices, Self::Indices> {
let Ellipse {
spatial,
color,
resolution,
} = self;
let (maybe_x, maybe_y, maybe_z) = spatial.dimensions.to_scalars(&draw);
assert!(
maybe_z.is_none(),
"z dimension support for ellipse is unimplemented"
);
const DEFAULT_RESOLUTION: usize = 50;
let default_w = || S::from(100.0).unwrap();
let default_h = || S::from(100.0).unwrap();
let w = maybe_x.unwrap_or_else(default_w);
let h = maybe_y.unwrap_or_else(default_h);
let rect = geom::Rect::from_wh(Vector2 { x: w, y: h });
let resolution = resolution.unwrap_or(DEFAULT_RESOLUTION);
let color = color
.or_else(|| {
draw.theme(|theme| {
theme
.color
.primitive
.get(&draw::theme::Primitive::Ellipse)
.map(|&c| c)
})
})
.unwrap_or(draw.theme(|t| t.color.default));
let ellipse = geom::Ellipse::new(rect, resolution);
let (points, indices) = ellipse.triangle_indices();
let vertices = draw::mesh::vertex::IterFromPoint2s::new(points, color);
(spatial, vertices, indices)
}
}
impl<S> Default for Ellipse<S> {
fn default() -> Self {
let spatial = Default::default();
let color = Default::default();
let resolution = Default::default();
Ellipse {
spatial,
color,
resolution,
}
}
}
impl<S> SetOrientation<S> for Ellipse<S> {
fn properties(&mut self) -> &mut orientation::Properties<S> {
SetOrientation::properties(&mut self.spatial)
}
}
impl<S> SetPosition<S> for Ellipse<S> {
fn properties(&mut self) -> &mut position::Properties<S> {
SetPosition::properties(&mut self.spatial)
}
}
impl<S> SetDimensions<S> for Ellipse<S> {
fn properties(&mut self) -> &mut dimension::Properties<S> {
SetDimensions::properties(&mut self.spatial)
}
}
impl<S> SetColor<ColorScalar> for Ellipse<S> {
fn rgba_mut(&mut self) -> &mut Option<Rgba> {
SetColor::rgba_mut(&mut self.color)
}
}
impl<S> From<Ellipse<S>> for Primitive<S> {
fn from(prim: Ellipse<S>) -> Self {
Primitive::Ellipse(prim)
}
}
impl<S> Into<Option<Ellipse<S>>> for Primitive<S> {
fn into(self) -> Option<Ellipse<S>> {
match self {
Primitive::Ellipse(prim) => Some(prim),
_ => None,
}
}
}
impl<'a, S> Drawing<'a, Ellipse<S>, S>
where
S: BaseFloat,
{
pub fn radius(self, radius: S) -> Self {
self.map_ty(|ty| ty.radius(radius))
}
pub fn resolution(self, resolution: usize) -> Self {
self.map_ty(|ty| ty.resolution(resolution))
}
}