use earths::biosphere::ecosystems::{borealforest, coralreef, tropicalrainforest};
use earths::biosphere::fauna::{PredatorPrey, africanelephant, bluewhale};
use earths::biosphere::vegetation::{
beerlambertlightextinction, coniferousforest, temperategrassland, tropicalbroadleaf,
};
use earths::geodata::bathymetry::{BathymetryData, OceanBasin};
use earths::geodata::coordinates::{EARTHFLATTENING, EARTHSEMIMAJORM, EARTHSEMIMINORM, LatLon};
use earths::geodata::elevation::ElevationProvider;
use earths::geodata::regions::{RegionDatabase, RegionType};
use earths::lighting::day_night::{DayNightCycle, DaylightState};
use earths::lighting::seasons::{
AXIALTILTDEG as SEASONSTILT, Season, TROPICALYEARDAYS, VERNALEQUINOXJD, seasonat, subsolarpoint,
};
use earths::lighting::solar_position::{EARTHAXIALTILTDEG, SolarPosition};
use earths::physics::collisions::{chicxulubequivalent, tunguskaequivalent};
use earths::physics::orbit::{
ARGUMENTPERIHELIONDEG, ECCENTRICITY, EarthOrbit, INCLINATIONDEG, LONGITUDEASCENDINGNODEDEG,
SEMIMAJORAXIS,
};
use earths::physics::rotation::{
AXIALTILTDEG, AXIALTILTRAD, EarthRotation, PRECESSIONPERIODYEARS, SIDEREALDAYS, SOLARDAYS,
};
use earths::physics::tides::{
TidalForce, lunartosolartideratio, neaptideamplitude, springtideamplitude,
};
use earths::rendering::atmosphere_scattering::AtmosphereParams;
use earths::rendering::clouds::{CloudLayer, CloudSystem, CloudType};
use earths::rendering::materials::PbrMaterial;
use earths::rendering::ocean_rendering::OceanParams;
use earths::rendering::shaders::{ShaderData, UniformValue};
use earths::satellites::artificial::{ArtificialSatellite, Constellation, OrbitType};
use earths::satellites::moon::{
EARTHMOONDISTANCE, LUNARMASS, LUNARORBITALPERIOD, LUNARRADIUS, MoonSource, MoonState,
};
use earths::temporal::calendar::{DateTime, J2000JD, SECONDSPERDAY, UNIXEPOCHJD};
use earths::temporal::epoch::{Epoch, J1950EPOCH, J2000EPOCH, MJDOFFSET};
use earths::temporal::time_scale::TimeScale;
use earths::terrain::heightmap::Heightmap;
use earths::terrain::lod::{Face, LodConfig, LodTerrain};
use earths::terrain::mesh::TerrainMesh;
use earths::terrain::texturing::{Biome, BiomeClassifier};
fn main() {
let orbit = EarthOrbit::new();
let perioddays = orbit.orbitalperioddays();
let vperihelion = orbit.velocityatdistance(orbit.perihelionm());
let vaphelion = orbit.velocityatdistance(orbit.aphelionm());
let energy = orbit.specific_orbital_energy();
let angmom = orbit.specific_angular_momentum();
let vesc = EarthOrbit::escape_velocity_at_surface();
let fsun = orbit.gravitational_force_sun();
let r = orbit.current_radius();
let vmean = orbit.mean_orbital_velocity();
println!(
"Orbit: P={:.2}d vperi={:.0}m/s vaph={:.0}m/s vmean={:.0}m/s",
perioddays, vperihelion, vaphelion, vmean
);
println!(
" E={:.2e}J/kg L={:.2e}m²/s vesc={:.0}m/s Fsun={:.2e}N r={:.3e}m",
energy, angmom, vesc, fsun, r
);
println!(
" a={:.3e}m e={} i={}° Ω={}° ω={}°",
SEMIMAJORAXIS,
ECCENTRICITY,
INCLINATIONDEG,
LONGITUDEASCENDINGNODEDEG,
ARGUMENTPERIHELIONDEG
);
let rot = EarthRotation::new();
let vequator = rot.surfacevelocityatlatitude(0.0);
let v45 = rot.surfacevelocityatlatitude(45.0);
let accel = rot.centripetalaccelerationatlatitude(0.0);
let coriolis = rot.coriolisparameter(45.0);
let moi = rot.momentofinertia();
let ke = rot.rotationalkineticenergy();
let lrot = rot.angular_momentum();
let prec = rot.precession_rate_rad_per_year();
let daylensummer = rot.day_length_variation_due_to_tilt(172, 60.0);
let daylenwinter = rot.day_length_variation_due_to_tilt(355, 60.0);
println!(
"Rotation: veq={:.0}m/s v45={:.0}m/s ac={:.4}m/s² f45={:.5e}",
vequator, v45, accel, coriolis
);
println!(
" I={:.3e}kg·m² KE={:.3e}J L={:.3e}kg·m²/s prec={:.2e}rad/yr",
moi, ke, lrot, prec
);
println!(
" day@60°N: summer={:.1}h winter={:.1}h",
daylensummer, daylenwinter
);
println!(
" sidereal={:.4}s solar={}s tilt={}°={:.4}rad precperiod={}yr",
SIDEREALDAYS, SOLARDAYS, AXIALTILTDEG, AXIALTILTRAD, PRECESSIONPERIODYEARS
);
let moontide = TidalForce::frommoon();
let suntide = TidalForce::fromsun();
let amoon = moontide.tidalacceleration();
let asun = suntide.tidalacceleration();
let pot = moontide.tidalpotential(0.0);
let bulgemoon = moontide.tidalbulgeheight();
let bulgesun = suntide.tidalbulgeheight();
let grav = moontide.gravitationalattraction();
let spring = springtideamplitude();
let neap = neaptideamplitude();
let ratio = lunartosolartideratio();
println!(
"Tides: amoon={:.2e} asun={:.2e} ratio={:.2}",
amoon, asun, ratio
);
println!(
" bulgemoon={:.3}m bulgesun={:.3}m spring={:.3}m neap={:.3}m",
bulgemoon, bulgesun, spring, neap
);
println!(" potential(0)={:.2e} Fgrav={:.2e}N", pot, grav);
let chix = chicxulubequivalent();
let tung = tunguskaequivalent();
let kechix = chix.kineticenergymt();
let crater = chix.craterdiameterm(2700.0);
let fireball = chix.fireballradiusm();
let ejecta = chix.ejectavolumem3(2700.0);
let vimp = chix.impactvelocity();
let ketung = tung.kineticenergymt();
println!(
"Chicxulub: {:.2e}Mt crater={:.0}m fireball={:.0}m ejecta={:.2e}m³ vimp={:.0}m/s",
kechix, crater, fireball, ejecta, vimp
);
println!("Tunguska: {:.2e}Mt", ketung);
let mut moon = MoonState::new();
let source = match moon.source.get() {
MoonSource::Binary => "binary",
MoonSource::Simulation => "simulated",
};
let pos0 = moon.position();
moon.step(3600.0);
let pos1 = moon.position();
let gmoon = moon.gravityat(EARTHMOONDISTANCE);
println!(
"Moon({}): pos0=({:.0},{:.0}) pos1h=({:.0},{:.0}) g@dist={:.4e}m/s²",
source, pos0.0, pos0.1, pos1.0, pos1.1, gmoon
);
println!(
" M={:.3e}kg R={:.4e}m d={:.3e}m P={:.0}s",
LUNARMASS, LUNARRADIUS, EARTHMOONDISTANCE, LUNARORBITALPERIOD
);
let iss = ArtificialSatellite::leo("ISS", 420000.0, 408000.0);
let geo = ArtificialSatellite::geo("GEO-Sat", 300.0);
let custom = ArtificialSatellite::new("Molniya", 1500.0, 500000.0, 0.7, 1.1);
let piss = iss.orbitalperiods();
let viss = iss.orbitalvelocityms();
let pgeo = geo.orbitalperiods();
let gsurf = iss.gravityatsurface();
let posiss = iss.position();
let posgeo = geo.position();
let orbittype = |sat: &ArtificialSatellite| -> &str {
match sat.orbittype {
OrbitType::LEO => "LEO",
OrbitType::MEO => "MEO",
OrbitType::GEO => "GEO",
OrbitType::HEO => "HEO",
OrbitType::Custom => "Custom",
}
};
println!(
"ISS({}): P={:.0}s v={:.0}m/s gsurf={:.2} pos=({:.0},{:.0},{:.0})",
orbittype(&iss),
piss,
viss,
gsurf,
posiss.0,
posiss.1,
posiss.2
);
println!(
"GEO({}): P={:.0}s pos=({:.0},{:.0},{:.0})",
orbittype(&geo),
pgeo,
posgeo.0,
posgeo.1,
posgeo.2
);
println!(
"Custom({}): e={:.1} i={:.1}rad",
orbittype(&custom),
custom.eccentricity,
custom.inclinationrad
);
let mut constellation = Constellation::new("Starlink-test");
constellation.add(ArtificialSatellite::leo("S1", 260.0, 550000.0));
constellation.add(ArtificialSatellite::leo("S2", 260.0, 550000.0));
let mut satstepped = iss;
satstepped.step(60.0);
constellation.stepall(60.0);
let positions = constellation.positions();
println!(
"Constellation: {} sats positions={}",
positions.len(),
positions.len()
);
let dt = DateTime::new(2024, 6, 21, 12, 0, 0.0);
let jd = dt.tojuliandate();
let dtback = DateTime::fromjuliandate(jd);
let unix = dt.tounixtimestamp();
let dtunix = DateTime::fromunixtimestamp(unix);
println!(
"DateTime: {}-{}-{} {}:{}:{:.0} JD={:.4} unix={:.0}",
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, jd, unix
);
println!(
" roundtrip JD: {}-{}-{} roundtrip unix: {}-{}-{}",
dtback.year, dtback.month, dtback.day, dtunix.year, dtunix.month, dtunix.day
);
println!(
" J2000JD={} UNIXJD={} SPD={}",
J2000JD, UNIXEPOCHJD, SECONDSPERDAY
);
let mut epoch = Epoch::j2000();
let epochmjd = Epoch::frommjd(51544.5);
let centuries = epoch.centuriessincej2000();
let days = epoch.dayssincej2000();
let gmst = epoch.gmstdegrees();
let mjd = epoch.tomjd();
epoch.advancedays(365.25);
let centuries1yr = epoch.centuriessincej2000();
let mut epoch2 = Epoch::fromjd(J2000JD);
epoch2.advanceseconds(86400.0);
println!(
"Epoch: T0={:.4} days={:.1} GMST={:.2}° MJD={:.1}",
centuries, days, gmst, mjd
);
println!(
" +1yr: T={:.6} frommjd.jd={:.1} epoch2.days={:.1}",
centuries1yr,
epochmjd.juliandate,
epoch2.dayssincej2000()
);
println!(
" J2000={} J1950={} MJDOFF={}",
J2000EPOCH, J1950EPOCH, MJDOFFSET
);
let mut ts = TimeScale::realtime();
ts.step(1.0);
let simdt = ts.simulationdt(1.0);
let hours = ts.simhours();
let daysts = ts.simdays();
let years = ts.simyears();
ts.pause();
ts.resume();
ts.togglepause();
ts.setspeed(100.0);
let mut ff = TimeScale::fastforward(10.0);
ff.step(1.0);
let sm = TimeScale::slowmotion(2.0);
println!(
"TimeScale: dt={:.1} h={:.6} d={:.8} yr={:.10} ffsim={:.1}s smspeed={:.1}",
simdt, hours, daysts, years, ff.simulationtimes, sm.speedmultiplier
);
let sunpos = SolarPosition::compute(jd, 48.8, 2.3);
let above = sunpos.isabovehorizon();
let distsun = sunpos.distancem();
println!(
"Solar: el={:.1}° az={:.1}° above={} dist={:.3e}m tilt={}°",
sunpos.elevationdeg, sunpos.azimuthdeg, above, distsun, EARTHAXIALTILTDEG
);
let dnc = DayNightCycle::new(jd);
let stateparis = dnc.stateat(48.8, 2.3);
let statetext = match stateparis {
DaylightState::Day => "day",
DaylightState::Night => "night",
DaylightState::CivilTwilight => "civiltwilight",
DaylightState::NauticalTwilight => "nauticaltwilight",
DaylightState::AstronomicalTwilight => "astrotwilight",
};
let terminator = dnc.terminatorpoints(36);
let ambient = dnc.ambientlight(48.8, 2.3);
println!(
"DayNight: Paris={} ambient={:.2} terminatorpts={}",
statetext,
ambient,
terminator.len()
);
let seasonstate = seasonat(jd, 48.8);
let seasonname = match seasonstate.seasonnorth {
Season::Spring => "spring",
Season::Summer => "summer",
Season::Autumn => "autumn",
Season::Winter => "winter",
};
let southname = match seasonstate.seasonsouth {
Season::Spring => "spring",
Season::Summer => "summer",
Season::Autumn => "autumn",
Season::Winter => "winter",
};
let (sublat, sublon) = subsolarpoint(jd);
println!(
"Season: N={} S={} decl={:.2}° dayh={:.2} subsolar=({:.1},{:.1})",
seasonname,
southname,
seasonstate.solardeclinationdeg,
seasonstate.daylengthhours,
sublat,
sublon
);
println!(
" tilt={}° tropyear={}d vernaljd={}",
SEASONSTILT, TROPICALYEARDAYS, VERNALEQUINOXJD
);
let paris = LatLon::new(48.8566, 2.3522, 35.0);
let tokyo = LatLon::new(35.6762, 139.6503, 40.0);
let ecefparis = paris.toecef();
let cart = paris.tocartesiansimple();
let distpt = paris.distanceto(&tokyo);
let latlonback = ecefparis.tolatlon();
println!(
"Paris->ECEF: ({:.0},{:.0},{:.0}) cart=({:.0},{:.0},{:.0})",
ecefparis.x, ecefparis.y, ecefparis.z, cart[0], cart[1], cart[2]
);
println!(
" dist(Paris-Tokyo)={:.0}m roundtriplat={:.4}°",
distpt, latlonback.latdeg
);
println!(
" f={:.9} a={:.0}m b={:.3}m",
EARTHFLATTENING, EARTHSEMIMAJORM, EARTHSEMIMINORM
);
let regions = RegionDatabase::continents();
let region = regions.pointinregion(48.8, 2.3);
if let Some(r) = region {
let rtype = match r.regiontype {
RegionType::Continent => "continent",
RegionType::Ocean => "ocean",
RegionType::Sea => "sea",
RegionType::Country => "country",
RegionType::Island => "island",
};
println!(
"Region(48.8,2.3): {} ({}) area={:.0}km²",
r.name, rtype, r.areakm2
);
}
let elevprov = ElevationProvider::global(30.0);
let eleveverest = elevprov.sample(27.988, 86.925);
let notables = ElevationProvider::notableelevations();
println!(
"Elevation(Everest)={:.0}m notables={}",
eleveverest,
notables.len()
);
let bathy = BathymetryData::global(60.0);
let depthmariana = bathy.sample(11.35, 142.2);
let isocean = bathy.isocean(0.0, -30.0);
let stats = BathymetryData::oceanstats();
let basins = OceanBasin::majorbasins();
println!(
"Bathy(Mariana)={:.0}m isocean(0,-30)={} basins={} avgdepth={:.0}m",
depthmariana,
isocean,
basins.len(),
stats.avgdepthm
);
let mut hmap = Heightmap::new(64);
hmap.generateprocedural(42, 6, 0.5, 2.0);
let hsample = hmap.sample(45.0, 10.0);
let rat = hmap.radiusat(45.0, 10.0);
println!(
"Heightmap(64): sample(45,10)={:.1}m radius={:.0}m",
hsample, rat
);
let config = LodConfig::default();
let mut lod = LodTerrain::new(config);
lod.update([6371000.0 + 1000.0, 0.0, 0.0]);
let mesh = TerrainMesh::fromregion(0.0, 10.0, 0.0, 10.0, 8, &|lat, lon| hmap.sample(lat, lon));
println!(
"Mesh: {} vertices {} triangles",
mesh.vertexcount(),
mesh.trianglecount()
);
let classifier = BiomeClassifier::default();
let biome = classifier.classify(2000.0, 45.0, 0.6);
let biomename = match biome {
Biome::Ocean => "ocean",
Biome::Beach => "beach",
Biome::Desert => "desert",
Biome::Grassland => "grassland",
Biome::Forest => "forest",
Biome::Tundra => "tundra",
Biome::Snow => "snow",
Biome::Mountain => "mountain",
Biome::Volcanic => "volcanic",
Biome::Taiga => "taiga",
};
let splat = classifier.splat(2000.0, 45.0, 0.6);
println!(
"Biome(2000m,45°,0.6)={} splattop={:.2}",
biomename, splat.weights[0].1
);
let face = Face::PosZ;
println!("LOD face={:?}", face);
let matocean = PbrMaterial::ocean();
let matgrass = PbrMaterial::grassland();
let matdesert = PbrMaterial::desert();
let matsnow = PbrMaterial::snow();
let matrock = PbrMaterial::rock();
let matvolc = PbrMaterial::volcanic();
let matforest = PbrMaterial::forest();
let matice = PbrMaterial::ice();
println!(
"Materials: oceanrough={:.2} grassrough={:.2} desertmetal={:.2} \
snowrough={:.2} rock={:.2} volc={:.2} forest={:.2} ice={:.2}",
matocean.roughness,
matgrass.roughness,
matdesert.metallic,
matsnow.roughness,
matrock.roughness,
matvolc.roughness,
matforest.roughness,
matice.roughness
);
let shterrain = ShaderData::terrain();
let shatm = ShaderData::atmosphere();
let shocean = ShaderData::ocean();
println!(
"Shaders: terrain={} uniforms atm={} ocean={}",
shterrain.uniforms.len(),
shatm.uniforms.len(),
shocean.uniforms.len()
);
for u in &shterrain.uniforms {
let val = match &u.value {
UniformValue::Float(f) => format!("f{:.2}", f),
UniformValue::Vec3(v) => format!("v3({:.1},{:.1},{:.1})", v[0], v[1], v[2]),
UniformValue::Vec4(v) => format!("v4({:.1},{:.1},{:.1},{:.1})", v[0], v[1], v[2], v[3]),
UniformValue::Mat4(..) => "mat4".to_string(),
UniformValue::Int(i) => format!("i{}", i),
};
println!(" {}={}", u.name, val);
}
let atmparams = AtmosphereParams::default();
let raydens = atmparams.rayleighdensity(4000.0);
let miedens = atmparams.miedensity(600.0);
let scatr = atmparams.scatterrayleigh(0.5);
let scatm = atmparams.scattermie(0.5);
let sky = atmparams.skycolor([0.0, 1.0, 0.0], [0.0, 0.5, 0.866], 0.0);
println!(
"Atmosphere: ρray(4km)={:.4} ρmie(600m)={:.4} scatr={:.4} scatm={:.4}",
raydens, miedens, scatr, scatm
);
println!(" sky=({:.4},{:.4},{:.4})", sky[0], sky[1], sky[2]);
let oceanrdr = OceanParams::default();
let phillips = oceanrdr.phillipsspectrum(0.1, 0.05);
let spectrum = oceanrdr.generatespectrum();
let disp = oceanrdr.dispersion(0.1);
println!(
"Ocean render: phillips(0.1,0.05)={:.6} spectrumsize={} disp={:.4}",
phillips,
spectrum.heights.len(),
disp
);
let cumulus = CloudLayer::cumulus();
let stratus = CloudLayer::stratus();
let cirrus = CloudLayer::cirrus();
let cb = CloudLayer::cumulonimbus();
let cloudtype = |ct: &CloudType| match ct {
CloudType::Cumulus => "Cu",
CloudType::Stratus => "St",
CloudType::Cirrus => "Ci",
CloudType::Cumulonimbus => "Cb",
CloudType::Altocumulus => "Ac",
};
println!(
"Clouds: {} base={:.0}m {} base={:.0}m {} base={:.0}m {} base={:.0}m",
cloudtype(&cumulus.cloudtype),
cumulus.basealtitudem,
cloudtype(&stratus.cloudtype),
stratus.basealtitudem,
cloudtype(&cirrus.cloudtype),
cirrus.basealtitudem,
cloudtype(&cb.cloudtype),
cb.basealtitudem
);
let mut clouds = CloudSystem::earthdefault();
clouds.step(3600.0);
let density = clouds.sampledensity(5000.0, 45.0, 10.0);
println!("CloudSystem: density@5km={:.4}", density);
let rainforest = tropicalrainforest();
let boreal = borealforest();
let reef = coralreef();
println!("Ecosystems:");
for eco in [&rainforest, &boreal, &reef] {
let sp = eco.totalspecies();
let ind = eco.totalindividuals();
let shannon = eco.shannonindex();
let simpson = eco.simpsondiversity();
let areasp = eco.expectedspeciesfromarea(0.25, 100.0);
let npp = eco.totalnppgcyr();
let turnover = eco.biomassturnovertimeyr(15000.0);
println!(
" {} species {} ind H'={:.2} D={:.4} SAR={:.0} NPP={:.0} τ={:.1}yr",
sp, ind, shannon, simpson, areasp, npp, turnover
);
}
let tb = tropicalbroadleaf();
let tg = temperategrassland();
let cf = coniferousforest();
let photo = tb.photosynthesisrate(400.0, 1500.0, 28.0);
let canopy = tb.canopyphotosynthesis(photo);
let transp = tg.transpirationmmday(1.5, 0.3);
let nppveg = cf.nppkgcm2yr(15.0);
let crt = cf.carbonresidencetimeyr(nppveg);
let light = beerlambertlightextinction(2000.0, 4.0, 0.5);
println!(
"Vegetation: photo={:.2} canopy={:.2} transp={:.2}mm/d NPP={:.3} CRT={:.1}yr light={:.1}",
photo, canopy, transp, nppveg, crt, light
);
let elephant = africanelephant();
let whale = bluewhale();
let grel = elephant.growthrate();
let proj = elephant.projectforward(10.0);
let metab = whale.metabolicratew();
let range = elephant.homerangekm2();
let gentime = whale.generationtimeyears();
let lifespan = elephant.maxlifespanyears();
println!(
"Elephant: r={:.3} N(+10yr)={:.0} range={:.1}km² lifespan={:.0}yr",
grel, proj, range, lifespan
);
println!("Whale: metab={:.0}W gen={:.1}yr", metab, gentime);
let mut pp = PredatorPrey {
prey: africanelephant(),
predator: bluewhale(),
attackrate: 0.01,
conversionefficiency: 0.1,
predatordeathrate: 0.05,
};
let preyr = pp.preygrowthrate();
let predr = pp.predatorgrowthrate();
pp.step(0.1);
println!(
"Lotka-Volterra: preyr={:.1} predr={:.1} -> prey={:.1} pred={:.2}",
preyr, predr, pp.prey.count, pp.predator.count
);
}