1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-30 05:10:03 -04:00

Add Bezier Shapes #1120 (#1178)

This commit is contained in:
Xu Desheng
2022-01-31 14:26:31 -05:00
committed by GitHub
parent 4e99d8f409
commit 1f03f53dc0
11 changed files with 1488 additions and 2 deletions

1101
epaint/src/bezier.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -87,6 +87,7 @@
#![allow(clippy::float_cmp)]
#![allow(clippy::manual_range_contains)]
mod bezier;
pub mod color;
pub mod image;
mod mesh;
@@ -104,6 +105,7 @@ pub mod textures;
pub mod util;
pub use {
bezier::{CubicBezierShape, QuadraticBezierShape},
color::{Color32, Rgba},
image::{AlphaImage, ColorImage, ImageData, ImageDelta},
mesh::{Mesh, Mesh16, Vertex},

View File

@@ -2,6 +2,7 @@ use crate::{
text::{FontId, Fonts, Galley},
Color32, Mesh, Stroke,
};
use crate::{CubicBezierShape, QuadraticBezierShape};
use emath::*;
/// A paint primitive such as a circle or a piece of text.
@@ -26,6 +27,8 @@ pub enum Shape {
Rect(RectShape),
Text(TextShape),
Mesh(Mesh),
QuadraticBezier(QuadraticBezierShape),
CubicBezier(CubicBezierShape),
}
/// ## Constructors
@@ -187,6 +190,16 @@ impl Shape {
Shape::Mesh(mesh) => {
mesh.translate(delta);
}
Shape::QuadraticBezier(bezier_shape) => {
bezier_shape.points[0] += delta;
bezier_shape.points[1] += delta;
bezier_shape.points[2] += delta;
}
Shape::CubicBezier(cubie_curve) => {
for p in &mut cubie_curve.points {
*p += delta;
}
}
}
}
}

View File

@@ -43,5 +43,13 @@ pub fn adjust_colors(shape: &mut Shape, adjust_color: &impl Fn(&mut Color32)) {
adjust_color(&mut v.color);
}
}
Shape::QuadraticBezier(quatratic) => {
adjust_color(&mut quatratic.fill);
adjust_color(&mut quatratic.stroke.color);
}
Shape::CubicBezier(bezier) => {
adjust_color(&mut bezier.fill);
adjust_color(&mut bezier.stroke.color);
}
}
}

View File

@@ -195,8 +195,12 @@ impl PaintStats {
self.add(shape);
}
}
Shape::Noop | Shape::Circle { .. } | Shape::LineSegment { .. } | Shape::Rect { .. } => {
}
Shape::Noop
| Shape::Circle { .. }
| Shape::LineSegment { .. }
| Shape::Rect { .. }
| Shape::CubicBezier(_)
| Shape::QuadraticBezier(_) => {}
Shape::Path(path_shape) => {
self.shape_path += AllocInfo::from_slice(&path_shape.points);
}

View File

@@ -286,6 +286,12 @@ pub struct TessellationOptions {
/// If true, no clipping will be done.
pub debug_ignore_clip_rects: bool,
/// The maximum distance between the original curve and the flattened curve.
pub bezier_tolerence: f32,
/// The default value will be 1.0e-5, it will be used during float compare.
pub epsilon: f32,
}
impl Default for TessellationOptions {
@@ -299,6 +305,8 @@ impl Default for TessellationOptions {
debug_paint_text_rects: false,
debug_paint_clip_rects: false,
debug_ignore_clip_rects: false,
bezier_tolerence: 0.1,
epsilon: 1.0e-5,
}
}
}
@@ -710,9 +718,93 @@ impl Tessellator {
}
self.tessellate_text(tex_size, text_shape, out);
}
Shape::QuadraticBezier(quadratic_shape) => {
self.tessellate_quadratic_bezier(quadratic_shape, out);
}
Shape::CubicBezier(cubic_shape) => self.tessellate_cubic_bezier(cubic_shape, out),
}
}
pub(crate) fn tessellate_quadratic_bezier(
&mut self,
quadratic_shape: QuadraticBezierShape,
out: &mut Mesh,
) {
let options = &self.options;
let clip_rect = self.clip_rect;
if options.coarse_tessellation_culling
&& !quadratic_shape.bounding_rect().intersects(clip_rect)
{
return;
}
let points = quadratic_shape.flatten(Some(options.bezier_tolerence));
self.tessellate_bezier_complete(
&points,
quadratic_shape.fill,
quadratic_shape.closed,
quadratic_shape.stroke,
out,
);
}
pub(crate) fn tessellate_cubic_bezier(
&mut self,
cubic_shape: CubicBezierShape,
out: &mut Mesh,
) {
let options = &self.options;
let clip_rect = self.clip_rect;
if options.coarse_tessellation_culling && !cubic_shape.bounding_rect().intersects(clip_rect)
{
return;
}
let points_vec =
cubic_shape.flatten_closed(Some(options.bezier_tolerence), Some(options.epsilon));
for points in points_vec {
self.tessellate_bezier_complete(
&points,
cubic_shape.fill,
cubic_shape.closed,
cubic_shape.stroke,
out,
);
}
}
fn tessellate_bezier_complete(
&mut self,
points: &[Pos2],
fill: Color32,
closed: bool,
stroke: Stroke,
out: &mut Mesh,
) {
self.scratchpad_path.clear();
if closed {
self.scratchpad_path.add_line_loop(points);
} else {
self.scratchpad_path.add_open_points(points);
}
if fill != Color32::TRANSPARENT {
crate::epaint_assert!(
closed,
"You asked to fill a path that is not closed. That makes no sense."
);
self.scratchpad_path.fill(fill, &self.options, out);
}
let typ = if closed {
PathType::Closed
} else {
PathType::Open
};
self.scratchpad_path.stroke(typ, stroke, &self.options, out);
}
pub(crate) fn tessellate_path(&mut self, path_shape: PathShape, out: &mut Mesh) {
if path_shape.points.len() < 2 {
return;