Tesseract 0.28.4
Loading...
Searching...
No Matches
Tesseract PropertyTree OneOf Example

Overview

This example demonstrates the oneOf feature of Tesseract's PropertyTree system, which enables polymorphic configuration structures. A oneOf schema allows exactly one of multiple configuration branches to be active at a time.

OneOf is useful for:

  • Union-like types (choose one of several variants)
  • Mutually exclusive configurations
  • Plugin selection (use either plugin A or plugin B)
  • Shape definitions (circle OR rectangle)
  • Protocol selection (USB OR Ethernet with type-specific fields)

Key Concepts

  • Branches: Named child schemas, each defining a configuration variant
  • Branch Selection: Automatic selection based on which required fields are present
  • Flattening: After selection, the schema becomes the selected branch
  • One Mandatory Match: Exactly one branch must match, no more, no less
  • Validation: Constraints validate only in the selected branch

OneOf Workflow

The example demonstrates:

  1. Define a OneOf Schema with multiple branches
  2. Load Configuration specifying one branch
  3. Merge Config into Schema - branch selection occurs here
  4. Validate - checks constraints for selected branch only
  5. Extract Results from the flattened schema

Example Code

// clang-format off
auto shape_schema = PropertyTreeBuilder()
.attribute(TYPE, ONEOF)
.container("circle")
.doubleNum("radius").required()
.doc("Circle radius").minimum(0.0).label("Radius").done()
.done()
.container("rectangle")
.doubleNum("width").required()
.doc("Rectangle width").minimum(0.0).label("Width").done()
.doubleNum("height").required()
.doc("Rectangle height").minimum(0.0).label("Height").done()
.done()
.build();
// clang-format on

The ONEOF type defines a schema where exactly one child must be selected. Child nodes are branches.

// Example 1a: Circle configuration
{
std::cout << "\n Circle config:\n";
YAML::Node circle_config;
circle_config["radius"] = 5.5;
auto schema_copy = shape_schema;
try
{
schema_copy.mergeConfig(circle_config);
auto errors = schema_copy.validate();
if (errors.empty())
{
std::cout << " ✓ Selected circle branch\n";
std::cout << " Radius: " << schema_copy.at("radius").as<double>() << "\n";
}
else
{
std::cout << " ✗ Validation errors:\n";
for (const auto& e : errors)
std::cout << " - " << e << "\n";
}
}
catch (const std::exception& ex)
{
std::cout << " ✗ Merge failed: " << ex.what() << "\n";
}
}

During mergeConfig(), PropertyTree examines the config and selects the branch whose required fields match the provided keys. If multiple branches match or none match, an exception is thrown.

Running the Example

Execute the example:

./tesseract_common_oneof_property_tree_example

The example demonstrates successful branch selection, error cases, and how validation applies only to the selected branch.