diff --git a/src-frontend/src/hooks/useTauri.js b/src-frontend/src/hooks/useTauri.js index 68f7247c..6c317987 100644 --- a/src-frontend/src/hooks/useTauri.js +++ b/src-frontend/src/hooks/useTauri.js @@ -44,7 +44,6 @@ export const DEFAULT_PAINT_PARAMS = { n_directions: 48, lookahead_steps: 3, momentum_weight: 0.20, - wall_follow_weight: 0.0, overpaint_penalty: 0.10, walk_bg_penalty: 0.69, min_score_factor: 0.20, diff --git a/src/brush_paint.rs b/src/brush_paint.rs index f1dff4c1..d7566a90 100644 --- a/src/brush_paint.rs +++ b/src/brush_paint.rs @@ -81,15 +81,6 @@ pub struct PaintParams { /// Bonus weight on direction alignment with current velocity. /// 0 = no momentum, 1 = momentum equally weighted with new coverage. pub momentum_weight: f32, - /// Bonus weight for "right-hand on the wall" wall-following. For each - /// candidate direction the walker raycasts perpendicular CW; if the - /// resulting wall distance is near `brush_radius` (= the pen would be - /// riding the wall at its natural offset), the candidate's score gets - /// a `wall_follow_weight × brush_area` bonus that decays linearly to - /// 0 as the wall distance moves away from `brush_radius`. Helps the - /// walker take the down-into-V step at M/W/A apexes where greedy - /// lookahead-coverage alone collapses. 0 = off, no behavior change. - pub wall_follow_weight: f32, /// Per-overpainted-pixel penalty in scoring (relative to new coverage /// which is +1 per pixel). Applied to ink we already painted (mild — /// just discourages backtracking). @@ -140,7 +131,6 @@ impl Default for PaintParams { n_directions: 48, lookahead_steps: 3, momentum_weight: 0.20, - wall_follow_weight: 0.0, overpaint_penalty: 0.10, walk_bg_penalty: 0.69, min_score_factor: 0.20, @@ -273,11 +263,7 @@ pub struct WalkCandidate { /// `momentum_weight × max(0, dot(dir, prev_dir)) × brush_area` (0 if /// no prev_dir). pub momentum_bonus: f32, - /// `wall_follow_weight × wall_proximity × brush_area`. Peaks when - /// the right-perpendicular raycast hits a wall at distance ≈ - /// brush_radius (pen riding the wall at natural offset). - pub wall_bonus: f32, - /// Final score = new_ink − overpaint·repaint − walk_bg·bg + momentum_bonus + wall_bonus. + /// Final score = new_ink − overpaint·repaint − walk_bg·bg + momentum_bonus. pub score: f32, } @@ -960,43 +946,6 @@ fn vec_unit(v: (f32, f32)) -> (f32, f32) { } fn vec_dot(a: (f32, f32), b: (f32, f32)) -> f32 { a.0 * b.0 + a.1 * b.1 } -/// Cast a ray from `p` in direction `dir` (unit vector) over the grid's -/// `was_ink` mask. Returns the distance, in pixels, to the first non-ink -/// pixel — capped at `max_steps`. The ray walks in 1-px increments; for -/// our use case (max_steps ≈ 2× brush_radius ≈ 5–10 px), that's a -/// handful of `BitMask::get` lookups per ray. -fn raycast_to_wall(grid: &Grid, p: (f32, f32), dir: (f32, f32), max_steps: u32) -> f32 { - for k in 1..=max_steps { - let kf = k as f32; - let probe_x = (p.0 + dir.0 * kf).round() as i32; - let probe_y = (p.1 + dir.1 * kf).round() as i32; - if !grid.is_ink(probe_x, probe_y) { - return kf - 1.0; - } - } - max_steps as f32 -} - -/// Right-hand wall-following bonus for one candidate direction. -/// Computes the perpendicular CW raycast distance and rewards positions -/// where it sits near `brush_radius` (the pen's natural offset for -/// riding the wall). Falls off linearly to 0 as the distance drifts -/// away from `brush_radius` by ±brush_radius. Returns a value in -/// [0, brush_area] so it scales the same as `momentum_bonus`. -fn wall_follow_bonus(grid: &Grid, p: (f32, f32), dir: (f32, f32), - brush_radius: f32, brush_area: f32) -> f32 { - if brush_radius <= 0.0 { return 0.0; } - // Perpendicular CW: rotate (dx, dy) by -90° → (dy, -dx). - let perp_cw = (dir.1, -dir.0); - // Cap the raycast at 2× brush_radius — anything farther means the - // pen isn't on a wall at all, so wall-bonus is 0 anyway. - let max_steps = (2.0 * brush_radius).ceil().max(1.0) as u32; - let wall_dist = raycast_to_wall(grid, p, perp_cw, max_steps); - let offset = (wall_dist - brush_radius).abs(); - let proximity = (1.0 - offset / brush_radius).max(0.0); - proximity * brush_area -} - // ── Trace a single stroke ─────────────────────────────────────────────── /// Score one candidate direction by simulating `lookahead_steps` walks @@ -1068,20 +1017,16 @@ fn walk_brush(start: (f32, f32), init_dir: Option<(f32, f32)>, let momentum_bonus = if has_momentum { params.momentum_weight * vec_dot(dir, prev_dir_unit).max(0.0) * brush_area } else { 0.0 }; - let wall_bonus = if params.wall_follow_weight > 0.0 { - params.wall_follow_weight * wall_follow_bonus(grid, p, dir, brush_radius, brush_area) - } else { 0.0 }; let score = new_ink - params.overpaint_penalty * repaint - params.walk_bg_penalty * bg - + momentum_bonus - + wall_bonus; + + momentum_bonus; if recording { recorded.push(WalkCandidate { theta, dir, probe, rejected_back, rejected_off_ink, - new_ink, repaint, bg, momentum_bonus, wall_bonus, score, + new_ink, repaint, bg, momentum_bonus, score, }); } diff --git a/src/brush_paint_opt.rs b/src/brush_paint_opt.rs index 40680a8f..cc7f25a5 100644 --- a/src/brush_paint_opt.rs +++ b/src/brush_paint_opt.rs @@ -59,8 +59,6 @@ pub fn default_axes() -> Vec { set: |p, v| p.n_directions = v as usize, get: |p| p.n_directions as f32 }, Axis { name: "momentum_weight", lo: 0.0, hi: 2.0, is_int: false, set: |p, v| p.momentum_weight = v, get: |p| p.momentum_weight }, - Axis { name: "wall_follow_weight", lo: 0.0, hi: 2.0, is_int: false, - set: |p, v| p.wall_follow_weight = v, get: |p| p.wall_follow_weight }, Axis { name: "min_score_factor", lo: 0.05, hi: 0.30, is_int: false, set: |p, v| p.min_score_factor = v, get: |p| p.min_score_factor }, Axis { name: "back_dir_cutoff", lo: -0.95, hi: -0.3, is_int: false,