Curve method changes & fixed all_included
This commit is contained in:
+18
-10
@@ -3,7 +3,10 @@
|
||||
all(feature = "osu", not(feature = "no_sliders_no_leniency"))
|
||||
))]
|
||||
|
||||
use crate::{math_util, parse::Pos2};
|
||||
use crate::{
|
||||
math_util,
|
||||
parse::{PathType, Pos2},
|
||||
};
|
||||
|
||||
const BEZIER_TOLERANCE: f32 = 0.25;
|
||||
const CATMULL_DETAIL: f32 = 50.0;
|
||||
@@ -26,11 +29,16 @@ pub(crate) enum Curve<'p> {
|
||||
|
||||
impl<'p> Curve<'p> {
|
||||
#[inline]
|
||||
pub(crate) fn linear(points: &'p [Pos2]) -> Self {
|
||||
Self::Linear(points)
|
||||
pub(crate) fn new(points: &'p [Pos2], kind: PathType) -> Self {
|
||||
match kind {
|
||||
PathType::Bezier => Self::bezier(points),
|
||||
PathType::Catmull => Self::catmull(points),
|
||||
PathType::Linear => Self::Linear(points),
|
||||
PathType::PerfectCurve => Self::perfect(points),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn bezier(points: &[Pos2]) -> Self {
|
||||
fn bezier(points: &[Pos2]) -> Self {
|
||||
if points.len() == 1 {
|
||||
return Self::Bezier(Points::Single(points[0]));
|
||||
}
|
||||
@@ -70,7 +78,7 @@ impl<'p> Curve<'p> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn catmull(points: &[Pos2]) -> Self {
|
||||
fn catmull(points: &[Pos2]) -> Self {
|
||||
if points.len() == 1 {
|
||||
return Self::Catmull(Points::Single(points[0]));
|
||||
}
|
||||
@@ -123,7 +131,7 @@ impl<'p> Curve<'p> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn perfect(points: &[Pos2]) -> Self {
|
||||
fn perfect(points: &[Pos2]) -> Self {
|
||||
let (a, b, c) = (points[0], points[1], points[2]);
|
||||
let (center, mut radius) = math_util::get_circum_circle(a, b, c);
|
||||
radius *= ((!math_util::is_left(a, b, c)) as i8 * 2 - 1) as f32;
|
||||
@@ -135,21 +143,21 @@ impl<'p> Curve<'p> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn point_at_distance(&self, len: f32) -> Pos2 {
|
||||
pub(crate) fn point_at_distance(&self, dist: f32) -> Pos2 {
|
||||
let points = match self {
|
||||
Self::Bezier(points) => points,
|
||||
Self::Catmull(points) => points,
|
||||
Self::Linear(points) => return math_util::point_on_lines(points, len),
|
||||
Self::Linear(points) => return math_util::point_on_lines(points, dist),
|
||||
Self::Perfect {
|
||||
origin,
|
||||
center,
|
||||
radius,
|
||||
} => return math_util::rotate(*center, *origin, len / *radius),
|
||||
} => return math_util::rotate(*center, *origin, dist / *radius),
|
||||
};
|
||||
|
||||
match points {
|
||||
Points::Single(point) => *point,
|
||||
Points::Multi(points) => math_util::point_at_distance(points, len),
|
||||
Points::Multi(points) => math_util::point_at_distance(points, dist),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-22
@@ -14,7 +14,7 @@ use slider_state::SliderState;
|
||||
|
||||
use crate::{
|
||||
curve::Curve,
|
||||
parse::{HitObjectKind, PathType, Pos2},
|
||||
parse::{HitObjectKind, Pos2},
|
||||
Beatmap, Mods, StarResult, Strains,
|
||||
};
|
||||
|
||||
@@ -90,12 +90,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
|
||||
/ 100.0;
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = match path_type {
|
||||
PathType::Linear => Curve::linear(curve_points),
|
||||
PathType::Bezier => Curve::bezier(curve_points),
|
||||
PathType::Catmull => Curve::catmull(curve_points),
|
||||
PathType::PerfectCurve => Curve::perfect(curve_points),
|
||||
};
|
||||
let curve = Curve::new(curve_points, *path_type);
|
||||
|
||||
let mut current_distance = tick_distance;
|
||||
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
|
||||
@@ -327,22 +322,8 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
|
||||
/ (map.sv * slider_state.speed_mult)
|
||||
/ 100.0;
|
||||
|
||||
// Ensure path type validity
|
||||
let path_type = if *path_type == PathType::PerfectCurve && curve_points.len() > 3 {
|
||||
PathType::Bezier
|
||||
} else if curve_points.len() == 2 {
|
||||
PathType::Linear
|
||||
} else {
|
||||
*path_type
|
||||
};
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = match path_type {
|
||||
PathType::Linear => Curve::linear(curve_points),
|
||||
PathType::Bezier => Curve::bezier(curve_points),
|
||||
PathType::Catmull => Curve::catmull(curve_points),
|
||||
PathType::PerfectCurve => Curve::perfect(curve_points),
|
||||
};
|
||||
let curve = Curve::new(curve_points, *path_type);
|
||||
|
||||
let mut current_distance = tick_distance;
|
||||
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
|
||||
|
||||
+15
-25
@@ -12,10 +12,11 @@ pub(crate) fn cpn(mut p: i32, n: i32) -> f32 {
|
||||
}
|
||||
|
||||
p = p.min(n - p);
|
||||
let diff = n - p;
|
||||
let mut out = 1.0;
|
||||
|
||||
for i in 1..=p {
|
||||
out *= (n - p + i) as f32 / i as f32;
|
||||
out *= (diff + i) as f32 / i as f32;
|
||||
}
|
||||
|
||||
out
|
||||
@@ -55,43 +56,32 @@ pub(crate) fn point_on_lines(points: &[Pos2], len: f32) -> Pos2 {
|
||||
point_on_line(points[points.len() - 2], points[points.len() - 1], len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn distance_from_points(arr: &[Pos2]) -> f32 {
|
||||
arr.iter()
|
||||
.skip(1)
|
||||
.zip(arr.iter())
|
||||
.map(|(curr, prev)| curr.distance(*prev))
|
||||
.sum()
|
||||
}
|
||||
|
||||
pub(crate) fn point_at_distance(array: &[Pos2], distance: f32) -> Pos2 {
|
||||
if array.len() < 2 {
|
||||
pub(crate) fn point_at_distance(points: &[Pos2], dist: f32) -> Pos2 {
|
||||
if points.len() < 2 {
|
||||
return Pos2 { x: 0.0, y: 0.0 };
|
||||
} else if distance.abs() <= f32::EPSILON {
|
||||
return array[0];
|
||||
} else if distance_from_points(array) <= distance {
|
||||
return array[array.len() - 1];
|
||||
} else if dist.abs() <= f32::EPSILON {
|
||||
return points[0];
|
||||
}
|
||||
|
||||
let mut current_distance = 0.0;
|
||||
let mut new_distance;
|
||||
let mut curr_dist = 0.0;
|
||||
let mut new_dist;
|
||||
|
||||
for (&curr, &next) in array.iter().zip(array.iter().skip(1)) {
|
||||
new_distance = (curr - next).length();
|
||||
current_distance += new_distance;
|
||||
for (&curr, &next) in points.iter().zip(points.iter().skip(1)) {
|
||||
new_dist = (curr - next).length();
|
||||
curr_dist += new_dist;
|
||||
|
||||
if distance <= current_distance {
|
||||
let remaining_dist = distance - (current_distance - new_distance);
|
||||
if dist <= curr_dist {
|
||||
let remaining_dist = dist - (curr_dist - new_dist);
|
||||
|
||||
return if remaining_dist.abs() <= f32::EPSILON {
|
||||
curr
|
||||
} else {
|
||||
curr + (next - curr) * (remaining_dist / new_distance)
|
||||
curr + (next - curr) * (remaining_dist / new_dist)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
array[array.len() - 1]
|
||||
points[points.len() - 1]
|
||||
}
|
||||
|
||||
pub(crate) fn get_circum_circle(p0: Pos2, p1: Pos2, p2: Pos2) -> (Pos2, f32) {
|
||||
|
||||
@@ -369,18 +369,18 @@ fn stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
||||
}
|
||||
|
||||
if hit_objects[n].is_slider()
|
||||
&& hit_objects[n].end_pos().distance(&hit_objects[i].pos) < STACK_DISTANCE
|
||||
&& hit_objects[n].end_pos().distance(hit_objects[i].pos) < STACK_DISTANCE
|
||||
{
|
||||
let offset = hit_objects[i].stack_height - hit_objects[n].stack_height + 1.0;
|
||||
|
||||
for j in n + 1..=i {
|
||||
if hit_objects[n].pos.distance(&hit_objects[j].pos) < STACK_DISTANCE {
|
||||
if hit_objects[n].pos.distance(hit_objects[j].pos) < STACK_DISTANCE {
|
||||
hit_objects[j].stack_height -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
} else if hit_objects[n].pos.distance(&hit_objects[i].pos) < STACK_DISTANCE {
|
||||
} else if hit_objects[n].pos.distance(hit_objects[i].pos) < STACK_DISTANCE {
|
||||
hit_objects[n].stack_height = hit_objects[i].stack_height + 1.0;
|
||||
i = n;
|
||||
}
|
||||
@@ -396,7 +396,7 @@ fn stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
||||
continue;
|
||||
} else if hit_objects[i].time - hit_objects[n].time > stack_threshold {
|
||||
break;
|
||||
} else if hit_objects[n].end_pos().distance(&hit_objects[i].pos) < STACK_DISTANCE {
|
||||
} else if hit_objects[n].end_pos().distance(hit_objects[i].pos) < STACK_DISTANCE {
|
||||
hit_objects[n].stack_height = hit_objects[i].stack_height + 1.0;
|
||||
i = n;
|
||||
}
|
||||
@@ -421,10 +421,10 @@ fn old_stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
||||
break;
|
||||
}
|
||||
|
||||
if hit_objects[j].pos.distance(&hit_objects[i].pos) < STACK_DISTANCE {
|
||||
if hit_objects[j].pos.distance(hit_objects[i].pos) < STACK_DISTANCE {
|
||||
hit_objects[i].stack_height += 1.0;
|
||||
start_time = hit_objects[j].end_time();
|
||||
} else if hit_objects[j].pos.distance(&end_pos) < STACK_DISTANCE {
|
||||
} else if hit_objects[j].pos.distance(end_pos) < STACK_DISTANCE {
|
||||
slider_stack += 1.0;
|
||||
hit_objects[j].stack_height -= slider_stack;
|
||||
start_time = hit_objects[j].end_time();
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::slider_state::SliderState;
|
||||
|
||||
use crate::{
|
||||
curve::Curve,
|
||||
parse::{HitObject, HitObjectKind, PathType, Pos2},
|
||||
parse::{HitObject, HitObjectKind, Pos2},
|
||||
Beatmap,
|
||||
};
|
||||
|
||||
@@ -76,12 +76,7 @@ impl OsuObject {
|
||||
let span_duration = duration / *repeats as f32;
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = match path_type {
|
||||
PathType::Linear => Curve::linear(curve_points[0], curve_points[1]),
|
||||
PathType::Bezier => Curve::bezier(&curve_points),
|
||||
PathType::Catmull => Curve::catmull(&curve_points),
|
||||
PathType::PerfectCurve => Curve::perfect(&curve_points),
|
||||
};
|
||||
let curve = Curve::new(curve_points, *path_type);
|
||||
|
||||
// Called on each slider object except for the head.
|
||||
// Increases combo and adjusts `end_pos` and `travel_dist`
|
||||
|
||||
@@ -3,7 +3,7 @@ use super::slider_state::SliderState;
|
||||
|
||||
use crate::{
|
||||
curve::Curve,
|
||||
parse::{HitObject, HitObjectKind, PathType, Pos2},
|
||||
parse::{HitObject, HitObjectKind, Pos2},
|
||||
Beatmap,
|
||||
};
|
||||
|
||||
@@ -63,12 +63,7 @@ impl OsuObject {
|
||||
let span_duration = duration / *repeats as f32;
|
||||
|
||||
// Build the curve w.r.t. the curve points
|
||||
let curve = match path_type {
|
||||
PathType::Linear => Curve::linear(curve_points),
|
||||
PathType::Bezier => Curve::bezier(curve_points),
|
||||
PathType::Catmull => Curve::catmull(curve_points),
|
||||
PathType::PerfectCurve => Curve::perfect(curve_points),
|
||||
};
|
||||
let curve = Curve::new(curve_points, *path_type);
|
||||
|
||||
// Called on each slider object except for the head.
|
||||
// Increases combo and adjusts `end_pos` and `travel_dist`
|
||||
|
||||
Reference in New Issue
Block a user