Run `rustfmt` on the geometry crate
This commit is contained in:
parent
db8eb1c97c
commit
0da11ffe01
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue