ranim_items/vitem/geometry/
parallelogram.rs1use ranim_core::{
2 Extract,
3 anchor::Aabb,
4 color::{AlphaColor, Srgb},
5 core_item::{CoreItem, vitem::DEFAULT_STROKE_WIDTH},
6 glam::{DAffine3, DVec3},
7 traits::{ApplyTransform, Discard, FillColor, Opacity, StrokeColor, StrokeWidth, With},
8 utils::bezier::PathBuilder,
9};
10
11use crate::vitem::{
12 VItem,
13 geometry::{Polygon, Rectangle, Square},
14};
15
16#[derive(Debug, Clone, ranim_macros::Interpolatable)]
18#[allow(missing_docs)]
19pub struct Parallelogram {
20 pub origin: DVec3,
22 pub axes: (DVec3, DVec3),
24 pub stroke_rgba: AlphaColor<Srgb>,
25 pub stroke_width: f32,
26 pub fill_rgba: AlphaColor<Srgb>,
27}
28
29impl Parallelogram {
30 pub fn new(axes: (DVec3, DVec3)) -> Self {
32 Self::from_origin_and_axes(DVec3::ZERO, axes)
33 }
34 pub fn from_origin_and_axes(origin: DVec3, axes: (DVec3, DVec3)) -> Self {
36 Self {
37 origin,
38 axes,
39 stroke_rgba: AlphaColor::WHITE,
40 stroke_width: DEFAULT_STROKE_WIDTH,
41 fill_rgba: AlphaColor::TRANSPARENT,
42 }
43 }
44 pub fn vertices(&self) -> [DVec3; 4] {
46 let (u, v) = self.axes;
47 [
48 self.origin,
49 self.origin + u,
50 self.origin + u + v,
51 self.origin + v,
52 ]
53 }
54}
55impl Aabb for Parallelogram {
56 fn aabb(&self) -> [DVec3; 2] {
57 self.vertices().aabb()
58 }
59}
60impl<G: Into<DAffine3>> ApplyTransform<G> for Parallelogram {
61 fn apply(&mut self, transform: G) -> &mut Self {
62 let t = transform.into();
63 self.origin = t.transform_point3(self.origin);
64 self.axes.0 = t.transform_vector3(self.axes.0);
65 self.axes.1 = t.transform_vector3(self.axes.1);
66 self
67 }
68}
69impl StrokeColor for Parallelogram {
70 fn stroke_color(&self) -> AlphaColor<Srgb> {
71 self.stroke_rgba
72 }
73 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
74 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
75 self
76 }
77 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
78 self.stroke_rgba = color;
79 self
80 }
81}
82impl FillColor for Parallelogram {
83 fn fill_color(&self) -> AlphaColor<Srgb> {
84 self.fill_rgba
85 }
86 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
87 self.fill_rgba = self.fill_rgba.with_alpha(opacity);
88 self
89 }
90 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
91 self.fill_rgba = color;
92 self
93 }
94}
95impl Opacity for Parallelogram {
96 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
97 self.set_stroke_opacity(opacity).set_fill_opacity(opacity)
98 }
99}
100
101impl From<Rectangle> for Parallelogram {
102 fn from(value: Rectangle) -> Self {
103 let (w, h) = (value.size.x, value.size.y);
104 Self {
105 origin: DVec3::new(-w / 2.0, -h / 2.0, 0.0),
106 axes: (DVec3::X * w, DVec3::Y * h),
107 stroke_rgba: value.stroke_rgba,
108 stroke_width: value.stroke_width,
109 fill_rgba: value.fill_rgba,
110 }
111 }
112}
113impl From<Square> for Parallelogram {
114 fn from(value: Square) -> Self {
115 Parallelogram::from(Rectangle::from(value))
116 }
117}
118impl From<Parallelogram> for Polygon {
119 fn from(value: Parallelogram) -> Self {
120 let p = value.vertices();
121 Polygon::new(p.to_vec()).with(|x| {
122 x.set_stroke_color(value.stroke_rgba)
123 .set_fill_color(value.fill_rgba);
124 x.stroke_width = value.stroke_width;
125 })
126 }
127}
128impl From<Parallelogram> for VItem {
129 fn from(value: Parallelogram) -> Self {
130 let (origin, (u, v), stroke_rgba, stroke_width, fill_rgba) = (
131 value.origin,
132 value.axes,
133 value.stroke_rgba,
134 value.stroke_width,
135 value.fill_rgba,
136 );
137 VItem::from_vpoints(
138 PathBuilder::new()
139 .move_to(origin)
140 .line_to(origin + u)
141 .line_to(origin + u + v)
142 .line_to(origin + v)
143 .close_path()
144 .vpoints()
145 .into(),
146 )
147 .with(|item| {
148 item.set_fill_color(fill_rgba)
149 .set_stroke_color(stroke_rgba)
150 .set_stroke_width(stroke_width)
151 .discard()
152 })
153 }
154}
155impl Extract for Parallelogram {
156 type Target = CoreItem;
157 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
158 VItem::from(self.clone()).extract_into(buf)
159 }
160}