Plot items: Image rotation and size in plot coordinates, polygon fill color (#3182)

* plot item improvements

* update changelog

* fix links

* revert changes to the changelog

* clean up merge
This commit is contained in:
Sven Niederberger 2023-08-27 14:28:10 +02:00 committed by GitHub
parent b6f46b000b
commit c722b7fd46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 49 additions and 43 deletions

View File

@ -2,8 +2,7 @@
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
use epaint::util::FloatOrd; use epaint::{emath::Rot2, util::FloatOrd, Mesh};
use epaint::Mesh;
use crate::*; use crate::*;
@ -517,7 +516,7 @@ pub struct Polygon {
pub(super) stroke: Stroke, pub(super) stroke: Stroke,
pub(super) name: String, pub(super) name: String,
pub(super) highlight: bool, pub(super) highlight: bool,
pub(super) fill_alpha: f32, pub(super) fill_color: Option<Color32>,
pub(super) style: LineStyle, pub(super) style: LineStyle,
} }
@ -528,7 +527,7 @@ impl Polygon {
stroke: Stroke::new(1.0, Color32::TRANSPARENT), stroke: Stroke::new(1.0, Color32::TRANSPARENT),
name: Default::default(), name: Default::default(),
highlight: false, highlight: false,
fill_alpha: DEFAULT_FILL_ALPHA, fill_color: None,
style: LineStyle::Solid, style: LineStyle::Solid,
} }
} }
@ -552,15 +551,21 @@ impl Polygon {
self self
} }
/// Stroke color. Default is `Color32::TRANSPARENT` which means a color will be auto-assigned. #[deprecated = "Use `fill_color`."]
#[allow(unused, clippy::needless_pass_by_value)]
pub fn color(mut self, color: impl Into<Color32>) -> Self { pub fn color(mut self, color: impl Into<Color32>) -> Self {
self.stroke.color = color.into();
self self
} }
/// Alpha of the filled area. #[deprecated = "Use `fill_color`."]
pub fn fill_alpha(mut self, alpha: impl Into<f32>) -> Self { #[allow(unused, clippy::needless_pass_by_value)]
self.fill_alpha = alpha.into(); pub fn fill_alpha(mut self, _alpha: impl Into<f32>) -> Self {
self
}
/// Fill color. Defaults to the stroke color with added transparency.
pub fn fill_color(mut self, color: impl Into<Color32>) -> Self {
self.fill_color = Some(color.into());
self self
} }
@ -589,24 +594,20 @@ impl PlotItem for Polygon {
series, series,
stroke, stroke,
highlight, highlight,
mut fill_alpha, fill_color,
style, style,
.. ..
} = self; } = self;
if *highlight {
fill_alpha = (2.0 * fill_alpha).at_most(1.0);
}
let mut values_tf: Vec<_> = series let mut values_tf: Vec<_> = series
.points() .points()
.iter() .iter()
.map(|v| transform.position_from_point(v)) .map(|v| transform.position_from_point(v))
.collect(); .collect();
let fill = Rgba::from(stroke.color).to_opaque().multiply(fill_alpha); let fill_color = fill_color.unwrap_or(stroke.color.linear_multiply(DEFAULT_FILL_ALPHA));
let shape = Shape::convex_polygon(values_tf.clone(), fill, Stroke::NONE); let shape = Shape::convex_polygon(values_tf.clone(), fill_color, Stroke::NONE);
shapes.push(shape); shapes.push(shape);
values_tf.push(*values_tf.first().unwrap()); values_tf.push(*values_tf.first().unwrap());
style.style_line(values_tf, *stroke, *highlight, shapes); style.style_line(values_tf, *stroke, *highlight, shapes);
@ -1135,11 +1136,11 @@ pub struct PlotImage {
pub(super) texture_id: TextureId, pub(super) texture_id: TextureId,
pub(super) uv: Rect, pub(super) uv: Rect,
pub(super) size: Vec2, pub(super) size: Vec2,
pub(crate) rotation: f64,
pub(super) bg_fill: Color32, pub(super) bg_fill: Color32,
pub(super) tint: Color32, pub(super) tint: Color32,
pub(super) highlight: bool, pub(super) highlight: bool,
pub(super) name: String, pub(super) name: String,
pub(crate) rotation: Option<(f32, Vec2)>,
} }
impl PlotImage { impl PlotImage {
@ -1156,9 +1157,9 @@ impl PlotImage {
texture_id: texture_id.into(), texture_id: texture_id.into(),
uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)), uv: Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)),
size: size.into(), size: size.into(),
rotation: 0.0,
bg_fill: Default::default(), bg_fill: Default::default(),
tint: Color32::WHITE, tint: Color32::WHITE,
rotation: None,
} }
} }
@ -1198,14 +1199,9 @@ impl PlotImage {
self self
} }
/// Rotate the image about an origin by some angle /// Rotate the image counter-clockwise around its center by an angle in radians.
/// pub fn rotate(mut self, angle: f64) -> Self {
/// Positive angle is clockwise. self.rotation = angle;
/// Origin is a vector in normalized UV space ((0,0) in top-left, (1,1) bottom right).
///
/// To rotate about the center you can pass `Vec2::splat(0.5)` as the origin.
pub fn rotate(mut self, angle: f32, origin: Vec2) -> Self {
self.rotation = Some((angle, origin));
self self
} }
} }
@ -1214,6 +1210,7 @@ impl PlotItem for PlotImage {
fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) { fn shapes(&self, ui: &mut Ui, transform: &PlotTransform, shapes: &mut Vec<Shape>) {
let Self { let Self {
position, position,
rotation,
texture_id, texture_id,
uv, uv,
size, size,
@ -1222,31 +1219,40 @@ impl PlotItem for PlotImage {
highlight, highlight,
.. ..
} = self; } = self;
let rect = { let image_screen_rect = {
let left_top = PlotPoint::new( let left_top = PlotPoint::new(
position.x as f32 - size.x / 2.0, position.x - 0.5 * size.x as f64,
position.y as f32 - size.y / 2.0, position.y - 0.5 * size.y as f64,
); );
let right_bottom = PlotPoint::new( let right_bottom = PlotPoint::new(
position.x as f32 + size.x / 2.0, position.x + 0.5 * size.x as f64,
position.y as f32 + size.y / 2.0, position.y + 0.5 * size.y as f64,
); );
let left_top_tf = transform.position_from_point(&left_top); let left_top_screen = transform.position_from_point(&left_top);
let right_bottom_tf = transform.position_from_point(&right_bottom); let right_bottom_screen = transform.position_from_point(&right_bottom);
Rect::from_two_pos(left_top_tf, right_bottom_tf) Rect::from_two_pos(left_top_screen, right_bottom_screen)
}; };
let mut image = Image::new(*texture_id, *size) let screen_rotation = -*rotation as f32;
Image::new(*texture_id, image_screen_rect.size())
.bg_fill(*bg_fill) .bg_fill(*bg_fill)
.tint(*tint) .tint(*tint)
.uv(*uv); .uv(*uv)
if let Some((angle, origin)) = self.rotation { .rotate(screen_rotation, Vec2::splat(0.5))
image = image.rotate(angle, origin); .paint_at(ui, image_screen_rect);
}
image.paint_at(ui, rect);
if *highlight { if *highlight {
shapes.push(Shape::rect_stroke( let center = image_screen_rect.center();
rect, let rotation = Rot2::from_angle(screen_rotation);
0.0, let outline = [
image_screen_rect.right_bottom(),
image_screen_rect.right_top(),
image_screen_rect.left_top(),
image_screen_rect.left_bottom(),
]
.iter()
.map(|point| center + rotation * (*point - center))
.collect();
shapes.push(Shape::closed_line(
outline,
Stroke::new(1.0, ui.visuals().strong_text_color()), Stroke::new(1.0, ui.visuals().strong_text_color()),
)); ));
} }