---
title: "OTB Wrapper in link2GI"
author: "Chris Reudenbach"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{OTB Wrapper in link2GI}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```
knitr::opts_chunk$set(
collapse = TRUE,
comment  = "#>",
eval     = FALSE
)
```

The Orfeo ToolBox (OTB) provides a collection of command-line applications for remote sensing and image processing. `link2GI` wraps these applications in R with a focus on **reproducibility, transparency, and robustness across OTB versions**.

`link2GI` supports two layers:

* a **legacy** wrapper layer (kept for backward compatibility)
* a **new Self-describing** API (recommended) that derives parameter metadata from OTB’s own `-help` output

# Two APIs: legacy vs. Self-describing

## Legacy API (`parseOTBFunction()` / `runOTB()`)

The legacy layer builds a modifiable R list by parsing the output of:

```
otbcli <algorithm> -help
```

Characteristics:

* permissive and convenient
* minimal upfront constraints
* useful for older scripts

Limitations:

* required parameters and defaults are inferred heuristically
* sensitive to OTB help formatting changes
* less suitable for strict, version-stable workflows

## Self-describing API (recommended)

The Self-describing API treats the OTB CLI help output as the **single source of truth** for parameters and their status (mandatory vs. optional). It supports a strict “write-to-disk” workflow and avoids implicit assumptions.

Core functions:

* `otb_capabilities()`: retrieve CLI help text (source of truth)
* `otb_args_spec()`: normalized parameter spec table parsed from `-help`
* `otb_build_cmd()`: create a `runOTB()`-compatible command template (valid keys only)
* `otb_set_out()`: set file-based outputs safely (including `[pixel]` outputs)

# Minimal workflow (Self-describing)

```{r eval=FALSE}
library(link2GI)

otb <- link2GI::linkOTB(searchLocation = "~/apps/otb911/")

cmd <- link2GI::otb_build_cmd(
"DimensionalityReduction",
otb,
include_optional = "defaults",
require_output   = TRUE
)

cmd[["in"]]     <- "in.tif"
cmd[["method"]] <- "pca"
cmd[["nbcomp"]] <- "3"

cmd <- link2GI::otb_set_out(cmd, otb, key = "out", path = "out.tif")
str(cmd)
```


# Typical transparent workflow (Self-describing)

This example demonstrates a complete workflow:

1. link an installed OTB
2. read and display the raw `-help` output (source of truth)
3. inspect the parsed parameter table (`spec`)
4. build a command template from valid keys
5. set input and explicit output
6. run via `runOTB()` and verify the output file

NOTE (CRAN/vignette hygiene): this vignette writes outputs into `tempdir()`.

## Example: `DimensionalityReduction` (PCA)

This example avoids guessing parameter names. The only manual step is choosing the correct
parameter key for “number of components” by reading the `spec` table printed from your local

```{r eval=FALSE}
# OTB build (for OTB 9.1.1 this is `nbcomp`).


library(link2GI)
library(terra)

# 0) Link OTB

otb <- link2GI::linkOTB(searchLocation="~/apps/otb911/")

# 1) Choose algorithm

algo <- "DimensionalityReduction"

# 2) Read the OTB help text (source of truth)

caps <- link2GI::otb_capabilities(algo = algo, gili = otb, include_param_help = FALSE)
cat(paste(head(caps$text, 60), collapse = "\n"), "\n")

# 3) Parsed parameter table

spec <- link2GI::otb_args_spec(algo, otb)
print(spec[, c("key", "class", "mandatory", "default")], row.names = FALSE)

# 4) Build a template containing only valid keys (mandatory + defaults)

cmd <- link2GI::otb_build_cmd(
algo,
otb,
include_optional = "defaults",
require_output   = TRUE
)

# 5) Identify component-count key by inspecting the spec table (no heuristics)

pca_related <- spec[grepl("^method\.pca\.|^nbcomp$|outdim|comp", spec$key), ]
print(pca_related[, c("key", "mandatory", "default", "desc")], row.names = FALSE)

# 6) Set PCA method + number of components (OTB 9.1.1: nbcomp)

cmd[["method"]] <- "pca"
cmd[["nbcomp"]] <- "3"

# 7) Input + output (explicit on-disk paths)

infile  <- system.file("ex/elev.tif", package = "terra")
out_dir <- file.path(tempdir(), "link2gi_otb_vignette")
dir.create(out_dir, recursive = TRUE, showWarnings = FALSE)

cmd[["in"]]  <- infile
cmd[["out"]] <- file.path(out_dir, "pca.tif")

# Show the exact CLI that would be executed

cat(link2GI::runOTB(cmd, otb, retCommand = TRUE), "\n")

# Run (writes to disk)

res <- link2GI::runOTB(cmd, otb, quiet = FALSE)

# Verify output exists

file.exists(cmd[["out"]])
```


# Legacy workflow (supported but not recommended)

The legacy workflow builds a command list by parsing `-help` output and then executes it.
Because the legacy parser may expose parameter names that vary between OTB versions/apps,
the safe pattern is:

1. parse the command list
2. inspect `names(cmd)` / `cmd$help` (if present)
3. set inputs/outputs and required parameters explicitly
4. run

```{r eval=FALSE}
library(link2GI)

otb <- link2GI::linkOTB()

algo <- "EdgeExtraction"
cmd  <- link2GI::parseOTBFunction(algo = algo, gili = otb)

# inspect keys (legacy API may expose app-specific names)

names(cmd)

# then set required parameters according to the returned structure:

# cmd[["<input_key>"]]  <- "in.tif"

# cmd[["<output_key>"]] <- "out.tif"

# cmd[["<other_key>"]]  <- "value"

# finally execute

# link2GI::runOTB(cmd, gili = otb, quiet = FALSE)
```


# What changed (Self-describing)

The new Self-describing API removes fragile heuristics and centralizes metadata on:

* OTB’s own `Parameters:` block emitted by `<Algo> -help`

Consequences:

* `otb_capabilities()` / `otb_args_spec()` become the source of truth
* `otb_build_cmd()` prevents invalid keys (reduces “parameter does not exist” failures)
* `runOTB()` on Linux/macOS uses the OTB launcher plus explicit environment, matching the help/spec stack
* Windows isolation is handled by `runOTB_isolated()` via `otbenv.ps1/.bat`

# Compatibility and deprecations

## Compatibility

* Existing scripts using `parseOTBFunction()` plus `runOTB()` should continue to work (best-effort).
* The Self-describing API is stable as long as OTB provides a parseable `Parameters:` section.

## Deprecations (explicit list)

* `parseOTBFunction()` is legacy (supported, but not recommended for new code).
* `parseOTBAlgorithms()` is legacy (if present in your build; prefer `otb_capabilities()`).

For new projects, prefer:

`otb_capabilities()` + `otb_args_spec()` + `otb_build_cmd()` + `otb_set_out()` then `runOTB()`.
