Add convenience translation, rotation, and scaling methods to `Transform2D`

This commit is contained in:
Patrick Walton 2019-07-12 11:34:48 -07:00
parent 1eb28a5539
commit 2c984de1ea
7 changed files with 29 additions and 44 deletions

View File

@ -441,8 +441,7 @@ impl Path2D {
start_angle: f32, start_angle: f32,
end_angle: f32, end_angle: f32,
direction: ArcDirection) { direction: ArcDirection) {
let mut transform = Transform2F::from_scale(Vector2F::splat(radius)); let transform = Transform2F::from_scale(Vector2F::splat(radius)).translate(center);
transform = Transform2F::from_translation(center) * transform;
self.current_contour.push_arc(&transform, start_angle, end_angle, direction); self.current_contour.push_arc(&transform, start_angle, end_angle, direction);
} }
@ -456,8 +455,7 @@ impl Path2D {
let bisector = vu0 + vu1; let bisector = vu0 + vu1;
let center = ctrl + bisector.scale(hypot / bisector.length()); let center = ctrl + bisector.scale(hypot / bisector.length());
let mut transform = Transform2F::from_scale(Vector2F::splat(radius)); let transform = Transform2F::from_scale(Vector2F::splat(radius)).translate(center);
transform = Transform2F::from_translation(center) * transform;
let chord = LineSegment2F::new(vu0.yx().scale_xy(Vector2F::new(-1.0, 1.0)), let chord = LineSegment2F::new(vu0.yx().scale_xy(Vector2F::new(-1.0, 1.0)),
vu1.yx().scale_xy(Vector2F::new(1.0, -1.0))); vu1.yx().scale_xy(Vector2F::new(1.0, -1.0)));
@ -483,9 +481,7 @@ impl Path2D {
end_angle: f32) { end_angle: f32) {
self.flush_current_contour(); self.flush_current_contour();
let mut transform = Transform2F::from_translation(center); let transform = Transform2F::from_scale(axes).rotate(rotation).translate(center);
transform *= Transform2F::from_rotation(rotation);
transform *= Transform2F::from_scale(axes);
self.current_contour.push_arc(&transform, start_angle, end_angle, ArcDirection::CW); self.current_contour.push_arc(&transform, start_angle, end_angle, ArcDirection::CW);
if end_angle - start_angle >= 2.0 * PI { if end_angle - start_angle >= 2.0 * PI {

View File

@ -138,9 +138,8 @@ impl<'a> OutlineStrokeToFill<'a> {
LineCap::Round => { LineCap::Round => {
let scale = Vector2F::splat(width * 0.5); let scale = Vector2F::splat(width * 0.5);
let offset = gradient.yx().scale_xy(Vector2F::new(-1.0, 1.0)); let offset = gradient.yx().scale_xy(Vector2F::new(-1.0, 1.0));
let mut transform = Transform2F::from_scale(scale);
let translation = p1 + offset.scale(width * 0.5); let translation = p1 + offset.scale(width * 0.5);
transform = Transform2F::from_translation(translation) * transform; let transform = Transform2F::from_scale(scale).translate(translation);
let chord = LineSegment2F::new(-offset, offset); let chord = LineSegment2F::new(-offset, offset);
contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW); contour.push_arc_from_unit_chord(&transform, chord, ArcDirection::CW);
} }
@ -374,8 +373,7 @@ impl Contour {
} }
LineJoin::Round => { LineJoin::Round => {
let scale = Vector2F::splat(distance.abs()); let scale = Vector2F::splat(distance.abs());
let mut transform = Transform2F::from_translation(join_point); let transform = Transform2F::from_scale(scale).translate(join_point);
transform *= Transform2F::from_scale(scale);
let chord_from = (prev_tangent.to() - join_point).normalize(); let chord_from = (prev_tangent.to() - join_point).normalize();
let chord_to = (next_tangent.to() - join_point).normalize(); let chord_to = (next_tangent.to() - join_point).normalize();
let chord = LineSegment2F::new(chord_from, chord_to); let chord = LineSegment2F::new(chord_from, chord_to);

View File

@ -14,7 +14,7 @@
// proper. // proper.
use crate::window::{OcularTransform, View}; use crate::window::{OcularTransform, View};
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F}; use pathfinder_geometry::vector::{Vector2I, Vector4F};
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2F; use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::transform3d::{Perspective, Transform4F}; use pathfinder_geometry::transform3d::{Perspective, Transform4F};
@ -56,8 +56,7 @@ impl Camera {
let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32 let scale = i32::min(viewport_size.x(), viewport_size.y()) as f32
* scale_factor_for_view_box(view_box); * scale_factor_for_view_box(view_box);
let origin = viewport_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5); let origin = viewport_size.to_f32().scale(0.5) - view_box.size().scale(scale * 0.5);
Camera::TwoD(Transform2F::from_translation(origin) * Camera::TwoD(Transform2F::from_uniform_scale(scale).translate(origin))
Transform2F::from_uniform_scale(scale))
} }
fn new_3d(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera { fn new_3d(mode: Mode, view_box: RectF, viewport_size: Vector2I) -> Camera {

View File

@ -327,10 +327,10 @@ impl<W> DemoApp<W> where W: Window {
if let Camera::TwoD(ref mut transform) = self.camera { if let Camera::TwoD(ref mut transform) = self.camera {
let backing_scale_factor = self.window_size.backing_scale_factor; let backing_scale_factor = self.window_size.backing_scale_factor;
let position = position.to_f32().scale(backing_scale_factor); let position = position.to_f32().scale(backing_scale_factor);
*transform = Transform2F::from_translation(-position) * *transform;
let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D; let scale_delta = 1.0 + d_dist * CAMERA_SCALE_SPEED_2D;
*transform = Transform2F::from_uniform_scale(scale_delta) * *transform; *transform = transform.translate(-position)
*transform = Transform2F::from_translation(position) * *transform; .uniform_scale(scale_delta)
.translate(position);
} }
} }
Event::Look { pitch, yaw } => { Event::Look { pitch, yaw } => {
@ -587,8 +587,7 @@ impl<W> DemoApp<W> where W: Window {
} }
UIEvent::MouseDragged(position) => { UIEvent::MouseDragged(position) => {
if let Camera::TwoD(ref mut transform) = self.camera { if let Camera::TwoD(ref mut transform) = self.camera {
*transform = Transform2F::from_translation(position.relative.to_f32()) * *transform = transform.translate(position.relative.to_f32());
*transform;
} }
} }
_ => {} _ => {}
@ -608,10 +607,7 @@ impl<W> DemoApp<W> where W: Window {
if let Camera::TwoD(ref mut transform) = self.camera { if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Vector2F::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D); let scale = Vector2F::splat(1.0 + CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window_size); let center = center_of_window(&self.window_size);
*transform = Transform2F::from_translation(center) * *transform = transform.translate(-center).scale(scale).translate(center);
Transform2F::from_scale(scale) *
Transform2F::from_translation(-center) *
*transform;
self.dirty = true; self.dirty = true;
} }
} }
@ -619,10 +615,7 @@ impl<W> DemoApp<W> where W: Window {
if let Camera::TwoD(ref mut transform) = self.camera { if let Camera::TwoD(ref mut transform) = self.camera {
let scale = Vector2F::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D); let scale = Vector2F::splat(1.0 - CAMERA_ZOOM_AMOUNT_2D);
let center = center_of_window(&self.window_size); let center = center_of_window(&self.window_size);
*transform = Transform2F::from_translation(center) * *transform = transform.translate(-center).scale(scale).translate(center);
Transform2F::from_scale(scale) *
Transform2F::from_translation(-center) *
*transform;
self.dirty = true; self.dirty = true;
} }
} }
@ -636,10 +629,9 @@ impl<W> DemoApp<W> where W: Window {
if let Camera::TwoD(ref mut transform) = self.camera { if let Camera::TwoD(ref mut transform) = self.camera {
let old_rotation = transform.rotation(); let old_rotation = transform.rotation();
let center = center_of_window(&self.window_size); let center = center_of_window(&self.window_size);
*transform = Transform2F::from_translation(-center) * *transform = transform.translate(-center)
Transform2F::from_rotation(*theta - old_rotation) * .rotate(*theta - old_rotation)
Transform2F::from_translation(center) * .translate(center);
*transform;
} }
} }
} }

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, LineJoin, Path2D}; use pathfinder_canvas::{CanvasFontContext, CanvasRenderingContext2D, Path2D};
use pathfinder_content::color::ColorF; use pathfinder_content::color::ColorF;
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_geometry::vector::{Vector2F, Vector2I};
@ -57,7 +57,6 @@ fn main() {
// Set line width. // Set line width.
canvas.set_line_width(10.0); canvas.set_line_width(10.0);
canvas.set_line_join(LineJoin::Round);
// Draw walls. // Draw walls.
canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0))); canvas.stroke_rect(RectF::new(Vector2F::new(75.0, 140.0), Vector2F::new(150.0, 110.0)));

