Revert "brush-paint: add wall_follow_weight — right-hand wall-following bonus"

This reverts commit 1ce6244340.
This commit is contained in:
Mitchell Hansen
2026-05-07 23:13:49 -07:00
parent 1ce6244340
commit f370b99d95
3 changed files with 3 additions and 61 deletions

View File

@@ -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,

View File

@@ -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 ≈ 510 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,
});
}

View File

@@ -59,8 +59,6 @@ pub fn default_axes() -> Vec<Axis> {
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,