use crate::numerical_integration::iterative_integration::DEFAULT_TOTAL_ITERATIONS;
use crate::utils::error_codes::CalcError;
fn curve_point<const N: usize>(transformations: &[&dyn Fn(f64) -> f64; N], t: f64) -> [f64; N] {
let mut point = [0.0; N];
for i in 0..N {
point[i] = transformations[i](t);
}
point
}
fn get_partial<const N: usize>(
vector_field: &[&dyn Fn(&[f64; N]) -> f64; N],
transformations: &[&dyn Fn(f64) -> f64; N],
integration_limit: &[f64; 2],
total_iterations: u64,
idx: usize,
) -> Result<f64, CalcError> {
if total_iterations == 0 {
return Err(CalcError::IterationsZero);
}
if !matches!(
integration_limit[0].partial_cmp(&integration_limit[1]),
Some(core::cmp::Ordering::Less)
) {
return Err(CalcError::IntegrationLimitsIllDefined);
}
let delta = (integration_limit[1] - integration_limit[0]) / total_iterations as f64;
let mut t = integration_limit[0];
let mut ans = 0.0;
let mut left = curve_point(transformations, t);
let mut left_value = vector_field[idx](&left);
for _ in 0..total_iterations {
let right = curve_point(transformations, t + delta);
let right_value = vector_field[idx](&right);
ans += (right[idx] - left[idx]) * (left_value + right_value) / 2.0;
t += delta;
left = right;
left_value = right_value;
}
Ok(ans)
}
pub fn get_2d(
vector_field: &[&dyn Fn(&[f64; 2]) -> f64; 2],
transformations: &[&dyn Fn(f64) -> f64; 2],
integration_limit: &[f64; 2],
) -> Result<f64, CalcError> {
get_2d_custom(
vector_field,
transformations,
integration_limit,
DEFAULT_TOTAL_ITERATIONS,
)
}
pub fn get_2d_custom(
vector_field: &[&dyn Fn(&[f64; 2]) -> f64; 2],
transformations: &[&dyn Fn(f64) -> f64; 2],
integration_limit: &[f64; 2],
total_iterations: u64,
) -> Result<f64, CalcError> {
Ok(get_partial_2d(
vector_field,
transformations,
integration_limit,
total_iterations,
0,
)? + get_partial_2d(
vector_field,
transformations,
integration_limit,
total_iterations,
1,
)?)
}
pub fn get_partial_2d(
vector_field: &[&dyn Fn(&[f64; 2]) -> f64; 2],
transformations: &[&dyn Fn(f64) -> f64; 2],
integration_limit: &[f64; 2],
total_iterations: u64,
idx: usize,
) -> Result<f64, CalcError> {
get_partial(
vector_field,
transformations,
integration_limit,
total_iterations,
idx,
)
}
pub fn get_3d(
vector_field: &[&dyn Fn(&[f64; 3]) -> f64; 3],
transformations: &[&dyn Fn(f64) -> f64; 3],
integration_limit: &[f64; 2],
) -> Result<f64, CalcError> {
get_3d_custom(
vector_field,
transformations,
integration_limit,
DEFAULT_TOTAL_ITERATIONS,
)
}
pub fn get_3d_custom(
vector_field: &[&dyn Fn(&[f64; 3]) -> f64; 3],
transformations: &[&dyn Fn(f64) -> f64; 3],
integration_limit: &[f64; 2],
total_iterations: u64,
) -> Result<f64, CalcError> {
Ok(get_partial_3d(
vector_field,
transformations,
integration_limit,
total_iterations,
0,
)? + get_partial_3d(
vector_field,
transformations,
integration_limit,
total_iterations,
1,
)? + get_partial_3d(
vector_field,
transformations,
integration_limit,
total_iterations,
2,
)?)
}
pub fn get_partial_3d(
vector_field: &[&dyn Fn(&[f64; 3]) -> f64; 3],
transformations: &[&dyn Fn(f64) -> f64; 3],
integration_limit: &[f64; 2],
total_iterations: u64,
idx: usize,
) -> Result<f64, CalcError> {
get_partial(
vector_field,
transformations,
integration_limit,
total_iterations,
idx,
)
}