cumulus3d_cli/lib.rs
1/*
2 * lib.rs
3 *
4 * Copyright (c) 2026 ParkSangWoo
5 *
6 * Author(s):
7 *
8 * ParkSangWoo <dev.parksangwoo@gmail.com>
9 *
10 *
11 * This file is part of cumulus3d.
12 *
13 * Licensed under the Apache License, Version 2.0 (the "License");
14 * you may not use this file except in compliance with the License.
15 * You may obtain a copy of the License at
16 *
17 * http://www.apache.org/licenses/LICENSE-2.0
18 *
19 * Unless required by applicable law or agreed to in writing, software
20 * distributed under the License is distributed on an "AS IS" BASIS,
21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 * See the License for the specific language governing permissions and
23 * limitations under the License.
24 *
25 * SPDX-License-Identifier: Apache-2.0
26 */
27
28//! Library part of the cumulus3d executable: the incremental stream pipeline and the stage-by-stage compatible subcommands ([`interop`]).
29//!
30//! - [`session`]: the state value [`session::Session`] and the reducer functions [`session::step`] / [`session::poll`] /
31//! [`session::command`] / [`session::finish`].
32//! - [`pipeline`]: [`pipeline::Pipeline`], which wraps the reducer and provides hooks, queue policy, panic isolation and subscription
33//! channels.
34//! - [`events`]: per-stage results [`events::Event`] and commands [`events::Command`].
35//! - [`sinks`]: default hooks that produce the file output of `cumulus3d stream` (timeline.txt, run.log, PLY, snapshots).
36//! - [`stream`]: input folder -> session -> pipeline assembly ([`stream::run_stream`]).
37//! - [`compose`]: a persistent node for live input. Declare the current input state ([`compose::FrameState`]) and it is compared with the
38//! accepted record to process incrementally.
39//! - [`declare`]: the declarative builder layer. It only records a plan ([`declare::Plan`]); `build` validates it and `run` executes it
40//! in one go
41//! ([`declare::Recon`]). Plans are saved and read as TOML (`cumulus3d run plan.toml`).
42//!
43//! # Usage example
44//!
45//! Feed an image folder (`images/camF|camR|camL/*.jpg`, `gps_ref.txt`) position by position for incremental reconstruction,
46//! and use the default output hook to produce the same files as `cumulus3d stream`.
47//!
48//! ```no_run
49//! use cumulus3d_cli::events::{Event, EventKind};
50//! use cumulus3d_cli::pipeline::Pipeline;
51//! use cumulus3d_cli::session::{Input, Session, SessionConfig};
52//! use cumulus3d_cli::sinks::{self, SinkOptions};
53//! use cumulus3d_cli::stream::{frame_set, Layout};
54//! use cumulus3d_core::io::read_gps_file;
55//! use std::path::Path;
56//!
57//! fn main() -> Result<(), String> {
58//! let src = Path::new("data");
59//! let layout = Layout::discover(src, 3)?;
60//! let mut cfg = SessionConfig::new(src.join("images"));
61//! cfg.gps = read_gps_file(src.join("gps_ref.txt")).map_err(|e| e.to_string())?;
62//! cfg.total_positions = Some(layout.frames.len());
63//!
64//! let pipeline = Pipeline::new(Session::new(cfg)).on(EventKind::ZonePreview, |e: &Event| {
65//! if let Event::ZonePreview { range, cloud, .. } = e {
66//! println!("preview zone {}: {} points", range.zone, cloud.len());
67//! }
68//! });
69//! let mut pipeline = sinks::attach(pipeline, Path::new("out"), &SinkOptions::default()).map_err(|e| e.to_string())?;
70//! for p in 0..layout.frames.len() {
71//! pipeline.push(Input::Frames(frame_set(&layout, p)));
72//! }
73//! let (_session, summary) = pipeline.finish();
74//! println!("{} events", summary.events);
75//! Ok(())
76//! }
77//! ```
78//!
79//! Declarative (record a plan -> validate -> run):
80//!
81//! ```no_run
82//! use cumulus3d_cli::declare::{Dense, Recon, Sinks};
83//!
84//! let recon = Recon::declare()
85//! .input("data")
86//! .preset("aerial-formation")
87//! .zones(12, 2)
88//! .dense(Dense::profile("fast").fusion_min_views(3))
89//! .sinks(Sinks::default_files("out"))
90//! .seed(7)
91//! .build()
92//! .unwrap_or_else(|e| panic!("{e}"));
93//! let summary = recon.run().unwrap();
94//! println!("{} events", summary.events);
95//! ```
96//!
97//! Functional use that only passes state values around, without hooks:
98//!
99//! ```no_run
100//! use cumulus3d_cli::session::{finish, step, FrameSet, Session, SessionConfig};
101//!
102//! let s0 = Session::new(SessionConfig::new("data/images"));
103//! let frames = FrameSet::new([("camF", "camF/camF_0000.jpg"), ("camR", "camR/camR_0000.jpg")]);
104//! let (s1, events) = step(&s0, frames);
105//! for e in &events {
106//! if let Some(t) = e.timeline_text() {
107//! println!("{t}");
108//! }
109//! }
110//! let (_done, _summary_events) = finish(&s1);
111//! ```
112
113#![warn(missing_docs)]
114
115pub mod blocks;
116pub mod compose;
117pub mod declare;
118pub mod densewrap;
119pub mod events;
120pub mod fusion_variants;
121pub mod interop;
122pub mod intrinsics;
123pub mod pipeline;
124pub mod post;
125pub mod session;
126pub mod sinks;
127pub mod stream;
128pub mod util;