From 7b66e2274bbfbbca72007243e0af74b2f1517601 Mon Sep 17 00:00:00 2001 From: Falk David Date: Mon, 27 May 2024 17:23:49 +0200 Subject: [PATCH] GPv3: Draw Tool: Refactor `simplify_stroke` Previously the `simplify_stroke` stroke step used the screen space coordinates to do the simplification. Instead, this is now refactored to use the more general `geometry::simplify_curve_attribute`. This means we can simplify the stroke based on the positions and radii. The simplify step is also now hooked up to the simplify option in the tool settings (under the `Stroke` panel). --- .../sculpt_paint/grease_pencil_paint.cc | 74 ++++++++----------- 1 file changed, 30 insertions(+), 44 deletions(-) diff --git a/source/blender/editors/sculpt_paint/grease_pencil_paint.cc b/source/blender/editors/sculpt_paint/grease_pencil_paint.cc index 18581c6b695..b2bd73e486a 100644 --- a/source/blender/editors/sculpt_paint/grease_pencil_paint.cc +++ b/source/blender/editors/sculpt_paint/grease_pencil_paint.cc @@ -26,6 +26,7 @@ #include "ED_grease_pencil.hh" #include "ED_view3d.hh" +#include "GEO_simplify_curves.hh" #include "GEO_smooth_curves.hh" #include "WM_api.hh" @@ -705,55 +706,41 @@ void PaintOperation::on_stroke_extended(const bContext &C, const InputSample &ex WM_event_add_notifier(&C, NC_GEOM | ND_DATA, grease_pencil); } -static float dist_to_interpolated_2d( - float2 pos, float2 posA, float2 posB, float val, float valA, float valB) -{ - const float dist1 = math::distance_squared(posA, pos); - const float dist2 = math::distance_squared(posB, pos); - - if (dist1 + dist2 > 1e-5f) { - const float interpolated_val = math::interpolate(valB, valA, dist1 / (dist1 + dist2)); - return math::distance(interpolated_val, val); - } - return 0.0f; -} - void PaintOperation::simplify_stroke(const bContext &C, bke::greasepencil::Drawing &drawing, - const float epsilon_px) + const float epsilon) { const Scene *scene = CTX_data_scene(&C); + const bke::CurvesGeometry &curves = drawing.strokes(); + const bool on_back = (scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) != 0; - const int active_curve = on_back ? drawing.strokes().curves_range().first() : - drawing.strokes().curves_range().last(); - const IndexRange points = drawing.strokes().points_by_curve()[active_curve]; - bke::CurvesGeometry &curves = drawing.strokes_for_write(); + const int active_curve = on_back ? curves.curves_range().first() : curves.curves_range().last(); + + IndexMaskMemory memory; + IndexMask points_to_delete = geometry::simplify_curve_attribute( + curves.positions(), + IndexRange::from_single(active_curve), + curves.points_by_curve(), + curves.cyclic(), + epsilon, + curves.positions(), + memory); + const VArray radii = drawing.radii(); + if (!radii.is_empty() && radii.is_span()) { + const IndexMask radii_mask = geometry::simplify_curve_attribute( + curves.positions(), + IndexRange::from_single(active_curve), + curves.points_by_curve(), + curves.cyclic(), + epsilon, + radii.get_internal_span(), + memory); + points_to_delete = IndexMask::from_intersection(points_to_delete, radii_mask, memory); + } - /* Distance function for `ramer_douglas_peucker_simplify`. */ - const Span positions_2d = this->screen_space_smoothed_coords_.as_span(); - const auto dist_function = [&](int64_t first_index, int64_t last_index, int64_t index) { - /* 2D coordinates are only stored for the current stroke, so offset the indices. */ - const float dist_position_px = dist_to_line_segment_v2( - positions_2d[index - points.first()], - positions_2d[first_index - points.first()], - positions_2d[last_index - points.first()]); - const float dist_radii_px = dist_to_interpolated_2d(positions_2d[index - points.first()], - positions_2d[first_index - points.first()], - positions_2d[last_index - points.first()], - radii[index], - radii[first_index], - radii[last_index]); - return math::max(dist_position_px, dist_radii_px); - }; - - Array points_to_delete(curves.points_num(), false); - int64_t total_points_to_delete = ed::greasepencil::ramer_douglas_peucker_simplify( - points, epsilon_px, dist_function, points_to_delete.as_mutable_span()); - - if (total_points_to_delete > 0) { - IndexMaskMemory memory; - curves.remove_points(IndexMask::from_bools(points_to_delete, memory), {}); + if (!points_to_delete.is_empty()) { + drawing.strokes_for_write().remove_points(points_to_delete, {}); } } @@ -867,8 +854,7 @@ void PaintOperation::on_stroke_done(const bContext &C) bke::greasepencil::Drawing &drawing = *grease_pencil.get_editable_drawing_at(active_layer, scene->r.cfra); if (do_post_processing) { - const float simplifiy_threshold_px = 0.5f; - this->simplify_stroke(C, drawing, simplifiy_threshold_px); + this->simplify_stroke(C, drawing, settings->simplify_f); } this->process_stroke_end(C, drawing); drawing.tag_topology_changed();