Skip to content

Commit 72ff610

Browse files
committed
fix curve preview bug
1 parent 52af0b1 commit 72ff610

4 files changed

Lines changed: 304 additions & 47 deletions

File tree

src/app.rs

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ use crate::domain::{
4848
};
4949
use crate::fit::{
5050
FitError, SplineConfig, SplineDuplicateXPolicy, SplineExtrapolation, SplineFamilyKind,
51-
SplineKnotStrategy, SplineResult, calculate_iteration_metrics, default_spline_initial_knot_y,
51+
SplineKnotStrategy, SplineResult, build_spline_initial_curve_from_knot_y,
52+
calculate_iteration_metrics, default_spline_initial_knot_y,
5253
fit_curve_with_progress_and_optimizer_config_and_loss_metric, sample_curve,
5354
};
5455
#[cfg(target_arch = "wasm32")]
@@ -979,6 +980,29 @@ impl CurveFitApp {
979980
self.replay_last_step_at = None;
980981
}
981982

983+
fn select_replay_last_frame(&mut self) {
984+
if let Some(last_index) = self.replay_frames.len().checked_sub(1) {
985+
self.set_replay_selected_index(last_index);
986+
}
987+
}
988+
989+
fn finalize_replay_after_fit_completion(&mut self) {
990+
if self.replay_autoplay_on_fit && self.replay_frames.len() > 1 {
991+
self.start_replay_from_beginning();
992+
return;
993+
}
994+
995+
self.pause_replay();
996+
self.select_replay_last_frame();
997+
}
998+
999+
fn finalize_replay_after_fit_stopped(&mut self) {
1000+
self.pause_replay();
1001+
if !self.replay_autoplay_on_fit {
1002+
self.select_replay_last_frame();
1003+
}
1004+
}
1005+
9821006
fn toggle_replay_autoplay(&mut self) {
9831007
if self.replay_autoplay {
9841008
self.replay_autoplay = false;
@@ -992,11 +1016,9 @@ impl CurveFitApp {
9921016

9931017
let at_end = self
9941018
.replay_selected_index
995-
.map_or(true, |index| index + 1 >= self.replay_frames.len());
1019+
.is_none_or(|index| index + 1 >= self.replay_frames.len());
9961020
if at_end {
9971021
self.set_replay_selected_index(0);
998-
} else if self.replay_selected_index.is_none() {
999-
self.set_replay_selected_index(0);
10001022
}
10011023

10021024
self.replay_autoplay = true;

src/app/fit_worker.rs

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
use super::*;
22

33
impl CurveFitApp {
4+
fn plot_points_from_pairs<I>(pairs: I) -> Vec<PlotPoint>
5+
where
6+
I: IntoIterator<Item = [f64; 2]>,
7+
{
8+
pairs
9+
.into_iter()
10+
.map(|point| PlotPoint::new(point[0], point[1]))
11+
.collect()
12+
}
13+
414
fn status_is_fitting(&self) -> bool {
515
matches!(
616
self.status.as_ref(),
@@ -69,11 +79,7 @@ impl CurveFitApp {
6979
r2: result.r2,
7080
max_abs_error: result.max_abs_error,
7181
});
72-
self.residual_plot_points = result
73-
.residuals
74-
.iter()
75-
.map(|point| PlotPoint::new(point[0], point[1]))
76-
.collect();
82+
self.residual_plot_points = Self::plot_points_from_pairs(result.residuals.iter().copied());
7783
}
7884

7985
#[cfg(not(target_arch = "wasm32"))]
@@ -124,18 +130,13 @@ impl CurveFitApp {
124130
}
125131
self.iteration_diagnostics
126132
.append_spline(iteration, metrics, &knot_y);
127-
self.upsert_spline_replay_frame(
128-
iteration,
129-
curve
130-
.into_iter()
131-
.map(|point| PlotPoint::new(point[0], point[1]))
132-
.collect(),
133-
);
133+
self.upsert_spline_replay_frame(iteration, Self::plot_points_from_pairs(curve));
134134
self.status = Some(StatusMessage::FittingInProgress);
135135
}
136136
Ok(FitWorkerMessage::Stopped) => {
137137
self.fit_in_progress = false;
138138
self.active_fit_points = None;
139+
self.finalize_replay_after_fit_stopped();
139140
if !self.discard_fit_worker_updates || self.status_is_fitting() {
140141
self.status = Some(StatusMessage::FitStopped);
141142
}
@@ -162,7 +163,7 @@ impl CurveFitApp {
162163
result.iterations,
163164
result.params.clone(),
164165
);
165-
self.start_replay_from_beginning();
166+
self.finalize_replay_after_fit_completion();
166167
self.fit_result = Some(result);
167168
self.status = Some(StatusMessage::FitCompleted);
168169
} else if self.status_is_fitting() {
@@ -176,11 +177,8 @@ impl CurveFitApp {
176177
self.fit_in_progress = false;
177178
if !self.discard_fit_worker_updates {
178179
let knot_y = result.knots.iter().map(|knot| knot[1]).collect::<Vec<_>>();
179-
let spline_plot_curve = result
180-
.curve
181-
.iter()
182-
.map(|point| PlotPoint::new(point[0], point[1]))
183-
.collect();
180+
let spline_plot_curve =
181+
Self::plot_points_from_pairs(result.curve.iter().copied());
184182
self.update_spline_result_metrics(&result);
185183
let metrics = result.iteration_metrics_snapshot(self.fit_loss_metric);
186184
self.iteration_diagnostics.append_spline(
@@ -189,7 +187,7 @@ impl CurveFitApp {
189187
&knot_y,
190188
);
191189
self.upsert_spline_replay_frame(result.iterations, spline_plot_curve);
192-
self.start_replay_from_beginning();
190+
self.finalize_replay_after_fit_completion();
193191
self.spline_result = Some(result);
194192
self.status = Some(StatusMessage::FitCompleted);
195193
} else if self.status_is_fitting() {
@@ -286,7 +284,7 @@ impl CurveFitApp {
286284
);
287285
}
288286
self.upsert_parametric_replay_frame(result.iterations, result.params.clone());
289-
self.start_replay_from_beginning();
287+
self.finalize_replay_after_fit_completion();
290288
self.fit_result = Some(result);
291289
self.status = Some(StatusMessage::FitCompleted);
292290
self.active_fit_points = None;
@@ -295,6 +293,7 @@ impl CurveFitApp {
295293
}
296294
WasmRunnerStep::Parametric(Ok(IncrementalFitStep::Cancelled)) => {
297295
self.fit_in_progress = false;
296+
self.finalize_replay_after_fit_stopped();
298297
self.status = Some(StatusMessage::FitStopped);
299298
self.active_fit_points = None;
300299
keep_runner = false;
@@ -316,29 +315,20 @@ impl CurveFitApp {
316315
})) => {
317316
self.iteration_diagnostics
318317
.append_spline(iteration, metrics, &knot_y);
319-
self.upsert_spline_replay_frame(
320-
iteration,
321-
curve
322-
.into_iter()
323-
.map(|point| PlotPoint::new(point[0], point[1]))
324-
.collect(),
325-
);
318+
self.upsert_spline_replay_frame(iteration, Self::plot_points_from_pairs(curve));
326319
self.status = Some(StatusMessage::FittingInProgress);
327320
}
328321
WasmRunnerStep::Spline(Ok(IncrementalSplineFitStep::Finished(result))) => {
329322
self.fit_in_progress = false;
330323
let knot_y = result.knots.iter().map(|knot| knot[1]).collect::<Vec<_>>();
331-
let spline_plot_curve = result
332-
.curve
333-
.iter()
334-
.map(|point| PlotPoint::new(point[0], point[1]))
335-
.collect();
324+
let spline_plot_curve =
325+
Self::plot_points_from_pairs(result.curve.iter().copied());
336326
self.update_spline_result_metrics(&result);
337327
let metrics = result.iteration_metrics_snapshot(self.fit_loss_metric);
338328
self.iteration_diagnostics
339329
.append_spline(result.iterations, metrics, &knot_y);
340330
self.upsert_spline_replay_frame(result.iterations, spline_plot_curve);
341-
self.start_replay_from_beginning();
331+
self.finalize_replay_after_fit_completion();
342332
self.spline_result = Some(result);
343333
self.status = Some(StatusMessage::FitCompleted);
344334
self.active_fit_points = None;
@@ -347,6 +337,7 @@ impl CurveFitApp {
347337
}
348338
WasmRunnerStep::Spline(Ok(IncrementalSplineFitStep::Cancelled)) => {
349339
self.fit_in_progress = false;
340+
self.finalize_replay_after_fit_stopped();
350341
self.status = Some(StatusMessage::FitStopped);
351342
self.active_fit_points = None;
352343
keep_runner = false;
@@ -587,6 +578,19 @@ impl CurveFitApp {
587578
}
588579
};
589580
self.clear_fit_outputs();
581+
let initial_curve = match build_spline_initial_curve_from_knot_y(
582+
&points,
583+
spline_family,
584+
spline_config,
585+
initial_knot_y.as_slice(),
586+
) {
587+
Ok(curve) => curve,
588+
Err(error) => {
589+
self.status = Some(StatusMessage::Error(error.to_string()));
590+
return;
591+
}
592+
};
593+
self.upsert_spline_replay_frame(0, Self::plot_points_from_pairs(initial_curve));
590594
self.status = Some(StatusMessage::FittingInProgress);
591595

592596
#[cfg(not(target_arch = "wasm32"))]
@@ -649,8 +653,6 @@ impl CurveFitApp {
649653
self.active_fit_points = Some(points.clone());
650654
self.iteration_diagnostics
651655
.initialize(&points, &initial_params, loss_metric);
652-
self.fit_preview_params = Some(initial_params.clone());
653-
self.fit_preview_iteration = Some(0);
654656
self.upsert_parametric_replay_frame(0, initial_params.clone());
655657
self.status = Some(StatusMessage::FittingInProgress);
656658

0 commit comments

Comments
 (0)