ranim_items/vitem/geometry/
parallelogram.rs1use ranim_core::{
2 Extract,
3 color::{AlphaColor, Srgb},
4 core_item::{CoreItem, vitem::DEFAULT_STROKE_WIDTH},
5 glam::DVec3,
6 traits::{
7 Aabb, Discard, FillColor, Opacity, RotateTransform, ScaleTransform, ShiftTransform,
8 StrokeColor, StrokeWidth, With,
9 },
10 utils::bezier::PathBuilder,
11};
12
13use crate::vitem::{
14 VItem,
15 geometry::{Polygon, Rectangle, Square},
16};
17
18#[derive(Debug, Clone, ranim_macros::Interpolatable)]
20pub struct Parallelogram {
21 pub origin: DVec3,
23 pub axes: (DVec3, DVec3),
25 pub stroke_rgba: AlphaColor<Srgb>,
27 pub stroke_width: f32,
29 pub fill_rgba: AlphaColor<Srgb>,
31}
32
33impl Parallelogram {
34 pub fn new(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
45 pub fn vertices(&self) -> [DVec3; 4] {
47 let &Parallelogram {
48 origin,
49 axes: (u, v),
50 ..
51 } = self;
52 [origin, origin + u, origin + u + v, origin + v]
53 }
54}
55
56impl Aabb for Parallelogram {
57 fn aabb(&self) -> [DVec3; 2] {
58 self.vertices().aabb()
59 }
60}
61
62impl ShiftTransform for Parallelogram {
63 fn shift(&mut self, offset: DVec3) -> &mut Self {
64 self.origin += offset;
65 self
66 }
67}
68
69impl RotateTransform for Parallelogram {
70 fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
71 self.origin.rotate_on_axis(axis, angle);
72 self.axes.0.rotate_on_axis(axis, angle);
73 self.axes.0 = self.axes.0.normalize();
74 self.axes.1.rotate_on_axis(axis, angle);
75 self.axes.1 = self.axes.1.normalize();
76 self
77 }
78}
79
80impl ScaleTransform for Parallelogram {
81 fn scale(&mut self, scale: DVec3) -> &mut Self {
82 self.origin.scale(scale).discard();
83 self.axes.0 *= scale;
84 self.axes.1 *= scale;
85 self
86 }
87}
88
89impl StrokeColor for Parallelogram {
90 fn stroke_color(&self) -> AlphaColor<Srgb> {
91 self.stroke_rgba
92 }
93
94 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
95 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
96 self
97 }
98
99 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
100 self.stroke_rgba = color;
101 self
102 }
103}
104
105impl FillColor for Parallelogram {
106 fn fill_color(&self) -> AlphaColor<Srgb> {
107 self.fill_rgba
108 }
109
110 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
111 self.fill_rgba = self.fill_rgba.with_alpha(opacity);
112 self
113 }
114
115 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
116 self.fill_rgba = color;
117 self
118 }
119}
120
121impl Opacity for Parallelogram {
122 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
123 self.set_stroke_opacity(opacity).set_fill_opacity(opacity);
124 self
125 }
126}
127
128impl From<Rectangle> for Parallelogram {
129 fn from(value: Rectangle) -> Self {
130 let Rectangle {
131 axes,
132 p0,
133 size,
134 stroke_rgba,
135 stroke_width,
136 fill_rgba,
137 } = value;
138 let (u, v) = (axes.0.normalize(), axes.1.normalize());
139 let axes = (u * size.x, v * size.y);
140 Self {
141 origin: p0,
142 axes,
143 stroke_rgba,
144 stroke_width,
145 fill_rgba,
146 }
147 }
148}
149
150impl From<Square> for Parallelogram {
151 fn from(value: Square) -> Self {
152 let Square {
153 axes,
154 center,
155 size,
156 stroke_rgba,
157 stroke_width,
158 fill_rgba,
159 } = value;
160 let (u, v) = (axes.0.normalize(), axes.1.normalize());
161 let axes = (u * size, v * size);
162 let origin = center - (u + v) * size / 2.;
163 Self {
164 origin,
165 axes,
166 stroke_rgba,
167 stroke_width,
168 fill_rgba,
169 }
170 }
171}
172
173impl From<Parallelogram> for Polygon {
174 fn from(value: Parallelogram) -> Self {
175 let Parallelogram {
176 stroke_rgba,
177 stroke_width,
178 fill_rgba,
179 ..
180 } = value;
181 Polygon::new(value.vertices().to_vec()).with(|item| {
182 item.set_stroke_color(stroke_rgba).set_fill_color(fill_rgba);
183 item.stroke_width = stroke_width;
184 })
185 }
186}
187
188impl From<Parallelogram> for VItem {
189 fn from(value: Parallelogram) -> Self {
190 let Parallelogram {
191 origin,
192 axes: (u, v),
193 stroke_rgba,
194 stroke_width,
195 fill_rgba,
196 } = value;
197 VItem::from_vpoints(
198 PathBuilder::new()
199 .move_to(origin)
200 .line_to(origin + u)
201 .line_to(origin + u + v)
202 .line_to(origin + v)
203 .close_path()
204 .vpoints()
205 .into(),
206 )
207 .with(|item| {
208 item.set_fill_color(fill_rgba)
209 .set_stroke_color(stroke_rgba)
210 .set_stroke_width(stroke_width)
211 .discard()
212 })
213 }
214}
215
216impl Extract for Parallelogram {
217 type Target = CoreItem;
218
219 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
220 VItem::from(self.clone()).extract_into(buf)
221 }
222}