1use crate::{
47 canvas::Canvas,
48 points::{pt, TAU},
49 util::{chaiken, Trail},
50};
51use log::error;
52use num_traits::AsPrimitive;
53use rand::RngCore;
55use rand_distr::{Distribution, Normal};
56use tiny_skia::{
57 FillRule, LineCap, LineJoin, Paint, PathBuilder, Point, Rect, Stroke, StrokeDash, Transform,
58};
59
60#[derive(Debug, Clone, Copy)]
62enum ShapeType {
63 Poly,
64 PolyQuad,
65 PolyCubic,
66 Rect,
67 Circle,
68 Line,
69 Ellipse,
70}
71
72#[derive(Debug, Clone)]
74struct ShapeData<'a> {
75 points: Vec<Point>,
76 fill_paint: Box<Option<Paint<'a>>>,
77 stroke: Stroke,
78 stroke_paint: Box<Option<Paint<'a>>>,
79 shape: ShapeType,
80 fillrule: FillRule,
81 transform: Transform,
82}
83
84impl<'a> ShapeData<'a> {
85 pub(crate) fn new(
86 points: Vec<Point>,
87 fill_paint: Box<Option<Paint<'a>>>,
88 stroke: Stroke,
89 stroke_paint: Box<Option<Paint<'a>>>,
90 shape: ShapeType,
91 fillrule: FillRule,
92 transform: Transform,
93 ) -> Self {
94 Self {
95 points,
96 fill_paint,
97 stroke,
98 stroke_paint,
99 shape,
100 fillrule,
101 transform,
102 }
103 }
104
105 fn draw(&self, canvas: &mut Canvas) {
106 let shape = self.shape;
107 match shape {
108 ShapeType::Poly => self.draw_poly(canvas),
109 ShapeType::PolyQuad => self.draw_quad(canvas),
110 ShapeType::PolyCubic => self.draw_cubic(canvas),
111 ShapeType::Rect => self.draw_rect(canvas),
112 ShapeType::Circle => self.draw_circle(canvas),
113 ShapeType::Line => self.draw_line(canvas),
114 ShapeType::Ellipse => self.draw_ellipse(canvas),
115 }
116 }
117
118 fn draw_poly(&self, canvas: &mut Canvas) {
120 if self.points.len() < 2 {
121 error!(
122 "Cannot draw a polygonal curve with less than 2 points, only {} points provided.",
123 self.points.len()
124 );
125 return;
126 }
127 let mut pb = PathBuilder::new();
128 let head = self.points[0];
129 let tail = &self.points[1..];
130 pb.move_to(head.x, head.y);
131 for p in tail {
132 pb.line_to(p.x, p.y);
133 }
134 if self.fill_paint.is_some() {
135 pb.close();
136 }
137 let path = pb.finish().unwrap();
138 if let Some(mut fp) = *self.fill_paint.clone() {
139 canvas.fill_path(&path, &mut fp, self.fillrule, self.transform, None);
140 }
141 if let Some(mut sp) = *self.stroke_paint.clone() {
142 canvas.stroke_path(&path, &mut sp, &self.stroke, self.transform, None);
143 }
144 }
145
146 fn draw_quad(&self, canvas: &mut Canvas) {
148 if self.points.len() < 3 {
149 error!(
150 "Cannot draw a quadratic bezier curve with less than 3 points, only {} points provided.",
151 self.points.len()
152 );
153 return;
154 }
155 let mut pb = PathBuilder::new();
156 let head = self.points[0];
157 pb.move_to(head.x, head.y);
158 let tail = self.points[1..].chunks_exact(2);
159 for t in tail {
160 let control = t[0];
161 let p = t[1];
162 pb.quad_to(control.x, control.y, p.x, p.y);
163 }
164 if self.fill_paint.is_some() {
165 pb.close();
166 }
167 let path = pb.finish().unwrap();
168 if let Some(mut fp) = *self.fill_paint.clone() {
169 canvas.fill_path(&path, &mut fp, self.fillrule, self.transform, None);
170 }
171 if let Some(mut sp) = *self.stroke_paint.clone() {
172 canvas.stroke_path(&path, &mut sp, &self.stroke, self.transform, None);
173 }
174 }
175
176 fn draw_cubic(&self, canvas: &mut Canvas) {
180 if self.points.len() < 4 {
181 error!(
182 "Cannot draw a cubic bezier curve with less than 4 points, only {} points provided.",
183 self.points.len()
184 );
185 return;
186 }
187 let mut pb = PathBuilder::new();
188 let head = self.points[0];
189 pb.move_to(head.x, head.y);
190 let tail = self.points[1..].chunks_exact(3);
191 for t in tail {
192 let control1 = t[0];
193 let control2 = t[1];
194 let p = t[2];
195 pb.cubic_to(control1.x, control1.y, control2.x, control2.y, p.x, p.y);
196 }
197 if self.fill_paint.is_some() {
198 pb.close();
199 }
200 let path = pb.finish().unwrap();
201 if let Some(mut fp) = *self.fill_paint.clone() {
202 canvas.fill_path(&path, &mut fp, self.fillrule, self.transform, None);
203 }
204 if let Some(mut sp) = *self.stroke_paint.clone() {
205 canvas.stroke_path(&path, &mut sp, &self.stroke, self.transform, None);
206 }
207 }
208
209 fn draw_rect(&self, canvas: &mut Canvas) {
211 if self.points.len() < 2 {
212 error!(
213 "Cannot draw a rectangle with less than 2 points, only {} points provided.",
214 self.points.len()
215 );
216 return;
217 }
218 let left = self.points[0].x;
219 let top = self.points[0].y;
220 let right = self.points[1].x;
221 let bottom = self.points[1].y;
222 let rect = Rect::from_ltrb(left, top, right, bottom).unwrap();
223 let path = PathBuilder::from_rect(rect);
224 if let Some(mut fp) = *self.fill_paint.clone() {
225 canvas.fill_path(&path, &mut fp, self.fillrule, self.transform, None);
226 }
227 if let Some(mut sp) = *self.stroke_paint.clone() {
228 canvas.stroke_path(&path, &mut sp, &self.stroke, self.transform, None);
229 }
230 }
231
232 fn draw_circle(&self, canvas: &mut Canvas) {
234 if self.points.len() < 2 {
235 error!(
236 "Cannot draw a circle with less than 2 points, only {} points provided.",
237 self.points.len()
238 );
239 return;
240 }
241 let cx = self.points[0].x;
242 let cy = self.points[0].y;
243 let w = self.points[1].x;
244 let circle = PathBuilder::from_circle(cx, cy, w).unwrap();
245 if let Some(mut fp) = *self.fill_paint.clone() {
246 canvas.fill_path(&circle, &mut fp, self.fillrule, self.transform, None);
247 }
248 if let Some(mut sp) = *self.stroke_paint.clone() {
249 canvas.stroke_path(&circle, &mut sp, &self.stroke, self.transform, None);
250 }
251 }
252
253 fn draw_ellipse(&self, canvas: &mut Canvas) {
256 if self.points.len() < 2 {
257 error!(
258 "Cannot draw a ellipse with less than 2 points, only {} points provided.",
259 self.points.len()
260 );
261 return;
262 }
263 let cx = self.points[0].x;
264 let cy = self.points[0].y;
265 let w = self.points[1].x;
266 let h = self.points[1].y;
267 let rect = Rect::from_xywh(cx - w / 2.0, cy - h / 2.0, w, h).unwrap();
268 let ellipse = PathBuilder::from_oval(rect).unwrap();
269 if let Some(mut fp) = *self.fill_paint.clone() {
270 canvas.fill_path(&ellipse, &mut fp, self.fillrule, self.transform, None);
271 }
272 if let Some(mut sp) = *self.stroke_paint.clone() {
273 canvas.stroke_path(&ellipse, &mut sp, &self.stroke, self.transform, None);
274 }
275 }
276
277 fn draw_line(&self, canvas: &mut Canvas) {
279 if self.points.len() < 2 {
280 error!(
281 "Cannot draw a line with less than 2 points, only {} points provided.",
282 self.points.len()
283 );
284 return;
285 }
286 let x0 = self.points[0].x;
287 let y0 = self.points[0].y;
288 let x1 = self.points[1].x;
289 let y1 = self.points[1].y;
290 let mut pb = PathBuilder::new();
291 pb.move_to(x0, y0);
292 pb.line_to(x1, y1);
293 let path = pb.finish().unwrap();
294 if let Some(mut sp) = *self.stroke_paint.clone() {
295 canvas.stroke_path(&path, &mut sp, &self.stroke, self.transform, None);
296 }
297 }
298}
299
300#[derive(Debug, Clone)]
302pub struct Shape<'a> {
303 fill_paint: Option<Paint<'a>>,
304 stroke_paint: Option<Paint<'a>>,
305 stroke_width: f32,
306 miter_limit: f32,
307 line_cap: LineCap,
308 line_join: LineJoin,
309 stroke_dash: Option<StrokeDash>,
310 points: Vec<Point>,
311 shape: ShapeType,
312 fillrule: FillRule,
313 transform: Transform,
314}
315
316impl Default for Shape<'_> {
317 fn default() -> Self {
318 let fill = Paint {
319 anti_alias: true,
320 ..Default::default()
321 };
322 let stroke = Paint {
323 anti_alias: true,
324 ..Default::default()
325 };
326 Self {
327 fill_paint: Some(fill),
328 stroke_paint: Some(stroke),
329 stroke_width: 1.0,
330 miter_limit: Default::default(),
331 line_cap: Default::default(),
332 line_join: Default::default(),
333 stroke_dash: None,
334 points: vec![],
335 shape: ShapeType::Poly,
336 fillrule: FillRule::Winding,
337 transform: Transform::identity(),
338 }
339 }
340}
341
342impl<'a> Shape<'a> {
343 pub fn new() -> Self {
345 Self::default()
346 }
347
348 pub fn fill_color(mut self, color: tiny_skia::Color) -> Self {
350 let mut paint = Paint {
351 anti_alias: true,
352 ..Default::default()
353 };
354 paint.set_color(color);
355 self.fill_paint = Some(paint);
356 self
357 }
358
359 pub fn fill_paint(mut self, texture: &'a Paint) -> Self {
362 self.fill_paint = Some(texture.clone());
363 self
364 }
365
366 pub fn no_fill(mut self) -> Self {
368 self.fill_paint = None;
369 self
370 }
371 pub fn no_stroke(mut self) -> Self {
373 self.stroke_paint = None;
374 self
375 }
376
377 pub fn stroke_color(mut self, color: tiny_skia::Color) -> Self {
379 let mut paint = Paint {
380 anti_alias: true,
381 ..Default::default()
382 };
383 paint.set_color(color);
384 self.stroke_paint = Some(paint);
385 self
386 }
387
388 pub fn stroke_paint(mut self, paint: &'a Paint) -> Self {
391 self.stroke_paint = Some(paint.clone());
392 self
393 }
394
395 pub fn stroke_weight(mut self, weight: f32) -> Self {
397 self.stroke_width = weight;
398 self
399 }
400
401 pub fn line_cap(mut self, cap: LineCap) -> Self {
403 self.line_cap = cap;
404 self
405 }
406
407 pub fn line_join(mut self, join: LineJoin) -> Self {
409 self.line_join = join;
410 self
411 }
412
413 pub fn miter_limit(mut self, limit: f32) -> Self {
414 self.miter_limit = limit;
415 self
416 }
417
418 pub fn stroke_dash(mut self, dash: StrokeDash) -> Self {
420 self.stroke_dash = Some(dash);
421 self
422 }
423
424 pub fn points(mut self, pts: &[Point]) -> Self {
426 let points = pts.to_vec();
427 self.points = points;
428 self
429 }
430
431 pub fn get_points(&self) -> &[Point] {
433 &self.points
434 }
435
436 pub fn rect_ltrb(mut self, lt: Point, rb: Point) -> Self {
439 self.shape = ShapeType::Rect;
440 self.points = vec![lt, rb];
441 self
442 }
443
444 pub fn rect_xywh(mut self, xy: Point, wh: Point) -> Self {
447 self.shape = ShapeType::Rect;
448 self.points = vec![xy, pt(xy.x + wh.x, xy.y + wh.y)];
449 self
450 }
451
452 pub fn rect_cwh(mut self, c: Point, wh: Point) -> Self {
455 self.shape = ShapeType::Rect;
456 let w2 = wh.x / 2.0;
457 let h2 = wh.y / 2.0;
458 let p = pt(c.x - w2, c.y - h2);
459 self.rect_xywh(p, wh)
460 }
461
462 pub fn circle(mut self, center: Point, radius: f32) -> Self {
464 self.shape = ShapeType::Circle;
465 self.points = vec![center, pt(radius, radius)];
466 self
467 }
468
469 pub fn ellipse(mut self, center: Point, width: f32, height: f32) -> Self {
471 self.shape = ShapeType::Ellipse;
472 self.points = vec![center, pt(width, height)];
473 self
474 }
475
476 pub fn polygon(mut self, center: Point, radius: f32, sides: u32) -> Self {
478 self.shape = ShapeType::Poly;
479 let mut theta = 0.0;
480 let delta = TAU / sides as f32;
481 let mut pts = vec![];
482 while theta < TAU {
483 pts.push(pt(
484 center.x + radius * theta.cos(),
485 center.y + radius * theta.sin(),
486 ));
487 theta += delta;
488 }
489 self.points = pts;
490 self
491 }
492
493 pub fn star(mut self, center: Point, inner_radius: f32, outer_radius: f32, sides: u32) -> Self {
496 self.shape = ShapeType::Poly;
497 let mut theta = 0.0;
498 let delta = TAU / sides as f32;
499 let half_delta = delta / 2.0;
500 let mut pts = vec![];
501 while theta < TAU {
502 pts.push(pt(
503 center.x + outer_radius * theta.cos(),
504 center.y + outer_radius * theta.sin(),
505 ));
506 pts.push(pt(
507 center.x + inner_radius * (theta + half_delta).cos(),
508 center.y + inner_radius * (theta + half_delta).sin(),
509 ));
510 theta += delta;
511 }
512 self.points = pts;
513 self
514 }
515
516 pub fn pearl<R: RngCore>(
522 mut self,
523 center: Point,
524 a: f32,
525 b: f32,
526 sides: u32,
527 smoothness: u32,
528 rng: &mut R,
529 ) -> Self {
530 self.shape = ShapeType::Poly;
531 let mut points = vec![];
532 for i in 0..sides {
533 let normal = Normal::new(0.0, 0.25 * a.min(b)).unwrap();
534 let dx = normal.sample(rng);
535 let dy = normal.sample(rng);
536 let u = TAU * i as f32 / sides as f32;
537 let x1 = a * u.cos() + center.x + dx;
538 let y1 = b * u.sin() + center.y + dy;
539 points.push(pt(x1, y1));
540 }
541 self.points = chaiken(&points, smoothness, Trail::Closed)
542 .into_iter()
543 .collect();
544 self
545 }
546
547 pub fn quad(mut self) -> Self {
550 self.shape = ShapeType::PolyQuad;
551 self
552 }
553
554 pub fn cubic(mut self) -> Self {
558 self.shape = ShapeType::PolyCubic;
559 self
560 }
561
562 pub fn line(mut self, from: Point, to: Point) -> Self {
564 self.points = vec![from, to];
565 self.shape = ShapeType::Line;
566 self
567 }
568
569 pub fn fill_rule(mut self, fillrule: FillRule) -> Self {
571 self.fillrule = fillrule;
572 self
573 }
574
575 pub fn transform(mut self, transform: &Transform) -> Self {
577 let t = self.transform.post_concat(*transform);
578 self.transform = t;
579 self
580 }
581
582 pub fn cartesian<T: AsPrimitive<f32>>(mut self, width: T, height: T) -> Self {
584 self.transform = self
585 .transform
586 .post_scale(1.0, -1.0)
587 .post_translate(width.as_() / 2.0, height.as_() / 2.0);
588 self
589 }
590
591 pub fn draw(self, canvas: &mut Canvas) {
593 let mut fill_paint: Box<Option<Paint<'_>>> = Box::new(None);
594 let mut stroke_paint: Box<Option<Paint<'_>>> = Box::new(None);
595 if let Some(fs) = self.fill_paint {
596 fill_paint = Box::new(Some(fs));
597 };
598 if let Some(ss) = self.stroke_paint {
599 stroke_paint = Box::new(Some(ss));
600 };
601 let stroke = Stroke {
602 width: self.stroke_width,
603 miter_limit: self.miter_limit,
604 line_cap: self.line_cap,
605 line_join: self.line_join,
606 dash: self.stroke_dash,
607 };
608 ShapeData::new(
609 self.points,
610 fill_paint,
611 stroke,
612 stroke_paint,
613 self.shape,
614 self.fillrule,
615 self.transform,
616 )
617 .draw(canvas);
618 }
619}