rs-wordcloud 0.1.0

☁ Flexible WordCloud implementation for ⚙Rust
Documentation
use crate::common::svg_command::{Curve, End, Line, Move, QuadCurve, SVGPathCommand};
use crate::types::point::Point;
use crate::types::rect::Rect;
use crate::types::rotation::Rotation;

#[derive(Debug, Clone)]
pub(crate) struct Letter {
    #[allow(dead_code)]
    pub(crate) char: char,
    pub(crate) pixel_bounding_box: Rect<f32>,

    pub(crate) offset: Point<f32>,
    cursor: Point<f32>,
    pub(crate) state: Vec<SVGPathCommand>,
    pub(crate) simplified_state: Option<Vec<Line<f32>>>,
    pub(crate) rotation: Rotation,

    move_cursor: Point<f32>,
}

impl Letter {
    pub fn new(
        char: char,
        pixel_bounding_box: Rect<f32>,
        offset: Point<f32>,
        rotation: Rotation,
    ) -> Self {
        Self {
            char,
            pixel_bounding_box,
            offset,
            cursor: Point::default(),
            state: Vec::default(),
            simplified_state: None,
            rotation,
            move_cursor: Point::default(),
        }
    }

    pub(crate) fn relative_bounding_box(&self, rotation: &Rotation) -> Rect<f32> {
        let bbox = self.pixel_bounding_box;

        rotation.rotate_rectangle(
            bbox + Point {
                x: 0.0,
                y: self.offset.y,
            },
        )
    }

    pub(crate) fn absolute_collidables(
        &self,
        rotation: &Rotation,
        word_offset: Point<f32>,
    ) -> Vec<Line<f32>> {
        let v = rotation.rotate_point(Point {
            x: self.offset.x,
            y: self.offset.y,
        });
        match &self.simplified_state {
            None => vec![],
            Some(b) => b
                .iter()
                .map(|y| Line {
                    start: y.start + v + word_offset,
                    end: y.end + v + word_offset,
                })
                .collect::<Vec<Line<f32>>>(),
        }
    }

    pub(crate) fn d(&self, global_off: &Point<f32>) -> String {
        let off: Point<f32> = self.rotation.rotate_point(self.offset) + *global_off;
        let mut d = String::with_capacity(self.state.iter().map(|x| x.length_estimation()).sum());
        for x in &self.state {
            x.append_to_string(&off, &mut d);
        }
        d
    }

    pub(crate) fn simplify(&mut self) {
        self.simplified_state = Some(
            self.state
                .iter()
                .flat_map(|x| match x {
                    SVGPathCommand::Move(_) => vec![],
                    SVGPathCommand::Line(l) => vec![*l],
                    SVGPathCommand::QuadCurve(q) => q.approximate(),
                    SVGPathCommand::Curve(c) => c.approximate(),
                    SVGPathCommand::End(_) => vec![],
                })
                .collect::<Vec<Line<f32>>>(),
        );
    }
}

impl Letter {
    pub(crate) fn move_to(&mut self, x: f32, y: f32) {
        self.cursor = self.rotation.rotate_point(Point { x, y });
        self.move_cursor = self.rotation.rotate_point(Point { x, y });
        self.state.push(SVGPathCommand::Move(Move {
            position: self.rotation.rotate_point(Point { x, y }),
        }));
    }

    pub(crate) fn line_to(&mut self, x: f32, y: f32) {
        self.state.push(SVGPathCommand::Line(Line {
            start: self.cursor,
            end: self.rotation.rotate_point(Point { x, y }),
        }));
        self.cursor = self.rotation.rotate_point(Point { x, y });
    }

    pub(crate) fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
        self.state.push(SVGPathCommand::QuadCurve(QuadCurve {
            c1: self.rotation.rotate_point(Point { x: x1, y: y1 }),
            e: self.rotation.rotate_point(Point { x, y }),
            s: self.cursor,
        }));
        self.cursor = self.rotation.rotate_point(Point { x, y });
    }

    pub(crate) fn curve_to(&mut self, x2: f32, y2: f32, x1: f32, y1: f32, x: f32, y: f32) {
        self.state.push(SVGPathCommand::Curve(Curve {
            c2: self.rotation.rotate_point(Point { x: x2, y: y2 }),
            c1: self.rotation.rotate_point(Point { x: x1, y: y1 }),
            e: self.rotation.rotate_point(Point { x, y }),
            s: self.cursor,
        }));
        self.cursor = self.rotation.rotate_point(Point { x, y });
    }

    pub(crate) fn close(&mut self) {
        self.state.push(SVGPathCommand::Line(Line {
            start: self.cursor,
            end: self.move_cursor,
        }));
        self.state.push(SVGPathCommand::End(End {}));
    }
}