ranim_items/vitem/geometry/
line.rs1#[cfg(feature = "render")]
2use ranim_render::extract::{Extract, ExtractContext};
3
4use ranim_core::{
5 color::{AlphaColor, Srgb},
6 glam::DVec3,
7 traits::{Aabb, ApplyTransform, Discard, Locate, Opacity, StrokeColor, StrokeWidth, With},
8};
9use ranim_macros::Interpolatable;
10
11use crate::vitem::{DEFAULT_STROKE_WIDTH, VItem};
12
13#[derive(Debug, Clone, Interpolatable)]
15pub struct Line {
16 pub points: [DVec3; 2],
18 pub extrude: [f64; 2],
21 pub stroke_rgba: AlphaColor<Srgb>,
23 pub stroke_width: f32,
25}
26
27impl Line {
28 pub fn new(start: DVec3, end: DVec3) -> Self {
30 Self {
31 points: [start, end],
32 extrude: [0., 0.],
33 stroke_rgba: AlphaColor::WHITE,
34 stroke_width: DEFAULT_STROKE_WIDTH,
35 }
36 }
37
38 pub fn invert(&mut self) -> &mut Self {
40 self.points.reverse();
41 self.extrude.reverse();
42 self
43 }
44
45 pub fn points_with_extrude(&self) -> [DVec3; 2] {
47 let [p1, p2] = self.points;
48 let [ext1, ext2] = self.extrude;
49 let d = (p2 - p1).normalize();
50 [p1 - d * ext1, p2 + d * ext2]
51 }
52}
53
54impl Locate<Line> for f64 {
55 fn locate(&self, target: &Line) -> DVec3 {
56 let [p1, p2] = target.points;
57 p1.lerp(p2, *self)
58 }
59}
60
61impl Aabb for Line {
62 fn aabb(&self) -> [DVec3; 2] {
63 self.points_with_extrude().aabb()
64 }
65}
66
67impl<G: Into<ranim_core::glam::DAffine3>> ApplyTransform<G> for Line {
68 fn apply(&mut self, transform: G) -> &mut Self {
69 let transform = transform.into();
70 let direction = (self.points[1] - self.points[0]).try_normalize();
71 self.points.apply(transform);
72 if let Some(direction) = direction {
73 let length_scale = transform.transform_vector3(direction).length();
74 self.extrude.iter_mut().for_each(|e| *e *= length_scale);
75 }
76 self
77 }
78}
79
80impl StrokeColor for Line {
81 fn stroke_color(&self) -> AlphaColor<Srgb> {
82 self.stroke_rgba
83 }
84
85 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
86 self.stroke_rgba = self.stroke_rgba.with_alpha(opacity);
87 self
88 }
89
90 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
91 self.stroke_rgba = color;
92 self
93 }
94}
95
96impl From<Line> for VItem {
97 fn from(value: Line) -> Self {
98 let [p1, p2] = value.points_with_extrude();
99 VItem::from_vpoints(vec![p1, (p1 + p2) / 2., p2]).with(|item| {
100 item.set_stroke_color(value.stroke_rgba)
101 .set_stroke_width(value.stroke_width)
102 .discard()
103 })
104 }
105}
106
107impl Opacity for Line {
108 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
109 self.set_stroke_opacity(opacity);
110 self
111 }
112}
113
114#[cfg(feature = "render")]
115impl Extract for Line {
116 fn extract(&self, ctx: &mut ExtractContext<'_>) {
117 VItem::from(self.clone()).extract(ctx);
118 }
119}