use calib_targets_aruco::builtins::builtin_dictionary;
use calib_targets_print::{
CharucoTargetSpec, ChessboardTargetSpec, MarkerBoardTargetSpec, PrintableTargetDocument,
PuzzleBoardTargetSpec, TargetSpec,
};
use clap::{Args, Subcommand};
use std::{fs, path::PathBuf};
use super::args::{
build_page_spec, build_render_options, parse_circles, MarkerLayoutArg, PageArgs, RenderArgs,
};
use super::error::CliError;
#[derive(Subcommand, Debug)]
pub enum InitCommand {
Chessboard(ChessboardInitArgs),
Charuco(CharucoInitArgs),
Puzzleboard(PuzzleboardInitArgs),
MarkerBoard(MarkerBoardInitArgs),
}
#[derive(Args, Debug)]
pub struct ChessboardInitArgs {
#[arg(long)]
pub out: PathBuf,
#[arg(long)]
pub inner_rows: u32,
#[arg(long)]
pub inner_cols: u32,
#[arg(long)]
pub square_size_mm: f64,
#[command(flatten)]
pub page: PageArgs,
#[command(flatten)]
pub render: RenderArgs,
}
#[derive(Args, Debug)]
pub struct CharucoInitArgs {
#[arg(long)]
pub out: PathBuf,
#[arg(long)]
pub rows: u32,
#[arg(long)]
pub cols: u32,
#[arg(long)]
pub square_size_mm: f64,
#[arg(long)]
pub marker_size_rel: f64,
#[arg(long)]
pub dictionary: String,
#[arg(long, value_enum, default_value_t = MarkerLayoutArg::OpencvCharuco)]
pub marker_layout: MarkerLayoutArg,
#[arg(long, default_value_t = 1)]
pub border_bits: usize,
#[command(flatten)]
pub page: PageArgs,
#[command(flatten)]
pub render: RenderArgs,
}
#[derive(Args, Debug)]
pub struct PuzzleboardInitArgs {
#[arg(long)]
pub out: PathBuf,
#[arg(long)]
pub rows: u32,
#[arg(long)]
pub cols: u32,
#[arg(long)]
pub square_size_mm: f64,
#[arg(long, default_value_t = 0)]
pub origin_row: u32,
#[arg(long, default_value_t = 0)]
pub origin_col: u32,
#[arg(long)]
pub dot_diameter_rel: Option<f64>,
#[command(flatten)]
pub page: PageArgs,
#[command(flatten)]
pub render: RenderArgs,
}
#[derive(Args, Debug)]
pub struct MarkerBoardInitArgs {
#[arg(long)]
pub out: PathBuf,
#[arg(long)]
pub inner_rows: u32,
#[arg(long)]
pub inner_cols: u32,
#[arg(long)]
pub square_size_mm: f64,
#[arg(long, default_value_t = 0.5)]
pub circle_diameter_rel: f64,
#[arg(long = "circle", value_name = "I,J,POLARITY")]
pub circles: Vec<String>,
#[command(flatten)]
pub page: PageArgs,
#[command(flatten)]
pub render: RenderArgs,
}
pub fn run(cmd: InitCommand) -> Result<(), CliError> {
match cmd {
InitCommand::Chessboard(args) => run_chessboard(args),
InitCommand::Charuco(args) => run_charuco(args),
InitCommand::Puzzleboard(args) => run_puzzleboard(args),
InitCommand::MarkerBoard(args) => run_marker_board(args),
}
}
fn run_chessboard(args: ChessboardInitArgs) -> Result<(), CliError> {
let doc = PrintableTargetDocument::new(TargetSpec::Chessboard(ChessboardTargetSpec::new(
args.inner_rows,
args.inner_cols,
args.square_size_mm,
)))
.with_page(build_page_spec(&args.page)?)
.with_render(build_render_options(&args.render));
write_document_json(&doc, args.out)
}
fn run_charuco(args: CharucoInitArgs) -> Result<(), CliError> {
let dictionary = builtin_dictionary(&args.dictionary)
.ok_or_else(|| CliError::UnknownDictionary(args.dictionary.clone()))?;
let marker_layout = match args.marker_layout {
MarkerLayoutArg::OpencvCharuco => calib_targets_charuco::MarkerLayout::OpenCvCharuco,
};
let target = CharucoTargetSpec::new(
args.rows,
args.cols,
args.square_size_mm,
args.marker_size_rel,
dictionary,
)
.with_marker_layout(marker_layout)
.with_border_bits(args.border_bits);
let doc = PrintableTargetDocument::new(TargetSpec::Charuco(target))
.with_page(build_page_spec(&args.page)?)
.with_render(build_render_options(&args.render));
write_document_json(&doc, args.out)
}
fn run_puzzleboard(args: PuzzleboardInitArgs) -> Result<(), CliError> {
let target = PuzzleBoardTargetSpec::new(args.rows, args.cols, args.square_size_mm)
.with_origin(args.origin_row, args.origin_col)
.with_dot_diameter_rel(args.dot_diameter_rel.unwrap_or(1.0 / 3.0));
let doc = PrintableTargetDocument::new(TargetSpec::PuzzleBoard(target))
.with_page(build_page_spec(&args.page)?)
.with_render(build_render_options(&args.render));
write_document_json(&doc, args.out)
}
fn run_marker_board(args: MarkerBoardInitArgs) -> Result<(), CliError> {
let circles = if args.circles.is_empty() {
MarkerBoardTargetSpec::default_circles(args.inner_rows, args.inner_cols)
} else {
parse_circles(&args.circles)?
};
let target = MarkerBoardTargetSpec::new(
args.inner_rows,
args.inner_cols,
args.square_size_mm,
circles,
)
.with_circle_diameter_rel(args.circle_diameter_rel);
let doc = PrintableTargetDocument::new(TargetSpec::MarkerBoard(target))
.with_page(build_page_spec(&args.page)?)
.with_render(build_render_options(&args.render));
write_document_json(&doc, args.out)
}
fn write_document_json(doc: &PrintableTargetDocument, out: PathBuf) -> Result<(), CliError> {
if let Some(parent) = out.parent() {
if !parent.as_os_str().is_empty() {
fs::create_dir_all(parent)?;
}
}
doc.write_json(&out)?;
println!("{}", out.display());
Ok(())
}