Skip to content

add ignore_smoothing #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/modules/tas_optimizer/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ impl Optimizer {
Line::RenderYawOverride(_) => (),
Line::PitchOverride(_) => (),
Line::RenderPitchOverride(_) => (),
Line::IgnoreSmoothing => (),
}
}

Expand Down
1 change: 1 addition & 0 deletions src/modules/tas_optimizer/simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ impl<'a, T: Trace> Iterator for Simulator<'a, T> {
Line::RenderYawOverride(_) => (),
Line::PitchOverride(_) => (),
Line::RenderPitchOverride(_) => (),
Line::IgnoreSmoothing => (),
}

// Advance to the next line for non-frame-bulks.
Expand Down
114 changes: 110 additions & 4 deletions src/modules/tas_studio/editor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use hltas::types::{
use hltas::HLTAS;
use itertools::Itertools;
use thiserror::Error;
use utils::get_ignore_smoothing_frames;

use self::db::{Action, ActionKind, Branch, Db};
use self::operation::{Key, Operation};
Expand Down Expand Up @@ -3512,12 +3513,15 @@ impl Editor {
let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw);
let pitches = frames.iter().map(|f| f.state.prev_frame_input.pitch);

let ignore_smoothing_frames = get_ignore_smoothing_frames(&self.script(), frames.len());

let smoothed_yaws = smoothed_views(
self.smooth_window_s,
self.smooth_small_window_s,
self.smooth_small_window_multiplier,
&frames[..frames.len()],
yaws,
ignore_smoothing_frames.as_slice(),
);

let smoothed_pitches = smoothed_views(
Expand All @@ -3526,6 +3530,7 @@ impl Editor {
self.smooth_small_window_multiplier,
&frames[..frames.len()],
pitches,
ignore_smoothing_frames.as_slice(),
);

let mut line = "target_yaw_override".to_string();
Expand Down Expand Up @@ -3583,13 +3588,16 @@ impl Editor {
));
}

let ignore_smoothing_frames = get_ignore_smoothing_frames(&self.script(), frames.len());

let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw);
let mut smoothed_yaws = smoothed_views(
self.smooth_window_s,
self.smooth_small_window_s,
self.smooth_small_window_multiplier,
&frames[start..=end],
yaws,
&ignore_smoothing_frames.as_slice()[start..=end],
);

// Skip the first frame because it is the initial frame before the start of the TAS.
Expand Down Expand Up @@ -3807,19 +3815,24 @@ impl Editor {
let yaws = branch.frames.iter().map(|f| f.state.prev_frame_input.yaw);
let pitches = branch.frames.iter().map(|f| f.state.prev_frame_input.pitch);

let ignore_smoothing_frames =
get_ignore_smoothing_frames(&smoothed_script, branch.frames.len());

let mut smoothed_yaws = smoothed_views(
self.smooth_window_s,
self.smooth_small_window_s,
self.smooth_small_window_multiplier,
&branch.frames,
yaws,
&ignore_smoothing_frames.as_slice(),
);
let mut smoothed_pitches = smoothed_views(
self.smooth_window_s,
self.smooth_small_window_s,
self.smooth_small_window_multiplier,
&branch.frames,
pitches,
&ignore_smoothing_frames.as_slice(),
);

// First yaw corresponds to the initial frame, which is not controlled by the TAS.
Expand Down Expand Up @@ -4581,10 +4594,11 @@ fn forward(pitch: f32, yaw: f32) -> Vec3 {
}

fn unwrap_angles(xs: impl Iterator<Item = f32>) -> impl Iterator<Item = f32> {
use std::f32::consts::PI;
// does things in f64 to avoid imprecision
use std::f64::consts::PI;

xs.scan((0., 0.), |(prev, offset), curr| {
let mut diff = curr - *prev + *offset;
let mut diff = curr as f64 - *prev as f64 + *offset as f64;
while diff >= PI {
diff -= 2. * PI;
*offset -= 2. * PI;
Expand All @@ -4595,7 +4609,7 @@ fn unwrap_angles(xs: impl Iterator<Item = f32>) -> impl Iterator<Item = f32> {
}

*prev += diff;
Some(*prev)
Some(*prev as f32)
})
}

Expand All @@ -4605,6 +4619,7 @@ fn smoothed_views(
small_window_multiplier: f32,
frames: &[Frame],
views: impl Iterator<Item = f32>,
ignore_smoothing_frames: &[bool],
) -> Vec<f32> {
if frames.is_empty() {
return vec![];
Expand All @@ -4626,6 +4641,11 @@ fn smoothed_views(
// The smoothing window is centered at the center of each yaw.
// For pitch smoothing, every frame has both pitch and yaw so iterate over this is ok.
for i in 0..unwrapped.len() {
if ignore_smoothing_frames[i] {
rv.push(unwrapped[i]);
continue;
}

let mut total_view = 0.;
let mut total_weight = 0.;

Expand Down Expand Up @@ -4950,6 +4970,7 @@ mod tests {
input: impl IntoIterator<Item = (f32, f32)>,
small_window_size: f32,
expect: Expect,
ignore_smoothing_frames: &[bool],
) {
let frames: Vec<Frame> = input
.into_iter()
Expand All @@ -4969,7 +4990,14 @@ mod tests {
.collect();

let yaws = frames.iter().map(|f| f.state.prev_frame_input.yaw);
let smoothed = smoothed_views(1., small_window_size, 4., &frames, yaws);
let smoothed = smoothed_views(
1.,
small_window_size,
4.,
&frames,
yaws,
ignore_smoothing_frames,
);
expect.assert_debug_eq(&smoothed);
}

Expand All @@ -4985,6 +5013,7 @@ mod tests {
2.0,
]
"#]],
vec![false; 3].as_slice(),
);
}

Expand All @@ -5008,6 +5037,7 @@ mod tests {
-0.75,
]
"#]],
vec![false; 5].as_slice(),
);
}

Expand All @@ -5031,6 +5061,7 @@ mod tests {
-0.75,
]
"#]],
vec![false; 5].as_slice(),
);
}

Expand All @@ -5054,6 +5085,7 @@ mod tests {
-0.9,
]
"#]],
vec![false; 5].as_slice(),
);
}

