rive_rs/shapes/
polygon.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cmp::Ordering;
6use std::rc::Rc;
7
8use crate::component::Component;
9use crate::component_dirt::ComponentDirt;
10use crate::core::{Core, Object, ObjectRef, OnAdded, Property};
11use crate::dyn_vec::DynVec;
12use crate::shapes::{ParametricPath, Path, PathVertex, StraightVertex};
13
14#[derive(Debug, Default)]
15pub struct Polygon {
16    parametric_path: ParametricPath,
17    points: Property<u64>,
18    corner_radius: Property<f32>,
19    vertices: DynVec<Rc<StraightVertex>>,
20}
21
22impl ObjectRef<'_, Polygon> {
23    pub fn points(&self) -> u64 {
24        self.points.get()
25    }
26
27    pub fn set_points(&self, points: u64) {
28        self.points.set(points);
29        self.cast::<Path>().mark_path_dirty();
30    }
31
32    pub fn corner_radius(&self) -> f32 {
33        self.corner_radius.get()
34    }
35
36    pub fn set_corner_radius(&self, corner_radius: f32) {
37        self.corner_radius.set(corner_radius);
38        self.cast::<Path>().mark_path_dirty();
39    }
40}
41
42impl ObjectRef<'_, Polygon> {
43    fn expected_len(&self) -> usize {
44        self.points() as usize
45    }
46
47    fn resize_vertices(&self, new_len: usize) {
48        match self.vertices.len().cmp(&new_len) {
49            Ordering::Less => {
50                for _ in 0..new_len - self.vertices.len() {
51                    let vertex = Rc::new(StraightVertex::default());
52
53                    self.cast::<Path>().push_vertex(Object::new(&(vertex.clone() as Rc<dyn Core>)));
54                    self.vertices.push(vertex);
55                }
56            }
57            Ordering::Greater => {
58                self.cast::<Path>().vertices.truncate(new_len);
59                self.vertices.truncate(new_len);
60            }
61            _ => (),
62        }
63    }
64
65    fn build_polygon(&self) {
66        let parametric_path = self.cast::<ParametricPath>();
67
68        let half_width = parametric_path.width() * 0.5;
69        let half_height = parametric_path.height() * 0.5;
70
71        let mut angle = -std::f32::consts::FRAC_PI_2;
72        let increment = std::f32::consts::PI / self.points() as f32;
73
74        for vertex in self.vertices.iter() {
75            let (sin, cos) = angle.sin_cos();
76
77            let vertex_ref = ObjectRef::from(&*vertex);
78            vertex_ref.cast::<PathVertex>().set_x(cos * half_width);
79            vertex_ref.cast::<PathVertex>().set_y(sin * half_height);
80            vertex_ref.set_radius(self.corner_radius());
81
82            angle += increment;
83        }
84    }
85
86    pub fn update(&self, value: ComponentDirt) {
87        let path = self.cast::<Path>();
88
89        if Component::value_has_dirt(value, ComponentDirt::PATH) {
90            let expected_len = self.expected_len();
91            if self.vertices.len() != expected_len {
92                self.resize_vertices(expected_len);
93            }
94
95            self.build_polygon();
96        }
97
98        path.update(value);
99    }
100}
101
102impl Core for Polygon {
103    parent_types![(parametric_path, ParametricPath)];
104
105    properties!(
106        (125, points, set_points),
107        (126, corner_radius, set_corner_radius),
108        parametric_path
109    );
110}
111
112impl OnAdded for ObjectRef<'_, Polygon> {
113    on_added!(ParametricPath);
114}