mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 02:08:12 +08:00
Serve bounding boxes through the lane source
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
use crate::Color;
|
use crate::Color;
|
||||||
|
use crate::lane::LaneSource;
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
#[derive(Clone, Copy, Default, Debug, PartialEq)]
|
||||||
@@ -51,3 +52,60 @@ impl BoundingBox for Color {
|
|||||||
RenderBoundingBox::Infinite
|
RenderBoundingBox::Infinite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Combined bounding box of a lane source's elements, composing each lane's
|
||||||
|
/// transform attribute with the given transform.
|
||||||
|
pub fn lane_bounding_box<S: LaneSource>(source: &S, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox
|
||||||
|
where
|
||||||
|
S::Element: BoundingBox,
|
||||||
|
{
|
||||||
|
let mut combined_bounds = None;
|
||||||
|
|
||||||
|
for lane in 0..source.lane_count() {
|
||||||
|
let Some(element) = source.element(lane) else { continue };
|
||||||
|
let lane_transform: DAffine2 = source.attr::<crate::attribute::Transform>(lane);
|
||||||
|
match element.bounding_box(transform * lane_transform, include_stroke) {
|
||||||
|
RenderBoundingBox::None => continue,
|
||||||
|
RenderBoundingBox::Infinite => return RenderBoundingBox::Infinite,
|
||||||
|
RenderBoundingBox::Rectangle(bounds) => match combined_bounds {
|
||||||
|
Some(existing) => combined_bounds = Some(crate::math::quad::Quad::combine_bounds(existing, bounds)),
|
||||||
|
None => combined_bounds = Some(bounds),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match combined_bounds {
|
||||||
|
Some(bounds) => RenderBoundingBox::Rectangle(bounds),
|
||||||
|
None => RenderBoundingBox::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// As [`lane_bounding_box`], but `Infinite` lanes are skipped (rather than
|
||||||
|
/// propagating outward) so a finite sibling in a mixed group dictates the
|
||||||
|
/// framing.
|
||||||
|
pub fn lane_thumbnail_bounding_box<S: LaneSource>(source: &S, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox
|
||||||
|
where
|
||||||
|
S::Element: BoundingBox,
|
||||||
|
{
|
||||||
|
let mut combined_bounds = None;
|
||||||
|
let mut any_infinite = false;
|
||||||
|
|
||||||
|
for lane in 0..source.lane_count() {
|
||||||
|
let Some(element) = source.element(lane) else { continue };
|
||||||
|
let lane_transform: DAffine2 = source.attr::<crate::attribute::Transform>(lane);
|
||||||
|
match element.thumbnail_bounding_box(transform * lane_transform, include_stroke) {
|
||||||
|
RenderBoundingBox::None => continue,
|
||||||
|
RenderBoundingBox::Infinite => any_infinite = true,
|
||||||
|
RenderBoundingBox::Rectangle(bounds) => match combined_bounds {
|
||||||
|
Some(existing) => combined_bounds = Some(crate::math::quad::Quad::combine_bounds(existing, bounds)),
|
||||||
|
None => combined_bounds = Some(bounds),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match (combined_bounds, any_infinite) {
|
||||||
|
(Some(bounds), _) => RenderBoundingBox::Rectangle(bounds),
|
||||||
|
(None, true) => RenderBoundingBox::Infinite,
|
||||||
|
(None, false) => RenderBoundingBox::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::attribute::Attribute as _;
|
use crate::attribute::Attribute as _;
|
||||||
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
use crate::bounds::{BoundingBox, RenderBoundingBox};
|
||||||
use crate::math::quad::Quad;
|
|
||||||
use crate::transform::ApplyTransform;
|
use crate::transform::ApplyTransform;
|
||||||
use dyn_any::{StaticType, StaticTypeSized};
|
use dyn_any::{StaticType, StaticTypeSized};
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
@@ -1105,48 +1104,12 @@ impl<T> List<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: BoundingBox> BoundingBox for List<T> {
|
impl<T: BoundingBox> BoundingBox for List<T> {
|
||||||
/// Computes the combined bounding box of all items, composing each item's transform attribute with the given transform.
|
|
||||||
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||||
let mut combined_bounds = None;
|
crate::bounds::lane_bounding_box(self, transform, include_stroke)
|
||||||
|
|
||||||
for (element, item_transform) in self.iter_element_values().zip(self.iter_attribute_values_or_default::<DAffine2>(ATTR_TRANSFORM)) {
|
|
||||||
match element.bounding_box(transform * item_transform, include_stroke) {
|
|
||||||
RenderBoundingBox::None => continue,
|
|
||||||
RenderBoundingBox::Infinite => return RenderBoundingBox::Infinite,
|
|
||||||
RenderBoundingBox::Rectangle(bounds) => match combined_bounds {
|
|
||||||
Some(existing) => combined_bounds = Some(Quad::combine_bounds(existing, bounds)),
|
|
||||||
None => combined_bounds = Some(bounds),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match combined_bounds {
|
|
||||||
Some(bounds) => RenderBoundingBox::Rectangle(bounds),
|
|
||||||
None => RenderBoundingBox::None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn thumbnail_bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
fn thumbnail_bounding_box(&self, transform: DAffine2, include_stroke: bool) -> RenderBoundingBox {
|
||||||
// `Infinite` items are skipped here (rather than propagating outward as in `bounding_box`) so a finite sibling in a mixed group dictates the framing
|
crate::bounds::lane_thumbnail_bounding_box(self, transform, include_stroke)
|
||||||
let mut combined_bounds = None;
|
|
||||||
let mut any_infinite = false;
|
|
||||||
|
|
||||||
for (element, item_transform) in self.iter_element_values().zip(self.iter_attribute_values_or_default::<DAffine2>(ATTR_TRANSFORM)) {
|
|
||||||
match element.thumbnail_bounding_box(transform * item_transform, include_stroke) {
|
|
||||||
RenderBoundingBox::None => continue,
|
|
||||||
RenderBoundingBox::Infinite => any_infinite = true,
|
|
||||||
RenderBoundingBox::Rectangle(bounds) => match combined_bounds {
|
|
||||||
Some(existing) => combined_bounds = Some(Quad::combine_bounds(existing, bounds)),
|
|
||||||
None => combined_bounds = Some(bounds),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match (combined_bounds, any_infinite) {
|
|
||||||
(Some(bounds), _) => RenderBoundingBox::Rectangle(bounds),
|
|
||||||
(None, true) => RenderBoundingBox::Infinite,
|
|
||||||
(None, false) => RenderBoundingBox::None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1919,6 +1919,16 @@ impl<'a, T: 'static> crate::lane::LaneSource for RunView<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: crate::bounds::BoundingBox + 'static> crate::bounds::BoundingBox for RunView<'_, T> {
|
||||||
|
fn bounding_box(&self, transform: glam::DAffine2, include_stroke: bool) -> crate::bounds::RenderBoundingBox {
|
||||||
|
crate::bounds::lane_bounding_box(self, transform, include_stroke)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail_bounding_box(&self, transform: glam::DAffine2, include_stroke: bool) -> crate::bounds::RenderBoundingBox {
|
||||||
|
crate::bounds::lane_thumbnail_bounding_box(self, transform, include_stroke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The records a group stores: a single homogeneous run, or a list of
|
/// The records a group stores: a single homogeneous run, or a list of
|
||||||
/// segments.
|
/// segments.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
|||||||
Reference in New Issue
Block a user