├── .github └── FUNDING.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE.md ├── Makefile ├── README.md ├── data ├── cities.csv ├── cities_with_state.csv ├── countries.csv ├── create_arrays.py ├── create_json.py └── timezones.csv ├── docs ├── 00.jpg ├── CMakeLists.txt ├── mainpage.md └── ptolemaicsystem.png ├── hypatia.i ├── include └── hypatia │ ├── Body.h │ ├── Constellation.h │ ├── CoordOps.h │ ├── GeoOps.h │ ├── Luna.h │ ├── MathOps.h │ ├── Observer.h │ ├── ProjOps.h │ ├── Satellite.h │ ├── Star.h │ ├── TimeOps.h │ ├── coordinates │ ├── ECI.h │ ├── Ecliptic.h │ ├── Equatorial.h │ ├── Galactic.h │ ├── Geodetic.h │ ├── Horizontal.h │ ├── PrecessionMatrix.h │ ├── Tile.h │ └── UTM.h │ ├── models │ ├── Exception.h │ ├── Orbit.h │ ├── Pluto.h │ ├── SGP4.h │ ├── TLE.h │ └── VSOP87.h │ └── primitives │ ├── DateTime.h │ ├── Matrix3x3.h │ ├── Polar.h │ ├── TimeSpan.h │ ├── Vector2.h │ └── Vector3.h ├── numpy.i ├── setup.py ├── src ├── Body.cpp ├── CMakeLists.txt ├── Constellation.cpp ├── CoordOps.cpp ├── GeoOps.cpp ├── Luna.cpp ├── MathOps.cpp ├── Observer.cpp ├── ProjOps.cpp ├── Satellite.cpp ├── Star.cpp ├── TimeOps.cpp ├── coordinates │ ├── ECI.cpp │ ├── Ecliptic.cpp │ ├── Equatorial.cpp │ ├── Galactic.cpp │ ├── Geodetic.cpp │ ├── Horizontal.cpp │ ├── PrecessionMatrix.cpp │ └── Tile.cpp ├── models │ ├── Orbit.cpp │ ├── Pluto.cpp │ ├── SGP4.cpp │ ├── TLE.cpp │ └── VSOP87.cpp └── primitives │ ├── DateTime.cpp │ ├── Matrix3x3.cpp │ ├── Polar.cpp │ ├── TimeSpan.cpp │ ├── Vector2.cpp │ └── Vector3.cpp └── tests ├── AstroOps.py ├── Body.py ├── MathOps.py └── TimeOps.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [patriciogonzalezvivo] 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.so 4 | build/* 5 | hypatia_wrap.cxx 6 | hypatia.py -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | # Project name and a few useful settings. Other commands can pick up the results 4 | project(hypatia 5 | VERSION 0.2 6 | DESCRIPTION "a Geo-Astronomical library for artist" 7 | LANGUAGES CXX) 8 | 9 | add_compile_options(-std=c++14 -fpermissive -Wno-psabi) 10 | 11 | # Only do these if this is the main project, and not if it is included through add_subdirectory 12 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 13 | 14 | # Optionally set things like CMAKE_CXX_STANDARD, CMAKE_POSITION_INDEPENDENT_CODE here 15 | 16 | # Let's ensure -std=c++xx instead of -std=g++xx 17 | set(CMAKE_CXX_EXTENSIONS OFF) 18 | 19 | # Let's nicely support folders in IDE's 20 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 21 | 22 | # Docs only available if this is the main app 23 | find_package(Doxygen) 24 | if(Doxygen_FOUND) 25 | add_subdirectory(docs) 26 | else() 27 | message(STATUS "Doxygen not found, not building docs") 28 | endif() 29 | endif() 30 | 31 | # The compiled library code is here 32 | add_subdirectory(src) 33 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The code in this repository is available under the [MIT License](https://secure.wikimedia.org/wikipedia/en/wiki/Mit_license). 2 | 3 | Copyright (c) 2025 Patricio Gonzalez Vivo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | scripts=$(wildcard test/*.py) 2 | 3 | install: 4 | swig -c++ -python hypatia.i 5 | python3 setup.py build_ext --inplace 6 | $(LIB) 7 | @rm -rf build 8 | sudo python3 setup.py install 9 | 10 | clean: 11 | @rm -rvf $(LIB) *.o */*.o *.so hypatia.py* hypatia_wrap.c* build 12 | 13 | test: $(scripts) 14 | 15 | $(scripts): hypatia.py 16 | @python $@ 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](docs/00.jpg) 2 | 3 | # HYPATIA [![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86)](https://github.com/sponsors/patriciogonzalezvivo) 4 | 5 | Hypatia is a geo-astronomical library based on the work of [Jean Meeus](https://en.wikipedia.org/wiki/Jean_Meeus), [Mark Huss](http://mhuss.com/AstroLib), [Bill Gray](https://github.com/Bill-Gray ), [Stuart Lowe](http://mhuss.com/AstroLib), [Brandon Rhodes](https://github.com/brandon-rhodes/pyephem) , [Daniel Warner](https://github.com/dnwrnr/sgp4), [Oliver Montenbruck and Thomas Peleger](https://www.amazon.com/gp/product/3540672214/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1). Was created mostly for educational purposes, but also to use in different personal artistic projects. 6 | 7 | In comparison with other astronomical/geographical libraries created for profesional uses Hypatia have a focus on: 8 | * reusability and portability 9 | * realtime performance 10 | * simplicity of the interface, than other 11 | 12 | ## Hypatia as C++ lib 13 | 14 | You can easily add hypatia into your project by adding the `include/` and `src/` folder or by installing hypatia into your system. For the former option you need to: 15 | 16 | ```bash 17 | sudo apt install cmake swig 18 | mkdir build 19 | cd build 20 | cmake .. 21 | make 22 | sudo make install 23 | ``` 24 | 25 | ```cpp 26 | #include 27 | 28 | #include "hypatia/Body.h" 29 | #include "hypatia/Luna.h" 30 | #include "hypatia/Constellation.h" 31 | 32 | void main(int argc, char **argv) { 33 | 34 | obs = Observer(40.781098831465, -73.97715657655); 35 | 36 | sun = Body(SUN); 37 | moon = Luna(LUNA); 38 | std::cout << "Moon's phase: " << moon.getPhase() << std::endl 39 | 40 | const = Constellation(moon) 41 | std::cout << "Moon's transit constelation: " << const.getName() << std::endl 42 | 43 | return 0; 44 | } 45 | ``` 46 | 47 | ## Hypatia as Python module 48 | 49 | First you need to create the package and install it 50 | 51 | ```bash 52 | sudo apt install swig 53 | make install 54 | ``` 55 | 56 | **Note**: to install inside anaconda do: 57 | ```bash 58 | /anaconda3/bin/./python3.7 setup.py install 59 | ``` 60 | 61 | Then you can use it as follow: 62 | 63 | ```python 64 | from hypatia import * 65 | 66 | obs = Observer(40.781098831465, -73.97715657655) 67 | 68 | sun = Body(SUN) 69 | sun.compute(obs) 70 | 71 | moon = Luna(LUNA) 72 | moon.compute(obs) 73 | print("Moon's phase: ", const.getPhase()) 74 | 75 | const = Constellation(moon) 76 | print("Moon's transit constelation: ", const.getName()) 77 | ``` 78 | -------------------------------------------------------------------------------- /data/create_arrays.py: -------------------------------------------------------------------------------- 1 | 2 | # Load timezones.csv 3 | import csv 4 | import os 5 | import sys 6 | 7 | SECONDS_PER_MINUTE = 60 8 | MINUTES_PER_HOUR = 60 9 | HOURS_PER_DAY = 24 10 | SECONDS_PER_DAY = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY 11 | MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY 12 | DAYS_PER_MINUTE = 1.0 / MINUTES_PER_DAY 13 | DAYS_PER_SECOND = 1.0 / SECONDS_PER_DAY 14 | 15 | continents = [] 16 | timezones = [] 17 | countries_name = [] 18 | countries_alpha2 = [] 19 | cities = [] 20 | 21 | def load_timezones(): 22 | filename = os.path.join(os.path.dirname(__file__), 'timezones.csv'); 23 | with open(filename, 'r') as f: 24 | reader = csv.reader(f) 25 | for row in reader: 26 | # Skip header 27 | if row[0].startswith('timezone'): 28 | continue 29 | tz_name = row[0].strip() 30 | timezones.append(tz_name) 31 | 32 | def load_countries(): 33 | filename = os.path.join(os.path.dirname(__file__), 'countries.csv'); 34 | with open(filename, 'r') as f: 35 | reader = csv.reader(f) 36 | for row in reader: 37 | # Skip header 38 | if row[0].startswith('name'): 39 | continue 40 | 41 | country_name = row[0].strip() 42 | if country_name.startswith('"') and country_name.endswith('"'): 43 | print(f"{country_name} has quotes") 44 | country_name = country_name[1:-1] 45 | 46 | country_alpha2 = row[1].strip() 47 | country_continent = row[5].strip() 48 | if (country_continent not in continents): 49 | continents.append(country_continent) 50 | countries_name.append(country_name) 51 | countries_alpha2.append(country_alpha2) 52 | 53 | 54 | def load_cities(): 55 | filename = os.path.join(os.path.dirname(__file__), 'cities.csv'); 56 | with open(filename 57 | , 'r') as f: 58 | reader = csv.reader(f) 59 | for row in reader: 60 | # Skip header 61 | if row[0].startswith('country'): 62 | continue 63 | city_country = row[0].strip() 64 | city_state = row[1].strip() 65 | city_name = row[2].strip() 66 | 67 | # convert city_name characters into the ASCII range 68 | city_name = city_name 69 | city_name = city_name.encode('ascii', 'ignore').decode('ascii') 70 | 71 | city_lat = float(row[3].strip()) 72 | city_lon = float(row[4].strip()) 73 | city_tz = row[5].strip() 74 | city_alt_m = float(row[6].strip()) 75 | 76 | if city_tz not in timezones: 77 | print(f"Timezone {city_tz} not found in timezones.csv") 78 | continue 79 | 80 | if city_country not in countries_alpha2: 81 | print(f"Country {city_country} not found in countries.csv") 82 | continue 83 | 84 | city_tz_index = timezones.index(city_tz) 85 | city_country_index = countries_alpha2.index(city_country) 86 | cities.append( [city_name, city_lat, city_lon, city_tz_index, city_country_index, city_alt_m] ) 87 | 88 | # city[city_name] = [ city_lat, city_lon, city_tz_index, city_country, city_state ] 89 | # print(f"City {city_name} loaded with timezone {city_tz}") 90 | 91 | load_timezones() 92 | load_countries() 93 | load_cities() 94 | 95 | # open a file call countries.txt in write mode 96 | with open('countries.h', 'w') as f: 97 | f.write("const size_t N_COUNTRIES = " + str(len(countries_name)) + ";\n") 98 | f.write("const char* countries[N_COUNTRIES] = {\n") 99 | for country in countries_name: 100 | f.write("(char*)\"" + country + "\", ") 101 | f.write("\n};\n") 102 | 103 | f.write("const char countries_alpha2[N_COUNTRIES][2] = {\n") 104 | for country in countries_alpha2: 105 | f.write("{\'" + country[0] + "\',\'" + country[1] + "\'},") 106 | f.write("\n};\n") 107 | 108 | # open a file call cities.txt in write mode 109 | with open('cities.h', 'w') as f: 110 | f.write("const size_t N_CITIES = " + str(len(cities)) + ";\n") 111 | f.write("const char* cities[N_CITIES] = {\n") 112 | for city in cities: 113 | f.write("(char*)\"" + city[0] + "\", ") 114 | f.write("\n};\n") 115 | 116 | f.write("const double cities_loc[N_CITIES][2] = {\n") 117 | for city in cities: 118 | f.write("{" + str(city[1]) + "," + str(city[2]) + "},") 119 | f.write("\n};\n") 120 | f.write("const size_t cities_tz[N_CITIES] = {\n") 121 | for city in cities: 122 | f.write(str(city[3]) + ",") 123 | f.write("\n};\n") 124 | f.write("const size_t cities_country[N_CITIES] = {\n") 125 | for city in cities: 126 | f.write(str(city[4]) + ",") 127 | f.write("\n};\n") 128 | 129 | f.write("const double cities_alt[N_CITIES] = {\n") 130 | for city in cities: 131 | f.write(str(int(city[5])) + ",") 132 | f.write("\n};\n") -------------------------------------------------------------------------------- /data/create_json.py: -------------------------------------------------------------------------------- 1 | 2 | # make a python script that creates a json from the cities.csv, which contains the name of the city, the state, and the country and their lat and long to then be use by the JS frontend in a fuzzy search 3 | 4 | import csv 5 | import json 6 | 7 | # Create a list to hold the city data 8 | cities = [] 9 | 10 | FILE = 'cities.csv' 11 | # FILE = 'cities_with_state.csv' 12 | 13 | # Open the CSV file and read the data 14 | with open(FILE, 'r') as csvfile: 15 | reader = csv.DictReader(csvfile) 16 | for row in reader: 17 | # Create a dictionary for each city and append it to the list 18 | 19 | # sanizite the string for unicode 20 | row['name'] = row['name'].encode('utf-8').decode('utf-8') 21 | # row['state'] = row['state'].encode('utf-8').decode('utf-8') 22 | row['country'] = row['country'].encode('utf-8').decode('utf-8') 23 | 24 | # lat and lng need to be save as double 25 | row['lat'] = float(row['lat']) 26 | row['lng'] = float(row['lng']) 27 | city = { 28 | 'name': row['name'], 29 | # 'state': row['state'], 30 | 'country': row['country'], 31 | 'lat': row['lat'], 32 | 'long': row['lng'] 33 | } 34 | cities.append(city) 35 | 36 | # Write the list of cities to a JSON file 37 | with open('cities.json', 'w') as jsonfile: 38 | json.dump(cities, jsonfile, indent=4) 39 | 40 | print("JSON file created successfully.") 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/00.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patriciogonzalezvivo/hypatia/0d01d125c038d9a67c553c94536196fadbde900c/docs/00.jpg -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(DOXYGEN_EXTRACT_ALL YES) 2 | set(DOXYGEN_BUILTIN_STL_SUPPORT YES) 3 | 4 | doxygen_add_docs(docs 5 | hypatia/ 6 | "${CMAKE_CURRENT_SOURCE_DIR}/mainpage.md" 7 | WORKING_DIRECTORY 8 | "${PROJECT_SOURCE_DIR}/include" 9 | ) 10 | -------------------------------------------------------------------------------- /docs/mainpage.md: -------------------------------------------------------------------------------- 1 | # Documentation for Hypatia {#mainpage} 2 | 3 | This is the documentation for Hypatia 4 | 5 | -------------------------------------------------------------------------------- /docs/ptolemaicsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patriciogonzalezvivo/hypatia/0d01d125c038d9a67c553c94536196fadbde900c/docs/ptolemaicsystem.png -------------------------------------------------------------------------------- /hypatia.i: -------------------------------------------------------------------------------- 1 | 2 | %begin %{ 3 | #if defined( __WIN32__ ) || defined( _WIN32 ) 4 | #include 5 | #endif 6 | %} 7 | 8 | %module hypatia 9 | 10 | %include 11 | %include 12 | %include 13 | 14 | %ignore *::operator[]; 15 | %ignore *::operator=; 16 | %ignore *::operator==; 17 | %ignore *::operator!=; 18 | %ignore *::operator<; 19 | %ignore *::operator<=; 20 | %ignore *::operator>; 21 | %ignore *::operator>=; 22 | %ignore operator<<; 23 | 24 | %{ 25 | #define SWIG_FILE_WITH_INIT 26 | #include "hypatia/MathOps.h" 27 | #include "hypatia/primitives/Polar.h" 28 | #include "hypatia/primitives/Vector2.h" 29 | #include "hypatia/primitives/Vector3.h" 30 | #include "hypatia/primitives/Matrix3x3.h" 31 | #include "hypatia/primitives/TimeSpan.h" 32 | #include "hypatia/primitives/DateTime.h" 33 | #include "hypatia/coordinates/Equatorial.h" 34 | #include "hypatia/coordinates/PrecessionMatrix.h" 35 | #include "hypatia/coordinates/Galactic.h" 36 | #include "hypatia/coordinates/Ecliptic.h" 37 | #include "hypatia/coordinates/Horizontal.h" 38 | #include "hypatia/coordinates/Geodetic.h" 39 | #include "hypatia/coordinates/ECI.h" 40 | #include "hypatia/coordinates/Tile.h" 41 | #include "hypatia/coordinates/UTM.h" 42 | #include "hypatia/TimeOps.h" 43 | #include "hypatia/GeoOps.h" 44 | #include "hypatia/Observer.h" 45 | #include "hypatia/CoordOps.h" 46 | #include "hypatia/ProjOps.h" 47 | #include "hypatia/Body.h" 48 | #include "hypatia/Luna.h" 49 | #include "hypatia/Star.h" 50 | #include "hypatia/Constellation.h" 51 | #include "hypatia/Satellite.h" 52 | #include "hypatia/models/TLE.h" 53 | %} 54 | 55 | %include "numpy.i" 56 | %init %{ 57 | import_array(); 58 | %} 59 | 60 | %apply double &OUTPUT { double &_x, double &_y }; 61 | %apply double &OUTPUT { double &_lng, double &_lat }; 62 | 63 | %apply double &OUTPUT { int &_deg, int &_min, double &_sec }; 64 | %apply double &OUTPUT { int &_hrs, int &_min, double &_sec }; 65 | 66 | %apply double &OUTPUT { int &_year, int &_month, double &_day }; 67 | %apply int &OUTPUT { int &_day, int &_month, int &_year }; 68 | %apply int &OUTPUT { int &_hrs, int &_min, int &_sec }; 69 | 70 | namespace std { 71 | %template(IntVector) vector; 72 | %template(EquatorialVector) vector; 73 | %template(TileList) vector; 74 | }; 75 | 76 | %include "include/hypatia/MathOps.h" 77 | %include "include/hypatia/primitives/Polar.h" 78 | %include "include/hypatia/primitives/Vector2.h" 79 | %include "include/hypatia/primitives/Vector3.h" 80 | %include "include/hypatia/primitives/Matrix3x3.h" 81 | %include "include/hypatia/primitives/TimeSpan.h" 82 | %include "include/hypatia/primitives/DateTime.h" 83 | %include "include/hypatia/coordinates/Equatorial.h" 84 | %include "include/hypatia/coordinates/PrecessionMatrix.h" 85 | %include "include/hypatia/coordinates/Galactic.h" 86 | %include "include/hypatia/coordinates/Ecliptic.h" 87 | %include "include/hypatia/coordinates/Horizontal.h" 88 | %include "include/hypatia/coordinates/Geodetic.h" 89 | %include "include/hypatia/coordinates/ECI.h" 90 | %include "include/hypatia/coordinates/Tile.h" 91 | %include "include/hypatia/coordinates/UTM.h" 92 | %include "include/hypatia/TimeOps.h" 93 | %include "include/hypatia/GeoOps.h" 94 | %include "include/hypatia/Observer.h" 95 | %include "include/hypatia/CoordOps.h" 96 | %include "include/hypatia/ProjOps.h" 97 | %include "include/hypatia/Body.h" 98 | %include "include/hypatia/Luna.h" 99 | %include "include/hypatia/Star.h" 100 | %include "include/hypatia/Constellation.h" 101 | %include "include/hypatia/Satellite.h" 102 | %include "include/hypatia/models/TLE.h" 103 | -------------------------------------------------------------------------------- /include/hypatia/Body.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Body.h 3 | * 4 | * Handles planetary motion calculations and conversions 5 | * 6 | * author: mark huss (mark@mhuss.com) 7 | * Based on Bill Gray's open-source code at projectpluto.com 8 | * 9 | \*****************************************************************************/ 10 | 11 | #pragma once 12 | 13 | #include "coordinates/Ecliptic.h" 14 | #include "coordinates/Equatorial.h" 15 | #include "coordinates/Horizontal.h" 16 | 17 | #include "Observer.h" 18 | 19 | enum BodyId { 20 | NAB=-1, // NotABody 21 | SUN=0, 22 | MERCURY=1, VENUS=2, EARTH=3, MARS=4, JUPITER=5, SATURN=6, URANUS=7, NEPTUNE=8, PLUTO=9, 23 | LUNA=10, 24 | SATELLITE=11 25 | }; 26 | 27 | class Body { 28 | public: 29 | Body(); 30 | Body( BodyId _body ); 31 | virtual ~Body(); 32 | 33 | virtual BodyId getId() const { return m_bodyId; } 34 | virtual char* getName() const; 35 | virtual char* getZodiacSign() const; 36 | virtual double getPeriod(TIME_UNIT _unit) const; 37 | virtual double getHourAngle(ANGLE_UNIT _type) const; 38 | 39 | // Heliocentric 40 | virtual Ecliptic getEclipticHeliocentric() const { return m_heliocentric; } 41 | 42 | // Geocentric 43 | virtual Ecliptic getEclipticGeocentric() const { return m_geocentric; } 44 | 45 | virtual Equatorial getEquatorial() const { return m_equatorial; } 46 | virtual Vector3 getEquatorialVector(DISTANCE_UNIT _type) const { return m_equatorial.getVector() * m_geocentric.getRadius(_type); } 47 | 48 | virtual bool haveHorizontal() const { return m_bHorizontal; } 49 | virtual Horizontal getHorizontal() const { return m_horizontal; } 50 | virtual Vector3 getHorizontalVector(DISTANCE_UNIT _type) const { return m_horizontal.getVector() * m_geocentric.getRadius(_type); }; 51 | 52 | // Calculate the data for a given planet given an observer 53 | // - This function must be called (directly or via c'tor) before calling any of the other fns! 54 | // - If the observer have no location Horizontal coordinates will not be calculate and remain 0.0, 0.0 55 | // 56 | virtual void compute( Observer& _obs ); 57 | 58 | protected: 59 | Ecliptic m_heliocentric; 60 | Ecliptic m_geocentric; 61 | 62 | Equatorial m_equatorial; 63 | Horizontal m_horizontal; 64 | 65 | double m_jcentury; 66 | double m_ha; 67 | BodyId m_bodyId; 68 | 69 | bool m_bHorizontal; 70 | }; 71 | 72 | inline std::ostream& operator<<(std::ostream& strm, const Body& b) { 73 | strm << b.getName() << ", "; 74 | strm << b.getEclipticHeliocentric() << ", "; 75 | strm << b.getEquatorial(); 76 | 77 | if ( b.haveHorizontal() ) { 78 | strm << ", " << b.getHorizontal(); 79 | } 80 | 81 | return strm; 82 | } 83 | -------------------------------------------------------------------------------- /include/hypatia/Constellation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "coordinates/Equatorial.h" 4 | 5 | #include 6 | 7 | class Constellation { 8 | public: 9 | 10 | static const int TOTAL; 11 | 12 | Constellation(); 13 | Constellation( int _id ); 14 | Constellation( char * _abbr ); 15 | Constellation( const Equatorial &_point ); 16 | Constellation( double _ra, double _dec ); 17 | 18 | void setId( int _id ); 19 | int getId() const { return m_id; } 20 | 21 | char* getName() const; 22 | char* getAbbreviation() const; 23 | 24 | Equatorial getEquatorialCentroid() const { return m_centroid; } 25 | 26 | std::vector getStarIndices() const { return m_sIndices; } 27 | std::vector getBoundary() const { return m_boundary; } 28 | 29 | protected: 30 | int m_id; 31 | Equatorial m_centroid; 32 | std::vector m_sIndices; 33 | std::vector m_boundary; 34 | }; 35 | 36 | inline std::ostream& operator<<(std::ostream& strm, const Constellation& c) { 37 | strm << c.getName() << " (" << c.getAbbreviation() << "), "; 38 | strm << c.getEquatorialCentroid(); 39 | return strm; 40 | } 41 | -------------------------------------------------------------------------------- /include/hypatia/CoordOps.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * CoordOps is a 'catch-all' class that performs odd handy calculations 3 | * 4 | * author: mark huss (mark@mhuss.com) 5 | * Based on Bill Gray's open-source code at projectpluto.com 6 | * 7 | \*****************************************************************************/ 8 | 9 | #pragma once 10 | 11 | #include "Observer.h" 12 | 13 | #include "coordinates/Galactic.h" 14 | #include "coordinates/Ecliptic.h" 15 | #include "coordinates/Equatorial.h" 16 | #include "coordinates/Horizontal.h" 17 | #include "coordinates/ECI.h" 18 | #include "coordinates/Geodetic.h" 19 | #include "coordinates/Tile.h" 20 | 21 | #include "coordinates/PrecessionMatrix.h" 22 | 23 | class CoordOps { 24 | public: 25 | 26 | static const double SPEED_OF_LIGHT; 27 | static const double AU_PER_DAY; 28 | 29 | static const double KM_TO_AU; 30 | static const double AU_TO_KM; 31 | static const double AU_TO_M; 32 | static const double AU_TO_LY; 33 | static const double LY_TO_AU; 34 | static const double LY_TO_PC; 35 | static const double PC_TO_LY; 36 | 37 | static const double SUN_DIAMETER_KM; 38 | 39 | // Transform celestial coordinates ( https://en.wikipedia.org/wiki/Celestial_coordinate_system ) 40 | // ******************************** 41 | 42 | // -------------------------------------------------- to HelioCentric (Ecliptic) 43 | 44 | /** 45 | * toHeliocentric() - ecliptic transformation from geocentric to heliocentric 46 | * 47 | * @param Observer 48 | * @param Ecliptic geocentric 49 | * 50 | * @return Ecliptic heliocentric 51 | */ 52 | static Ecliptic toHeliocentric(Observer& _obs, const Ecliptic& _geocentric); 53 | 54 | // -------------------------------------------------- to GeoCentric (Ecliptic) 55 | 56 | /** 57 | * eclipticToEquatorial() - ecliptic transformation from heliocentric to geocentric 58 | * 59 | * @param Observer 60 | * @param Ecliptic heliocentric 61 | * 62 | * @return Ecliptic geocentric 63 | */ 64 | static Ecliptic toGeocentric(Observer& _obs, const Ecliptic& _heliocentric ); 65 | 66 | /** 67 | * toGeocentric() - ) Obliquity, right Ascention and declination to Ecliptic Geocentric 68 | * (Meeus, Ch. 93) 69 | * 70 | * @param mean obliquity angle (radians) 71 | * @param right ascention (radians) 72 | * @param declination (radians) 73 | * @param distance (AU) 74 | * 75 | * @return Equatorial position 76 | */ 77 | static Ecliptic toGeocentric (double _obliquity, double _ra, double _dec, double _dist); 78 | 79 | /** 80 | * toGeocentric() - ECI to ecliptic geocentric 81 | * (Meeus, Ch. 93) 82 | * 83 | * @param Earth Center Inertial 84 | * 85 | * @return Equatorial position 86 | */ 87 | static Ecliptic toGeocentric (Observer& _obs, const ECI& _eci); 88 | 89 | // -------------------------------------------------- to Equatorial 90 | 91 | /** 92 | * toEquatorial() - Galactic to equatorial coordinates 93 | * 94 | * @param Observer 95 | * @param Galactic position 96 | * 97 | * @return Equatorial position 98 | */ 99 | static Equatorial toEquatorial (const Galactic& _galactic ); 100 | 101 | /** 102 | * eclipticToEquatorial() - ecliptic to equatorial coordinates 103 | * (Meeus, Ch. 93) 104 | * 105 | * @param mean obliquity angle (radians) 106 | * @param lng - of ecliptic position (radians) 107 | * @param lat - of ecliptic position (radians) 108 | * 109 | * @return Equatorial position 110 | */ 111 | static Equatorial toEquatorial( double _obliq, double _lng, double _lat); 112 | 113 | /** 114 | * toEquatorial() - ecliptic to equatorial coordinates 115 | * (Meeus, Ch. 93) 116 | * 117 | * @param Observer 118 | * @param Ecliptic position 119 | * 120 | * @return Equatorial position 121 | */ 122 | static Equatorial toEquatorial (const Observer& _obs, const Ecliptic& _ecliptic ); 123 | 124 | // -------------------------------------------------- to Earth Center Innertial (equatorial) 125 | 126 | /** 127 | * toECI() - Geodetic to Earth Center Innertial coordinatws 128 | * 129 | * @param julian days 130 | * @param geodetic coordinate 131 | * 132 | * @return Earth Center Innertial 133 | */ 134 | static ECI toECI(double _jd, const Geodetic& _geod); 135 | 136 | // -------------------------------------------------- to Geodetic 137 | 138 | /** 139 | * toGeodetic() - Earth Center Innertial to Geodetic coordinates 140 | * 141 | * @param Earth Center Innertial 142 | * 143 | * @return Geodetic Coordinate 144 | */ 145 | static Geodetic toGeodetic(const ECI& _eci); 146 | 147 | 148 | // -------------------------------------------------- to Hour Angle 149 | /** 150 | * toHourAngle() - calcuate hour angle (Meeus, Ch. 92) 151 | * 152 | * @param lst - observer's local sideral time 153 | * @param ra - right acention position (radians) 154 | * 155 | * @return hour angle 156 | */ 157 | static double toHourAngle( double _lst, double _ra ); 158 | 159 | /** 160 | * toHourAngle() - calcuate hour angle (Meeus, Ch. 92) 161 | * 162 | * @param obs - observer 163 | * @param ra - right acention position (radians) 164 | * 165 | * @return hour angle 166 | */ 167 | static double toHourAngle( const Observer& _obs, double _ra ); 168 | 169 | /** 170 | * toHourAngle() - calcuate hour angle (Meeus, Ch. 92) 171 | * 172 | * @param obs - observer 173 | * @param Equatorial coordinate 174 | * 175 | * @return hour angle 176 | */ 177 | static double toHourAngle( const Observer& _obs, const Equatorial& _equatorial ); 178 | 179 | // -------------------------------------------------- to TopoCentric 180 | /** 181 | * eclipticToEquatorial() - equatorial to horizontal coordinates 182 | * (Meeus, Ch. 93) 183 | * 184 | * @param lat - Observer's latitud (radians) 185 | * @param ha - hour angle (radians) 186 | * @param dec - of equatorial position (radians) 187 | * 188 | * @return horizontal position 189 | */ 190 | static Horizontal toHorizontal( double _lat, double _ha, double _dec); 191 | 192 | /** 193 | * toHorizontal() - to horizontal coordinates 194 | * (Meeus, Ch. 93) 195 | * 196 | * @param Observer 197 | * @param equatorial coordinate 198 | * 199 | * @return horizontal position 200 | */ 201 | static Horizontal toHorizontal( const Observer& _obs, const Equatorial& _equatorial); 202 | 203 | /** 204 | * toECI() - Earth Center Innertial to Horizontal coordinates 205 | * 206 | * @param observer 207 | * @param Earth Center Innertial 208 | * 209 | * @return Horizontal coordinates 210 | */ 211 | static Horizontal toHorizontal(const Observer& _obs, const ECI& _Eci); 212 | 213 | // -------------------------------------------------- Other coordinates functions 214 | 215 | /** 216 | * meanSolarLongitude() - calculate the mean solar latitude on the given T 217 | * (Meeus, Ch. 25) 218 | * 219 | * @param _jm - day to use in Julian Millenia 220 | * 221 | * @return - the longitude in radians 222 | */ 223 | static double meanSolarLongitude( double _jm ); 224 | 225 | /** 226 | * solarLongitude() - calculate the solar latitude on the given JD 227 | * (Meeus, Ch. 25) 228 | * 229 | * @param _jd - day to use 230 | * 231 | * @return - the longitude in radians 232 | */ 233 | static double solarLongitude( double _jd ); 234 | 235 | /** 236 | * meanSolarAnomaly() - calculate the mean solar anomaly on the given T 237 | * (Meeus, Ch. 25) 238 | * 239 | * @param _jc - day to use in Julian Centuries 240 | * 241 | * @return - the anomaly in radians 242 | */ 243 | static double meanSolarAnomaly( double _jc ); 244 | 245 | /** 246 | * earthEccentricity() - calculate the eccentricity of the Earth's orbit on 247 | * the given T (Meeus, Ch. 25) 248 | * 249 | * @param _jc - day to use in Julian Centuries 250 | * 251 | * @return - the eccentricity 252 | */ 253 | static double earthEccentricity( double _jc ); 254 | 255 | /** 256 | * meanObliquity() - calculate the mean obliquity for a given jd 257 | * 258 | * @param jd - julian day (valid for years -8000 to +12000) 259 | * 260 | * @return Mean obliquity (epsilon sub 0) in radians. 261 | * 262 | * 263 | */ 264 | static double meanObliquity( double _jcentury ); 265 | 266 | /** 267 | * nutation() - calculate delta phi and/or delta epsilon for the given jd 268 | * 269 | * @param - julian day 270 | * @param _pDPhi - [out] nutation (delta phi) in arcseconds 271 | * @param _pDEpsilon - [out] nutation (delta epsilon) in arcseconds 272 | * 273 | * The nutation formula (and all the magic numbers below) come from 274 | * p 132-5, Meeus, Astro Algorithms 275 | * 276 | * Either pointer can be NULL, in which case that value is 277 | * not computed. (we added this because sometimes, you want 278 | * only pDPhi or pDEpsilon; in such cases, computing _both_ 279 | * is a waste of perfectly good CPU time) 280 | */ 281 | static void nutation( double _jd, double* _pDPhi, double* _pDEpsilon ); 282 | 283 | 284 | /** 285 | * anomaly() - calculate delta phi and/or delta epsilon for the given jd 286 | * 287 | * @param - mean anomaly of elliptical motion (rad), 288 | * @param - eccentricity of elliptical motion (rad), 289 | * @param - return true anomaly (rad) 290 | * @param - return eccentrict anomaly (rad), 291 | */ 292 | static void anomaly (double _mean_anomaly, double _eccentricity, double* _true_anomaly, double* _eccentrict_anomaly); 293 | 294 | /** 295 | * parallaticAngle() - compute parallactic angle given latitude, object dec and alt. 296 | * all angles in rads. 297 | * (Meeus, Ch. 98) 298 | * 299 | * N.B. always return >= 0, caller must determine sign and degenerate cases at 300 | * pole or zenith. 301 | * 302 | * @param lat - Observer latitud (radians) 303 | * @param alt - of ecliptic position (radians) 304 | * @param az - of ecliptic position (radians) 305 | * 306 | * @return parallatic angle 307 | */ 308 | static double parallaticAngle( double _lat, double _alt, double _dec); 309 | 310 | /** 311 | * positionAngle() - compute the position angle of direction d w.r.t the position r 312 | * Astronomy on the Personal Computer p. 134 313 | * 314 | * @param por - position of observed body 315 | * @param dir - direction of which the position angle is to be calculated 316 | * 317 | * @return position angle in rad: range [0, TAU] 318 | * 319 | * Note: pos and dir must refer to the same coordinate system and equinox 320 | */ 321 | static double positionAngle( const Vector3& _pos, const Vector3& _dir ); 322 | 323 | /** 324 | * precess() - precess the given equatorial coordinates 325 | * 326 | * @param _matrix - precession matrix 327 | * @param _equatorial - equatorial coordinates 328 | * 329 | * @return precessed equatorial coordinates 330 | */ 331 | static Equatorial precess(const PrecessionMatrix& _matrix, const Equatorial& _equatorial); 332 | 333 | 334 | /** 335 | * eclipticToEquatorial() - ecliptic to equatorial coordinates 336 | * (Meeus, Ch. 93) 337 | * * 338 | * @param mean obliquity angle (radians) 339 | * * @return transformation matrix 340 | * 341 | */ 342 | static Matrix3x3 eclipticToEquatorial(const double _obliquity); 343 | 344 | /** 345 | * equatorialToEcliptic() - equatorial to ecliptic coordinates 346 | * (Meeus, Ch. 93) 347 | * * 348 | * @param mean obliquity angle (radians) 349 | * * @return transformation matrix 350 | * 351 | */ 352 | static Matrix3x3 equatorialToEcliptic(const double _obliquity); 353 | 354 | /** 355 | * eclipticPrecessionFromJ2000() - ecliptic precession matrix from J2000 356 | * (Meeus, Ch. 93) 357 | * 358 | * @param year - year to precess to 359 | * 360 | * @return transformation matrix 361 | */ 362 | static Matrix3x3 eclipticPrecessionFromJ2000(const double _year); 363 | }; 364 | 365 | -------------------------------------------------------------------------------- /include/hypatia/GeoOps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "hypatia/coordinates/Geodetic.h" 4 | #include "hypatia/coordinates/UTM.h" 5 | #include "hypatia/coordinates/Tile.h" 6 | #include "hypatia/primitives/Vector2.h" 7 | #include 8 | 9 | class GeoOps { 10 | public: 11 | 12 | static const double EARTH_FLATTENING; 13 | static const double EARTH_POLAR_RADIUS_KM; 14 | static const double EARTH_EQUATORIAL_RADIUS_M; 15 | static const double EARTH_EQUATORIAL_RADIUS_KM; 16 | static const double EARTH_EQUATORIAL_CIRCUMFERENCE_M; 17 | static const double EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M; 18 | static const double EARTH_ROTATION_PER_SIDERAL_DAY; 19 | static const double EARTH_GRAVITATIONAL_CONSTANT; 20 | 21 | static const int TIMEZONES_TOTAL; 22 | static const int COUNTRIES_TOTAL; 23 | static const int CITIES_TOTAL; 24 | 25 | // Timezones 26 | 27 | /** 28 | * tzNameToIndex(): convert a time zone string to an index 29 | * 30 | * @param _tz = time zone name string 31 | * 32 | * @return index of time zone 33 | */ 34 | static size_t tzNameToIndex ( const char* _tz ); 35 | 36 | 37 | /** 38 | * tzIndexToName(): convert a time zone index to a string 39 | * 40 | * @param _tzIndex = time zone index 41 | * 42 | * @return time zone name string 43 | */ 44 | static const char* tzIndexToName ( size_t _tzIndex ); 45 | 46 | /** 47 | * tzOffsetInDays(): calculate time zone offset from Universal Time 48 | * in days for the spec'd time_t (includes DST) 49 | * 50 | * @param _tzIndex = time zone index 51 | * 52 | * @return Offset (-0.5 ... +0.5 ) 53 | */ 54 | 55 | static double tzOffsetInDaysST ( size_t _tzIndex ); 56 | 57 | 58 | /** 59 | * tzOffsetInDaysDST(): calculate time zone offset from Universal Time 60 | * in days for the spec'd time_t (includes DST) 61 | * 62 | * @param _tzIndex = time zone index 63 | * 64 | * @return Offset (-0.5 ... +0.5 ) 65 | */ 66 | 67 | static double tzOffsetInDaysDST ( size_t _tzIndex ); 68 | 69 | /** 70 | * tzIsDST(): determine if the given date is in Daylight Savings Time 71 | * 72 | * @param _lat = latitude of location 73 | * @param _month = month of year 74 | * @param _day = day of month 75 | * @param _year = year 76 | * 77 | * @return true if in DST, false otherwise 78 | */ 79 | static bool tzIsDST ( double _lat, int _month, int _day ); 80 | 81 | /** 82 | * tzOffsetInDays(): calculate time zone offset from Universal Time 83 | * in days for the spec'd time_t (includes DST) 84 | * 85 | * @param _lat = latitude of location 86 | * @param _month = month of year 87 | * @param _day = day of month 88 | * @param _tzIndex = time zone index 89 | * 90 | * @return Offset (-0.5 ... +0.5 ) 91 | */ 92 | static double tzOffsetInDays ( double _lat, int _month, int _day, size_t _tzIndex ); 93 | 94 | 95 | // Distance 96 | static double distance(double _lng1, double _lat1, double _lng2, double _lat2); 97 | static double distance(const Geodetic& _g1, const Geodetic& _g2); 98 | 99 | // Find closest city Index 100 | static size_t findClosestCity(double _lng, double _lat); 101 | static size_t findClosestCity(const Geodetic& _g); 102 | 103 | // return City data 104 | static std::string getCityName(size_t _index); 105 | static size_t getCityCountryIndex(size_t _index); 106 | static std::string getCityCountry(size_t _index); 107 | 108 | static std::string getCountryName(size_t _index); 109 | static std::string getCountry2LetterCode(size_t _index); 110 | 111 | static size_t getCityTimezoneIndex(size_t _index); 112 | static std::string getCityTimezone(size_t _index); 113 | 114 | static double getCityLongitude(size_t _index); 115 | static double getCityLatitude(size_t _index); 116 | static int getCityAltitudeM(size_t _index); 117 | static Geodetic getCityLocation(size_t _index); 118 | 119 | static UTM toUTM(double _lng, double _lat); 120 | static UTM toUTM(const Geodetic& _g); 121 | 122 | static Geodetic toGeodetic(const UTM& _utm); 123 | static Geodetic toGeodetic(const Vector2& _mercator); 124 | static Geodetic toGeodetic(const Tile& _tile); 125 | static Geodetic toGeodetic(const Tile& _tile, const Vector2& _uv); 126 | 127 | static Vector2 toMercator( double _lng, double _lat); 128 | static Vector2 toMercator( const Geodetic& _coord ); 129 | 130 | // /** 131 | // * toTile() - Geodetic location to Tile coordinates 132 | // * 133 | // * @param geodetic location (lat/lng) 134 | // * @param zoom level 135 | // * 136 | // * @return tile coords on a mercator tile grid 137 | // */ 138 | static Tile toTile(const Geodetic& _geo, int _zoomLevel); 139 | 140 | static double getMetersPerTileAt(int _zoom); 141 | }; -------------------------------------------------------------------------------- /include/hypatia/Luna.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Luna.h 3 | * 4 | * Luna is a class that can calculate lunar fundmentals for any reasonable 5 | * time. 6 | * 7 | * author: mark huss (mark@mhuss.com) 8 | * Based on Bill Gray's open-source code at projectpluto.com 9 | * 10 | \*****************************************************************************/ 11 | 12 | #pragma once 13 | 14 | // #include "CoordOps.h" 15 | #include "Body.h" 16 | 17 | // A struct to hold the fundmental elements 18 | // The member names should be familiar to Meeus fans ;-) 19 | // 20 | struct LunarFundamentals { 21 | double Lp, D, M, Mp, F, A1, A2, A3, T; 22 | LunarFundamentals():Lp(0.),D(0.),M(0.),Mp(0.),F(0.),A1(0.),A2(0.),A3(0.),T(0.) {} 23 | }; 24 | 25 | // our main class -- calculates Luna fundamentals, lat, lon & distance 26 | // 27 | class Luna : public Body { 28 | public: 29 | Luna(); 30 | 31 | static const double SYNODIC_MONTH; 32 | static const double SYNODIC_WEEK; 33 | static const double PERIGEE_KM; 34 | static const double APOGEE_KM; 35 | static const double DIAMETER_KM; 36 | 37 | // Calculate age of the moon in days (0.0 to 29.53...) 38 | virtual double getAge() const { return m_age; }; 39 | 40 | // Illuminated Fraction of the Moon's disk. 41 | virtual double getPhase(); 42 | 43 | // Distance to the earht usually better in km 44 | virtual double getDistance(DISTANCE_UNIT _type) const; 45 | 46 | // Phase Angle of the Moon's. 47 | virtual double getPhaseAngle(ANGLE_UNIT _type); 48 | 49 | // Position Angle of bright limb 50 | virtual double getPositionAngle(ANGLE_UNIT _type) const; 51 | 52 | // calculate all three location elements of the spec'd body at the given time 53 | virtual void compute( Observer &_obs ); 54 | 55 | private: 56 | LunarFundamentals m_f; // our calculated fundmentals 57 | 58 | double m_age, m_posAngle, m_distance; 59 | }; 60 | 61 | -------------------------------------------------------------------------------- /include/hypatia/MathOps.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * MathOps defines misc. handy constants & mathematical fns 3 | * 4 | * author: mark huss (mark@mhuss.com) 5 | * Based on Bill Gray's open-source code at projectpluto.com 6 | * 7 | \*****************************************************************************/ 8 | 9 | #pragma once 10 | #undef PI 11 | 12 | enum DISTANCE_UNIT { 13 | KM, AU, LY, PC 14 | }; 15 | 16 | enum ANGLE_UNIT { 17 | DEGS, RADS 18 | }; 19 | 20 | enum ANGLE_FMT { 21 | Dd, // 16.2° 22 | Ddd, // 16.29° 23 | Dddd, // 16.294° 24 | D_Mm, // 12° 36.1' 25 | D_M_Ss, // 12° 36' 59.1" 26 | Hs, // 15.1h 27 | Hss, // 15.12h 28 | Hsss, // 15.123h 29 | H_Mm, // 15h 15,3m 30 | H_M_Ss // 15h 15m 32.9s 31 | }; 32 | 33 | struct MathOps { 34 | static const double PI; 35 | static const double TAU; 36 | static const double PI_OVER_TWO; 37 | static const double TWO_OVER_PI; 38 | static const double DEG_PER_CIRCLE; 39 | static const double RAD_PER_CIRCLE; 40 | 41 | static const double MINUTES_PER_DEGREE; 42 | static const double SECONDS_PER_DEGREE; 43 | static const double RADS_PER_DEGREE; 44 | 45 | static const double RADS_TO_DEGS; 46 | static const double DEGS_TO_RADS; 47 | static const double DEGS_TO_HRS; 48 | 49 | static const double RADS_TO_ARCS; 50 | static const double ARCS_TO_RADS; 51 | 52 | static const double RADIAN; 53 | 54 | static const double ROUND; 55 | static const double INVALID; 56 | 57 | static const double TWO_THIRD; 58 | 59 | /** 60 | * toDegrees(): convert radians to degrees 61 | * 62 | * @param an angle in radians 63 | * 64 | * @return an angle in degrees 65 | */ 66 | static double toDegrees( double _rad ); 67 | 68 | /** 69 | * toDegrees(): convert radians to degrees 70 | * 71 | * @param an degrees 72 | * @param an minutes 73 | * @param an seconds 74 | * 75 | * @return an angle in degrees 76 | */ 77 | static double toDegrees( int _deg, int _min, double _sec ); 78 | 79 | /** 80 | * toRadians(): convert degrees to radians 81 | * 82 | * @param an angle in degrees 83 | * 84 | * @return an angle in radians 85 | */ 86 | static double toRadians( double _deg ); 87 | 88 | /** 89 | * secToRadians(): convert arcseconds to radians 90 | * 91 | * @param an angle in arcseconds 92 | * 93 | * @return an angle in radians 94 | */ 95 | static double secToRadians( double _sec ); 96 | 97 | /** 98 | * toHrs(): convert arcseconds to radians 99 | * 100 | * @param degrees 101 | * 102 | * @return hours double 103 | */ 104 | static double toHrs( double _angle, ANGLE_UNIT _type ); 105 | 106 | /** 107 | * toDMS(): convert angle to degrees, minutes and seconds 108 | * 109 | * @param angle in 110 | * @param angle type 111 | * 112 | * @param degrees out 113 | * @param minutes out 114 | * @param seconds out 115 | * 116 | */ 117 | static void toDMS ( double _angles, ANGLE_UNIT _type, int &_deg, int &_min, double &_sec ); 118 | 119 | /** 120 | * toHMS(): convert angles to degrees, minutes and seconds 121 | * 122 | * @param angle in 123 | * @param angle type 124 | * 125 | * @param hours out 126 | * @param minutes out 127 | * @param seconds out 128 | * 129 | */ 130 | static void toHMS ( double _deg, ANGLE_UNIT _type, int &_hrs, int &_min, double &_sec ); 131 | 132 | /** 133 | * formatAngle(): format angle into a string 134 | * 135 | * @param angle value 136 | * @param angle type 137 | * @param format type 138 | * 139 | * @return formated string 140 | * 141 | */ 142 | static char* formatAngle ( double _angle, ANGLE_UNIT _type, ANGLE_FMT _format ); 143 | 144 | /** 145 | * normalize(): reduce an angle to the range (0 <= d < 360 or 0 <= d << TAO) 146 | * 147 | * @param angle 148 | * @param angle type 149 | * 150 | * 151 | * @return a 152 | */ 153 | static double normalize( double _angle, ANGLE_UNIT _type ); 154 | 155 | /** 156 | * quadrant(): returns the quadrant ( 0, 1, 2, or 3 ) of the spec'd angle 157 | * 158 | * @param angle - in radians 159 | * 160 | * @return quadrant of angle 161 | */ 162 | static int quadrant( double _rad ); 163 | 164 | /** 165 | * acose(): "safe" acos which prevents overflow errors 166 | * 167 | * @param angle 168 | * 169 | * @return acos (0 ... PI) 170 | */ 171 | static double acose( double _rad ); 172 | 173 | /** 174 | * asine(): "safe" asine which prevents overflow errors 175 | * 176 | * @param angle 177 | * 178 | * @return asin (PI/2 ... -PI/2) 179 | */ 180 | static double asine( double _rad ); 181 | 182 | /** 183 | * actan(): 184 | * 185 | * @param sinx 186 | * @param cosx 187 | * 188 | * @return actan 189 | */ 190 | static double actan(const double sinx, const double cosx); 191 | 192 | /** 193 | * fract(): gives the fractional part of a number 194 | * 195 | * @param number 196 | * 197 | * @return fractional part of it 198 | */ 199 | static double fract (double _x); 200 | 201 | /** 202 | * mod(): calculates x modulus y 203 | * 204 | * @param base 205 | * 206 | * @return modulus of 207 | */ 208 | static long mod ( long x, long y ); 209 | static double mod ( double _x, double _y ); 210 | 211 | /** 212 | * clamp(): clamp thev x value between _low and _high 213 | * 214 | * @param value 215 | * @param lower 216 | * @param higest 217 | * 218 | * @return the clamped value between low and high 219 | */ 220 | static double clamp( double _x, double _low, double _high); 221 | 222 | }; 223 | -------------------------------------------------------------------------------- /include/hypatia/Observer.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * ObsInf 3 | * 4 | * author: mark huss (mark@mhuss.com) 5 | * Based on Bill Gray's open-source code at projectpluto.com 6 | * 7 | \*****************************************************************************/ 8 | 9 | #pragma once 10 | 11 | #include "TimeOps.h" 12 | #include "GeoOps.h" 13 | #include "coordinates/Geodetic.h" 14 | 15 | // * * * * * Observer's Location Info * * * * * 16 | class Observer { 17 | public: 18 | // c'tor: lon & lat are passed in DEGREES 19 | Observer(); 20 | Observer(double _jd); 21 | Observer(const Geodetic& _location, double _jd = 0); 22 | Observer(double _lng_deg, double _lat_deg, double _jd = 0); 23 | virtual ~Observer(); 24 | 25 | virtual void setSeconds(unsigned long _sec = 0); 26 | virtual void setLocation(const Geodetic& _location); 27 | virtual void setLocation(double _lng_deg, double _lat_deg); 28 | virtual void setJD(double _jd); 29 | virtual void setJDLocal(double _jd); 30 | 31 | virtual void setTimezone(const char* _tz); 32 | virtual void setTimezoneIndex(size_t _tz); 33 | 34 | virtual size_t searchLocation(double _lng_deg, double _lat_deg); 35 | 36 | virtual void setCityId(size_t _cityId); 37 | virtual size_t getCityId() const { return m_cityId; } 38 | virtual std::string getCity() const { return GeoOps::getCityName(m_cityId); } 39 | virtual std::string getCountry() const { return GeoOps::getCountryName( GeoOps::getCityCountryIndex(m_cityId) ); } 40 | virtual std::string getCountry2LetterCode() const { return GeoOps::getCountry2LetterCode( GeoOps::getCityCountryIndex(m_cityId) ); } 41 | 42 | virtual double getJD() const { return m_jd; } 43 | virtual double getJDLocal() const; 44 | virtual double getJC() const { return m_jcentury; } 45 | virtual double getObliquity() const { return m_obliquity; } 46 | 47 | virtual bool haveLocation() const { return m_bLocation; } 48 | virtual Geodetic getLocation() const; 49 | virtual double getLST() const; 50 | 51 | virtual double getTZOffsetST() const { return m_tzOffsetST; } 52 | virtual double getTZOffsetDST() const { return m_tzOffsetDST; } 53 | virtual size_t getTimezoneIndex() const { return m_tzIndex; } 54 | virtual std::string getTimezone() const; 55 | 56 | virtual Vector3 getHeliocentricVector(DISTANCE_UNIT _type); 57 | 58 | virtual void update(); 59 | 60 | private: 61 | Vector3 m_heliocentricLoc; 62 | Geodetic m_location; 63 | size_t m_cityId = 0; 64 | 65 | double m_jd = 0.0; 66 | double m_jcentury = 0.0; 67 | double m_obliquity = 0.0; 68 | double m_lst = 0.0; 69 | 70 | double m_tzOffsetST = 0.0; 71 | double m_tzOffsetDST = 0.0; 72 | size_t m_tzIndex = 0; 73 | 74 | bool m_changed = true; 75 | bool m_bLocation = false; 76 | }; 77 | 78 | inline std::ostream& operator<<(std::ostream& strm, const Observer& o) { 79 | strm << "Observer, jd:" << std::setw(8) << o.getJD(); 80 | strm << ", " << std::setw(8) << TimeOps::formatDateTime(o.getJD(), Y_M_D_HM); 81 | strm << ", obliq:" << std::setw(8) << MathOps::formatAngle(o.getObliquity(), RADS, Dd); 82 | if ( o.haveLocation() ) { 83 | strm << ", " << o.getLocation(); 84 | strm << ", lst:" << std::setw(8) << MathOps::formatAngle(o.getLST(), DEGS, Dd); 85 | } 86 | return strm; 87 | } 88 | -------------------------------------------------------------------------------- /include/hypatia/ProjOps.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "coordinates/Horizontal.h" 4 | #include "coordinates/Geodetic.h" 5 | 6 | #include "primitives/Vector2.h" 7 | 8 | enum ProjId { 9 | POLAR=0, FISHEYE=1, ORTHO=2, 10 | STEREO=3, LAMBERT=4, EQUIRECTANGULAR=5 11 | }; 12 | 13 | class ProjOps { 14 | public: 15 | 16 | static void toXY( ProjId _id, double _alt, double _az, double _width, double _height, double &_x, double &_y ); 17 | static Vector2 toVector2( ProjId _id, const Horizontal& _coord, double _width, double _height); 18 | 19 | static void toPolar( double _alt, double _az, double _width, double _height, double &_x, double &_y ); 20 | static Vector2 toPolar( const Horizontal& _coord, double _width, double _height ); 21 | 22 | static void toFisheye( double _alt, double _az, double _width, double _height, double &_x, double &_y ); 23 | static Vector2 toFisheye( const Horizontal& _coord, double _width, double _height ); 24 | 25 | static void toOrtho( double _alt, double _az, double _width, double _height, double &_x, double &_y ); 26 | static Vector2 toOrtho( const Horizontal& _coord, double _width, double _height ); 27 | 28 | static void toStereo( double _alt, double _az, double _width, double _height, double &_x, double &_y ); 29 | static Vector2 toStereo( const Horizontal& _coord, double _width, double _height ); 30 | 31 | static void toLambert( double _alt, double _az, double _width, double _height, double &_x, double &_y ); 32 | static Vector2 toLambert( const Horizontal& _coord, double _width, double _height ); 33 | 34 | static void toEquirectangular( double _alt, double _az, double _width, double _height, double &_x, double &_y ); 35 | static Vector2 toEquirectangular( const Horizontal& _coord, double _width, double _height ); 36 | }; 37 | -------------------------------------------------------------------------------- /include/hypatia/Satellite.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Body.h" 4 | #include "models/SGP4.h" 5 | 6 | class Satellite : public Body { 7 | public: 8 | Satellite(); 9 | Satellite(const TLE& _tle); 10 | virtual ~Satellite(); 11 | 12 | virtual void setTLE(const TLE& _tle); 13 | 14 | virtual Orbit getOrbit() const { return m_sgp4.getOrbit(); }; 15 | virtual double getPeriod(TIME_UNIT _unit) const; 16 | 17 | virtual ECI getECI() const { return m_eci; }; 18 | virtual Geodetic getGeodetic() const; 19 | virtual Vector3 getEquatorialVector(DISTANCE_UNIT _type) const { return getGeodetic().getVector(_type); } 20 | 21 | virtual char* getName() const; 22 | 23 | virtual void compute( Observer& _obs ); 24 | 25 | protected: 26 | SGP4 m_sgp4; 27 | ECI m_eci; 28 | 29 | std::string m_name; 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /include/hypatia/Star.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "coordinates/Equatorial.h" 4 | #include "coordinates/Horizontal.h" 5 | #include "coordinates/PrecessionMatrix.h" 6 | 7 | #include "Observer.h" 8 | 9 | #define USE_HIPPACOS_EXTRADATA 10 | 11 | enum STAR_CATALOG { 12 | ASTRO, HIP 13 | }; 14 | 15 | class Star { 16 | public: 17 | 18 | static const int TOTAL; 19 | 20 | Star(); 21 | Star( int _id, STAR_CATALOG _cat = ASTRO ); 22 | Star( double _ra, double _dec, double _mag ); 23 | virtual ~Star(); 24 | 25 | virtual int getId() const { return m_id; }; 26 | 27 | virtual int getHIP() const; 28 | virtual char* getName() const; 29 | 30 | virtual double getMagnitud() const; 31 | 32 | // Positioning 33 | virtual Equatorial getEquatorial() const { return m_equatorial; } 34 | virtual Vector3 getEquatorialVector(DISTANCE_UNIT _type) const { return m_equatorial.getVector() * getDistance(_type); } 35 | 36 | virtual bool haveHorizontal() const { return m_bHorizontal; } 37 | virtual Horizontal getHorizontal() const { return m_horizontal; } 38 | virtual Vector3 getHorizontalVector(DISTANCE_UNIT _type) const { return m_horizontal.getVector() * getDistance(_type); }; 39 | virtual double getHourAngle(ANGLE_UNIT _type) const; 40 | 41 | virtual double getParalax() const; 42 | virtual double getDistance(DISTANCE_UNIT _type) const; 43 | 44 | #ifdef USE_HIPPACOS_EXTRADATA 45 | virtual double getAbsMagnitud() const; 46 | virtual double getTemperature() const; 47 | virtual double getVB() const; 48 | #endif 49 | 50 | virtual void compute( Observer& _obs ); 51 | virtual void compute( Observer& _obs, const PrecessionMatrix& _matrix ); 52 | 53 | protected: 54 | 55 | // Position 56 | Equatorial m_equatorial; 57 | Horizontal m_horizontal; 58 | double m_ha; 59 | 60 | // Magnitud 61 | double m_mag; // aparent 62 | 63 | // ID 64 | int m_id; 65 | 66 | bool m_bHorizontal; 67 | }; 68 | 69 | inline std::ostream& operator<<(std::ostream& strm, const Star& s) { 70 | strm << std::setprecision(3); 71 | strm << "id: " << std::setw(8) << s.getId() << ", "; 72 | strm << ", mag: " << std::setw(8) << s.getMagnitud() << ", "; 73 | strm << s.getEquatorial() << ", "; 74 | strm << s.getHorizontal(); 75 | return strm; 76 | } 77 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/ECI.h: -------------------------------------------------------------------------------- 1 | // 2 | // Eci.hpp 3 | // 4 | // Created by Patricio González Vivo on 5/31/18. 5 | // 6 | #pragma once 7 | 8 | #include "../primitives/Vector3.h" 9 | 10 | /** 11 | * @brief Stores an Earth-centered inertial position for a particular time. 12 | */ 13 | class ECI { 14 | public: 15 | ECI(); 16 | ECI(double _jd, const Vector3 &_pos, const Vector3 &_vel = Vector3(), DISTANCE_UNIT _type = KM); 17 | virtual ~ECI(); 18 | 19 | virtual double getJD() const { return m_jd; }; 20 | virtual Vector3 getPosition(DISTANCE_UNIT _type) const; 21 | virtual Vector3 getVelocity(DISTANCE_UNIT _type) const; 22 | 23 | private: 24 | Vector3 m_position; // km 25 | Vector3 m_velocity; // km/s 26 | double m_jd; 27 | }; 28 | 29 | inline std::ostream& operator<<(std::ostream& strm, const ECI& e) { 30 | strm << std::setprecision(3); 31 | strm << "JD: " << std::setw(12) << e.getJD(); 32 | strm << ", Pos: " << e.getPosition(KM); 33 | strm << ", Vel: " << e.getVelocity(KM); 34 | return strm; 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/Ecliptic.h: -------------------------------------------------------------------------------- 1 | // Ecliptic Position (Helio/Geocentric) 2 | // 3 | 4 | #pragma once 5 | 6 | #include "../primitives/Vector3.h" 7 | 8 | class Ecliptic : public Polar { 9 | public: 10 | Ecliptic (); 11 | Ecliptic (const Vector3& _parent, DISTANCE_UNIT _type); 12 | Ecliptic (double _lng, double _lat, double _radius, ANGLE_UNIT _a_type, DISTANCE_UNIT _d_type); 13 | virtual ~Ecliptic(); 14 | 15 | virtual Ecliptic& operator= (const Vector3& _vec); 16 | 17 | virtual double getLongitude (ANGLE_UNIT _type) const; 18 | virtual double getLatitude (ANGLE_UNIT _type) const; 19 | virtual double getRadius (DISTANCE_UNIT _type) const; 20 | 21 | virtual Vector3 getVector (DISTANCE_UNIT _type) const; 22 | 23 | protected: 24 | double m_radius; // AU 25 | }; 26 | 27 | inline std::ostream& operator<<(std::ostream& strm, const Ecliptic& p) { 28 | strm << std::setprecision(3); 29 | strm << "lng: " << std::setw(12) << MathOps::formatAngle(p.getLongitude(DEGS), DEGS, D_M_Ss); 30 | strm << ", lat: " << std::setw(12) << MathOps::formatAngle(p.getLatitude(DEGS), DEGS, D_M_Ss); 31 | strm << ", rad: " << std::setw(8) << p.getRadius(AU); 32 | return strm; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/Equatorial.h: -------------------------------------------------------------------------------- 1 | // Equatorial Position (Geocentric) 2 | // 3 | 4 | #pragma once 5 | 6 | #include "../primitives/Vector3.h" 7 | 8 | class Equatorial : public Polar { 9 | public: 10 | Equatorial(); 11 | Equatorial(const Vector3& _parent); 12 | Equatorial(const double _ra, const double _dec, ANGLE_UNIT _type); 13 | virtual ~Equatorial(); 14 | 15 | virtual double getRightAscension(ANGLE_UNIT _type) const; 16 | virtual double getDeclination(ANGLE_UNIT _type) const; 17 | 18 | virtual Vector3 getVector() const; 19 | 20 | virtual double getAngularDistance(const Equatorial& _equ, ANGLE_UNIT _type) const; 21 | }; 22 | 23 | inline std::ostream& operator<<(std::ostream& strm, const Equatorial& p) { 24 | strm << std::setprecision(3); 25 | strm << "ra: " << std::setw(12) << MathOps::formatAngle(p.getRightAscension(DEGS), DEGS, H_M_Ss); 26 | strm << ", dec: " << std::setw(12) << MathOps::formatAngle(p.getDeclination(DEGS), DEGS, D_M_Ss); 27 | return strm; 28 | } 29 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/Galactic.h: -------------------------------------------------------------------------------- 1 | // Galactic Position 2 | // 3 | 4 | #pragma once 5 | 6 | #include "../primitives/Vector3.h" 7 | 8 | class Galactic : public Polar { 9 | public: 10 | Galactic (); 11 | Galactic (const Vector3& _parent, DISTANCE_UNIT _type); 12 | Galactic (double _lng, double _lat, ANGLE_UNIT _a_type); 13 | Galactic (double _lng, double _lat, double _paralax, ANGLE_UNIT _a_type); 14 | Galactic (double _lng, double _lat, double _radius, ANGLE_UNIT _a_type, DISTANCE_UNIT _d_type); 15 | virtual ~Galactic(); 16 | 17 | virtual Galactic& operator= (const Vector3& _vec); 18 | virtual Galactic& operator= (const Polar& _vec); 19 | 20 | virtual double getLongitude (ANGLE_UNIT _type) const; 21 | virtual double getLatitude (ANGLE_UNIT _type) const; 22 | virtual double getRadius (DISTANCE_UNIT _type) const; 23 | 24 | virtual Vector3 getVector (DISTANCE_UNIT _type) const; 25 | 26 | protected: 27 | double m_radius; // PC 28 | }; 29 | 30 | inline std::ostream& operator<<(std::ostream& strm, const Galactic& p) { 31 | strm << std::setprecision(3); 32 | strm << "lng: " << std::setw(12) << MathOps::formatAngle(p.getLongitude(DEGS), DEGS, D_M_Ss); 33 | strm << ", lat: " << std::setw(12) << MathOps::formatAngle(p.getLatitude(DEGS), DEGS, D_M_Ss); 34 | strm << ", rad: " << std::setw(8) << p.getRadius(AU); 35 | return strm; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/Geodetic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../primitives/Vector3.h" 4 | 5 | class Geodetic : public Polar { 6 | public: 7 | Geodetic(); 8 | Geodetic( double _lng, double _lat, double _alt, ANGLE_UNIT _a_type, DISTANCE_UNIT _alt_unit ); 9 | virtual ~Geodetic(); 10 | 11 | virtual void setLongitude( double _lng, ANGLE_UNIT _type ); 12 | virtual void setLatitude( double _lat, ANGLE_UNIT _type ); 13 | virtual void setAltitude( double _alt, DISTANCE_UNIT _type ); 14 | 15 | virtual double getLongitude( ANGLE_UNIT _type ) const; 16 | virtual double getLatitude( ANGLE_UNIT _type ) const; 17 | virtual double getAltitude( DISTANCE_UNIT _type ) const; 18 | 19 | virtual double getRadius( DISTANCE_UNIT _type ) const; 20 | 21 | virtual Vector3 getVector( DISTANCE_UNIT _type ) const; 22 | 23 | protected: 24 | double m_alt; // always stored on KM 25 | }; 26 | 27 | inline std::ostream& operator<<(std::ostream& strm, const Geodetic& p) { 28 | strm << std::setprecision(3); 29 | strm << "lng: " << std::setw(12) << MathOps::formatAngle(p.getLongitude(DEGS), DEGS, D_M_Ss); 30 | strm << ", lat: " << std::setw(12) << MathOps::formatAngle(p.getLatitude(DEGS), DEGS, D_M_Ss); 31 | strm << ", alt: " << std::setw(8) << p.getAltitude(KM); 32 | 33 | return strm; 34 | }; 35 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/Horizontal.h: -------------------------------------------------------------------------------- 1 | // Horizontal Position s(Topocentric) 2 | // 3 | 4 | #pragma once 5 | 6 | #include "../primitives/Vector3.h" 7 | 8 | class Horizontal : public Polar { 9 | public: 10 | Horizontal(); 11 | Horizontal( const Vector3& _parent ); 12 | Horizontal(const double _alt, const double _az, ANGLE_UNIT _type); 13 | virtual ~Horizontal(); 14 | 15 | virtual double getAltitud(ANGLE_UNIT _type) const; 16 | virtual double getAzimuth(ANGLE_UNIT _type) const; 17 | 18 | virtual Vector3 getVector() const; 19 | }; 20 | 21 | inline std::ostream& operator<<(std::ostream& strm, const Horizontal& p) { 22 | strm << std::setprecision(3); 23 | strm << "alt: " << std::setw(8) << MathOps::formatAngle(p.getAltitud(DEGS), DEGS, Dd); 24 | strm << ", az: " << std::setw(8) << MathOps::formatAngle(p.getAzimuth(DEGS), DEGS, Dd); 25 | return strm; 26 | }; 27 | -------------------------------------------------------------------------------- /include/hypatia/coordinates/PrecessionMatrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../primitives/Matrix3x3.h" 4 | 5 | class PrecessionMatrix : public Matrix3x3 { 6 | public: 7 | PrecessionMatrix(); 8 | PrecessionMatrix(double _toYear, double _fromYear = 2000.0); 9 | virtual ~PrecessionMatrix(); 10 | 11 | double fromYear() const { return m_fromYear; } 12 | double toYear() const { return m_toYear; } 13 | bool isBackward() const { return m_backward; } 14 | 15 | Vector3 precess(const Vector3& _v) const; 16 | Vector3 deprecess(const Vector3& _v) const; 17 | 18 | protected: 19 | void compute(); 20 | 21 | double m_fromYear; 22 | double m_toYear; 23 | bool m_backward; 24 | }; -------------------------------------------------------------------------------- /include/hypatia/coordinates/Tile.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "hypatia/primitives/Vector2.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | /* An immutable identifier for a map tile 10 | * 11 | * Contains the column, row, and zoom indices of a tile in a quad tree; Tiles are ordered by: 12 | * 1. zoom, highest to lowest 13 | * 2. column, lowest to highest 14 | * 3. row, lowest to highest 15 | */ 16 | 17 | enum TileProvider { 18 | 19 | NEXTZEN_JSON, NEXTZEN_MVT, 20 | NEXTZEN_TERRARIUM, NEXTZEN_NORMAL, NEXTZEN_GEOTIFF, 21 | 22 | OSM, 23 | 24 | BING, 25 | 26 | MICROSOFT_BASE, MICROSOFT_NIGHT, MICROSOFT_ROAD_SHADED_RELIEVEF, 27 | MICROSOFT_SATELLITE, MICROSOFT_SATELLITE_ROAD_LABELS, 28 | MICROSOFT_GRAYSCALE_DARK, MICROSOFT_GRAYSCALE_LIGHT, 29 | 30 | STAMEN_TONER, STAMEN_TONER_HYBRID, STAMEN_TONER_LABELS, STAMEN_TONER_LINES, STAMEN_TONER_BACKGROUND, 31 | STAMEN_TERRAIN, STAMEN_TERRAIN_LABELS, STAMEN_TERRAIN_LINES, STAMEN_TERRAIN_BACKGROUND 32 | 33 | }; 34 | 35 | class Tile { 36 | public: 37 | Tile(); 38 | Tile(const std::string& _quadKey); 39 | Tile(double _x, double _y, int _zoom); 40 | virtual ~Tile(); 41 | 42 | int getColumn() const; 43 | int getRow() const; 44 | int getZoom() const; 45 | 46 | Vector2 getUV() const; 47 | Vector2 getMercator() const; 48 | Vector2 getMercatorForUV(const Vector2& _uv) const; 49 | Vector2 getMercatorForSouthWestCorner() const; 50 | Vector2 getMercatorForNorthWestCorner() const; 51 | 52 | std::string getProviderURL( TileProvider _prov ) const; 53 | 54 | bool operator < (const Tile& _tile) const; 55 | 56 | bool operator > (const Tile& _tile) const; 57 | bool operator <= (const Tile& _tile) const; 58 | bool operator >= (const Tile& _tile) const; 59 | bool operator == (const Tile& _tile) const; 60 | bool operator != (const Tile& _tile) const; 61 | 62 | bool isValid() const; 63 | bool isValid(int _maxZoom) const; 64 | 65 | Tile getParent() const; 66 | Tile getChild(int _index, int _maxZoom) const; 67 | Tile getTileAtZoom(const int& _zoom) const; 68 | Tile withMaxSourceZoom(int _maxZoom) const; 69 | 70 | Tile zoom(const int& _distance) const; 71 | Tile up(const double& _distance=1) const; 72 | Tile right(const double& _distance=1) const; 73 | Tile down(const double& _distance=1) const; 74 | Tile left(const double& _distance=1) const; 75 | 76 | double getMetersPerTile() const; 77 | std::string getQuadKey() const; 78 | 79 | static double getMetersPerTileAt(int zoom); 80 | static std::string getQuadKey(int _column, int _row, int _zoom); 81 | 82 | static bool compareNW(const Tile& a, const Tile& b) { 83 | int col = 2 ^ a.getZoom(); 84 | return (a.getColumn() + a.getRow() * col) < (b.getColumn() + b.getRow() * col); 85 | } 86 | 87 | static std::vector sorteNW( std::vector _TileList ) { 88 | std::sort(_TileList.begin(), _TileList.end(), Tile::compareNW); 89 | return _TileList; 90 | } 91 | 92 | // static void sorteNW( Tile* _array1D, int _n ) { 93 | // std::sort(_array1D, _array1D+_n, Tile::compareNW); 94 | // } 95 | 96 | 97 | protected: 98 | double meters; // meters per tile in te given zoom level (cached) 99 | double x, y; // This is the actual grid column and rows but with decimals 100 | int z; // the zoom is sorted from highest to lowest 101 | }; 102 | 103 | inline std::ostream& operator<<(std::ostream& strm, const Tile& p) { 104 | strm << std::setprecision(3); 105 | strm << p.getZoom() << "/" << p.getColumn() << "/" << p.getRow(); 106 | return strm; 107 | } -------------------------------------------------------------------------------- /include/hypatia/coordinates/UTM.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class UTM { 6 | public: 7 | UTM() {}; 8 | virtual ~UTM() {}; 9 | 10 | int zoneX; 11 | char zoneY; 12 | 13 | double easting; 14 | double northing; 15 | }; 16 | 17 | 18 | inline std::ostream& operator<<(std::ostream& strm, const UTM& _utm) { 19 | strm << std::setprecision(3); 20 | strm << "zone: " << _utm.zoneX << _utm.zoneY; 21 | strm << ", easting: " << _utm.easting; 22 | strm << ", northing: " << _utm.northing; 23 | return strm; 24 | } 25 | -------------------------------------------------------------------------------- /include/hypatia/models/Exception.h: -------------------------------------------------------------------------------- 1 | // 2 | // TleException.h 3 | // 4 | // Created by Patricio González Vivo on 5/31/18. 5 | // 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | class Exception : public std::runtime_error { 13 | public: 14 | Exception(const char* message) : runtime_error(message) { } 15 | }; 16 | -------------------------------------------------------------------------------- /include/hypatia/models/Orbit.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Orbit 3 | * 4 | * Created by Patricio González Vivo on 5/31/18. 5 | \*****************************************************************************/ 6 | 7 | #pragma once 8 | 9 | #include "TLE.h" 10 | 11 | class Orbit { 12 | public: 13 | Orbit(); 14 | Orbit(const TLE& tle); 15 | 16 | double getEccentricity() const { return m_eccentricity; } 17 | 18 | double getMeanAnomaly(ANGLE_UNIT _type) const; 19 | double getAscendingNode(ANGLE_UNIT _type) const; 20 | double getArgumentPeriapsis(ANGLE_UNIT _type) const; 21 | 22 | double getInclination(ANGLE_UNIT _type) const; 23 | double getMeanMotion() const { return m_meanMotion; } 24 | 25 | double getBStar() const { return m_bstar; } 26 | double getSemiMajorAxis() const { return m_semiMajorAxis; } 27 | double getRecoveredMeanMotion() const { return m_recoveredMeanMotion; } 28 | double getPeriapsis() const { return m_periapsis; } 29 | double getPeriod() const { return m_period; } 30 | 31 | double getEpoch() const { return m_epoch; } 32 | 33 | private: 34 | // Shape 35 | double m_eccentricity; // shape of the ellipse, describing how much it is elongated compared to a circle 36 | double m_semiMajorAxis; // the sum of the periapsis and apoapsis distances divided by two. For circular orbits, 37 | // the semimajor axis is the distance between the centers of the bodies, not the distance of the bodies from the center of mass. 38 | 39 | // Plane Orientation 40 | double m_inclination; // vertical tilt of the ellipse with respect to the reference plane, measured at the ascending 41 | // node (where the orbit passes upward through the reference plane, the green angle i in the diagram). Tilt angle is measured perpendicular to line of intersection between orbital plane and reference plane. Any three points on an ellipse will define the ellipse orbital plane. The plane and the ellipse are both two-dimensional objects defined in three-dimensional space. 42 | double m_ascendingNode; // horizontally orients the ascending node of the ellipse (where the orbit passes upward through 43 | // the reference plane) with respect to the reference frame's vernal point (the green angle Ω in the diagram). 44 | 45 | double m_argumentPeriapsis; // defines the orientation of the ellipse in the orbital plane, as an angle measured from the 46 | // ascending node to the periapsis (the closest point the satellite object comes to the primary object around which it orbits, the blue angle ω in the diagram). 47 | double m_periapsis; 48 | double m_period; 49 | 50 | // Optional 51 | double m_meanMotion; 52 | double m_recoveredMeanMotion; 53 | double m_bstar; 54 | 55 | double m_meanAnomoly; // angle used in calculating the position of a body in an elliptical orbit in the classical 56 | // two-body problem. It is the angular distance from the pericenter which a fictitious body would have if it moved in a circular orbit, with constant speed, in the same orbital period as the actual body in its elliptical orbit 57 | double m_epoch; // Epoch of mean anomaly 58 | }; 59 | 60 | inline std::ostream& operator<<(std::ostream& strm, const Orbit& o) { 61 | strm << std::right << std::fixed; 62 | strm << "Eccentricity: " << std::setw(12) << o.getEccentricity() << std::endl; 63 | strm << "SemiMajor Axis: " << std::setw(12) << o.getSemiMajorAxis() << std::endl; 64 | strm << "Inclination: " << std::setw(12) << o.getInclination(DEGS) << std::endl; 65 | strm << "AscendingNode: " << std::setw(12) << o.getAscendingNode(DEGS) << std::endl; 66 | strm << "ArgumentPeriapsis: " << std::setw(12) << o.getArgumentPeriapsis(DEGS) << std::endl; 67 | strm << "MeanAnomoly: " << std::setw(12) << o.getMeanAnomaly(DEGS) << std::endl; 68 | 69 | strm << "Mean Motion: " << std::setw(12) << o.getMeanMotion() << std::endl; 70 | strm << "Recovered Mean Motion:" << std::setw(12) << o.getRecoveredMeanMotion() << std::endl; 71 | strm << "BStar: " << std::setw(12) << o.getBStar() << std::endl; 72 | 73 | strm << "Periapsis: " << std::setw(12) << o.getPeriapsis() << std::endl; 74 | strm << "Period: " << std::setw(12) << o.getPeriod() << std::endl; 75 | strm << "Epoch: " << std::setw(12) << o.getEpoch() << std::endl; 76 | return strm; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /include/hypatia/models/Pluto.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Pluto.h 3 | * 4 | * Pluto is a class that can calculate the orbit of Pluto. 5 | * It currently requires data from the file 'vsop.bin'. 6 | * 7 | * author: mark huss (mark@mhuss.com) 8 | * Based on Bill Gray's open-source code at projectpluto.com 9 | * 10 | \*****************************************************************************/ 11 | 12 | #pragma once 13 | 14 | #define N_COEFFS 36 15 | #define XEPHEM 16 | 17 | struct PlutoCoeffs { 18 | short j, s, p, dummyToMaintainAlignment; 19 | short lon_a, lon_b, lat_a, lat_b, rad_a, rad_b; 20 | }; 21 | 22 | class Pluto { 23 | public: 24 | static void calcAllLocs (double& _lon, double& _lat, double& _r, const double _jcentury); 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /include/hypatia/models/SGP4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Daniel Warner 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include "TLE.h" 20 | #include "Orbit.h" 21 | #include "../coordinates/ECI.h" 22 | 23 | /** 24 | * @brief The simplified perturbations model 4 propagater. 25 | */ 26 | class SGP4 { 27 | public: 28 | SGP4(); 29 | virtual ~SGP4(); 30 | virtual void setTLE(const TLE& _tle); 31 | 32 | virtual Orbit getOrbit() const { return m_elements; }; 33 | virtual ECI getECI(double _jd) const; 34 | 35 | private: 36 | struct CommonConstants { 37 | double cosio; 38 | double sinio; 39 | double eta; 40 | double t2cof; 41 | double a3ovk2; 42 | double x1mth2; 43 | double x3thm1; 44 | double x7thm1; 45 | double aycof; 46 | double xlcof; 47 | double xnodcf; 48 | double c1; 49 | double c4; 50 | double omgdot; // secular rate of omega (radians/sec) 51 | double xnodot; // secular rate of xnode (radians/sec) 52 | double xmdot; // secular rate of xmo (radians/sec) 53 | }; 54 | 55 | struct NearSpaceConstants { 56 | double c5; 57 | double omgcof; 58 | double xmcof; 59 | double delmo; 60 | double sinmo; 61 | double d2; 62 | double d3; 63 | double d4; 64 | double t3cof; 65 | double t4cof; 66 | double t5cof; 67 | }; 68 | 69 | struct DeepSpaceConstants { 70 | double gsto; 71 | double zmol; 72 | double zmos; 73 | 74 | /* 75 | * lunar / solar constants for epoch 76 | * applied during DeepSpaceSecular() 77 | */ 78 | double sse; 79 | double ssi; 80 | double ssl; 81 | double ssg; 82 | double ssh; 83 | /* 84 | * lunar / solar constants 85 | * used during DeepSpaceCalculateLunarSolarTerms() 86 | */ 87 | double se2; 88 | double si2; 89 | double sl2; 90 | double sgh2; 91 | double sh2; 92 | double se3; 93 | double si3; 94 | double sl3; 95 | double sgh3; 96 | double sh3; 97 | double sl4; 98 | double sgh4; 99 | double ee2; 100 | double e3; 101 | double xi2; 102 | double xi3; 103 | double xl2; 104 | double xl3; 105 | double xl4; 106 | double xgh2; 107 | double xgh3; 108 | double xgh4; 109 | double xh2; 110 | double xh3; 111 | /* 112 | * used during DeepSpaceCalcDotTerms() 113 | */ 114 | double d2201; 115 | double d2211; 116 | double d3210; 117 | double d3222; 118 | double d4410; 119 | double d4422; 120 | double d5220; 121 | double d5232; 122 | double d5421; 123 | double d5433; 124 | double del1; 125 | double del2; 126 | double del3; 127 | /* 128 | * whether the deep space orbit is 129 | * geopotential resonance for 12 hour orbits 130 | */ 131 | bool resonance_flag; 132 | /* 133 | * whether the deep space orbit is 134 | * 24h synchronous resonance 135 | */ 136 | bool synchronous_flag; 137 | }; 138 | 139 | struct IntegratorValues { 140 | double xndot; 141 | double xnddt; 142 | double xldot; 143 | }; 144 | 145 | struct IntegratorConstants { 146 | /* 147 | * integrator constants 148 | */ 149 | double xfact; 150 | double xlamo; 151 | 152 | /* 153 | * integrator values for epoch 154 | */ 155 | struct IntegratorValues values_0; 156 | }; 157 | 158 | struct IntegratorParams { 159 | /* 160 | * integrator values 161 | */ 162 | double xli; 163 | double xni; 164 | double atime; 165 | /* 166 | * itegrator values for current d_atime_ 167 | */ 168 | struct IntegratorValues values_t; 169 | }; 170 | 171 | ECI findPositionSDP4(const double _jd) const; 172 | ECI findPositionSGP4(const double _jd) const; 173 | ECI calculateFinalPositionVelocity(const double tsince, 174 | const double e, 175 | const double a, 176 | const double omega, 177 | const double xl, 178 | const double xnode, 179 | const double xincl, 180 | const double xlcof, 181 | const double aycof, 182 | const double x3thm1, 183 | const double x1mth2, 184 | const double x7thm1, 185 | const double cosio, 186 | const double sinio) const; 187 | /** 188 | * Deep space initialisation 189 | */ 190 | void deepSpaceInitialise( 191 | const double eosq, 192 | const double sinio, 193 | const double cosio, 194 | const double betao, 195 | const double theta2, 196 | const double betao2, 197 | const double xmdot, 198 | const double omgdot, 199 | const double xnodot); 200 | /* 201 | * Calculate lunar / solar terms 202 | */ 203 | void deepSpaceCalculateLunarSolarTerms( 204 | const double tsince, 205 | double& pe, 206 | double& pinc, 207 | double& pl, 208 | double& pgh, 209 | double& ph) const; 210 | /** 211 | * Calculate lunar / solar periodics and apply 212 | */ 213 | void deepSpacePeriodics( 214 | const double tsince, 215 | double& em, 216 | double& xinc, 217 | double& omgasm, 218 | double& xnodes, 219 | double& xll) const; 220 | /** 221 | * Deep space secular effects 222 | */ 223 | void deepSpaceSecular( 224 | const double tsince, 225 | double& xll, 226 | double& omgasm, 227 | double& xnodes, 228 | double& em, 229 | double& xinc, 230 | double& xn) const; 231 | /** 232 | * Calculate dot terms 233 | * @param[in,out] values the integrator values 234 | */ 235 | void deepSpaceCalcDotTerms(struct IntegratorValues& values) const; 236 | /** 237 | * Deep space integrator for time period of delt 238 | */ 239 | void deepSpaceIntegrator( 240 | const double delt, 241 | const double step2, 242 | const struct IntegratorValues& values) const; 243 | void reset(); 244 | 245 | /* 246 | * the constants used 247 | */ 248 | struct CommonConstants m_commonConsts; 249 | struct NearSpaceConstants m_nearspaceConsts; 250 | struct DeepSpaceConstants m_deepspaceConsts; 251 | struct IntegratorConstants m_integratorConsts; 252 | mutable struct IntegratorParams m_integratorParams; 253 | Orbit m_elements; 254 | bool m_useSimpleModel; 255 | bool m_useDeepSpace; 256 | 257 | static const struct SGP4::CommonConstants Empty_CommonConstants; 258 | static const struct SGP4::NearSpaceConstants Empty_NearSpaceConstants; 259 | static const struct SGP4::DeepSpaceConstants Empty_DeepSpaceConstants; 260 | static const struct SGP4::IntegratorConstants Empty_IntegratorConstants; 261 | static const struct SGP4::IntegratorParams Empty_IntegratorParams; 262 | }; 263 | 264 | inline std::ostream& operator<<(std::ostream& strm, const SGP4& s) { 265 | strm << std::right << std::fixed; 266 | strm << "Satelite: " << std::endl; 267 | return strm; 268 | } 269 | -------------------------------------------------------------------------------- /include/hypatia/models/TLE.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * TLE 3 | * 4 | * Created by Patricio González Vivo on 5/31/18. 5 | \*****************************************************************************/ 6 | 7 | #pragma once 8 | 9 | #include "../MathOps.h" 10 | #include 11 | #include 12 | 13 | /** 14 | * @brief Processes a two-line element set used to convey OrbitalElements. 15 | * 16 | * Used to extract the various raw fields from a two-line element set. 17 | */ 18 | class TLE { 19 | public: 20 | TLE(const std::string& line_one, const std::string& line_two); 21 | TLE(const std::string& name, const std::string& line_one, const std::string& line_two); 22 | TLE(const TLE& tle); 23 | 24 | std::string getName() const { return m_name; } 25 | std::string getLine1() const { return m_line_one; } 26 | std::string getLine2() const { return m_line_two; } 27 | 28 | unsigned int getNoradNumber() const { return m_norad_number; } 29 | std::string getIntDesignator() const { return m_int_designator; } 30 | double getEpoch() const { return m_epoch; } 31 | double getMeanMotionDt2() const { return m_mean_motion_dt2; } 32 | double getMeanMotionDdt6() const { return m_mean_motion_ddt6; } 33 | double getBStar() const { return m_bstar; } 34 | double getInclination(ANGLE_UNIT _type) const; 35 | double getRightAscendingNode(ANGLE_UNIT _type) const; 36 | double getEccentricity() const { return m_eccentricity; } 37 | double getArgumentPerigee(ANGLE_UNIT _type) const; 38 | double getMeanAnomaly(ANGLE_UNIT _type) const ; 39 | double getMeanMotion() const { return m_mean_motion; } 40 | unsigned int getOrbitNumber() const { return m_orbit_number; } 41 | 42 | private: 43 | void initialize(); 44 | 45 | private: 46 | std::string m_name; 47 | std::string m_line_one; 48 | std::string m_line_two; 49 | 50 | std::string m_int_designator; // International designator 51 | double m_epoch; 52 | double m_mean_motion_dt2; // first time derivative of the mean motion divided by two 53 | double m_mean_motion_ddt6; // second time derivative of mean motion divided by six 54 | double m_bstar; // BSTAR drag term 55 | double m_inclination; 56 | double m_right_ascending_node; 57 | double m_eccentricity; 58 | double m_argument_perigee; 59 | double m_mean_anomaly; 60 | double m_mean_motion; 61 | unsigned int m_norad_number; 62 | unsigned int m_orbit_number; 63 | }; 64 | 65 | inline std::ostream& operator<<(std::ostream& strm, const TLE& t) { 66 | strm << std::right << std::fixed; 67 | strm << "Norad Number: " << t.getNoradNumber() << std::endl; 68 | strm << "Int. Designator: " << t.getIntDesignator() << std::endl; 69 | strm << "Epoch: " << t.getEpoch() << std::endl; 70 | strm << "Orbit Number: " << t.getOrbitNumber() << std::endl; 71 | strm << std::setprecision(8); 72 | strm << "Eccentricity: "; 73 | strm << std::setw(12) << t.getEccentricity() << std::endl; 74 | strm << "Inclination: "; 75 | strm << std::setw(12) << t.getInclination(DEGS) << std::endl; 76 | strm << "Right Ascending Node: "; 77 | strm << std::setw(12) << t.getRightAscendingNode(DEGS) << std::endl; 78 | strm << "Argument Perigee: "; 79 | strm << std::setw(12) << t.getArgumentPerigee(DEGS) << std::endl; 80 | strm << "Mean Anomaly: "; 81 | strm << std::setw(12) << t.getMeanAnomaly(DEGS) << std::endl; 82 | 83 | strm << "Mean Motion: "; 84 | strm << std::setw(12) << t.getMeanMotion() << std::endl; 85 | strm << "Mean Motion Dt2: "; 86 | strm << std::setw(12) << t.getMeanMotionDt2() << std::endl; 87 | strm << "Mean Motion Ddt6: "; 88 | strm << std::setw(12) << t.getMeanMotionDdt6() << std::endl; 89 | 90 | strm << "BStar: "; 91 | strm << std::setw(12) << t.getBStar() << std::endl; 92 | return strm; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /include/hypatia/models/VSOP87.h: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Vsop.h 3 | * 4 | * The Vsop class wraps the VSOP87 data and provides VSOP support fns 5 | * 6 | * author: mark huss (mark@mhuss.com) 7 | * Based on Bill Gray's open-source code at projectpluto.com 8 | * 9 | \*****************************************************************************/ 10 | 11 | #pragma once 12 | 13 | #include "../Body.h" // for enum Body 14 | 15 | // * * * * * simple support structs * * * * * 16 | 17 | // One VSOP term 18 | 19 | struct VSOP87Set { 20 | double A; 21 | double B; 22 | double C; 23 | }; 24 | 25 | // A set of VSOP terms 26 | struct VSOP87Terms { 27 | unsigned rows; // number of term sets 28 | const VSOP87Set* pTerms; // pointer to start of data 29 | 30 | VSOP87Terms() : rows(0), pTerms(0) {} 31 | VSOP87Terms( unsigned r, const VSOP87Set* p ) : rows(r), pTerms(p) {} 32 | }; 33 | 34 | // A complete collection of VSOP terms (6 Lat, 6 Lon, 6 Rad ) 35 | 36 | typedef const VSOP87Terms AstroTerms[3*6]; 37 | 38 | // The main VSOP support class 39 | 40 | class VSOP87 { 41 | public: 42 | // location elements (longitude, latitide, distance) 43 | // 44 | enum LocType { ECLIPTIC_LON = 0, ECLIPTIC_LAT = 1, RADIUS = 2 }; 45 | 46 | // calculate the spec'd location element of the spec'd body at the given time 47 | // 48 | static double calcLoc( 49 | double cen, // time in decimal centuries 50 | BodyId planet, // must be in the range SUN...NEPTUNE 51 | LocType value); // 0=ecliptic lon, 1=ecliptic lat, 2=radius 52 | 53 | // calculate all three location elements of the spec'd body at the given time 54 | // 55 | static void calcAllLocs( 56 | double& lon, // returned longitude 57 | double& lat, // returned latitude 58 | double& rad, // returned radius vector 59 | double cen, // time in decimal centuries 60 | BodyId planet) // must be in the range SUN...NEPTUNE 61 | { 62 | lon = calcLoc( cen, planet, ECLIPTIC_LON ); 63 | lat = calcLoc( cen, planet, ECLIPTIC_LAT ); 64 | rad = calcLoc( cen, planet, RADIUS ); 65 | } 66 | }; // end class Vsop 67 | -------------------------------------------------------------------------------- /include/hypatia/primitives/DateTime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TimeSpan.h" 4 | 5 | /** 6 | * @brief Represents an instance in time. 7 | * Default contructor initialise to 0001/01/01 00:00:00.000000 8 | */ 9 | class DateTime { 10 | public: 11 | 12 | DateTime(); 13 | DateTime(int64_t _ticks); 14 | DateTime(unsigned int _year, double _DoY); 15 | DateTime(int _year, int _month, int _day); 16 | DateTime(int _year, int _month, int _day, int _hour, int _minute, int _second); 17 | virtual ~DateTime(); 18 | 19 | virtual TimeSpan getTimeOfDay() const; 20 | virtual int64_t getTicks() const; 21 | 22 | virtual int getYear() const; 23 | virtual int getMonth() const; 24 | virtual int getDay() const; 25 | virtual int getHour() const; 26 | virtual int getMinute() const; 27 | virtual int getSecond() const; 28 | virtual int getMicrosecond() const; 29 | 30 | static DateTime now(bool microseconds = false); 31 | 32 | virtual DateTime add(const TimeSpan& t) const; 33 | virtual DateTime addYears(const int years) const; 34 | virtual DateTime addMonths(const int months) const; 35 | virtual DateTime addDays(const double days) const; 36 | virtual DateTime addHours(const double hours) const; 37 | virtual DateTime addMinutes(const double minutes) const; 38 | virtual DateTime addSeconds(const double seconds) const; 39 | virtual DateTime addMicroseconds(const double microseconds) const; 40 | virtual DateTime addTicks(int64_t ticks) const; 41 | 42 | virtual DateTime operator+ (const TimeSpan& _ts) const; 43 | virtual DateTime operator+ (const DateTime& _dt) const; 44 | virtual DateTime operator- (const TimeSpan& _ts) const; 45 | virtual DateTime operator- (const DateTime& _dt) const; 46 | 47 | virtual bool operator==(const DateTime& _dt) const; 48 | virtual bool operator!=(const DateTime& _dt) const; 49 | virtual bool operator>(const DateTime& dt) const; 50 | virtual bool operator>=(const DateTime& _dt) const; 51 | virtual bool operator<(const DateTime& _dt) const; 52 | virtual bool operator<=(const DateTime& _dt) const; 53 | 54 | protected: 55 | void initialise(int year, int month, int day, int hour, int minute, int second, int microsecond); 56 | 57 | int64_t m_encoded; 58 | }; 59 | 60 | inline std::ostream& operator<<(std::ostream& strm, const DateTime& _dt) { 61 | strm << std::right << std::setfill('0'); 62 | strm << std::setw(4) << _dt.getYear() << "-"; 63 | strm << std::setw(2) << _dt.getMonth() << "-"; 64 | strm << std::setw(2) << _dt.getDay() << " "; 65 | strm << std::setw(2) << _dt.getHour() << ":"; 66 | strm << std::setw(2) << _dt.getMinute() << ":"; 67 | strm << std::setw(2) << _dt.getSecond() << "."; 68 | strm << std::setw(6) << _dt.getMicrosecond() << " UTC"; 69 | return strm; 70 | } 71 | -------------------------------------------------------------------------------- /include/hypatia/primitives/Matrix3x3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Vector3.h" 4 | 5 | class Matrix3x3 { 6 | public: 7 | Matrix3x3(); 8 | Matrix3x3(const double* _m); 9 | Matrix3x3(const double _m00, const double _m01, const double _m02, 10 | const double _m10, const double _m11, const double _m12, 11 | const double _m20, const double _m21, const double _m22); 12 | 13 | Matrix3x3(Vector3& _v0, Vector3& _v1, Vector3& _v2); 14 | Matrix3x3(const Matrix3x3& _m); 15 | virtual ~Matrix3x3(); 16 | 17 | static Matrix3x3 transpose(const Matrix3x3& _m); 18 | static Matrix3x3 rotationX(const double _radians); 19 | static Matrix3x3 rotationY(const double _radians); 20 | static Matrix3x3 rotationZ(const double _radians); 21 | static Matrix3x3 rotation(const double _radians, const Vector3& _axis); 22 | 23 | void transpose(); 24 | void rotateX(const double _radians); 25 | void rotateY(const double _radians); 26 | void rotateZ(const double _radians); 27 | 28 | // product 29 | Matrix3x3 operator*(const Matrix3x3& _m) const; 30 | Vector3 operator*(const Vector3& _v) const; 31 | Matrix3x3& operator=(const Matrix3x3& _m); 32 | Matrix3x3& operator*=(const Matrix3x3& _m); 33 | Matrix3x3& operator*=(const double _s); 34 | Matrix3x3& operator/=(const double _s); 35 | Matrix3x3 operator*(const double _s) const; 36 | Matrix3x3 operator/(const double _s) const; 37 | 38 | Vector3 getRow(size_t _i) const; 39 | Vector3 getColumn(size_t _i) const; 40 | 41 | void setData(const double* _m); 42 | double* getData() { return &m_data[0][0]; } 43 | const double* getData() const { return &m_data[0][0]; } 44 | 45 | protected: 46 | 47 | double m_data[3][3]; 48 | }; 49 | -------------------------------------------------------------------------------- /include/hypatia/primitives/Polar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "hypatia/MathOps.h" 4 | #include 5 | 6 | class Polar { 7 | public: 8 | Polar(); 9 | Polar(const double _phi, const double _theta, ANGLE_UNIT _type); 10 | virtual ~Polar(); 11 | 12 | virtual Polar& invert(); 13 | 14 | virtual double& operator[]( int _n ); 15 | virtual double operator[]( int _n ) const; 16 | 17 | protected: 18 | virtual double * getPtr(); 19 | virtual const double * getPtr() const; 20 | 21 | double m_phi; 22 | double m_theta; 23 | }; 24 | 25 | inline std::ostream& operator<<(std::ostream& strm, const Polar& p) { 26 | strm << std::setprecision(3); 27 | strm << "phi: " << std::setw(8) << p[0]; 28 | strm << ", theta: " << std::setw(8) << p[1]; 29 | return strm; 30 | } 31 | 32 | -------------------------------------------------------------------------------- /include/hypatia/primitives/TimeSpan.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * @brief Represents a time interval. 8 | * 9 | * Represents a time interval (duration/elapsed) that is measured as a positive 10 | * or negative number of days, hours, minutes, seconds, and fractions 11 | * of a second. 12 | */ 13 | class TimeSpan{ 14 | public: 15 | TimeSpan(int64_t ticks); 16 | TimeSpan(int hours, int minutes, int seconds); 17 | TimeSpan(int days, int hours, int minutes, int seconds); 18 | TimeSpan(int days, int hours, int minutes, int seconds, int microseconds); 19 | virtual ~TimeSpan(); 20 | 21 | virtual TimeSpan operator+ (const TimeSpan& _ts) const; 22 | virtual TimeSpan operator- (const TimeSpan& _ts) const; 23 | virtual bool operator==(const TimeSpan& _ts) const; 24 | virtual bool operator!=(const TimeSpan& _ts) const; 25 | virtual bool operator>(const TimeSpan& ts) const; 26 | virtual bool operator>=(const TimeSpan& _ts) const; 27 | virtual bool operator<(const TimeSpan& _ts) const; 28 | virtual bool operator<=(const TimeSpan& _ts) const; 29 | 30 | virtual int64_t getTicks() const; 31 | 32 | virtual int getDays() const; 33 | virtual int getHours() const; 34 | virtual int getMinutes() const; 35 | virtual int getSeconds() const; 36 | virtual int getMilliseconds() const; 37 | virtual int getMicroseconds() const; 38 | 39 | virtual double getTotalDays() const; 40 | virtual double getTotalHours() const; 41 | virtual double getTotalMinutes() const; 42 | virtual double getTotalSeconds() const; 43 | virtual double getTotalMilliseconds() const; 44 | virtual double getTotalMicroseconds() const; 45 | 46 | static const int64_t TICKS_PER_DAY; 47 | static const int64_t TICKS_PER_HOUR; 48 | static const int64_t TICKS_PER_MINUTE; 49 | static const int64_t TICKS_PER_SECOND; 50 | static const int64_t TICKS_PER_MILLISECOND; 51 | static const int64_t TICKS_PER_MICROSECOND; 52 | static const int64_t UNIX_EPOCH; 53 | static const int64_t GREGORIAN_EPOCH; // 1582-Oct-15 54 | static const int64_t MAX_VALUE_TICKS; 55 | 56 | protected: 57 | void updateTicks(int _days, int _hours, int _minutes, int _seconds, int _microseconds); 58 | 59 | int64_t m_ticks; 60 | }; 61 | 62 | inline std::ostream& operator<<(std::ostream& strm, const TimeSpan& _ts) { 63 | strm << std::right << std::setfill('0'); 64 | 65 | if (_ts.getTicks() < 0) { 66 | strm << '-'; 67 | } 68 | 69 | if (_ts.getDays() != 0) { 70 | strm << std::setw(2) << std::abs(_ts.getDays()) << '.'; 71 | } 72 | 73 | strm << std::setw(2) << std::abs(_ts.getHours()) << ':'; 74 | strm << std::setw(2) << std::abs(_ts.getMinutes()) << ':'; 75 | strm << std::setw(2) << std::abs(_ts.getSeconds()); 76 | 77 | if (_ts.getMicroseconds() != 0) { 78 | strm << '.' << std::setw(6) << std::abs(_ts.getMicroseconds()); 79 | } 80 | 81 | return strm; 82 | } 83 | -------------------------------------------------------------------------------- /include/hypatia/primitives/Vector2.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Polar.h" 4 | 5 | class Vector2 { 6 | public: 7 | Vector2(); 8 | Vector2(const Polar& _polar); 9 | Vector2(const double _x, const double _y); 10 | 11 | virtual ~Vector2(); 12 | 13 | double x, y; 14 | 15 | virtual double getMagnitud() const; 16 | virtual Vector2 getNormalized() const; 17 | 18 | virtual double dot(const Vector2& _vec) const; 19 | 20 | virtual Vector2& normalize(); 21 | 22 | virtual double& operator[]( int _n ); 23 | virtual double operator[]( int _n ) const; 24 | 25 | virtual Vector2 operator+ (const Vector2& _vec) const; 26 | virtual Vector2 operator- (const Vector2& _vec) const; 27 | virtual Vector2 operator* (const Vector2& _vec) const; 28 | virtual Vector2 operator/ (const Vector2& _vec) const; 29 | 30 | virtual Vector2 operator+ (double _d) const; 31 | virtual Vector2 operator- (double _d) const; 32 | virtual Vector2 operator* (double _d) const; 33 | virtual Vector2 operator/ (double _d) const; 34 | 35 | virtual Vector2& operator+= (const Vector2& _vec); 36 | virtual Vector2& operator-= (const Vector2& _vec); 37 | virtual Vector2& operator*= (const Vector2& _vec); 38 | virtual Vector2& operator/= (const Vector2& _vec); 39 | 40 | virtual Vector2& operator+= (double _d); 41 | virtual Vector2& operator-= (double _d); 42 | virtual Vector2& operator*= (double _d); 43 | virtual Vector2& operator/= (double _d); 44 | 45 | protected: 46 | virtual double * getPtr(); 47 | virtual const double * getPtr() const; 48 | }; 49 | 50 | inline std::ostream& operator<<(std::ostream& strm, const Vector2& v) { 51 | // strm << std::setprecision(3); 52 | strm << " " << std::setw(8) << v.x; 53 | strm << "," << std::setw(8) << v.y; 54 | return strm; 55 | } 56 | -------------------------------------------------------------------------------- /include/hypatia/primitives/Vector3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Polar.h" 4 | 5 | class Vector3 { 6 | public: 7 | Vector3(); 8 | Vector3(const Polar& _polar); 9 | Vector3(const double _x, const double _y, const double _z); 10 | 11 | virtual ~Vector3(); 12 | 13 | double x, y, z; 14 | 15 | virtual double getMagnitud() const; 16 | virtual Vector3 getNormalized() const; 17 | 18 | virtual double getLongitude(ANGLE_UNIT _type) const; 19 | virtual double getLatitude(ANGLE_UNIT _type) const; 20 | 21 | virtual double dot(const Vector3& _vec) const; 22 | 23 | virtual Vector3& normalize(); 24 | virtual Vector3& rotate(double _lng, double _lat, bool _radians = false); 25 | virtual Vector3& rotate(double _angle, int _axis, bool _radians = false); 26 | virtual Vector3& rotate(double _angle, const Vector3& _axis, bool _radians = false); 27 | 28 | virtual double& operator[]( int _n ); 29 | virtual double operator[]( int _n ) const; 30 | 31 | virtual Vector3 operator+ (const Vector3& _vec) const; 32 | virtual Vector3 operator- (const Vector3& _vec) const; 33 | virtual Vector3 operator* (const Vector3& _vec) const; 34 | virtual Vector3 operator/ (const Vector3& _vec) const; 35 | 36 | virtual Vector3 operator+ (double _d) const; 37 | virtual Vector3 operator- (double _d) const; 38 | virtual Vector3 operator* (double _d) const; 39 | virtual Vector3 operator/ (double _d) const; 40 | 41 | virtual Vector3& operator+= (const Vector3& _vec); 42 | virtual Vector3& operator-= (const Vector3& _vec); 43 | virtual Vector3& operator*= (const Vector3& _vec); 44 | virtual Vector3& operator/= (const Vector3& _vec); 45 | 46 | virtual Vector3& operator+= (double _d); 47 | virtual Vector3& operator-= (double _d); 48 | virtual Vector3& operator*= (double _d); 49 | virtual Vector3& operator/= (double _d); 50 | 51 | protected: 52 | virtual double * getPtr(); 53 | virtual const double * getPtr() const; 54 | }; 55 | 56 | inline std::ostream& operator<<(std::ostream& strm, const Vector3& v) { 57 | strm << std::setprecision(3); 58 | strm << " " << std::setw(8) << v.x; 59 | strm << "," << std::setw(8) << v.y; 60 | strm << "," << std::setw(8) << v.z; 61 | 62 | return strm; 63 | } 64 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | hypatia: is an astronomy library based on Mark Huss's and Bill Gray's code. Both authors have very technical and ambitious projects, with over comboluted code for my porposes. I mostly: 5 | - simplify the C++ interfaces by making simpler and clear objects and classes 6 | - clean the dependences so the C++ code can be added to other C++ projects easily 7 | - add Python package which makes a C++ wrapper usign swig 8 | """ 9 | 10 | from distutils.core import setup, Extension 11 | 12 | doc_lines = __doc__.split('\n') 13 | hypatia_module = Extension( 14 | '_hypatia', 15 | include_dirs=['include'], 16 | sources= [ 17 | 'hypatia_wrap.cxx', 18 | 'src/primitives/Polar.cpp', 19 | 'src/primitives/Vector2.cpp', 20 | 'src/primitives/Vector3.cpp', 21 | 'src/primitives/TimeSpan.cpp', 22 | 'src/primitives/DateTime.cpp', 23 | 'src/coordinates/Galactic.cpp', 24 | 'src/coordinates/Ecliptic.cpp', 25 | 'src/coordinates/Equatorial.cpp', 26 | 'src/coordinates/Horizontal.cpp', 27 | 'src/coordinates/Geodetic.cpp', 28 | 'src/coordinates/ECI.cpp', 29 | 'src/coordinates/Tile.cpp', 30 | 'src/MathOps.cpp', 31 | 'src/TimeOps.cpp', 32 | 'src/CoordOps.cpp', 33 | 'src/ProjOps.cpp', 34 | 'src/Observer.cpp', 35 | 'src/Body.cpp', 36 | 'src/Luna.cpp', 37 | 'src/Star.cpp', 38 | 'src/Constellation.cpp', 39 | 'src/Satellite.cpp', 40 | 'src/models/VSOP87.cpp', 41 | 'src/models/Pluto.cpp', 42 | 'src/models/TLE.cpp', 43 | 'src/models/Orbit.cpp', 44 | 'src/models/SGP4.cpp' 45 | ], 46 | swig_opts = ['-c++'] 47 | ) 48 | 49 | setup( 50 | name = 'hypatia', 51 | description = doc_lines[0], 52 | long_description = '\n'.join(doc_lines[2:]), 53 | version = '0.2', 54 | author = 'Patricio Gonzalez Vivo', 55 | author_email = 'patriciogonzalezvivo@gmail.com', 56 | license = "BSD", 57 | ext_modules = [ hypatia_module ], 58 | py_modules = [ 'hypatia' ], 59 | ) 60 | -------------------------------------------------------------------------------- /src/Body.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Body.cpp 3 | * 4 | * Handles planetary motion calculations and conversions 5 | * 6 | * author: mark huss (mark@mhuss.com) 7 | * Based on Bill Gray's open-source code at projectpluto.com 8 | * 9 | \*****************************************************************************/ 10 | 11 | #include "hypatia/Body.h" 12 | 13 | #include "hypatia/CoordOps.h" 14 | 15 | #include "hypatia/Luna.h" 16 | #include "hypatia/models/Pluto.h" 17 | #include "hypatia/models/VSOP87.h" 18 | 19 | static char* bodyNames[] = { (char*)"Sun", (char*)"Mer", (char*)"Ven", (char*)"Earth", (char*)"Mar", (char*)"Jup", (char*)"Sat", (char*)"Ur", (char*)"Nep", (char*)"Pl", (char*)"Luna", (char*)"Satellite" }; 20 | 21 | static char* zodiacSigns[] = { (char*)"Ari", (char*)"Tau", (char*)"Gem", (char*)"Cnc", (char*)"Leo", (char*)"Vir", (char*)"Lib", (char*)"Sco", (char*)"Sgr", (char*)"Cap", (char*)"Aqr", (char*)"Psc" }; 22 | 23 | // Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, Moon, Sats 24 | static double period[] = { 0.0, 0.240846, 0.615, 1.0, 1.881, 11.86, 29.46, 84.01, 164.8, 248.1, 0.0751, 0.0 }; 25 | 26 | Body::Body() : m_jcentury(0.0), m_ha(0.0), m_bodyId( NAB ) { 27 | } 28 | 29 | Body::Body( BodyId _body ) : m_jcentury(0.0), m_ha(0.0), m_bodyId( _body ) { 30 | } 31 | 32 | Body::~Body() { 33 | } 34 | 35 | char* Body::getName() const { 36 | return bodyNames[m_bodyId]; 37 | } 38 | 39 | char * Body::getZodiacSign() const { 40 | return zodiacSigns[ int((m_geocentric.getLongitude(RADS)/MathOps::TAU)*12.)%12 ]; 41 | } 42 | 43 | double Body::getHourAngle(ANGLE_UNIT _type) const { 44 | if ( _type == DEGS ) { 45 | return MathOps::toDegrees( m_ha );;; 46 | } 47 | else { 48 | return m_ha; 49 | } 50 | } 51 | 52 | double Body::getPeriod(TIME_UNIT _unit) const { 53 | if (m_bodyId > SUN && m_bodyId < SATELLITE) { 54 | return TimeOps::yearTo(period[m_bodyId], _unit); 55 | } 56 | else { 57 | return 0.0; 58 | } 59 | } 60 | 61 | // calculate the data for a given planet, jd, and location 62 | // 63 | void Body::compute( Observer& _obs ) { 64 | // There's a lot of calculating here, but the one we need most often 65 | // is the last one (AltAzLoc), which depends on all the previous 66 | // calculations 67 | // 68 | // if (m_jcentury != _obs.getJC()) 69 | { 70 | m_jcentury = _obs.getJC(); 71 | 72 | // choose appropriate method, based on planet 73 | // 74 | if (LUNA == m_bodyId) { /* not VSOP */ 75 | static Luna luna; 76 | luna.compute(_obs); 77 | m_geocentric = luna.getEclipticGeocentric(); 78 | m_heliocentric = luna.getEclipticHeliocentric(); 79 | 80 | } 81 | else if (PLUTO == m_bodyId) { /* not VSOP */ 82 | double hLng, hLat, rad = 0.0; 83 | Pluto::calcAllLocs(hLng, hLat, rad, m_jcentury); 84 | m_heliocentric = Ecliptic(hLng, hLat, rad, RADS, AU); 85 | m_geocentric = CoordOps::toGeocentric(_obs, m_heliocentric); 86 | } 87 | else if (SUN == m_bodyId) { 88 | double hLng, hLat, rad = 0.0; 89 | VSOP87::calcAllLocs(hLng, hLat, rad, m_jcentury, EARTH); 90 | m_heliocentric = Ecliptic(hLng, hLat, rad, RADS, AU); 91 | 92 | /* 93 | * What we _really_ want is the location of the sun as seen from 94 | * the earth (geocentric view). VSOP gives us the opposite 95 | * (heliocentric) view, i.e., the earth as seen from the sun. 96 | * To work around this, we add PI to the longitude (rotate 180 degrees) 97 | * and negate the latitude. 98 | */ 99 | m_geocentric = Ecliptic(hLng + MathOps::PI, hLat * -1., rad, RADS, AU); 100 | } 101 | else { 102 | double hLng, hLat, rad = 0.0; 103 | VSOP87::calcAllLocs(hLng, hLat, rad, m_jcentury, m_bodyId); 104 | m_heliocentric = Ecliptic(hLng, hLat, rad, RADS, AU); 105 | m_geocentric = CoordOps::toGeocentric(_obs, m_heliocentric); 106 | } 107 | 108 | if (m_bodyId == EARTH) { 109 | m_geocentric = Ecliptic(0., 0., 0., RADS, AU); 110 | } 111 | 112 | m_equatorial = CoordOps::toEquatorial( _obs, m_geocentric ); 113 | 114 | if ( _obs.haveLocation() ) { 115 | m_ha = MathOps::normalize(CoordOps::toHourAngle( _obs, m_equatorial ), RADS); 116 | m_horizontal = CoordOps::toHorizontal( _obs, m_equatorial ); 117 | m_bHorizontal = true; 118 | } 119 | else { 120 | m_ha = 0.0; 121 | m_horizontal[0] = 0.0; 122 | m_horizontal[1] = 0.0; 123 | m_bHorizontal = false; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Note that headers are optional, and do not affect add_library, but they will not 2 | # show up in IDEs unless they are listed in add_library. 3 | 4 | file(GLOB ROOT_HEADER "${PROJECT_SOURCE_DIR}/include/hypatia/*.h") 5 | file(GLOB ROOT_SOURCE "${PROJECT_SOURCE_DIR}/src/*.cpp") 6 | 7 | file(GLOB COORD_HEADER "${PROJECT_SOURCE_DIR}/include/hypatia/coordinates/*.h") 8 | file(GLOB COORD_SOURCE "${PROJECT_SOURCE_DIR}/src/coordinates/*.cpp") 9 | 10 | file(GLOB MODEL_HEADER "${PROJECT_SOURCE_DIR}/include/hypatia/models/*.h") 11 | file(GLOB MODEL_SOURCE "${PROJECT_SOURCE_DIR}/src/models/*.cpp") 12 | 13 | file(GLOB PRIMI_HEADER "${PROJECT_SOURCE_DIR}/include/hypatia/primitives/*.h") 14 | file(GLOB PRIMI_SOURCE "${PROJECT_SOURCE_DIR}/src/primitives/*.cpp") 15 | 16 | set(INCLUDE_FOLDER "${PROJECT_SOURCE_DIR}/include") 17 | set(INCLUDE_SWIG_FILE "${PROJECT_SOURCE_DIR}/${PROJECT_NAME}.i") 18 | 19 | # Make an automatic library - will be static or dynamic based on user setting 20 | add_library(hypatia ${ROOT_SOURCE} ${COORD_SOURCE} ${MODEL_SOURCE} ${PRIMI_SOURCE}) 21 | 22 | # We need this directory, and users of our library will need it too 23 | target_include_directories(hypatia PUBLIC ../include) 24 | 25 | # IDEs should put the headers in a nice place 26 | source_group( TREE "${PROJECT_SOURCE_DIR}/include" 27 | PREFIX "Header Files" FILES ${ROOT_HEADER}) 28 | 29 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 30 | 31 | install(TARGETS ${PROJECT_NAME} DESTINATION lib) 32 | install(FILES ${ROOT_HEADER} DESTINATION include/hypatia) 33 | install(FILES ${COORD_HEADER} DESTINATION include/hypatia/coordinates) 34 | install(FILES ${MODEL_HEADER} DESTINATION include/hypatia/models) 35 | install(FILES ${PRIMI_HEADER} DESTINATION include/hypatia/primitives) 36 | 37 | 38 | # PYTHON BINDINGS 39 | # 40 | # if(POLICY CMP0078) 41 | # cmake_policy(SET CMP0078 OLDif(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)) 42 | # endif(POLICY CMP0078) 43 | 44 | # if(POLICY CMP0086) 45 | # cmake_policy(SET CMP0086 OLD) 46 | # endif(POLICY CMP0086) 47 | 48 | find_package(PythonLibs REQUIRED) 49 | include_directories(${PYTHON_INCLUDE_DIRS}) 50 | if(NOT PYTHON_NUMPY_INCLUDE_DIR) 51 | execute_process(COMMAND python3 -c "import numpy; print(numpy.get_include())" 52 | RESULT_VARIABLE PYTHON_NUMPY_PROCESS 53 | OUTPUT_VARIABLE PYTHON_NUMPY_INCLUDE_DIR 54 | OUTPUT_STRIP_TRAILING_WHITESPACE) 55 | 56 | if(PYTHON_NUMPY_PROCESS EQUAL 0) 57 | file(TO_CMAKE_PATH "${PYTHON_NUMPY_INCLUDE_DIR}" PYTHON_NUMPY_INCLUDE_CMAKE_PATH) 58 | set(PYTHON_NUMPY_INCLUDE_DIR ${PYTHON_NUMPY_INCLUDE_CMAKE_PATH} CACHE PATH "Numpy include directory") 59 | else() 60 | message(SEND_ERROR "Could not determine the NumPy include directory, verify that NumPy was installed correctly.") 61 | endif() 62 | endif() 63 | 64 | include_directories(${PYTHON_NUMPY_INCLUDE_DIR} ${INCLUDE_FOLDER}) 65 | set_property(SOURCE ${INCLUDE_SWIG_FILE} PROPERTY CPLUSPLUS ON) 66 | 67 | find_package(SWIG REQUIRED) 68 | include(${SWIG_USE_FILE}) 69 | cmake_policy(SET CMP0078 NEW) 70 | cmake_policy(SET CMP0086 NEW) 71 | include(UseSWIG) 72 | set(UseSWIG_TARGET_NAME_PREFERENCE STANDARD) 73 | set(PYTHON_WRAPPER "${PROJECT_SOURCE_DIR}/hypatia.i") 74 | set_property( 75 | SOURCE "${PYTHON_WRAPPER}" PROPERTY 76 | GENERATED_INCLUDE_DIRECTORIES "${PYTHON_INCLUDE_DIRS}" 77 | ) 78 | set_property( 79 | SOURCE "${PYTHON_WRAPPER}" PROPERTY 80 | CPLUSPLUS ON 81 | ) 82 | swig_add_library(py${PROJECT_NAME} 83 | LANGUAGE python 84 | SOURCES ${INCLUDE_SWIG_FILE} ${ROOT_SOURCE} ${COORD_SOURCE} ${MODEL_SOURCE} ${PRIMI_SOURCE}) 85 | target_link_libraries(py${PROJECT_NAME} ${PYTHON_LIBRARIES}) 86 | 87 | # INSTALL PYTHON BINDINGS 88 | # Get the python site packages directory by invoking python 89 | execute_process(COMMAND python3 -c "import site; print(site.getsitepackages()[0])" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) 90 | message("Installing at ${SITE_PACKAGES}") 91 | 92 | install(TARGETS py${PROJECT_NAME} DESTINATION ${PYTHON_SITE_PACKAGES}) 93 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.py DESTINATION ${PYTHON_SITE_PACKAGES}) 94 | endif() -------------------------------------------------------------------------------- /src/MathOps.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/MathOps.h" 2 | 3 | #include 4 | #include 5 | 6 | // In-class constants cannot be initialized in the class declaration. Sigh. 7 | // 8 | 9 | const double MathOps::PI = 3.1415926535897932384626433832795028841971693993751058209749445923; 10 | const double MathOps::TAU = 6.2831853071795864769252867665590; 11 | const double MathOps::PI_OVER_TWO = 1.57079632679489661923; 12 | const double MathOps::TWO_OVER_PI = 0.63661977236758134308; 13 | 14 | const double MathOps::RADS_TO_DEGS = 5.7295779513082320877e1; 15 | const double MathOps::DEGS_TO_RADS = 1.7453292519943295769e-2; 16 | 17 | const double MathOps::RAD_PER_CIRCLE = TAU; 18 | const double MathOps::DEG_PER_CIRCLE = 360.; 19 | const double MathOps::MINUTES_PER_DEGREE = 60.; 20 | const double MathOps::SECONDS_PER_DEGREE = 3600.; 21 | 22 | const double MathOps::RADS_PER_DEGREE = RAD_PER_CIRCLE / DEG_PER_CIRCLE; 23 | 24 | const double MathOps::DEGS_TO_HRS = 1. / 15.; 25 | 26 | const double MathOps::RADS_TO_ARCS = 2.0626480624709635516e5; 27 | const double MathOps::ARCS_TO_RADS = 4.8481368110953599359e-6; 28 | 29 | const double MathOps::RADIAN = (180.0 / MathOps::PI); 30 | 31 | const double MathOps::ROUND = 0.5; 32 | const double MathOps::INVALID = -1.0; 33 | 34 | const double MathOps::TWO_THIRD = 2.0 / 3.0; 35 | 36 | /** 37 | * toDegrees(): convert radians to degrees 38 | * 39 | * @param an angle in radians 40 | * 41 | * @return an angle in degrees 42 | */ 43 | double MathOps::toDegrees( double _rad ) { 44 | return _rad * RADS_TO_DEGS; 45 | }; 46 | 47 | /** 48 | * toDegrees(): convert radians to degrees 49 | * 50 | * @param an degrees 51 | * @param an minutes 52 | * @param an seconds 53 | * 54 | * @return an angle in degrees 55 | */ 56 | double MathOps::toDegrees( int _deg, int _min, double _sec ) { 57 | double sign = 1.0; 58 | if ( (_deg < 0) || (_min < 0) || (_sec < 0) ) { 59 | sign = -1.0; 60 | } 61 | return sign * (fabs(_deg) + fabs(_min)/MINUTES_PER_DEGREE + fabs(_sec)/SECONDS_PER_DEGREE); 62 | } 63 | 64 | /** 65 | * toRadians(): convert degrees to radians 66 | * 67 | * @param an angle in degrees 68 | * 69 | * @return an angle in radians 70 | */ 71 | double MathOps::toRadians( double _deg ) { 72 | return _deg * DEGS_TO_RADS; 73 | }; 74 | 75 | /** 76 | * secToRadians(): convert arcseconds to radians 77 | * 78 | * @param an angle in arcseconds 79 | * 80 | * @return an angle in radians 81 | */ 82 | double MathOps::secToRadians( double _sec ) { 83 | return (_sec/MathOps::SECONDS_PER_DEGREE) * MathOps::RADS_PER_DEGREE; 84 | } 85 | 86 | /** 87 | * toHrs(): convert arcseconds to radians 88 | * 89 | * @param degrees 90 | * 91 | * @return hours double 92 | */ 93 | double MathOps::toHrs( double _angle, ANGLE_UNIT _type ) { 94 | if ( _type == RADS ) { 95 | _angle = MathOps::toDegrees(_angle); 96 | } 97 | return _angle * DEGS_TO_HRS; 98 | }; 99 | 100 | //---------------------------------------------------------------------------- 101 | // reduce an angle in degrees to (0 <= d < 360) or (0 <= d << 2PI ) 102 | // 103 | double MathOps::normalize ( double _angle, ANGLE_UNIT _type ) { 104 | 105 | if ( _type == DEGS ) { 106 | if (_angle >= 0.0 && 107 | _angle < MathOps::DEG_PER_CIRCLE ) { 108 | return _angle; 109 | } 110 | 111 | _angle = MathOps::mod( _angle, MathOps::DEG_PER_CIRCLE); 112 | if ( _angle < 0.) { 113 | _angle += MathOps::DEG_PER_CIRCLE; 114 | } 115 | return _angle; 116 | 117 | // double temp = (int)(_angle / MathOps::DEG_PER_CIRCLE); 118 | // if ( _angle < 0.0 ) { 119 | // temp --; 120 | // } 121 | // temp *= MathOps::DEG_PER_CIRCLE; 122 | // return _angle - temp; 123 | } 124 | else { 125 | if (_angle >= 0.0 && 126 | _angle < MathOps::TAU ) { 127 | return _angle; 128 | } 129 | 130 | _angle = MathOps::mod( _angle, MathOps::TAU ); 131 | if ( _angle < 0. ) { 132 | _angle += MathOps::TAU; 133 | } 134 | return _angle; 135 | 136 | // double temp = (int)(_angle / MathOps::TAU); 137 | // if ( _angle < 0.0 ) { 138 | // temp --; 139 | // } 140 | // temp *= MathOps::TAU; 141 | // return _angle - temp; 142 | } 143 | } 144 | 145 | /** 146 | * quadrant(): returns the quadrant ( 0, 1, 2, or 3 ) of the spec'd angle 147 | * 148 | * @param angle - in radians 149 | * 150 | * @return quadrant of angle 151 | */ 152 | 153 | int MathOps::quadrant( double _rad ) { 154 | return (int)( normalize( _rad, RADS ) * MathOps::TWO_OVER_PI ); 155 | } 156 | 157 | void MathOps::toDMS ( double _angle, ANGLE_UNIT _type, int &_deg, int &_min, double &_sec ) { 158 | // int totalSeconds = (int)round( rangeDegrees(_rad) * SECONDS_PER_DEGREE); 159 | // _sec = totalSeconds % 60; 160 | // _min = (totalSeconds / 60) % 60; 161 | // _deg = totalSeconds / (360); 162 | 163 | double degrees = _angle; 164 | if ( _type == RADS) { 165 | degrees = MathOps::toDegrees(_angle); 166 | } 167 | 168 | double dtemp; 169 | int sign = 1; 170 | 171 | if (degrees < 0) 172 | sign = -1; 173 | 174 | degrees = fabs(degrees); 175 | _deg = (int)degrees; 176 | 177 | /* multiply remainder by 60 to get minutes */ 178 | dtemp = 60*(degrees - _deg); 179 | _min = (unsigned short)dtemp; 180 | 181 | /* multiply remainder by 60 to get seconds */ 182 | _sec = 60*(dtemp - _min); 183 | 184 | /* catch any overflows */ 185 | if (_sec > 59) { 186 | _sec = 0; 187 | _min ++; 188 | } 189 | if (_min > 59) { 190 | _min = 0; 191 | _deg ++; 192 | } 193 | 194 | _deg *= sign; 195 | } 196 | 197 | void MathOps::toHMS ( double _angle, ANGLE_UNIT _type, int &_hrs, int &_min, double &_sec ) { 198 | double degrees = _angle; 199 | if ( _type == RADS) { 200 | degrees = MathOps::toDegrees(_angle); 201 | } 202 | 203 | double dtemp; 204 | degrees = normalize(degrees, DEGS); 205 | 206 | /* divide degrees by 15 to get the hours */ 207 | dtemp = degrees * DEGS_TO_HRS; 208 | _hrs = (unsigned short) dtemp; 209 | 210 | /* multiply remainder by 60 to get minutes */ 211 | dtemp = 60 * ( dtemp - _hrs ); 212 | _min = (unsigned short) dtemp; 213 | 214 | /* multiply remainder by 60 to get seconds */ 215 | _sec = 60 * ( dtemp - _min ); 216 | 217 | /* catch any overflows */ 218 | if ( _sec > 59 ) { 219 | _sec = 0; 220 | _min ++; 221 | } 222 | if ( _min > 59) { 223 | _min = 0; 224 | _hrs ++; 225 | } 226 | } 227 | 228 | /** 229 | * formatAngle(): format angle into a string 230 | * 231 | * @param angle value 232 | * @param angle type 233 | * @param format type 234 | * 235 | * @return formated string 236 | * 237 | */ 238 | char* MathOps::formatAngle ( double _angle, ANGLE_UNIT _type, ANGLE_FMT _fmt ) { 239 | double degrees = _angle; 240 | if ( _type == RADS) { 241 | degrees = MathOps::toDegrees(_angle); 242 | } 243 | 244 | char *buf = new char[32]; 245 | 246 | if (_fmt == Dd) { 247 | sprintf ( buf, "%.1f°", degrees); 248 | return buf; 249 | } 250 | else if (_fmt == Ddd) { 251 | sprintf ( buf, "%.2f°", degrees); 252 | return buf; 253 | } 254 | else if (_fmt == Ddd) { 255 | sprintf ( buf, "%.3f°", degrees); 256 | return buf; 257 | } 258 | else if (_fmt == Hs) { 259 | sprintf ( buf, "%.1f°", toHrs(degrees, DEGS)); 260 | return buf; 261 | } 262 | else if (_fmt == Hss) { 263 | sprintf ( buf, "%.2f°", toHrs(degrees, DEGS)); 264 | return buf; 265 | } 266 | else if (_fmt == Hsss) { 267 | sprintf ( buf, "%.3f°", toHrs(degrees, DEGS)); 268 | return buf; 269 | } 270 | 271 | int first, m; 272 | double s; 273 | 274 | char sign = ' '; 275 | if (degrees < 0) { 276 | sign = '-'; 277 | } 278 | 279 | switch (_fmt) { 280 | case D_M_Ss: 281 | MathOps::toDMS(degrees, DEGS, first, m, s); 282 | sprintf ( buf, "%c %02d° %02d' %.2f\"", sign, (int)fabs(first), (int)fabs(m), fabs(s) ); 283 | break; 284 | case D_Mm: 285 | MathOps::toDMS(degrees, DEGS, first, m, s); 286 | sprintf ( buf, "%c %02d° %.2f'", sign, (int)fabs(first), fabs(m + s/60.0)); 287 | break; 288 | case H_M_Ss: 289 | MathOps::toHMS(degrees, DEGS, first, m, s); 290 | sprintf ( buf, "%c %02dhs %02dm %.2fs", sign, (int)fabs(first), (int)fabs(m), fabs(s) ); 291 | break; 292 | case H_Mm: 293 | MathOps::toHMS(degrees, DEGS, first, m, s); 294 | sprintf ( buf, "%c %02dhs %.2fm", sign, (int)fabs(first), fabs(m + s/60.0)); 295 | break; 296 | case Dd: 297 | case Ddd: 298 | case Dddd: 299 | case Hs: 300 | case Hss: 301 | case Hsss: 302 | break; 303 | } 304 | 305 | return buf; 306 | } 307 | 308 | /** 309 | * acose(): "safe" acos which prevents overflow errors 310 | * 311 | * @param angle 312 | * 313 | * @return acos (0 ... PI) 314 | */ 315 | double MathOps::acose ( double _angle ) { 316 | if( _angle >= 1. ) 317 | return( 0. ); 318 | else if( _angle <= -1. ) 319 | return( MathOps::PI ); 320 | else 321 | return( acos( _angle ) ); 322 | } 323 | 324 | /** 325 | * asine(): "safe" asine which prevents overflow errors 326 | * 327 | * @param angle 328 | * 329 | * @return asin (PI/2 ... -PI/2) 330 | */ 331 | double MathOps::asine ( double _angle ) { 332 | if( _angle >= 1. ) 333 | return( MathOps::PI_OVER_TWO ); 334 | else if( _angle <= -1. ) 335 | return( -MathOps::PI_OVER_TWO ); 336 | else 337 | return( asin( _angle ) ); 338 | } 339 | 340 | double MathOps::actan(const double sinx, const double cosx) { 341 | if (cosx == 0.0) { 342 | if (sinx > 0.0) { 343 | return MathOps::PI_OVER_TWO; 344 | } 345 | else { 346 | return 3.0 * MathOps::PI_OVER_TWO; 347 | } 348 | } 349 | else { 350 | if (cosx > 0.0) { 351 | return atan(sinx / cosx); 352 | } 353 | else { 354 | return MathOps::PI + atan(sinx / cosx); 355 | } 356 | } 357 | } 358 | 359 | /** 360 | * fract(): gives the fractional part of a number 361 | * 362 | * @param number 363 | * 364 | * @return fractional part of it 365 | */ 366 | double MathOps::fract ( double _x ) { 367 | return _x - floor(_x); 368 | } 369 | 370 | /** 371 | * mod(): calculates x modulus y 372 | * 373 | * @param base 374 | * 375 | * @return modulus of 376 | */ 377 | double MathOps::mod ( double _x, double _y ) { 378 | return _y * MathOps::fract( _x / _y); 379 | } 380 | 381 | long MathOps::mod ( long x, long y ) { 382 | long rval = x % y; 383 | 384 | if( rval < 0L ) 385 | rval += y; 386 | 387 | return rval; 388 | } 389 | 390 | double MathOps::clamp( double _v, double _low, double _high) { 391 | return (_v < _low) ? _low : (_high < _v) ? _high : _v; 392 | } 393 | -------------------------------------------------------------------------------- /src/Observer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "hypatia/Observer.h" 3 | 4 | #include "hypatia/MathOps.h" 5 | #include "hypatia/CoordOps.h" 6 | 7 | #include "hypatia/models/VSOP87.h" 8 | #include 9 | #include 10 | 11 | Observer::Observer() : 12 | m_cityId(0), 13 | m_jd(0.0), 14 | m_jcentury(0.0), 15 | m_obliquity(0.0), 16 | m_lst(0.0), 17 | m_tzOffsetST(0.0), 18 | m_tzOffsetDST(0.0), 19 | m_tzIndex(0), 20 | m_bLocation(false) { 21 | } 22 | 23 | Observer::Observer(double _jd) : 24 | m_cityId(0), 25 | m_jd(0.0), 26 | m_jcentury(0.0), 27 | m_obliquity(0.0), 28 | m_lst(0.0), 29 | m_tzOffsetST(0.0), 30 | m_tzOffsetDST(0.0), 31 | m_tzIndex(0), 32 | m_bLocation(false) { 33 | if ( _jd == 0 ) { 34 | setJD( TimeOps::now(UTC) ); 35 | } 36 | else { 37 | setJD( _jd ); 38 | } 39 | } 40 | 41 | Observer::Observer(const Geodetic& _location, double _jd) : 42 | m_location(_location), 43 | m_cityId(0), 44 | m_jd(0.0), 45 | m_jcentury(0.0), 46 | m_obliquity(0.0), 47 | m_lst(0.0), 48 | m_tzOffsetST(0.0), 49 | m_tzOffsetDST(0.0), 50 | m_tzIndex(0), 51 | m_bLocation(true) { 52 | if ( _jd == 0 ) { 53 | setJD( TimeOps::now(UTC) ); 54 | } 55 | else { 56 | setJD( _jd ); 57 | } 58 | } 59 | 60 | Observer::Observer( double _lng_deg, double _lat_deg, double _jd) : 61 | m_location(_lng_deg, _lat_deg, 0., DEGS, KM), 62 | m_cityId(0), 63 | m_jd(0.0), 64 | m_jcentury(0.0), 65 | m_obliquity(0.0), 66 | m_lst(0.0), 67 | m_tzOffsetST(0.0), 68 | m_tzOffsetDST(0.0), 69 | m_tzIndex(0), 70 | m_bLocation(true) { 71 | if ( _jd == 0 ) { 72 | setJD( TimeOps::now(UTC) ); 73 | } 74 | else { 75 | setJD( _jd ); 76 | } 77 | } 78 | 79 | Observer::~Observer() { 80 | } 81 | 82 | void Observer::setSeconds(unsigned long _sec) { 83 | if ( _sec == 0 ) { 84 | _sec = TimeOps::nowSeconds(); 85 | } 86 | setJD( TimeOps::toJD(_sec) ); 87 | } 88 | 89 | void Observer::setJD(double _jd) { 90 | if ( m_jd != _jd ) { 91 | m_jd = _jd; 92 | update(); 93 | } 94 | } 95 | 96 | void Observer::setJDLocal(double _jd) { 97 | if ( !haveLocation() || m_tzIndex == 0 ) { 98 | setJD(_jd); 99 | return; 100 | } 101 | 102 | int month, day, year; 103 | TimeOps::toDMY(_jd, day, month, year); 104 | setJD(_jd - (GeoOps::tzIsDST(m_location.getLatitude(RADS), month, day)? m_tzOffsetDST : m_tzOffsetST)); 105 | } 106 | 107 | void Observer::setTimezone(const char* _tz) { 108 | size_t tzIndex = GeoOps::tzNameToIndex(_tz); 109 | if ( tzIndex != m_tzIndex ) 110 | setTimezoneIndex(tzIndex); 111 | } 112 | 113 | void Observer::setLocation(const Geodetic &_location) { 114 | if (m_location.getLongitude(RADS) != _location.getLongitude(RADS) || 115 | m_location.getLatitude(RADS) != _location.getLatitude(RADS) ) { 116 | m_location = _location; 117 | m_bLocation = true; 118 | update(); 119 | } 120 | } 121 | 122 | void Observer::setLocation(double _lng_deg, double _lat_deg) { 123 | if (m_location.getLongitude(DEGS) != _lng_deg || 124 | m_location.getLatitude(DEGS) != _lat_deg ) { 125 | m_location.setLongitude(_lng_deg, DEGS); 126 | m_location.setLatitude(_lat_deg, DEGS); 127 | m_bLocation = true; 128 | update(); 129 | } 130 | } 131 | 132 | size_t Observer::searchLocation(double _lng_deg, double _lat_deg) { 133 | setLocation(Geodetic(_lng_deg, _lat_deg, 0., DEGS, KM)); 134 | m_cityId = GeoOps::findClosestCity(_lng_deg, _lat_deg); 135 | if ( m_cityId == 0 ) { 136 | // No city found, use the current location and construct the correct timezone "Etc/GMT{+X/-X}" basedo on the longitude 137 | 138 | int timezone_number = int( m_location.getLongitude(DEGS) / 15.0); 139 | std::string timezone_name = "Etc/GMT"; 140 | if ( timezone_number > 0 ) { 141 | timezone_name += "-" + std::to_string(abs(timezone_number)); 142 | } 143 | else if ( timezone_number < 0 ) { 144 | timezone_name += "+" + std::to_string(abs(timezone_number)); 145 | } 146 | setTimezone(timezone_name.c_str()); 147 | } 148 | else { 149 | setTimezoneIndex(GeoOps::getCityTimezoneIndex(m_cityId)); 150 | } 151 | return m_cityId; 152 | } 153 | 154 | void Observer::setCityId(size_t _cityId) { 155 | if ( _cityId != m_cityId ) { 156 | m_cityId = _cityId; 157 | m_location = GeoOps::getCityLocation(_cityId); 158 | setTimezoneIndex(GeoOps::getCityTimezoneIndex(_cityId)); 159 | m_bLocation = true; 160 | update(); 161 | } 162 | } 163 | 164 | void Observer::setTimezoneIndex(size_t _tz) { 165 | m_tzIndex = _tz; 166 | m_tzOffsetST = GeoOps::tzOffsetInDaysST(_tz); 167 | m_tzOffsetDST = GeoOps::tzOffsetInDaysDST(_tz); 168 | } 169 | 170 | double Observer::getJDLocal() const { 171 | if ( !haveLocation() ) 172 | return m_jd; 173 | 174 | int month, day, year; 175 | TimeOps::toDMY(m_jd, day, month, year); 176 | return m_jd + (GeoOps::tzIsDST(m_location.getLatitude(RADS), month, day)? m_tzOffsetDST : m_tzOffsetST); 177 | } 178 | 179 | void Observer::update() { 180 | m_jcentury = TimeOps::toJC(m_jd); 181 | m_obliquity = CoordOps::meanObliquity(m_jcentury); 182 | 183 | if ( haveLocation() ) { 184 | m_lst = TimeOps::toLocalSideralTime(m_jd, m_location.getLongitude(RADS), RADS); 185 | } 186 | 187 | m_changed = true; 188 | } 189 | 190 | Geodetic Observer::getLocation() const { 191 | if ( haveLocation() ) { 192 | return m_location; 193 | } 194 | else { 195 | return Geodetic(); 196 | } 197 | } 198 | 199 | double Observer::getLST() const { 200 | if ( haveLocation() ) { 201 | return m_lst; 202 | } 203 | else { 204 | return 0.0; 205 | } 206 | } 207 | 208 | std::string Observer::getTimezone() const { 209 | return std::string( GeoOps::tzIndexToName(m_tzIndex) ); 210 | } 211 | 212 | Vector3 Observer::getHeliocentricVector(DISTANCE_UNIT _type) { 213 | if (m_changed) { 214 | double pLng, pLat, pRad = 0.0; 215 | VSOP87::calcAllLocs(pLng, pLat, pRad, m_jcentury, EARTH); 216 | m_heliocentricLoc = Ecliptic(pLng, pLat, pRad, RADS, AU).getVector(_type); 217 | m_changed = false; 218 | } 219 | 220 | return m_heliocentricLoc; 221 | } 222 | -------------------------------------------------------------------------------- /src/ProjOps.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/ProjOps.h" 2 | #include "hypatia/CoordOps.h" 3 | #include "hypatia/GeoOps.h" 4 | 5 | #include 6 | 7 | void ProjOps::toXY( ProjId _id, double _alt, double _az, double _width, double _height, double &_x, double &_y ) { 8 | switch(_id) { 9 | case POLAR: ProjOps::toPolar(_alt, _az, _width, _height, _x, _y); 10 | break; 11 | case FISHEYE: ProjOps::toFisheye(_alt, _az, _width, _height, _x, _y); 12 | break; 13 | case ORTHO: ProjOps::toOrtho(_alt, _az, _width, _height, _x, _y); 14 | break; 15 | case STEREO: ProjOps::toStereo(_alt, _az, _width, _height, _x, _y); 16 | break; 17 | case LAMBERT: ProjOps::toLambert(_alt, _az, _width, _height, _x, _y); 18 | break; 19 | case EQUIRECTANGULAR: ProjOps::toEquirectangular(_alt, _az, _width, _height, _x, _y); 20 | break; 21 | } 22 | } 23 | 24 | Vector2 ProjOps::toVector2( ProjId _id, const Horizontal& _coord, double _width, double _height ) { 25 | Vector2 rta; 26 | ProjOps::toXY(_id, _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y); 27 | return rta; 28 | } 29 | 30 | // https://github.com/slowe/VirtualSky/blob/gh-pages/virtualsky.js 31 | void ProjOps::toPolar( double _alt, double _az, double _width, double _height, double &_x, double &_y ) { 32 | double radius = _height * .5; 33 | double r = radius * ( MathOps::PI_OVER_TWO - _alt ) / MathOps::PI_OVER_TWO; 34 | 35 | _x = (_width*.5 - r * sin(_az)); 36 | _y = (radius - r * cos(_az)) - .5; 37 | } 38 | 39 | Vector2 ProjOps::toPolar( const Horizontal& _coord, double _width, double _height ) { 40 | Vector2 rta; 41 | ProjOps::toPolar( _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y ); 42 | return rta; 43 | } 44 | 45 | void ProjOps::toFisheye(double _alt, double _az, double _width, double _height, double &_x, double &_y) { 46 | double radius = _height * .5; 47 | double r = radius * sin( (MathOps::PI_OVER_TWO - _alt)*.5 ) / 0.70710678; 48 | 49 | _x = (_width*.5 - r * sin(_az)) - .5; 50 | _y = (radius - r * cos(_az)) - .5; 51 | } 52 | 53 | Vector2 ProjOps::toFisheye(const Horizontal& _coord, double _width, double _height ) { 54 | Vector2 rta; 55 | ProjOps::toFisheye( _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y ); 56 | return rta; 57 | } 58 | 59 | void ProjOps::toOrtho( double _alt, double _az, double _width, double _height, double &_x, double &_y) { 60 | double radius = _height * .5; 61 | double r = radius * cos(_alt); 62 | 63 | _x = (_width*.5 - r * sin(_az)) - .5; 64 | _y = (radius - r * cos(_az)) - .5; 65 | } 66 | 67 | Vector2 ProjOps::toOrtho( const Horizontal& _coord, double _width, double _height ) { 68 | Vector2 rta; 69 | ProjOps::toOrtho( _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y); 70 | return rta; 71 | } 72 | 73 | void ProjOps::toStereo( double _alt, double _az, double _width ,double _height, double &_x, double &_y ) { 74 | double f = 0.42; 75 | double sinel1 = 0.0; 76 | double cosel1 = 1.0; 77 | double cosaz = cos(_az-MathOps::PI); 78 | double sinaz = sin(_az-MathOps::PI); 79 | double sinel = sin(_alt); 80 | double cosel = cos(_alt); 81 | double k = 2.0/(1.0 + sinel1 * sinel + cosel1 * cosel * cosaz); 82 | 83 | _x = _width * .5 + f * k * _height * cosel * sinaz; 84 | _y = _height - f * _height * k * (cosel1 * sinel - sinel1 * cosel * cosaz); 85 | } 86 | 87 | Vector2 ProjOps::toStereo( const Horizontal& _coord, double _width ,double _height ) { 88 | Vector2 rta; 89 | ProjOps::toStereo( _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y ); 90 | return rta; 91 | } 92 | 93 | void ProjOps::toLambert( double _alt, double _az, double _width ,double _height, double &_x, double &_y ) { 94 | double cosaz = cos(_az-MathOps::PI); 95 | double sinaz = sin(_az-MathOps::PI); 96 | double sinel = sin(_alt); 97 | double cosel = cos(_alt); 98 | double k = sqrt( 2/(1.0 + cosel * cosaz)); 99 | 100 | _x = _width * .5 + 0.6 * _height * k * cosel * sinaz; 101 | _y = _height - 0.6 * _height * k * sinel; 102 | } 103 | 104 | Vector2 ProjOps::toLambert( const Horizontal& _coord, double _width ,double _height ) { 105 | Vector2 rta; 106 | ProjOps::toLambert( _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y ); 107 | return rta; 108 | } 109 | 110 | void ProjOps::toEquirectangular( double _alt, double _az, double _width ,double _height, double &_x, double &_y ) { 111 | while (_az < 0) { 112 | _az += MathOps::TAU; 113 | } 114 | _az = fmod(_az, MathOps::TAU); 115 | 116 | _x = ( (_az-MathOps::PI) / MathOps::PI_OVER_TWO ) * _height + _width*.5; 117 | _y = _height - (_alt / MathOps::PI_OVER_TWO) * _height; 118 | } 119 | 120 | Vector2 ProjOps::toEquirectangular( const Horizontal& _coord, double _width ,double _height ) { 121 | Vector2 rta; 122 | ProjOps::toEquirectangular( _coord.getAltitud(RADS), _coord.getAzimuth(RADS), _width, _height, rta.x, rta.y ); 123 | return rta; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /src/Satellite.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Satellite.cpp 3 | // 4 | // Created by Patricio González Vivo on 6/2/18. 5 | // 6 | 7 | #include "hypatia/Satellite.h" 8 | #include "hypatia/CoordOps.h" 9 | 10 | Satellite::Satellite(): m_name("NAN") { 11 | m_bodyId = SATELLITE; 12 | } 13 | 14 | Satellite::Satellite(const TLE& _tle) { 15 | m_bodyId = SATELLITE; 16 | setTLE(_tle); 17 | } 18 | 19 | Satellite::~Satellite() { 20 | } 21 | 22 | void Satellite::setTLE(const TLE& _tle) { 23 | m_sgp4.setTLE(_tle); 24 | 25 | m_name = _tle.getName(); 26 | } 27 | 28 | char* Satellite::getName() const { 29 | return (char *)m_name.c_str(); 30 | } 31 | 32 | Geodetic Satellite::getGeodetic() const { 33 | return CoordOps::toGeodetic( m_eci ); 34 | } 35 | 36 | double Satellite::getPeriod(TIME_UNIT _unit) const { 37 | return TimeOps::minutesTo( getOrbit().getPeriod(), _unit ); 38 | } 39 | 40 | void Satellite::compute(Observer &_obs) { 41 | if (m_jcentury != _obs.getJC()) { 42 | m_jcentury = _obs.getJC(); 43 | 44 | m_eci = m_sgp4.getECI(_obs.getJD()); 45 | 46 | m_geocentric = CoordOps::toGeocentric(_obs, m_eci); 47 | m_heliocentric = CoordOps::toHeliocentric(_obs, m_geocentric); 48 | m_equatorial = Equatorial(m_eci.getPosition(AU)); 49 | 50 | if ( _obs.haveLocation() ) { 51 | m_ha = MathOps::normalize(CoordOps::toHourAngle( _obs, m_equatorial ), RADS); 52 | m_horizontal = CoordOps::toHorizontal( _obs, m_equatorial ); 53 | m_bHorizontal = true; 54 | } 55 | else { 56 | m_ha = 0.0; 57 | m_horizontal[0] = 0.0; 58 | m_horizontal[1] = 0.0; 59 | m_bHorizontal = false; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/coordinates/ECI.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // ECI.cpp 3 | // Solar 4 | // 5 | // Created by Patricio González Vivo on 5/31/18. 6 | // 7 | 8 | #include "hypatia/coordinates/ECI.h" 9 | 10 | #include "hypatia/TimeOps.h" 11 | #include "hypatia/CoordOps.h" 12 | 13 | #include 14 | 15 | ECI::ECI() { 16 | 17 | } 18 | /** 19 | * @param[in] jd the date to be used for this position 20 | * @param[in] position the position 21 | * @param[in] velocity the velocity 22 | */ 23 | ECI::ECI(double _jd, const Vector3 &_pos, const Vector3 &_vel, DISTANCE_UNIT _type) { 24 | m_jd = _jd; 25 | 26 | if (_type == KM) { 27 | m_position = _pos; 28 | m_velocity = _vel; 29 | } 30 | else if (_type == AU) { 31 | m_position = _pos * CoordOps::AU_TO_KM; 32 | m_velocity = _vel * CoordOps::AU_TO_KM; 33 | } 34 | else if (_type == LY) { 35 | m_position = _pos * CoordOps::LY_TO_AU * CoordOps::AU_TO_KM; 36 | m_velocity = _vel * CoordOps::LY_TO_AU * CoordOps::AU_TO_KM; 37 | } 38 | else if (_type == PC) { 39 | m_position = _pos * CoordOps::PC_TO_LY * CoordOps::LY_TO_AU * CoordOps::AU_TO_KM; 40 | m_velocity = _vel * CoordOps::PC_TO_LY * CoordOps::LY_TO_AU * CoordOps::AU_TO_KM; 41 | } 42 | } 43 | 44 | ECI::~ECI(){ 45 | } 46 | 47 | /** 48 | * @returns the position 49 | */ 50 | Vector3 ECI::getPosition(DISTANCE_UNIT _type) const { 51 | if (_type == KM) { 52 | return m_position; 53 | } 54 | else if (_type == AU) { 55 | return getPosition(KM) * CoordOps::KM_TO_AU; 56 | } 57 | else if (_type == LY) { 58 | return getPosition(AU) * CoordOps::AU_TO_LY; 59 | } 60 | else if (_type == PC) { 61 | return getPosition(LY) * CoordOps::LY_TO_PC; 62 | } 63 | else { 64 | return m_position; 65 | } 66 | } 67 | 68 | /** 69 | * @returns the velocity 70 | */ 71 | Vector3 ECI::getVelocity(DISTANCE_UNIT _type) const { 72 | if (_type == KM) { 73 | return m_velocity; 74 | } 75 | else if (_type == AU) { 76 | return getVelocity(KM) * CoordOps::KM_TO_AU; 77 | } 78 | else if (_type == LY) { 79 | return getVelocity(AU) * CoordOps::AU_TO_LY; 80 | } 81 | else if (_type == PC) { 82 | return getVelocity(LY) * CoordOps::LY_TO_PC; 83 | } 84 | else { 85 | return m_velocity; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/coordinates/Ecliptic.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/Ecliptic.h" 2 | 3 | #include "hypatia/CoordOps.h" 4 | #include 5 | 6 | Ecliptic::Ecliptic() : m_radius(1.0) { 7 | } 8 | 9 | Ecliptic::Ecliptic(const Vector3& _parent, DISTANCE_UNIT _type) { 10 | m_phi = atan2(_parent.y, _parent.x); 11 | m_theta = atan2(_parent.z, sqrt(_parent.x * _parent.x + _parent.y * _parent.y)); 12 | if ( _type == AU ) { 13 | m_radius = _parent.getMagnitud(); 14 | } 15 | else if ( _type == KM ) { 16 | m_radius = _parent.getMagnitud() * CoordOps::KM_TO_AU; 17 | } 18 | else if ( _type == LY ) { 19 | m_radius = _parent.getMagnitud() * CoordOps::LY_TO_AU; 20 | } 21 | else if ( _type == PC ) { 22 | m_radius = _parent.getMagnitud() * CoordOps::PC_TO_LY * CoordOps::LY_TO_AU; 23 | } 24 | } 25 | 26 | Ecliptic::Ecliptic(double _lng, double _lat, double _radius, ANGLE_UNIT _a_type, DISTANCE_UNIT _r_type) { 27 | if ( _a_type == RADS ) { 28 | m_phi = _lng; 29 | m_theta = _lat; 30 | } 31 | else { 32 | m_phi = MathOps::toRadians( _lng ); 33 | m_theta = MathOps::toRadians( _lat ); 34 | } 35 | 36 | if (_r_type == AU ) { 37 | m_radius = _radius; 38 | } 39 | else if ( _r_type == KM ) { 40 | m_radius = _radius * CoordOps::KM_TO_AU; 41 | } 42 | else if ( _r_type == LY ) { 43 | m_radius = _radius * CoordOps::LY_TO_AU; 44 | } 45 | else if ( _r_type == PC ) { 46 | m_radius = _radius * CoordOps::PC_TO_LY * CoordOps::LY_TO_AU; 47 | } 48 | } 49 | 50 | Ecliptic::~Ecliptic() { 51 | } 52 | 53 | double Ecliptic::getLongitude(ANGLE_UNIT _type) const { 54 | if ( _type == DEGS ) { 55 | return MathOps::toDegrees( m_phi ); 56 | } 57 | else { 58 | return m_phi; 59 | } 60 | } 61 | 62 | double Ecliptic::getLatitude(ANGLE_UNIT _type) const { 63 | if ( _type == DEGS ) { 64 | return MathOps::toDegrees( m_theta ); 65 | } 66 | else { 67 | return m_theta; 68 | } 69 | } 70 | 71 | Ecliptic& Ecliptic::operator= (const Vector3& _vec) { 72 | m_phi = atan2(_vec.y, _vec.x); 73 | m_theta = atan2(_vec.z, sqrt(_vec.x * _vec.x + _vec.y * _vec.y)); 74 | m_radius = _vec.getMagnitud(); 75 | return *this; 76 | } 77 | 78 | double Ecliptic::getRadius (DISTANCE_UNIT _type) const { 79 | if (_type == AU) { 80 | return m_radius; 81 | } 82 | else if ( _type == KM ) { 83 | return getRadius(AU) * CoordOps::AU_TO_KM; 84 | } 85 | else if ( _type == LY ) { 86 | return getRadius(AU) * CoordOps::AU_TO_LY; 87 | } 88 | else if ( _type == PC ) { 89 | return getRadius(LY) * CoordOps::LY_TO_PC; 90 | } 91 | else { 92 | return m_radius; 93 | } 94 | } 95 | 96 | Vector3 Ecliptic::getVector (DISTANCE_UNIT _type) const { 97 | return Vector3(*this) * getRadius(_type); 98 | } 99 | -------------------------------------------------------------------------------- /src/coordinates/Equatorial.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/Equatorial.h" 2 | 3 | #include 4 | 5 | Equatorial::Equatorial() { 6 | } 7 | 8 | Equatorial::Equatorial(const Vector3& _parent) { 9 | m_phi = atan2(_parent.y, _parent.x); 10 | m_theta = atan2(_parent.z, sqrt(_parent.x * _parent.x + _parent.y * _parent.y)); 11 | } 12 | 13 | Equatorial::Equatorial(const double _ra, const double _dec, ANGLE_UNIT _type) { 14 | if ( _type == RADS ) { 15 | m_phi = _ra; 16 | m_theta = _dec; 17 | } 18 | else { 19 | m_phi = MathOps::toRadians( _ra ); 20 | m_theta = MathOps::toRadians( _dec ); 21 | } 22 | } 23 | 24 | Equatorial::~Equatorial() { 25 | } 26 | 27 | double Equatorial::getRightAscension(ANGLE_UNIT _type) const { 28 | if ( _type == DEGS ) { 29 | return MathOps::toDegrees( m_phi ); 30 | } 31 | else { 32 | return m_phi; 33 | } 34 | } 35 | 36 | double Equatorial::getDeclination(ANGLE_UNIT _type) const { 37 | if ( _type == DEGS ) { 38 | return MathOps::toDegrees( m_theta ); 39 | } 40 | else { 41 | return m_theta; 42 | } 43 | } 44 | 45 | Vector3 Equatorial::getVector() const { 46 | return Vector3(*this); 47 | } 48 | 49 | double Equatorial::getAngularDistance(const Equatorial& _equ, ANGLE_UNIT _type) const { 50 | // Astronomical Formulae for Calculators by J. Meeus 51 | // Pag 109 52 | 53 | double ra1 = m_phi; 54 | double dec1 = m_theta; 55 | 56 | double ra2 = _equ.getRightAscension(RADS); 57 | double dec2 = _equ.getDeclination(RADS); 58 | 59 | double raD = ra1 - ra2; 60 | 61 | double ang_dist = acos( sin(dec1) * sin(dec2) + cos(dec1) * cos(dec2) * cos(raD) ); 62 | 63 | // if the angular distance is close to 0 o 180 deg by 10 sec use approximate formula 64 | if (ang_dist < 0.00290888) { 65 | double decD = dec1 - dec2; 66 | double a = raD * cos(dec1); 67 | 68 | ang_dist = sqrt(a * a + decD * decD); 69 | } 70 | 71 | if (_type == RADS) { 72 | return ang_dist; 73 | } 74 | else { 75 | return MathOps::toDegrees(ang_dist); 76 | } 77 | } -------------------------------------------------------------------------------- /src/coordinates/Galactic.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/Galactic.h" 2 | #include "hypatia/CoordOps.h" 3 | 4 | #include 5 | 6 | Galactic::Galactic() : m_radius(1.0) { 7 | } 8 | 9 | Galactic::Galactic(const Vector3& _parent, DISTANCE_UNIT _type) { 10 | m_phi = atan2(_parent.y, _parent.x); 11 | m_theta = atan2(_parent.z, sqrt(_parent.x * _parent.x + _parent.y * _parent.y)); 12 | 13 | if ( _type == PC ) { 14 | m_radius = _parent.getMagnitud(); 15 | } 16 | else if ( _type == LY ) { 17 | m_radius = _parent.getMagnitud() * CoordOps::LY_TO_PC; 18 | } 19 | else if ( _type == AU ) { 20 | m_radius = _parent.getMagnitud() * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 21 | } 22 | else if ( _type == KM ) { 23 | m_radius = _parent.getMagnitud() * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 24 | } 25 | } 26 | 27 | Galactic::Galactic(double _lng, double _lat, ANGLE_UNIT _a_type) { 28 | if ( _a_type == RADS ) { 29 | m_phi = _lng; 30 | m_theta = _lat; 31 | } 32 | else { 33 | m_phi = MathOps::toRadians( _lng ); 34 | m_theta = MathOps::toRadians( _lat ); 35 | } 36 | 37 | m_radius = 1.0; 38 | } 39 | 40 | Galactic::Galactic(double _lng, double _lat, double _paralax, ANGLE_UNIT _a_type) { 41 | if ( _a_type == RADS ) { 42 | m_phi = _lng; 43 | m_theta = _lat; 44 | } 45 | else { 46 | m_phi = MathOps::toRadians( _lng ); 47 | m_theta = MathOps::toRadians( _lat ); 48 | } 49 | 50 | m_radius = (1.0/_paralax); 51 | } 52 | 53 | Galactic::Galactic (double _lng, double _lat, double _radius, ANGLE_UNIT _a_type, DISTANCE_UNIT _d_type) { 54 | if ( _a_type == RADS ) { 55 | m_phi = _lng; 56 | m_theta = _lat; 57 | } 58 | else { 59 | m_phi = MathOps::toRadians( _lng ); 60 | m_theta = MathOps::toRadians( _lat ); 61 | } 62 | 63 | if ( _d_type == PC ) { 64 | m_radius = _radius; 65 | } 66 | else if ( _d_type == LY ) { 67 | m_radius = _radius * CoordOps::LY_TO_PC; 68 | } 69 | else if ( _d_type == AU ) { 70 | m_radius = _radius * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 71 | } 72 | else if ( _d_type == KM ) { 73 | m_radius = _radius * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 74 | } 75 | } 76 | 77 | Galactic::~Galactic() { 78 | } 79 | 80 | double Galactic::getLongitude(ANGLE_UNIT _type) const { 81 | if ( _type == DEGS ) { 82 | return MathOps::toDegrees( m_phi ); 83 | } 84 | else { 85 | return m_phi; 86 | } 87 | } 88 | 89 | double Galactic::getLatitude(ANGLE_UNIT _type) const { 90 | if ( _type == DEGS ) { 91 | return MathOps::toDegrees( m_theta ); 92 | } 93 | else { 94 | return m_theta; 95 | } 96 | } 97 | 98 | Galactic& Galactic::operator= (const Vector3& _vec) { 99 | m_phi = atan2(_vec.y, _vec.x); 100 | m_theta = atan2(_vec.z, sqrt(_vec.x * _vec.x + _vec.y * _vec.y)); 101 | m_radius = _vec.getMagnitud(); 102 | return *this; 103 | } 104 | 105 | Galactic& Galactic::operator= (const Polar& _pol) { 106 | m_phi = _pol[0]; 107 | m_theta = _pol[1]; 108 | return *this; 109 | } 110 | 111 | double Galactic::getRadius (DISTANCE_UNIT _type) const { 112 | if ( _type == PC) { 113 | return m_radius; 114 | } 115 | else if ( _type == LY ) { 116 | return getRadius(PC) * CoordOps::PC_TO_LY; 117 | } 118 | else if ( _type == AU ) { 119 | return getRadius(LY) * CoordOps::LY_TO_AU; 120 | } 121 | else if ( _type == KM ) { 122 | return getRadius(AU) * CoordOps::AU_TO_KM; 123 | } 124 | else { 125 | return m_radius; 126 | } 127 | } 128 | 129 | Vector3 Galactic::getVector (DISTANCE_UNIT _type) const { 130 | if ( _type == PC ) { 131 | return Vector3(*this) * m_radius; 132 | } 133 | else if ( _type == LY ) { 134 | return getVector(PC) * CoordOps::PC_TO_LY; 135 | } 136 | else if ( _type == AU ) { 137 | return getVector(LY) * CoordOps::LY_TO_AU; 138 | } 139 | else if ( _type == KM ) { 140 | return getVector(AU) * CoordOps::AU_TO_KM; 141 | } 142 | else { 143 | return Vector3(*this); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/coordinates/Geodetic.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/Geodetic.h" 2 | #include "hypatia/CoordOps.h" 3 | #include "hypatia/GeoOps.h" 4 | 5 | #include 6 | 7 | Geodetic::Geodetic () : m_alt(0.0) { 8 | } 9 | 10 | Geodetic::Geodetic ( double _lng, double _lat, double _alt, ANGLE_UNIT _angles_unit, DISTANCE_UNIT _alt_unit) { 11 | if ( _angles_unit == RADS ) { 12 | m_phi = _lng; 13 | m_theta = _lat; 14 | } 15 | else { 16 | m_phi = MathOps::toRadians( _lng ); 17 | m_theta = MathOps::toRadians( _lat ); 18 | } 19 | 20 | m_phi = std::max( std::min( m_phi, MathOps::toRadians( 180.0 ) ), MathOps::toRadians( -180.0 ) ); 21 | m_theta = std::max( std::min( m_theta, MathOps::toRadians( 90.0 ) ), MathOps::toRadians( -90.0 ) ); 22 | 23 | if ( _alt_unit == KM ) { 24 | m_alt = _alt; 25 | } 26 | else if ( _alt_unit == AU ) { 27 | m_alt = _alt * CoordOps::AU_TO_KM; 28 | } 29 | else if ( _alt_unit == LY ) { 30 | m_alt = _alt * CoordOps::AU_TO_KM * CoordOps::LY_TO_AU; 31 | } 32 | else if ( _alt_unit == PC ) { 33 | m_alt = _alt * CoordOps::AU_TO_KM * CoordOps::LY_TO_AU * CoordOps::LY_TO_PC; 34 | } 35 | else { 36 | m_alt = _alt; 37 | } 38 | } 39 | 40 | Geodetic::~Geodetic () { 41 | } 42 | 43 | void Geodetic::setLongitude( double _lng, ANGLE_UNIT _type ) { 44 | if ( _type == DEGS ) { 45 | m_phi = MathOps::toRadians( _lng ); 46 | } 47 | else { 48 | m_phi = _lng; 49 | } 50 | } 51 | 52 | void Geodetic::setLatitude( double _lat, ANGLE_UNIT _type ) { 53 | if ( _type == DEGS ) { 54 | m_theta = MathOps::toRadians( _lat ); 55 | } 56 | else { 57 | m_theta = _lat; 58 | } 59 | } 60 | 61 | void Geodetic::setAltitude( double _alt, DISTANCE_UNIT _type ) { 62 | if ( _type == KM ) { 63 | m_alt = _alt; 64 | } 65 | else if ( _type == AU ) { 66 | m_alt = _alt * CoordOps::AU_TO_KM; 67 | } 68 | else if ( _type == LY ) { 69 | m_alt = _alt * CoordOps::AU_TO_KM * CoordOps::LY_TO_AU; 70 | } 71 | else if ( _type == PC ) { 72 | m_alt = _alt * CoordOps::AU_TO_KM * CoordOps::LY_TO_AU * CoordOps::LY_TO_PC; 73 | } 74 | else { 75 | m_alt = _alt; 76 | } 77 | } 78 | 79 | double Geodetic::getLongitude ( ANGLE_UNIT _type ) const { 80 | if ( _type == DEGS ) { 81 | return MathOps::toDegrees( m_phi ); 82 | } 83 | else { 84 | return m_phi; 85 | } 86 | } 87 | 88 | double Geodetic::getLatitude ( ANGLE_UNIT _type ) const { 89 | if ( _type == DEGS ) { 90 | return MathOps::toDegrees( m_theta ); 91 | } 92 | else { 93 | return m_theta; 94 | } 95 | } 96 | 97 | double Geodetic::getRadius ( DISTANCE_UNIT _type ) const { 98 | double pct = abs(sin(m_theta)); 99 | double rad = GeoOps::EARTH_EQUATORIAL_RADIUS_KM * (1.-pct) + GeoOps::EARTH_POLAR_RADIUS_KM * pct; 100 | rad += m_alt * 0.001; // radious is in KM 101 | 102 | if ( _type == KM ) { 103 | return rad; 104 | } 105 | else if ( _type == AU ) { 106 | return rad * CoordOps::KM_TO_AU; 107 | } 108 | else if ( _type == LY ) { 109 | return rad * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY; 110 | } 111 | else if ( _type == PC ) { 112 | return rad * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 113 | } 114 | else { 115 | return rad; 116 | } 117 | } 118 | 119 | double Geodetic::getAltitude (DISTANCE_UNIT _type) const { 120 | if (_type == KM) { 121 | return m_alt; 122 | } 123 | else if ( _type == AU ) { 124 | return m_alt * CoordOps::KM_TO_AU; 125 | } 126 | else if ( _type == LY ) { 127 | return m_alt * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY; 128 | } 129 | else if ( _type == PC ) { 130 | return m_alt * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 131 | } 132 | else { 133 | return m_alt; 134 | } 135 | }; 136 | 137 | Vector3 Geodetic::getVector (DISTANCE_UNIT _type) const { 138 | if (_type == KM) { 139 | return Vector3(*this); 140 | } 141 | else if ( _type == AU ) { 142 | return Vector3(*this) * CoordOps::KM_TO_AU; 143 | } 144 | else if ( _type == LY ) { 145 | return Vector3(*this) * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY; 146 | } 147 | else if ( _type == PC ) { 148 | return Vector3(*this) * CoordOps::KM_TO_AU * CoordOps::AU_TO_LY * CoordOps::LY_TO_PC; 149 | } 150 | else { 151 | return Vector3(*this); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/coordinates/Horizontal.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/Horizontal.h" 2 | 3 | #include 4 | 5 | Horizontal::Horizontal () { 6 | } 7 | 8 | Horizontal::Horizontal ( const Vector3& _parent ) { 9 | m_phi = atan2(_parent.y, _parent.x); 10 | m_theta = atan2(_parent.z, sqrt(_parent.x * _parent.x + _parent.y * _parent.y)); 11 | } 12 | 13 | Horizontal::Horizontal ( const double _alt, const double _az, ANGLE_UNIT _type ) { 14 | if ( _type == RADS ) { 15 | m_phi = _alt; 16 | m_theta = _az; 17 | } 18 | else { 19 | m_phi = MathOps::toRadians( _alt ); 20 | m_theta = MathOps::toRadians( _az ); 21 | } 22 | } 23 | 24 | Horizontal::~Horizontal () { 25 | } 26 | 27 | double Horizontal::getAltitud(ANGLE_UNIT _type) const { 28 | if ( _type == DEGS ) { 29 | return MathOps::toDegrees( m_phi ); 30 | } 31 | else { 32 | return m_phi; 33 | } 34 | } 35 | 36 | double Horizontal::getAzimuth(ANGLE_UNIT _type) const { 37 | if ( _type == DEGS ) { 38 | return MathOps::toDegrees( m_theta ); 39 | } 40 | else { 41 | return m_theta; 42 | } 43 | } 44 | 45 | Vector3 Horizontal::getVector () const { 46 | return Vector3(Polar(m_phi, -m_theta, RADS)); 47 | } 48 | -------------------------------------------------------------------------------- /src/coordinates/PrecessionMatrix.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/PrecessionMatrix.h" 2 | #include "hypatia/MathOps.h" 3 | #include "hypatia/CoordOps.h" 4 | 5 | #include 6 | #include 7 | 8 | PrecessionMatrix::PrecessionMatrix() : Matrix3x3() { 9 | m_fromYear = 2000.0; 10 | m_toYear = 0.0; 11 | m_backward = true; 12 | } 13 | 14 | PrecessionMatrix::PrecessionMatrix(double _toYear, double _fromYear) : Matrix3x3() { 15 | m_fromYear = _fromYear; 16 | m_toYear = _toYear; 17 | m_backward = true; 18 | 19 | if ( _fromYear > _toYear ) { 20 | m_backward = true; 21 | } 22 | 23 | compute(); 24 | } 25 | 26 | PrecessionMatrix::~PrecessionMatrix() { 27 | 28 | } 29 | 30 | //---------------------------------------------------------------------------- precess 31 | 32 | void PrecessionMatrix::compute() { 33 | const double t1 = (m_fromYear - 2000.) / 100.; 34 | const double t2 = (m_toYear - 2000.) / 100.; 35 | const double obliquity1 = CoordOps::meanObliquity(t1); 36 | const double obliquity2 = CoordOps::meanObliquity(t2); 37 | 38 | Matrix3x3 m; 39 | 40 | if (m_fromYear == m_toYear) 41 | m = Matrix3x3(); // identity 42 | 43 | else if (m_fromYear == 2000.0) 44 | m = CoordOps::eclipticPrecessionFromJ2000(m_toYear); 45 | 46 | else { 47 | m = CoordOps::eclipticPrecessionFromJ2000(m_fromYear); 48 | m.transpose(); 49 | if( m_toYear != 2000.) 50 | m *= CoordOps::eclipticPrecessionFromJ2000(m_toYear); 51 | } 52 | 53 | m = Matrix3x3::rotationX(obliquity1) * m; 54 | m *= CoordOps::eclipticToEquatorial(obliquity2); 55 | 56 | double* matrix = m.getData(); 57 | setData(matrix); 58 | } 59 | 60 | Vector3 PrecessionMatrix::precess(const Vector3& _v) const { 61 | return Vector3( 62 | m_data[0][0] * _v.x + m_data[1][0] * _v.y + m_data[2][0] * _v.z, 63 | m_data[0][1] * _v.x + m_data[1][1] * _v.y + m_data[2][1] * _v.z, 64 | m_data[0][2] * _v.x + m_data[1][2] * _v.y + m_data[2][2] * _v.z 65 | ); 66 | } 67 | 68 | Vector3 PrecessionMatrix::deprecess(const Vector3& _v) const { 69 | return Vector3( 70 | m_data[0][0] * _v.x + m_data[0][1] * _v.y + m_data[0][2] * _v.z, 71 | m_data[1][0] * _v.x + m_data[1][1] * _v.y + m_data[1][2] * _v.z, 72 | m_data[2][0] * _v.x + m_data[2][1] * _v.y + m_data[2][2] * _v.z 73 | ); 74 | } -------------------------------------------------------------------------------- /src/coordinates/Tile.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/coordinates/Tile.h" 2 | #include "hypatia/GeoOps.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | Tile::Tile(): meters(0.0), x(0.0), y(0.0), z(0) { 9 | } 10 | 11 | // https://docs.microsoft.com/en-us/azure/azure-maps/zoom-levels-and-tile-grid?tabs=csharp 12 | Tile::Tile(const std::string& _quadKey): meters(0.0), x(0.0), y(0.0), z(0){ 13 | z = _quadKey.size(); 14 | int tileX, tileY; 15 | for (int i = z; i > 0; i--) { 16 | int mask = 1 << (i - 1); 17 | switch (_quadKey[z - i]) { 18 | case '0': 19 | break; 20 | 21 | case '1': 22 | tileX |= mask; 23 | break; 24 | 25 | case '2': 26 | tileY |= mask; 27 | break; 28 | 29 | case '3': 30 | tileX |= mask; 31 | tileY |= mask; 32 | break; 33 | } 34 | } 35 | 36 | x = tileX; 37 | y = tileY; 38 | } 39 | 40 | Tile::Tile(double _x, double _y, int _z): x(_x), y(_y), z(_z) { 41 | meters = GeoOps::getMetersPerTileAt(_z); 42 | } 43 | 44 | Tile::~Tile() { 45 | } 46 | 47 | int Tile::getColumn() const { 48 | return floor(x); 49 | } 50 | 51 | int Tile::getRow() const { 52 | return floor(y); 53 | } 54 | 55 | int Tile::getZoom() const { 56 | return z; 57 | } 58 | 59 | Vector2 Tile::getUV() const { 60 | return Vector2(MathOps::fract(x), MathOps::fract(y)); 61 | } 62 | 63 | Vector2 Tile::getMercator() const { 64 | double metersPerTile = getMetersPerTile(); 65 | return Vector2( x * metersPerTile - GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M, 66 | GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M - y * metersPerTile ); 67 | } 68 | 69 | Vector2 Tile::getMercatorForSouthWestCorner() const { 70 | double metersPerTile = getMetersPerTile(); 71 | return Vector2( floor(x) * metersPerTile - GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M, 72 | GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M - floor(y) * metersPerTile ); 73 | } 74 | 75 | Vector2 Tile::getMercatorForNorthWestCorner() const { 76 | double metersPerTile = getMetersPerTile(); 77 | return Vector2( floor(x) * metersPerTile - GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M, 78 | GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M - floor(y+1.0) * metersPerTile ); 79 | } 80 | 81 | Vector2 Tile::getMercatorForUV(const Vector2& _uv) const { 82 | double metersPerTile = getMetersPerTile(); 83 | return Vector2( (getColumn() + _uv.x) * metersPerTile - GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M, 84 | GeoOps::EARTH_EQUATORIAL_HALF_CIRCUMFERENCE_M - (getRow() + _uv.y) * metersPerTile ); 85 | } 86 | 87 | // BoundingBox Tile::getMercatorBoundingBox() const { 88 | // Tile minT = Tile(getColumn(), getRow() + 1.0, z); 89 | // Tile maxT = Tile(getColumn() + 1.0, getRow(), z); 90 | 91 | // BoundingBox bb; 92 | // bb.min = minT.getMercator(); 93 | // bb.max = maxT.getMercator(); 94 | // return bb; 95 | // } 96 | 97 | std::string Tile::getProviderURL( TileProvider _prov ) const { 98 | std::string X = std::to_string(getColumn()); 99 | std::string Y = std::to_string(getRow()); 100 | std::string Z = std::to_string(getZoom()); 101 | 102 | std::string letter[] = { "a", "b", "c", "d" }; 103 | int rnd = rand() % 4; 104 | 105 | switch (_prov) { 106 | case NEXTZEN_JSON: 107 | return "https://tile.nextzen.org/tilezen/vector/v1/all/"+Z+"/"+X+"/"+Y+".json?api_key="; 108 | case NEXTZEN_MVT: 109 | return "https://tile.nextzen.org/tilezen/vector/v1/all/"+Z+"/"+X+"/"+Y+".mvt?api_key="; 110 | break; 111 | case NEXTZEN_TERRARIUM: 112 | return "https://tile.nextzen.org/tilezen/terrain/v1/512/terrarium/"+Z+"/"+X+"/"+Y+".png?api_key="; 113 | break; 114 | case NEXTZEN_NORMAL: 115 | return "https://tile.nextzen.org/tilezen/terrain/v1/512/terrarium/"+Z+"/"+X+"/"+Y+".png?api_key="; 116 | break; 117 | case NEXTZEN_GEOTIFF: 118 | return "https://tile.nextzen.org/tilezen/terrain/v1/geotiff/"+Z+"/"+X+"/"+Y+".tif?api_key="; 119 | break; 120 | 121 | case OSM: 122 | return "https://"+letter[rnd%3]+".tile.openstreetmap.org/"+Z+"/"+X+"/"+Y+".png"; 123 | break; 124 | 125 | case BING: 126 | return "http://ecn.t"+std::to_string( rnd )+".tiles.virtualearth.net/tiles/a"+ getQuadKey() +".jpeg?g=543"; 127 | break; 128 | 129 | case MICROSOFT_BASE: 130 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=microsoft.base&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 131 | break; 132 | 133 | case MICROSOFT_SATELLITE: 134 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=satellite&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 135 | break; 136 | 137 | case MICROSOFT_SATELLITE_ROAD_LABELS: 138 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=satellite_road_labels&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 139 | break; 140 | 141 | case MICROSOFT_GRAYSCALE_DARK: 142 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=grayscale_dark&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 143 | break; 144 | 145 | case MICROSOFT_GRAYSCALE_LIGHT: 146 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=grayscale_light&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 147 | break; 148 | 149 | case MICROSOFT_NIGHT: 150 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=night&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 151 | break; 152 | 153 | case MICROSOFT_ROAD_SHADED_RELIEVEF: 154 | return "https://atlas.microsoft.com/map/tile?api-version=2.0&tilesetId=road_shaded_relief&zoom="+Z+"&x="+X+"&y="+Y+"?subscription-key="; 155 | break; 156 | 157 | case STAMEN_TONER: 158 | return "http://"+letter[rnd]+".tile.stamen.com/toner/"+Z+"/"+X+"/"+Y+".png"; 159 | break; 160 | case STAMEN_TONER_HYBRID: 161 | return "http://"+letter[rnd]+".tile.stamen.com/toner-hybrid/"+Z+"/"+X+"/"+Y+".png"; 162 | break; 163 | case STAMEN_TONER_LABELS: 164 | return "http://"+letter[rnd]+".tile.stamen.com/toner-labels/"+Z+"/"+X+"/"+Y+".png"; 165 | break; 166 | case STAMEN_TONER_LINES: 167 | return "http://"+letter[rnd]+".tile.stamen.com/toner-lines/"+Z+"/"+X+"/"+Y+".png"; 168 | break; 169 | case STAMEN_TONER_BACKGROUND: 170 | return "http://"+letter[rnd]+".tile.stamen.com/toner-background/"+Z+"/"+X+"/"+Y+".png"; 171 | break; 172 | 173 | case STAMEN_TERRAIN: 174 | return "http://"+letter[rnd]+".tile.stamen.com/terrain/"+Z+"/"+X+"/"+Y+".png"; 175 | break; 176 | case STAMEN_TERRAIN_LABELS: 177 | return "http://"+letter[rnd]+".tile.stamen.com/terrain-labels/"+Z+"/"+X+"/"+Y+".png"; 178 | break; 179 | case STAMEN_TERRAIN_LINES: 180 | return "http://"+letter[rnd]+".tile.stamen.com/terrain-lines/"+Z+"/"+X+"/"+Y+".png"; 181 | break; 182 | case STAMEN_TERRAIN_BACKGROUND: 183 | return "http://"+letter[rnd]+".tile.stamen.com/terrain-background/"+Z+"/"+X+"/"+Y+".png"; 184 | break; 185 | 186 | default: 187 | return Z+"/"+X+"/"+Y; 188 | } 189 | 190 | } 191 | 192 | double Tile::getMetersPerTile() const { return meters; } 193 | 194 | Tile Tile::getTileAtZoom(const int& _zoom) const { 195 | return zoom(_zoom - z); 196 | } 197 | 198 | Tile Tile::getParent() const { 199 | double xF = MathOps::fract(x); 200 | double yF = MathOps::fract(y); 201 | return Tile( (int(x) >> 1) + xF, (int(y) >> 1) + yF, z - 1); 202 | } 203 | 204 | Tile Tile::getChild(int _index, int _maxZoom) const { 205 | if (_index > 3 || _index < 0) { 206 | return Tile(-1, -1, -1); 207 | } 208 | 209 | int i = _index / 2; 210 | int j = _index % 2; 211 | 212 | // _index: 0, 1, 2, 3 213 | // i: 0, 0, 1, 1 214 | // j: 0, 1, 0, 1 215 | // 216 | // 0 | 2 217 | // ---|--- 218 | // 1 | 3 219 | 220 | double xF = MathOps::fract(x); 221 | double yF = MathOps::fract(y); 222 | 223 | Tile childID = Tile(double((int(x)<<1)+i) + xF, ((int(y)<<1)+j) + yF, z + 1); 224 | return childID.withMaxSourceZoom(_maxZoom); 225 | } 226 | 227 | Tile Tile::withMaxSourceZoom(int _maxZoom) const { 228 | if (z <= _maxZoom) { 229 | return *this; 230 | } 231 | int over = z - _maxZoom; 232 | 233 | double xF = MathOps::fract(x); 234 | double yF = MathOps::fract(y); 235 | 236 | return Tile( double((int(x) >> over)) + xF , double((int(y) >> over)) + yF, _maxZoom); 237 | } 238 | 239 | Tile Tile::zoom(const int& _distance) const { 240 | double adjust = pow(2.0, _distance); 241 | return Tile(x * adjust, y * adjust, z + _distance); 242 | } 243 | 244 | Tile Tile::up(const double& _distance) const { 245 | return Tile(x, y - _distance, z); 246 | } 247 | 248 | Tile Tile::right(const double& _distance) const { 249 | return Tile(x + _distance, y, z); 250 | } 251 | 252 | Tile Tile::down(const double& _distance) const { 253 | return Tile(x, y + _distance, z); 254 | } 255 | 256 | Tile Tile::left(const double& _distance) const { 257 | return Tile(x - _distance, y, z); 258 | } 259 | 260 | bool Tile::operator < (const Tile& _tile) const { 261 | return z > _tile.z || (z == _tile.z && (x < _tile.x || (x == _tile.x && (y < _tile.y)))); 262 | } 263 | 264 | bool Tile::operator > (const Tile& _tile) const { return _tile < const_cast(*this); } 265 | bool Tile::operator <= (const Tile& _tile) const { return !(*this > _tile); } 266 | bool Tile::operator >= (const Tile& _tile) const { return !(*this < _tile); } 267 | bool Tile::operator == (const Tile& _tile) const { return x == _tile.x && y == _tile.y && z == _tile.z;} 268 | bool Tile::operator != (const Tile& _tile) const { return !(*this == _tile); } 269 | 270 | bool Tile::isValid() const { 271 | int max = 1 << z; 272 | return x >= 0 && x < max && y >= 0 && y < max && z >= 0; 273 | } 274 | 275 | bool Tile::isValid(int _maxZoom) const { 276 | return isValid() && z <= _maxZoom; 277 | } 278 | 279 | std::string Tile::getQuadKey() const { 280 | return getQuadKey(getColumn(), getRow(), getZoom()); 281 | } 282 | 283 | std::string Tile::getQuadKey(int _column, int _row, int _zoom) { 284 | std::stringstream key; 285 | for (int i = 1; i <= _zoom; i++) { 286 | int digit = (((_row >> (_zoom - i)) & 1) << 1) | ((_column >> (_zoom - i)) & 1); 287 | key << digit; 288 | } 289 | return key.str(); 290 | } -------------------------------------------------------------------------------- /src/models/Orbit.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Orbit.cpp 3 | // 4 | // Created by Patricio González Vivo on 5/31/18. 5 | // 6 | 7 | #include "hypatia/MathOps.h" 8 | #include "hypatia/TimeOps.h" 9 | #include "hypatia/GeoOps.h" 10 | 11 | #include 12 | 13 | #include "hypatia/models/Orbit.h" 14 | 15 | const double kAE = 1.0; 16 | const double kXJ2 = 1.082616e-3; 17 | 18 | /* 19 | * alternative XKE 20 | * affects final results 21 | * aiaa-2006-6573 22 | * const double kXKE = 60.0 / sqrt(kXKMPER * kXKMPER * kXKMPER / kMU); 23 | * dundee 24 | * const double kXKE = 7.43669161331734132e-2; 25 | */ 26 | const double kXKE = 60.0 / sqrt(GeoOps::EARTH_EQUATORIAL_RADIUS_KM * GeoOps::EARTH_EQUATORIAL_RADIUS_KM * GeoOps::EARTH_EQUATORIAL_RADIUS_KM / GeoOps::EARTH_GRAVITATIONAL_CONSTANT); 27 | const double kCK2 = 0.5 * kXJ2 * kAE * kAE; 28 | 29 | Orbit::Orbit() { 30 | 31 | } 32 | 33 | Orbit::Orbit(const TLE& tle) { 34 | /* 35 | * extract and format tle data 36 | */ 37 | m_meanAnomoly = tle.getMeanAnomaly(RADS); 38 | m_ascendingNode = tle.getRightAscendingNode(RADS); 39 | m_argumentPeriapsis = tle.getArgumentPerigee(RADS); 40 | m_eccentricity = tle.getEccentricity(); 41 | m_inclination = tle.getInclination(RADS); 42 | m_meanMotion = tle.getMeanMotion() * MathOps::TAU / TimeOps::MINUTES_PER_DAY; 43 | m_bstar = tle.getBStar(); 44 | m_epoch = tle.getEpoch(); 45 | 46 | /* 47 | * recover original mean motion (xnodp) and semimajor axis (aodp) 48 | * from input elements 49 | */ 50 | const double a1 = pow(kXKE / getMeanMotion(), MathOps::TWO_THIRD); 51 | const double cosio = cos(getInclination(RADS)); 52 | const double theta2 = cosio * cosio; 53 | const double x3thm1 = 3.0 * theta2 - 1.0; 54 | const double eosq = getEccentricity() * getEccentricity(); 55 | const double betao2 = 1.0 - eosq; 56 | const double betao = sqrt(betao2); 57 | const double temp = (1.5 * kCK2) * x3thm1 / (betao * betao2); 58 | const double del1 = temp / (a1 * a1); 59 | const double a0 = a1 * (1.0 - del1 * (1.0 / 3.0 + del1 * (1.0 + del1 * 134.0 / 81.0))); 60 | const double del0 = temp / (a0 * a0); 61 | 62 | m_recoveredMeanMotion = getMeanMotion() / (1.0 + del0); 63 | /* 64 | * alternative way to calculate 65 | * doesnt affect final results 66 | * m_semimajorAxis = pow(XKE / RecoveredMeanMotion(), TWOTHIRD); 67 | */ 68 | m_semiMajorAxis = a0 / (1.0 - del0); 69 | 70 | /* 71 | * find perigee and period 72 | */ 73 | m_periapsis = (getSemiMajorAxis() * (1.0 - getEccentricity()) - kAE) * GeoOps::EARTH_EQUATORIAL_RADIUS_KM; 74 | m_period = MathOps::TAU / getMeanMotion(); 75 | } 76 | 77 | double Orbit::getInclination(ANGLE_UNIT _type) const { 78 | if (_type == DEGS) { 79 | return MathOps::toDegrees(m_inclination); 80 | } 81 | else { 82 | return m_inclination; 83 | } 84 | } 85 | 86 | double Orbit::getAscendingNode(ANGLE_UNIT _type) const { 87 | if (_type == DEGS) { 88 | return MathOps::toDegrees(m_ascendingNode); 89 | } 90 | else { 91 | return m_ascendingNode; 92 | } 93 | } 94 | 95 | double Orbit::getArgumentPeriapsis(ANGLE_UNIT _type) const { 96 | if (_type == DEGS) { 97 | return MathOps::toDegrees(m_argumentPeriapsis); 98 | } 99 | else { 100 | return m_argumentPeriapsis; 101 | } 102 | } 103 | 104 | double Orbit::getMeanAnomaly(ANGLE_UNIT _type) const { 105 | if (_type == DEGS) { 106 | return MathOps::toDegrees(m_meanAnomoly); 107 | } 108 | else { 109 | return m_meanAnomoly; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/models/Pluto.cpp: -------------------------------------------------------------------------------- 1 | /*****************************************************************************\ 2 | * Pluto.cpp 3 | * 4 | * Pluto is a class that can calculate the orbit of Pluto. 5 | * 6 | * author: mark huss (mark@mhuss.com) 7 | * Based on Bill Gray's open-source code at projectpluto.com 8 | * 9 | \*****************************************************************************/ 10 | 11 | #include "hypatia/MathOps.h" 12 | #include "hypatia/CoordOps.h" 13 | #include "hypatia/models/Pluto.h" 14 | 15 | #include 16 | 17 | // long coefficients 18 | long plutoLongCoeff[7][6] = { 19 | { 68955876, 66867334, -14974876, -5453098, 19848454, -19798886 }, 20 | { -333765, -11826086, 1672673, 3527363, -4955707, 897499 }, 21 | { -1439953, 1593657, 327763, -1050939, 1210521, 610820 }, 22 | { 482443, -18948, -291925, 178691, -189719, -341639 }, 23 | { -85576, -66634, 100448, 18763, -34863, 129027 }, 24 | { -5765, 30841, -25838, -30594, 31061, -38215 }, 25 | { 45637, 105, 201, 157, 747, 7049 } 26 | }; 27 | 28 | // pluto coefficients 29 | PlutoCoeffs plutoCoeff[N_COEFFS] = { 30 | { 0, 1, -1, 0, 20349, -9886, 4965, 11263, -6140, 22254 }, 31 | { 0, 1, 0, 0, -4045, -4904, 310, -132, 4434, 4443 }, 32 | { 0, 1, 1, 0, -5885, -3238, 2036, -947, -1518, 641 }, 33 | { 0, 1, 2, 0, -3812, 3011, -2, -674, -5, 792 }, 34 | { 0, 1, 3, 0, -601, 3468, -329, -563, 518, 518 }, 35 | { 0, 2, -2, 0, 1237, 463, -64, 39, -13, -221 }, 36 | { 0, 2, -1, 0, 1086, -911, -94, 210, 837, -494 }, 37 | { 0, 2, 0, 0, 595, -1229, -8, -160, -281, 616 }, 38 | { 1, -1, 0, 0, 2484, -485, -177, 259, 260, -395 }, 39 | { 1, -1, 1, 0, 839, -1414, 17, 234, -191, -396 }, 40 | { 1, 0, -3, 0, -964, 1059, 582, -285, -3218, 370 }, 41 | { 1, 0, -2, 0, -2303, -1038, -298, 692, 8019, -7869 }, 42 | { 1, 0, 0, 0, 1179, -358, 304, 825, 8623, 8444 }, 43 | { 1, 0, 1, 0, 393, -63, -124, -29, -896, -801 }, 44 | { 1, 0, 2, 0, 111, -268, 15, 8, 208, -122 }, 45 | { 1, 0, 3, 0, -52, -154, 7, 15, -133, 65 }, 46 | { 1, 0, 4, 0, -78, -30, 2, 2, -16, 1 }, 47 | { 1, 1, -3, 0, -34, -26, 4, 2, -22, 7 }, 48 | { 1, 1, -2, 0, -43, 1, 3, 0, -8, 16 }, 49 | { 1, 1, -1, 0, -15, 21, 1, -1, 2, 9 }, 50 | { 1, 1, 0, 0, -1, 15, 0, -2, 12, 5 }, 51 | { 1, 1, 1, 0, 4, 7, 1, 0, 1, -3 }, 52 | { 1, 1, 3, 0, 1, 5, 1, -1, 1, 0 }, 53 | { 2, 0, -6, 0, 8, 3, -2, -3, 9, 5 }, 54 | { 2, 0, -5, 0, -3, 6, 1, 2, 2, -1 }, 55 | { 2, 0, -4, 0, 6, -13, -8, 2, 14, 10 }, 56 | { 2, 0, -3, 0, 10, 22, 10, -7, -65, 12 }, 57 | { 2, 0, -2, 0, -57, -32, 0, 21, 126, -233 }, 58 | { 2, 0, -1, 0, 157, -46, 8, 5, 270, 1068 }, 59 | { 2, 0, 0, 0, 12, -18, 13, 16, 254, 155 }, 60 | { 2, 0, 1, 0, -4, 8, -2, -3, -26, -2 }, 61 | { 2, 0, 2, 0, -5, 0, 0, 0, 7, 0 }, 62 | { 2, 0, 3, 0, 3, 4, 0, 1, -11, 4 }, 63 | { 3, 0, -2, 0, -1, -1, 0, 1, 4, -14 }, 64 | { 3, 0, -1, 0, 6, -3, 0, 0, 18, 35 }, 65 | { 3, 0, 0, 0, -1, -2, 0, 1, 13, 3 } 66 | }; 67 | 68 | /** 69 | * reduceElements() - 70 | * 71 | * @param - mj0, initial epoch 72 | * @param - mj, desired epoch 73 | * @param - inc0, initial inclination, rads 74 | * @param - ap0, initial argument of perihelion, as an mj 75 | * @param - om0, initial long of ascending node, rads 76 | * @param - inc, resultant inclination, rads 77 | * @param - ap, resultant arg of perihelion, as an mj 78 | * @param - om, resultant long of ascending node, rads 79 | * 80 | */ 81 | void reduceElements ( double mj0, double mj, double inc0, double ap0, double om0, double *inc, double *ap, double *om) { 82 | double t0, t1; 83 | double tt, tt2, t02, tt3; 84 | double eta, th, th0; 85 | double a, b; 86 | double dap; 87 | double cinc, sinc; 88 | double ot, sot, cot, ot1; 89 | double seta, ceta; 90 | 91 | if (fabs(mj - mj0) < 1e-5) { 92 | /* sin(eta) blows for inc < 10 degrees -- anyway, no need */ 93 | *inc = inc0; 94 | *ap = ap0; 95 | *om = om0; 96 | return; 97 | } 98 | 99 | t0 = mj0/365250.0; 100 | t1 = mj/365250.0; 101 | 102 | tt = t1-t0; 103 | tt2 = tt*tt; 104 | t02 = t0*t0; 105 | tt3 = tt*tt2; 106 | eta = (471.07-6.75*t0+.57*t02)*tt+(.57*t0-3.37)*tt2+.05*tt3; 107 | th0 = 32869.0*t0+56*t02-(8694+55*t0)*tt+3*tt2; 108 | eta = MathOps::toRadians(eta/3600.0); 109 | th0 = MathOps::toRadians((th0/3600.0)+173.950833); 110 | th = (50256.41+222.29*t0+.26*t02)*tt+(111.15+.26*t0)*tt2+.1*tt3; 111 | th = th0+MathOps::toRadians(th/3600.0); 112 | cinc = cos(inc0); 113 | sinc = sin(inc0); 114 | ot = om0-th0; 115 | sot = sin(ot); 116 | cot = cos(ot); 117 | seta = sin(eta); 118 | ceta = cos(eta); 119 | a = sinc*sot; 120 | b = ceta*sinc*cot-seta*cinc; 121 | ot1 = atan(a/b); 122 | if (b<0) { 123 | ot1 += MathOps::PI; 124 | } 125 | 126 | b = sinc*ceta-cinc*seta*cot; 127 | a = -1*seta*sot; 128 | dap = atan(a/b); 129 | 130 | if (b<0) { 131 | dap += MathOps::PI; 132 | } 133 | 134 | *ap = MathOps::mod(ap0 + dap, MathOps::TAU); 135 | *om = MathOps::mod(ot1 + th, MathOps::TAU); 136 | 137 | if (inc0<.175) 138 | *inc = asin(a/sin(dap)); 139 | else 140 | *inc = 1.570796327-asin((cinc*ceta)+(sinc*seta*cot)); 141 | } 142 | 143 | #define MJD0 2415020.0 144 | 145 | // t is in julian centuries from J2000.0 146 | void Pluto::calcAllLocs (double& _lon, double& _lat, double& _rad, const double _jc) { 147 | #ifdef XEPHEM 148 | 149 | double mj = (_jc * TimeOps::DAYS_PER_CENTURY) + TimeOps::J2000; 150 | /* mean orbital elements of Pluto. 151 | * The origin of these is somewhat obscure. 152 | */ 153 | double a = 39.543; /* semimajor axis, au */ 154 | double e = 0.2490; /* excentricity */ 155 | double inc0 = MathOps::toRadians(17.140); /* inclination, deg */ 156 | double Om0 = MathOps::toRadians(110.307); /* long asc node, deg */ 157 | double omeg0 = MathOps::toRadians(113.768); /* arg of perihel, deg */ 158 | double mjp = 2448045.539 - MJD0; /* epoch of perihel */ 159 | double mjeq = TimeOps::J2000; /* equinox of elements */ 160 | double n = 144.9600/ TimeOps::DAYS_PER_CENTURY; /* daily motion, deg */ 161 | 162 | double inc, Om, omeg; /* orbital elements at epoch of date */ 163 | double ma, ea, nu; /* mean, excentric and true anomaly */ 164 | double lo, slo, clo; /* longitude in orbit from asc node */ 165 | 166 | reduceElements(mjeq, mj, inc0, omeg0, Om0, &inc, &omeg, &Om); 167 | 168 | ma = MathOps::toRadians((mj - mjp) * n); 169 | CoordOps::anomaly(ma, e, &nu, &ea); 170 | 171 | _rad = a * (1.0 - e*cos(ea)); /* r */ 172 | lo = omeg + nu; 173 | slo = sin(lo); 174 | clo = cos(lo); 175 | _lat = asin(slo * sin(inc)); /* b - lat */ 176 | _lon = atan2(slo * cos(inc), clo) + Om; /* l - lng */ 177 | 178 | #else 179 | // jupiter's mean longitude 180 | double mlJup = MathOps::toRadians(34.35 + 3034.9057 * _jc); 181 | 182 | // saturn's mean longitude 183 | double mlSat = MathOps::toRadians(50.08 + 1222.1138 * _jc); 184 | 185 | // pluto's mean longitude 186 | double mlPl = MathOps::toRadians(238.96 + 144.9600 * _jc); 187 | 188 | // use local vars for retvals, hoping to encourage FP reg optimizations 189 | double lon = 238.956785 + 144.96 * _jc; 190 | double lat = -3.908202; 191 | double rad = 407.247248; // temporarily in tenths of AUs; fixed at the end 192 | 193 | double arg, cosArg, sinArg; 194 | long* plc; 195 | for (int i = 0; i < 7; i++) { 196 | if ( i == 6 ) { 197 | arg = mlJup - mlPl; 198 | } 199 | else { 200 | arg = (double)(i + 1) * mlPl; 201 | } 202 | 203 | cosArg = cos(arg) * 1.e-6; 204 | sinArg = sin(arg) * 1.e-6; 205 | plc = plutoLongCoeff[i]; 206 | 207 | lon += (double)(plc[0]) * sinArg + (double)(plc[1]) * cosArg; 208 | lat += (double)(plc[2]) * sinArg + (double)(plc[3]) * cosArg; 209 | rad += (double)(plc[4]) * sinArg + (double)(plc[5]) * cosArg; 210 | } 211 | 212 | 213 | PlutoCoeffs* pc = plutoCoeff; 214 | for (int i=0; ilon_a || pc->lon_b || 216 | pc->lat_a || pc->lat_b || 217 | pc->rad_a || pc->rad_b) { 218 | 219 | if ( 0 == pc->j ) { 220 | arg = 0.; 221 | } 222 | else { 223 | arg = ((1 == pc->j) ? mlJup : mlJup * (double)pc->j); 224 | } 225 | 226 | if ( pc->s < 0 ) { 227 | arg -= (-1 == pc->s) ? mlSat : mlSat + mlSat; 228 | } 229 | 230 | if ( pc->s > 0 ) { 231 | arg += (1 == pc->s) ? mlSat : mlSat + mlSat; 232 | } 233 | 234 | if ( pc->p ) { 235 | arg += mlPl * (double)pc->p; 236 | } 237 | 238 | cosArg = cos(arg) * 1.e-6; 239 | sinArg = sin(arg) * 1.e-6; 240 | lon += sinArg * (double)(pc->lon_a) + cosArg * (double)(pc->lon_b); 241 | lat += sinArg * (double)(pc->lat_a) + cosArg * (double)(pc->lat_b); 242 | rad += sinArg * (double)(pc->rad_a) + cosArg * (double)(pc->rad_b); 243 | } 244 | pc++; 245 | } 246 | _lon = MathOps::toRadians(lon); 247 | _lat = MathOps::toRadians(lat); 248 | _rad = rad / 10.; // convert back to AUs 249 | #endif 250 | } 251 | -------------------------------------------------------------------------------- /src/primitives/DateTime.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/primitives/DateTime.h" 2 | 3 | #include "hypatia/TimeOps.h" 4 | 5 | #if defined(_WIN32) || defined(_WIN64) 6 | 7 | //#define NOMINMAX 8 | #include 9 | 10 | #define BILLION (1E9) 11 | #define CLOCK_REALTIME 0 12 | 13 | static BOOL g_first_time = 1; 14 | static LARGE_INTEGER g_counts_per_sec; 15 | 16 | int clock_gettime(int dummy, struct timespec *ct) { 17 | LARGE_INTEGER count; 18 | 19 | if (g_first_time) { 20 | g_first_time = 0; 21 | if (0 == QueryPerformanceFrequency(&g_counts_per_sec)) { 22 | g_counts_per_sec.QuadPart = 0; 23 | } 24 | } 25 | 26 | if ((NULL == ct) || (g_counts_per_sec.QuadPart <= 0) || 27 | (0 == QueryPerformanceCounter(&count))) { 28 | return -1; 29 | } 30 | 31 | ct->tv_sec = count.QuadPart / g_counts_per_sec.QuadPart; 32 | ct->tv_nsec = ((count.QuadPart % g_counts_per_sec.QuadPart) * BILLION) / g_counts_per_sec.QuadPart; 33 | 34 | return 0; 35 | } 36 | #define MIN min 37 | #else 38 | #define MIN std::min 39 | #endif 40 | 41 | static int daysInMonth[2][13] = { 42 | // 1 2 3 4 5 6 7 8 9 10 11 12 43 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, 44 | {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 45 | }; 46 | static int cumulDaysInMonth[2][13] = { 47 | // 1 2 3 4 5 6 7 8 9 10 11 12 48 | {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, 49 | {0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} 50 | }; 51 | 52 | // --------------------------------------------------- STATIC 53 | 54 | /** 55 | * Check whether the year/month is valid 56 | * @param[in] year the year to check 57 | * @param[in] month the month to check 58 | * @returns whether the year/month is valid 59 | */ 60 | bool IsValidYearMonth(int year, int month) { 61 | bool valid = true; 62 | if (TimeOps::isValidYear(year)) { 63 | if (month < 1 || month > 12) { 64 | valid = false; 65 | } 66 | } 67 | else { 68 | valid = false; 69 | } 70 | return valid; 71 | } 72 | 73 | /** 74 | * Find the number of days in a month given the year/month 75 | * @param[in] year the year 76 | * @param[in] month the month 77 | * @returns the days in the given month 78 | */ 79 | int DaysInMonth(int year, int month) { 80 | if (!IsValidYearMonth(year, month)) { 81 | throw 1; 82 | } 83 | 84 | const int* daysInMonthPtr; 85 | 86 | if (TimeOps::isLeapYear(year)) { 87 | daysInMonthPtr = daysInMonth[1]; 88 | } 89 | else { 90 | daysInMonthPtr = daysInMonth[0]; 91 | } 92 | 93 | return daysInMonthPtr[month]; 94 | } 95 | 96 | /** 97 | * Check whether the year/month/day is valid 98 | * @param[in] year the year to check 99 | * @param[in] month the month to check 100 | * @param[in] day the day to check 101 | * @returns whether the year/month/day is valid 102 | */ 103 | bool IsValidYearMonthDay(int year, int month, int day) { 104 | bool valid = true; 105 | if (IsValidYearMonth(year, month)) { 106 | if (day < 1 || day > DaysInMonth(year, month)) { 107 | valid = false; 108 | } 109 | } 110 | else { 111 | valid = false; 112 | } 113 | return valid; 114 | } 115 | 116 | /** 117 | * Find the day of the year given the year/month/day 118 | * @param[in] year the year 119 | * @param[in] month the month 120 | * @param[in] day the day 121 | * @returns the day of the year 122 | */ 123 | int DayOfYear(int year, int month, int day) { 124 | if (!IsValidYearMonthDay(year, month, day)) { 125 | throw 1; 126 | } 127 | 128 | int daysThisYear = day; 129 | 130 | if (TimeOps::isLeapYear(year)) { 131 | daysThisYear += cumulDaysInMonth[1][month]; 132 | } 133 | else { 134 | daysThisYear += cumulDaysInMonth[0][month]; 135 | } 136 | 137 | return daysThisYear; 138 | } 139 | 140 | double AbsoluteDays(unsigned int year, double doy) { 141 | int64_t previousYear = year - 1; 142 | 143 | /* 144 | * + days in previous years ignoring leap days 145 | * + Julian leap days before this year 146 | * - minus prior century years 147 | * + plus prior years divisible by 400 days 148 | */ 149 | int64_t daysSoFar = 365 * previousYear 150 | + previousYear / 4LL 151 | - previousYear / 100LL 152 | + previousYear / 400LL; 153 | 154 | return static_cast(daysSoFar) + doy - 1.0; 155 | } 156 | 157 | int AbsoluteDays(int year, int month, int day) { 158 | int previousYear = year - 1; 159 | 160 | /* 161 | * days this year (0 - ...) 162 | * + days in previous years ignoring leap days 163 | * + Julian leap days before this year 164 | * - minus prior century years 165 | * + plus prior years divisible by 400 days 166 | */ 167 | int result = DayOfYear(year, month, day) - 1 168 | + 365 * previousYear 169 | + previousYear / 4 170 | - previousYear / 100 171 | + previousYear / 400; 172 | 173 | return result; 174 | } 175 | 176 | // ---------------- END of static 177 | 178 | /** 179 | * Default contructor 180 | * Initialise to 0001/01/01 00:00:00.000000 181 | */ 182 | DateTime::DateTime() { 183 | initialise(1, 1, 1, 0, 0, 0, 0); 184 | } 185 | 186 | /** 187 | * Constructor 188 | * @param[in] ticks raw tick value 189 | */ 190 | DateTime::DateTime(int64_t ticks) : m_encoded(ticks) { 191 | } 192 | 193 | /** 194 | * Constructor 195 | * @param[in] year the year 196 | * @param[in] doy the day of the year 197 | */ 198 | DateTime::DateTime(unsigned int year, double doy) { 199 | m_encoded = TimeSpan(static_cast(AbsoluteDays(year, doy) * TimeSpan::TICKS_PER_DAY)).getTicks(); 200 | } 201 | 202 | /** 203 | * Constructor 204 | * @param[in] year the year 205 | * @param[in] month the month 206 | * @param[in] day the day 207 | */ 208 | DateTime::DateTime(int year, int month, int day) { 209 | initialise(year, month, day, 0, 0, 0, 0); 210 | } 211 | 212 | /** 213 | * Constructor 214 | * @param[in] year the year 215 | * @param[in] month the month 216 | * @param[in] day the day 217 | * @param[in] hour the hour 218 | * @param[in] minute the minute 219 | * @param[in] second the second 220 | */ 221 | DateTime::DateTime(int year, int month, int day, int hour, int minute, int second) { 222 | initialise(year, month, day, hour, minute, second, 0); 223 | } 224 | 225 | /** 226 | * Constructor 227 | * @param[in] year the year 228 | * @param[in] month the month 229 | * @param[in] day the day 230 | * @param[in] hour the hour 231 | * @param[in] minute the minute 232 | * @param[in] second the second 233 | * @param[in] microsecond the microsecond 234 | */ 235 | void DateTime::initialise(int year, int month, int day, int hour, int minute, int second, int microsecond) { 236 | if (!IsValidYearMonthDay(year, month, day) || 237 | hour < 0 || hour > 23 || 238 | minute < 0 || minute > 59 || 239 | second < 0 || second > 59 || 240 | microsecond < 0 || microsecond > 999999) { 241 | throw 1; 242 | } 243 | m_encoded = TimeSpan(AbsoluteDays(year, month, day), 244 | hour, 245 | minute, 246 | second, 247 | microsecond).getTicks(); 248 | } 249 | 250 | /** 251 | * Return the current time 252 | * @param[in] microseconds whether to set the microsecond component 253 | * @returns a DateTime object set to the current date and time 254 | */ 255 | DateTime DateTime::now(bool microseconds) { 256 | DateTime dt; 257 | struct timespec ts; 258 | 259 | if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { 260 | if (microseconds) { 261 | dt = DateTime(TimeSpan::UNIX_EPOCH 262 | + ts.tv_sec * TimeSpan::TICKS_PER_SECOND 263 | + ts.tv_nsec / 1000LL * TimeSpan::TICKS_PER_MICROSECOND); 264 | } 265 | else { 266 | dt = DateTime(TimeSpan::UNIX_EPOCH 267 | + ts.tv_sec * TimeSpan::TICKS_PER_SECOND); 268 | } 269 | } 270 | else { 271 | throw 1; 272 | } 273 | 274 | return dt; 275 | } 276 | 277 | DateTime::~DateTime() { 278 | } 279 | 280 | TimeSpan DateTime::getTimeOfDay() const { 281 | return TimeSpan(getTicks() % TimeSpan::TICKS_PER_DAY); 282 | } 283 | 284 | DateTime DateTime::addYears(const int years) const { 285 | return addMonths(years * 12); 286 | } 287 | 288 | DateTime DateTime::addMonths(const int months) const { 289 | int year, month, day; 290 | TimeOps::toDMY(*this, day, month, year); 291 | month += months % 12; 292 | year += months / 12; 293 | 294 | if (month < 1) 295 | { 296 | month += 12; 297 | --year; 298 | } 299 | else if (month > 12) 300 | { 301 | month -= 12; 302 | ++year; 303 | } 304 | 305 | int maxday = DaysInMonth(year, month); 306 | day = MIN(day, maxday); 307 | 308 | return DateTime(year, month, day).add(getTimeOfDay()); 309 | } 310 | 311 | /** 312 | * Add a TimeSpan to this DateTime 313 | * @param[in] t the TimeSpan to add 314 | * @returns a DateTime which has the given TimeSpan added 315 | */ 316 | DateTime DateTime::add(const TimeSpan& t) const { 317 | return addTicks(t.getTicks()); 318 | } 319 | 320 | DateTime DateTime::addDays(const double days) const { 321 | return addMicroseconds(days * 86400000000.0); 322 | } 323 | 324 | DateTime DateTime::addHours(const double hours) const { 325 | return addMicroseconds(hours * 3600000000.0); 326 | } 327 | 328 | DateTime DateTime::addMinutes(const double minutes) const { 329 | return addMicroseconds(minutes * 60000000.0); 330 | } 331 | 332 | DateTime DateTime::addSeconds(const double seconds) const { 333 | return addMicroseconds(seconds * 1000000.0); 334 | } 335 | 336 | DateTime DateTime::addMicroseconds(const double microseconds) const { 337 | int64_t ticks = static_cast(microseconds * TimeSpan::TICKS_PER_MICROSECOND); 338 | return addTicks(ticks); 339 | } 340 | 341 | DateTime DateTime::addTicks(int64_t ticks) const { 342 | return DateTime(m_encoded + ticks); 343 | } 344 | 345 | /** 346 | * Get the number of ticks 347 | * @returns the number of ticks 348 | */ 349 | int64_t DateTime::getTicks() const { 350 | return m_encoded; 351 | } 352 | 353 | int DateTime::getYear() const { 354 | int year, month, day; 355 | TimeOps::toDMY(*this, day, month, year); 356 | return year; 357 | } 358 | 359 | int DateTime::getMonth() const { 360 | int year, month, day; 361 | TimeOps::toDMY(*this, day, month, year); 362 | return month; 363 | } 364 | 365 | int DateTime::getDay() const { 366 | int year, month, day; 367 | TimeOps::toDMY(*this, day, month, year); 368 | return day; 369 | } 370 | 371 | /** 372 | * Hour component 373 | * @returns the hour component 374 | */ 375 | int DateTime::getHour() const { 376 | return static_cast(m_encoded % TimeSpan::TICKS_PER_DAY / TimeSpan::TICKS_PER_HOUR); 377 | } 378 | 379 | /** 380 | * Minute component 381 | * @returns the minute component 382 | */ 383 | int DateTime::getMinute() const { 384 | return static_cast(m_encoded % TimeSpan::TICKS_PER_HOUR / TimeSpan::TICKS_PER_MINUTE); 385 | } 386 | 387 | /** 388 | * Second component 389 | * @returns the Second component 390 | */ 391 | int DateTime::getSecond() const { 392 | return static_cast(m_encoded % TimeSpan::TICKS_PER_MINUTE / TimeSpan::TICKS_PER_SECOND); 393 | } 394 | 395 | /** 396 | * Microsecond component 397 | * @returns the microsecond component 398 | */ 399 | int DateTime::getMicrosecond() const { 400 | return static_cast(m_encoded % TimeSpan::TICKS_PER_SECOND / TimeSpan::TICKS_PER_MICROSECOND); 401 | } 402 | 403 | DateTime DateTime::operator+ (const TimeSpan& _ts) const { 404 | return DateTime(getTicks() + _ts.getTicks()); 405 | } 406 | 407 | DateTime DateTime::operator+ (const DateTime& _dt) const { 408 | return DateTime(getTicks() + _dt.getTicks()); 409 | } 410 | 411 | DateTime DateTime::operator- (const TimeSpan& _ts) const { 412 | return DateTime(getTicks() - _ts.getTicks()); 413 | } 414 | 415 | DateTime DateTime::operator- (const DateTime& _dt) const { 416 | return DateTime(getTicks() - _dt.getTicks()); 417 | } 418 | 419 | bool DateTime::operator==(const DateTime& _dt) const { 420 | return m_encoded == _dt.getTicks(); 421 | } 422 | 423 | bool DateTime::operator!=(const DateTime& _dt) const { 424 | return m_encoded != _dt.getTicks(); 425 | } 426 | 427 | bool DateTime::operator>(const DateTime& _dt) const { 428 | return m_encoded > _dt.getTicks(); 429 | } 430 | 431 | bool DateTime::operator>=(const DateTime& _dt) const { 432 | return m_encoded >= _dt.getTicks(); 433 | } 434 | 435 | bool DateTime::operator<(const DateTime& _dt) const { 436 | return m_encoded < _dt.getTicks(); 437 | } 438 | 439 | bool DateTime::operator<=(const DateTime& _dt) const { 440 | return m_encoded <= _dt.getTicks(); 441 | } 442 | -------------------------------------------------------------------------------- /src/primitives/Matrix3x3.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix3x3.cpp 3 | // 4 | // Created by Patricio González Vivo on 2/21/25. 5 | // 6 | 7 | #include "hypatia/primitives/Matrix3x3.h" 8 | 9 | #include 10 | #include 11 | 12 | Matrix3x3::Matrix3x3() { 13 | // identity 14 | m_data[0][0] = 1.0; 15 | m_data[0][1] = 0.0; 16 | m_data[0][2] = 0.0; 17 | 18 | m_data[1][0] = 0.0; 19 | m_data[1][1] = 1.0; 20 | m_data[1][2] = 0.0; 21 | 22 | m_data[2][0] = 0.0; 23 | m_data[2][1] = 0.0; 24 | m_data[2][2] = 1.0; 25 | } 26 | 27 | Matrix3x3::Matrix3x3(const double* _m) { setData(_m); } 28 | 29 | Matrix3x3::Matrix3x3(const double _m00, const double _m01, const double _m02, 30 | const double _m10, const double _m11, const double _m12, 31 | const double _m20, const double _m21, const double _m22) { 32 | m_data[0][0] = _m00; 33 | m_data[0][1] = _m01; 34 | m_data[0][2] = _m02; 35 | 36 | m_data[1][0] = _m10; 37 | m_data[1][1] = _m11; 38 | m_data[1][2] = _m12; 39 | 40 | m_data[2][0] = _m20; 41 | m_data[2][1] = _m21; 42 | m_data[2][2] = _m22; 43 | } 44 | 45 | Matrix3x3::Matrix3x3(Vector3& _v0, Vector3& _v1, Vector3& _v2) { 46 | m_data[0][0] = _v0.x; 47 | m_data[0][1] = _v0.y; 48 | m_data[0][2] = _v0.z; 49 | 50 | m_data[1][0] = _v1.x; 51 | m_data[1][1] = _v1.y; 52 | m_data[1][2] = _v1.z; 53 | 54 | m_data[2][0] = _v2.x; 55 | m_data[2][1] = _v2.y; 56 | m_data[2][2] = _v2.z; 57 | } 58 | 59 | Matrix3x3::Matrix3x3(const Matrix3x3& _m) { setData(_m.getData()); } 60 | 61 | Matrix3x3::~Matrix3x3() { 62 | } 63 | 64 | Matrix3x3 Matrix3x3::transpose(const Matrix3x3& _m) { 65 | return Matrix3x3(_m.m_data[0][0], _m.m_data[1][0], _m.m_data[2][0], 66 | _m.m_data[0][1], _m.m_data[1][1], _m.m_data[2][1], 67 | _m.m_data[0][2], _m.m_data[1][2], _m.m_data[2][2]); 68 | } 69 | 70 | Matrix3x3 Matrix3x3::rotationX(const double _radians) { 71 | return Matrix3x3(1.0, 0.0, 0.0, 72 | 0.0, cos(_radians), -sin(_radians), 73 | 0.0, sin(_radians), cos(_radians)); 74 | } 75 | 76 | Matrix3x3 Matrix3x3::rotationY(const double _radians) { 77 | return Matrix3x3(cos(_radians), 0.0, sin(_radians), 78 | 0.0, 1.0, 0.0, 79 | -sin(_radians), 0.0, cos(_radians)); 80 | } 81 | 82 | Matrix3x3 Matrix3x3::rotationZ(const double _radians) { 83 | return Matrix3x3(cos(_radians), -sin(_radians), 0.0, 84 | sin(_radians), cos(_radians), 0.0, 85 | 0.0, 0.0, 1.0); 86 | } 87 | 88 | Matrix3x3 Matrix3x3::rotation(const double _radians, const Vector3& _axis) { 89 | const double c = cos(_radians); 90 | const double s = sin(_radians); 91 | const double t = 1.0 - c; 92 | 93 | return Matrix3x3(t * _axis.x * _axis.x + c, t * _axis.x * _axis.y - s * _axis.z, t * _axis.x * _axis.z + s * _axis.y, 94 | t * _axis.x * _axis.y + s * _axis.z, t * _axis.y * _axis.y + c, t * _axis.y * _axis.z - s * _axis.x, 95 | t * _axis.x * _axis.z - s * _axis.y, t * _axis.y * _axis.z + s * _axis.x, t * _axis.z * _axis.z + c); 96 | } 97 | 98 | void Matrix3x3::transpose() { *this = Matrix3x3::transpose(*this); } 99 | void Matrix3x3::rotateX(const double _radians) { *this *= Matrix3x3::rotationX(_radians); } 100 | void Matrix3x3::rotateY(const double _radians) { *this *= Matrix3x3::rotationY(_radians); } 101 | void Matrix3x3::rotateZ(const double _radians) { *this *= Matrix3x3::rotationZ(_radians); } 102 | void Matrix3x3::setData(const double* _m) { memcpy(m_data, _m, 3 * 3 * sizeof(double)); } 103 | 104 | Vector3 Matrix3x3::getRow(size_t _i) const { return Vector3(m_data[_i][0], m_data[_i][1], m_data[_i][2]); } 105 | Vector3 Matrix3x3::getColumn(size_t _i) const { return Vector3(m_data[0][_i], m_data[1][_i], m_data[2][_i]); } 106 | 107 | Vector3 Matrix3x3::operator*(const Vector3& _v) const { 108 | return Vector3( 109 | m_data[0][0] * _v.x + m_data[0][1] * _v.y + m_data[0][2] * _v.z, 110 | m_data[1][0] * _v.x + m_data[1][1] * _v.y + m_data[1][2] * _v.z, 111 | m_data[2][0] * _v.x + m_data[2][1] * _v.y + m_data[2][2] * _v.z 112 | ); 113 | } 114 | 115 | Matrix3x3 Matrix3x3::operator*(const Matrix3x3& _m) const { 116 | Matrix3x3 result; 117 | for (int i = 0; i < 3; i++) { 118 | for (int j = 0; j < 3; j++) { 119 | result.m_data[i][j] = m_data[i][0] * _m.m_data[0][j] + 120 | m_data[i][1] * _m.m_data[1][j] + 121 | m_data[i][2] * _m.m_data[2][j]; 122 | } 123 | } 124 | return result; 125 | } 126 | 127 | Matrix3x3& Matrix3x3::operator=(const Matrix3x3& _m) { 128 | memcpy(m_data, _m.m_data, 3 * 3 * sizeof(double)); 129 | return *this; 130 | } 131 | 132 | Matrix3x3& Matrix3x3::operator*=(const Matrix3x3& _m) { 133 | *this = *this * _m; 134 | return *this; 135 | } 136 | 137 | Matrix3x3& Matrix3x3::operator*=(const double _s) { 138 | for (int i = 0; i < 3; i++) { 139 | for (int j = 0; j < 3; j++) { 140 | m_data[i][j] *= _s; 141 | } 142 | } 143 | return *this; 144 | } 145 | 146 | Matrix3x3& Matrix3x3::operator/=(const double _s) { 147 | for (int i = 0; i < 3; i++) { 148 | for (int j = 0; j < 3; j++) { 149 | m_data[i][j] /= _s; 150 | } 151 | } 152 | return *this; 153 | } 154 | 155 | Matrix3x3 Matrix3x3::operator*(const double _s) const { 156 | Matrix3x3 result; 157 | for (int i = 0; i < 3; i++) { 158 | for (int j = 0; j < 3; j++) { 159 | result.m_data[i][j] = m_data[i][j] * _s; 160 | } 161 | } 162 | return result; 163 | } 164 | 165 | Matrix3x3 Matrix3x3::operator/(const double _s) const { 166 | Matrix3x3 result; 167 | for (int i = 0; i < 3; i++) { 168 | for (int j = 0; j < 3; j++) { 169 | result.m_data[i][j] = m_data[i][j] / _s; 170 | } 171 | } 172 | return result; 173 | } -------------------------------------------------------------------------------- /src/primitives/Polar.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Polar.cpp 3 | // Solar 4 | // 5 | // Created by Patricio González Vivo on 2/11/18. 6 | // 7 | 8 | #include "hypatia/primitives/Polar.h" 9 | 10 | #include 11 | 12 | Polar::Polar() : m_phi(0.0), m_theta(0.0) { 13 | } 14 | 15 | Polar::Polar(const double _phi, const double _theta, ANGLE_UNIT _type) { 16 | if (_type == RADS) { 17 | m_phi = _phi; 18 | m_theta = _theta; 19 | } 20 | else { 21 | m_phi = MathOps::toRadians( _phi ); 22 | m_theta = MathOps::toRadians( _theta ); 23 | } 24 | } 25 | 26 | Polar::~Polar() { 27 | } 28 | 29 | Polar& Polar::invert() { 30 | m_phi += MathOps::PI; 31 | m_theta *= -1.; 32 | 33 | return *this; 34 | } 35 | 36 | double& Polar::operator[]( int _n ) { 37 | return getPtr()[_n]; 38 | } 39 | 40 | double Polar::operator[]( int _n ) const { 41 | return getPtr()[_n]; 42 | } 43 | 44 | double * Polar::getPtr() { 45 | return (double*)&m_phi; 46 | } 47 | 48 | const double * Polar::getPtr() const { 49 | return (const double *)&m_phi; 50 | } 51 | -------------------------------------------------------------------------------- /src/primitives/TimeSpan.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // TimeSpan.cpp 3 | // Solar 4 | // 5 | // Created by Patricio González Vivo on 2/13/18. 6 | // 7 | 8 | #include "hypatia/primitives/TimeSpan.h" 9 | 10 | #include 11 | 12 | const int64_t TimeSpan::TICKS_PER_DAY = 86400000000LL; 13 | const int64_t TimeSpan::TICKS_PER_HOUR = 3600000000LL; 14 | const int64_t TimeSpan::TICKS_PER_MINUTE = 60000000LL; 15 | const int64_t TimeSpan::TICKS_PER_SECOND = 1000000LL; 16 | const int64_t TimeSpan::TICKS_PER_MILLISECOND = 1000LL; 17 | const int64_t TimeSpan::TICKS_PER_MICROSECOND = 1LL; 18 | const int64_t TimeSpan::UNIX_EPOCH = 62135596800000000LL; 19 | const int64_t TimeSpan::GREGORIAN_EPOCH = 49916304000000000LL; // 1582-Oct-15 20 | const int64_t TimeSpan::MAX_VALUE_TICKS = 315537897599999999LL; 21 | 22 | TimeSpan::TimeSpan(int64_t ticks) : m_ticks(ticks) { 23 | } 24 | 25 | TimeSpan::TimeSpan(int hours, int minutes, int seconds) { 26 | updateTicks(0, hours, minutes, seconds, 0); 27 | } 28 | 29 | TimeSpan::TimeSpan(int days, int hours, int minutes, int seconds) { 30 | updateTicks(days, hours, minutes, seconds, 0); 31 | } 32 | 33 | TimeSpan::TimeSpan(int days, int hours, int minutes, int seconds, int microseconds) { 34 | updateTicks(days, hours, minutes, seconds, microseconds); 35 | } 36 | 37 | TimeSpan::~TimeSpan() { 38 | } 39 | 40 | TimeSpan TimeSpan::operator+ (const TimeSpan& _ts) const { 41 | return TimeSpan(m_ticks + _ts.getTicks()); 42 | } 43 | 44 | TimeSpan TimeSpan::operator- (const TimeSpan& _ts) const { 45 | return TimeSpan(m_ticks - _ts.getTicks()); 46 | } 47 | 48 | bool TimeSpan::operator==(const TimeSpan& _ts) const { 49 | return m_ticks == _ts.getTicks(); 50 | } 51 | 52 | bool TimeSpan::operator!=(const TimeSpan& _ts) const { 53 | return m_ticks != _ts.getTicks(); 54 | } 55 | 56 | bool TimeSpan::operator>(const TimeSpan& _ts) const { 57 | return m_ticks > _ts.getTicks(); 58 | } 59 | 60 | bool TimeSpan::operator>=(const TimeSpan& _ts) const { 61 | return m_ticks >= _ts.getTicks(); 62 | } 63 | 64 | bool TimeSpan::operator<(const TimeSpan& _ts) const { 65 | return m_ticks < _ts.getTicks(); 66 | } 67 | 68 | bool TimeSpan::operator<=(const TimeSpan& _ts) const { 69 | return m_ticks <= _ts.getTicks(); 70 | } 71 | 72 | int TimeSpan::getDays() const { 73 | return static_cast(m_ticks / TICKS_PER_DAY); 74 | } 75 | 76 | int TimeSpan::getHours() const { 77 | return static_cast(m_ticks % TICKS_PER_DAY / TICKS_PER_HOUR); 78 | } 79 | 80 | int TimeSpan::getMinutes() const { 81 | return static_cast(m_ticks % TICKS_PER_HOUR / TICKS_PER_MINUTE); 82 | } 83 | 84 | int TimeSpan::getSeconds() const { 85 | return static_cast(m_ticks % TICKS_PER_MINUTE / TICKS_PER_SECOND); 86 | } 87 | 88 | int TimeSpan::getMilliseconds() const { 89 | return static_cast(m_ticks % TICKS_PER_SECOND / TICKS_PER_MILLISECOND); 90 | } 91 | 92 | int TimeSpan::getMicroseconds() const { 93 | return static_cast(m_ticks % TICKS_PER_SECOND / TICKS_PER_MICROSECOND); 94 | } 95 | 96 | int64_t TimeSpan::getTicks() const { 97 | return m_ticks; 98 | } 99 | 100 | double TimeSpan::getTotalDays() const { 101 | return static_cast(m_ticks) / TICKS_PER_DAY; 102 | } 103 | 104 | double TimeSpan::getTotalHours() const { 105 | return static_cast(m_ticks) / TICKS_PER_HOUR; 106 | } 107 | 108 | double TimeSpan::getTotalMinutes() const { 109 | return static_cast(m_ticks) / TICKS_PER_MINUTE; 110 | } 111 | 112 | double TimeSpan::getTotalSeconds() const { 113 | return static_cast(m_ticks) / TICKS_PER_SECOND; 114 | } 115 | 116 | double TimeSpan::getTotalMilliseconds() const { 117 | return static_cast(m_ticks) / TICKS_PER_MILLISECOND; 118 | } 119 | 120 | double TimeSpan::getTotalMicroseconds() const { 121 | return static_cast(m_ticks) / TICKS_PER_MICROSECOND; 122 | } 123 | 124 | void TimeSpan::updateTicks(int days, int hours, int minutes, int seconds, int microseconds) { 125 | m_ticks = days * TICKS_PER_DAY + 126 | (hours * 3600LL + minutes * 60LL + seconds) * TICKS_PER_SECOND + 127 | microseconds * TICKS_PER_MICROSECOND; 128 | } 129 | 130 | -------------------------------------------------------------------------------- /src/primitives/Vector2.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/primitives/Vector2.h" 2 | #include "hypatia/MathOps.h" 3 | 4 | #include 5 | 6 | Vector2::Vector2() : x(0.0), y(0.0) { 7 | } 8 | 9 | Vector2::Vector2(const Polar& _polar) { 10 | x = cos( _polar[0] ); 11 | y = sin( _polar[1] ); 12 | } 13 | 14 | Vector2::Vector2(const double _x, const double _y): x(_x), y(_y) { 15 | } 16 | 17 | Vector2::~Vector2() { 18 | } 19 | 20 | Vector2 Vector2::getNormalized() const { 21 | double length = getMagnitud(); 22 | if ( length > 0 ) { 23 | return Vector2( x/length, y/length ); 24 | } 25 | else { 26 | return Vector2(); 27 | } 28 | } 29 | 30 | double Vector2::getMagnitud() const { 31 | return sqrt(x*x + y*y); 32 | } 33 | 34 | double Vector2::dot(const Vector2& _vec) const { 35 | return (x * _vec.x) + (y * _vec.y); 36 | } 37 | 38 | Vector2& Vector2::normalize() { 39 | double length = getMagnitud(); 40 | if ( length > 0 ) { 41 | x /= length; 42 | y /= length; 43 | } 44 | return *this; 45 | } 46 | 47 | double * Vector2::getPtr() { 48 | return (double*)&x; 49 | } 50 | const double * Vector2::getPtr() const { 51 | return (const double *)&x; 52 | } 53 | 54 | double& Vector2::operator[]( int _n ){ 55 | return getPtr()[_n]; 56 | } 57 | 58 | double Vector2::operator[]( int _n ) const { 59 | return getPtr()[_n]; 60 | } 61 | 62 | Vector2 Vector2::operator+ (const Vector2& _vec) const { 63 | Vector2 rta; 64 | rta.x = x + _vec.x; 65 | rta.y = y + _vec.y; 66 | return rta; 67 | } 68 | 69 | Vector2 Vector2::operator- (const Vector2& _vec) const { 70 | Vector2 rta; 71 | rta.x = x - _vec.x; 72 | rta.y = y - _vec.y; 73 | return rta; 74 | } 75 | 76 | Vector2 Vector2::operator* (const Vector2& _vec) const { 77 | Vector2 rta; 78 | rta.x = x * _vec.x; 79 | rta.y = y * _vec.y; 80 | return rta; 81 | } 82 | 83 | Vector2 Vector2::operator/ (const Vector2& _vec) const { 84 | Vector2 rta; 85 | rta.x = x / _vec.x; 86 | rta.y = y / _vec.y; 87 | return rta; 88 | } 89 | 90 | Vector2 Vector2::operator+ (double _d) const { 91 | Vector2 rta; 92 | rta.x = x + _d; 93 | rta.y = y + _d; 94 | return rta; 95 | } 96 | 97 | Vector2 Vector2::operator- (double _d) const { 98 | Vector2 rta; 99 | rta.x = x - _d; 100 | rta.y = y - _d; 101 | return rta; 102 | } 103 | 104 | Vector2 Vector2::operator* (double _d) const { 105 | Vector2 rta; 106 | rta.x = x * _d; 107 | rta.y = y * _d; 108 | return rta; 109 | } 110 | 111 | Vector2 Vector2::operator/ (double _d) const { 112 | Vector2 rta; 113 | rta.x = x / _d; 114 | rta.y = y / _d; 115 | return rta; 116 | } 117 | 118 | Vector2& Vector2::operator+= (const Vector2& _vec) { 119 | x += _vec.x; 120 | y += _vec.y; 121 | return *this; 122 | } 123 | 124 | Vector2& Vector2::operator-= (const Vector2& _vec) { 125 | x -= _vec.x; 126 | y -= _vec.y; 127 | return *this; 128 | } 129 | 130 | Vector2& Vector2::operator*= (const Vector2& _vec) { 131 | x *= _vec.x; 132 | y *= _vec.y; 133 | return *this; 134 | } 135 | 136 | Vector2& Vector2::operator/= (const Vector2& _vec) { 137 | x /= _vec.x; 138 | y /= _vec.y; 139 | return *this; 140 | } 141 | 142 | Vector2& Vector2::operator+= (double _d) { 143 | x += _d; 144 | y += _d; 145 | return *this; 146 | } 147 | Vector2& Vector2::operator-= (double _d) { 148 | x -= _d; 149 | y -= _d; 150 | return *this; 151 | } 152 | 153 | Vector2& Vector2::operator*= (double _d) { 154 | x *= _d; 155 | y *= _d; 156 | return *this; 157 | } 158 | 159 | Vector2& Vector2::operator/= (double _d) { 160 | x /= _d; 161 | y /= _d; 162 | return *this; 163 | } 164 | -------------------------------------------------------------------------------- /src/primitives/Vector3.cpp: -------------------------------------------------------------------------------- 1 | #include "hypatia/primitives/Vector3.h" 2 | #include "hypatia/MathOps.h" 3 | 4 | #include 5 | 6 | Vector3::Vector3() : x(0.0), y(0.0), z(0.0) { 7 | } 8 | 9 | Vector3::Vector3(const Polar& _polar) { 10 | const double cosLat = cos( _polar[1] ); 11 | x = cos( _polar[0] ) * cosLat; 12 | y = sin( _polar[0] ) * cosLat; 13 | z = sin( _polar[1] ); 14 | } 15 | 16 | Vector3::Vector3(const double _x, const double _y, const double _z): x(_x), y(_y), z(_z) { 17 | } 18 | 19 | Vector3::~Vector3() { 20 | } 21 | 22 | Vector3 Vector3::getNormalized() const { 23 | double length = getMagnitud(); 24 | if ( length > 0 ) { 25 | return Vector3( x/length, y/length, z/length ); 26 | } 27 | else { 28 | return Vector3(); 29 | } 30 | } 31 | 32 | double Vector3::getMagnitud() const { 33 | return sqrt(x*x + y*y + z*z); 34 | } 35 | 36 | double Vector3::getLongitude(ANGLE_UNIT _type) const { 37 | double lng = atan2(y, x); 38 | if ( _type == DEGS ) { 39 | return MathOps::toDegrees( lng ); 40 | } 41 | else { 42 | return lng; 43 | } 44 | 45 | }; 46 | double Vector3::getLatitude(ANGLE_UNIT _type) const { 47 | // double lat = asin(z); 48 | double lat = atan2(z, sqrt(x * x + y * y)); 49 | if ( _type == DEGS ) { 50 | return MathOps::toDegrees( lat ); 51 | } 52 | else { 53 | return lat; 54 | } 55 | }; 56 | 57 | double Vector3::dot(const Vector3& _vec) const { 58 | return (x * _vec.x) + (y * _vec.y) + (z * _vec.z); 59 | } 60 | 61 | Vector3& Vector3::normalize() { 62 | double length = getMagnitud(); 63 | if ( length > 0 ) { 64 | x /= length; 65 | y /= length; 66 | z /= length; 67 | } 68 | return *this; 69 | } 70 | 71 | Vector3& Vector3::rotate ( double _angle, int _axis, bool _radians ) { 72 | if (!_radians) { 73 | _angle = MathOps::toRadians(_angle); 74 | } 75 | const double sinAng = sin( _angle ); 76 | const double cosAng = cos( _angle ); 77 | const int a = (_axis + 1) % 3; 78 | const int b = (_axis + 2) % 3; 79 | 80 | double temp = getPtr()[a] * cosAng - getPtr()[b] * sinAng; 81 | getPtr()[b] = getPtr()[b] * cosAng + getPtr()[a] * sinAng; 82 | getPtr()[a] = temp; 83 | 84 | return *this; 85 | } 86 | 87 | Vector3& Vector3::rotate ( double _lng, double _lat, bool _radians ) { 88 | if (!_radians) { 89 | _lng = MathOps::toRadians(_lng); 90 | _lat = MathOps::toRadians(_lat); 91 | } 92 | 93 | double cosLng = cos(_lng); 94 | double sinLng = sin(_lng); 95 | double cosLat = cos(_lat); 96 | double sinLat = sin(_lat); 97 | 98 | double x_tmp = cosLat * cosLng * x + sinLng * y + sinLat * cosLng * z; 99 | double y_tmp = -cosLat * sinLng * x + cosLng * y - sinLat * sinLng * z; 100 | z = -sinLat * x + cosLat * z; 101 | y = y_tmp; 102 | x = x_tmp; 103 | 104 | return *this; 105 | } 106 | 107 | Vector3& Vector3::rotate(double _angle, const Vector3& _axis, bool _radians ) { 108 | if (!_radians) { 109 | _angle = MathOps::toRadians(_angle); 110 | } 111 | 112 | Vector3 ax = _axis.getNormalized(); 113 | 114 | double sina = sin( _angle ); 115 | double cosa = cos( _angle ); 116 | double cosb = 1.0f - cosa; 117 | 118 | x = x * (ax.x*ax.x*cosb + cosa) 119 | + y * (ax.x*ax.y*cosb - ax.z*sina) 120 | + z * (ax.x*ax.z*cosb + ax.y*sina); 121 | 122 | y = x * (ax.y*ax.x*cosb + ax.z*sina) 123 | + y * (ax.y*ax.y*cosb + cosa) 124 | + z * (ax.y*ax.z*cosb - ax.x*sina); 125 | 126 | z = x * (ax.z*ax.x*cosb - ax.y*sina) 127 | + y * (ax.z*ax.y*cosb + ax.x*sina) 128 | + z * (ax.z*ax.z*cosb + cosa); 129 | 130 | return *this; 131 | } 132 | 133 | double * Vector3::getPtr() { 134 | return (double*)&x; 135 | } 136 | const double * Vector3::getPtr() const { 137 | return (const double *)&x; 138 | } 139 | 140 | double& Vector3::operator[]( int _n ){ 141 | return getPtr()[_n]; 142 | } 143 | 144 | double Vector3::operator[]( int _n ) const { 145 | return getPtr()[_n]; 146 | } 147 | 148 | Vector3 Vector3::operator+ (const Vector3& _vec) const { 149 | Vector3 rta; 150 | rta.x = x + _vec.x; 151 | rta.y = y + _vec.y; 152 | rta.z = z + _vec.z; 153 | return rta; 154 | } 155 | 156 | Vector3 Vector3::operator- (const Vector3& _vec) const { 157 | Vector3 rta; 158 | rta.x = x - _vec.x; 159 | rta.y = y - _vec.y; 160 | rta.z = z - _vec.z; 161 | return rta; 162 | } 163 | 164 | Vector3 Vector3::operator* (const Vector3& _vec) const { 165 | Vector3 rta; 166 | rta.x = x * _vec.x; 167 | rta.y = y * _vec.y; 168 | rta.z = z * _vec.z; 169 | return rta; 170 | } 171 | 172 | Vector3 Vector3::operator/ (const Vector3& _vec) const { 173 | Vector3 rta; 174 | rta.x = x / _vec.x; 175 | rta.y = y / _vec.y; 176 | rta.z = z / _vec.z; 177 | return rta; 178 | } 179 | 180 | Vector3 Vector3::operator+ (double _d) const { 181 | Vector3 rta; 182 | rta.x = x + _d; 183 | rta.y = y + _d; 184 | rta.z = z + _d; 185 | return rta; 186 | } 187 | 188 | Vector3 Vector3::operator- (double _d) const { 189 | Vector3 rta; 190 | rta.x = x - _d; 191 | rta.y = y - _d; 192 | rta.z = z - _d; 193 | return rta; 194 | } 195 | 196 | Vector3 Vector3::operator* (double _d) const { 197 | Vector3 rta; 198 | rta.x = x * _d; 199 | rta.y = y * _d; 200 | rta.z = z * _d; 201 | return rta; 202 | } 203 | 204 | Vector3 Vector3::operator/ (double _d) const { 205 | Vector3 rta; 206 | rta.x = x / _d; 207 | rta.y = y / _d; 208 | rta.z = z / _d; 209 | return rta; 210 | } 211 | 212 | Vector3& Vector3::operator+= (const Vector3& _vec) { 213 | x += _vec.x; 214 | y += _vec.y; 215 | z += _vec.z; 216 | return *this; 217 | } 218 | 219 | Vector3& Vector3::operator-= (const Vector3& _vec) { 220 | x -= _vec.x; 221 | y -= _vec.y; 222 | z -= _vec.z; 223 | return *this; 224 | } 225 | 226 | Vector3& Vector3::operator*= (const Vector3& _vec) { 227 | x *= _vec.x; 228 | y *= _vec.y; 229 | z *= _vec.z; 230 | return *this; 231 | } 232 | 233 | Vector3& Vector3::operator/= (const Vector3& _vec) { 234 | x /= _vec.x; 235 | y /= _vec.y; 236 | z /= _vec.z; 237 | return *this; 238 | } 239 | 240 | Vector3& Vector3::operator+= (double _d) { 241 | x += _d; 242 | y += _d; 243 | z += _d; 244 | return *this; 245 | } 246 | Vector3& Vector3::operator-= (double _d) { 247 | x -= _d; 248 | y -= _d; 249 | z -= _d; 250 | return *this; 251 | } 252 | 253 | Vector3& Vector3::operator*= (double _d) { 254 | x *= _d; 255 | y *= _d; 256 | z *= _d; 257 | return *this; 258 | } 259 | 260 | Vector3& Vector3::operator/= (double _d) { 261 | x /= _d; 262 | y /= _d; 263 | z /= _d; 264 | return *this; 265 | } 266 | -------------------------------------------------------------------------------- /tests/AstroOps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | from __future__ import unicode_literals 7 | 8 | from hypatia import * 9 | 10 | tests = [ ] 11 | 12 | check = True 13 | for i in range(0, len(tests)): 14 | if not tests[i]: 15 | check = False 16 | print("Test number",str(i), "fail") 17 | 18 | if not check: 19 | print(__file__, "FAILURE") 20 | else: 21 | print(__file__, "SUCESS") 22 | -------------------------------------------------------------------------------- /tests/Body.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from __future__ import absolute_import 5 | from __future__ import division 6 | from __future__ import print_function 7 | from __future__ import unicode_literals 8 | 9 | import time 10 | import datetime 11 | import math 12 | 13 | from hypatia import * 14 | import ephem 15 | 16 | LNG = -122.0442 17 | LAT = 37.6393 18 | TOLERANCE_DEG = 0.5 19 | 20 | a_obs = Observer(LNG, LAT) 21 | e_obs = ephem.Observer(); 22 | e_obs.lon = MathOps.toRadians(LNG) 23 | e_obs.lat = MathOps.toRadians(LAT) 24 | e_obs.elevation = 32 25 | 26 | def test(a_body, e_body ): 27 | a_body.compute(a_obs) 28 | print( "[ " + a_body.getName() + " ]") 29 | ok = True 30 | 31 | # a_hlat = a_body.getEclipticHeliocentric().getLatitude(DEGS) 32 | # a_hlng = a_body.getEclipticHeliocentric().getLongitude(DEGS) 33 | # e_hlat = MathOps.toDegrees(float(repr(e_body.hlat))) 34 | # e_hlng = MathOps.toDegrees(float(repr(e_body.hlon))) 35 | # d_hlat = abs(a_hlat - e_hlat) 36 | # d_hlng = abs(a_hlng - e_hlng) 37 | # if (d_hlat > TOLERANCE_DEG or d_hlng > TOLERANCE_DEG): 38 | # # print('Astro Lat: %s° Lng: %s°' % (a_hlat, a_hlng)) 39 | # # print('Ephem Lat: %s° Lng: %s°' % (e_hlat, e_hlng)) 40 | # print('DELTA Lat: %s° Lng: %s°' % (d_hlat, d_hlng)) 41 | # ok = False 42 | 43 | a_ra = a_body.getEquatorial().getRightAscension(DEGS) 44 | a_dec = a_body.getEquatorial().getDeclination(DEGS) 45 | e_ra = MathOps.toDegrees(float(repr(e_body.g_ra))) 46 | e_dec = MathOps.toDegrees(float(repr(e_body.g_dec))) 47 | d_ra = abs(a_ra - e_ra) 48 | d_dec = abs(a_dec - e_dec) 49 | if (d_ra > TOLERANCE_DEG or d_dec > TOLERANCE_DEG): 50 | # print('Astro Ra: %s° Dec: %s°' % (a_ra, a_dec)) 51 | # print('Ephem Ra: %s° Dec: %s°' % (e_ra, e_dec)) 52 | print('DELTA Ra: %s° Dec: %s°' % (d_ra, d_dec)) 53 | ok = False 54 | 55 | a_alt = a_body.getHorizontal().getAltitud(DEGS) 56 | a_az = a_body.getHorizontal().getAzimuth(DEGS) 57 | e_alt = MathOps.toDegrees(float(repr(e_body.alt))) 58 | e_az = MathOps.toDegrees(float(repr(e_body.az))) 59 | d_alt = abs(a_alt - e_alt) 60 | d_az = abs(a_az - e_az) 61 | 62 | if (d_alt > TOLERANCE_DEG or d_az > TOLERANCE_DEG): 63 | # print('Astro Alt: %s° Az: %s°' % (a_alt, a_az)) 64 | # print('Ephem Alt: %s° Az: %s°' % (e_alt, e_az)) 65 | print('DELTA Alt: %s° Az: %s°' % (d_alt, d_az)) 66 | ok = False 67 | 68 | return ok 69 | 70 | tests = [ 71 | test(Body(SUN), ephem.Sun(e_obs)), 72 | test(Body(MERCURY), ephem.Mercury(e_obs)), 73 | test(Body(VENUS), ephem.Venus(e_obs)), 74 | test(Body(LUNA), ephem.Moon(e_obs)), 75 | test(Body(MARS), ephem.Mars(e_obs)), 76 | test(Body(SATURN), ephem.Saturn(e_obs)), 77 | test(Body(JUPITER), ephem.Jupiter(e_obs)), 78 | test(Body(URANUS), ephem.Uranus(e_obs)), 79 | test(Body(NEPTUNE), ephem.Neptune(e_obs)), 80 | test(Body(PLUTO), ephem.Pluto(e_obs)) 81 | ] 82 | 83 | check = True 84 | for i in range(0, len(tests)): 85 | if not tests[i]: 86 | check = False 87 | print("Test number",str(i), "fail") 88 | 89 | if not check: 90 | print(__file__, "FAILURE") 91 | else: 92 | print(__file__, "SUCESS") 93 | -------------------------------------------------------------------------------- /tests/MathOps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | from __future__ import unicode_literals 7 | 8 | from hypatia import * 9 | 10 | tests = [ ] 11 | 12 | check = True 13 | for i in range(0, len(tests)): 14 | if not tests[i]: 15 | check = False 16 | print("Test number",str(i), "fail") 17 | 18 | if not check: 19 | print(__file__, "FAILURE") 20 | else: 21 | print(__file__, "SUCESS") 22 | -------------------------------------------------------------------------------- /tests/TimeOps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | from __future__ import unicode_literals 7 | 8 | import time 9 | import datetime 10 | import math 11 | 12 | from hypatia import * 13 | import ephem 14 | 15 | def testEqual(A, B): 16 | return A == B 17 | 18 | def testJDtoDatetimetoJD(jd): 19 | ymd = TimeOps.toYMD(jd) 20 | hms = TimeOps.toHMS(jd) 21 | expected = TimeOps.toJD(int(ymd[0]),int(ymd[1]),int(math.floor(ymd[2])), int(hms[0]), int(hms[1]), int(hms[2])) 22 | check = jd == expected 23 | if not check: 24 | print( "[FAIL]", str("{:.1f}".format(jd)), "is not", expected ) 25 | 26 | return check 27 | 28 | def testJDtoDatetime(jd, expected): 29 | dt = TimeOps.formatDateTime(jd, Y_M_D_HM) 30 | check = dt[0:len(dt)-2] == expected[0:len(expected)-2] 31 | if not check: 32 | print( "[FAIL]", str("{:.1f}".format(jd)), "(", dt, ") is not", expected ) 33 | 34 | return check 35 | 36 | def testJDtoYMD(jd, expected): 37 | ymd = TimeOps.toYMD(jd) 38 | hms = TimeOps.toHMS(jd) 39 | dt = str(ymd[0])+'-'+"{:0>2d}".format(ymd[1])+'-'+"{:.1f}".format(ymd[2]) 40 | dt = str(dt) 41 | 42 | check = dt == expected 43 | if not check: 44 | print( "[FAIL]",str("{:.1f}".format(jd)), "(", dt, ") is not", expected ) 45 | 46 | return check 47 | 48 | def testDOW(jd, expected): 49 | check = TimeOps.toDOW(jd) == expected 50 | if not check: 51 | dt = TimeOps.formatDateTime(jd, Y_M_D_HM) 52 | print( "[FAIL]",str("{:.1f}".format(jd)), "(", dt, ") is not", expected ) 53 | 54 | return check 55 | 56 | now_jd = TimeOps.now(UTC) 57 | now_secs = TimeOps.toJD( TimeOps.nowSeconds() ) 58 | now_date = datetime.datetime.utcnow() 59 | utc_date = now_date.strftime('%Y-%m-%d %H:%M') 60 | 61 | tests = [ 62 | testEqual(TimeOps.toJD(DateTime.now()), now_jd), 63 | testJDtoDatetime(ephem.julian_date(now_date), utc_date ), 64 | testJDtoDatetime(now_secs, utc_date ), 65 | testJDtoDatetime(now_jd, utc_date ), 66 | testJDtoYMD(2451545.0, '2000-01-1.5'), 67 | testJDtoYMD(2451179.5, '1999-01-1.0'), 68 | testJDtoYMD(2446822.5, '1987-01-27.0'), 69 | testJDtoYMD(2446966.0, '1987-06-19.5'), 70 | testJDtoYMD(2415020.5, '1900-01-1.0'), 71 | testJDtoYMD(2305447.5, '1600-01-1.0'), 72 | testJDtoYMD(2305812.5, '1600-12-31.0'), 73 | testJDtoYMD(2026871.8, '837-04-10.3'), 74 | testJDtoYMD(1676496.5, '-123-12-31.0'), 75 | testJDtoYMD(1676497.5, '-122-01-1.0'), 76 | testJDtoYMD(1356001.0, '-1000-07-12.5'), 77 | testJDtoYMD(1355866.5, '-1000-02-29.0'), 78 | testJDtoYMD(1355671.4, '-1001-08-17.9'), 79 | testJDtoYMD(0.0, '-4712-01-1.5'), 80 | testDOW(2434923.5, 3), 81 | testJDtoDatetimetoJD(2451545.0), 82 | testJDtoDatetimetoJD(2451179.5), 83 | testJDtoDatetimetoJD(2446822.5), 84 | testJDtoDatetimetoJD(2446966.0), 85 | testJDtoDatetimetoJD(2415020.5), 86 | testJDtoDatetimetoJD(2305447.5), 87 | testJDtoDatetimetoJD(2305812.5), 88 | # testJDtoDatetimetoJD(2026871.8), 89 | # testJDtoDatetimetoJD(1676496.5), 90 | # testJDtoDatetimetoJD(1676497.5), 91 | # testJDtoDatetimetoJD(1356001.0), 92 | # testJDtoDatetimetoJD(1355866.5), 93 | # testJDtoDatetimetoJD(1355671.4) 94 | ] 95 | 96 | # dt = DateTime.now() 97 | # print(TimeOps.toJD(dt), now_jd) 98 | # print(TimeOps.toGreenwichMeanSiderealTime(dt), MathOps.normalize(TimeOps.toGreenwichMeanSiderealTime(now_jd),RADS) ) 99 | # print(TimeOps.toGreenwichSiderealTime(dt), MathOps.normalize(TimeOps.toGreenwichSiderealTime(now_jd),RADS) ) 100 | # print(TimeOps.toGreenwichSiderealTime(now_jd), TimeOps.toGreenwichMeanSiderealTime(now_jd)) 101 | # print(TimeOps.toLST(dt, -122, DEGS), MathOps.normalize(TimeOps.toLST(now_jd, -122, DEGS), RADS) ) 102 | 103 | check = True 104 | for i in range(0, len(tests)): 105 | if not tests[i]: 106 | check = False 107 | print("Test number",str(i), "fail") 108 | 109 | if not check: 110 | print(__file__, "FAILURE") 111 | else: 112 | print(__file__, "SUCESS") 113 | --------------------------------------------------------------------------------