typst_library/layout/
point.rs1use std::fmt::{self, Debug, Formatter};
2use std::ops::{Add, Div, Mul, Neg};
3
4use typst_utils::{Get, Numeric};
5
6use crate::layout::{Abs, Axis, Size, Transform};
7
8#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
10pub struct Point {
11 pub x: Abs,
13 pub y: Abs,
15}
16
17impl Point {
18 pub const fn zero() -> Self {
20 Self { x: Abs::zero(), y: Abs::zero() }
21 }
22
23 pub const fn new(x: Abs, y: Abs) -> Self {
25 Self { x, y }
26 }
27
28 pub const fn splat(value: Abs) -> Self {
30 Self { x: value, y: value }
31 }
32
33 pub const fn with_x(x: Abs) -> Self {
35 Self { x, y: Abs::zero() }
36 }
37
38 pub const fn with_y(y: Abs) -> Self {
40 Self { x: Abs::zero(), y }
41 }
42
43 pub fn min(self, other: Self) -> Self {
45 Self { x: self.x.min(other.x), y: self.y.min(other.y) }
46 }
47
48 pub fn max(self, other: Self) -> Self {
50 Self { x: self.x.max(other.x), y: self.y.max(other.y) }
51 }
52
53 pub fn map(self, f: impl Fn(Abs) -> Abs) -> Self {
55 Self { x: f(self.x), y: f(self.y) }
56 }
57
58 pub fn hypot(self) -> Abs {
60 let x = self.x.to_raw();
63 let y = self.y.to_raw();
64 Abs::raw((x * x + y * y).sqrt())
65 }
66
67 pub fn normalized(self) -> Self {
69 self / self.hypot().to_raw()
70 }
71
72 pub fn rot90ccw(self) -> Self {
74 Self { x: self.y, y: -self.x }
75 }
76
77 pub fn transform(self, ts: Transform) -> Self {
82 Self::new(
83 ts.sx.of(self.x) + ts.kx.of(self.y) + ts.tx,
84 ts.ky.of(self.x) + ts.sy.of(self.y) + ts.ty,
85 )
86 }
87
88 pub fn transform_inf(self, ts: Transform) -> Self {
91 Self::new(
92 ts.sx.get() * self.x + ts.kx.get() * self.y + ts.tx,
93 ts.ky.get() * self.x + ts.sy.get() * self.y + ts.ty,
94 )
95 }
96
97 pub fn to_size(self) -> Size {
99 Size::new(self.x, self.y)
100 }
101}
102
103impl Numeric for Point {
104 fn zero() -> Self {
105 Self::zero()
106 }
107
108 fn is_finite(self) -> bool {
109 self.x.is_finite() && self.y.is_finite()
110 }
111}
112
113impl Get<Axis> for Point {
114 type Component = Abs;
115
116 fn get_ref(&self, axis: Axis) -> &Abs {
117 match axis {
118 Axis::X => &self.x,
119 Axis::Y => &self.y,
120 }
121 }
122
123 fn get_mut(&mut self, axis: Axis) -> &mut Abs {
124 match axis {
125 Axis::X => &mut self.x,
126 Axis::Y => &mut self.y,
127 }
128 }
129}
130
131impl Debug for Point {
132 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
133 write!(f, "Point({:?}, {:?})", self.x, self.y)
134 }
135}
136
137impl Neg for Point {
138 type Output = Self;
139
140 fn neg(self) -> Self {
141 Self { x: -self.x, y: -self.y }
142 }
143}
144
145impl Add for Point {
146 type Output = Self;
147
148 fn add(self, other: Self) -> Self {
149 Self { x: self.x + other.x, y: self.y + other.y }
150 }
151}
152
153typst_utils::sub_impl!(Point - Point -> Point);
154
155impl Mul<f64> for Point {
156 type Output = Self;
157
158 fn mul(self, other: f64) -> Self {
159 Self { x: self.x * other, y: self.y * other }
160 }
161}
162
163impl Mul<Point> for f64 {
164 type Output = Point;
165
166 fn mul(self, other: Point) -> Point {
167 other * self
168 }
169}
170
171impl Div<f64> for Point {
172 type Output = Self;
173
174 fn div(self, other: f64) -> Self {
175 Self { x: self.x / other, y: self.y / other }
176 }
177}
178
179typst_utils::assign_impl!(Point += Point);
180typst_utils::assign_impl!(Point -= Point);
181typst_utils::assign_impl!(Point *= f64);
182typst_utils::assign_impl!(Point /= f64);