Skip to content

Commit

Permalink
Better transform API.
Browse files Browse the repository at this point in the history
Add a Transformation trait to avoid forcing the matrix representation to transform paths and segments.
  • Loading branch information
nical committed Dec 25, 2019
1 parent db00133 commit 1ec7a61
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 67 deletions.
4 changes: 2 additions & 2 deletions algorithms/src/fit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub enum FitStyle {
}

/// Computes a transform that fits a rectangle into another one.
pub fn fit_rectangle(src_rect: &Rect, dst_rect: &Rect, style: FitStyle) -> Transform2D {
pub fn fit_rectangle(src_rect: &Rect, dst_rect: &Rect, style: FitStyle) -> Transform {
let scale: Vector = vector(
dst_rect.size.width / src_rect.size.width,
dst_rect.size.height / src_rect.size.height
Expand All @@ -45,7 +45,7 @@ pub fn fit_rectangle(src_rect: &Rect, dst_rect: &Rect, style: FitStyle) -> Trans
let src_center = src_rect.origin.lerp(src_rect.max(), 0.5);
let dst_center = dst_rect.origin.lerp(dst_rect.max(), 0.5);

Transform2D::create_translation(-src_center.x, -src_center.y)
Transform::create_translation(-src_center.x, -src_center.y)
.post_scale(scale.x, scale.y)
.post_translate(dst_center.to_vector())
}
Expand Down
35 changes: 17 additions & 18 deletions algorithms/src/hatching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
use crate::path::PathEvent;
use crate::path::builder::{Build, FlatPathBuilder, PathBuilder};
use crate::geom::LineSegment;
use crate::geom::math::{Point, Vector, point, vector};
use crate::geom::euclid::{Angle, default::Rotation2D};
use crate::geom::math::{Point, Vector, point, vector, Angle, Rotation};
use std::marker::PhantomData;

use std::cmp::Ordering;
Expand All @@ -49,7 +48,7 @@ pub struct HatchingOptions {
/// Angle between the hatching pattern and the x axis.
///
/// Default value: `HatchingOptions::ANGLE`.
pub angle: Angle<f32>,
pub angle: Angle,
/// Whether to compute the tangent of the outline where it meets the hatching pattern.
///
/// Default value: `true, .
Expand All @@ -71,7 +70,7 @@ impl HatchingOptions {
/// Default flattening tolerance.
pub const DEFAULT_TOLERANCE: f32 = 0.1;
/// Default hatching angle.
pub const DEFAULT_ANGLE: Angle<f32> = Angle { radians: 0.0 };
pub const DEFAULT_ANGLE: Angle = Angle { radians: 0.0 };
pub const DEFAULT_UV_ORIGIN: Point = Point { x: 0.0, y: 0.0, _unit: PhantomData };

pub const DEFAULT: Self = HatchingOptions {
Expand All @@ -88,7 +87,7 @@ impl HatchingOptions {
}

#[inline]
pub fn angle(angle: Angle<f32>) -> Self {
pub fn angle(angle: Angle) -> Self {
Self::DEFAULT.with_angle(angle)
}

Expand All @@ -99,7 +98,7 @@ impl HatchingOptions {
}

#[inline]
pub fn with_angle(mut self, angle: Angle<f32>) -> Self {
pub fn with_angle(mut self, angle: Angle) -> Self {
self.angle = angle;
self
}
Expand All @@ -124,7 +123,7 @@ pub struct DotOptions {
/// Angle between the hatching pattern and the x axis.
///
/// Default value: `HatchingOptions::ANGLE`.
pub angle: Angle<f32>,
pub angle: Angle,
/// The origin of the rotated uv coordinates.
pub uv_origin: Point,

Expand All @@ -141,7 +140,7 @@ impl DotOptions {
/// Default flattening tolerance.
pub const DEFAULT_TOLERANCE: f32 = 0.1;
/// Default inclination of the dot pattern.
pub const DEFAULT_ANGLE: Angle<f32> = Angle { radians: 0.0 };
pub const DEFAULT_ANGLE: Angle = Angle { radians: 0.0 };
pub const DEFAULT_UV_ORIGIN: Point = Point { x: 0.0, y: 0.0, _unit: PhantomData };

pub const DEFAULT: Self = DotOptions {
Expand All @@ -157,7 +156,7 @@ impl DotOptions {
}

#[inline]
pub fn angle(angle: Angle<f32>) -> Self {
pub fn angle(angle: Angle) -> Self {
Self::DEFAULT.with_angle(angle)
}

Expand All @@ -168,7 +167,7 @@ impl DotOptions {
}

#[inline]
pub fn with_angle(mut self, angle: Angle<f32>) -> Self {
pub fn with_angle(mut self, angle: Angle) -> Self {
self.angle = angle;
self
}
Expand Down Expand Up @@ -254,7 +253,7 @@ pub struct RegularDotPattern<Cb: FnMut(&Dot)> {
pub struct Hatcher {
events: HatchingEvents,
active_edges: Vec<Edge>,
transform: Rotation2D<f32>,
transform: Rotation,
compute_tangents: bool,
segment: HatchSegment,
uv_origin: Point,
Expand All @@ -266,7 +265,7 @@ impl Hatcher {
Hatcher {
events: HatchingEvents::new(),
active_edges: Vec::new(),
transform: Rotation2D::identity(),
transform: Rotation::identity(),
compute_tangents: true,
segment: HatchSegment {
a: HatchEndpoint {
Expand Down Expand Up @@ -328,8 +327,8 @@ impl Hatcher {
options: &HatchingOptions,
output: &mut dyn HatchBuilder
) {
self.transform = Rotation2D::new(-options.angle);
self.uv_origin = Rotation2D::new(options.angle).transform_point(
self.transform = Rotation::new(-options.angle);
self.uv_origin = Rotation::new(options.angle).transform_point(
options.uv_origin
);
self.active_edges.clear();
Expand Down Expand Up @@ -452,14 +451,14 @@ impl HatchingEvents {

struct EventsBuilder {
edges: Vec<Edge>,
angle: Angle<f32>,
angle: Angle,
first: Point,
current: Point,
nth: u32,
}

impl EventsBuilder {
fn new(angle: Angle<f32>) -> Self {
fn new(angle: Angle) -> Self {
EventsBuilder {
edges: Vec::new(),
angle,
Expand All @@ -470,7 +469,7 @@ impl EventsBuilder {
}

fn add_edge(&mut self, from: Point, to: Point) {
let rotation = Rotation2D::new(self.angle);
let rotation = Rotation::new(self.angle);
let mut from = rotation.transform_point(from);
let mut to = rotation.transform_point(to);
if compare_positions(from, to) == Ordering::Greater {
Expand Down Expand Up @@ -547,7 +546,7 @@ impl HatchingEvents {
pub fn set_path<Iter>(
&mut self,
tolerance: f32,
angle: Angle<f32>,
angle: Angle,
it: Iter
)
where Iter: Iterator<Item = PathEvent>
Expand Down
8 changes: 4 additions & 4 deletions geom/src/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::mem::swap;

use crate::Line;
use crate::scalar::{Scalar, Float, cast};
use crate::generic_math::{Point, point, Vector, vector, Rotation2D, Transform2D, Angle, Rect};
use crate::generic_math::{Point, point, Vector, vector, Rotation, Transform, Angle, Rect};
use crate::segment::{Segment, FlatteningStep, BoundingRect};
use crate::segment;
use crate::QuadraticBezierSegment;
Expand Down Expand Up @@ -330,7 +330,7 @@ impl<S: Scalar> Arc<S> {

/// Returns a conservative rectangle that contains the curve.
pub fn fast_bounding_rect(&self) -> Rect<S> {
Transform2D::create_rotation(self.x_rotation).transform_rect(
Transform::create_rotation(self.x_rotation).transform_rect(
&Rect::new(
self.center - self.radii,
self.radii.to_size() * S::TWO
Expand Down Expand Up @@ -445,7 +445,7 @@ impl<S: Scalar> Arc<S> {
#[inline]
fn tangent_at_angle(&self, angle: Angle<S>) -> Vector<S> {
let a = angle.get();
Rotation2D::new(self.x_rotation).transform_vector(
Rotation::new(self.x_rotation).transform_vector(
vector(-self.radii.x * Float::sin(a), self.radii.y * Float::cos(a))
)
}
Expand Down Expand Up @@ -599,7 +599,7 @@ where
}

fn sample_ellipse<S: Scalar>(radii: Vector<S>, x_rotation: Angle<S>, angle: Angle<S>) -> Point<S> {
Rotation2D::new(x_rotation).transform_point(
Rotation::new(x_rotation).transform_point(
point(radii.x * Float::cos(angle.get()), radii.y * Float::sin(angle.get()))
)
}
Expand Down
5 changes: 3 additions & 2 deletions geom/src/cubic_bezier.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
pub use crate::flatten_cubic::Flattened;
use crate::{Line, LineSegment, LineEquation, QuadraticBezierSegment};
use crate::scalar::Scalar;
use crate::generic_math::{Point, Vector, Rect, rect, Transform2D};
use crate::generic_math::{Point, Vector, Rect, rect};
use crate::flatten_cubic::{flatten_cubic_bezier, flatten_cubic_bezier_with_t, find_cubic_bezier_inflection_points};
use crate::cubic_to_quadratic::*;
use crate::cubic_bezier_intersections::cubic_bezier_intersections_t;
use crate::monotonic::Monotonic;
use crate::utils::{min_max, cubic_polynomial_roots};
use crate::segment::{Segment, BoundingRect};
use crate::traits::Transformation;
use arrayvec::ArrayVec;

use std::ops::Range;
Expand Down Expand Up @@ -290,7 +291,7 @@ impl<S: Scalar> CubicBezierSegment<S> {

/// Applies the transform to this curve and returns the results.
#[inline]
pub fn transform(&self, transform: &Transform2D<S>) -> Self {
pub fn transformed<T: Transformation<S>>(&self, transform: &T) -> Self {
CubicBezierSegment {
from: transform.transform_point(self.from),
ctrl1: transform.transform_point(self.ctrl1),
Expand Down
74 changes: 64 additions & 10 deletions geom/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,16 @@ mod generic_math {
pub use euclid::default::Rect;

/// Alias for `euclid::default::Transform2D`
pub use euclid::default::Transform2D;
pub type Transform<S> = euclid::default::Transform2D<S>;

/// Alias for `euclid::default::Rotation2D`
pub use euclid::default::Rotation2D;
pub type Rotation<S> = euclid::default::Rotation2D<S>;

/// Alias for `euclid::default::Translation2D`
pub type Translation<S> = euclid::Translation2D<S, euclid::UnknownUnit, euclid::UnknownUnit>;

/// Alias for `euclid::default::Scale`
pub use euclid::default::Scale;

/// An angle in radians.
pub use euclid::Angle;
Expand Down Expand Up @@ -249,10 +255,16 @@ pub mod math {
pub type Rect = euclid::default::Rect<f32>;

/// Alias for ```euclid::default::Transform2D<f32>```
pub type Transform2D = euclid::default::Transform2D<f32>;
pub type Transform = euclid::default::Transform2D<f32>;

/// Alias for ```euclid::default::Rotation2D<f32>```
pub type Rotation2D = euclid::default::Rotation2D<f32>;
pub type Rotation = euclid::default::Rotation2D<f32>;

/// Alias for ```euclid::default::Translation2D<f32>```
pub type Translation = euclid::Translation2D<f32, euclid::UnknownUnit, euclid::UnknownUnit>;

/// Alias for ```euclid::default::Scale<f32>```
pub type Scale = euclid::default::Scale<f32>;

/// An angle in radians (f32).
pub type Angle = euclid::Angle<f32>;
Expand All @@ -268,15 +280,57 @@ pub mod math {

/// Shorthand for `Size::new(x, y)`.
pub use euclid::size2 as size;

/// Anything that can be transformed in 2D.
pub trait Transform {
fn transform(&self, mat: &Transform2D) -> Self;
}
}


pub mod traits {
pub use crate::segment::{Segment, FlatteningStep};
//pub use monotonic::MonotonicSegment;

use crate::generic_math::{Point, Vector, Transform, Rotation, Translation, Scale};
use crate::Scalar;

pub trait Transformation<S> {
fn transform_point(&self, p: Point<S>) -> Point<S>;
fn transform_vector(&self, v: Vector<S>) -> Vector<S>;
}

impl<S: Scalar> Transformation<S> for Transform<S> {
fn transform_point(&self, p: Point<S>) -> Point<S> {
self.transform_point(p)
}

fn transform_vector(&self, v: Vector<S>) -> Vector<S> {
self.transform_vector(v)
}
}

impl<S: Scalar> Transformation<S> for Rotation<S> {
fn transform_point(&self, p: Point<S>) -> Point<S> {
self.transform_point(p)
}

fn transform_vector(&self, v: Vector<S>) -> Vector<S> {
self.transform_vector(v)
}
}

impl<S: Scalar> Transformation<S> for Translation<S> {
fn transform_point(&self, p: Point<S>) -> Point<S> {
self.transform_point(p)
}

fn transform_vector(&self, v: Vector<S>) -> Vector<S> {
v
}
}

impl<S: Scalar> Transformation<S> for Scale<S> {
fn transform_point(&self, p: Point<S>) -> Point<S> {
self.transform_point(p)
}

fn transform_vector(&self, v: Vector<S>) -> Vector<S> {
self.transform_vector(v)
}
}
}
5 changes: 3 additions & 2 deletions geom/src/line.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::scalar::Scalar;
use crate::generic_math::{Point, point, Vector, vector, Rect, Size, Transform2D};
use crate::generic_math::{Point, point, Vector, vector, Rect, Size};
use crate::segment::{Segment, FlatteningStep, BoundingRect};
use crate::monotonic::MonotonicSegment;
use crate::utils::min_max;
use crate::traits::Transformation;
use std::mem::swap;

use std::ops::Range;
Expand Down Expand Up @@ -168,7 +169,7 @@ impl<S: Scalar> LineSegment<S> {

/// Applies the transform to this segment and returns the results.
#[inline]
pub fn transform(&self, transform: &Transform2D<S>) -> Self {
pub fn transformed<T: Transformation<S>>(&self, transform: &T) -> Self {
LineSegment {
from: transform.transform_point(self.from),
to: transform.transform_point(self.to),
Expand Down
5 changes: 3 additions & 2 deletions geom/src/quadratic_bezier.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::{CubicBezierSegment, Triangle, Line, LineSegment, LineEquation};
use crate::scalar::Scalar;
use crate::generic_math::{Point, Vector, Rect, rect, Transform2D};
use crate::generic_math::{Point, Vector, Rect, rect};
use crate::monotonic::Monotonic;
use crate::segment::{Segment, FlatteningStep, BoundingRect};
use crate::segment;
use crate::traits::Transformation;
use arrayvec::ArrayVec;

use std::ops::Range;
Expand Down Expand Up @@ -245,7 +246,7 @@ impl<S: Scalar> QuadraticBezierSegment<S> {

/// Applies the transform to this curve and returns the results.
#[inline]
pub fn transform(&self, transform: &Transform2D<S>) -> Self {
pub fn transformed<T: Transformation<S>>(&self, transform: &T) -> Self {
QuadraticBezierSegment {
from: transform.transform_point(self.from),
ctrl: transform.transform_point(self.ctrl),
Expand Down
5 changes: 3 additions & 2 deletions geom/src/triangle.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::scalar::Scalar;
use crate::generic_math::{Point, Rect, Size, Transform2D};
use crate::generic_math::{Point, Rect, Size};
use crate::traits::Transformation;
use crate::LineSegment;

/// A 2D triangle defined by three points `a`, `b` and `c`.
Expand Down Expand Up @@ -74,7 +75,7 @@ impl<S: Scalar> Triangle<S> {

/// [Not implemented] Applies the transform to this triangle and returns the results.
#[inline]
pub fn transform(&self, transform: &Transform2D<S>) -> Self {
pub fn transform<T: Transformation<S>>(&self, transform: &T) -> Self {
Triangle {
a: transform.transform_point(self.a),
b: transform.transform_point(self.b),
Expand Down
Loading

0 comments on commit 1ec7a61

Please sign in to comment.