nannou/draw/primitive/
ellipse.rs1use crate::color::conv::IntoLinSrgba;
2use crate::draw;
3use crate::draw::primitive::polygon::{self, PolygonInit, PolygonOptions, SetPolygon};
4use crate::draw::primitive::Primitive;
5use crate::draw::properties::spatial::{dimension, orientation, position};
6use crate::draw::properties::{
7 spatial, ColorScalar, LinSrgba, SetColor, SetDimensions, SetOrientation, SetPosition, SetStroke,
8};
9use crate::draw::Drawing;
10use crate::geom;
11use crate::glam::Vec2;
12use lyon::tessellation::StrokeOptions;
13
14#[derive(Clone, Debug, Default)]
16pub struct Ellipse {
17 dimensions: spatial::dimension::Properties,
18 resolution: Option<f32>,
19 polygon: PolygonInit,
20}
21
22pub type DrawingEllipse<'a> = Drawing<'a, Ellipse>;
24
25impl Ellipse {
28 pub fn stroke<C>(self, color: C) -> Self
30 where
31 C: IntoLinSrgba<ColorScalar>,
32 {
33 self.stroke_color(color)
34 }
35
36 pub fn radius(self, radius: f32) -> Self {
38 let side = radius * 2.0;
39 self.w_h(side, side)
40 }
41
42 pub fn resolution(mut self, resolution: f32) -> Self {
47 self.resolution = Some(resolution);
48 self
49 }
50}
51
52impl draw::renderer::RenderPrimitive for Ellipse {
55 fn render_primitive(
56 self,
57 ctxt: draw::renderer::RenderContext,
58 mesh: &mut draw::Mesh,
59 ) -> draw::renderer::PrimitiveRender {
60 let Ellipse {
61 dimensions,
62 polygon,
63 resolution,
64 } = self;
65
66 let (maybe_x, maybe_y, maybe_z) = (dimensions.x, dimensions.y, dimensions.z);
68 assert!(
69 maybe_z.is_none(),
70 "z dimension support for ellipse is unimplemented"
71 );
72
73 let w = maybe_x.map(f32::abs).unwrap_or(100.0);
74 let h = maybe_y.map(f32::abs).unwrap_or(100.0);
75 match resolution {
76 None => {
77 let radii = lyon::math::vector(w * 0.5, h * 0.5);
79 if radii.square_length() > 0.0 {
80 let centre = lyon::math::point(0.0, 0.0);
81 let mut builder = lyon::path::Path::svg_builder();
82 let sweep_angle = lyon::math::Angle::radians(std::f32::consts::PI * 2.0);
83 let x_rotation = lyon::math::Angle::radians(0.0);
84 let start = lyon::math::point(w * 0.5, 0.0);
85 builder.move_to(start);
86 builder.arc(centre, radii, sweep_angle, x_rotation);
87 let path = builder.build();
88 polygon::render_events_themed(
89 polygon.opts,
90 || (&path).into_iter(),
91 ctxt,
92 &draw::theme::Primitive::Ellipse,
93 mesh,
94 );
95 }
96 }
97 Some(resolution) => {
98 let rect = geom::Rect::from_w_h(w, h);
99 let ellipse = geom::Ellipse::new(rect, resolution);
100 let points = ellipse.circumference().map(Vec2::from);
101 polygon::render_points_themed(
102 polygon.opts,
103 points,
104 ctxt,
105 &draw::theme::Primitive::Ellipse,
106 mesh,
107 );
108 }
109 }
110
111 draw::renderer::PrimitiveRender::default()
112 }
113}
114
115impl SetOrientation for Ellipse {
116 fn properties(&mut self) -> &mut orientation::Properties {
117 SetOrientation::properties(&mut self.polygon)
118 }
119}
120
121impl SetPosition for Ellipse {
122 fn properties(&mut self) -> &mut position::Properties {
123 SetPosition::properties(&mut self.polygon)
124 }
125}
126
127impl SetDimensions for Ellipse {
128 fn properties(&mut self) -> &mut dimension::Properties {
129 SetDimensions::properties(&mut self.dimensions)
130 }
131}
132
133impl SetColor<ColorScalar> for Ellipse {
134 fn rgba_mut(&mut self) -> &mut Option<LinSrgba> {
135 SetColor::rgba_mut(&mut self.polygon)
136 }
137}
138
139impl SetStroke for Ellipse {
140 fn stroke_options_mut(&mut self) -> &mut StrokeOptions {
141 SetStroke::stroke_options_mut(&mut self.polygon)
142 }
143}
144
145impl SetPolygon for Ellipse {
146 fn polygon_options_mut(&mut self) -> &mut PolygonOptions {
147 SetPolygon::polygon_options_mut(&mut self.polygon)
148 }
149}
150
151impl From<Ellipse> for Primitive {
154 fn from(prim: Ellipse) -> Self {
155 Primitive::Ellipse(prim)
156 }
157}
158
159impl Into<Option<Ellipse>> for Primitive {
160 fn into(self) -> Option<Ellipse> {
161 match self {
162 Primitive::Ellipse(prim) => Some(prim),
163 _ => None,
164 }
165 }
166}
167
168impl<'a> DrawingEllipse<'a> {
171 pub fn stroke<C>(self, color: C) -> Self
173 where
174 C: IntoLinSrgba<ColorScalar>,
175 {
176 self.map_ty(|ty| ty.stroke(color))
177 }
178
179 pub fn radius(self, radius: f32) -> Self {
181 self.map_ty(|ty| ty.radius(radius))
182 }
183
184 pub fn resolution(self, resolution: f32) -> Self {
186 self.map_ty(|ty| ty.resolution(resolution))
187 }
188}