use crate::{buffer::Cell, map::unicode_map::FRAGMENTS_UNICODE, Merge, Point};
pub use crate::{Property, Settings, Signal};
pub use arc::Arc;
pub use circle::Circle;
pub use line::Line;
pub use marker_line::{Marker, MarkerLine};
use parry2d::{
bounding_volume::{BoundingVolume, AABB},
math::Isometry,
query::{intersection_test, PointQuery},
shape::{ConvexPolygon, Polyline, Segment, Shape},
};
pub use polygon::{Polygon, PolygonTag};
pub use rect::Rect;
use sauron::Node;
use std::{cmp::Ordering, fmt};
pub use text::{CellText, Text};
mod arc;
mod circle;
mod line;
mod marker_line;
mod polygon;
mod rect;
mod text;
/// ```ignore
/// 0 1 2 3 4 B C D
/// 0┌─┬─┬─┬─┐ A┌─┬─┬─┬─┐E
/// 1├─┼─┼─┼─┤ │ │ │ │ │
/// 2├─┼─┼─┼─┤ F├─G─H─I─┤J
/// 3├─┼─┼─┼─┤ │ │ │ │ │
/// 4├─┼─┼─┼─┤ K├─L─M─N─┤O
/// 5├─┼─┼─┼─┤ │ │ │ │ │
/// 6├─┼─┼─┼─┤ P├─Q─R─S─┤T
/// 7├─┼─┼─┼─┤ │ │ │ │ │
/// 8└─┴─┴─┴─┘ U└─┴─┴─┴─┘Y
/// ``` V W X
#[derive(Debug, Clone)]
pub enum Fragment {
Line(Line),
MarkerLine(MarkerLine),
Circle(Circle),
Arc(Arc),
Polygon(Polygon),
Rect(Rect),
// cell base
CellText(CellText),
// point base
Text(Text),
}
/// get the boundary of a fragment
/// this is used for sorting the fragments
/// in a consistent sorted order
pub trait Bounds {
fn bounds(&self) -> (Point, Point);
fn mins(&self) -> Point {
self.bounds().0
}
fn maxs(&self) -> Point {
self.bounds().1
}
}
impl Fragment {
/// get the character that matches the shape present on this cell
pub fn match_unicode(fragments: &[Fragment]) -> Option<char> {
let mut sorted_shapes: Vec<Fragment> = fragments.to_vec();
sorted_shapes.sort();
FRAGMENTS_UNICODE.get(&sorted_shapes).copied()
}
/// check to see if this fragment is a line and that line
/// can completely overlap line a b
/// TODO: only checking for solid, also expose API for broken
pub(crate) fn line_overlap(&self, a: Point, b: Point) -> bool {
match self {
Fragment::Line(line) => line.overlaps(a, b),
_ => false,
}
}
/// check if any of the fragment end point is touching p
pub(crate) fn has_endpoint(&self, p: Point) -> bool {
match self {
Fragment::Line(line) => line.has_endpoint(p),
Fragment::Arc(arc) => arc.has_endpoint(p),
_ => false,
}
}
/// check to see if this fragment is an arc
/// overlaps from point a to b
pub(crate) fn arcs_to(&self, a: Point, b: Point) -> bool {
match self {
Fragment::Arc(arc) => arc.arcs_to(a, b),
_ => false,
}
}
/// check whether the other fragment is can be fit in this fragment
pub(crate) fn can_fit(&self, other: &Self) -> bool {
let (tl, br) = self.bounds();
let (other_tl, other_br) = other.bounds();
tl.x <= other_tl.x
&& tl.y <= other_tl.y
&& br.x >= other_br.x
&& br.y >= other_br.y
}
/// are lines axis align and parallel
pub(crate) fn is_aabb_parallel(&self, other: &Self) -> bool {
match (self, other) {
(Fragment::Line(line), Fragment::Line(other)) => {
line.is_aabb_parallel(other)
}
(_, _) => false,
}
}
#[allow(unused)]
pub(crate) fn is_aabb_perpendicular(&self, other: &Self) -> bool {
match (self, other) {
(Fragment::Line(line), Fragment::Line(other)) => {
line.is_aabb_perpendicular(other)
}
(_, _) => false,
}
}
/// check if this fragment is touching the other fragment
/// therefore can be in a group together
pub(crate) fn is_contacting(&self, other: &Self) -> bool {
match self {
Fragment::Line(line) => match other {
Fragment::Line(other) => line.is_touching(other),
Fragment::Arc(other_arc) => line.is_touching_arc(other_arc),
Fragment::Polygon(polygon) => false,
Fragment::Circle(circle) => line.is_touching_circle(circle),
_ => false,
},
Fragment::Polygon(polygon) => match other {
Fragment::Line(other) => false,
_ => false,
},
Fragment::Arc(arc) => match other {
Fragment::Arc(other_arc) => arc.is_touching(other_arc),
Fragment::Line(other_line) => other_line.is_touching_arc(arc),
_ => false,