use crate::annotation::LabelObject;
use crate::{
Annotation, AnnotationHandle, CoreError, EntityKind, EntityRef, Measurement, MeasurementHandle,
Scene,
};
#[cfg(test)]
#[path = "labels_tests.rs"]
mod tests;
impl Scene {
pub fn add_validation_marker(
&mut self,
marker: crate::ValidationMarker,
) -> Result<AnnotationHandle, CoreError> {
let annotation = Annotation::marker(marker.owner, marker.anchor, marker.style)?;
self.add_annotation(annotation)
}
pub fn add_annotation(
&mut self,
annotation: Annotation,
) -> Result<AnnotationHandle, CoreError> {
self.validate_annotation(&annotation)?;
self.label_revision = self.label_revision.wrapping_add(1);
Ok(AnnotationHandle(
self.labels.insert(LabelObject::Annotation(annotation)),
))
}
pub fn add_measurement(
&mut self,
measurement: Measurement,
) -> Result<MeasurementHandle, CoreError> {
self.validate_measurement(&measurement)?;
self.label_revision = self.label_revision.wrapping_add(1);
Ok(MeasurementHandle(
self.labels.insert(LabelObject::Measurement(measurement)),
))
}
#[must_use]
pub fn annotation(&self, handle: AnnotationHandle) -> Option<&Annotation> {
match self.labels.get(handle.0)? {
LabelObject::Annotation(value) => Some(value),
LabelObject::Measurement(_) => None,
}
}
#[must_use]
pub fn measurement(&self, handle: MeasurementHandle) -> Option<&Measurement> {
match self.labels.get(handle.0)? {
LabelObject::Measurement(value) => Some(value),
LabelObject::Annotation(_) => None,
}
}
pub fn annotation_mut(&mut self, handle: AnnotationHandle) -> Option<&mut Annotation> {
let object = self.labels.get_mut(handle.0)?;
let LabelObject::Annotation(annotation) = object else {
return None;
};
self.label_revision = self.label_revision.wrapping_add(1);
Some(annotation)
}
pub fn measurement_mut(&mut self, handle: MeasurementHandle) -> Option<&mut Measurement> {
let object = self.labels.get_mut(handle.0)?;
let LabelObject::Measurement(measurement) = object else {
return None;
};
self.label_revision = self.label_revision.wrapping_add(1);
Some(measurement)
}
pub fn remove_annotation(&mut self, handle: AnnotationHandle) -> Option<Annotation> {
if !matches!(self.labels.get(handle.0), Some(LabelObject::Annotation(_))) {
return None;
}
let LabelObject::Annotation(annotation) = self.labels.remove(handle.0)? else {
return None;
};
self.label_revision = self.label_revision.wrapping_add(1);
Some(annotation)
}
pub fn remove_measurement(&mut self, handle: MeasurementHandle) -> Option<Measurement> {
if !matches!(self.labels.get(handle.0), Some(LabelObject::Measurement(_))) {
return None;
}
let LabelObject::Measurement(measurement) = self.labels.remove(handle.0)? else {
return None;
};
self.label_revision = self.label_revision.wrapping_add(1);
Some(measurement)
}
pub fn annotations(&self) -> impl Iterator<Item = (AnnotationHandle, &Annotation)> + '_ {
self.labels
.iter()
.filter_map(|(handle, object)| match object {
LabelObject::Annotation(annotation) => Some((AnnotationHandle(handle), annotation)),
LabelObject::Measurement(_) => None,
})
}
pub fn measurements(&self) -> impl Iterator<Item = (MeasurementHandle, &Measurement)> + '_ {
self.labels
.iter()
.filter_map(|(handle, object)| match object {
LabelObject::Measurement(measurement) => {
Some((MeasurementHandle(handle), measurement))
}
LabelObject::Annotation(_) => None,
})
}
#[must_use]
pub fn annotation_for_entity(
&self,
entity: EntityRef,
) -> Option<(AnnotationHandle, &Annotation)> {
if entity.kind != EntityKind::Label {
return None;
}
let (handle, object) = self.labels.get_index(entity.index)?;
let LabelObject::Annotation(annotation) = object else {
return None;
};
(annotation.owner() == entity.structure).then_some((AnnotationHandle(handle), annotation))
}
#[must_use]
pub fn measurement_for_entity(
&self,
entity: EntityRef,
) -> Option<(MeasurementHandle, &Measurement)> {
if entity.kind != EntityKind::Label {
return None;
}
let (handle, object) = self.labels.get_index(entity.index)?;
let LabelObject::Measurement(measurement) = object else {
return None;
};
(measurement.owner() == entity.structure)
.then_some((MeasurementHandle(handle), measurement))
}
#[must_use]
pub const fn label_revision(&self) -> u64 {
self.label_revision
}
#[must_use]
pub fn annotation_row(handle: AnnotationHandle) -> u32 {
handle.row()
}
#[must_use]
pub fn measurement_row(handle: MeasurementHandle) -> u32 {
handle.row()
}
fn validate_annotation(&self, annotation: &Annotation) -> Result<(), CoreError> {
if self.structure(annotation.owner()).is_none()
|| annotation
.anchor()
.and_then(crate::AnnotationAnchor::source_entity)
.is_some_and(|entity| self.structure(entity.structure).is_none())
|| annotation
.region_selection()
.is_some_and(|selection| self.selection(selection).is_none())
{
return Err(CoreError::StaleHandle);
}
Ok(())
}
fn validate_measurement(&self, measurement: &Measurement) -> Result<(), CoreError> {
if self.structure(measurement.owner()).is_none()
|| measurement.anchors().iter().any(|anchor| {
anchor
.source_entity()
.is_some_and(|entity| self.structure(entity.structure).is_none())
})
{
return Err(CoreError::StaleHandle);
}
Ok(())
}
}