mod rendering;
mod scoring;
mod utils;
const MAX_SKIP_AMOUNT: i32 = 9;
const Q_VALUES: [f64; 6] = [1.0, 5.0, 2.0, 2.5, 4.0, 3.0];
pub fn float_axis_labels(
x_min: f64,
x_max: f64,
available_space: u32,
padding_left: u32,
vertical_direction: bool,
unit: &String,
) -> String {
if (available_space == 0) || (x_max < x_min) {
return String::from("");
}
let base_exponent = (x_max - x_min).log10() as i64;
let preferred_nr_labels =
crate::scoring::compute_preferred_number_of_labels(available_space, false);
let mut best_score = -2.0;
let mut best_result = String::new();
let mut q: f64;
let mut step_size: f64;
for exponent in [base_exponent, base_exponent - 1] {
let f = x_min / 10_f64.powf(exponent as f64 + 1.0);
let label_start = f.floor() * 10_f64.powf(exponent as f64 + 1.0);
for j in 1..(MAX_SKIP_AMOUNT + 1) {
for ix in 0..(Q_VALUES.len()) {
let i = ix as i32;
q = Q_VALUES[ix];
step_size = q * (j as f64) * 10_f64.powf(exponent as f64);
let labels = crate::utils::linspace(label_start, x_min, x_max, step_size);
if labels.len() < 2 {
continue;
}
let simplicity =
crate::scoring::compute_simplicity_score(&labels, i, j, Q_VALUES.len());
let coverage = crate::scoring::compute_coverage_score(&labels, x_min, x_max);
let density = crate::scoring::compute_density_score(&labels, preferred_nr_labels);
let score_upper_bound =
crate::scoring::upper_bound_on_overall_score(simplicity, coverage, density);
if (!best_result.is_empty()) && (score_upper_bound < best_score) {
continue;
}
let (result, grid_overlap) = crate::rendering::render(
&labels,
x_min,
x_max,
available_space,
padding_left,
vertical_direction,
&unit,
);
let grid_alignment = 1.0 - ((grid_overlap as i32) as f64);
let score =
crate::scoring::overall_score(simplicity, coverage, density, grid_alignment);
if score > best_score {
best_score = score;
best_result = result;
}
}
}
}
return best_result;
}