This commit is contained in:
Brandon Thomas committed 2026-11-03 09:04:45 -05:00
commit e175a272c7
3 files changed
+27 -3

No files matched your search

+7 -2
View File
@@ -246,13 +246,18 @@ fn status(s: &mut Session, p: &Value) -> Result<Value> {
out["deleted"] = json!(settings.deleted.len());
out["lensDistortionSolved"] = json!(settings.lens_distortion);
let solve = ct::solve(&params);
out["solved"] = json!(solve.is_some());
// The solver interpolates the frames it could not solve: only a solve of every frame is
// `solved` (what `camera.exportBlender` needs); one with gaps is `partial`.
let solved_frames = solve.as_ref().map_or(0, |sv| sv.frames.iter().filter(|c| c.solved).count());
let complete = solve.as_ref().is_some_and(|sv| solved_frames == sv.frames.len());
out["solved"] = json!(complete);
out["partial"] = json!(solve.is_some() && !complete);
if let Some(sv) = &solve {
let f = sv.focal();
out["methodUsed"] = json!(sv.method_used.label());
out["averageError"] = json!(sv.average_error);
out["points"] = json!(sv.points.len());
out["solvedFrames"] = json!(sv.frames.iter().filter(|c| c.solved).count());
out["solvedFrames"] = json!(solved_frames);
out["focalLength"] = json!(f);
out["horizontalAngleOfView"] = json!(sv.hfov(f));
out["groundPlane"] = json!(sv.ground.is_some());
+17
View File
@@ -238,6 +238,23 @@ fn blender_export_rejects_malformed_solves_without_panicking() {
}
}
/// A solve with unsolved (interpolated) frames is partial, not solved, so the status agrees with
/// the export, which refuses it.
#[test]
fn solve_status_reports_unsolved_frames_as_partial() {
let (mut s, lid, uid) = fixture(false);
let st = s.execute("camera.solveStatus", json!({"layer": lid.0})).unwrap();
assert_eq!((&st["solved"], &st["partial"], &st["solvedFrames"]), (&json!(true), &json!(false), &json!(3)), "{st}");
let mut solve =
ct::solve(&crate::camera_track::static_params(s.active_comp().unwrap().layer(lid).unwrap().props.find_group(uid).unwrap())).unwrap().as_ref().clone();
solve.frames[1].solved = false;
s.execute("prop.set", json!({"layer": lid.0, "path": "effects/#1/solve", "value": solve.to_json()})).unwrap();
s.camera_pending.clear();
let st = s.execute("camera.solveStatus", json!({"layer": lid.0})).unwrap();
assert_eq!((&st["solved"], &st["partial"], &st["solvedFrames"]), (&json!(false), &json!(true), &json!(2)), "{st}");
assert!(s.execute_checked("camera.exportBlender", json!({"layer": lid.0, "path": path("partial.py")})).is_err());
}
#[test]
fn blender_export_respects_script_write_permission() {
let (mut s, lid, _) = fixture(false);
+3 -1
View File
@@ -476,7 +476,9 @@ undistort?, wait?}`) apply
Effect ▸ Perspective ▸ 3D Camera Tracker (or reuse the layer's) and analyse it in the background:
"Analyzing in background (step 1 of 2)" tracks features, "Solving camera" solves.
`camera.analyze {layer?, effect?, wait?}` re-runs it, `camera.cancel` stops it without writing
anything. `camera.solveStatus` reports `progress`/`banner`, `analyzed`, `solved`, `methodUsed`,
anything. `camera.solveStatus` reports `progress`/`banner`, `analyzed`, `solved` (every frame
solved), `partial` with `solvedFrames` of `frames` (the camera is interpolated on the other frames,
and `camera.exportBlender` refuses such a solve), `methodUsed`,
`averageError` (pixels), `focalLength`, `horizontalAngleOfView`, the current frame's `camera`
(position, orientation, zoom), `groundPlane` and the solved `lensDistortion` (`k1`, `k2`, normalised by
half the frame diagonal) when Solve Lens Distortion (`effects/#1/advanced/lensDistortion`, also on