update
This commit is contained in:
parent
ee4590276a
commit
1a97b9e986
@ -68,13 +68,6 @@
|
||||
position: (2.987992735576156e+01, -6.341879950443392e-01, -6.754997950415415e-01),
|
||||
velocity: (3.941595250081164e-05, 3.160389775728832e-03, -6.636996572427530e-05),
|
||||
),
|
||||
(
|
||||
name: "Pluto",
|
||||
mass: 1.307e22,
|
||||
radius: 1188.3,
|
||||
position: (1.822881632666475e+01, -3.000801293901950e+01, -2.059815785829023e+00),
|
||||
velocity: (2.758977855246929e-03, 9.457264850164455e-04, -8.880815395819214e-04),
|
||||
),
|
||||
(
|
||||
name: "Moon",
|
||||
mass: 7.349e22,
|
||||
|
||||
@ -1,124 +0,0 @@
|
||||
API VERSION: 1.2
|
||||
API SOURCE: NASA/JPL Horizons API
|
||||
|
||||
*******************************************************************************
|
||||
Revised: Apr 03, 2024 134340 Pluto 999
|
||||
|
||||
Pre-computed solution PLU060/DE440. Fit to post New Horizons encounter and
|
||||
Gaia data through 2023. For discussion, see ...
|
||||
|
||||
M. Brozovic, R. A. Jacobson (2024) "Post-New Horizons orbits and masses
|
||||
for the satellites of Pluto". AJ (in press)
|
||||
|
||||
PHYSICAL DATA (updated 2021-Jun-07; Mc= Charon mass, radius is IAU 2015):
|
||||
Mass x10^22 (kg) = 1.307+-0.018 Volume, 10^10 km^3 = 0.697
|
||||
GM (planet) km^3/s^2 = 869.326 Density (R=1195 km) = 1.86 g/cm^3
|
||||
GM 1-sigma, km^3/s^2 = 0.4 Surface gravity = 0.611 m/s^2
|
||||
Vol. mean radius (km) = 1188.3+-1.6 Mass ratio (Mc/Mp) = 0.122
|
||||
Sidereal rot. period = 153.29335198 h Sid. rot. rat, rad/s = 0.0000113856
|
||||
Mean solar day, h = 153.2820 Mean orbit velocity = 4.67 km/s
|
||||
Sidereal orbit period = 249.58932 yr Escape speed, km/s = 1.21
|
||||
Perihelion Aphelion Mean
|
||||
Solar Constant (W/m^2) 1.56 0.56 0.88
|
||||
Maximum Planetary IR (W/m^2) 0.8 0.3 0.5
|
||||
Minimum Planetary IR (W/m^2) 0.8 0.3 0.5
|
||||
*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************
|
||||
Ephemeris / API_USER Thu Aug 14 15:51:59 2025 Pasadena, USA / Horizons
|
||||
*******************************************************************************
|
||||
Target body name: Pluto (999) {source: plu060_merged}
|
||||
Center body name: Sun (10) {source: plu060_merged}
|
||||
Center-site name: BODY CENTER
|
||||
*******************************************************************************
|
||||
Start time : A.D. 2025-Jan-01 00:00:00.0000 TDB
|
||||
Stop time : A.D. 2025-Jan-01 00:01:00.0000 TDB
|
||||
Step-size : 1 minutes
|
||||
*******************************************************************************
|
||||
Center geodetic : 0.0, 0.0, 0.0 {E-lon(deg),Lat(deg),Alt(km)}
|
||||
Center cylindric: 0.0, 0.0, 0.0 {E-lon(deg),Dxy(km),Dz(km)}
|
||||
Center radii : 695700.0, 695700.0, 695700.0 km {Equator_a, b, pole_c}
|
||||
Output units : AU-D
|
||||
Calendar mode : Mixed Julian/Gregorian
|
||||
Output type : GEOMETRIC cartesian states
|
||||
Output format : 2 (position and velocity)
|
||||
Reference frame : Ecliptic of J2000.0
|
||||
*******************************************************************************
|
||||
JDTDB
|
||||
X Y Z
|
||||
VX VY VZ
|
||||
*******************************************************************************
|
||||
$$SOE
|
||||
2460676.500000000 = A.D. 2025-Jan-01 00:00:00.0000 TDB
|
||||
X = 1.822881632666475E+01 Y =-3.000801293901950E+01 Z =-2.059815785829023E+00
|
||||
VX= 2.758977855246929E-03 VY= 9.457264850164455E-04 VZ=-8.880815395819214E-04
|
||||
2460676.500694444 = A.D. 2025-Jan-01 00:01:00.0000 TDB
|
||||
X = 1.822881824262399E+01 Y =-3.000801228226284E+01 Z =-2.059816402553139E+00
|
||||
VX= 2.758984750779286E-03 VY= 9.457327203036255E-04 VZ=-8.880839212592113E-04
|
||||
$$EOE
|
||||
*******************************************************************************
|
||||
|
||||
TIME
|
||||
|
||||
Barycentric Dynamical Time ("TDB" or T_eph) output was requested. This
|
||||
continuous coordinate time is equivalent to the relativistic proper time
|
||||
of a clock at rest in a reference frame co-moving with the solar system
|
||||
barycenter but outside the system's gravity well. It is the independent
|
||||
variable in the solar system relativistic equations of motion.
|
||||
|
||||
TDB runs at a uniform rate of one SI second per second and is independent
|
||||
of irregularities in Earth's rotation.
|
||||
|
||||
CALENDAR SYSTEM
|
||||
|
||||
Mixed calendar mode was active such that calendar dates after AD 1582-Oct-15
|
||||
(if any) are in the modern Gregorian system. Dates prior to 1582-Oct-5 (if any)
|
||||
are in the Julian calendar system, which is automatically extended for dates
|
||||
prior to its adoption on 45-Jan-1 BC. The Julian calendar is useful for
|
||||
matching historical dates. The Gregorian calendar more accurately corresponds
|
||||
to the Earth's orbital motion and seasons. A "Gregorian-only" calendar mode is
|
||||
available if such physical events are the primary interest.
|
||||
|
||||
REFERENCE FRAME AND COORDINATES
|
||||
|
||||
Ecliptic at the standard reference epoch
|
||||
|
||||
Reference epoch: J2000.0
|
||||
X-Y plane: adopted Earth orbital plane at the reference epoch
|
||||
Note: IAU76 obliquity of 84381.448 arcseconds wrt ICRF X-Y plane
|
||||
X-axis : ICRF
|
||||
Z-axis : perpendicular to the X-Y plane in the directional (+ or -) sense
|
||||
of Earth's north pole at the reference epoch.
|
||||
|
||||
Symbol meaning [1 au= 149597870.700 km, 1 day= 86400.0 s]:
|
||||
|
||||
JDTDB Julian Day Number, Barycentric Dynamical Time
|
||||
X X-component of position vector (au)
|
||||
Y Y-component of position vector (au)
|
||||
Z Z-component of position vector (au)
|
||||
VX X-component of velocity vector (au/day)
|
||||
VY Y-component of velocity vector (au/day)
|
||||
VZ Z-component of velocity vector (au/day)
|
||||
|
||||
ABERRATIONS AND CORRECTIONS
|
||||
|
||||
Geometric state vectors have NO corrections or aberrations applied.
|
||||
|
||||
Computations by ...
|
||||
|
||||
Solar System Dynamics Group, Horizons On-Line Ephemeris System
|
||||
4800 Oak Grove Drive, Jet Propulsion Laboratory
|
||||
Pasadena, CA 91109 USA
|
||||
|
||||
General site: https://ssd.jpl.nasa.gov/
|
||||
Mailing list: https://ssd.jpl.nasa.gov/email_list.html
|
||||
System news : https://ssd.jpl.nasa.gov/horizons/news.html
|
||||
User Guide : https://ssd.jpl.nasa.gov/horizons/manual.html
|
||||
Connect : browser https://ssd.jpl.nasa.gov/horizons/app.html#/x
|
||||
API https://ssd-api.jpl.nasa.gov/doc/horizons.html
|
||||
command-line telnet ssd.jpl.nasa.gov 6775
|
||||
e-mail/batch https://ssd.jpl.nasa.gov/ftp/ssd/horizons_batch.txt
|
||||
scripts https://ssd.jpl.nasa.gov/ftp/ssd/SCRIPTS
|
||||
Author : Jon.D.Giorgini@jpl.nasa.gov
|
||||
*******************************************************************************
|
||||
112
src/main.rs
112
src/main.rs
@ -42,7 +42,7 @@ pub struct PositionAu(pub DVec3);
|
||||
pub struct VelocityAuPerDay(pub DVec3);
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct MassKg(pub f64);
|
||||
pub struct MassSolarMass(pub f64);
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct ObjectName(pub String);
|
||||
@ -55,7 +55,7 @@ struct Position(PositionAu);
|
||||
struct Velocity(VelocityAuPerDay);
|
||||
|
||||
#[derive(Component)]
|
||||
struct Mass(MassKg);
|
||||
struct Mass(MassSolarMass);
|
||||
|
||||
#[derive(Component)]
|
||||
struct Radius(DistanceAu);
|
||||
@ -83,6 +83,10 @@ struct ObjectLabel {
|
||||
target_entity: Entity,
|
||||
}
|
||||
|
||||
// Component to control label visibility
|
||||
#[derive(Component)]
|
||||
struct LabelVisible(bool);
|
||||
|
||||
// Component to mark objects that can be focused on with proper zoom levels
|
||||
#[derive(Component)]
|
||||
struct Trackable {}
|
||||
@ -109,10 +113,11 @@ impl Plugin for SolarRenderingPlugin {
|
||||
sync_radius_to_mesh,
|
||||
sync_position_to_transform,
|
||||
sync_name_labels,
|
||||
manage_label_overlaps.after(sync_position_to_transform).after(sync_name_labels),
|
||||
camera_follow_system.after(sync_position_to_transform),
|
||||
),
|
||||
)
|
||||
.add_systems(PostUpdate, update_label_positions)
|
||||
.add_systems(PostUpdate, update_label_positions.after(manage_label_overlaps))
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
@ -251,13 +256,14 @@ fn sync_name_labels(
|
||||
ObjectLabel {
|
||||
target_entity: entity,
|
||||
},
|
||||
LabelVisible(true), // Start visible by default
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_label_positions(
|
||||
mut label_query: Query<(&mut Node, &ObjectLabel, &mut Text), With<ObjectLabel>>,
|
||||
fn manage_label_overlaps(
|
||||
mut label_query: Query<(&ObjectLabel, &mut LabelVisible)>,
|
||||
objects_query: Query<(&GlobalTransform, &Name, &Radius)>,
|
||||
camera_query: Query<(&Camera, &GlobalTransform)>,
|
||||
) {
|
||||
@ -265,7 +271,78 @@ fn update_label_positions(
|
||||
return;
|
||||
};
|
||||
|
||||
for (mut node, label, mut text) in label_query.iter_mut() {
|
||||
// Collect all on-screen objects with their screen positions and radii
|
||||
let mut visible_objects: Vec<(Entity, Vec2, f64, String)> = Vec::new();
|
||||
|
||||
for (label, _) in label_query.iter() {
|
||||
if let Ok((global_transform, name, radius)) = objects_query.get(label.target_entity) {
|
||||
let world_pos = global_transform.translation();
|
||||
if let Ok(screen_pos) = camera.world_to_viewport(camera_transform, world_pos) {
|
||||
visible_objects.push((
|
||||
label.target_entity,
|
||||
screen_pos,
|
||||
radius.0.0, // radius in AU
|
||||
name.0.0.clone(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset all labels to visible first
|
||||
for (_, mut visible) in label_query.iter_mut() {
|
||||
visible.0 = true;
|
||||
}
|
||||
|
||||
// Check for overlaps and hide smaller objects
|
||||
const OVERLAP_THRESHOLD: f32 = 50.0; // pixels
|
||||
|
||||
for i in 0..visible_objects.len() {
|
||||
for j in (i + 1)..visible_objects.len() {
|
||||
let (entity_a, pos_a, radius_a, name_a) = &visible_objects[i];
|
||||
let (entity_b, pos_b, radius_b, name_b) = &visible_objects[j];
|
||||
|
||||
let distance = pos_a.distance(*pos_b);
|
||||
if distance < OVERLAP_THRESHOLD {
|
||||
// Determine which label to hide based on radius (larger wins)
|
||||
let entity_to_hide = if radius_a > radius_b {
|
||||
*entity_b
|
||||
} else if radius_b > radius_a {
|
||||
*entity_a
|
||||
} else {
|
||||
// If radii are equal, prefer alphabetically first name
|
||||
if name_a < name_b { *entity_b } else { *entity_a }
|
||||
};
|
||||
|
||||
// Hide the smaller object's label
|
||||
for (label, mut visible) in label_query.iter_mut() {
|
||||
if label.target_entity == entity_to_hide {
|
||||
visible.0 = false;
|
||||
// Debug: which label got hidden
|
||||
debug!("Hiding label due to overlap (distance: {:.1}px)", distance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_label_positions(
|
||||
mut label_query: Query<(&mut Node, &ObjectLabel, &mut Text, &LabelVisible), With<ObjectLabel>>,
|
||||
objects_query: Query<(&GlobalTransform, &Name, &Radius)>,
|
||||
camera_query: Query<(&Camera, &GlobalTransform)>,
|
||||
) {
|
||||
let Ok((camera, camera_transform)) = camera_query.single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (mut node, label, mut text, visible) in label_query.iter_mut() {
|
||||
if !visible.0 {
|
||||
// Label is marked as invisible due to overlap, hide it
|
||||
node.display = Display::None;
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Ok((global_transform, name, _radius)) = objects_query.get(label.target_entity) {
|
||||
let world_pos = global_transform.translation();
|
||||
if let Ok(screen_pos) = camera.world_to_viewport(camera_transform, world_pos) {
|
||||
@ -275,17 +352,17 @@ fn update_label_positions(
|
||||
// Position the label on screen, offset slightly to avoid overlapping the object
|
||||
node.left = Val::Px(screen_pos.x + scaled_offset);
|
||||
node.top = Val::Px(screen_pos.y - scaled_offset);
|
||||
node.display = Display::Flex; // Make sure it's visible
|
||||
|
||||
// Update text in case name changed
|
||||
text.0 = name.0.0.clone();
|
||||
} else {
|
||||
// Object is off-screen, hide label by moving it off-screen
|
||||
node.left = Val::Px(-1000.0);
|
||||
node.top = Val::Px(-1000.0);
|
||||
// Object is off-screen, hide label
|
||||
node.display = Display::None;
|
||||
}
|
||||
} else {
|
||||
// Target entity no longer exists, remove label
|
||||
// Note: In a more complex system, you might want to handle this in a separate cleanup system
|
||||
// Target entity no longer exists, hide label
|
||||
node.display = Display::None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,6 +522,9 @@ fn setup_solar_system(mut commands: Commands) {
|
||||
for body_data in initial_state.bodies {
|
||||
// Convert radius from km to AU
|
||||
let radius_au = body_data.radius / 149597870.691; // km to AU conversion
|
||||
|
||||
// Convert mass from kg to solar masses
|
||||
let mass_solar = body_data.mass / SOLAR_MASS_KG;
|
||||
|
||||
// Create base bundle
|
||||
let mut entity_commands = commands.spawn((
|
||||
@ -460,7 +540,7 @@ fn setup_solar_system(mut commands: Commands) {
|
||||
body_data.velocity.1,
|
||||
body_data.velocity.2,
|
||||
))),
|
||||
mass: Mass(MassKg(body_data.mass)),
|
||||
mass: Mass(MassSolarMass(mass_solar)),
|
||||
radius: Radius(DistanceAu(radius_au)),
|
||||
},
|
||||
Trackable {},
|
||||
@ -485,9 +565,13 @@ fn setup_solar_system(mut commands: Commands) {
|
||||
const G_SI: f64 = 6.67430e-11; // m^3 / (kg s^2)
|
||||
const AU_TO_M: f64 = 149_597_870_691.0; // m
|
||||
const DAY_TO_S: f64 = 86_400.0; // s
|
||||
const SOLAR_MASS_KG: f64 = 1.98841e30; // kg
|
||||
|
||||
// G in AU^3 / (kg day^2)
|
||||
const G_AU: f64 = G_SI * (DAY_TO_S * DAY_TO_S) / (AU_TO_M * AU_TO_M * AU_TO_M);
|
||||
// G in AU^3 / (solar_mass day^2)
|
||||
// G_SI has units m^3 / (kg s^2)
|
||||
// We want AU^3 / (solar_mass day^2)
|
||||
// G_AU = G_SI * (day^2 / s^2) * (kg / solar_mass) * (m^3 / AU^3)
|
||||
const G_AU: f64 = G_SI * (DAY_TO_S * DAY_TO_S) / (SOLAR_MASS_KG * AU_TO_M * AU_TO_M * AU_TO_M);
|
||||
|
||||
const STEPS: usize = 100;
|
||||
// If FixedUpdate is 64 Hz and you want 1 day per game second: DT = 1/(64*STEPS) day/step
|
||||
|
||||
Loading…
Reference in New Issue
Block a user