Skip to content

Commit

Permalink
Further genericize QuadToCubic, add a test for it.
Browse files Browse the repository at this point in the history
Needed for work on Logicalshift/flo_curves#14.
  • Loading branch information
ctrlcctrlv committed Feb 7, 2022
1 parent 35ef688 commit 580b814
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 11 deletions.
22 changes: 11 additions & 11 deletions src/outline/quad_to_cubic.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use crate::point::{FromKurboPoint, ToKurboPoint};
use crate::point::PointLike;

pub trait QuadToCubic<QCO: FromKurboPoint + ToKurboPoint, const N: usize> {
pub trait QuadToCubic<QCO: Default, const N: usize> {
fn quad_to_cubic(self) -> [QCO; N];
}

// This method of Quad->Cubic conversion is used all over the place in FontForge.
impl<QCO: FromKurboPoint + ToKurboPoint> QuadToCubic<QCO, 4> for [QCO; 3] {
impl<QCO> QuadToCubic<QCO, 4> for [QCO; 3] where QCO: PointLike + Default {
fn quad_to_cubic(self) -> [QCO; 4] {
#[allow(unused_assignments)]
let [p0_o, p1_o, p2_o, p3_o] = [self[0].to_kurbo(), self[1].to_kurbo(), self[2].to_kurbo(), self[2].to_kurbo()];
let [p0, mut p1, mut p2, p3] = [p0_o, p1_o, p2_o, p3_o];
p1.x = p0_o.x + (2./3.) * (p1_o.x-p0_o.x);
p1.y = p0_o.y + (2./3.) * (p1_o.y-p0_o.y);
p2.x = p2_o.x + (2./3.) * (p1_o.x-p2_o.x);
p2.y = p2_o.y + (2./3.) * (p1_o.y-p2_o.y);
[QCO::from_kurbo(&p0), QCO::from_kurbo(&p1), QCO::from_kurbo(&p2), QCO::from_kurbo(&p3)]
let [p0_o, p1_o, p2_o] = self;
let (mut p1, mut p2): (QCO, QCO) = Default::default();
p1.set_x( p0_o.x() + (2./3.) * (p1_o.x()-p0_o.x()) );
p1.set_y( p0_o.y() + (2./3.) * (p1_o.y()-p0_o.y()) );
p2.set_x( p2_o.x() + (2./3.) * (p1_o.x()-p2_o.x()) );
p2.set_y( p2_o.y() + (2./3.) * (p1_o.y()-p2_o.y()) );
let (p0, p3) = (p0_o, p2_o);
[p0, p1, p2, p3]
}
}
23 changes: 23 additions & 0 deletions src/point/conv/skia.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use integer_or_float::IntegerOrFloat;
use skia_safe as skia;
use skia::{Point as SkPoint};
use super::kurbo::{KurboPoint, FromKurboPoint, ToKurboPoint};
use crate::point::{IsValid, PointLike};

pub trait ToSkiaPoint {
fn to_skia(&self) -> SkPoint;
Expand All @@ -23,3 +25,24 @@ impl FromKurboPoint for SkPoint {
kp.to_skia()
}
}

impl IsValid for SkPoint {
fn is_valid(&self) -> bool {
!self.x.is_nan() && !self.y.is_nan()
}
}

impl PointLike for SkPoint {
fn x(&self) -> IntegerOrFloat {
IntegerOrFloat::Float(self.x)
}
fn y(&self) -> IntegerOrFloat {
IntegerOrFloat::Float(self.y)
}
fn set_x(&mut self, x: IntegerOrFloat) {
self.set(f32::from(x), self.y)
}
fn set_y(&mut self, y: IntegerOrFloat) {
self.set(self.x, f32::from(y))
}
}
47 changes: 47 additions & 0 deletions tests/quad_to_cubic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use glifparser::glif::IntoXML as _;
use glifparser::outline::{GlifOutline, QuadToCubic as _};
use glifparser::point::{GlifPoint, PointType};
use glifparser::write;
use glifparser::{Glif, Handle, Outline, Point};

static PARABOLA: [[Point<()>; 2]; 1] = {
use Handle::*;
use PointType::*;
[[
Point {
b: Colocated,
x: 0.0,
y: 0.0,
a: At(66.66667, 333.33334),
name: None,
ptype: Move,
smooth: false,
data: None,
},
Point {
b: At(133.33333, 333.33334),
x: 200.0,
y: 0.0,
a: Colocated,
name: None,
ptype: Curve,
smooth: false,
data: None,
},
]]
};

#[test]
fn parabola() {
let gp_s = GlifPoint::from_x_y_type((0., 0.), PointType::Move);
let gp_o = GlifPoint::from_x_y_type((100., 500.), PointType::OffCurve);
let gp_e = GlifPoint::from_x_y_type((200., 0.), PointType::Curve);
let result: GlifOutline =
vec![[gp_s, gp_o, gp_e.clone()].quad_to_cubic().into_iter().collect()].into();
let result: Outline<()> = result.try_into().unwrap();
let mut glif = Glif::new();
assert_eq!(&result, &PARABOLA);
glif.outline = Some(result);
//eprintln!("{}", write(&glif).unwrap());
write(&glif).unwrap();
}

0 comments on commit 580b814

Please sign in to comment.