Run `rustfmt` on the geometry crate

This commit is contained in:
Patrick Walton 2019-04-29 16:46:35 -07:00
parent db8eb1c97c
commit 0da11ffe01
10 changed files with 590 additions and 301 deletions

View File

@ -97,8 +97,10 @@ impl LineSegmentF32 {
let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw()); let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw());
let d_d = to_to - from_from; let d_d = to_to - from_from;
let mid_mid = from_from + d_d * F32x4::splat(t); let mid_mid = from_from + d_d * F32x4::splat(t);
(LineSegmentF32(from_from.concat_xy_xy(mid_mid)), (
LineSegmentF32(mid_mid.concat_xy_xy(to_to))) LineSegmentF32(from_from.concat_xy_xy(mid_mid)),
LineSegmentF32(mid_mid.concat_xy_xy(to_to)),
)
} }
// Returns the left segment first, followed by the right segment. // Returns the left segment first, followed by the right segment.
@ -248,7 +250,12 @@ impl LineSegmentF32 {
if self.is_zero_length() { if self.is_zero_length() {
*self *self
} else { } else {
*self + self.vector().yx().normalize().scale_xy(Point2DF32::new(-distance, distance)) *self
+ self
.vector()
.yx()
.normalize()
.scale_xy(Point2DF32::new(-distance, distance))
} }
} }

View File

