pathfinder_geometry-0.5.1/Cargo.toml.orig010064400007650000024000000006601364640751500166770ustar0000000000000000[package] name = "pathfinder_geometry" version = "0.5.1" edition = "2018" authors = ["Patrick Walton "] description = "Basic SIMD-accelerated geometry/linear algebra" license = "MIT/Apache-2.0" repository = "https://github.com/servo/pathfinder" homepage = "https://github.com/servo/pathfinder" [dependencies] [dependencies.log] version = "0.4" [dependencies.pathfinder_simd] path = "../simd" version = "0.5" pathfinder_geometry-0.5.1/Cargo.toml0000644000000016331364640761600132120ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "pathfinder_geometry" version = "0.5.1" authors = ["Patrick Walton "] description = "Basic SIMD-accelerated geometry/linear algebra" homepage = "https://github.com/servo/pathfinder" license = "MIT/Apache-2.0" repository = "https://github.com/servo/pathfinder" [dependencies.log] version = "0.4" [dependencies.pathfinder_simd] version = "0.5" pathfinder_geometry-0.5.1/src/angle.rs010064400007650000024000000010721362330267200162220ustar0000000000000000// pathfinder/geometry/src/angle.rs // // Copyright © 2020 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Angle utilities. use std::f32::consts::PI; #[inline] pub fn angle_from_degrees(degrees: f32) -> f32 { const SCALE: f32 = 2.0 * PI / 360.0; degrees * SCALE } pathfinder_geometry-0.5.1/src/lib.rs010064400007650000024000000011451362330267200157030ustar0000000000000000// pathfinder/geometry/src/lib.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Basic geometry and linear algebra primitives, optimized with SIMD. pub mod angle; pub mod line_segment; pub mod rect; pub mod transform2d; pub mod transform3d; pub mod unit_vector; pub mod util; pub mod vector; pathfinder_geometry-0.5.1/src/line_segment.rs010064400007650000024000000165431364122507300176150ustar0000000000000000// pathfinder/geometry/src/basic/line_segment.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Line segment types, optimized with SIMD. use crate::transform2d::Matrix2x2F; use crate::vector::{Vector2F, vec2f}; use crate::util; use pathfinder_simd::default::F32x4; use std::ops::{Add, Mul, MulAssign, Sub}; #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct LineSegment2F(pub F32x4); impl LineSegment2F { #[inline] pub fn new(from: Vector2F, to: Vector2F) -> LineSegment2F { LineSegment2F(from.0.concat_xy_xy(to.0)) } #[inline] pub fn from(self) -> Vector2F { Vector2F(self.0.xy()) } #[inline] pub fn to(self) -> Vector2F { Vector2F(self.0.zw()) } #[inline] pub fn set_from(&mut self, point: Vector2F) { self.0 = point.0.to_f32x4().concat_xy_zw(self.0) } #[inline] pub fn set_to(&mut self, point: Vector2F) { self.0 = self.0.concat_xy_xy(point.0.to_f32x4()) } #[allow(clippy::wrong_self_convention)] #[inline] pub fn from_x(self) -> f32 { self.0[0] } #[allow(clippy::wrong_self_convention)] #[inline] pub fn from_y(self) -> f32 { self.0[1] } #[inline] pub fn to_x(self) -> f32 { self.0[2] } #[inline] pub fn to_y(self) -> f32 { self.0[3] } #[inline] pub fn set_from_x(&mut self, x: f32) { self.0[0] = x } #[inline] pub fn set_from_y(&mut self, y: f32) { self.0[1] = y } #[inline] pub fn set_to_x(&mut self, x: f32) { self.0[2] = x } #[inline] pub fn set_to_y(&mut self, y: f32) { self.0[3] = y } #[inline] pub fn split(self, t: f32) -> (LineSegment2F, LineSegment2F) { debug_assert!(t >= 0.0 && t <= 1.0); let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw()); let d_d = to_to - from_from; let mid_mid = from_from + d_d * F32x4::splat(t); ( LineSegment2F(from_from.concat_xy_xy(mid_mid)), LineSegment2F(mid_mid.concat_xy_xy(to_to)), ) } // Returns the left segment first, followed by the right segment. #[inline] pub fn split_at_x(self, x: f32) -> (LineSegment2F, LineSegment2F) { let (min_part, max_part) = self.split(self.solve_t_for_x(x)); if min_part.from_x() < max_part.from_x() { (min_part, max_part) } else { (max_part, min_part) } } // Returns the upper segment first, followed by the lower segment. #[inline] pub fn split_at_y(self, y: f32) -> (LineSegment2F, LineSegment2F) { let (min_part, max_part) = self.split(self.solve_t_for_y(y)); // Make sure we compare `from_y` and `to_y` to properly handle the case in which one of the // two segments is zero-length. if min_part.from_y() < max_part.to_y() { (min_part, max_part) } else { (max_part, min_part) } } #[inline] pub fn solve_t_for_x(self, x: f32) -> f32 { (x - self.from_x()) / (self.to_x() - self.from_x()) } #[inline] pub fn solve_t_for_y(self, y: f32) -> f32 { (y - self.from_y()) / (self.to_y() - self.from_y()) } #[inline] pub fn solve_x_for_y(self, y: f32) -> f32 { util::lerp(self.from_x(), self.to_x(), self.solve_t_for_y(y)) } #[inline] pub fn solve_y_for_x(self, x: f32) -> f32 { util::lerp(self.from_y(), self.to_y(), self.solve_t_for_x(x)) } #[inline] pub fn reversed(self) -> LineSegment2F { LineSegment2F(self.0.zwxy()) } #[inline] pub fn upper_point(self) -> Vector2F { if self.from_y() < self.to_y() { self.from() } else { self.to() } } #[inline] pub fn min_x(self) -> f32 { f32::min(self.from_x(), self.to_x()) } #[inline] pub fn max_x(self) -> f32 { f32::max(self.from_x(), self.to_x()) } #[inline] pub fn min_y(self) -> f32 { f32::min(self.from_y(), self.to_y()) } #[inline] pub fn max_y(self) -> f32 { f32::max(self.from_y(), self.to_y()) } #[inline] pub fn y_winding(self) -> i32 { if self.from_y() < self.to_y() { 1 } else { -1 } } // Reverses if necessary so that the from point is above the to point. Calling this method // again will undo the transformation. #[inline] pub fn orient(self, y_winding: i32) -> LineSegment2F { if y_winding >= 0 { self } else { self.reversed() } } // TODO(pcwalton): Optimize with SIMD. #[inline] pub fn square_length(self) -> f32 { let (dx, dy) = (self.to_x() - self.from_x(), self.to_y() - self.from_y()); dx * dx + dy * dy } #[inline] pub fn vector(self) -> Vector2F { self.to() - self.from() } // http://www.cs.swan.ac.uk/~cssimon/line_intersection.html pub fn intersection_t(self, other: LineSegment2F) -> Option { let p0p1 = self.vector(); let matrix = Matrix2x2F(other.vector().0.concat_xy_xy((-p0p1).0)); if f32::abs(matrix.det()) < EPSILON { return None; } return Some((matrix.inverse() * (self.from() - other.from())).y()); const EPSILON: f32 = 0.0001; } #[inline] pub fn sample(self, t: f32) -> Vector2F { self.from() + self.vector() * t } #[inline] pub fn midpoint(self) -> Vector2F { self.sample(0.5) } #[inline] pub fn offset(self, distance: f32) -> LineSegment2F { if self.is_zero_length() { self } else { self + self.vector().yx().normalize() * vec2f(-distance, distance) } } #[inline] pub fn is_zero_length(self) -> bool { self.vector().is_zero() } } impl Add for LineSegment2F { type Output = LineSegment2F; #[inline] fn add(self, point: Vector2F) -> LineSegment2F { LineSegment2F(self.0 + point.0.to_f32x4().xyxy()) } } impl Sub for LineSegment2F { type Output = LineSegment2F; #[inline] fn sub(self, point: Vector2F) -> LineSegment2F { LineSegment2F(self.0 - point.0.to_f32x4().xyxy()) } } impl Mul for LineSegment2F { type Output = LineSegment2F; #[inline] fn mul(self, factors: Vector2F) -> LineSegment2F { LineSegment2F(self.0 * factors.0.to_f32x4().xyxy()) } } impl Mul for LineSegment2F { type Output = LineSegment2F; #[inline] fn mul(self, factor: f32) -> LineSegment2F { LineSegment2F(self.0 * F32x4::splat(factor)) } } impl MulAssign for LineSegment2F { #[inline] fn mul_assign(&mut self, factors: Vector2F) { *self = *self * factors } } #[derive(Clone, Copy, Debug, Default)] #[repr(C)] pub struct LineSegmentU4 { pub from: u8, pub to: u8, } #[derive(Clone, Copy, Debug, Default)] #[repr(C)] pub struct LineSegmentU8 { pub from_x: u8, pub from_y: u8, pub to_x: u8, pub to_y: u8, } pathfinder_geometry-0.5.1/src/rect.rs010064400007650000024000000210431364143153500160720ustar0000000000000000// pathfinder/geometry/src/basic/rect.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! 2D axis-aligned rectangles, optimized with SIMD. use crate::vector::{IntoVector2F, Vector2F, Vector2I}; use pathfinder_simd::default::{F32x4, I32x4}; use std::ops::{Add, Mul, Sub}; #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct RectF(pub F32x4); impl RectF { #[inline] pub fn new(origin: Vector2F, size: Vector2F) -> RectF { RectF(origin.0.concat_xy_xy(origin.0 + size.0)) } #[inline] pub fn from_points(origin: Vector2F, lower_right: Vector2F) -> RectF { RectF(origin.0.concat_xy_xy(lower_right.0)) } // Accessors #[inline] pub fn origin(self) -> Vector2F { Vector2F(self.0.xy()) } #[inline] pub fn size(self) -> Vector2F { Vector2F(self.0.zw() - self.0.xy()) } #[inline] pub fn origin_x(self) -> f32 { self.0.x() } #[inline] pub fn origin_y(self) -> f32 { self.0.y() } #[inline] pub fn width(self) -> f32 { self.0.z() - self.0.x() } #[inline] pub fn height(self) -> f32 { self.0.w() - self.0.y() } #[inline] pub fn upper_right(self) -> Vector2F { Vector2F(self.0.zy()) } #[inline] pub fn lower_left(self) -> Vector2F { Vector2F(self.0.xw()) } #[inline] pub fn lower_right(self) -> Vector2F { Vector2F(self.0.zw()) } // Mutators #[inline] pub fn set_origin_x(&mut self, x: f32) { self.0.set_x(x) } #[inline] pub fn set_origin_y(&mut self, y: f32) { self.0.set_y(y) } #[inline] pub fn contains_point(self, point: Vector2F) -> bool { // self.origin <= point && point <= self.lower_right let point = point.0.to_f32x4(); self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).all_true() } #[inline] pub fn contains_rect(self, other: RectF) -> bool { // 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)).all_true() } #[inline] pub fn is_empty(self) -> bool { self.origin() == self.lower_right() } #[inline] pub fn union_point(self, point: Vector2F) -> RectF { RectF::from_points(self.origin().min(point), self.lower_right().max(point)) } #[inline] pub fn union_rect(self, other: RectF) -> RectF { RectF::from_points( self.origin().min(other.origin()), self.lower_right().max(other.lower_right()), ) } #[inline] pub fn intersects(self, other: RectF) -> bool { // 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)).all_true() } #[inline] pub fn intersection(self, other: RectF) -> Option { if !self.intersects(other) { None } else { Some(RectF::from_points( self.origin().max(other.origin()), self.lower_right().min(other.lower_right()), )) } } #[inline] pub fn min_x(self) -> f32 { self.0[0] } #[inline] pub fn min_y(self) -> f32 { self.0[1] } #[inline] pub fn max_x(self) -> f32 { self.0[2] } #[inline] pub fn max_y(self) -> f32 { self.0[3] } #[inline] pub fn center(self) -> Vector2F { self.origin() + self.size() * 0.5 } /// Rounds all points to the nearest integer. #[inline] pub fn round(self) -> RectF { RectF(self.0.to_i32x4().to_f32x4()) } #[inline] pub fn round_out(self) -> RectF { RectF::from_points(self.origin().floor(), self.lower_right().ceil()) } #[inline] pub fn dilate(self, amount: A) -> RectF where A: IntoVector2F { let amount = amount.into_vector_2f(); RectF::from_points(self.origin() - amount, self.lower_right() + amount) } #[inline] pub fn contract(self, amount: A) -> RectF where A: IntoVector2F { let amount = amount.into_vector_2f(); RectF::from_points(self.origin() + amount, self.lower_right() - amount) } #[inline] pub fn to_i32(&self) -> RectI { RectI(self.0.to_i32x4()) } } impl Add for RectF { type Output = RectF; #[inline] fn add(self, other: Vector2F) -> RectF { RectF::new(self.origin() + other, self.size()) } } impl Add for RectF { type Output = RectF; #[inline] fn add(self, other: f32) -> RectF { RectF::new(self.origin() + other, self.size()) } } impl Mul for RectF { type Output = RectF; #[inline] fn mul(self, factors: Vector2F) -> RectF { RectF(self.0 * factors.0.concat_xy_xy(factors.0)) } } impl Mul for RectF { type Output = RectF; #[inline] fn mul(self, factor: f32) -> RectF { RectF(self.0 * F32x4::splat(factor)) } } impl Sub for RectF { type Output = RectF; #[inline] fn sub(self, other: Vector2F) -> RectF { RectF::new(self.origin() - other, self.size()) } } impl Sub for RectF { type Output = RectF; #[inline] fn sub(self, other: f32) -> RectF { RectF::new(self.origin() - other, self.size()) } } /// NB: The origin is inclusive, while the lower right point is exclusive. #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct RectI(pub I32x4); impl RectI { #[inline] pub fn new(origin: Vector2I, size: Vector2I) -> RectI { RectI(origin.0.concat_xy_xy(origin.0 + size.0)) } #[inline] pub fn from_points(origin: Vector2I, lower_right: Vector2I) -> RectI { RectI(origin.0.concat_xy_xy(lower_right.0)) } // Accessors #[inline] pub fn origin(&self) -> Vector2I { Vector2I(self.0.xy()) } #[inline] pub fn size(&self) -> Vector2I { Vector2I(self.0.zw() - self.0.xy()) } #[inline] pub fn origin_x(self) -> i32 { self.0.x() } #[inline] pub fn origin_y(self) -> i32 { self.0.y() } #[inline] pub fn width(self) -> i32 { self.0.z() - self.0.x() } #[inline] pub fn height(self) -> i32 { self.0.w() - self.0.y() } #[inline] pub fn upper_right(&self) -> Vector2I { Vector2I(self.0.zy()) } #[inline] pub fn lower_left(&self) -> Vector2I { Vector2I(self.0.xw()) } #[inline] pub fn lower_right(&self) -> Vector2I { Vector2I(self.0.zw()) } #[inline] pub fn scale(self, factor: i32) -> RectI { RectI(self.0 * I32x4::splat(factor)) } #[inline] pub fn scale_xy(self, factors: Vector2I) -> RectI { RectI(self.0 * factors.0.concat_xy_xy(factors.0)) } #[inline] pub fn min_x(self) -> i32 { self.0[0] } #[inline] pub fn min_y(self) -> i32 { self.0[1] } #[inline] pub fn max_x(self) -> i32 { self.0[2] } #[inline] pub fn max_y(self) -> i32 { self.0[3] } #[inline] pub fn intersects(self, other: RectI) -> bool { // 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)).all_true() } #[inline] pub fn intersection(self, other: RectI) -> Option { if !self.intersects(other) { None } else { Some(RectI::from_points( self.origin().max(other.origin()), self.lower_right().min(other.lower_right()), )) } } #[inline] pub fn contains_point(&self, point: Vector2I) -> bool { // self.origin <= point && point <= self.lower_right - 1 let lower_right = self.lower_right() - 1; self.origin() .0 .concat_xy_xy(point.0) .packed_le(point.0.concat_xy_xy(lower_right.0)) .all_true() } #[inline] pub fn contract(self, amount: Vector2I) -> RectI { RectI::from_points(self.origin() + amount, self.lower_right() - amount) } #[inline] pub fn to_f32(&self) -> RectF { RectF(self.0.to_f32x4()) } } pathfinder_geometry-0.5.1/src/transform2d.rs010064400007650000024000000220551364415413500174030ustar0000000000000000// pathfinder/geometry/src/basic/transform2d.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! 2D affine transforms. use crate::line_segment::LineSegment2F; use crate::rect::RectF; use crate::transform3d::Transform4F; use crate::unit_vector::UnitVector; use crate::vector::{IntoVector2F, Vector2F, vec2f}; use pathfinder_simd::default::F32x4; use std::ops::{Mul, MulAssign, Sub}; /// A 2x2 matrix, optimized with SIMD, in column-major order. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Matrix2x2F(pub F32x4); impl Default for Matrix2x2F { #[inline] fn default() -> Matrix2x2F { Self::from_scale(1.0) } } impl Matrix2x2F { #[inline] pub fn from_scale(scale: S) -> Matrix2x2F where S: IntoVector2F { let scale = scale.into_vector_2f(); Matrix2x2F(F32x4::new(scale.x(), 0.0, 0.0, scale.y())) } #[inline] pub fn from_rotation(theta: f32) -> Matrix2x2F { Matrix2x2F::from_rotation_vector(UnitVector::from_angle(theta)) } #[inline] pub fn from_rotation_vector(vector: UnitVector) -> Matrix2x2F { Matrix2x2F((vector.0).0.to_f32x4().xyyx() * F32x4::new(1.0, 1.0, -1.0, 1.0)) } #[inline] pub fn row_major(m00: f32, m01: f32, m10: f32, m11: f32) -> Matrix2x2F { Matrix2x2F(F32x4::new(m00, m10, m01, m11)) } #[inline] pub fn entrywise_mul(&self, other: &Matrix2x2F) -> Matrix2x2F { Matrix2x2F(self.0 * other.0) } #[inline] pub fn adjugate(&self) -> Matrix2x2F { Matrix2x2F(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0)) } #[inline] pub fn det(&self) -> f32 { self.0[0] * self.0[3] - self.0[2] * self.0[1] } #[inline] pub fn inverse(&self) -> Matrix2x2F { Matrix2x2F(F32x4::splat(1.0 / self.det()) * self.adjugate().0) } #[inline] pub fn scale(&self, factor: f32) -> Matrix2x2F { Matrix2x2F(self.0 * F32x4::splat(factor)) } /// Extracts the scale from this matrix. #[inline] pub fn extract_scale(&self) -> Vector2F { let squared = self.0 * self.0; Vector2F((squared.xy() + squared.zw()).sqrt()) } #[inline] pub fn m11(&self) -> f32 { self.0[0] } #[inline] pub fn m21(&self) -> f32 { self.0[1] } #[inline] pub fn m12(&self) -> f32 { self.0[2] } #[inline] pub fn m22(&self) -> f32 { self.0[3] } } impl Sub for Matrix2x2F { type Output = Matrix2x2F; #[inline] fn sub(self, other: Matrix2x2F) -> Matrix2x2F { Matrix2x2F(self.0 - other.0) } } impl Mul for Matrix2x2F { type Output = Matrix2x2F; #[inline] fn mul(self, other: Matrix2x2F) -> Matrix2x2F { Matrix2x2F(self.0.xyxy() * other.0.xxzz() + self.0.zwzw() * other.0.yyww()) } } impl Mul for Matrix2x2F { type Output = Vector2F; #[inline] fn mul(self, vector: Vector2F) -> Vector2F { let halves = self.0 * vector.0.to_f32x4().xxyy(); Vector2F(halves.xy() + halves.zw()) } } /// An affine transform, optimized with SIMD. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Transform2F { pub matrix: Matrix2x2F, pub vector: Vector2F, } impl Default for Transform2F { #[inline] fn default() -> Transform2F { Self::from_scale(vec2f(1.0, 1.0)) } } impl Transform2F { #[inline] pub fn from_scale(scale: S) -> Transform2F where S: IntoVector2F { let scale = scale.into_vector_2f(); Transform2F { matrix: Matrix2x2F::from_scale(scale), vector: Vector2F::zero(), } } #[inline] pub fn from_rotation(theta: f32) -> Transform2F { Transform2F { matrix: Matrix2x2F::from_rotation(theta), vector: Vector2F::zero(), } } #[inline] pub fn from_rotation_vector(vector: UnitVector) -> Transform2F { Transform2F { matrix: Matrix2x2F::from_rotation_vector(vector), vector: Vector2F::zero(), } } #[inline] pub fn from_translation(vector: Vector2F) -> Transform2F { Transform2F { matrix: Matrix2x2F::default(), vector } } #[inline] pub fn from_scale_rotation_translation(scale: S, theta: f32, translation: Vector2F) -> Transform2F where S: IntoVector2F { let scale = scale.into_vector_2f(); let rotation = Transform2F::from_rotation(theta); let translation = Transform2F::from_translation(translation); Transform2F::from_scale(scale) * rotation * translation } #[inline] pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2F { Transform2F { matrix: Matrix2x2F::row_major(m11, m12, m21, m22), vector: Vector2F::new(m31, m32), } } // TODO(pcwalton): Optimize better with SIMD. #[inline] pub fn to_3d(&self) -> Transform4F { Transform4F::row_major( self.matrix.0[0], self.matrix.0[1], 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] pub fn is_identity(&self) -> bool { *self == Transform2F::default() } /// Extracts the scale from this matrix. #[inline] pub fn extract_scale(&self) -> Vector2F { self.matrix.extract_scale() } #[inline] pub fn m11(&self) -> f32 { self.matrix.m11() } #[inline] pub fn m21(&self) -> f32 { self.matrix.m21() } #[inline] pub fn m12(&self) -> f32 { self.matrix.m12() } #[inline] pub fn m22(&self) -> f32 { self.matrix.m22() } #[inline] pub fn m31(&self) -> f32 { self.vector.x() } #[inline] pub fn m32(&self) -> f32 { self.vector.y() } #[inline] pub fn translate(&self, vector: Vector2F) -> Transform2F { Transform2F::from_translation(vector) * *self } #[inline] pub fn rotate(&self, theta: f32) -> Transform2F { Transform2F::from_rotation(theta) * *self } #[inline] pub fn scale(&self, scale: S) -> Transform2F where S: IntoVector2F { let scale = scale.into_vector_2f(); Transform2F::from_scale(scale) * *self } /// Returns the translation part of this matrix. /// /// This decomposition assumes that scale, rotation, and translation are applied in that order. #[inline] pub fn translation(&self) -> Vector2F { self.vector } /// Returns the rotation angle of this matrix. /// /// This decomposition assumes that scale, rotation, and translation are applied in that order. #[inline] pub fn rotation(&self) -> f32 { f32::atan2(self.m21(), self.m11()) } /// Returns the scale factor of this matrix. /// /// This decomposition assumes that scale, rotation, and translation are applied in that order. #[inline] pub fn scale_factor(&self) -> f32 { Vector2F(self.matrix.0.zw()).length() } #[inline] pub fn inverse(&self) -> Transform2F { let matrix_inv = self.matrix.inverse(); let vector_inv = -(matrix_inv * self.vector); Transform2F { matrix: matrix_inv, vector: vector_inv } } } impl Mul for Transform2F { type Output = Transform2F; #[inline] fn mul(self, other: Transform2F) -> Transform2F { Transform2F { matrix: self.matrix * other.matrix, vector: self * other.vector, } } } impl Mul for Transform2F { type Output = Vector2F; #[inline] fn mul(self, vector: Vector2F) -> Vector2F { self.matrix * vector + self.vector } } impl Mul for Transform2F { type Output = LineSegment2F; #[inline] fn mul(self, line_segment: LineSegment2F) -> LineSegment2F { LineSegment2F::new(self * line_segment.from(), self * line_segment.to()) } } impl Mul for Transform2F { type Output = RectF; #[inline] fn mul(self, rect: RectF) -> RectF { let (upper_left, upper_right) = (self * rect.origin(), self * rect.upper_right()); let (lower_left, lower_right) = (self * rect.lower_left(), self * rect.lower_right()); let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right); RectF::from_points(min_point, max_point) } } impl MulAssign for Transform2F { #[inline] fn mul_assign(&mut self, other: Transform2F) { *self = *self * other } } pathfinder_geometry-0.5.1/src/transform3d.rs010064400007650000024000000357431364122510500174050ustar0000000000000000// pathfinder/geometry/src/basic/transform3d.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! 3D transforms that can be applied to paths. use crate::rect::RectF; use crate::transform2d::Matrix2x2F; use crate::vector::{Vector2F, Vector2I, Vector3F, Vector4F}; use pathfinder_simd::default::F32x4; use std::ops::{Add, Mul, MulAssign, Neg}; /// An transform, optimized with SIMD. /// /// In column-major order. #[derive(Clone, Copy, Debug, PartialEq)] #[repr(C)] pub struct Transform4F { pub c0: F32x4, pub c1: F32x4, pub c2: F32x4, pub c3: F32x4, } impl Default for Transform4F { #[inline] fn default() -> Transform4F { Transform4F { c0: F32x4::new(1.0, 0.0, 0.0, 0.0), c1: F32x4::new(0.0, 1.0, 0.0, 0.0), c2: F32x4::new(0.0, 0.0, 1.0, 0.0), c3: F32x4::new(0.0, 0.0, 0.0, 1.0), } } } impl Transform4F { #[inline] pub fn row_major( m00: f32, m01: f32, m02: f32, 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, ) -> Transform4F { Transform4F { c0: F32x4::new(m00, m10, m20, m30), c1: F32x4::new(m01, m11, m21, m31), c2: F32x4::new(m02, m12, m22, m32), c3: F32x4::new(m03, m13, m23, m33), } } #[inline] pub fn from_scale(scale: Vector4F) -> Transform4F { Transform4F { c0: F32x4::new(scale.x(), 0.0, 0.0, 0.0), c1: F32x4::new(0.0, scale.y(), 0.0, 0.0), c2: F32x4::new(0.0, 0.0, scale.z(), 0.0), c3: F32x4::new(0.0, 0.0, 0.0, 1.0), } } #[inline] pub fn from_uniform_scale(factor: f32) -> Transform4F { Transform4F::from_scale(Vector4F::splat(factor)) } #[inline] pub fn from_translation(mut translation: Vector4F) -> Transform4F { translation.set_w(1.0); Transform4F { c3: translation.0, ..Transform4F::default() } } // TODO(pcwalton): Optimize. pub fn from_rotation(yaw: f32, pitch: f32, roll: f32) -> Transform4F { let (cos_b, sin_b) = (yaw.cos(), yaw.sin()); let (cos_c, sin_c) = (pitch.cos(), pitch.sin()); let (cos_a, sin_a) = (roll.cos(), roll.sin()); let m00 = cos_a * cos_b; 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 m10 = sin_a * cos_b; let m11 = sin_a * sin_b * sin_c + cos_a * cos_c; let m12 = sin_a * sin_b * cos_c - cos_a * sin_c; let m20 = -sin_b; let m21 = cos_b * sin_c; let m22 = cos_b * cos_c; Transform4F::row_major( m00, m01, m02, 0.0, m10, m11, m12, 0.0, m20, m21, m22, 0.0, 0.0, 0.0, 0.0, 1.0, ) } /// Creates a rotation matrix from the given quaternion. /// /// The quaternion is expected to be packed into a SIMD type (x, y, z, w) corresponding to /// x + yi + zj + wk. pub fn from_rotation_quaternion(q: F32x4) -> Transform4F { // 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()); sq += sq; w += w; xy_xz_yz += xy_xz_yz; let diag = F32x4::splat(1.0) - (sq.yxxy() + sq.zzyy()); 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()); Transform4F::row_major( diag.x(), xy2 - wz2, 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()`. #[inline] pub fn from_ortho( left: f32, right: f32, bottom: f32, top: f32, near_val: f32, far_val: f32, ) -> Transform4F { let x_inv = 1.0 / (right - left); let y_inv = 1.0 / (top - bottom); let z_inv = 1.0 / (far_val - near_val); let tx = -(right + left) * x_inv; let ty = -(top + bottom) * y_inv; let tz = -(far_val + near_val) * z_inv; Transform4F::row_major( 2.0 * x_inv, 0.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, ) } /// Linearly interpolate between transforms pub fn lerp(&self, weight: f32, other: &Transform4F) -> Transform4F { let c0 = self.c0 * F32x4::splat(weight) + other.c0 * F32x4::splat(1.0 - weight); let c1 = self.c1 * F32x4::splat(weight) + other.c1 * F32x4::splat(1.0 - weight); let c2 = self.c2 * F32x4::splat(weight) + other.c2 * F32x4::splat(1.0 - weight); let c3 = self.c3 * F32x4::splat(weight) + other.c3 * F32x4::splat(1.0 - weight); Transform4F { c0, c1, c2, c3 } } /// Just like `gluPerspective()`. #[inline] pub fn from_perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> Transform4F { let f = 1.0 / (fov_y * 0.5).tan(); let z_denom = 1.0 / (z_near - z_far); let m00 = f / aspect; let m11 = f; let m22 = (z_far + z_near) * z_denom; let m23 = 2.0 * z_far * z_near * z_denom; let m32 = -1.0; Transform4F::row_major( 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, ) } /// Just like `gluLookAt()`. #[inline] pub fn looking_at(eye: Vector3F, center: Vector3F, mut up: Vector3F) -> Transform4F { let f = (center - eye).normalize(); up = up.normalize(); let s = f.cross(up); let u = s.normalize().cross(f); let minus_f = -f; // TODO(pcwalton): Use SIMD. This needs a matrix transpose: // https://fgiesen.wordpress.com/2013/07/09/simd-transposes-1/ let transform = Transform4F::row_major(s.x(), s.y(), s.z(), 0.0, u.x(), u.y(), u.z(), 0.0, minus_f.x(), minus_f.y(), minus_f.z(), 0.0, 0.0, 0.0, 0.0, 1.0) * Transform4F::from_translation((-eye).to_4d()); transform } // +- -+ // | A B | // | C D | // +- -+ #[inline] pub fn from_submatrices( a: Matrix2x2F, b: Matrix2x2F, c: Matrix2x2F, d: Matrix2x2F, ) -> Transform4F { Transform4F { c0: a.0.concat_xy_xy(c.0), c1: a.0.concat_zw_zw(c.0), c2: b.0.concat_xy_xy(d.0), c3: b.0.concat_zw_zw(d.0), } } #[inline] pub fn rotate(&self, yaw: f32, pitch: f32, roll: f32) -> Transform4F { Transform4F::from_rotation(yaw, pitch, roll) * *self } #[inline] pub fn scale(&self, scale: Vector4F) -> Transform4F { Transform4F::from_scale(scale) * *self } #[inline] pub fn uniform_scale(&self, scale: f32) -> Transform4F { Transform4F::from_uniform_scale(scale) * *self } #[inline] pub fn translate(&self, translation: Vector4F) -> Transform4F { Transform4F::from_translation(translation) * *self } #[inline] pub fn upper_left(&self) -> Matrix2x2F { Matrix2x2F(self.c0.concat_xy_xy(self.c1)) } #[inline] pub fn upper_right(&self) -> Matrix2x2F { Matrix2x2F(self.c2.concat_xy_xy(self.c3)) } #[inline] pub fn lower_left(&self) -> Matrix2x2F { Matrix2x2F(self.c0.concat_zw_zw(self.c1)) } #[inline] pub fn lower_right(&self) -> Matrix2x2F { Matrix2x2F(self.c2.concat_zw_zw(self.c3)) } // https://en.wikipedia.org/wiki/Invertible_matrix#Blockwise_inversion // // If A is the upper left submatrix of this matrix, this method assumes that A and the Schur // complement of A are invertible. pub fn inverse(&self) -> Transform4F { // Extract submatrices. let (a, b) = (self.upper_left(), self.upper_right()); let (c, d) = (self.lower_left(), self.lower_right()); // Compute temporary matrices. let a_inv = a.inverse(); let x = c * a_inv; let y = (d - x * b).inverse(); let z = a_inv * b; // Compute new submatrices. let (a_new, b_new) = (a_inv + z * y * x, -z * y); let (c_new, d_new) = (-y * x, y); // Construct inverse. Transform4F::from_submatrices(a_new, b_new, c_new, d_new) } pub fn approx_eq(&self, other: &Transform4F, epsilon: f32) -> bool { self.c0.approx_eq(other.c0, epsilon) && self.c1.approx_eq(other.c1, epsilon) && self.c2.approx_eq(other.c2, epsilon) && self.c3.approx_eq(other.c3, epsilon) } #[inline] pub fn as_ptr(&self) -> *const f32 { (&self.c0) as *const F32x4 as *const f32 } #[inline] pub fn to_columns(&self) -> [F32x4; 4] { [self.c0, self.c1, self.c2, self.c3] } } impl Mul for Transform4F { type Output = Transform4F; // https://stackoverflow.com/a/18508113 #[inline] fn mul(self, other: Transform4F) -> Transform4F { return Transform4F { c0: mul_col(&self, other.c0), c1: mul_col(&self, other.c1), c2: mul_col(&self, other.c2), c3: mul_col(&self, other.c3), }; #[inline] fn mul_col(a: &Transform4F, b_col: F32x4) -> F32x4 { a.c0 * b_col.xxxx() + a.c1 * b_col.yyyy() + a.c2 * b_col.zzzz() + a.c3 * b_col.wwww() } } } impl Mul for Transform4F { type Output = Vector4F; #[inline] fn mul(self, vector: Vector4F) -> Vector4F { let term0 = self.c0 * F32x4::splat(vector.x()); let term1 = self.c1 * F32x4::splat(vector.y()); let term2 = self.c2 * F32x4::splat(vector.z()); let term3 = self.c3 * F32x4::splat(vector.w()); Vector4F(term0 + term1 + term2 + term3) } } impl MulAssign for Transform4F { fn mul_assign(&mut self, other: Transform4F) { *self = *self * other } } impl Add for Matrix2x2F { type Output = Matrix2x2F; #[inline] fn add(self, other: Matrix2x2F) -> Matrix2x2F { Matrix2x2F(self.0 + other.0) } } impl Neg for Matrix2x2F { type Output = Matrix2x2F; #[inline] fn neg(self) -> Matrix2x2F { Matrix2x2F(-self.0) } } #[derive(Clone, Copy, Debug)] pub struct Perspective { pub transform: Transform4F, pub window_size: Vector2I, } impl Perspective { #[inline] pub fn new(transform: &Transform4F, window_size: Vector2I) -> Perspective { Perspective { transform: *transform, window_size, } } } impl Mul for Perspective { type Output = Perspective; #[inline] fn mul(self, other: Transform4F) -> Perspective { Perspective { transform: self.transform * other, window_size: self.window_size, } } } impl Mul for Perspective { type Output = Vector2F; #[inline] fn mul(self, vector: Vector2F) -> Vector2F { let point = (self.transform * vector.to_4d()).to_2d() * Vector2F::new(1.0, -1.0); (point + 1.0) * self.window_size.to_f32() * 0.5 } } impl Mul for Perspective { type Output = RectF; #[inline] fn mul(self, rect: RectF) -> RectF { let (upper_left, upper_right) = (self * rect.origin(), self * rect.upper_right()); let (lower_left, lower_right) = (self * rect.lower_left(), self * rect.lower_right()); let min_point = upper_left.min(upper_right).min(lower_left).min(lower_right); let max_point = upper_left.max(upper_right).max(lower_left).max(lower_right); RectF::from_points(min_point, max_point) } } #[cfg(test)] mod test { use crate::vector::Vector4F; use crate::transform3d::Transform4F; #[test] fn test_post_mul() { let a = Transform4F::row_major( 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, ); let b = Transform4F::row_major( 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, ); let c = Transform4F::row_major( 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, 152.0, 83.0, 75.0, ); assert_eq!(a * b, c); } #[test] fn test_pre_mul() { let a = Transform4F::row_major( 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, ); let b = Transform4F::row_major( 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, ); let c = Transform4F::row_major( 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, 50.0, 122.0, 125.0, ); assert_eq!(b * a, c); } #[test] fn test_transform_point() { let a = Transform4F::row_major( 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, ); let p = Vector4F::new(3.0, 8.0, 4.0, 6.0); let q = Vector4F::new(63.0, 97.0, 135.0, 117.0); assert_eq!(a * p, q); } #[test] fn test_inverse() { // Random matrix. let m = Transform4F::row_major( 0.86277982, 0.15986552, 0.90739898, 0.60066808, 0.17386167, 0.016353, 0.8535783, 0.12969608, 0.0946466, 0.43248631, 0.63480505, 0.08154603, 0.50305436, 0.48359687, 0.51057162, 0.24812012, ); let p0 = Vector4F::new(0.95536648, 0.80633691, 0.16357357, 0.5477598); let p1 = m * p0; let m_inv = m.inverse(); let m_inv_exp = Transform4F::row_major( -2.47290136, 3.48865688, -6.12298336, 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)); let p2 = m_inv * p1; assert!(p0.approx_eq(p2, 0.0001)); } } pathfinder_geometry-0.5.1/src/unit_vector.rs010064400007650000024000000032371364072432700175060ustar0000000000000000// pathfinder/geometry/src/unit_vector.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A utility module that allows unit vectors to be treated like angles. use crate::vector::Vector2F; use pathfinder_simd::default::F32x2; #[derive(Clone, Copy, Debug)] pub struct UnitVector(pub Vector2F); impl UnitVector { #[inline] pub fn from_angle(theta: f32) -> UnitVector { UnitVector(Vector2F::new(theta.cos(), theta.sin())) } /// Angle addition formula. #[inline] pub fn rotate_by(&self, other: UnitVector) -> UnitVector { let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy(); UnitVector(Vector2F::new(products[0] - products[1], products[2] + products[3])) } /// Angle subtraction formula. #[inline] pub fn rev_rotate_by(&self, other: UnitVector) -> UnitVector { let products = (self.0).0.to_f32x4().xyyx() * (other.0).0.to_f32x4().xyxy(); UnitVector(Vector2F::new(products[0] + products[1], products[2] - products[3])) } /// Half angle formula. #[inline] pub fn halve_angle(&self) -> UnitVector { let x = self.0.x(); let term = F32x2::new(x, -x); UnitVector(Vector2F((F32x2::splat(0.5) * (F32x2::splat(1.0) + term)).max(F32x2::default()) .sqrt())) } } pathfinder_geometry-0.5.1/src/util.rs010064400007650000024000000016411364273735000161210ustar0000000000000000// pathfinder/geometry/src/util.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Various utilities. use std::f32; pub const EPSILON: f32 = 0.001; /// Approximate equality. #[inline] pub fn approx_eq(a: f32, b: f32) -> bool { f32::abs(a - b) <= EPSILON } /// Linear interpolation. #[inline] pub fn lerp(a: f32, b: f32, t: f32) -> f32 { a + (b - a) * t } /// Clamping. #[inline] pub fn clamp(x: f32, min_val: f32, max_val: f32) -> f32 { f32::min(max_val, f32::max(min_val, x)) } /// Divides `a` by `b`, rounding up. #[inline] pub fn alignup_i32(a: i32, b: i32) -> i32 { (a + b - 1) / b } pathfinder_geometry-0.5.1/src/vector.rs010064400007650000024000000347761364420072200164530ustar0000000000000000// pathfinder/geometry/src/basic/point.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! A SIMD-optimized point type. use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use std::hash::{Hash, Hasher}; use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign}; /// 2D points with 32-bit floating point coordinates. #[derive(Clone, Copy, Debug, Default)] pub struct Vector2F(pub F32x2); impl Vector2F { #[inline] pub fn new(x: f32, y: f32) -> Vector2F { Vector2F(F32x2::new(x, y)) } #[inline] pub fn splat(value: f32) -> Vector2F { Vector2F(F32x2::splat(value)) } #[inline] pub fn zero() -> Vector2F { Vector2F::default() } #[inline] pub fn to_3d(self) -> Vector3F { Vector3F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 0.0))) } #[inline] pub fn to_4d(self) -> Vector4F { Vector4F(self.0.to_f32x4().concat_xy_zw(F32x4::new(0.0, 0.0, 0.0, 1.0))) } #[inline] pub fn x(self) -> f32 { self.0[0] } #[inline] pub fn y(self) -> f32 { self.0[1] } #[inline] pub fn set_x(&mut self, x: f32) { self.0[0] = x; } #[inline] pub fn set_y(&mut self, y: f32) { self.0[1] = y; } #[inline] pub fn min(self, other: Vector2F) -> Vector2F { Vector2F(self.0.min(other.0)) } #[inline] pub fn max(self, other: Vector2F) -> Vector2F { Vector2F(self.0.max(other.0)) } #[inline] pub fn clamp(self, min_val: Vector2F, max_val: Vector2F) -> Vector2F { self.max(min_val).min(max_val) } #[inline] pub fn det(self, other: Vector2F) -> f32 { self.x() * other.y() - self.y() * other.x() } #[inline] pub fn dot(self, other: Vector2F) -> f32 { let xy = self.0 * other.0; xy.x() + xy.y() } #[inline] pub fn floor(self) -> Vector2F { Vector2F(self.0.floor()) } #[inline] pub fn ceil(self) -> Vector2F { Vector2F(self.0.ceil()) } /// Rounds both coordinates to the nearest integer. #[inline] pub fn round(self) -> Vector2F { Vector2F(self.0.to_i32x2().to_f32x2()) } /// Treats this point as a vector and calculates its squared length. #[inline] pub fn square_length(self) -> f32 { let squared = self.0 * self.0; squared[0] + squared[1] } /// Treats this point as a vector and calculates its length. #[inline] pub fn length(self) -> f32 { f32::sqrt(self.square_length()) } /// Treats this point as a vector and normalizes it. #[inline] pub fn normalize(self) -> Vector2F { self * (1.0 / self.length()) } /// Swaps y and x. #[inline] pub fn yx(self) -> Vector2F { Vector2F(self.0.yx()) } /// Returns the coefficient when the given vector `a` is projected onto this one. /// /// That is, if this vector is `v` and this function returns `c`, then `proj_v a = cv`. In /// other words, this function computes `(a⋅v) / (v⋅v)`. #[inline] pub fn projection_coefficient(self, a: Vector2F) -> f32 { a.dot(self) / self.square_length() } #[inline] pub fn is_zero(self) -> bool { self == Vector2F::zero() } #[inline] pub fn lerp(self, other: Vector2F, t: f32) -> Vector2F { self + (other - self) * t } #[inline] pub fn to_i32(self) -> Vector2I { Vector2I(self.0.to_i32x2()) } } /// A convenience alias for `Vector2F::new()`. #[inline] pub fn vec2f(x: f32, y: f32) -> Vector2F { Vector2F::new(x, y) } impl PartialEq for Vector2F { #[inline] fn eq(&self, other: &Vector2F) -> bool { self.0.packed_eq(other.0).all_true() } } impl Add for Vector2F { type Output = Vector2F; #[inline] fn add(self, other: Vector2F) -> Vector2F { Vector2F(self.0 + other.0) } } impl Add for Vector2F { type Output = Vector2F; #[inline] fn add(self, other: f32) -> Vector2F { self + Vector2F::splat(other) } } impl AddAssign for Vector2F { #[inline] fn add_assign(&mut self, other: Vector2F) { *self = *self + other } } impl Sub for Vector2F { type Output = Vector2F; #[inline] fn sub(self, other: Vector2F) -> Vector2F { Vector2F(self.0 - other.0) } } impl Sub for Vector2F { type Output = Vector2F; #[inline] fn sub(self, other: f32) -> Vector2F { self - Vector2F::splat(other) } } impl SubAssign for Vector2F { #[inline] fn sub_assign(&mut self, other: Vector2F) { *self = *self - other } } impl Mul for Vector2F { type Output = Vector2F; #[inline] fn mul(self, other: Vector2F) -> Vector2F { Vector2F(self.0 * other.0) } } impl Mul for Vector2F { type Output = Vector2F; #[inline] fn mul(self, other: f32) -> Vector2F { self * Vector2F::splat(other) } } impl MulAssign for Vector2F { #[inline] fn mul_assign(&mut self, other: Vector2F) { *self = *self * other } } impl MulAssign for Vector2F { #[inline] fn mul_assign(&mut self, other: f32) { *self = *self * other } } impl Div for Vector2F { type Output = Vector2F; #[inline] fn div(self, other: Vector2F) -> Vector2F { Vector2F(self.0 / other.0) } } impl Div for Vector2F { type Output = Vector2F; #[inline] fn div(self, other: f32) -> Vector2F { self / Vector2F::splat(other) } } impl Neg for Vector2F { type Output = Vector2F; #[inline] fn neg(self) -> Vector2F { Vector2F(-self.0) } } /// Either a scalar or a `Vector2F`. /// /// Scalars will be automatically splatted (i.e. `x` becomes `vec2f(x, x)`). /// /// Be judicious with the use of this trait. Only use it if it will aid readability without the /// potential to introduce bugs. pub trait IntoVector2F { fn into_vector_2f(self) -> Vector2F; } impl IntoVector2F for Vector2F { #[inline] fn into_vector_2f(self) -> Vector2F { self } } impl IntoVector2F for f32 { #[inline] fn into_vector_2f(self) -> Vector2F { Vector2F::splat(self) } } /// 2D points with 32-bit signed integer coordinates. #[derive(Clone, Copy, Debug, Default)] pub struct Vector2I(pub I32x2); impl Vector2I { #[inline] pub fn new(x: i32, y: i32) -> Vector2I { Vector2I(I32x2::new(x, y)) } #[inline] pub fn splat(value: i32) -> Vector2I { Vector2I(I32x2::splat(value)) } #[inline] pub fn zero() -> Vector2I { Vector2I::default() } #[inline] pub fn x(self) -> i32 { self.0[0] } #[inline] pub fn y(self) -> i32 { self.0[1] } #[inline] pub fn set_x(&mut self, x: i32) { self.0[0] = x; } #[inline] pub fn set_y(&mut self, y: i32) { self.0[1] = y; } #[inline] pub fn min(self, other: Vector2I) -> Vector2I { Vector2I(self.0.min(other.0)) } #[inline] pub fn max(self, other: Vector2I) -> Vector2I { Vector2I(self.0.max(other.0)) } #[inline] pub fn to_f32(self) -> Vector2F { Vector2F(self.0.to_f32x2()) } } /// A convenience alias for `Vector2I::new()`. #[inline] pub fn vec2i(x: i32, y: i32) -> Vector2I { Vector2I::new(x, y) } impl Add for Vector2I { type Output = Vector2I; #[inline] fn add(self, other: Vector2I) -> Vector2I { Vector2I(self.0 + other.0) } } impl Add for Vector2I { type Output = Vector2I; #[inline] fn add(self, other: i32) -> Vector2I { self + Vector2I::splat(other) } } impl AddAssign for Vector2I { #[inline] fn add_assign(&mut self, other: Vector2I) { self.0 += other.0 } } impl Neg for Vector2I { type Output = Vector2I; #[inline] fn neg(self) -> Vector2I { Vector2I(-self.0) } } impl Sub for Vector2I { type Output = Vector2I; #[inline] fn sub(self, other: Vector2I) -> Vector2I { Vector2I(self.0 - other.0) } } impl Sub for Vector2I { type Output = Vector2I; #[inline] fn sub(self, other: i32) -> Vector2I { self - Vector2I::splat(other) } } impl Mul for Vector2I { type Output = Vector2I; #[inline] fn mul(self, other: Vector2I) -> Vector2I { Vector2I(self.0 * other.0) } } impl Mul for Vector2I { type Output = Vector2I; #[inline] fn mul(self, other: i32) -> Vector2I { self * Vector2I::splat(other) } } impl PartialEq for Vector2I { #[inline] fn eq(&self, other: &Vector2I) -> bool { self.0.packed_eq(other.0).all_true() } } impl Eq for Vector2I {} impl Hash for Vector2I { #[inline] fn hash(&self, state: &mut H) where H: Hasher { self.x().hash(state); self.y().hash(state); } } /// 3D points. /// /// The w value in the SIMD vector is always 0.0. #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Vector3F(pub F32x4); impl Vector3F { #[inline] pub fn new(x: f32, y: f32, z: f32) -> Vector3F { Vector3F(F32x4::new(x, y, z, 0.0)) } #[inline] pub fn splat(x: f32) -> Vector3F { let mut vector = F32x4::splat(x); vector.set_w(0.0); Vector3F(vector) } /// Truncates this vector to 2D. #[inline] pub fn to_2d(self) -> Vector2F { Vector2F(self.0.xy()) } /// Converts this vector to an equivalent 3D homogeneous one with a w component of 1.0. #[inline] pub fn to_4d(self) -> Vector4F { let mut vector = self.0; vector.set_w(1.0); Vector4F(vector) } #[inline] pub fn cross(self, other: Vector3F) -> Vector3F { Vector3F(self.0.yzxw() * other.0.zxyw() - self.0.zxyw() * other.0.yzxw()) } #[inline] pub fn square_length(self) -> f32 { let squared = self.0 * self.0; squared[0] + squared[1] + squared[2] } #[inline] pub fn length(self) -> f32 { f32::sqrt(self.square_length()) } #[inline] pub fn normalize(self) -> Vector3F { Vector3F(self.0 * F32x4::splat(1.0 / self.length())) } #[inline] pub fn x(self) -> f32 { self.0[0] } #[inline] pub fn y(self) -> f32 { self.0[1] } #[inline] pub fn z(self) -> f32 { self.0[2] } #[inline] pub fn scale(self, factor: f32) -> Vector3F { Vector3F(self.0 * F32x4::splat(factor)) } } impl Add for Vector3F { type Output = Vector3F; #[inline] fn add(self, other: Vector3F) -> Vector3F { Vector3F(self.0 + other.0) } } impl AddAssign for Vector3F { #[inline] fn add_assign(&mut self, other: Vector3F) { self.0 += other.0 } } impl Neg for Vector3F { type Output = Vector3F; #[inline] fn neg(self) -> Vector3F { Vector3F(self.0 * F32x4::new(-1.0, -1.0, -1.0, 0.0)) } } impl Sub for Vector3F { type Output = Vector3F; #[inline] fn sub(self, other: Vector3F) -> Vector3F { Vector3F(self.0 - other.0) } } /// 3D homogeneous points. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Vector4F(pub F32x4); impl Vector4F { #[inline] pub fn new(x: f32, y: f32, z: f32, w: f32) -> Vector4F { Vector4F(F32x4::new(x, y, z, w)) } #[inline] pub fn splat(value: f32) -> Vector4F { Vector4F(F32x4::splat(value)) } #[inline] pub fn to_2d(self) -> Vector2F { self.to_3d().to_2d() } /// Performs perspective division to convert this vector to 3D. #[inline] pub fn to_3d(self) -> Vector3F { let mut vector = self.0 * F32x4::splat(1.0 / self.w()); vector.set_w(0.0); Vector3F(vector) } #[inline] pub fn x(self) -> f32 { self.0[0] } #[inline] pub fn y(self) -> f32 { self.0[1] } #[inline] pub fn z(self) -> f32 { self.0[2] } #[inline] pub fn w(self) -> f32 { self.0[3] } #[inline] pub fn scale(self, x: f32) -> Vector4F { let mut factors = F32x4::splat(x); factors[3] = 1.0; Vector4F(self.0 * factors) } #[inline] pub fn set_x(&mut self, x: f32) { self.0[0] = x } #[inline] pub fn set_y(&mut self, y: f32) { self.0[1] = y } #[inline] pub fn set_z(&mut self, z: f32) { self.0[2] = z } #[inline] pub fn set_w(&mut self, w: f32) { self.0[3] = w } #[inline] pub fn approx_eq(self, other: Vector4F, epsilon: f32) -> bool { self.0.approx_eq(other.0, epsilon) } /// Checks to see whether this *homogeneous* coordinate equals zero. /// /// Note that since this treats the coordinate as a homogeneous coordinate, the `w` is ignored. // TODO(pcwalton): Optimize with SIMD. #[inline] pub fn is_zero(self) -> bool { self.x() == 0.0 && self.y() == 0.0 && self.z() == 0.0 } #[inline] pub fn lerp(self, other: Vector4F, t: f32) -> Vector4F { Vector4F(self.0 + (other.0 - self.0) * F32x4::splat(t)) } } impl Add for Vector4F { type Output = Vector4F; #[inline] fn add(self, other: Vector4F) -> Vector4F { Vector4F(self.0 + other.0) } } impl AddAssign for Vector4F { #[inline] fn add_assign(&mut self, other: Vector4F) { self.0 += other.0 } } impl Mul for Vector4F { type Output = Vector4F; #[inline] fn mul(self, other: Vector4F) -> Vector4F { Vector4F(self.0 * other.0) } } impl Neg for Vector4F { type Output = Vector4F; /// NB: This does not negate w, because that is rarely what you what for homogeneous /// coordinates. #[inline] fn neg(self) -> Vector4F { Vector4F(self.0 * F32x4::new(-1.0, -1.0, -1.0, 1.0)) } } impl Sub for Vector4F { type Output = Vector4F; #[inline] fn sub(self, other: Vector4F) -> Vector4F { Vector4F(self.0 - other.0) } } impl Default for Vector4F { #[inline] fn default() -> Vector4F { let mut point = F32x4::default(); point.set_w(1.0); Vector4F(point) } } pathfinder_geometry-0.5.1/.cargo_vcs_info.json0000644000000001121364640761600152030ustar00{ "git": { "sha1": "a5e98fac00f433fe2ff4b2135383d82491b8bfc5" } }