View File

@ -246,22 +246,25 @@ impl Transform2F {
self.matrix.m22() self.matrix.m22()
} }
/*
#[inline] #[inline]
pub fn post_translate(&self, vector: Vector2F) -> Transform2F { pub fn translate(&self, vector: Vector2F) -> Transform2F {
self.post_mul(&Transform2F::from_translation(vector)) Transform2F::from_translation(vector) * *self
} }
#[inline] #[inline]
pub fn post_rotate(&self, theta: f32) -> Transform2F { pub fn rotate(&self, theta: f32) -> Transform2F {
self.post_mul(&Transform2F::from_rotation(theta)) Transform2F::from_rotation(theta) * *self
} }
#[inline] #[inline]
pub fn post_scale(&self, scale: Vector2F) -> Transform2F { pub fn scale(&self, scale: Vector2F) -> Transform2F {
self.post_mul(&Transform2F::from_scale(scale)) Transform2F::from_scale(scale) * *self
}
#[inline]
pub fn uniform_scale(&self, scale: f32) -> Transform2F {
self.scale(Vector2F::splat(scale))
} }
*/
/// Returns the translation part of this matrix. /// Returns the translation part of this matrix.
/// ///

View File

@ -93,9 +93,7 @@ impl SceneExt for Scene {
// FIXME(pcwalton): Cache this! // FIXME(pcwalton): Cache this!
let scale = style.size / (font.metrics().units_per_em as f32); let scale = style.size / (font.metrics().units_per_em as f32);
let scale = Vector2F::new(scale, -scale); let scale = Vector2F::new(scale, -scale);
let transform = *transform * let transform = *transform * Transform2F::from_scale(scale).translate(offset);
Transform2F::from_translation(offset) *
Transform2F::from_scale(scale);
self.push_glyph(font, self.push_glyph(font,
glyph.glyph_id, glyph.glyph_id,
&transform, &transform,