///|
/// Build a deterministic measurement plan from features and devices.
pub fn plan(
part_id~ : String,
features : Array[Feature],
devices : Array[Device],
) -> MeasurementPlan {
let steps = []
let warnings = []
let mut capable = true
for feature in features {
match choose_device(feature~, devices~) {
None => {
warnings.push("no device for " + feature.id)
capable = false
}
Some(candidate) => {
let device = candidate.device
let count = repeat_count(feature, device)
let strategy = if feature.kind == Cylinder {
Scan(count=if count < 5 { 5 } else { count })
} else if count == 1 {
SinglePoint
} else {
RepeatedPoint(count~)
}
let uncertainty = estimate_uncertainty(strategy, device)
if !capability_ok(feature, uncertainty) {
warnings.push("device capability is insufficient for " + feature.id)
capable = false
}
steps.push({
feature_id: feature.id,
device_id: device.id,
strategy,
direction: if feature.datum {
"datum-aligned"
} else {
"normal"
},
uncertainty,
})
}
}
}
let coverage = if features.length() == 0 {
1.0
} else {
steps.length().to_double() / features.length().to_double()
}
{
part_id,
steps,
summary: { coverage, capability: capable, steps: steps.length(), warnings },
}
}
///|
/// Find a matching observation and classify it.
pub fn verdict(
plan : MeasurementPlan,
feature : Feature,
observations : Array[Observation],
) -> Verdict {
ignore(plan)
let mut observation = None
for item in observations {
if item.feature_id == feature.id && observation is None {
observation = Some(item)
}
}
classify(feature, observation)
}