ranim_items/vitem/geometry/
line.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 as _, Locate, Opacity, RotateTransform, ScaleTransform, ShiftTransform,
8 StrokeColor, StrokeWidth, With as _,
9 },
10};
11use ranim_macros::Interpolatable;
12
13use crate::vitem::VItem;
14
15#[derive(Debug, Clone, Interpolatable)]
17pub struct Line {
18 pub points: [DVec3; 2],
20 pub extrude: [f64; 2],
23 pub stroke_rgba: AlphaColor<Srgb>,
25 pub stroke_width: f32,
27}
28
29impl Line {
30 pub fn new(start: DVec3, end: DVec3) -> Self {
32 Self {
33 points: [start, end],
34 extrude: [0., 0.],
35 stroke_rgba: AlphaColor::WHITE,
36 stroke_width: DEFAULT_STROKE_WIDTH,
37 }
38 }
39
40 pub fn invert(&mut self) -> &mut Self {
42 self.points.reverse();
43 self.extrude.reverse();
44 self
45 }
46
47 pub fn points_with_extrude(&self) -> [DVec3; 2] {
49 let [p1, p2] = self.points;
50 let [ext1, ext2] = self.extrude;
51 let d = (p2 - p1).normalize();
52 [p1 - d * ext1, p2 + d * ext2]
53 }
54}
55
56impl Locate<Line> for f64 {
57 fn locate(&self, target: &Line) -> DVec3 {
58 let [p1, p2] = target.points;
59 p1.lerp(p2, *self)
60 }
61}
62
63impl Aabb for Line {
64 fn aabb(&self) -> [DVec3; 2] {
65 self.points_with_extrude().aabb()
66 }
67}
68
69impl ShiftTransform for Line {
70 fn shift(&mut self, offset: DVec3) -> &mut Self {
71 self.points.shift(offset);
72 self
73 }
74}
75
76impl RotateTransform for Line {
77 fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
78 self.points.rotate_on_axis(axis, angle);
79 self
80 }
81}
82
83impl ScaleTransform for Line {
84 fn scale(&mut self, scale: DVec3) -> &mut Self {
85 let [p1, p2] = self.points;
86 let k = ((p2 - p1).normalize() * scale).length();
87 self.points.scale(scale);
88 self.extrude.iter_mut().for_each(|e| *e *= k);
89 self
90 }
91}
92
93impl StrokeColor for Line {
94 fn stroke_color(&self) -> AlphaColor<Srgb> {
95 self.stroke_rgba
96 }
97
98 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
99 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
100 self
101 }
102
103 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
104 self.stroke_rgba = color;
105 self
106 }
107}
108
109impl From<Line> for VItem {
110 fn from(value: Line) -> Self {
111 let [p1, p2] = value.points_with_extrude();
112 VItem::from_vpoints(vec![p1, (p1 + p2) / 2., p2]).with(|item| {
113 item.set_stroke_color(value.stroke_rgba)
114 .set_stroke_width(value.stroke_width)
115 .discard()
116 })
117 }
118}
119
120impl Opacity for Line {
121 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
122 self.set_stroke_opacity(opacity);
123 self
124 }
125}
126
127impl Extract for Line {
128 type Target = CoreItem;
129
130 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
131 VItem::from(self.clone()).extract_into(buf);
132 }
133}