summaryrefslogtreecommitdiff
path: root/alligator_tvg/src/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alligator_tvg/src/path.rs')
-rw-r--r--alligator_tvg/src/path.rs294
1 files changed, 0 insertions, 294 deletions
diff --git a/alligator_tvg/src/path.rs b/alligator_tvg/src/path.rs
deleted file mode 100644
index d2bf4fb..0000000
--- a/alligator_tvg/src/path.rs
+++ /dev/null
@@ -1,294 +0,0 @@
-use std::io::{self, Read};
-
-use byteorder::ReadBytesExt;
-use num_enum::TryFromPrimitive;
-
-use crate::{header::TvgHeader, read_unit, read_varuint, Decode, Point};
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
-#[repr(u8)]
-enum Sweep {
- Right = 0,
- Left = 1,
-}
-
-/// An instruction to move a hypothetical "pen".
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, TryFromPrimitive)]
-#[repr(u8)]
-enum InstructionKind {
- /// A straight line is drawn from the current point to a new point.
- Line = 0,
- /// A straight horizontal line is drawn from the current point to a new x
- /// coordinate.
- HorizontalLine = 1,
- /// A straight vertical line is drawn from the current point to a new y
- /// coordiante.
- VerticalLine = 2,
- /// A cubic Bézier curve is drawn from the current point to a new point.
- CubicBezier = 3,
- /// A circle segment is drawn from current point to a new point.
- ArcCircle = 4,
- /// An ellipse segment is drawn from current point to a new point.
- ArcEllipse = 5,
- /// The path is closed, and a straight line is drawn to the starting point.
- ClosePath = 6,
- /// A quadratic Bézier curve is drawn from the current point to a new point.
- QuadraticBezier = 7,
-}
-
-#[derive(Debug, Clone, Copy)]
-enum InstructionData {
- /// The line instruction draws a straight line to the position.
- Line {
- /// The end point of the line.
- position: Point,
- },
- /// The horizontal line instruction draws a straight horizontal line to a
- /// given x coordinate.
- HorizontalLine {
- /// The new x coordinate.
- x: f64,
- },
- /// The vertical line instruction draws a straight vertical line to a given
- /// y coordinate.
- VerticalLine {
- /// The new y coordinate.
- y: f64,
- },
- /// The cubic bezier instruction draws a Bézier curve with two control
- /// points.
- ///
- /// The curve is drawn between the current location and `point_1` with
- /// `control_0` being the first control point and `control_1` being the
- /// second one.
- CubicBezier {
- /// The first control point.
- control_0: Point,
- /// The second control point.
- control_1: Point,
- /// The end point of the Bézier curve.
- point_1: Point,
- },
- /// Draws a circle segment between the current and the target point.
- ///
- /// The `radius` field determines the radius of the circle. If the distance
- /// between the current point and `target` is larger than `radius`, the
- /// distance is used as the radius.
- ArcCircle {
- /// If `true`, the large portion of the circle segment is drawn.
- large_arc: bool,
- /// Determines if the circle segment is left- or right bending.
- sweep: Sweep,
- /// The radius of the circle.
- radius: f64,
- /// The end point of the circle segment.
- target: Point,
- },
- /// Draws an ellipse segment between the current and the target point.
- ///
- /// The `radius_x` and `radius_y` fields determine the both radii of the
- /// ellipse. If the distance between the current point and target is not
- /// enough to fit any ellipse segment between the two points, `radius_x`
- /// and `radius_y` are scaled uniformly so that it fits exactly.
- ArcEllipse {
- /// If `true`, the large portion of the ellipse segment is drawn.
- large_arc: bool,
- /// Determines if the ellipse segment is left- or right bending.
- sweep: Sweep,
- /// The radius of the ellipse segment in the horizontal direction.
- radius_x: f64,
- /// The radius of the ellipse segment in the vertical direction.
- radius_y: f64,
- /// The rotation of the ellipse in mathematical negative direction, in
- /// degrees.
- rotation: f64,
- /// The end point of the ellipse segment.
- target: Point,
- },
- /// A straight line is drawn to the start location of the current segment.
- /// This instruction doesn’t have additional data encoded.
- ClosePath,
- /// The quadratic bezier instruction draws a Bézier curve with a single
- /// control point.
- ///
- /// The curve is drawn between the current location and `point_1` with
- /// control being the control point.
- QuadraticBezier {
- /// The control point.
- control: Point,
- /// The end point of the Bézier curve.
- target: Point,
- },
-}
-
-impl InstructionData {
- fn read(reader: &mut impl Read, header: &TvgHeader, kind: InstructionKind) -> io::Result<Self> {
- match kind {
- InstructionKind::Line => Self::read_line(reader, header),
- InstructionKind::HorizontalLine => Self::read_horizontal_line(reader, header),
- InstructionKind::VerticalLine => Self::read_vertical_line(reader, header),
- InstructionKind::CubicBezier => Self::read_cubic_bezier(reader, header),
- InstructionKind::ArcCircle => Self::read_arc_circle(reader, header),
- InstructionKind::ArcEllipse => Self::read_arc_ellipse(reader, header),
- InstructionKind::ClosePath => Ok(Self::ClosePath),
- InstructionKind::QuadraticBezier => Self::read_quadratic_bezier(reader, header),
- }
- }
-
- fn read_line(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- Ok(Self::Line {
- position: Point::read(reader, header)?,
- })
- }
-
- fn read_horizontal_line(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- Ok(Self::HorizontalLine {
- x: read_unit(reader, header)?,
- })
- }
-
- fn read_vertical_line(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- Ok(Self::VerticalLine {
- y: read_unit(reader, header)?,
- })
- }
-
- fn read_cubic_bezier(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- Ok(Self::CubicBezier {
- control_0: Point::read(reader, header)?,
- control_1: Point::read(reader, header)?,
- point_1: Point::read(reader, header)?,
- })
- }
-
- fn read_arc_header(reader: &mut impl Read, header: &TvgHeader) -> io::Result<(bool, Sweep)> {
- // large_arc and sweep are stored in the same byte
- let byte = reader.read_u8()?;
- let large_arc = (byte & 1) != 0;
- let sweep = match byte & 2 {
- 0 => Sweep::Left,
- _ => Sweep::Right,
- };
-
- Ok((large_arc, sweep))
- }
-
- fn read_arc_circle(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- let (large_arc, sweep) = Self::read_arc_header(reader, header)?;
- let radius = read_unit(reader, header)?;
- let target = Point::read(reader, header)?;
-
- Ok(Self::ArcCircle {
- large_arc,
- sweep,
- radius,
- target,
- })
- }
-
- fn read_arc_ellipse(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- let (large_arc, sweep) = Self::read_arc_header(reader, header)?;
- let radius_x = read_unit(reader, header)?;
- let radius_y = read_unit(reader, header)?;
- let rotation = read_unit(reader, header)?;
- let target = Point::read(reader, header)?;
-
- Ok(Self::ArcEllipse {
- large_arc,
- sweep,
- radius_x,
- radius_y,
- rotation,
- target,
- })
- }
-
- fn read_quadratic_bezier(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- Ok(Self::QuadraticBezier {
- control: Point::read(reader, header)?,
- target: Point::read(reader, header)?,
- })
- }
-}
-
-#[derive(Debug, Clone)]
-struct Instruction {
- /// The width of the line the "pen" makes, if it makes one at all.
- line_width: Option<f64>,
- /// The arguments to the instruction.
- data: InstructionData,
-}
-
-impl Instruction {
- fn read(reader: &mut impl Read, header: &TvgHeader) -> io::Result<Self> {
- let byte = reader.read_u8()?;
- let instruction_kind =
- InstructionKind::try_from_primitive(byte & 0b0000_0111).expect("invalid instruction");
- let has_line_width = (byte & 0b0001_0000) != 0;
-
- let line_width = has_line_width
- .then(|| read_unit(reader, header))
- .transpose()?;
- let data = InstructionData::read(reader, header, instruction_kind)?;
-
- Ok(Self { line_width, data })
- }
-}
-
-#[derive(Debug, Clone)]
-struct Segment {
- /// The starting point of the segment.
- start: Point,
- /// The list of instructions for tha segment.
- instructions: Box<[Instruction]>,
-}
-
-impl Segment {
- fn read(reader: &mut impl Read, header: &TvgHeader, segment_length: u32) -> io::Result<Self> {
- let start = Point::read(reader, header)?;
-
- let mut instructions = Vec::with_capacity(segment_length as usize);
- for _ in 0..segment_length {
- instructions.push(Instruction::read(reader, header)?)
- }
-
- Ok(Segment {
- start,
- instructions: instructions.into_boxed_slice(),
- })
- }
-}
-
-/// Paths describe instructions to create complex 2D graphics.
-///
-/// Each path segment generates a shape by moving a ”pen” around. The path this
-/// ”pen” takes is the outline of our segment. Each segment, the ”pen” starts
-/// at a defined position and is moved by instructions. Each instruction will
-/// leave the ”pen” at a new position. The line drawn by our ”pen” is the
-/// outline of the shape.
-#[derive(Debug, Clone)]
-pub struct Path {
- segments: Box<[Segment]>,
-}
-
-impl Path {
- pub(crate) fn read(
- reader: &mut impl Read,
- header: &TvgHeader,
- segment_count: u32,
- ) -> io::Result<Self> {
- let mut segment_lengths = Vec::with_capacity(segment_count as usize);
- for _ in 0..segment_count {
- segment_lengths.push(read_varuint(reader)? + 1);
- }
-
- let mut segments = Vec::with_capacity(segment_count as usize);
- for segment_length in segment_lengths {
- segments.push(Segment::read(reader, header, segment_length)?);
- }
-
- Ok(Self {
- segments: segments.into_boxed_slice(),
- })
- }
-}