rive_rs/shapes/
polygon.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::cmp::Ordering;
use std::rc::Rc;

use crate::component::Component;
use crate::component_dirt::ComponentDirt;
use crate::core::{Core, Object, ObjectRef, OnAdded, Property};
use crate::dyn_vec::DynVec;
use crate::shapes::{ParametricPath, Path, PathVertex, StraightVertex};

#[derive(Debug, Default)]
pub struct Polygon {
    parametric_path: ParametricPath,
    points: Property<u64>,
    corner_radius: Property<f32>,
    vertices: DynVec<Rc<StraightVertex>>,
}

impl ObjectRef<'_, Polygon> {
    pub fn points(&self) -> u64 {
        self.points.get()
    }

    pub fn set_points(&self, points: u64) {
        self.points.set(points);
        self.cast::<Path>().mark_path_dirty();
    }

    pub fn corner_radius(&self) -> f32 {
        self.corner_radius.get()
    }

    pub fn set_corner_radius(&self, corner_radius: f32) {
        self.corner_radius.set(corner_radius);
        self.cast::<Path>().mark_path_dirty();
    }
}

impl ObjectRef<'_, Polygon> {
    fn expected_len(&self) -> usize {
        self.points() as usize
    }

    fn resize_vertices(&self, new_len: usize) {
        match self.vertices.len().cmp(&new_len) {
            Ordering::Less => {
                for _ in 0..new_len - self.vertices.len() {
                    let vertex = Rc::new(StraightVertex::default());

                    self.cast::<Path>().push_vertex(Object::new(&(vertex.clone() as Rc<dyn Core>)));
                    self.vertices.push(vertex);
                }
            }
            Ordering::Greater => {
                self.cast::<Path>().vertices.truncate(new_len);
                self.vertices.truncate(new_len);
            }
            _ => (),
        }
    }

    fn build_polygon(&self) {
        let parametric_path = self.cast::<ParametricPath>();

        let half_width = parametric_path.width() * 0.5;
        let half_height = parametric_path.height() * 0.5;

        let mut angle = -std::f32::consts::FRAC_PI_2;
        let increment = std::f32::consts::PI / self.points() as f32;

        for vertex in self.vertices.iter() {
            let (sin, cos) = angle.sin_cos();

            let vertex_ref = ObjectRef::from(&*vertex);
            vertex_ref.cast::<PathVertex>().set_x(cos * half_width);
            vertex_ref.cast::<PathVertex>().set_y(sin * half_height);
            vertex_ref.set_radius(self.corner_radius());

            angle += increment;
        }
    }

    pub fn update(&self, value: ComponentDirt) {
        let path = self.cast::<Path>();

        if Component::value_has_dirt(value, ComponentDirt::PATH) {
            let expected_len = self.expected_len();
            if self.vertices.len() != expected_len {
                self.resize_vertices(expected_len);
            }

            self.build_polygon();
        }

        path.update(value);
    }
}

impl Core for Polygon {
    parent_types![(parametric_path, ParametricPath)];

    properties!(
        (125, points, set_points),
        (126, corner_radius, set_corner_radius),
        parametric_path
    );
}

impl OnAdded for ObjectRef<'_, Polygon> {
    on_added!(ParametricPath);
}