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 =
|
let shape =
|
||||||
QuadraticBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
|
QuadraticBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
|
||||||
painter.add(epaint::RectShape::stroke(
|
painter.add(epaint::RectShape::stroke(
|
||||||
shape.bounding_rect(),
|
shape.visual_bounding_rect(),
|
||||||
0.0,
|
0.0,
|
||||||
self.bounding_box_stroke,
|
self.bounding_box_stroke,
|
||||||
));
|
));
|
||||||
|
@ -133,7 +133,7 @@ impl PaintBezier {
|
||||||
let shape =
|
let shape =
|
||||||
CubicBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
|
CubicBezierShape::from_points_stroke(points, true, self.fill, self.stroke);
|
||||||
painter.add(epaint::RectShape::stroke(
|
painter.add(epaint::RectShape::stroke(
|
||||||
shape.bounding_rect(),
|
shape.visual_bounding_rect(),
|
||||||
0.0,
|
0.0,
|
||||||
self.bounding_box_stroke,
|
self.bounding_box_stroke,
|
||||||
));
|
));
|
||||||
|
|
|
@ -74,8 +74,17 @@ impl CubicBezierShape {
|
||||||
pathshapes
|
pathshapes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Screen-space bounding rectangle.
|
/// The visual bounding rectangle (includes stroke width)
|
||||||
pub fn bounding_rect(&self) -> Rect {
|
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
|
//temporary solution
|
||||||
let (mut min_x, mut max_x) = if self.points[0].x < self.points[3].x {
|
let (mut min_x, mut max_x) = if self.points[0].x < self.points[3].x {
|
||||||
(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
|
/// The visual bounding rectangle (includes stroke width)
|
||||||
pub fn bounding_rect(&self) -> Rect {
|
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 {
|
let (mut min_x, mut max_x) = if self.points[0].x < self.points[2].x {
|
||||||
(self.points[0].x, self.points[2].x)
|
(self.points[0].x, self.points[2].x)
|
||||||
} else {
|
} else {
|
||||||
|
@ -755,7 +773,7 @@ mod tests {
|
||||||
fill: Default::default(),
|
fill: Default::default(),
|
||||||
stroke: 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.x - 72.96).abs() < 0.01);
|
||||||
assert!((bbox.min.y - 27.78).abs() < 0.01);
|
assert!((bbox.min.y - 27.78).abs() < 0.01);
|
||||||
|
|
||||||
|
@ -779,7 +797,7 @@ mod tests {
|
||||||
fill: Default::default(),
|
fill: Default::default(),
|
||||||
stroke: 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.x - 10.0).abs() < 0.01);
|
||||||
assert!((bbox.min.y - 10.0).abs() < 0.01);
|
assert!((bbox.min.y - 10.0).abs() < 0.01);
|
||||||
|
|
||||||
|
@ -848,7 +866,7 @@ mod tests {
|
||||||
stroke: Default::default(),
|
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.x, 10.0);
|
||||||
assert_eq!(bbox.min.y, 10.0);
|
assert_eq!(bbox.min.y, 10.0);
|
||||||
assert_eq!(bbox.max.x, 270.0);
|
assert_eq!(bbox.max.x, 270.0);
|
||||||
|
@ -866,7 +884,7 @@ mod tests {
|
||||||
stroke: Default::default(),
|
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.x, 10.0);
|
||||||
assert_eq!(bbox.min.y, 10.0);
|
assert_eq!(bbox.min.y, 10.0);
|
||||||
assert!((bbox.max.x - 206.50).abs() < 0.01);
|
assert!((bbox.max.x - 206.50).abs() < 0.01);
|
||||||
|
@ -884,7 +902,7 @@ mod tests {
|
||||||
stroke: Default::default(),
|
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.x - 86.71).abs() < 0.01);
|
||||||
assert!((bbox.min.y - 30.0).abs() < 0.01);
|
assert!((bbox.min.y - 30.0).abs() < 0.01);
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,34 @@ impl Shape {
|
||||||
crate::epaint_assert!(mesh.is_valid());
|
crate::epaint_assert!(mesh.is_valid());
|
||||||
Self::Mesh(mesh)
|
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
|
/// ## Inspection and transforms
|
||||||
|
@ -260,6 +288,18 @@ impl CircleShape {
|
||||||
stroke: stroke.into(),
|
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 {
|
impl From<CircleShape> for Shape {
|
||||||
|
@ -327,10 +367,14 @@ impl PathShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Screen-space bounding rectangle.
|
/// The visual bounding rectangle (includes stroke width)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn bounding_rect(&self) -> Rect {
|
pub fn visual_bounding_rect(&self) -> Rect {
|
||||||
Rect::from_points(&self.points).expand(self.stroke.width)
|
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]
|
#[inline]
|
||||||
pub fn bounding_rect(&self) -> Rect {
|
pub fn visual_bounding_rect(&self) -> Rect {
|
||||||
self.rect.expand(self.stroke.width)
|
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]
|
#[inline]
|
||||||
pub fn bounding_rect(&self) -> Rect {
|
pub fn visual_bounding_rect(&self) -> Rect {
|
||||||
self.galley.mesh_bounds.translate(self.pos.to_vec2())
|
self.galley.mesh_bounds.translate(self.pos.to_vec2())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -793,7 +793,7 @@ impl Tessellator {
|
||||||
let clip_rect = self.clip_rect;
|
let clip_rect = self.clip_rect;
|
||||||
|
|
||||||
if options.coarse_tessellation_culling
|
if options.coarse_tessellation_culling
|
||||||
&& !quadratic_shape.bounding_rect().intersects(clip_rect)
|
&& !quadratic_shape.visual_bounding_rect().intersects(clip_rect)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -816,7 +816,8 @@ impl Tessellator {
|
||||||
) {
|
) {
|
||||||
let options = &self.options;
|
let options = &self.options;
|
||||||
let clip_rect = self.clip_rect;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -870,7 +871,7 @@ impl Tessellator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.options.coarse_tessellation_culling
|
if self.options.coarse_tessellation_culling
|
||||||
&& !path_shape.bounding_rect().intersects(self.clip_rect)
|
&& !path_shape.visual_bounding_rect().intersects(self.clip_rect)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue