///|
fn copy_object(
obj : DataObject,
start : Int32,
end : Int32,
) -> DataObject raise TdmsError {
demand(
start >= 0 && end >= start && end <= obj.values.length(),
"sample selection outside channel",
)
{
path: { parts: obj.path.parts.map(x => x), },
kind: obj.kind,
properties: obj.properties.map(x => x),
values: Array::makei(end - start, i => obj.values[start + i]),
}
}
///|
pub fn Document::select(
self : Document,
channels : Array[ObjectPath],
start~ : Int32 = 0,
end? : Int32,
limits~ : Limits = Limits::default(),
) -> Document raise TdmsError {
self.validate(limits)
demand(!channels.is_empty(), "no selected channels")
let selected : Map[String, Bool] = Map([])
let groups : Map[String, Bool] = Map([])
for path in channels {
demand(path.parts.length() == 2, "selection requires channel paths")
let key = path.text()
demand(!selected.contains(key), "duplicate selected channel")
demand(self.find(path) is Some(_), "selected channel does not exist")
selected[key] = true
groups[path.parts[0]] = true
}
let result = Document::new()
for obj in self.objects {
if obj.path.parts.length() == 2 {
if !selected.contains(obj.path.text()) {
continue
}
let stop = end.unwrap_or(obj.values.length())
let copy = copy_object(obj, start, stop)
if start > 0 && obj.property("wf_increment") is Some(increment) {
let dt = increment.as_double()
demand(finite(dt) && dt > 0.0, "invalid waveform increment")
let offset = match obj.property("wf_start_offset") {
Some(v) => v.as_double()
None => 0.0
}
let shifted = offset + start.to_double() * dt
demand(finite(shifted), "waveform offset overflow")
set_property(copy, {
name: "wf_start_offset",
kind: F64,
value: Real(shifted),
})
}
result.objects.push(copy)
} else if obj.path.parts.is_empty() || groups.contains(obj.path.parts[0]) {
result.objects.push(copy_object(obj, 0, 0))
}
}
result.validate(limits)
result
}
///|
pub fn Document::channel_paths(self : Document) -> Array[ObjectPath] {
self.objects
.filter(o => o.path.parts.length() == 2)
.map(o => { parts: o.path.parts.map(x => x), })
}
///|
fn finite(x : Double) -> Bool {
!x.is_nan() && !x.is_inf()
}