// PathSegment, Path, and PathBuilder vector path representation.
///|
pub enum PathSegment {
MoveTo(@math.Vec2)
LineTo(@math.Vec2)
QuadTo(@math.Vec2, @math.Vec2)
CubicTo(@math.Vec2, @math.Vec2, @math.Vec2)
ArcTo(Double, Double, Double, Bool, Bool, @math.Vec2)
Close
} derive(Eq, Debug)
///|
pub impl Show for PathSegment with fn output(self, logger) {
match self {
MoveTo(p) =>
logger.write_string("M " + p.x.to_string() + " " + p.y.to_string())
LineTo(p) =>
logger.write_string("L " + p.x.to_string() + " " + p.y.to_string())
QuadTo(control, end) =>
logger.write_string(
"Q " +
control.x.to_string() +
" " +
control.y.to_string() +
" " +
end.x.to_string() +
" " +
end.y.to_string(),
)
CubicTo(control1, control2, end) =>
logger.write_string(
"C " +
control1.x.to_string() +
" " +
control1.y.to_string() +
" " +
control2.x.to_string() +
" " +
control2.y.to_string() +
" " +
end.x.to_string() +
" " +
end.y.to_string(),
)
ArcTo(radius_x, radius_y, _, _, _, end) =>
logger.write_string(
"A " +
radius_x.to_string() +
" " +
radius_y.to_string() +
" " +
end.x.to_string() +
" " +
end.y.to_string(),
)
Close => logger.write_string("Z")
}
}
///|
pub struct Path {
segments : Array[PathSegment]
} derive(Eq, Debug)
///|
pub impl Show for Path with fn output(self, logger) {
let mut first = true
for i = 0; i < self.segments.length(); i = i + 1 {
if !first {
logger.write_string(" ")
}
logger.write_string(Show::to_string(self.segments[i]))
first = false
}
}
///|
pub fn Path::empty() -> Path {
{ segments: [] }
}
///|
pub fn Path::new(segments : Array[PathSegment]) -> Path {
{ segments, }
}
///|
pub fn Path::bounds(self : Path) -> @math.Rect2D {
let mut curr = @math.Vec2::zero()
let mut start_p = @math.Vec2::zero()
let mut rect = @math.Rect2D::empty()
for i = 0; i < self.segments.length(); i = i + 1 {
match self.segments[i] {
MoveTo(p) => {
curr = p
start_p = p
rect = rect.union(@math.Rect2D::from_point(p))
}
LineTo(p) => {
rect = rect
.union(@math.Rect2D::from_point(curr))
.union(@math.Rect2D::from_point(p))
curr = p
}
QuadTo(control, end) => {
let quad = @math.QuadraticBezier::new(curr, control, end)
let cb = quad.to_cubic()
rect = rect.union(cb.bounds())
curr = end
}
CubicTo(control1, control2, end) => {
let cb = @math.CubicBezier::new(curr, control1, control2, end)
rect = rect.union(cb.bounds())
curr = end
}
ArcTo(_, _, _, _, _, end) => {
rect = rect
.union(@math.Rect2D::from_point(curr))
.union(@math.Rect2D::from_point(end))
curr = end
}
Close => curr = start_p
}
}
rect
}
///|
pub struct PathBuilder {
segments : Array[PathSegment]
} derive(Eq, Debug)
///|
pub fn PathBuilder::new() -> PathBuilder {
{ segments: [] }
}
///|
pub fn PathBuilder::move_to(self : PathBuilder, p : @math.Vec2) -> PathBuilder {
self.segments.push(MoveTo(p))
self
}
///|
pub fn PathBuilder::line_to(self : PathBuilder, p : @math.Vec2) -> PathBuilder {
self.segments.push(LineTo(p))
self
}
///|
pub fn PathBuilder::quad_to(
self : PathBuilder,
control : @math.Vec2,
end : @math.Vec2,
) -> PathBuilder {
self.segments.push(QuadTo(control, end))
self
}
///|
pub fn PathBuilder::cubic_to(
self : PathBuilder,
control1 : @math.Vec2,
control2 : @math.Vec2,
end : @math.Vec2,
) -> PathBuilder {
self.segments.push(CubicTo(control1, control2, end))
self
}
///|
pub fn PathBuilder::arc_to(
self : PathBuilder,
rx : Double,
ry : Double,
rot : Double,
large : Bool,
sweep : Bool,
end : @math.Vec2,
) -> PathBuilder {
self.segments.push(ArcTo(rx, ry, rot, large, sweep, end))
self
}
///|
pub fn PathBuilder::close_path(self : PathBuilder) -> PathBuilder {
self.segments.push(Close)
self
}
///|
pub fn PathBuilder::build(self : PathBuilder) -> Path {
Path::new(self.segments)
}