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