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"))
|
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 BEZIER_TOLERANCE: f32 = 0.25;
|
||||||
const CATMULL_DETAIL: f32 = 50.0;
|
const CATMULL_DETAIL: f32 = 50.0;
|
||||||
@@ -26,11 +29,16 @@ pub(crate) enum Curve<'p> {
|
|||||||
|
|
||||||
impl<'p> Curve<'p> {
|
impl<'p> Curve<'p> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn linear(points: &'p [Pos2]) -> Self {
|
pub(crate) fn new(points: &'p [Pos2], kind: PathType) -> Self {
|
||||||
Self::Linear(points)
|
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 {
|
if points.len() == 1 {
|
||||||
return Self::Bezier(Points::Single(points[0]));
|
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 {
|
if points.len() == 1 {
|
||||||
return Self::Catmull(Points::Single(points[0]));
|
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 (a, b, c) = (points[0], points[1], points[2]);
|
||||||
let (center, mut radius) = math_util::get_circum_circle(a, b, c);
|
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;
|
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 {
|
let points = match self {
|
||||||
Self::Bezier(points) => points,
|
Self::Bezier(points) => points,
|
||||||
Self::Catmull(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 {
|
Self::Perfect {
|
||||||
origin,
|
origin,
|
||||||
center,
|
center,
|
||||||
radius,
|
radius,
|
||||||
} => return math_util::rotate(*center, *origin, len / *radius),
|
} => return math_util::rotate(*center, *origin, dist / *radius),
|
||||||
};
|
};
|
||||||
|
|
||||||
match points {
|
match points {
|
||||||
Points::Single(point) => *point,
|
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::{
|
use crate::{
|
||||||
curve::Curve,
|
curve::Curve,
|
||||||
parse::{HitObjectKind, PathType, Pos2},
|
parse::{HitObjectKind, Pos2},
|
||||||
Beatmap, Mods, StarResult, Strains,
|
Beatmap, Mods, StarResult, Strains,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,12 +90,7 @@ pub fn stars(map: &Beatmap, mods: impl Mods, passed_objects: Option<usize>) -> S
|
|||||||
/ 100.0;
|
/ 100.0;
|
||||||
|
|
||||||
// Build the curve w.r.t. the curve points
|
// Build the curve w.r.t. the curve points
|
||||||
let curve = match path_type {
|
let curve = Curve::new(curve_points, *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 mut current_distance = tick_distance;
|
let mut current_distance = tick_distance;
|
||||||
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
|
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)
|
/ (map.sv * slider_state.speed_mult)
|
||||||
/ 100.0;
|
/ 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
|
// Build the curve w.r.t. the curve points
|
||||||
let curve = match path_type {
|
let curve = Curve::new(curve_points, *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 mut current_distance = tick_distance;
|
let mut current_distance = tick_distance;
|
||||||
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
|
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);
|
p = p.min(n - p);
|
||||||
|
let diff = n - p;
|
||||||
let mut out = 1.0;
|
let mut out = 1.0;
|
||||||
|
|
||||||
for i in 1..=p {
|
for i in 1..=p {
|
||||||
out *= (n - p + i) as f32 / i as f32;
|
out *= (diff + i) as f32 / i as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
out
|
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)
|
point_on_line(points[points.len() - 2], points[points.len() - 1], len)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
pub(crate) fn point_at_distance(points: &[Pos2], dist: f32) -> Pos2 {
|
||||||
pub(crate) fn distance_from_points(arr: &[Pos2]) -> f32 {
|
if points.len() < 2 {
|
||||||
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 {
|
|
||||||
return Pos2 { x: 0.0, y: 0.0 };
|
return Pos2 { x: 0.0, y: 0.0 };
|
||||||
} else if distance.abs() <= f32::EPSILON {
|
} else if dist.abs() <= f32::EPSILON {
|
||||||
return array[0];
|
return points[0];
|
||||||
} else if distance_from_points(array) <= distance {
|
|
||||||
return array[array.len() - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut current_distance = 0.0;
|
let mut curr_dist = 0.0;
|
||||||
let mut new_distance;
|
let mut new_dist;
|
||||||
|
|
||||||
for (&curr, &next) in array.iter().zip(array.iter().skip(1)) {
|
for (&curr, &next) in points.iter().zip(points.iter().skip(1)) {
|
||||||
new_distance = (curr - next).length();
|
new_dist = (curr - next).length();
|
||||||
current_distance += new_distance;
|
curr_dist += new_dist;
|
||||||
|
|
||||||
if distance <= current_distance {
|
if dist <= curr_dist {
|
||||||
let remaining_dist = distance - (current_distance - new_distance);
|
let remaining_dist = dist - (curr_dist - new_dist);
|
||||||
|
|
||||||
return if remaining_dist.abs() <= f32::EPSILON {
|
return if remaining_dist.abs() <= f32::EPSILON {
|
||||||
curr
|
curr
|
||||||
} else {
|
} 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) {
|
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()
|
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;
|
let offset = hit_objects[i].stack_height - hit_objects[n].stack_height + 1.0;
|
||||||
|
|
||||||
for j in n + 1..=i {
|
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;
|
hit_objects[j].stack_height -= offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
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;
|
hit_objects[n].stack_height = hit_objects[i].stack_height + 1.0;
|
||||||
i = n;
|
i = n;
|
||||||
}
|
}
|
||||||
@@ -396,7 +396,7 @@ fn stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
|||||||
continue;
|
continue;
|
||||||
} else if hit_objects[i].time - hit_objects[n].time > stack_threshold {
|
} else if hit_objects[i].time - hit_objects[n].time > stack_threshold {
|
||||||
break;
|
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;
|
hit_objects[n].stack_height = hit_objects[i].stack_height + 1.0;
|
||||||
i = n;
|
i = n;
|
||||||
}
|
}
|
||||||
@@ -421,10 +421,10 @@ fn old_stacking(hit_objects: &mut [OsuObject], stack_threshold: f32) {
|
|||||||
break;
|
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;
|
hit_objects[i].stack_height += 1.0;
|
||||||
start_time = hit_objects[j].end_time();
|
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;
|
slider_stack += 1.0;
|
||||||
hit_objects[j].stack_height -= slider_stack;
|
hit_objects[j].stack_height -= slider_stack;
|
||||||
start_time = hit_objects[j].end_time();
|
start_time = hit_objects[j].end_time();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use super::slider_state::SliderState;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
curve::Curve,
|
curve::Curve,
|
||||||
parse::{HitObject, HitObjectKind, PathType, Pos2},
|
parse::{HitObject, HitObjectKind, Pos2},
|
||||||
Beatmap,
|
Beatmap,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,12 +76,7 @@ impl OsuObject {
|
|||||||
let span_duration = duration / *repeats as f32;
|
let span_duration = duration / *repeats as f32;
|
||||||
|
|
||||||
// Build the curve w.r.t. the curve points
|
// Build the curve w.r.t. the curve points
|
||||||
let curve = match path_type {
|
let curve = Curve::new(curve_points, *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),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Called on each slider object except for the head.
|
// Called on each slider object except for the head.
|
||||||
// Increases combo and adjusts `end_pos` and `travel_dist`
|
// Increases combo and adjusts `end_pos` and `travel_dist`
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use super::slider_state::SliderState;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
curve::Curve,
|
curve::Curve,
|
||||||
parse::{HitObject, HitObjectKind, PathType, Pos2},
|
parse::{HitObject, HitObjectKind, Pos2},
|
||||||
Beatmap,
|
Beatmap,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,12 +63,7 @@ impl OsuObject {
|
|||||||
let span_duration = duration / *repeats as f32;
|
let span_duration = duration / *repeats as f32;
|
||||||
|
|
||||||
// Build the curve w.r.t. the curve points
|
// Build the curve w.r.t. the curve points
|
||||||
let curve = match path_type {
|
let curve = Curve::new(curve_points, *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),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Called on each slider object except for the head.
|
// Called on each slider object except for the head.
|
||||||
// Increases combo and adjusts `end_pos` and `travel_dist`
|
// Increases combo and adjusts `end_pos` and `travel_dist`
|
||||||
|
|||||||
Reference in New Issue
Block a user