add mirror_and_close path operator
This commit is contained in:
parent
636d5da589
commit
7e05972549
|
@ -743,6 +743,11 @@ impl Path2D {
|
||||||
self.current_contour = last_contour.unwrap_or_else(Contour::new);
|
self.current_contour = last_contour.unwrap_or_else(Contour::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mirror_and_close_last(&mut self) {
|
||||||
|
self.current_contour.mirror_and_close();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn into_outline(mut self) -> Outline {
|
pub fn into_outline(mut self) -> Outline {
|
||||||
self.flush_current_contour();
|
self.flush_current_contour();
|
||||||
self.outline
|
self.outline
|
||||||
|
|
|
@ -20,6 +20,7 @@ use pathfinder_geometry::transform2d::Transform2F;
|
||||||
use pathfinder_geometry::transform3d::Perspective;
|
use pathfinder_geometry::transform3d::Perspective;
|
||||||
use pathfinder_geometry::unit_vector::UnitVector;
|
use pathfinder_geometry::unit_vector::UnitVector;
|
||||||
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
use pathfinder_geometry::vector::{Vector2F, vec2f};
|
||||||
|
use pathfinder_geometry::util::reflection;
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -342,6 +343,11 @@ impl Contour {
|
||||||
self.points[index as usize]
|
self.points[index as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn first_position(&self) -> Option<Vector2F> {
|
||||||
|
self.points.first().cloned()
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn last_position(&self) -> Option<Vector2F> {
|
pub fn last_position(&self) -> Option<Vector2F> {
|
||||||
self.points.last().cloned()
|
self.points.last().cloned()
|
||||||
|
@ -628,6 +634,31 @@ impl Contour {
|
||||||
Some(bounds) => bounds.union_rect(self.bounds),
|
Some(bounds) => bounds.union_rect(self.bounds),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mirror_and_close(&mut self) {
|
||||||
|
if self.points.len() < 2 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let a = self.first_position().unwrap();
|
||||||
|
let b = self.last_position().unwrap();
|
||||||
|
if a == b {
|
||||||
|
self.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let tr = reflection(a, b);
|
||||||
|
|
||||||
|
let mut segments: Vec<_> = self
|
||||||
|
.iter(ContourIterFlags::empty())
|
||||||
|
.map(|segment| segment.reversed().transform(&tr))
|
||||||
|
.collect();
|
||||||
|
segments.reverse();
|
||||||
|
|
||||||
|
for segment in &segments {
|
||||||
|
self.push_segment(segment, PushSegmentFlags::UPDATE_BOUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Contour {
|
impl Debug for Contour {
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
//! Various utilities.
|
//! Various utilities.
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
|
use crate::transform2d::{Transform2F, Matrix2x2F};
|
||||||
|
use crate::vector::Vector2F;
|
||||||
|
|
||||||
pub const EPSILON: f32 = 0.001;
|
pub const EPSILON: f32 = 0.001;
|
||||||
|
|
||||||
|
@ -37,3 +39,17 @@ pub fn clamp(x: f32, min_val: f32, max_val: f32) -> f32 {
|
||||||
pub fn alignup_i32(a: i32, b: i32) -> i32 {
|
pub fn alignup_i32(a: i32, b: i32) -> i32 {
|
||||||
(a + b - 1) / b
|
(a + b - 1) / b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reflection(a: Vector2F, b: Vector2F) -> Transform2F {
|
||||||
|
let l = b - a;
|
||||||
|
let l2 = l * l;
|
||||||
|
let l2_yx = l2.yx();
|
||||||
|
let d = l2 - l2_yx;
|
||||||
|
let lxy2 = 2.0 * l.x() * l.y();
|
||||||
|
let s = 1.0 / (l2.x() + l2.y());
|
||||||
|
|
||||||
|
Transform2F::from_translation(-a) * Transform2F {
|
||||||
|
matrix: Matrix2x2F::row_major(d.x(), lxy2, lxy2, d.y()).scale(s),
|
||||||
|
vector: a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue