use kinavis::error::Result;
use kinavis::relative_motion::Contact;
use kinavis::sailings::rhumb_destination;
use kinavis_kernel::angle::TrueCourse;
use kinavis_kernel::event::TargetId;
use kinavis_kernel::position::Position;
use kinavis_kernel::snapshot::GroundTrack;
use kinavis_kernel::time::{Instant, Utc};
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TargetObservation {
target: TargetId,
position: Position,
at: Instant<Utc>,
ground_track: Option<GroundTrack>,
heading: Option<TrueCourse>,
}
impl TargetObservation {
#[must_use]
pub const fn new(target: TargetId, position: Position, at: Instant<Utc>) -> Self {
Self {
target,
position,
at,
ground_track: None,
heading: None,
}
}
pub fn from_contact(
target: TargetId,
own: Position,
contact: Contact,
at: Instant<Utc>,
) -> Result<Self> {
let position = rhumb_destination(
own,
TrueCourse::new(contact.bearing.degrees())?,
contact.range,
)?;
Ok(Self::new(target, position, at))
}
#[must_use]
pub const fn with_ground_track(mut self, ground_track: GroundTrack) -> Self {
self.ground_track = Some(ground_track);
self
}
#[must_use]
pub const fn with_heading(mut self, heading: TrueCourse) -> Self {
self.heading = Some(heading);
self
}
#[must_use]
pub const fn target(&self) -> TargetId {
self.target
}
#[must_use]
pub const fn position(&self) -> Position {
self.position
}
#[must_use]
pub const fn at(&self) -> Instant<Utc> {
self.at
}
#[must_use]
pub const fn ground_track(&self) -> Option<GroundTrack> {
self.ground_track
}
#[must_use]
pub const fn heading(&self) -> Option<TrueCourse> {
self.heading
}
}