Graphite/graphene/src/intersection.rs

72 lines
1.9 KiB
Rust

use std::ops::Mul;
use glam::{DAffine2, DVec2};
use kurbo::{BezPath, Line, PathSeg, Point, Shape};
#[derive(Debug, Clone, Default, Copy)]
pub struct Quad([DVec2; 4]);
impl Quad {
pub fn from_box(bbox: [DVec2; 2]) -> Self {
let size = bbox[1] - bbox[0];
Self([bbox[0], bbox[0] + size * DVec2::X, bbox[1], bbox[0] + size * DVec2::Y])
}
pub fn lines(&self) -> [Line; 4] {
[
Line::new(to_point(self.0[0]), to_point(self.0[1])),
Line::new(to_point(self.0[1]), to_point(self.0[2])),
Line::new(to_point(self.0[2]), to_point(self.0[3])),
Line::new(to_point(self.0[3]), to_point(self.0[0])),
]
}
pub fn path(&self) -> BezPath {
let mut path = kurbo::BezPath::new();
path.move_to(to_point(self.0[0]));
path.line_to(to_point(self.0[1]));
path.line_to(to_point(self.0[2]));
path.line_to(to_point(self.0[3]));
path.close_path();
path
}
}
impl Mul<Quad> for DAffine2 {
type Output = Quad;
fn mul(self, rhs: Quad) -> Self::Output {
let mut output = Quad::default();
for (i, point) in rhs.0.iter().enumerate() {
output.0[i] = self.transform_point2(*point);
}
output
}
}
fn to_point(vec: DVec2) -> Point {
Point::new(vec.x, vec.y)
}
pub fn intersect_quad_bez_path(quad: Quad, shape: &BezPath, closed: bool) -> bool {
// check if outlines intersect
if shape.segments().any(|path_segment| quad.lines().iter().any(|line| !path_segment.intersect_line(*line).is_empty())) {
return true;
}
// check if selection is entirely within the shape
if closed && shape.contains(to_point(quad.0[0])) {
return true;
}
// check if shape is entirely within selection
get_arbitrary_point_on_path(shape).map(|shape_point| quad.path().contains(shape_point)).unwrap_or_default()
}
pub fn get_arbitrary_point_on_path(path: &BezPath) -> Option<Point> {
path.segments().next().map(|seg| match seg {
PathSeg::Line(line) => line.p0,
PathSeg::Quad(quad) => quad.p0,
PathSeg::Cubic(cubic) => cubic.p0,
})
}