@ -55,13 +55,19 @@ impl RectF32 {
#[inline] #[inline]
pub fn contains_point(&self, point: Point2DF32) -> bool { pub fn contains_point(&self, point: Point2DF32) -> bool {
// self.origin <= point && point <= self.lower_right // self.origin <= point && point <= self.lower_right
self.0.concat_xy_xy(point.0).packed_le(point.0.concat_xy_zw(self.0)).is_all_ones() self.0
.concat_xy_xy(point.0)
.packed_le(point.0.concat_xy_zw(self.0))
.is_all_ones()
} }
#[inline] #[inline]
pub fn contains_rect(&self, other: RectF32) -> bool { pub fn contains_rect(&self, other: RectF32) -> bool {
// self.origin <= other.origin && other.lower_right <= self.lower_right // self.origin <= other.origin && other.lower_right <= self.lower_right
self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).is_all_ones() self.0
.concat_xy_zw(other.0)
.packed_le(other.0.concat_xy_zw(self.0))
.is_all_ones()
} }
#[inline] #[inline]
@ -76,14 +82,19 @@ impl RectF32 {
#[inline] #[inline]
pub fn union_rect(&self, other: RectF32) -> RectF32 { pub fn union_rect(&self, other: RectF32) -> RectF32 {
RectF32::from_points(self.origin().min(other.origin()), RectF32::from_points(
self.lower_right().max(other.lower_right())) self.origin().min(other.origin()),
self.lower_right().max(other.lower_right()),
)
} }
#[inline] #[inline]
pub fn intersects(&self, other: RectF32) -> bool { pub fn intersects(&self, other: RectF32) -> bool {
// self.origin < other.lower_right && other.origin < self.lower_right // self.origin < other.lower_right && other.origin < self.lower_right
self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).is_all_ones() self.0
.concat_xy_xy(other.0)
.packed_lt(other.0.concat_zw_zw(self.0))
.is_all_ones()
} }
#[inline] #[inline]
@ -91,8 +102,10 @@ impl RectF32 {
if !self.intersects(other) { if !self.intersects(other) {
None None
} else { } else {
Some(RectF32::from_points(self.origin().max(other.origin()), Some(RectF32::from_points(
self.lower_right().min(other.lower_right()))) self.origin().max(other.origin()),
self.lower_right().min(other.lower_right()),
))
} }
} }
@ -200,7 +213,10 @@ impl RectI32 {
pub fn contains_point(&self, point: Point2DI32) -> bool { pub fn contains_point(&self, point: Point2DI32) -> bool {
// self.origin <= point && point <= self.lower_right - 1 // self.origin <= point && point <= self.lower_right - 1
let lower_right = self.lower_right() - Point2DI32::splat(1); let lower_right = self.lower_right() - Point2DI32::splat(1);
self.0.concat_xy_xy(point.0).packed_le(point.0.concat_xy_xy(lower_right.0)).is_all_ones() self.0
.concat_xy_xy(point.0)
.packed_le(point.0.concat_xy_xy(lower_right.0))
.is_all_ones()
} }
#[inline] #[inline]

View File

@ -82,13 +82,21 @@ impl Matrix2x2F32 {
} }
#[inline] #[inline]
pub fn m11(&self) -> f32 { self.0[0] } pub fn m11(&self) -> f32 {
self.0[0]
}
#[inline] #[inline]
pub fn m21(&self) -> f32 { self.0[1] } pub fn m21(&self) -> f32 {
self.0[1]
}
#[inline] #[inline]
pub fn m12(&self) -> f32 { self.0[2] } pub fn m12(&self) -> f32 {
self.0[2]
}
#[inline] #[inline]
pub fn m22(&self) -> f32 { self.0[3] } pub fn m22(&self) -> f32 {
self.0[3]
}
} }
impl Sub<Matrix2x2F32> for Matrix2x2F32 { impl Sub<Matrix2x2F32> for Matrix2x2F32 {
@ -140,16 +148,20 @@ impl Transform2DF32 {
} }
#[inline] #[inline]
pub fn from_scale_rotation_translation(scale: Point2DF32, theta: f32, translation: Point2DF32) pub fn from_scale_rotation_translation(
-> Transform2DF32 { scale: Point2DF32,
theta: f32,
translation: Point2DF32,
) -> Transform2DF32 {
let rotation = Transform2DF32::from_rotation(theta); let rotation = Transform2DF32::from_rotation(theta);
let translation = Transform2DF32::from_translation(&translation); let translation = Transform2DF32::from_translation(&translation);
Transform2DF32::from_scale(&scale).post_mul(&rotation).post_mul(&translation) Transform2DF32::from_scale(&scale)
.post_mul(&rotation)
.post_mul(&translation)
} }
#[inline] #[inline]
pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2DF32 {
-> Transform2DF32 {
Transform2DF32 { Transform2DF32 {
matrix: Matrix2x2F32::row_major(m11, m12, m21, m22), matrix: Matrix2x2F32::row_major(m11, m12, m21, m22),
vector: Point2DF32::new(m31, m32), vector: Point2DF32::new(m31, m32),
@ -187,10 +199,24 @@ impl Transform2DF32 {
// TODO(pcwalton): Optimize better with SIMD. // TODO(pcwalton): Optimize better with SIMD.
#[inline] #[inline]
pub fn to_3d(&self) -> Transform3DF32 { pub fn to_3d(&self) -> Transform3DF32 {
Transform3DF32::row_major(self.matrix.0[0], self.matrix.0[1], 0.0, self.vector.x(), Transform3DF32::row_major(
self.matrix.0[2], self.matrix.0[3], 0.0, self.vector.y(), self.matrix.0[0],
0.0, 0.0, 0.0, 0.0, self.matrix.0[1],
0.0, 0.0, 0.0, 1.0) 0.0,
self.vector.x(),
self.matrix.0[2],
self.matrix.0[3],
0.0,
self.vector.y(),
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
)
} }
#[inline] #[inline]
@ -199,13 +225,21 @@ impl Transform2DF32 {
} }
#[inline] #[inline]
pub fn m11(&self) -> f32 { self.matrix.m11() } pub fn m11(&self) -> f32 {
self.matrix.m11()
}
#[inline] #[inline]
pub fn m21(&self) -> f32 { self.matrix.m21() } pub fn m21(&self) -> f32 {
self.matrix.m21()
}
#[inline] #[inline]
pub fn m12(&self) -> f32 { self.matrix.m12() } pub fn m12(&self) -> f32 {
self.matrix.m12()
}
#[inline] #[inline]
pub fn m22(&self) -> f32 { self.matrix.m22() } pub fn m22(&self) -> f32 {
self.matrix.m22()
}
#[inline] #[inline]
pub fn post_translate(&self, vector: Point2DF32) -> Transform2DF32 { pub fn post_translate(&self, vector: Point2DF32) -> Transform2DF32 {

View File

@ -43,11 +43,24 @@ impl Default for Transform3DF32 {
impl Transform3DF32 { impl Transform3DF32 {
#[inline] #[inline]
pub fn row_major(m00: f32, m01: f32, m02: f32, m03: f32, pub fn row_major(
m10: f32, m11: f32, m12: f32, m13: f32, m00: f32,
m20: f32, m21: f32, m22: f32, m23: f32, m01: f32,
m30: f32, m31: f32, m32: f32, m33: f32) m02: f32,
-> Transform3DF32 { m03: f32,
m10: f32,
m11: f32,
m12: f32,
m13: f32,
m20: f32,
m21: f32,
m22: f32,
m23: f32,
m30: f32,
m31: f32,
m32: f32,
m33: f32,
) -> Transform3DF32 {
Transform3DF32 { Transform3DF32 {
c0: F32x4::new(m00, m10, m20, m30), c0: F32x4::new(m00, m10, m20, m30),
c1: F32x4::new(m01, m11, m21, m31), c1: F32x4::new(m01, m11, m21, m31),
@ -58,10 +71,9 @@ impl Transform3DF32 {
#[inline] #[inline]
pub fn from_scale(x: f32, y: f32, z: f32) -> Transform3DF32 { pub fn from_scale(x: f32, y: f32, z: f32) -> Transform3DF32 {
Transform3DF32::row_major( x, 0.0, 0.0, 0.0, Transform3DF32::row_major(
0.0, y, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, z, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0, 0.0, z, 0.0, )
0.0, 0.0, 0.0, 1.0)
} }
#[inline] #[inline]
@ -71,17 +83,16 @@ impl Transform3DF32 {
#[inline] #[inline]
pub fn from_translation(x: f32, y: f32, z: f32) -> Transform3DF32 { pub fn from_translation(x: f32, y: f32, z: f32) -> Transform3DF32 {
Transform3DF32::row_major(1.0, 0.0, 0.0, x, Transform3DF32::row_major(
0.0, 1.0, 0.0, y, 1.0, 0.0, 0.0, x, 0.0, 1.0, 0.0, y, 0.0, 0.0, 1.0, z, 0.0, 0.0, 0.0, 1.0,
0.0, 0.0, 1.0, z, )
0.0, 0.0, 0.0, 1.0)
} }
// TODO(pcwalton): Optimize. // TODO(pcwalton): Optimize.
pub fn from_rotation(yaw: f32, pitch: f32, roll: f32) -> Transform3DF32 { pub fn from_rotation(yaw: f32, pitch: f32, roll: f32) -> Transform3DF32 {
let (cos_b, sin_b) = (yaw.cos(), yaw.sin()); let (cos_b, sin_b) = (yaw.cos(), yaw.sin());
let (cos_c, sin_c) = (pitch.cos(), pitch.sin()); let (cos_c, sin_c) = (pitch.cos(), pitch.sin());
let (cos_a, sin_a) = (roll.cos(), roll.sin()); let (cos_a, sin_a) = (roll.cos(), roll.sin());
let m00 = cos_a * cos_b; let m00 = cos_a * cos_b;
let m01 = cos_a * sin_b * sin_c - sin_a * cos_c; let m01 = cos_a * sin_b * sin_c - sin_a * cos_c;
let m02 = cos_a * sin_b * cos_c + sin_a * sin_c; let m02 = cos_a * sin_b * cos_c + sin_a * sin_c;
@ -91,10 +102,9 @@ impl Transform3DF32 {
let m20 = -sin_b; let m20 = -sin_b;
let m21 = cos_b * sin_c; let m21 = cos_b * sin_c;
let m22 = cos_b * cos_c; let m22 = cos_b * cos_c;
Transform3DF32::row_major(m00, m01, m02, 0.0, Transform3DF32::row_major(
m10, m11, m12, 0.0, m00, m01, m02, 0.0, m10, m11, m12, 0.0, m20, m21, m22, 0.0, 0.0, 0.0, 0.0, 1.0,
m20, m21, m22, 0.0, )
0.0, 0.0, 0.0, 1.0)
} }
/// Creates a rotation matrix from the given quaternion. /// Creates a rotation matrix from the given quaternion.
@ -104,30 +114,66 @@ impl Transform3DF32 {
pub fn from_rotation_quaternion(q: F32x4) -> Transform3DF32 { pub fn from_rotation_quaternion(q: F32x4) -> Transform3DF32 {
// TODO(pcwalton): Optimize better with more shuffles. // TODO(pcwalton): Optimize better with more shuffles.
let (mut sq, mut w, mut xy_xz_yz) = (q * q, q.wwww() * q, q.xxyy() * q.yzzy()); let (mut sq, mut w, mut xy_xz_yz) = (q * q, q.wwww() * q, q.xxyy() * q.yzzy());
sq += sq; w += w; xy_xz_yz += xy_xz_yz; sq += sq;
w += w;
xy_xz_yz += xy_xz_yz;
let diag = F32x4::splat(1.0) - (sq.yxxy() + sq.zzyy()); let diag = F32x4::splat(1.0) - (sq.yxxy() + sq.zzyy());
let (wx2, wy2, wz2) = (w.x(), w.y(), w.z()); let (wx2, wy2, wz2) = (w.x(), w.y(), w.z());
let (xy2, xz2, yz2) = (xy_xz_yz.x(), xy_xz_yz.y(), xy_xz_yz.z()); let (xy2, xz2, yz2) = (xy_xz_yz.x(), xy_xz_yz.y(), xy_xz_yz.z());
Transform3DF32::row_major(diag.x(), xy2 - wz2, xz2 + wy2, 0.0, Transform3DF32::row_major(
xy2 + wz2, diag.y(), yz2 - wx2, 0.0, diag.x(),
xz2 - wy2, yz2 + wx2, diag.z(), 0.0, xy2 - wz2,
0.0, 0.0, 0.0, 1.0) xz2 + wy2,
0.0,
xy2 + wz2,
diag.y(),
yz2 - wx2,
0.0,
xz2 - wy2,
yz2 + wx2,
diag.z(),
0.0,
0.0,
0.0,
0.0,
1.0,
)
} }
/// Just like `glOrtho()`. /// Just like `glOrtho()`.
#[inline] #[inline]
pub fn from_ortho(left: f32, right: f32, bottom: f32, top: f32, near_val: f32, far_val: f32) pub fn from_ortho(
-> Transform3DF32 { left: f32,
right: f32,
bottom: f32,
top: f32,
near_val: f32,
far_val: f32,
) -> Transform3DF32 {
let x_inv = 1.0 / (right - left); let x_inv = 1.0 / (right - left);
let y_inv = 1.0 / (top - bottom); let y_inv = 1.0 / (top - bottom);
let z_inv = 1.0 / (far_val - near_val); let z_inv = 1.0 / (far_val - near_val);
let tx = -(right + left) * x_inv; let tx = -(right + left) * x_inv;
let ty = -(top + bottom) * y_inv; let ty = -(top + bottom) * y_inv;
let tz = -(far_val + near_val) * z_inv; let tz = -(far_val + near_val) * z_inv;
Transform3DF32::row_major(2.0 * x_inv, 0.0, 0.0, tx, Transform3DF32::row_major(
0.0, 2.0 * y_inv, 0.0, ty, 2.0 * x_inv,
0.0, 0.0, -2.0 * z_inv, tz, 0.0,
0.0, 0.0, 0.0, 1.0) 0.0,
tx,
0.0,
2.0 * y_inv,
0.0,
ty,
0.0,
0.0,
-2.0 * z_inv,
tz,
0.0,
0.0,
0.0,
1.0,
)
} }
/// Just like `gluPerspective()`. /// Just like `gluPerspective()`.
@ -140,10 +186,9 @@ impl Transform3DF32 {
let m22 = (z_far + z_near) * z_denom; let m22 = (z_far + z_near) * z_denom;
let m23 = 2.0 * z_far * z_near * z_denom; let m23 = 2.0 * z_far * z_near * z_denom;
let m32 = -1.0; let m32 = -1.0;
Transform3DF32::row_major(m00, 0.0, 0.0, 0.0, Transform3DF32::row_major(
0.0, m11, 0.0, 0.0, m00, 0.0, 0.0, 0.0, 0.0, m11, 0.0, 0.0, 0.0, 0.0, m22, m23, 0.0, 0.0, m32, 0.0,
0.0, 0.0, m22, m23, )
0.0, 0.0, m32, 0.0)
} }
// +- -+ // +- -+
@ -151,8 +196,12 @@ impl Transform3DF32 {
// | C D | // | C D |
// +- -+ // +- -+
#[inline] #[inline]
pub fn from_submatrices(a: Matrix2x2F32, b: Matrix2x2F32, c: Matrix2x2F32, d: Matrix2x2F32) pub fn from_submatrices(
-> Transform3DF32 { a: Matrix2x2F32,
b: Matrix2x2F32,
c: Matrix2x2F32,
d: Matrix2x2F32,
) -> Transform3DF32 {
Transform3DF32 { Transform3DF32 {
c0: a.0.concat_xy_xy(c.0), c0: a.0.concat_xy_xy(c.0),
c1: a.0.concat_zw_zw(c.0), c1: a.0.concat_zw_zw(c.0),
@ -232,17 +281,17 @@ impl Transform3DF32 {
// Compute new submatrices. // Compute new submatrices.
let (a_new, b_new) = (a_inv + z.post_mul(&y).post_mul(&x), (-z).post_mul(&y)); let (a_new, b_new) = (a_inv + z.post_mul(&y).post_mul(&x), (-z).post_mul(&y));
let (c_new, d_new) = ((-y).post_mul(&x), y); let (c_new, d_new) = ((-y).post_mul(&x), y);
// Construct inverse. // Construct inverse.
Transform3DF32::from_submatrices(a_new, b_new, c_new, d_new) Transform3DF32::from_submatrices(a_new, b_new, c_new, d_new)
} }
pub fn approx_eq(&self, other: &Transform3DF32, epsilon: f32) -> bool { pub fn approx_eq(&self, other: &Transform3DF32, epsilon: f32) -> bool {
self.c0.approx_eq(other.c0, epsilon) && self.c0.approx_eq(other.c0, epsilon)
self.c1.approx_eq(other.c1, epsilon) && && self.c1.approx_eq(other.c1, epsilon)
self.c2.approx_eq(other.c2, epsilon) && && self.c2.approx_eq(other.c2, epsilon)
self.c3.approx_eq(other.c3, epsilon) && self.c3.approx_eq(other.c3, epsilon)
} }
#[inline] #[inline]
@ -276,15 +325,20 @@ pub struct Perspective {
impl Perspective { impl Perspective {
#[inline] #[inline]
pub fn new(transform: &Transform3DF32, window_size: Point2DI32) -> Perspective { pub fn new(transform: &Transform3DF32, window_size: Point2DI32) -> Perspective {
Perspective { transform: *transform, window_size } Perspective {
transform: *transform,
window_size,
}
} }
#[inline] #[inline]
pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 { pub fn transform_point_2d(&self, point: &Point2DF32) -> Point2DF32 {
let point = self.transform let point = self
.transform_point(point.to_3d()) .transform
.perspective_divide() .transform_point(point.to_3d())
.to_2d() * Point2DF32::new(1.0, -1.0); .perspective_divide()
.to_2d()
* Point2DF32::new(1.0, -1.0);
(point + Point2DF32::splat(1.0)) * self.window_size.to_f32().scale(0.5) (point + Point2DF32::splat(1.0)) * self.window_size.to_f32().scale(0.5)
} }
@ -328,13 +382,22 @@ where
fn next(&mut self) -> Option<Segment> { fn next(&mut self) -> Option<Segment> {
let mut segment = self.iter.next()?; let mut segment = self.iter.next()?;
if !segment.is_none() { if !segment.is_none() {
segment.baseline.set_from(&self.perspective segment.baseline.set_from(
.transform_point_2d(&segment.baseline.from())); &self
segment.baseline.set_to(&self.perspective.transform_point_2d(&segment.baseline.to())); .perspective
.transform_point_2d(&segment.baseline.from()),
);
segment
.baseline
.set_to(&self.perspective.transform_point_2d(&segment.baseline.to()));
if !segment.is_line() { if !segment.is_line() {
segment.ctrl.set_from(&self.perspective.transform_point_2d(&segment.ctrl.from())); segment
.ctrl
.set_from(&self.perspective.transform_point_2d(&segment.ctrl.from()));
if !segment.is_quadratic() { if !segment.is_quadratic() {
segment.ctrl.set_to(&self.perspective.transform_point_2d(&segment.ctrl.to())); segment
.ctrl
.set_to(&self.perspective.transform_point_2d(&segment.ctrl.to()));
} }
} }
} }
@ -348,7 +411,10 @@ where
{ {
#[inline] #[inline]
pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter<I> { pub fn new(iter: I, perspective: &Perspective) -> PerspectivePathIter<I> {
PerspectivePathIter { iter, perspective: *perspective } PerspectivePathIter {
iter,
perspective: *perspective,
}
} }
} }
@ -359,44 +425,39 @@ mod test {
#[test] #[test]
fn test_post_mul() { fn test_post_mul() {
let a = Transform3DF32::row_major(3.0, 1.0, 4.0, 5.0, let a = Transform3DF32::row_major(
9.0, 2.0, 6.0, 5.0, 3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
3.0, 5.0, 8.0, 9.0, );
7.0, 9.0, 3.0, 2.0); let b = Transform3DF32::row_major(
let b = Transform3DF32::row_major(3.0, 8.0, 4.0, 6.0, 3.0, 8.0, 4.0, 6.0, 2.0, 6.0, 4.0, 3.0, 3.0, 8.0, 3.0, 2.0, 7.0, 9.0, 5.0, 0.0,
2.0, 6.0, 4.0, 3.0, );
3.0, 8.0, 3.0, 2.0, let c = Transform3DF32::row_major(
7.0, 9.0, 5.0, 0.0); 58.0, 107.0, 53.0, 29.0, 84.0, 177.0, 87.0, 72.0, 106.0, 199.0, 101.0, 49.0, 62.0,
let c = Transform3DF32::row_major(58.0, 107.0, 53.0, 29.0, 152.0, 83.0, 75.0,
84.0, 177.0, 87.0, 72.0, );
106.0, 199.0, 101.0, 49.0,
62.0, 152.0, 83.0, 75.0);
assert_eq!(a.post_mul(&b), c); assert_eq!(a.post_mul(&b), c);
} }
#[test] #[test]
fn test_pre_mul() { fn test_pre_mul() {
let a = Transform3DF32::row_major(3.0, 1.0, 4.0, 5.0, let a = Transform3DF32::row_major(
9.0, 2.0, 6.0, 5.0, 3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
3.0, 5.0, 8.0, 9.0, );
7.0, 9.0, 3.0, 2.0); let b = Transform3DF32::row_major(
let b = Transform3DF32::row_major(3.0, 8.0, 4.0, 6.0, 3.0, 8.0, 4.0, 6.0, 2.0, 6.0, 4.0, 3.0, 3.0, 8.0, 3.0, 2.0, 7.0, 9.0, 5.0, 0.0,
2.0, 6.0, 4.0, 3.0, );
3.0, 8.0, 3.0, 2.0, let c = Transform3DF32::row_major(
7.0, 9.0, 5.0, 0.0); 135.0, 93.0, 110.0, 103.0, 93.0, 61.0, 85.0, 82.0, 104.0, 52.0, 90.0, 86.0, 117.0,
let c = Transform3DF32::row_major(135.0, 93.0, 110.0, 103.0, 50.0, 122.0, 125.0,
93.0, 61.0, 85.0, 82.0, );
104.0, 52.0, 90.0, 86.0,
117.0, 50.0, 122.0, 125.0);
assert_eq!(a.pre_mul(&b), c); assert_eq!(a.pre_mul(&b), c);
} }
#[test] #[test]
fn test_transform_point() { fn test_transform_point() {
let a = Transform3DF32::row_major(3.0, 1.0, 4.0, 5.0, let a = Transform3DF32::row_major(
9.0, 2.0, 6.0, 5.0, 3.0, 1.0, 4.0, 5.0, 9.0, 2.0, 6.0, 5.0, 3.0, 5.0, 8.0, 9.0, 7.0, 9.0, 3.0, 2.0,
3.0, 5.0, 8.0, 9.0, );
7.0, 9.0, 3.0, 2.0);
let p = Point3DF32::new(3.0, 8.0, 4.0, 6.0); let p = Point3DF32::new(3.0, 8.0, 4.0, 6.0);
let q = Point3DF32::new(63.0, 97.0, 135.0, 117.0); let q = Point3DF32::new(63.0, 97.0, 135.0, 117.0);
assert_eq!(a.transform_point(p), q); assert_eq!(a.transform_point(p), q);
@ -405,18 +466,32 @@ mod test {
#[test] #[test]
fn test_inverse() { fn test_inverse() {
// Random matrix. // Random matrix.
let m = Transform3DF32::row_major(0.86277982, 0.15986552, 0.90739898, 0.60066808, let m = Transform3DF32::row_major(
0.17386167, 0.016353 , 0.8535783 , 0.12969608, 0.86277982, 0.15986552, 0.90739898, 0.60066808, 0.17386167, 0.016353, 0.8535783,
0.0946466 , 0.43248631, 0.63480505, 0.08154603, 0.12969608, 0.0946466, 0.43248631, 0.63480505, 0.08154603, 0.50305436, 0.48359687,
0.50305436, 0.48359687, 0.51057162, 0.24812012); 0.51057162, 0.24812012,
);
let p0 = Point3DF32::new(0.95536648, 0.80633691, 0.16357357, 0.5477598); let p0 = Point3DF32::new(0.95536648, 0.80633691, 0.16357357, 0.5477598);
let p1 = m.transform_point(p0); let p1 = m.transform_point(p0);
let m_inv = m.inverse(); let m_inv = m.inverse();
let m_inv_exp = let m_inv_exp = Transform3DF32::row_major(
Transform3DF32::row_major(-2.47290136 , 3.48865688, -6.12298336 , 6.17536696 , -2.47290136,
0.00124033357, -1.72561993, 2.16876606 , 0.186227748, 3.48865688,
-0.375021729 , 1.53883017, -0.0558194403, 0.121857058, -6.12298336,
5.78300323 , -6.87635769, 8.30196620 , -9.10374060); 6.17536696,
0.00124033357,
-1.72561993,
2.16876606,
0.186227748,
-0.375021729,
1.53883017,
-0.0558194403,
0.121857058,
5.78300323,
-6.87635769,
8.30196620,
-9.10374060,
);
assert!(m_inv.approx_eq(&m_inv_exp, 0.0001)); assert!(m_inv.approx_eq(&m_inv_exp, 0.0001));
let p2 = m_inv.transform_point(p1); let p2 = m_inv.transform_point(p1);
assert!(p0.approx_eq(&p2, 0.0001)); assert!(p0.approx_eq(&p2, 0.0001));

View File

@ -53,9 +53,9 @@ impl TEdge for AxisAlignedEdge {
#[inline] #[inline]
fn point_is_inside(&self, point: &Point2DF32) -> bool { fn point_is_inside(&self, point: &Point2DF32) -> bool {
match *self { match *self {
AxisAlignedEdge::Left(x) => point.x() >= x, AxisAlignedEdge::Left(x) => point.x() >= x,
AxisAlignedEdge::Top(y) => point.y() >= y, AxisAlignedEdge::Top(y) => point.y() >= y,
AxisAlignedEdge::Right(x) => point.x() <= x, AxisAlignedEdge::Right(x) => point.x() <= x,
AxisAlignedEdge::Bottom(y) => point.y() <= y, AxisAlignedEdge::Bottom(y) => point.y() <= y,
} }
} }
@ -63,8 +63,8 @@ impl TEdge for AxisAlignedEdge {
fn intersect_line_segment(&self, segment: &LineSegmentF32) -> ArrayVec<[f32; 3]> { fn intersect_line_segment(&self, segment: &LineSegmentF32) -> ArrayVec<[f32; 3]> {
let mut results = ArrayVec::new(); let mut results = ArrayVec::new();
let t = match *self { let t = match *self {
AxisAlignedEdge::Left(x) | AxisAlignedEdge::Right(x) => segment.solve_t_for_x(x), AxisAlignedEdge::Left(x) | AxisAlignedEdge::Right(x) => segment.solve_t_for_x(x),
AxisAlignedEdge::Top(y) | AxisAlignedEdge::Bottom(y) => segment.solve_t_for_y(y), AxisAlignedEdge::Top(y) | AxisAlignedEdge::Bottom(y) => segment.solve_t_for_y(y),
}; };
if t >= 0.0 && t <= 1.0 { if t >= 0.0 && t <= 1.0 {
results.push(t); results.push(t);
@ -79,7 +79,12 @@ trait TEdge: Debug {
fn trivially_test_segment(&self, segment: &Segment) -> EdgeRelativeLocation { fn trivially_test_segment(&self, segment: &Segment) -> EdgeRelativeLocation {
let from_inside = self.point_is_inside(&segment.baseline.from()); let from_inside = self.point_is_inside(&segment.baseline.from());
debug!("point {:?} inside {:?}: {:?}", segment.baseline.from(), self, from_inside); debug!(
"point {:?} inside {:?}: {:?}",
segment.baseline.from(),
self,
from_inside
);
if from_inside != self.point_is_inside(&segment.baseline.to()) { if from_inside != self.point_is_inside(&segment.baseline.to()) {
return EdgeRelativeLocation::Intersecting; return EdgeRelativeLocation::Intersecting;
} }
@ -93,7 +98,11 @@ trait TEdge: Debug {
} }
} }
} }
if from_inside { EdgeRelativeLocation::Inside } else { EdgeRelativeLocation::Outside } if from_inside {
EdgeRelativeLocation::Inside
} else {
EdgeRelativeLocation::Outside
}
} }
fn intersect_segment(&self, segment: &Segment) -> ArrayVec<[f32; 3]> { fn intersect_segment(&self, segment: &Segment) -> ArrayVec<[f32; 3]> {
@ -110,7 +119,7 @@ trait TEdge: Debug {
let mut prev_t = 0.0; let mut prev_t = 0.0;
while !results.is_full() { while !results.is_full() {
if prev_t >= 1.0 { if prev_t >= 1.0 {
break break;
} }
let next_t = match self.intersect_cubic_segment(&segment, prev_t, 1.0) { let next_t = match self.intersect_cubic_segment(&segment, prev_t, 1.0) {
None => break, None => break,
@ -124,15 +133,24 @@ trait TEdge: Debug {
const EPSILON: f32 = 0.0001; const EPSILON: f32 = 0.0001;
} }
fn intersect_cubic_segment(&self, segment: &Segment, mut t_min: f32, mut t_max: f32) fn intersect_cubic_segment(
-> Option<f32> { &self,
debug!("... intersect_cubic_segment({:?}, {:?}, t=({}, {}))", self, segment, t_min, t_max); segment: &Segment,
mut t_min: f32,
mut t_max: f32,
) -> Option<f32> {
debug!(
"... intersect_cubic_segment({:?}, {:?}, t=({}, {}))",
self, segment, t_min, t_max
);
let mut segment = segment.as_cubic_segment().split_after(t_min); let mut segment = segment.as_cubic_segment().split_after(t_min);
segment = segment.as_cubic_segment().split_before(t_max / (1.0 - t_min)); segment = segment
.as_cubic_segment()
.split_before(t_max / (1.0 - t_min));
if !self.intersects_cubic_segment_hull(segment.as_cubic_segment()) { if !self.intersects_cubic_segment_hull(segment.as_cubic_segment()) {
return None return None;
} }
loop { loop {
@ -156,13 +174,16 @@ trait TEdge: Debug {
fn intersects_cubic_segment_hull(&self, cubic_segment: CubicSegment) -> bool { fn intersects_cubic_segment_hull(&self, cubic_segment: CubicSegment) -> bool {
let inside = self.point_is_inside(&cubic_segment.0.baseline.from()); let inside = self.point_is_inside(&cubic_segment.0.baseline.from());
inside != self.point_is_inside(&cubic_segment.0.ctrl.from()) || inside != self.point_is_inside(&cubic_segment.0.ctrl.from())
inside != self.point_is_inside(&cubic_segment.0.ctrl.to()) || || inside != self.point_is_inside(&cubic_segment.0.ctrl.to())
inside != self.point_is_inside(&cubic_segment.0.baseline.to()) || inside != self.point_is_inside(&cubic_segment.0.baseline.to())
} }
} }
trait ContourClipper where Self::Edge: TEdge + Debug { trait ContourClipper
where
Self::Edge: TEdge + Debug,
{
type Edge; type Edge;
fn contour_mut(&mut self) -> &mut Contour; fn contour_mut(&mut self) -> &mut Contour;
@ -209,11 +230,10 @@ trait ContourClipper where Self::Edge: TEdge + Debug {
let (before_split, after_split) = segment.split((t - last_t) / (1.0 - last_t)); let (before_split, after_split) = segment.split((t - last_t) / (1.0 - last_t));
// Push the split segment if appropriate. // Push the split segment if appropriate.
debug!("... ... edge={:?} before_split={:?} t={:?} starts_inside={:?}", debug!(
edge, "... ... edge={:?} before_split={:?} t={:?} starts_inside={:?}",
before_split, edge, before_split, t, starts_inside
t, );
starts_inside);
if starts_inside { if starts_inside {
debug!("... split segment case, pushing segment"); debug!("... split segment case, pushing segment");
self.push_segment(&before_split); self.push_segment(&before_split);
@ -255,8 +275,8 @@ trait ContourClipper where Self::Edge: TEdge + Debug {
(None, EdgeRelativeLocation::Inside) => { (None, EdgeRelativeLocation::Inside) => {
result = Some(FastClipResult::AllInside); result = Some(FastClipResult::AllInside);
} }
(Some(FastClipResult::AllInside), EdgeRelativeLocation::Inside) | (Some(FastClipResult::AllInside), EdgeRelativeLocation::Inside)
(Some(FastClipResult::AllOutside), EdgeRelativeLocation::Outside) => {} | (Some(FastClipResult::AllOutside), EdgeRelativeLocation::Outside) => {}
(_, _) => return FastClipResult::SlowPath, (_, _) => return FastClipResult::SlowPath,
} }
} }
@ -290,7 +310,10 @@ impl ContourClipper for ContourPolygonClipper {
impl ContourPolygonClipper { impl ContourPolygonClipper {
#[inline] #[inline]
pub(crate) fn new(clip_polygon: &[Point2DF32], contour: Contour) -> ContourPolygonClipper { pub(crate) fn new(clip_polygon: &[Point2DF32], contour: Contour) -> ContourPolygonClipper {
ContourPolygonClipper { clip_polygon: SmallVec::from_slice(clip_polygon), contour } ContourPolygonClipper {
clip_polygon: SmallVec::from_slice(clip_polygon),
contour,
}
} }
pub(crate) fn clip(mut self) -> Contour { pub(crate) fn clip(mut self) -> Contour {
@ -341,7 +364,7 @@ impl ContourRectClipper {
pub(crate) fn clip(mut self) -> Contour { pub(crate) fn clip(mut self) -> Contour {
if self.clip_rect.contains_rect(self.contour.bounds()) { if self.clip_rect.contains_rect(self.contour.bounds()) {
return self.contour return self.contour;
} }
self.clip_against(AxisAlignedEdge::Left(self.clip_rect.min_x())); self.clip_against(AxisAlignedEdge::Left(self.clip_rect.min_x()));
@ -412,7 +435,7 @@ enum Edge3D {
Bottom, Bottom,
Top, Top,
Near, Near,
Far Far,
} }
impl Edge3D { impl Edge3D {
@ -420,23 +443,26 @@ impl Edge3D {
fn point_is_inside(self, point: Point3DF32) -> bool { fn point_is_inside(self, point: Point3DF32) -> bool {
let w = point.w(); let w = point.w();
match self { match self {
Edge3D::Left => point.x() >= -w, Edge3D::Right => point.x() <= w, Edge3D::Left => point.x() >= -w,
Edge3D::Bottom => point.y() >= -w, Edge3D::Top => point.y() <= w, Edge3D::Right => point.x() <= w,
Edge3D::Near => point.z() >= -w, Edge3D::Far => point.z() <= w, Edge3D::Bottom => point.y() >= -w,
Edge3D::Top => point.y() <= w,
Edge3D::Near => point.z() >= -w,
Edge3D::Far => point.z() <= w,
} }
} }
// Blinn & Newell, "Clipping using homogeneous coordinates", SIGGRAPH 1978. // Blinn & Newell, "Clipping using homogeneous coordinates", SIGGRAPH 1978.
fn line_intersection(self, prev: Point3DF32, next: Point3DF32) -> Point3DF32 { fn line_intersection(self, prev: Point3DF32, next: Point3DF32) -> Point3DF32 {
let (x0, x1) = match self { let (x0, x1) = match self {
Edge3D::Left | Edge3D::Right => (prev.x(), next.x()), Edge3D::Left | Edge3D::Right => (prev.x(), next.x()),
Edge3D::Bottom | Edge3D::Top => (prev.y(), next.y()), Edge3D::Bottom | Edge3D::Top => (prev.y(), next.y()),
Edge3D::Near | Edge3D::Far => (prev.z(), next.z()), Edge3D::Near | Edge3D::Far => (prev.z(), next.z()),
}; };
let (w0, w1) = (prev.w(), next.w()); let (w0, w1) = (prev.w(), next.w());
let sign = match self { let sign = match self {
Edge3D::Left | Edge3D::Bottom | Edge3D::Near => -1.0, Edge3D::Left | Edge3D::Bottom | Edge3D::Near => -1.0,
Edge3D::Right | Edge3D::Top | Edge3D::Far => 1.0, Edge3D::Right | Edge3D::Top | Edge3D::Far => 1.0,
}; };
let alpha = ((x0 - sign * w0) as f64) / ((sign * (w1 - w0) - (x1 - x0)) as f64); let alpha = ((x0 - sign * w0) as f64) / ((sign * (w1 - w0) - (x1 - x0)) as f64);
prev.lerp(next, alpha as f32) prev.lerp(next, alpha as f32)
@ -449,17 +475,30 @@ impl Edge3D {
pub(crate) fn rect_is_outside_polygon(rect: RectF32, polygon_points: &[Point2DF32]) -> bool { pub(crate) fn rect_is_outside_polygon(rect: RectF32, polygon_points: &[Point2DF32]) -> bool {
let mut outcode = Outcode::all(); let mut outcode = Outcode::all();
for point in polygon_points { for point in polygon_points {
if point.x() > rect.min_x() { outcode.remove(Outcode::LEFT); } if point.x() > rect.min_x() {
if point.x() < rect.max_x() { outcode.remove(Outcode::RIGHT); } outcode.remove(Outcode::LEFT);
if point.y() > rect.min_y() { outcode.remove(Outcode::TOP); } }
if point.y() < rect.max_y() { outcode.remove(Outcode::BOTTOM); } if point.x() < rect.max_x() {
outcode.remove(Outcode::RIGHT);
}
if point.y() > rect.min_y() {
outcode.remove(Outcode::TOP);
}
if point.y() < rect.max_y() {
outcode.remove(Outcode::BOTTOM);
}
} }
if !outcode.is_empty() { if !outcode.is_empty() {
return true return true;
} }
// FIXME(pcwalton): Check winding! // FIXME(pcwalton): Check winding!
let rect_points = [rect.origin(), rect.upper_right(), rect.lower_left(), rect.lower_right()]; let rect_points = [
rect.origin(),
rect.upper_right(),
rect.lower_left(),
rect.lower_right(),
];
for (next_point_index, &next) in polygon_points.iter().enumerate() { for (next_point_index, &next) in polygon_points.iter().enumerate() {
let prev_point_index = if next_point_index == 0 { let prev_point_index = if next_point_index == 0 {
polygon_points.len() - 1 polygon_points.len() - 1
@ -468,8 +507,11 @@ pub(crate) fn rect_is_outside_polygon(rect: RectF32, polygon_points: &[Point2DF3
}; };
let prev = polygon_points[prev_point_index]; let prev = polygon_points[prev_point_index];
let polygon_edge_vector = next - prev; let polygon_edge_vector = next - prev;
if rect_points.iter().all(|&rect_point| polygon_edge_vector.det(rect_point - prev) < 0.0) { if rect_points
return true .iter()
.all(|&rect_point| polygon_edge_vector.det(rect_point - prev) < 0.0)
{
return true;
} }
} }
@ -479,7 +521,12 @@ pub(crate) fn rect_is_outside_polygon(rect: RectF32, polygon_points: &[Point2DF3
// Edge equation method. Requires that the polygon be convex. // Edge equation method. Requires that the polygon be convex.
pub(crate) fn rect_is_inside_polygon(rect: RectF32, polygon_points: &[Point2DF32]) -> bool { pub(crate) fn rect_is_inside_polygon(rect: RectF32, polygon_points: &[Point2DF32]) -> bool {
// FIXME(pcwalton): Check winding! // FIXME(pcwalton): Check winding!
let rect_points = [rect.origin(), rect.upper_right(), rect.lower_left(), rect.lower_right()]; let rect_points = [
rect.origin(),
rect.upper_right(),
rect.lower_left(),
rect.lower_right(),
];
for (next_point_index, &next) in polygon_points.iter().enumerate() { for (next_point_index, &next) in polygon_points.iter().enumerate() {
let prev_point_index = if next_point_index == 0 { let prev_point_index = if next_point_index == 0 {
polygon_points.len() - 1 polygon_points.len() - 1

View File

@ -42,12 +42,14 @@ impl Debug for ColorU {
if self.a == 255 { if self.a == 255 {
write!(formatter, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b) write!(formatter, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b)
} else { } else {
write!(formatter, write!(
"rgba({}, {}, {}, {})", formatter,
self.r, "rgba({}, {}, {}, {})",
self.g, self.r,
self.b, self.g,
self.a as f32 / 255.0) self.b,
self.a as f32 / 255.0
)
} }
} }
} }

View File

@ -19,16 +19,23 @@ pub struct ContourDilator<'a> {
} }
impl<'a> ContourDilator<'a> { impl<'a> ContourDilator<'a> {
pub fn new(contour: &'a mut Contour, amount: Point2DF32, orientation: Orientation) pub fn new(
-> ContourDilator<'a> { contour: &'a mut Contour,
ContourDilator { contour, amount, orientation } amount: Point2DF32,
orientation: Orientation,
) -> ContourDilator<'a> {
ContourDilator {
contour,
amount,
orientation,
}
} }
pub fn dilate(&mut self) { pub fn dilate(&mut self) {
// Determine orientation. // Determine orientation.
let scale = self.amount.scale_xy(match self.orientation { let scale = self.amount.scale_xy(match self.orientation {
Orientation::Ccw => Point2DF32::new( 1.0, -1.0), Orientation::Ccw => Point2DF32::new(1.0, -1.0),
Orientation::Cw => Point2DF32::new(-1.0, 1.0), Orientation::Cw => Point2DF32::new(-1.0, 1.0),
}); });
// Find the starting and previous positions. // Find the starting and previous positions.
@ -68,10 +75,10 @@ impl<'a> ContourDilator<'a> {
} }
let next_vector = (next_position - position).normalize(); let next_vector = (next_position - position).normalize();
debug!("prev={} cur={} next={}", debug!(
prev_point_index, "prev={} cur={} next={}",
current_point_index, prev_point_index, current_point_index, next_point_index
next_point_index); );
// Calculate new position by moving the point by the bisector. // Calculate new position by moving the point by the bisector.
let bisector = prev_vector.yx() + next_vector.yx(); let bisector = prev_vector.yx() + next_vector.yx();
@ -83,16 +90,18 @@ impl<'a> ContourDilator<'a> {
}; };
let new_position = position - scaled_bisector; let new_position = position - scaled_bisector;
debug!("dilate(): prev={}({:?}) cur={}({:?}) next={}({:?}) bisector={:?}({:?}, {:?})", debug!(
prev_point_index, "dilate(): prev={}({:?}) cur={}({:?}) next={}({:?}) bisector={:?}({:?}, {:?})",
prev_position, prev_point_index,
current_point_index, prev_position,
position, current_point_index,
next_point_index, position,
next_position, next_point_index,
bisector, next_position,
bisector_length, bisector,
scaled_bisector); bisector_length,
scaled_bisector
);
// Update all points. // Update all points.
let mut point_index = current_point_index; let mut point_index = current_point_index;

View File

@ -46,7 +46,10 @@ bitflags! {
impl Outline { impl Outline {
#[inline] #[inline]
pub fn new() -> Outline { pub fn new() -> Outline {
Outline { contours: vec![], bounds: RectF32::default() } Outline {
contours: vec![],
bounds: RectF32::default(),
}
} }
#[inline] #[inline]
@ -85,9 +88,11 @@ impl Outline {
if !segment.is_line() { if !segment.is_line() {
current_contour.push_point(segment.ctrl.from(), PointFlags::CONTROL_POINT_0, true); current_contour.push_point(segment.ctrl.from(), PointFlags::CONTROL_POINT_0, true);
if !segment.is_quadratic() { if !segment.is_quadratic() {
current_contour.push_point(segment.ctrl.to(), current_contour.push_point(
PointFlags::CONTROL_POINT_1, segment.ctrl.to(),
true); PointFlags::CONTROL_POINT_1,
true,
);
} }
} }
@ -131,13 +136,20 @@ impl Outline {
pub fn dilate(&mut self, amount: Point2DF32) { pub fn dilate(&mut self, amount: Point2DF32) {
let orientation = Orientation::from_outline(self); let orientation = Orientation::from_outline(self);
self.contours.iter_mut().for_each(|contour| contour.dilate(amount, orientation)); self.contours
.iter_mut()
.for_each(|contour| contour.dilate(amount, orientation));
self.bounds = self.bounds.dilate(amount); self.bounds = self.bounds.dilate(amount);
} }
pub fn prepare_for_tiling(&mut self, view_box: RectF32) { pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box)); self.contours
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default()); .iter_mut()
.for_each(|contour| contour.prepare_for_tiling(view_box));
self.bounds = self
.bounds
.intersection(view_box)
.unwrap_or_else(|| RectF32::default());
} }
pub fn is_outside_polygon(&self, clip_polygon: &[Point2DF32]) -> bool { pub fn is_outside_polygon(&self, clip_polygon: &[Point2DF32]) -> bool {
@ -197,24 +209,35 @@ impl Debug for Outline {
impl Contour { impl Contour {
#[inline] #[inline]
pub fn new() -> Contour { pub fn new() -> Contour {
Contour { points: vec![], flags: vec![], bounds: RectF32::default(), closed: false } Contour {
points: vec![],
flags: vec![],
bounds: RectF32::default(),
closed: false,
}
} }
// Replaces this contour with a new one, with arrays preallocated to match `self`. // Replaces this contour with a new one, with arrays preallocated to match `self`.
#[inline] #[inline]
pub(crate) fn take(&mut self) -> Contour { pub(crate) fn take(&mut self) -> Contour {
let length = self.len() as usize; let length = self.len() as usize;
mem::replace(self, Contour { mem::replace(
points: Vec::with_capacity(length), self,
flags: Vec::with_capacity(length), Contour {
bounds: RectF32::default(), points: Vec::with_capacity(length),
closed: false, flags: Vec::with_capacity(length),
}) bounds: RectF32::default(),
closed: false,
},
)
} }
#[inline] #[inline]
pub fn iter(&self) -> ContourIter { pub fn iter(&self) -> ContourIter {
ContourIter { contour: self, index: 1 } ContourIter {
contour: self,
index: 1,
}
} }
#[inline] #[inline]
@ -254,10 +277,7 @@ impl Contour {
// TODO(pcwalton): SIMD. // TODO(pcwalton): SIMD.
#[inline] #[inline]
pub(crate) fn push_point(&mut self, pub(crate) fn push_point(&mut self, point: Point2DF32, flags: PointFlags, update_bounds: bool) {
point: Point2DF32,
flags: PointFlags,
update_bounds: bool) {
debug_assert!(!point.x().is_nan() && !point.y().is_nan()); debug_assert!(!point.x().is_nan() && !point.y().is_nan());
if update_bounds { if update_bounds {
@ -272,7 +292,7 @@ impl Contour {
#[inline] #[inline]
pub(crate) fn push_segment(&mut self, segment: Segment, update_bounds: bool) { pub(crate) fn push_segment(&mut self, segment: Segment, update_bounds: bool) {
if segment.is_none() { if segment.is_none() {
return return;
} }
if self.is_empty() { if self.is_empty() {
@ -280,9 +300,17 @@ impl Contour {
} }
if !segment.is_line() { if !segment.is_line() {
self.push_point(segment.ctrl.from(), PointFlags::CONTROL_POINT_0, update_bounds); self.push_point(
segment.ctrl.from(),
PointFlags::CONTROL_POINT_0,
update_bounds,
);
if !segment.is_quadratic() { if !segment.is_quadratic() {
self.push_point(segment.ctrl.to(), PointFlags::CONTROL_POINT_1, update_bounds); self.push_point(
segment.ctrl.to(),
PointFlags::CONTROL_POINT_1,
update_bounds,
);
} }
} }
@ -294,9 +322,17 @@ impl Contour {
self.push_point(segment.baseline.from(), PointFlags::empty(), update_bounds); self.push_point(segment.baseline.from(), PointFlags::empty(), update_bounds);
if !segment.is_line() { if !segment.is_line() {
self.push_point(segment.ctrl.from(), PointFlags::CONTROL_POINT_0, update_bounds); self.push_point(
segment.ctrl.from(),
PointFlags::CONTROL_POINT_0,
update_bounds,
);
if !segment.is_quadratic() { if !segment.is_quadratic() {
self.push_point(segment.ctrl.to(), PointFlags::CONTROL_POINT_1, update_bounds); self.push_point(
segment.ctrl.to(),
PointFlags::CONTROL_POINT_1,
update_bounds,
);
} }
} }
@ -336,14 +372,16 @@ impl Contour {
#[inline] #[inline]
pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegmentF32 { pub fn hull_segment_after(&self, prev_point_index: u32) -> LineSegmentF32 {
let next_point_index = self.next_point_index_of(prev_point_index); let next_point_index = self.next_point_index_of(prev_point_index);
LineSegmentF32::new(&self.points[prev_point_index as usize], LineSegmentF32::new(
&self.points[next_point_index as usize]) &self.points[prev_point_index as usize],
&self.points[next_point_index as usize],
)
} }
#[inline] #[inline]
pub fn point_is_endpoint(&self, point_index: u32) -> bool { pub fn point_is_endpoint(&self, point_index: u32) -> bool {
!self.flags[point_index as usize] !self.flags[point_index as usize]
.intersects(PointFlags::CONTROL_POINT_0 | PointFlags::CONTROL_POINT_1) .intersects(PointFlags::CONTROL_POINT_0 | PointFlags::CONTROL_POINT_1)
} }
#[inline] #[inline]
@ -427,8 +465,8 @@ impl Contour {
if contour_is_monotonic { if contour_is_monotonic {
if self.point_is_endpoint(point_index) { if self.point_is_endpoint(point_index) {
if let Some(last_endpoint_index) = last_endpoint_index { if let Some(last_endpoint_index) = last_endpoint_index {
if !self.curve_with_endpoints_is_monotonic(last_endpoint_index, if !self.curve_with_endpoints_is_monotonic(last_endpoint_index, point_index)
point_index) { {
contour_is_monotonic = false; contour_is_monotonic = false;
} }
} }
@ -443,7 +481,10 @@ impl Contour {
} }
// Update bounds. // Update bounds.
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default()); self.bounds = self
.bounds
.intersection(view_box)
.unwrap_or_else(|| RectF32::default());
} }
fn make_monotonic(&mut self) { fn make_monotonic(&mut self) {
@ -458,15 +499,23 @@ impl Contour {
} }
if let Some(last_endpoint_index) = last_endpoint_index { if let Some(last_endpoint_index) = last_endpoint_index {
let position_index = let position_index = if point_index == input_point_count {
if point_index == input_point_count { 0 } else { point_index }; 0
let baseline = LineSegmentF32::new(&contour.points[last_endpoint_index as usize], } else {
&contour.points[position_index as usize]); point_index
};
let baseline = LineSegmentF32::new(
&contour.points[last_endpoint_index as usize],
&contour.points[position_index as usize],
);
let point_count = point_index - last_endpoint_index + 1; let point_count = point_index - last_endpoint_index + 1;
if point_count == 3 { if point_count == 3 {
let ctrl_point_index = last_endpoint_index as usize + 1; let ctrl_point_index = last_endpoint_index as usize + 1;
let ctrl_position = &contour.points[ctrl_point_index]; let ctrl_position = &contour.points[ctrl_point_index];
handle_cubic(self, Segment::quadratic(&baseline, &ctrl_position).to_cubic()); handle_cubic(
self,
Segment::quadratic(&baseline, &ctrl_position).to_cubic(),
);
} else if point_count == 4 { } else if point_count == 4 {
let first_ctrl_point_index = last_endpoint_index as usize + 1; let first_ctrl_point_index = last_endpoint_index as usize + 1;
let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0]; let ctrl_position_0 = &contour.points[first_ctrl_point_index + 0];
@ -475,9 +524,11 @@ impl Contour {
handle_cubic(self, Segment::cubic(&baseline, &ctrl)); handle_cubic(self, Segment::cubic(&baseline, &ctrl));
} }
self.push_point(contour.points[position_index as usize], self.push_point(
PointFlags::empty(), contour.points[position_index as usize],
false); PointFlags::empty(),
false,
);
} }
last_endpoint_index = Some(point_index); last_endpoint_index = Some(point_index);
@ -502,22 +553,25 @@ impl Contour {
} }
} }
fn curve_with_endpoints_is_monotonic(&self, start_endpoint_index: u32, end_endpoint_index: u32) fn curve_with_endpoints_is_monotonic(
-> bool { &self,
start_endpoint_index: u32,
end_endpoint_index: u32,
) -> bool {
let start_position = self.points[start_endpoint_index as usize]; let start_position = self.points[start_endpoint_index as usize];
let end_position = self.points[end_endpoint_index as usize]; let end_position = self.points[end_endpoint_index as usize];
if start_position.x() <= end_position.x() { if start_position.x() <= end_position.x() {
for point_index in start_endpoint_index..end_endpoint_index { for point_index in start_endpoint_index..end_endpoint_index {
if self.points[point_index as usize].x() > if self.points[point_index as usize].x() > self.points[point_index as usize + 1].x()
self.points[point_index as usize + 1].x() { {
return false; return false;
} }
} }
} else { } else {
for point_index in start_endpoint_index..end_endpoint_index { for point_index in start_endpoint_index..end_endpoint_index {
if self.points[point_index as usize].x() < if self.points[point_index as usize].x() < self.points[point_index as usize + 1].x()
self.points[point_index as usize + 1].x() { {
return false; return false;
} }
} }
@ -525,15 +579,15 @@ impl Contour {
if start_position.y() <= end_position.y() { if start_position.y() <= end_position.y() {
for point_index in start_endpoint_index..end_endpoint_index { for point_index in start_endpoint_index..end_endpoint_index {
if self.points[point_index as usize].y() > if self.points[point_index as usize].y() > self.points[point_index as usize + 1].y()
self.points[point_index as usize + 1].y() { {
return false; return false;
} }
} }
} else { } else {
for point_index in start_endpoint_index..end_endpoint_index { for point_index in start_endpoint_index..end_endpoint_index {
if self.points[point_index as usize].y() < if self.points[point_index as usize].y() < self.points[point_index as usize + 1].y()
self.points[point_index as usize + 1].y() { {
return false; return false;
} }
} }
@ -554,37 +608,45 @@ impl Debug for Contour {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result { fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
for (segment_index, segment) in self.iter().enumerate() { for (segment_index, segment) in self.iter().enumerate() {
if segment_index == 0 { if segment_index == 0 {
write!(formatter, write!(
"M {} {}", formatter,
segment.baseline.from_x(), "M {} {}",
segment.baseline.from_y())?; segment.baseline.from_x(),
segment.baseline.from_y()
)?;
} }
match segment.kind { match segment.kind {
SegmentKind::None => {} SegmentKind::None => {}
SegmentKind::Line => { SegmentKind::Line => {
write!(formatter, write!(
" L {} {}", formatter,
segment.baseline.to_x(), " L {} {}",
segment.baseline.to_y())?; segment.baseline.to_x(),
segment.baseline.to_y()
)?;
} }
SegmentKind::Quadratic => { SegmentKind::Quadratic => {
write!(formatter, write!(
" Q {} {} {} {}", formatter,
segment.ctrl.from_x(), " Q {} {} {} {}",
segment.ctrl.from_y(), segment.ctrl.from_x(),
segment.baseline.to_x(), segment.ctrl.from_y(),
segment.baseline.to_y())?; segment.baseline.to_x(),
segment.baseline.to_y()
)?;
} }
SegmentKind::Cubic => { SegmentKind::Cubic => {
write!(formatter, write!(
" C {} {} {} {} {} {}", formatter,
segment.ctrl.from_x(), " C {} {} {} {} {} {}",
segment.ctrl.from_y(), segment.ctrl.from_x(),
segment.ctrl.to_x(), segment.ctrl.from_y(),
segment.ctrl.to_y(), segment.ctrl.to_x(),
segment.baseline.to_x(), segment.ctrl.to_y(),
segment.baseline.to_y())?; segment.baseline.to_x(),
segment.baseline.to_y()
)?;
} }
} }
} }
@ -630,8 +692,8 @@ impl<'a> Iterator for ContourIter<'a> {
#[inline] #[inline]
fn next(&mut self) -> Option<Segment> { fn next(&mut self) -> Option<Segment> {
let contour = self.contour; let contour = self.contour;
if (self.index == contour.len() && !self.contour.closed) || if (self.index == contour.len() && !self.contour.closed) || self.index == contour.len() + 1
self.index == contour.len() + 1 { {
return None; return None;
} }
@ -654,15 +716,20 @@ impl<'a> Iterator for ContourIter<'a> {
let point2 = contour.position_of(point2_index); let point2 = contour.position_of(point2_index);
self.index += 1; self.index += 1;
if contour.point_is_endpoint(point2_index) { if contour.point_is_endpoint(point2_index) {
return Some(Segment::quadratic(&LineSegmentF32::new(&point0, &point2), &point1)); return Some(Segment::quadratic(
&LineSegmentF32::new(&point0, &point2),
&point1,
));
} }
let point3_index = self.index; let point3_index = self.index;
let point3 = contour.position_of(point3_index); let point3 = contour.position_of(point3_index);
self.index += 1; self.index += 1;
debug_assert!(contour.point_is_endpoint(point3_index)); debug_assert!(contour.point_is_endpoint(point3_index));
return Some(Segment::cubic(&LineSegmentF32::new(&point0, &point3), return Some(Segment::cubic(
&LineSegmentF32::new(&point1, &point2))); &LineSegmentF32::new(&point0, &point3),
&LineSegmentF32::new(&point1, &point2),
));
} }
} }

View File

@ -197,9 +197,10 @@ impl<'s> CubicSegment<'s> {
// See Kaspar Fischer, "Piecewise Linear Approximation of Bézier Curves", 2000. // See Kaspar Fischer, "Piecewise Linear Approximation of Bézier Curves", 2000.
#[inline] #[inline]
pub fn is_flat(self, tolerance: f32) -> bool { pub fn is_flat(self, tolerance: f32) -> bool {
let mut uv = F32x4::splat(3.0) * self.0.ctrl.0 - let mut uv = F32x4::splat(3.0) * self.0.ctrl.0
self.0.baseline.0 - self.0.baseline.0 - - self.0.baseline.0
self.0.baseline.reversed().0; - self.0.baseline.0
- self.0.baseline.reversed().0;
uv = uv * uv; uv = uv * uv;
uv = uv.max(uv.zwxy()); uv = uv.max(uv.zwxy());
uv[0] + uv[1] <= 16.0 * tolerance * tolerance uv[0] + uv[1] <= 16.0 * tolerance * tolerance
@ -244,17 +245,20 @@ impl<'s> CubicSegment<'s> {
ctrl1 = LineSegmentF32(p012p123.concat_zw_zw(p12p23)); ctrl1 = LineSegmentF32(p012p123.concat_zw_zw(p12p23));
} }
(Segment { (
baseline: baseline0, Segment {
ctrl: ctrl0, baseline: baseline0,
kind: SegmentKind::Cubic, ctrl: ctrl0,
flags: self.0.flags & SegmentFlags::FIRST_IN_SUBPATH, kind: SegmentKind::Cubic,
}, Segment { flags: self.0.flags & SegmentFlags::FIRST_IN_SUBPATH,
baseline: baseline1, },
ctrl: ctrl1, Segment {
kind: SegmentKind::Cubic, baseline: baseline1,
flags: self.0.flags & SegmentFlags::CLOSES_SUBPATH, ctrl: ctrl1,
}) kind: SegmentKind::Cubic,
flags: self.0.flags & SegmentFlags::CLOSES_SUBPATH,
},
)
} }
#[inline] #[inline]
@ -284,13 +288,15 @@ impl<'s> CubicSegment<'s> {
#[inline] #[inline]
pub fn y_extrema(self) -> (Option<f32>, Option<f32>) { pub fn y_extrema(self) -> (Option<f32>, Option<f32>) {
if self.is_monotonic() { if self.is_monotonic() {
return (None, None) return (None, None);
} }
let p0p1p2p3 = F32x4::new(self.0.baseline.from_y(), let p0p1p2p3 = F32x4::new(
self.0.ctrl.from_y(), self.0.baseline.from_y(),
self.0.ctrl.to_y(), self.0.ctrl.from_y(),
self.0.baseline.to_y()); self.0.ctrl.to_y(),
self.0.baseline.to_y(),
);
let pxp0p1p2 = p0p1p2p3.wxyz(); let pxp0p1p2 = p0p1p2p3.wxyz();
let pxv0v1v2 = p0p1p2p3 - pxp0p1p2; let pxv0v1v2 = p0p1p2p3 - pxp0p1p2;
@ -317,11 +323,19 @@ impl<'s> CubicSegment<'s> {
} }
#[inline] #[inline]
pub fn min_x(&self) -> f32 { f32::min(self.0.baseline.min_x(), self.0.ctrl.min_x()) } pub fn min_x(&self) -> f32 {
f32::min(self.0.baseline.min_x(), self.0.ctrl.min_x())
}
#[inline] #[inline]
pub fn min_y(&self) -> f32 { f32::min(self.0.baseline.min_y(), self.0.ctrl.min_y()) } pub fn min_y(&self) -> f32 {
f32::min(self.0.baseline.min_y(), self.0.ctrl.min_y())
}
#[inline] #[inline]
pub fn max_x(&self) -> f32 { f32::max(self.0.baseline.max_x(), self.0.ctrl.max_x()) } pub fn max_x(&self) -> f32 {
f32::max(self.0.baseline.max_x(), self.0.ctrl.max_x())
}
#[inline] #[inline]
pub fn max_y(&self) -> f32 { f32::max(self.0.baseline.max_y(), self.0.ctrl.max_y()) } pub fn max_y(&self) -> f32 {
f32::max(self.0.baseline.max_y(), self.0.ctrl.max_y())
}
} }

View File

@ -26,7 +26,10 @@ pub struct OutlineStrokeToFill {
impl OutlineStrokeToFill { impl OutlineStrokeToFill {
#[inline] #[inline]
pub fn new(outline: Outline, stroke_width: f32) -> OutlineStrokeToFill { pub fn new(outline: Outline, stroke_width: f32) -> OutlineStrokeToFill {
OutlineStrokeToFill { outline, stroke_width } OutlineStrokeToFill {
outline,
stroke_width,
}
} }
#[inline] #[inline]
@ -55,7 +58,11 @@ struct ContourStrokeToFill {
impl ContourStrokeToFill { impl ContourStrokeToFill {
#[inline] #[inline]
fn new(input: Contour, output: Contour, radius: f32) -> ContourStrokeToFill { fn new(input: Contour, output: Contour, radius: f32) -> ContourStrokeToFill {
ContourStrokeToFill { input, output, radius } ContourStrokeToFill {
input,
output,
radius,
}
} }
fn offset_forward(&mut self) { fn offset_forward(&mut self) {
@ -66,7 +73,11 @@ impl ContourStrokeToFill {
fn offset_backward(&mut self) { fn offset_backward(&mut self) {
// FIXME(pcwalton) // FIXME(pcwalton)
let mut segments: Vec<_> = self.input.iter().map(|segment| segment.reversed()).collect(); let mut segments: Vec<_> = self
.input
.iter()
.map(|segment| segment.reversed())
.collect();
segments.reverse(); segments.reverse();
for segment in &segments { for segment in &segments {
segment.offset(self.radius, &mut self.output); segment.offset(self.radius, &mut self.output);
@ -108,7 +119,7 @@ impl Offset for SegmentPF3 {
if self.is_quadratic() { if self.is_quadratic() {
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from()); let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.baseline.to()); let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
let ctrl = match segment_0.intersection_t(&segment_1) { let ctrl = match segment_0.intersection_t(&segment_1) {
@ -123,7 +134,7 @@ impl Offset for SegmentPF3 {
if self.baseline.from() == self.ctrl.from() { if self.baseline.from() == self.ctrl.from() {
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.to()); let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.to());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.to(), &self.baseline.to()); let mut segment_1 = LineSegmentF32::new(&self.ctrl.to(), &self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
let ctrl = match segment_0.intersection_t(&segment_1) { let ctrl = match segment_0.intersection_t(&segment_1) {
@ -137,7 +148,7 @@ impl Offset for SegmentPF3 {
if self.ctrl.to() == self.baseline.to() { if self.ctrl.to() == self.baseline.to() {
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from()); let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.baseline.to()); let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
let ctrl = match segment_0.intersection_t(&segment_1) { let ctrl = match segment_0.intersection_t(&segment_1) {
@ -150,18 +161,20 @@ impl Offset for SegmentPF3 {
} }
let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from()); let mut segment_0 = LineSegmentF32::new(&self.baseline.from(), &self.ctrl.from());
let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.ctrl.to()); let mut segment_1 = LineSegmentF32::new(&self.ctrl.from(), &self.ctrl.to());
let mut segment_2 = LineSegmentF32::new(&self.ctrl.to(), &self.baseline.to()); let mut segment_2 = LineSegmentF32::new(&self.ctrl.to(), &self.baseline.to());
segment_0 = segment_0.offset(distance); segment_0 = segment_0.offset(distance);
segment_1 = segment_1.offset(distance); segment_1 = segment_1.offset(distance);
segment_2 = segment_2.offset(distance); segment_2 = segment_2.offset(distance);
let (ctrl_0, ctrl_1) = match (segment_0.intersection_t(&segment_1), let (ctrl_0, ctrl_1) = match (
segment_1.intersection_t(&segment_2)) { segment_0.intersection_t(&segment_1),
segment_1.intersection_t(&segment_2),
) {
(Some(t0), Some(t1)) => (segment_0.sample(t0), segment_1.sample(t1)), (Some(t0), Some(t1)) => (segment_0.sample(t0), segment_1.sample(t1)),
_ => { _ => (
(segment_0.to().lerp(segment_1.from(), 0.5), segment_0.to().lerp(segment_1.from(), 0.5),
segment_1.to().lerp(segment_2.from(), 0.5)) segment_1.to().lerp(segment_2.from(), 0.5),
} ),
}; };
let baseline = LineSegmentF32::new(&segment_0.from(), &segment_2.to()); let baseline = LineSegmentF32::new(&segment_0.from(), &segment_2.to());
let ctrl = LineSegmentF32::new(&ctrl_0, &ctrl_1); let ctrl = LineSegmentF32::new(&ctrl_0, &ctrl_1);
@ -169,7 +182,10 @@ impl Offset for SegmentPF3 {
} }
fn error_is_within_tolerance(&self, other: &SegmentPF3, distance: f32) -> bool { fn error_is_within_tolerance(&self, other: &SegmentPF3, distance: f32) -> bool {
let (mut min, mut max) = (f32::abs(distance) - TOLERANCE, f32::abs(distance) + TOLERANCE); let (mut min, mut max) = (
f32::abs(distance) - TOLERANCE,
f32::abs(distance) + TOLERANCE,
);
min = if min <= 0.0 { 0.0 } else { min * min }; min = if min <= 0.0 { 0.0 } else { min * min };
max = if max <= 0.0 { 0.0 } else { max * max }; max = if max <= 0.0 { 0.0 } else { max * max };
@ -179,8 +195,10 @@ impl Offset for SegmentPF3 {
let (this_p, other_p) = (self.sample(t), other.sample(t)); let (this_p, other_p) = (self.sample(t), other.sample(t));
let vector = this_p - other_p; let vector = this_p - other_p;
let square_distance = vector.square_length(); let square_distance = vector.square_length();
debug!("this_p={:?} other_p={:?} vector={:?} sqdist={:?} min={:?} max={:?}", debug!(
this_p, other_p, vector, square_distance, min, max); "this_p={:?} other_p={:?} vector={:?} sqdist={:?} min={:?} max={:?}",
this_p, other_p, vector, square_distance, min, max
);
if square_distance < min || square_distance > max { if square_distance < min || square_distance > max {
return false; return false;
} }