Add Shape::visual_bounding_rect()
This commit is contained in:
parent
fd3fb726c1
commit
8f887e2ebd
4 changed files with 89 additions and 22 deletions
|
@ -122,7 +122,7 @@ impl PaintBezier {
|
|||
let shape =
|
||||
QuadraticBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
|
||||
painter.add(epaint::RectShape::stroke(
|
||||
shape.bounding_rect(),
|
||||
shape.visual_bounding_rect(),
|
||||
0.0,
|
||||
self.bounding_box_stroke,
|
||||
));
|
||||
|
@ -133,7 +133,7 @@ impl PaintBezier {
|
|||
let shape =
|
||||
CubicBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
|
||||
painter.add(epaint::RectShape::stroke(
|
||||
shape.bounding_rect(),
|
||||
shape.visual_bounding_rect(),
|
||||
0.0,
|
||||
self.bounding_box_stroke,
|
||||
));
|
||||
|
|
|
@ -74,8 +74,17 @@ impl CubicBezierShape {
|
|||
pathshapes
|
||||
}
|
||||
|
||||
/// Screen-space bounding rectangle.
|
||||
pub fn bounding_rect(&self) -> Rect {
|
||||
/// The visual bounding rectangle (includes stroke width)
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
self.logical_bounding_rect().expand(self.stroke.width / 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Logical bounding rectangle (ignoring stroke width)
|
||||
pub fn logical_bounding_rect(&self) -> Rect {
|
||||
//temporary solution
|
||||
let (mut min_x, mut max_x) = if self.points[0].x < self.points[3].x {
|
||||
(self.points[0].x, self.points[3].x)
|
||||
|
@ -421,8 +430,17 @@ impl QuadraticBezierShape {
|
|||
}
|
||||
}
|
||||
|
||||
/// bounding box of the quadratic Bézier shape
|
||||
pub fn bounding_rect(&self) -> Rect {
|
||||
/// The visual bounding rectangle (includes stroke width)
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
self.logical_bounding_rect().expand(self.stroke.width / 2.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Logical bounding rectangle (ignoring stroke width)
|
||||
pub fn logical_bounding_rect(&self) -> Rect {
|
||||
let (mut min_x, mut max_x) = if self.points[0].x < self.points[2].x {
|
||||
(self.points[0].x, self.points[2].x)
|
||||
} else {
|
||||
|
@ -755,7 +773,7 @@ mod tests {
|
|||
fill: Default::default(),
|
||||
stroke: Default::default(),
|
||||
};
|
||||
let bbox = curve.bounding_rect();
|
||||
let bbox = curve.logical_bounding_rect();
|
||||
assert!((bbox.min.x - 72.96).abs() < 0.01);
|
||||
assert!((bbox.min.y - 27.78).abs() < 0.01);
|
||||
|
||||
|
@ -779,7 +797,7 @@ mod tests {
|
|||
fill: Default::default(),
|
||||
stroke: Default::default(),
|
||||
};
|
||||
let bbox = curve.bounding_rect();
|
||||
let bbox = curve.logical_bounding_rect();
|
||||
assert!((bbox.min.x - 10.0).abs() < 0.01);
|
||||
assert!((bbox.min.y - 10.0).abs() < 0.01);
|
||||
|
||||
|
@ -848,7 +866,7 @@ mod tests {
|
|||
stroke: Default::default(),
|
||||
};
|
||||
|
||||
let bbox = curve.bounding_rect();
|
||||
let bbox = curve.logical_bounding_rect();
|
||||
assert_eq!(bbox.min.x, 10.0);
|
||||
assert_eq!(bbox.min.y, 10.0);
|
||||
assert_eq!(bbox.max.x, 270.0);
|
||||
|
@ -866,7 +884,7 @@ mod tests {
|
|||
stroke: Default::default(),
|
||||
};
|
||||
|
||||
let bbox = curve.bounding_rect();
|
||||
let bbox = curve.logical_bounding_rect();
|
||||
assert_eq!(bbox.min.x, 10.0);
|
||||
assert_eq!(bbox.min.y, 10.0);
|
||||
assert!((bbox.max.x - 206.50).abs() < 0.01);
|
||||
|
@ -884,7 +902,7 @@ mod tests {
|
|||
stroke: Default::default(),
|
||||
};
|
||||
|
||||
let bbox = curve.bounding_rect();
|
||||
let bbox = curve.logical_bounding_rect();
|
||||
assert!((bbox.min.x - 86.71).abs() < 0.01);
|
||||
assert!((bbox.min.y - 30.0).abs() < 0.01);
|
||||
|
||||
|
|
|
@ -170,6 +170,34 @@ impl Shape {
|
|||
crate::epaint_assert!(mesh.is_valid());
|
||||
Self::Mesh(mesh)
|
||||
}
|
||||
|
||||
/// The visual bounding rectangle (includes stroke widths)
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
match self {
|
||||
Self::Noop => Rect::NOTHING,
|
||||
Self::Vec(shapes) => {
|
||||
let mut rect = Rect::NOTHING;
|
||||
for shape in shapes {
|
||||
rect = rect.union(shape.visual_bounding_rect());
|
||||
}
|
||||
rect
|
||||
}
|
||||
Self::Circle(circle_shape) => circle_shape.visual_bounding_rect(),
|
||||
Self::LineSegment { points, stroke } => {
|
||||
if stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
Rect::from_two_pos(points[0], points[1]).expand(stroke.width / 2.0)
|
||||
}
|
||||
}
|
||||
Self::Path(path_shape) => path_shape.visual_bounding_rect(),
|
||||
Self::Rect(rect_shape) => rect_shape.visual_bounding_rect(),
|
||||
Self::Text(text_shape) => text_shape.visual_bounding_rect(),
|
||||
Self::Mesh(mesh) => mesh.calc_bounds(),
|
||||
Self::QuadraticBezier(bezier) => bezier.visual_bounding_rect(),
|
||||
Self::CubicBezier(bezier) => bezier.visual_bounding_rect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// ## Inspection and transforms
|
||||
|
@ -260,6 +288,18 @@ impl CircleShape {
|
|||
stroke: stroke.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The visual bounding rectangle (includes stroke width)
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
Rect::from_center_size(
|
||||
self.center,
|
||||
Vec2::splat(self.radius + self.stroke.width / 2.0),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CircleShape> for Shape {
|
||||
|
@ -327,10 +367,14 @@ impl PathShape {
|
|||
}
|
||||
}
|
||||
|
||||
/// Screen-space bounding rectangle.
|
||||
/// The visual bounding rectangle (includes stroke width)
|
||||
#[inline]
|
||||
pub fn bounding_rect(&self) -> Rect {
|
||||
Rect::from_points(&self.points).expand(self.stroke.width)
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
Rect::from_points(&self.points).expand(self.stroke.width / 2.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,10 +423,14 @@ impl RectShape {
|
|||
}
|
||||
}
|
||||
|
||||
/// Screen-space bounding rectangle.
|
||||
/// The visual bounding rectangle (includes stroke width)
|
||||
#[inline]
|
||||
pub fn bounding_rect(&self) -> Rect {
|
||||
self.rect.expand(self.stroke.width)
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
if self.fill == Color32::TRANSPARENT && self.stroke.is_empty() {
|
||||
Rect::NOTHING
|
||||
} else {
|
||||
self.rect.expand(self.stroke.width / 2.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,9 +539,9 @@ impl TextShape {
|
|||
}
|
||||
}
|
||||
|
||||
/// Screen-space bounding rectangle.
|
||||
/// The visual bounding rectangle
|
||||
#[inline]
|
||||
pub fn bounding_rect(&self) -> Rect {
|
||||
pub fn visual_bounding_rect(&self) -> Rect {
|
||||
self.galley.mesh_bounds.translate(self.pos.to_vec2())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -793,7 +793,7 @@ impl Tessellator {
|
|||
let clip_rect = self.clip_rect;
|
||||
|
||||
if options.coarse_tessellation_culling
|
||||
&& !quadratic_shape.bounding_rect().intersects(clip_rect)
|
||||
&& !quadratic_shape.visual_bounding_rect().intersects(clip_rect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -816,7 +816,8 @@ impl Tessellator {
|
|||
) {
|
||||
let options = &self.options;
|
||||
let clip_rect = self.clip_rect;
|
||||
if options.coarse_tessellation_culling && !cubic_shape.bounding_rect().intersects(clip_rect)
|
||||
if options.coarse_tessellation_culling
|
||||
&& !cubic_shape.visual_bounding_rect().intersects(clip_rect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -870,7 +871,7 @@ impl Tessellator {
|
|||
}
|
||||
|
||||
if self.options.coarse_tessellation_culling
|
||||
&& !path_shape.bounding_rect().intersects(self.clip_rect)
|
||||
&& !path_shape.visual_bounding_rect().intersects(self.clip_rect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue