1use super::*;
2
3#[derive(Clone, Debug, PartialEq)]
5pub struct PackagedArtifactFitEnvelopeSummary {
6 pub sample_count: usize,
8 pub expected_sample_count: usize,
10 pub body_count: usize,
12 pub mean_longitude_delta_degrees: f64,
14 pub mean_latitude_delta_degrees: f64,
16 pub mean_distance_delta_au: f64,
18 pub max_longitude_delta_degrees: f64,
20 pub max_latitude_delta_degrees: f64,
22 pub max_distance_delta_au: f64,
24}
25
26#[derive(Clone, Debug, Eq, PartialEq)]
28pub struct PackagedArtifactFitThresholdViolation {
29 pub field: &'static str,
31 pub measured_bits: u64,
33 pub threshold_bits: u64,
35 pub overage_bits: u64,
37}
38
39impl PackagedArtifactFitThresholdViolation {
40 fn summary_line(&self) -> String {
41 format!(
42 "`{}` measured={:.12}, threshold={:.12}, overage={:+.12}",
43 self.field,
44 f64::from_bits(self.measured_bits),
45 f64::from_bits(self.threshold_bits),
46 f64::from_bits(self.overage_bits),
47 )
48 }
49}
50
51pub(crate) fn packaged_artifact_fit_threshold_violations_from_envelope_and_thresholds(
52 envelope: &PackagedArtifactFitEnvelopeSummary,
53 thresholds: &PackagedArtifactFitThresholdSummary,
54) -> Vec<PackagedArtifactFitThresholdViolation> {
55 let mut violations = Vec::new();
56
57 macro_rules! check_threshold {
58 ($field:literal, $measured:expr, $threshold:expr) => {
59 if $measured > $threshold {
60 violations.push(PackagedArtifactFitThresholdViolation {
61 field: $field,
62 measured_bits: $measured.to_bits(),
63 threshold_bits: $threshold.to_bits(),
64 overage_bits: ($measured - $threshold).to_bits(),
65 });
66 }
67 };
68 }
69
70 check_threshold!(
71 "mean_longitude_delta_degrees",
72 envelope.mean_longitude_delta_degrees,
73 thresholds.max_mean_longitude_delta_degrees
74 );
75 check_threshold!(
76 "mean_latitude_delta_degrees",
77 envelope.mean_latitude_delta_degrees,
78 thresholds.max_mean_latitude_delta_degrees
79 );
80 check_threshold!(
81 "mean_distance_delta_au",
82 envelope.mean_distance_delta_au,
83 thresholds.max_mean_distance_delta_au
84 );
85 check_threshold!(
86 "max_longitude_delta_degrees",
87 envelope.max_longitude_delta_degrees,
88 thresholds.max_longitude_delta_degrees
89 );
90 check_threshold!(
91 "max_latitude_delta_degrees",
92 envelope.max_latitude_delta_degrees,
93 thresholds.max_latitude_delta_degrees
94 );
95 check_threshold!(
96 "max_distance_delta_au",
97 envelope.max_distance_delta_au,
98 thresholds.max_distance_delta_au
99 );
100
101 violations
102}
103
104#[derive(Clone, Debug, Eq, PartialEq)]
106pub enum PackagedArtifactFitEnvelopeSummaryValidationError {
107 FieldOutOfSync { field: &'static str },
109 ThresholdExceeded {
111 violations: Vec<PackagedArtifactFitThresholdViolation>,
112 },
113}
114
115impl PackagedArtifactFitEnvelopeSummaryValidationError {
116 pub fn violation_count(&self) -> usize {
118 match self {
119 Self::FieldOutOfSync { .. } => 0,
120 Self::ThresholdExceeded { violations } => violations.len(),
121 }
122 }
123
124 pub fn summary_line(&self) -> String {
126 match self {
127 Self::FieldOutOfSync { field } => format!(
128 "the packaged artifact fit envelope summary field `{field}` is out of sync with the current posture"
129 ),
130 Self::ThresholdExceeded { violations } => {
131 let rendered = violations
132 .iter()
133 .map(PackagedArtifactFitThresholdViolation::summary_line)
134 .collect::<Vec<_>>()
135 .join("; ");
136 let violation_count = violations.len();
137 let violation_label = if violation_count == 1 {
138 "violation"
139 } else {
140 "violations"
141 };
142 format!(
143 "the packaged artifact fit envelope summary exceeds the calibrated fit thresholds ({violation_count} {violation_label}): {rendered}"
144 )
145 }
146 }
147 }
148}
149
150impl fmt::Display for PackagedArtifactFitEnvelopeSummaryValidationError {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 f.write_str(&self.summary_line())
153 }
154}
155
156impl std::error::Error for PackagedArtifactFitEnvelopeSummaryValidationError {}
157
158#[derive(Clone, Debug, PartialEq)]
160pub struct PackagedArtifactFitThresholdSummary {
161 pub max_mean_longitude_delta_degrees: f64,
163 pub max_mean_latitude_delta_degrees: f64,
165 pub max_mean_distance_delta_au: f64,
167 pub max_longitude_delta_degrees: f64,
169 pub max_latitude_delta_degrees: f64,
171 pub max_distance_delta_au: f64,
173}
174
175#[derive(Clone, Debug, Eq, PartialEq)]
177pub enum PackagedArtifactFitThresholdSummaryValidationError {
178 FieldOutOfSync { field: &'static str },
180}
181
182impl PackagedArtifactFitThresholdSummaryValidationError {
183 pub fn summary_line(&self) -> String {
185 match self {
186 Self::FieldOutOfSync { field } => format!(
187 "the packaged artifact fit threshold summary field `{field}` is out of sync with the current posture"
188 ),
189 }
190 }
191}
192
193impl fmt::Display for PackagedArtifactFitThresholdSummaryValidationError {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 f.write_str(&self.summary_line())
196 }
197}
198
199impl std::error::Error for PackagedArtifactFitThresholdSummaryValidationError {}
200
201impl PackagedArtifactFitThresholdSummary {
202 pub fn summary_line(&self) -> String {
204 format!(
205 "fit thresholds: mean Δlon≤{:.12}°, mean Δlat≤{:.12}°, mean Δdist≤{:.12} AU; max Δlon≤{:.12}°, max Δlat≤{:.12}°, max Δdist≤{:.12} AU",
206 self.max_mean_longitude_delta_degrees,
207 self.max_mean_latitude_delta_degrees,
208 self.max_mean_distance_delta_au,
209 self.max_longitude_delta_degrees,
210 self.max_latitude_delta_degrees,
211 self.max_distance_delta_au,
212 )
213 }
214
215 pub fn validate(&self) -> Result<(), PackagedArtifactFitThresholdSummaryValidationError> {
217 if self != &PACKAGED_ARTIFACT_FIT_THRESHOLD_SUMMARY {
218 return Err(
219 PackagedArtifactFitThresholdSummaryValidationError::FieldOutOfSync {
220 field: "thresholds",
221 },
222 );
223 }
224
225 Ok(())
226 }
227
228 pub fn validated_summary_line(
230 &self,
231 ) -> Result<String, PackagedArtifactFitThresholdSummaryValidationError> {
232 self.validate()?;
233 Ok(self.summary_line())
234 }
235}
236
237impl fmt::Display for PackagedArtifactFitThresholdSummary {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 f.write_str(&self.summary_line())
240 }
241}
242
243#[derive(Clone, Debug, PartialEq)]
245pub struct PackagedArtifactFitMarginSummary {
246 pub envelope: PackagedArtifactFitEnvelopeSummary,
248 pub thresholds: PackagedArtifactFitThresholdSummary,
250}
251
252impl PackagedArtifactFitMarginSummary {
253 pub fn summary_line(&self) -> String {
255 format!(
256 "fit margins: mean Δlon={:+.12}°, mean Δlat={:+.12}°, mean Δdist={:+.12} AU; max Δlon={:+.12}°, max Δlat={:+.12}°, max Δdist={:+.12} AU",
257 self.thresholds.max_mean_longitude_delta_degrees - self.envelope.mean_longitude_delta_degrees,
258 self.thresholds.max_mean_latitude_delta_degrees - self.envelope.mean_latitude_delta_degrees,
259 self.thresholds.max_mean_distance_delta_au - self.envelope.mean_distance_delta_au,
260 self.thresholds.max_longitude_delta_degrees - self.envelope.max_longitude_delta_degrees,
261 self.thresholds.max_latitude_delta_degrees - self.envelope.max_latitude_delta_degrees,
262 self.thresholds.max_distance_delta_au - self.envelope.max_distance_delta_au,
263 )
264 }
265
266 pub fn validate(&self) -> Result<(), PackagedArtifactFitEnvelopeSummaryValidationError> {
268 let current_envelope = packaged_artifact_fit_envelope_summary_details();
269 if self.envelope != current_envelope {
270 return Err(
271 PackagedArtifactFitEnvelopeSummaryValidationError::FieldOutOfSync {
272 field: "envelope",
273 },
274 );
275 }
276
277 let current_thresholds = packaged_artifact_fit_threshold_summary_details();
278 if self.thresholds != current_thresholds {
279 return Err(
280 PackagedArtifactFitEnvelopeSummaryValidationError::FieldOutOfSync {
281 field: "thresholds",
282 },
283 );
284 }
285
286 self.envelope.validate_against_thresholds(&self.thresholds)
287 }
288
289 pub fn validated_summary_line(
291 &self,
292 ) -> Result<String, PackagedArtifactFitEnvelopeSummaryValidationError> {
293 self.validate()?;
294 Ok(self.summary_line())
295 }
296}
297
298impl fmt::Display for PackagedArtifactFitMarginSummary {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 f.write_str(&self.summary_line())
301 }
302}
303
304#[derive(Clone, Debug, PartialEq, Eq)]
306pub struct PackagedArtifactFitThresholdViolationsSummary {
307 pub violations: Vec<PackagedArtifactFitThresholdViolation>,
309}
310
311#[derive(Clone, Debug, Eq, PartialEq)]
313pub enum PackagedArtifactFitThresholdViolationsSummaryValidationError {
314 FieldOutOfSync { field: &'static str },
316}
317
318impl PackagedArtifactFitThresholdViolationsSummaryValidationError {
319 pub fn summary_line(&self) -> String {
321 match self {
322 Self::FieldOutOfSync { field } => format!(
323 "the packaged artifact fit threshold violation summary field `{field}` is out of sync with the current posture"
324 ),
325 }
326 }
327}
328
329impl fmt::Display for PackagedArtifactFitThresholdViolationsSummaryValidationError {
330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331 f.write_str(&self.summary_line())
332 }
333}
334
335impl std::error::Error for PackagedArtifactFitThresholdViolationsSummaryValidationError {}
336
337impl PackagedArtifactFitThresholdViolationsSummary {
338 pub fn summary_line(&self) -> String {
340 let violation_count = self.violations.len();
341 if violation_count == 0 {
342 return "fit threshold violations: 0; details: none".to_string();
343 }
344
345 let rendered = self
346 .violations
347 .iter()
348 .map(PackagedArtifactFitThresholdViolation::summary_line)
349 .collect::<Vec<_>>()
350 .join("; ");
351 let violation_label = if violation_count == 1 {
352 "violation"
353 } else {
354 "violations"
355 };
356 format!(
357 "fit threshold violations: {violation_count} {violation_label}; details: {rendered}"
358 )
359 }
360
361 pub fn validate(
363 &self,
364 ) -> Result<(), PackagedArtifactFitThresholdViolationsSummaryValidationError> {
365 let current = packaged_artifact_fit_threshold_violation_summary_details();
366 if self == ¤t {
367 Ok(())
368 } else {
369 Err(
370 PackagedArtifactFitThresholdViolationsSummaryValidationError::FieldOutOfSync {
371 field: "violations",
372 },
373 )
374 }
375 }
376
377 pub fn validated_summary_line(
379 &self,
380 ) -> Result<String, PackagedArtifactFitThresholdViolationsSummaryValidationError> {
381 self.validate()?;
382 Ok(self.summary_line())
383 }
384}
385
386impl fmt::Display for PackagedArtifactFitThresholdViolationsSummary {
387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
388 f.write_str(&self.summary_line())
389 }
390}
391
392impl PackagedArtifactFitEnvelopeSummary {
393 pub fn validate_against_thresholds(
395 &self,
396 thresholds: &PackagedArtifactFitThresholdSummary,
397 ) -> Result<(), PackagedArtifactFitEnvelopeSummaryValidationError> {
398 let violations = packaged_artifact_fit_threshold_violations_from_envelope_and_thresholds(
399 self, thresholds,
400 );
401
402 if violations.is_empty() {
403 Ok(())
404 } else {
405 Err(PackagedArtifactFitEnvelopeSummaryValidationError::ThresholdExceeded { violations })
406 }
407 }
408}
409
410#[derive(Clone, Debug, PartialEq)]
411pub(crate) struct PackagedArtifactFitSample {
412 pub(crate) body: CelestialBody,
413 pub(crate) segment_start: Instant,
414 pub(crate) segment_end: Instant,
415 pub(crate) sample_instant: Instant,
416 pub(crate) sample_fraction: f64,
417 pub(crate) longitude_delta_degrees: f64,
418 pub(crate) latitude_delta_degrees: f64,
419 pub(crate) distance_delta_au: f64,
420}
421
422#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
423pub(crate) struct PackagedArtifactFitSegmentFamilyKey {
424 segment_start_days_bits: u64,
425 segment_start_scale: TimeScale,
426 segment_end_days_bits: u64,
427 segment_end_scale: TimeScale,
428}
429
430impl PackagedArtifactFitSegmentFamilyKey {
431 pub(crate) fn from_sample(sample: &PackagedArtifactFitSample) -> Self {
432 Self {
433 segment_start_days_bits: sample.segment_start.julian_day.days().to_bits(),
434 segment_start_scale: sample.segment_start.scale,
435 segment_end_days_bits: sample.segment_end.julian_day.days().to_bits(),
436 segment_end_scale: sample.segment_end.scale,
437 }
438 }
439}
440
441#[derive(Clone, Debug)]
442pub(crate) struct PackagedArtifactFitChannelFamilyAccumulator {
443 sample_count: usize,
444 worst_sample: Option<PackagedArtifactFitSample>,
445}
446
447impl PackagedArtifactFitChannelFamilyAccumulator {
448 pub(crate) fn new() -> Self {
449 Self {
450 sample_count: 0,
451 worst_sample: None,
452 }
453 }
454
455 pub(crate) fn push(&mut self, sample: &PackagedArtifactFitSample, channel: ChannelKind) {
456 self.sample_count += 1;
457 let should_replace = self
458 .worst_sample
459 .as_ref()
460 .map(|existing| {
461 let existing_delta = packaged_artifact_fit_channel_delta(existing, channel);
462 let candidate_delta = packaged_artifact_fit_channel_delta(sample, channel);
463 candidate_delta > existing_delta
464 || (candidate_delta == existing_delta
465 && (sample.segment_end.julian_day.days()
466 - sample.segment_start.julian_day.days())
467 < (existing.segment_end.julian_day.days()
468 - existing.segment_start.julian_day.days()))
469 })
470 .unwrap_or(true);
471
472 if should_replace {
473 self.worst_sample = Some(sample.clone());
474 }
475 }
476
477 pub(crate) fn finish(self, channel: ChannelKind) -> Option<PackagedArtifactFitChannelOutlier> {
478 self.worst_sample.as_ref().map(|sample| {
479 PackagedArtifactFitChannelOutlier::from_sample(sample, channel, self.sample_count)
480 })
481 }
482}
483
484#[derive(Clone, Debug, PartialEq)]
485pub struct PackagedArtifactFitChannelOutlier {
486 pub channel: ChannelKind,
488 pub delta: f64,
490 pub segment_start: Instant,
492 pub segment_end: Instant,
494 pub segment_span_days: f64,
496 pub sample_instant: Instant,
498 pub sample_fraction: f64,
500 pub sample_count: usize,
502}
503
504impl PackagedArtifactFitChannelOutlier {
505 fn from_sample(
506 sample: &PackagedArtifactFitSample,
507 channel: ChannelKind,
508 sample_count: usize,
509 ) -> Self {
510 Self {
511 channel,
512 delta: packaged_artifact_fit_channel_delta(sample, channel),
513 segment_start: sample.segment_start,
514 segment_end: sample.segment_end,
515 segment_span_days: sample.segment_end.julian_day.days()
516 - sample.segment_start.julian_day.days(),
517 sample_instant: sample.sample_instant,
518 sample_fraction: sample.sample_fraction,
519 sample_count,
520 }
521 }
522
523 fn delta_unit(&self) -> &'static str {
524 match self.channel {
525 ChannelKind::Longitude | ChannelKind::Latitude => "°",
526 ChannelKind::DistanceAu => " AU",
527 _ => unreachable!("unsupported packaged-artifact channel kind"),
528 }
529 }
530
531 fn summary_line(&self) -> String {
532 format!(
533 "{}={:.12}{} @ {} (segment {} → {}, span={:.12} d, x={:.3}, samples={})",
534 self.channel,
535 self.delta,
536 self.delta_unit(),
537 self.sample_instant,
538 self.segment_start,
539 self.segment_end,
540 self.segment_span_days,
541 self.sample_fraction,
542 self.sample_count,
543 )
544 }
545}
546
547impl fmt::Display for PackagedArtifactFitChannelOutlier {
548 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549 f.write_str(&self.summary_line())
550 }
551}
552
553#[derive(Clone, Debug, PartialEq)]
554pub struct PackagedArtifactFitBodyOutlierSummary {
555 pub body: CelestialBody,
557 pub channel_outliers: Vec<PackagedArtifactFitChannelOutlier>,
559}
560
561impl PackagedArtifactFitBodyOutlierSummary {
562 pub(crate) fn summary_line(&self) -> String {
563 format!("{}{{{}}}", self.body, join_display(&self.channel_outliers))
564 }
565}
566
567impl fmt::Display for PackagedArtifactFitBodyOutlierSummary {
568 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
569 f.write_str(&self.summary_line())
570 }
571}
572
573#[derive(Clone, Debug, PartialEq)]
574pub struct PackagedArtifactFitOutlierSummary {
575 pub body_count: usize,
577 pub body_summaries: Vec<PackagedArtifactFitBodyOutlierSummary>,
579}
580
581impl PackagedArtifactFitOutlierSummary {
582 pub fn summary_line(&self) -> String {
584 format!(
585 "fit outliers: {} bundled bodies; {}",
586 self.body_count,
587 join_display(&self.body_summaries)
588 )
589 }
590
591 pub fn validate(&self) -> Result<(), PackagedArtifactFitEnvelopeSummaryValidationError> {
593 let expected = packaged_artifact_fit_outlier_summary_details();
594 if self != &expected {
595 return Err(
596 PackagedArtifactFitEnvelopeSummaryValidationError::FieldOutOfSync {
597 field: "outlier summary",
598 },
599 );
600 }
601
602 Ok(())
603 }
604
605 pub fn validated_summary_line(
607 &self,
608 ) -> Result<String, PackagedArtifactFitEnvelopeSummaryValidationError> {
609 self.validate()?;
610 Ok(self.summary_line())
611 }
612}
613
614impl fmt::Display for PackagedArtifactFitOutlierSummary {
615 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
616 f.write_str(&self.summary_line())
617 }
618}
619
620#[derive(Clone, Debug, PartialEq)]
621pub struct PackagedArtifactFitChannelOutlierSummary {
622 pub channel_summaries: Vec<String>,
624}
625
626#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
628pub enum PackagedArtifactFitChannelOutlierSummaryValidationError {
629 FieldOutOfSync { field: &'static str },
631}
632
633impl PackagedArtifactFitChannelOutlierSummaryValidationError {
634 pub fn summary_line(&self) -> String {
636 match self {
637 Self::FieldOutOfSync { field } => format!(
638 "the packaged artifact fit outlier-by-channel summary field `{field}` is out of sync with the current posture"
639 ),
640 }
641 }
642}
643
644impl fmt::Display for PackagedArtifactFitChannelOutlierSummaryValidationError {
645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
646 f.write_str(&self.summary_line())
647 }
648}
649
650impl std::error::Error for PackagedArtifactFitChannelOutlierSummaryValidationError {}
651
652impl PackagedArtifactFitChannelOutlierSummary {
653 pub fn summary_line(&self) -> String {
655 if self.channel_summaries.is_empty() {
656 "fit outliers by channel: none".to_string()
657 } else {
658 format!(
659 "fit outliers by channel: {}",
660 self.channel_summaries.join("; ")
661 )
662 }
663 }
664
665 pub fn validate(&self) -> Result<(), PackagedArtifactFitChannelOutlierSummaryValidationError> {
667 let expected = packaged_artifact_fit_channel_outlier_summary_details();
668 if self != &expected {
669 return Err(
670 PackagedArtifactFitChannelOutlierSummaryValidationError::FieldOutOfSync {
671 field: "channel_summaries",
672 },
673 );
674 }
675
676 Ok(())
677 }
678
679 pub fn validated_summary_line(
681 &self,
682 ) -> Result<String, PackagedArtifactFitChannelOutlierSummaryValidationError> {
683 self.validate()?;
684 Ok(self.summary_line())
685 }
686}
687
688impl fmt::Display for PackagedArtifactFitChannelOutlierSummary {
689 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690 f.write_str(&self.summary_line())
691 }
692}
693
694pub(crate) fn packaged_artifact_fit_channel_outlier_summary_for_channel(
695 samples: &[PackagedArtifactFitSample],
696 channel: ChannelKind,
697) -> Option<String> {
698 let mut families: HashMap<
699 (CelestialBody, PackagedArtifactFitSegmentFamilyKey),
700 PackagedArtifactFitChannelFamilyAccumulator,
701 > = HashMap::new();
702
703 for sample in samples {
704 let family_key = PackagedArtifactFitSegmentFamilyKey::from_sample(sample);
705 let entry = families
706 .entry((sample.body.clone(), family_key))
707 .or_insert_with(PackagedArtifactFitChannelFamilyAccumulator::new);
708 entry.push(sample, channel);
709 }
710
711 let mut body_outliers: HashMap<CelestialBody, PackagedArtifactFitChannelOutlier> =
712 HashMap::new();
713
714 for ((body, _family_key), family) in families {
715 let Some(candidate) = family.finish(channel) else {
716 continue;
717 };
718 match body_outliers.get_mut(&body) {
719 Some(existing) if existing.delta > candidate.delta => {}
720 Some(existing)
721 if existing.delta == candidate.delta
722 && existing.segment_span_days <= candidate.segment_span_days => {}
723 Some(existing) => *existing = candidate,
724 None => {
725 body_outliers.insert(body, candidate);
726 }
727 }
728 }
729
730 if body_outliers.is_empty() {
731 return None;
732 }
733
734 let mut body_entries = body_outliers
735 .into_iter()
736 .map(|(body, outlier)| format!("{body}{{{outlier}}}"))
737 .collect::<Vec<_>>();
738 body_entries.sort();
739
740 Some(format!("{channel}{{{}}}", body_entries.join(", ")))
741}
742
743pub fn packaged_artifact_fit_channel_outlier_summary_details(
745) -> PackagedArtifactFitChannelOutlierSummary {
746 let samples = packaged_artifact_fit_outlier_samples_for_current_artifact();
747 let mut channel_summaries = Vec::new();
748
749 for channel in [
750 ChannelKind::DistanceAu,
751 ChannelKind::Longitude,
752 ChannelKind::Latitude,
753 ] {
754 if let Some(entry) =
755 packaged_artifact_fit_channel_outlier_summary_for_channel(samples, channel)
756 {
757 channel_summaries.push(entry);
758 }
759 }
760
761 PackagedArtifactFitChannelOutlierSummary { channel_summaries }
762}
763
764pub(crate) const PACKAGED_ARTIFACT_FIT_MAX_MEAN_LONGITUDE_DELTA_DEGREES: f64 = 79.29937281518961;
774pub(crate) const PACKAGED_ARTIFACT_FIT_MAX_MEAN_LATITUDE_DELTA_DEGREES: f64 =
775 3.320_919_159_432_106_6;
776pub(crate) const PACKAGED_ARTIFACT_FIT_MAX_MEAN_DISTANCE_DELTA_AU: f64 = 5240.2473102557;
777pub(crate) const PACKAGED_ARTIFACT_FIT_MAX_LONGITUDE_DELTA_DEGREES: f64 = 179.999_799_204_804_48;
778pub(crate) const PACKAGED_ARTIFACT_FIT_MAX_LATITUDE_DELTA_DEGREES: f64 = 69.9571184739231;
779pub(crate) const PACKAGED_ARTIFACT_FIT_MAX_DISTANCE_DELTA_AU: f64 = 10227288.989857685;
780
781pub(crate) const PACKAGED_ARTIFACT_FIT_THRESHOLD_SUMMARY: PackagedArtifactFitThresholdSummary =
782 PackagedArtifactFitThresholdSummary {
783 max_mean_longitude_delta_degrees: PACKAGED_ARTIFACT_FIT_MAX_MEAN_LONGITUDE_DELTA_DEGREES,
784 max_mean_latitude_delta_degrees: PACKAGED_ARTIFACT_FIT_MAX_MEAN_LATITUDE_DELTA_DEGREES,
785 max_mean_distance_delta_au: PACKAGED_ARTIFACT_FIT_MAX_MEAN_DISTANCE_DELTA_AU,
786 max_longitude_delta_degrees: PACKAGED_ARTIFACT_FIT_MAX_LONGITUDE_DELTA_DEGREES,
787 max_latitude_delta_degrees: PACKAGED_ARTIFACT_FIT_MAX_LATITUDE_DELTA_DEGREES,
788 max_distance_delta_au: PACKAGED_ARTIFACT_FIT_MAX_DISTANCE_DELTA_AU,
789 };