Expand All @@ -5079,6 +5111,7 @@ mod tests {
-0.9,
]
"#]],
vec![false; 6].as_slice(),
);
}

Expand All @@ -5102,6 +5135,79 @@ mod tests {
-0.9,
]
"#]],
vec![false; 5].as_slice(),
);
}

#[test]
fn test_smoothing_ignore1() {
check_smoothing(
[
(0.25, -1.),
(0.25, -1.),
(0.4, 1.),
(0.25, -1.),
(0.25, -1.),
],
0.5,
expect![[r#"
[
-1.0,
-0.4,
0.28000003,
-0.4,
-0.9,
]
"#]],
&[true, false, false, false, false],
);
}

#[test]
fn test_smoothing_ignore2() {
check_smoothing(
[
(0.25, -1.),
(0.25, -1.),
(0.4, 1.),
(0.25, -1.),
(0.25, -1.),
],
0.5,
expect![[r#"
[
-1.0,
-0.4,
0.28000003,
-0.4,
-1.0,
]
"#]],
&[true, false, false, false, true],
);
}

#[test]
fn test_smoothing_ignore3() {
check_smoothing(
[
(0.25, -1.),
(0.25, -1.),
(0.4, 1.),
(0.25, -1.),
(0.25, -1.),
],
0.5,
expect![[r#"
[
-1.0,
-0.4,
1.0,
-0.4,
-1.0,
]
"#]],
&[true, false, true, false, true],
);
}

Expand Down
54 changes: 54 additions & 0 deletions src/modules/tas_studio/editor/utils.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::iter;
use std::num::NonZeroU32;
use std::ops::Range;

use hltas::types::{AutoMovement, FrameBulk, Line, StrafeDir, StrafeSettings, StrafeType};
use hltas::HLTAS;
Expand Down Expand Up @@ -304,3 +305,56 @@ pub fn join_lines(prev: &mut Line, next: &Line) {

prev_bulk.frame_count = NonZeroU32::new(temp.get() + next_bulk.frame_count.get()).unwrap();
}

pub fn get_ignore_smoothing_frames(hltas: &HLTAS, frame_count: usize) -> Vec<bool> {
let line_first_frame_iter = line_first_frame_idx_and_frame_count(hltas).collect::<Vec<usize>>();

let mut numbers = vec![];
let mut get_next = false;

for (idx, line) in hltas.lines.iter().enumerate() {
// if matches `ignore_smoothing`, takes the immediate line or at the least calculate
// its affecting frame bulk
if matches!(line, Line::IgnoreSmoothing) && !get_next {
get_next = true;
numbers.push(idx);
continue;
}

// taking a framebulk immediately after `ignore_smoothing`
if matches!(line, Line::FrameBulk(_)) && get_next {
get_next = false;
numbers.push(idx);
continue;
}
}

// just to make sure
let numbers = if numbers.len() % 2 == 0 {
numbers
} else {
let mut numbers = numbers;

numbers.push(hltas.lines.len() - 1);

numbers
};

let ranges = numbers
// by the end of this, we have
// is line idx -> framebulk idx -> is line idx -> framebulk idx
.chunks(2)
// chunking by 2 will have us range of (start..end) based on line idx and bulk idx
.map(|arr| {
// .nth `line_first_frame_iter` to get the actual frame number
// need to add 1 always to the line number just because
(line_first_frame_iter[arr[0] + 1])..(line_first_frame_iter[arr[1] + 1])
})
.collect::<Vec<Range<usize>>>();

let contains = |idx| ranges.iter().any(|range| range.contains(&idx));

(0..frame_count)
.map(|frame_idx| if contains(frame_idx) { true } else { false })
.collect::<Vec<bool>>()
}
Loading