mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 10:59:20 +02:00
* refactor(sonar): use override instead of redundant virtual (cpp:S3471) * refactor(sonar): remove empty statements, one declaration per statement (cpp:S1116, cpp:S1659) * refactor(sonar): drop redundant lambda return types (cpp:S3574) * refactor(sonar): prefer using over typedef (cpp:S5416) * refactor(sonar): use =default for trivial special members (cpp:S3490) * refactor(sonar): use nullptr literal (cpp:S4962) * refactor(sonar): remove redundant access specifiers (cpp:S3539) * refactor(sonar): remove redundant casts (cpp:S1905) * refactor(sonar): use std::scoped_lock instead of std::lock_guard (cpp:S5997) * refactor(sonar): construct elements in place with emplace_back (cpp:S6003) * refactor(sonar): make narrowing conversions explicit (cpp:S5276) * refactor(sonar): mark unused parameters (cpp:S1172) Unused names are commented out; parameters used only on some platforms are marked [[maybe_unused]]. * refactor(sonar): declare non-mutating member functions const (cpp:S5817) Virtual functions are left untouched so overrides keep matching. * refactor(sonar): merge collapsible nested if statements (cpp:S1066) Comments that preceded the inner if are kept above the merged statement. * refactor(sonar): scope single-use variables in if init-statements (cpp:S6004) * fix(sonar): give polymorphic base classes virtual destructors (cpp:S1235) * refactor(sonar): use try_emplace for map insertion (cpp:S6030) * refactor(sonar): use auto where the type is spelled out on the right (cpp:S5827) * refactor(sonar): remove redundant parentheses (cpp:S1110) * refactor(sonar): document intentionally empty functions (cpp:S1186) * refactor(sonar): remove dead stores (cpp:S1854) Side effects (e.g. LISTLINE++) are kept. * refactor(sonar): remove unused variables, captures and private fields (cpp:S1481, cpp:S1068) * refactor(sonar): use structured bindings for pair access (cpp:S6005) * refactor(sonar): use range-based loops and ranges algorithms (cpp:S5566) * refactor(sonar): split chained assignments (cpp:S1121) * refactor(sonar): add default cases to switch statements (cpp:S3562) * refactor(sonar): use std::size for array lengths (cpp:S7127) * refactor(sonar): use std::ranges algorithms and std::erase(_if) (cpp:S6197) * refactor(sonar): access static members through the class (cpp:S2209) * refactor(sonar): add braces around nested if-else (cpp:S5261) * refactor(sonar): avoid side effects inside typeid operands (cpp:S5279) * refactor(sonar): drop top-level const from by-value return types (cpp:S5951) * refactor(sonar): declare variables separately from their type definitions (cpp:S3646) * refactor(sonar): declare loop counters in the for statement (cpp:S5955) * refactor(sonar): rely on class template argument deduction (cpp:S6012) * refactor(sonar): inherit base constructors instead of forwarding them (cpp:S5952) * refactor(sonar): rename locals that shadow outer declarations (cpp:S1117) Only local variables and definition parameters are renamed; shadowing struct fields and enumerators in headers are left for a separate change. * refactor(sonar): reduce enum qualification with using enum (cpp:S6177) Applied only where no unqualified name in the block could be captured by the introduced enumerators. * refactor(sonar): mark converting constructors explicit (cpp:S1709) sound_source and the gl::object conversion operators stay implicit; they are relied upon by copy-list-initialisation and GL calls. * refactor(sonar): initialise members in initialiser lists or declarations (cpp:S3230) * refactor(sonar): make read-only local references and pointers const (cpp:S5350) * refactor(sonar): take read-only pointer and reference parameters as const (cpp:S995) TTrain command handlers keep their signature, it is fixed by the handler table. * refactor(sonar): pass expensive-to-copy parameters by const reference (cpp:S1238) Signatures declared in files touched by PR 206 (Driver.h, EU07.cpp) and virtual overrides are left unchanged. * refactor(sonar): use transparent comparators for string-keyed maps (cpp:S6045) std::unordered_map instances and map types exposed in headers used by other modules are left as they are. * fix(sonar): do not use UI text as a printf format string (cpp:S5281) Text lines containing '%' would otherwise be interpreted as format specifiers by ImGui::TextColored. * refactor(sonar): use std::bind_front for callbacks (cpp:S5995) * refactor(sonar): drop const_cast on string literals passed to the Python C API (cpp:S859) * refactor(sonar): take read-only string parameters as std::string_view (cpp:S6009) The Windows messaging helpers keep std::string, they need c_str(). * refactor(sonar): make read-only global tables const (cpp:S5421) Mutable global state (flags, timers, singletons) is left as is. * refactor(sonar): replace single-case switch statements with if (cpp:S1301) * refactor(sonar): format UUIDs and log timestamps with std::format (cpp:S6494, cpp:S5945) * refactor(sonar): use std::array for local fixed-size arrays (cpp:S5945) Arrays that are class members or part of headers are left unchanged. * fix(sonar): test the bearing damage bit, not bit 0 (cpp:S872) 'DamageFlag & dtrain_bearing > 0' parsed as 'DamageFlag & (dtrain_bearing > 0)', i.e. DamageFlag & 1, so bearing friction reacted to the wrong damage flag. * refactor(sonar): assorted small fixes - empty() instead of size() comparisons (cpp:S1155) - member initialisers in declaration order (cpp:S3229) - no redundant c_str() when a std::string is accepted (cpp:S7121) - contains() on associative containers (cpp:S6171) - const reference instead of a copying range-for (cpp:S6032) - starts_with() for prefix checks (cpp:S6178) - no std::move on temporaries (cpp:S5274) - has_value() on std::optional (cpp:S7172) - bool literals for bool members (cpp:S5820) - inline only on the definition (cpp:S3548) - explicit base access specifier (cpp:S5965) - explicit element access instead of dereferencing an array (cpp:S7116) - rely on the C++20 rewritten operator!= (cpp:S6186) * refactor(sonar): more small fixes - std::format instead of iostream manipulators in to_string/to_hex_str (cpp:S6495); output verified identical, negative hex values keep the unsigned form - remove an empty compound statement (cpp:S108) - drop an always-false unsigned < 0 branch (cpp:S1768) - explicit lambda capture (cpp:S3608) - std::make_unique (cpp:S5950) * chore: strip stray carriage returns left in TTrain constructor comments * fix: keep quantize() in its own value type The S5276 change cast the result of the generic quantize<Type_>() to unsigned int, which truncated float/double callers (shadow angle slider, editor rotation snapping, AI speed control steps) and broke negative values. * fix(sonar): use integer loop counters in segment sampling (cpp:S2193) * refactor(sonar): clean up issues reported on PR 209 - remove locals left unused after the dead-store cleanup (cpp:S1481, cpp:S1854) - unnamed unused parameter (cpp:S1172) - single-use declarations moved into if init-statements (cpp:S6004) - auto for casted initialisers (cpp:S5827) - const references and pointers where nothing is modified (cpp:S5350) - rename structured bindings shadowed by inner declarations (cpp:S1117)
308 lines
12 KiB
C++
308 lines
12 KiB
C++
#include "stdafx.h"
|
|
#include "environment/moon.h"
|
|
#include "utilities/Globals.h"
|
|
#include "world/mtable.h"
|
|
#include "utilities/utilities.h"
|
|
#include "simulation/simulationtime.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// cSun -- class responsible for dynamic calculation of position and intensity of the Sun,
|
|
|
|
cMoon::cMoon() {
|
|
|
|
setLocation( 19.00f, 52.00f ); // default location roughly in centre of Poland
|
|
m_observer.press = 1013.0; // surface pressure, millibars
|
|
m_observer.temp = 15.0; // ambient dry-bulb temperature, degrees C
|
|
}
|
|
|
|
cMoon::~cMoon() = default;
|
|
|
|
void
|
|
cMoon::init() {
|
|
|
|
m_observer.timezone = -1.0 * simulation::Time.zone_bias();
|
|
// NOTE: we're calculating phase just once, because it's unlikely simulation will last a few days,
|
|
// plus a sudden texture change would be pretty jarring
|
|
phase();
|
|
}
|
|
|
|
void
|
|
cMoon::update( bool const Includephase ) {
|
|
|
|
m_observer.temp = Global.AirTemperature;
|
|
|
|
move();
|
|
if( Includephase ) { phase(); }
|
|
glm::vec3 position( 0.f, 0.f, -1.f );
|
|
position = glm::rotateX( position, glm::radians( static_cast<float>( m_body.elevref ) ) );
|
|
position = glm::rotateY( position, glm::radians( static_cast<float>( -m_body.hrang ) ) );
|
|
|
|
m_position = glm::normalize( position );
|
|
}
|
|
|
|
void
|
|
cMoon::render() {
|
|
|
|
//m7t
|
|
}
|
|
|
|
glm::vec3
|
|
cMoon::getDirection() const {
|
|
|
|
return m_position;
|
|
}
|
|
|
|
float
|
|
cMoon::getAngle() const {
|
|
|
|
return (float)m_body.elevref;
|
|
}
|
|
|
|
float cMoon::getIntensity() {
|
|
|
|
irradiance();
|
|
// NOTE: we don't have irradiance model for the moon so we cheat here
|
|
// calculating intensity of the sun instead, and returning 15% of the value,
|
|
// which roughly matches how much sunlight is reflected by the moon
|
|
// We alter the intensity further based on current phase of the moon
|
|
auto const phasefactor = 1.0f - std::abs( m_phase - 29.53f * 0.5f ) / ( 29.53f * 0.5f );
|
|
return static_cast<float>( m_body.etr / 1399.0 * phasefactor * 0.15 ); // arbitrary scaling factor taken from etrn value
|
|
}
|
|
|
|
void cMoon::setLocation( float const Longitude, float const Latitude ) {
|
|
|
|
// convert fraction from geographical base of 6o minutes
|
|
m_observer.longitude = (int)Longitude + (Longitude - static_cast<float>((int)Longitude)) * 100.0 / 60.0;
|
|
m_observer.latitude = (int)Latitude + (Latitude - static_cast<float>((int)Latitude)) * 100.0 / 60.0 ;
|
|
}
|
|
|
|
// sets current time, overriding one acquired from the system clock
|
|
void cMoon::setTime( int const Hour, int const Minute, int const Second ) {
|
|
|
|
m_observer.hour = std::clamp( Hour, -1, 23 );
|
|
m_observer.minute = std::clamp( Minute, -1, 59 );
|
|
m_observer.second = std::clamp( Second, -1, 59 );
|
|
}
|
|
|
|
void cMoon::setTemperature( float const Temperature ) {
|
|
|
|
m_observer.temp = Temperature;
|
|
}
|
|
|
|
void cMoon::setPressure( float const Pressure ) {
|
|
|
|
m_observer.press = Pressure;
|
|
}
|
|
|
|
void cMoon::move() {
|
|
|
|
static double radtodeg = 57.295779513; // converts from radians to degrees
|
|
static double degtorad = 0.0174532925; // converts from degrees to radians
|
|
|
|
SYSTEMTIME localtime = simulation::Time.data(); // time for the calculation
|
|
|
|
if( m_observer.hour >= 0 ) { localtime.wHour = static_cast<uint16_t>(m_observer.hour); }
|
|
if( m_observer.minute >= 0 ) { localtime.wMinute = static_cast<uint16_t>(m_observer.minute); }
|
|
if( m_observer.second >= 0 ) { localtime.wSecond = static_cast<uint16_t>(m_observer.second); }
|
|
|
|
double localut =
|
|
localtime.wHour
|
|
+ localtime.wMinute / 60.0 // too low resolution, noticeable skips
|
|
+ localtime.wSecond / 3600.0; // good enough in normal circumstances
|
|
/*
|
|
+ localtime.wMilliseconds / 3600000.0; // for really smooth movement
|
|
*/
|
|
double daynumber
|
|
= 367 * localtime.wYear
|
|
- 7 * ( localtime.wYear + ( localtime.wMonth + 9 ) / 12 ) / 4
|
|
+ 275 * localtime.wMonth / 9
|
|
+ localtime.wDay
|
|
- 730530
|
|
+ localut / 24.0;
|
|
|
|
// Universal Coordinated (Greenwich standard) time
|
|
m_observer.utime = localut - m_observer.timezone;
|
|
|
|
// obliquity of the ecliptic
|
|
m_body.oblecl = clamp_circular( 23.4393 - 3.563e-7 * daynumber );
|
|
// moon parameters
|
|
double longascnode = clamp_circular( 125.1228 - 0.0529538083 * daynumber ); // N, degrees
|
|
double const inclination = 5.1454; // i, degrees
|
|
double const mndistance = 60.2666; // a, in earth radii
|
|
// argument of perigee
|
|
double const perigeearg = clamp_circular( 318.0634 + 0.1643573223 * daynumber ); // w, degrees
|
|
// mean anomaly
|
|
m_body.mnanom = clamp_circular( 115.3654 + 13.0649929509 * daynumber ); // M, degrees
|
|
// eccentricity
|
|
double constexpr e = 0.054900;
|
|
// eccentric anomaly
|
|
double E0 = m_body.mnanom + radtodeg * e * std::sin( degtorad * m_body.mnanom ) * ( 1.0 + e * std::cos( degtorad * m_body.mnanom ) );
|
|
double E1 = E0 - ( E0 - radtodeg * e * std::sin( degtorad * E0 ) - m_body.mnanom ) / ( 1.0 - e * std::cos( degtorad * E0 ) );
|
|
while( std::abs( E0 - E1 ) > 0.005 ) { // arbitrary precision tolerance threshold
|
|
E0 = E1;
|
|
E1 = E0 - ( E0 - radtodeg * e * std::sin( degtorad * E0 ) - m_body.mnanom ) / ( 1.0 - e * std::cos( degtorad * E0 ) );
|
|
}
|
|
double const E = E1;
|
|
// lunar orbit plane rectangular coordinates
|
|
double const xv = mndistance * ( std::cos( degtorad * E ) - e );
|
|
double const yv = mndistance * std::sin( degtorad * E ) * std::sqrt( 1.0 - sq(e) );
|
|
// distance
|
|
m_body.distance = std::sqrt( xv*xv + yv*yv ); // r
|
|
// true anomaly
|
|
m_body.tranom = clamp_circular( radtodeg * std::atan2( yv, xv ) ); // v
|
|
// ecliptic rectangular coordinates
|
|
double const vpluswinrad = degtorad * ( m_body.tranom + perigeearg );
|
|
double const xeclip = m_body.distance * ( std::cos( degtorad * longascnode ) * std::cos( vpluswinrad ) - std::sin( degtorad * longascnode ) * std::sin( vpluswinrad ) * std::cos( degtorad * inclination ) );
|
|
double const yeclip = m_body.distance * ( std::sin( degtorad * longascnode ) * std::cos( vpluswinrad ) + std::cos( degtorad * longascnode ) * std::sin( vpluswinrad ) * std::cos( degtorad * inclination ) );
|
|
double const zeclip = m_body.distance * std::sin( vpluswinrad ) * std::sin( degtorad * inclination );
|
|
// ecliptic coordinates
|
|
m_body.eclong = clamp_circular( radtodeg * std::atan2( yeclip, xeclip ) );
|
|
// distance
|
|
m_body.distance = std::sqrt( xeclip*xeclip + yeclip*yeclip + zeclip*zeclip );
|
|
// perturbations
|
|
// NOTE: perturbation calculation can be safely disabled if we don't mind error of 1-2 degrees
|
|
// Sun's mean anomaly: Ms (already computed)
|
|
double const sunmnanom = clamp_circular( 356.0470 + 0.9856002585 * daynumber ); // M
|
|
// Sun's mean longitude: Ls (already computed)
|
|
double const sunphlong = clamp_circular( 282.9404 + 4.70935e-5 * daynumber );
|
|
double const sunmnlong = clamp_circular( sunphlong + sunmnanom ); // L = w + M
|
|
// Moon's mean anomaly: Mm (already computed)
|
|
// Moon's mean longitude: Lm = N + w + M (for the Moon)
|
|
m_body.mnlong = clamp_circular( longascnode + perigeearg + m_body.mnanom );
|
|
// Moon's mean elongation: D = Lm - Ls
|
|
double const mnelong = clamp_circular( m_body.mnlong - sunmnlong );
|
|
// longitude perturbations
|
|
double const pertevection = -1.274 * std::sin( degtorad * ( m_body.mnanom - 2.0 * mnelong ) ); // Evection
|
|
double const pertvariation = +0.658 * std::sin( degtorad * ( 2.0 * mnelong ) ); // Variation
|
|
double const pertyearlyeqt = -0.186 * std::sin( degtorad * sunmnanom ); // Yearly equation
|
|
// latitude perturbations
|
|
|
|
m_body.eclong += pertevection + pertvariation + pertyearlyeqt;
|
|
// declination
|
|
m_body.declin = radtodeg * std::asin( std::sin (m_body.oblecl * degtorad) * std::sin(m_body.eclong * degtorad) );
|
|
|
|
// right ascension
|
|
double top = std::cos( degtorad * m_body.oblecl ) * std::sin( degtorad * m_body.eclong );
|
|
double bottom = std::cos( degtorad * m_body.eclong );
|
|
m_body.rascen = clamp_circular( radtodeg * std::atan2( top, bottom ) );
|
|
|
|
// Greenwich mean sidereal time
|
|
m_observer.gmst = 6.697375 + 0.0657098242 * daynumber + m_observer.utime;
|
|
|
|
m_observer.gmst -= 24.0 * (int)( m_observer.gmst / 24.0 );
|
|
if( m_observer.gmst < 0.0 ) m_observer.gmst += 24.0;
|
|
|
|
// local mean sidereal time
|
|
m_observer.lmst = m_observer.gmst * 15.0 + m_observer.longitude;
|
|
|
|
m_observer.lmst -= 360.0 * (int)( m_observer.lmst / 360.0 );
|
|
if( m_observer.lmst < 0.0 ) m_observer.lmst += 360.0;
|
|
|
|
// hour angle
|
|
m_body.hrang = m_observer.lmst - m_body.rascen;
|
|
|
|
if( m_body.hrang < -180.0 ) m_body.hrang += 360.0; // (force it between -180 and 180 degrees)
|
|
else if( m_body.hrang > 180.0 ) m_body.hrang -= 360.0;
|
|
|
|
double cz; // cosine of the solar zenith angle
|
|
|
|
double tdatcd = std::cos( degtorad * m_body.declin );
|
|
double tdatch = std::cos( degtorad * m_body.hrang );
|
|
double tdatcl = std::cos( degtorad * m_observer.latitude );
|
|
double tdatsd = std::sin( degtorad * m_body.declin );
|
|
double tdatsl = std::sin( degtorad * m_observer.latitude );
|
|
|
|
cz = tdatsd * tdatsl + tdatcd * tdatcl * tdatch;
|
|
|
|
// (watch out for the roundoff errors)
|
|
if( fabs (cz) > 1.0 ) { cz >= 0.0 ? cz = 1.0 : cz = -1.0; }
|
|
|
|
m_body.zenetr = std::acos( cz ) * radtodeg;
|
|
m_body.elevetr = 90.0 - m_body.zenetr;
|
|
refract();
|
|
}
|
|
|
|
void cMoon::refract() {
|
|
|
|
static double degtorad = 0.0174532925; // converts from degrees to radians
|
|
|
|
double prestemp; // temporary pressure/temperature correction
|
|
double refcor; // temporary refraction correction
|
|
double tanelev; // tangent of the solar elevation angle
|
|
|
|
// if the sun is near zenith, the algorithm bombs; refraction near 0.
|
|
if( m_body.elevetr > 85.0 )
|
|
refcor = 0.0;
|
|
else {
|
|
|
|
tanelev = tan( degtorad * m_body.elevetr );
|
|
if( m_body.elevetr >= 5.0 )
|
|
refcor = 58.1 / tanelev
|
|
- 0.07 / pow( tanelev, 3 )
|
|
+ 0.000086 / pow( tanelev, 5 );
|
|
else if( m_body.elevetr >= -0.575 )
|
|
refcor = 1735.0
|
|
+ m_body.elevetr * ( -518.2 + m_body.elevetr *
|
|
( 103.4 + m_body.elevetr * ( -12.79 + m_body.elevetr * 0.711 ) ) );
|
|
else
|
|
refcor = -20.774 / tanelev;
|
|
|
|
prestemp = m_observer.press * 283.0 / ( 1013.0 * ( 273.0 + m_observer.temp ) );
|
|
refcor *= prestemp / 3600.0;
|
|
}
|
|
|
|
// refracted solar elevation angle
|
|
m_body.elevref = m_body.elevetr + refcor;
|
|
|
|
// refracted solar zenith angle
|
|
m_body.zenref = 90.0 - m_body.elevref;
|
|
}
|
|
|
|
void cMoon::irradiance() {
|
|
|
|
static double degtorad = 0.0174532925; // converts from degrees to radians
|
|
|
|
m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
|
|
double sd = sin( degtorad * m_body.dayang ); // sine of the day angle
|
|
double cd = cos( degtorad * m_body.dayang ); // cosine of the day angle or delination
|
|
m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
|
|
double d2 = 2.0 * m_body.dayang;
|
|
double c2 = cos( degtorad * d2 );
|
|
double s2 = sin( degtorad * d2 );
|
|
m_body.erv += 0.000719*c2 + 0.000077*s2;
|
|
|
|
double solcon = 1367.0; // Solar constant, 1367 W/sq m
|
|
|
|
m_body.coszen = cos( degtorad * m_body.zenref );
|
|
if( m_body.coszen > 0.0 ) {
|
|
m_body.etrn = solcon * m_body.erv;
|
|
m_body.etr = m_body.etrn * m_body.coszen;
|
|
}
|
|
else {
|
|
m_body.etrn = 0.0;
|
|
m_body.etr = 0.0;
|
|
}
|
|
}
|
|
|
|
void
|
|
cMoon::phase() {
|
|
SYSTEMTIME lt = simulation::Time.data();
|
|
if (lt.wMonth == 5 && lt.wDay == 4) //May the forth be with you!
|
|
m_phase = 50;
|
|
else {
|
|
// calculate moon's age in days from new moon
|
|
float ip = normalize( ( static_cast<float>(simulation::Time.julian_day()) - 2451550.1f ) / 29.530588853f );
|
|
m_phase = ip * 29.53f;
|
|
}
|
|
}
|
|
|
|
// normalize values to range 0...1
|
|
float
|
|
cMoon::normalize( const float Value ) const {
|
|
|
|
auto value = static_cast<float>(Value - floor( Value ));
|
|
if( value < 0.f ) { ++value; }
|
|
|
|
return value;
|
|
}
|