Pastebin
API
tools
faq
paste
Login
Sign up
Please fix the following errors:
New Paste
Syntax Highlighting
// Compute a list of transits over aspects of a given horoscope // Also compute the enter and leave times into the 1° orb of each aspect #include <iostream> #include <iomanip> #include <vector> #include <regex> #include <map> #include <math.h> #include "swephexp.h" struct t_input { double jd_et,lon,lat; double from,to; unsigned int filter; }; using namespace std; // Difference on the arc (taking account of the gap 360->0) inline double arcdiff(double x, double y) { double z = x - y; return ( (z >= -180) && (z < 180)) ? z : z - floor(z/360+.5)*360; } // Reduce a degree value to the [0...360[ inline double fmod360( double x ) { return (x < 360 && x >= 0) ? x : x - floor(x/360)*360; } // An ecliptical position (only longitude may be filled) // Also keeps track of possible warnings during computation class Position { public: Position() : Position(0.) {} Position(const double lon, const string& warning = "") { this->lon = lon; this->lat = 0; this->dist = 0; this->vlon = 0; this->vlat = 0; this->vdist = 0; this->warning = warning; } Position(const double *xx, const string& warning ="") { this->lon = xx[0]; this->lat = xx[1]; this->dist = xx[2]; this->vlon = xx[3]; this->vlat = xx[4]; this->vdist = xx[5]; this->warning = warning; } double lon, lat, dist; double vlon,vlat,vdist; string warning; bool has_warnings() { return !warning.empty(); } void toStream(ostream &str) const { str << lon; } }; // Ouput of a position ostream & operator<<(ostream & Str, Position const & p) { p.toStream(Str); return Str; } class ComputationError { public: ComputationError(const string message) : message(message) {} string message; }; // The minimum which is necessary for computing a horoscope: jd, lon, lat class HoroscopeBasicData { public: double jd_et,lon,lat; bool initial = true; HoroscopeBasicData() {} HoroscopeBasicData(double jd_et,double lon, double lat) : jd_et(jd_et),lon(lon),lat(lat) { initial = false; } bool operator == (const HoroscopeBasicData& h) { return h.jd_et == jd_et && h.lon == lon && h.lat == lat; } bool operator != (const HoroscopeBasicData& h) { return h.jd_et != jd_et || h.lon != lon || h.lat != lat; } }; // An astrological object // abstraction of all computable points of a Horoscope // (like planets, asteroids, fixed stars, house cusps, midpoints, ...) class AstroObject { public: const string name; const string symbol; unsigned int aspectStrength = 0x7f; // Default: aspects of all groups AstroObject(const string& name, const string& symbol) : name(name),symbol(symbol) {} AstroObject(const char* name, const char* symbol) : name(name), symbol(symbol) {} virtual Position compute( const HoroscopeBasicData& data ) const throw(ComputationError) = 0; virtual ~AstroObject() {} protected: friend ostream& operator<<(ostream&, const AstroObject&); }; ostream& operator<<(ostream &strm, const AstroObject &a) { return strm << a.symbol ; } // I define an ephemeris object by computability via a swe_calc() call class EphemerisObject : public AstroObject { public: EphemerisObject(const string& name, const string& symbol, const int number): AstroObject(name,symbol), ipl(number) { } Position compute( const HoroscopeBasicData& data ) const throw(ComputationError) { double xx[6]; char serr[256]; int iflag = SEFLG_SPEED; int rc = swe_calc( data.jd_et, ipl, iflag, xx, serr); if (rc < 0) { throw ComputationError(string(serr)); } return Position(xx,rc > 0 ? string(serr) : ""); } private: int ipl; }; class Planet : public EphemerisObject { public: Planet(const string& name, const string& symbol, const int number): EphemerisObject(name,symbol,number) { } }; // We want to treat a single house cusp like any other AstroObject // On the other hand, swe_houses gives us all the house cusps at once // For efficiency, we have a class Houses treating the complete group... class Houses; // ... and a class House representing a single house cusp class House : public AstroObject { public: House(const char* name, const char* symbol, const int number, Houses *houses): AstroObject(name,symbol), number(number), houses(houses) { // Intermediate house cusps: ☌☌ only // Angles: ☌☌, □□, △△ (respect symmetry of AC/DC and MC/IC) switch (number) { case 1: case 10: aspectStrength = 0b1101; break; default: aspectStrength = 0b1; } } Position compute( const HoroscopeBasicData& data ) const throw(ComputationError); private: int number; // Reference to a Houses instance, which computes all the house cusps Houses* houses; }; class Houses { public: struct t_cusp { const char * name, *symbol; }; Houses(int hsys = 'P', // Default: Placidus const t_cusp cusps[] = (t_cusp[]) { {"ASC","AC"}, {"Haus 2","H2"}, {"Haus 3","H3"}, {"IC","IC"}, {"Haus 5","H5"}, {"Haus 6","H6"}, {"DSC","DC"}, {"Haus 8","H8"}, {"Haus 9","H9"}, {"MC","MC"}, {"Haus 11","H11"}, {"Haus 12","H12"}, {NULL,NULL} }) : hsys(hsys) { for (int i=0;cusps[i].name != NULL;i++) { this->cusps.push_back( new House( cusps[i].name, cusps[i].symbol, i+1, this) ); } } vector<const AstroObject*> cusps; int hsys; map<const AstroObject*,Position> compute( const HoroscopeBasicData& data ) throw(ComputationError); Position compute( const HoroscopeBasicData& data, const int number ) throw(ComputationError); private: HoroscopeBasicData data; vector<Position> positions; }; // Default values: 12 house cusps, Placidus Houses* housesDefault = new Houses(); // Default: the ten most commonly used astrological planets, plus lunar node vector<const AstroObject*> planetsDefault = { new Planet("Sonne","☉",0), new Planet("Mond","☽",1), new Planet("Merkur","☿",2), new Planet("Venus","♀",3), new Planet("Mars","♂",4), new Planet("Jupiter","♃",5), new Planet("Saturn","♄",6), new Planet("Uranus","⛢",7), new Planet("Neptun","♆",8), new Planet("Pluto","♇",9), new Planet("Mondknoten","☊",10) }; // Descriptive class, only keeps a vector of AstroObjects, in particular house cusps // Has a compute() method for getting all the positions in a concrete Horoscope class HoroscopeParts { public: HoroscopeParts( vector<const AstroObject*>& planets, Houses* houses ) : planets(planets),houses(houses) {} map<const AstroObject*,Position> compute( const HoroscopeBasicData& data ) const { map<const AstroObject*,Position> result; for (const AstroObject* p : planets ) { result[p] = p->compute( data ); } map<const AstroObject*,Position> hpos = houses->compute( data ); result.insert( hpos.begin(), hpos.end() ); return result; } private: vector<const AstroObject*> planets; Houses* houses; }; HoroscopeParts horoscopePartsDefault( planetsDefault, housesDefault); // Implements the swe_houses() call map<const AstroObject*,Position> Houses::compute(const HoroscopeBasicData& data) throw (ComputationError) { map<const AstroObject*,Position> result; this->data = data; positions.clear(); double houses[13], ascmc[10]; swe_houses( data.jd_et - swe_deltat( data.jd_et), data.lat, data.lon, hsys, houses, ascmc); for (int i=0;i<12;i++) { Position p = Position( houses[i+1] ); result[ cusps[i] ] = p; positions.push_back( p ); } return result; } // Give back a single house cusp position Position Houses::compute( const HoroscopeBasicData& data, const int number ) throw(ComputationError) { if (this->data.initial || data.jd_et != this->data.jd_et || data.lon != this->data.lon || data.lat != this->data.lat ) { compute( data ); } return positions[number-1]; } // The same, viewed from inside of AstroObject Position House::compute( const HoroscopeBasicData& data ) const throw(ComputationError) { return houses->compute(data,number); } // Descriptive class, objects representing single aspects class Aspect { public: Aspect( const char* name, const char* symbol, int strength, double angle) : name(name), symbol(symbol), strength(strength), angle(angle) {} string name; string symbol; unsigned int strength; double angle; ostream& toStream( ostream& str ) const { str << symbol; return str; } }; ostream & operator<<(ostream & str, Aspect const & a) { return a.toStream(str); } // The aspects in use, and their groups vector<Aspect> aspects = { { "Konjunktion", "☌", 0x01, 0 }, { "Halbsextil", "⚺", 0x40, 30 }, { "Halbquadrat", "∠", 0x20, 45 }, { "Sextil", "⚹", 0x10, 60 }, { "Quadrat", "□", 0x04, 90 }, { "Trigon", "△", 0x08, 120 }, { "Anderthalbquadrat", "⚼", 0x20, 135}, { "Quincunx", "⚻", 0x40, 150}, { "Opposition", "☍", 0x02, 180} }; enum Direction { LEFT, RIGHT }; // Descriptive structure for an aspect to a planet (to an AstroObject) class AspectPoint { public: const Aspect* aspect; // Aspect... const AstroObject* object; // ...to this AstroObject const Direction direction; // ...RIGHT = in forward, LEFT = in backward zodiac direction const int bound; // Usually zero, but +1 or -1 for aspect boundaries }; ostream & operator<<(ostream & str, AspectPoint const & ap) { str << *(ap.aspect) << *(ap.object); return str; } // Compputes an aspect wreath from a map of AstroObjects with positions class Aspectarium { public: multimap<double,AspectPoint> wreath; Aspectarium(const map<const AstroObject*,Position> p, const unsigned int filter = 0xff, const vector<Aspect>& aspects = aspects) { for (auto o : p) { for (const Aspect& a: aspects) { if (!(a.strength & filter )) continue; if (!(o.first->aspectStrength & a.strength)) continue; addAspect(o.first,o.second.lon,RIGHT,a); if (a.symbol != "☌" && a.symbol != "☍") { addAspect(o.first,o.second.lon,LEFT,a); } } } } multimap<double,AspectPoint> wreath_enriched_with_boundaries() const { multimap<double,AspectPoint> result = wreath; for (auto it : wreath) { result.insert( pair<double,AspectPoint>( fmod360(it.first-1), AspectPoint({ it.second.aspect,it.second.object,it.second.direction,-1 }) )); result.insert( pair<double,AspectPoint>( fmod360(it.first+1), AspectPoint({ it.second.aspect,it.second.object,it.second.direction,+1 }) )); } return result; } ostream& toStream( ostream& str) const { for (auto a: wreath) { AspectPoint ap = a.second; str << setw(12) << setprecision(4) << fixed << a.first << " : " << ap << endl; } return str; } private: void addAspect(const AstroObject* o, const double pos, const Direction direction, const Aspect& a) { double l = fmod360( pos + a.angle * (direction == RIGHT ? 1 : -1) ); AspectPoint ap({ &a, o, direction, 0 }); wreath.insert( pair<double,AspectPoint>(l,ap)); } }; ostream & operator<<(ostream & str, Aspectarium const & a) { a.toStream(str); return str; } // Class Horoscope, basically wraps a map of AstroObjects together with their positions class Horoscope : public HoroscopeBasicData { public: Horoscope(double jd_et,double lon, double lat,const HoroscopeParts& hp = horoscopePartsDefault) : HoroscopeBasicData(jd_et,lon,lat) { p = hp.compute((HoroscopeBasicData)*this); } Aspectarium getAspectarium( unsigned int aspect_filter = 0xff) { return Aspectarium( p, aspect_filter ); } void toStream(ostream &str) const { for (auto const& pos: p) { str << setw(20) << *(pos.first) << ": " << pos.second << endl; } } private: map<const AstroObject*,Position> p; }; ostream & operator<<(ostream & Str, Horoscope const & h) { h.toStream(Str); return Str; } // Position with time typedef struct { double jd_et; Position pos; } t_position; // Any interval typedef struct { double from, to; } t_interval; // Compute the time of a transit double transit_time( double lon, const t_position last, const t_position next) { double jd_et; if (next.pos.lon == last.pos.lon) return (last.pos.lon == lon) ? last.jd_et : NAN; // To keep it simple, we use linear interpolation // Could improve by cubic interpolation, employing also last.pos.vlon and next.pos.vlon jd_et = (next.jd_et-last.jd_et)*arcdiff(lon,last.pos.lon)/arcdiff(next.pos.lon,last.pos.lon) + last.jd_et; return jd_et; } // An object of class Transit represents a single transit // a current AstroObject is crossing an aspect to a given AstroObject (from the base horoscope) class Transit { public: double jd_et,lon; const AstroObject* current; AspectPoint aspect; Direction direction; double jd_begin, jd_end; // Current planet is entering the orbis // - either it is moving directly, and the bound is -1 // - or it is moving retrogradely, and the bound is +1 bool entering() const { return ( (aspect.bound == -1 && direction == RIGHT) || (aspect.bound == +1 && direction == LEFT) ); } // Current planet is leaving the orbis // - either it is moving directly, and the bound is +1 // - or it is moving retrogradely, and the bound is -1 bool leaving() const { return ( (aspect.bound == -1 && direction == LEFT) || (aspect.bound == +1 && direction == RIGHT) ); } // Consider two transit objects as equal if the aspect formulae are identical // here, we do distinguish right from left aspects bool operator==(const Transit& t) const { return ( current == t.current && aspect.aspect == t.aspect.aspect && aspect.object == t.aspect.object && aspect.direction == t.aspect.direction ); } }; // Output a transit list as JSON object void print(ostream & Str, const multimap<double,Transit>& t) { bool first = true; Str << "[" << endl; for ( auto it : t ) { if (!first) { Str << "," << endl; } Str << "[" << setw(14) << setprecision(5) << fixed << it.first << ", " << setw(14) << setprecision(5) << fixed << it.second.jd_begin << ", " << setw(14) << setprecision(5) << fixed << it.second.jd_end << ", " << setw(8) << setprecision(4) << it.second.lon << ", " << "\"" << *(it.second.current) << (it.second.direction == LEFT ? "℞" :"") << (it.second.aspect.bound == -1 ? "LB " :"") << (it.second.aspect.bound == 1 ? "RB " :"") << it.second.aspect << "\"]"; first = false; } Str << endl << "]"; } // Output an aspect wreath as a list (plain text, not JSON) void print(ostream & Str, const multimap<double,AspectPoint>& w) { for (auto it: w) { Str << setw(14) << setprecision(5) << fixed << it.first << ": "; Str << it.second << endl; } } // Find all the aspects from the wreath falling into the given interval, // and compute the exact transit time for each of them multimap<double,Transit> transits_from_interval( const t_interval& interval, const AstroObject* o, const t_position last, const t_position next, const multimap<double,AspectPoint>& wreath) { multimap<double,Transit> r; for (auto it = wreath.lower_bound( interval.from ); it != wreath.end() && it->first < interval.to; ++it ) { double jd_et = transit_time(it->first,last,next); r.insert( pair<double,Transit>( jd_et, Transit({ jd_et, it->first, o, it->second, (arcdiff(next.pos.lon,last.pos.lon)<0) ? LEFT: RIGHT }) )); } return r; } // Decompose an interval on the circle into parts on [0...360] // Take account of the discontinuity 360->0 // Take account of retrograde motion (input.from may well be > input.to) vector<t_interval> get_segments(const t_interval& input) { if (arcdiff(input.to,input.from)>0) { if (input.to > input.from) { return vector<t_interval>({input}); } else { return vector<t_interval>({ { input.from, 360.}, { 0., input.to } }); } } else { if (input.to < input.from) { return vector<t_interval>({{input.to,input.from}}); } else { return vector<t_interval>({ { input.to, 360.}, { 0., input.from} }); } } } // Compute all transits in the given interval, // including the times when the aspect is entered and left by the current AstroObject multimap<double,Transit> transits(double from, double to, const Aspectarium& a, vector<const AstroObject*>& planets = planetsDefault) { // Enrich the aspect wreath with aspect boundaries (i.e. aspect locus +1° / -1°) multimap<double,AspectPoint> wreath = a.wreath_enriched_with_boundaries( ); // For each planet: // Compute the times where it passes the aspects of the 'enriched wreath' multimap<double,Transit> r; for (const AstroObject* o : planets) { Position last = o->compute( HoroscopeBasicData(from,0,0) ); for (double t = from+1; t<=to; t+=1) { Position next = o->compute( HoroscopeBasicData(t,0,0) ); vector<t_interval> v = get_segments({ last.lon, next.lon }); for (t_interval iv: v) { multimap<double,Transit> s = transits_from_interval( iv, o, (t_position) { t-1, last }, (t_position) { t, next }, wreath ); r.insert(s.begin(),s.end()); } last = next; } } // For each transit: adjoin the time when it enters and leaves the orbis multimap<double,Transit> result; for (auto it = r.begin(); it != r.end(); ++it) { if (it->second.aspect.bound == 0) { // Scan backwards in longitude, when did the planet enter the aspect orb it->second.jd_begin = from; for (auto it1 = it; it1 != r.begin();--it1) { if (it1->second == it->second && it1->second.entering()) { it->second.jd_begin = it1->first; break; } } // Scan forward in longitude, when did the planet leave the aspect orb it->second.jd_end = to; for (auto it2 = next(it); it2 != r.end();++it2) { if (it2->second == it->second && it2->second.leaving() ) { it->second.jd_end = it2->first; break; } } result.insert(*it); } } return result; } void teardown() { for (auto p: planetsDefault) { delete p; } } void parse_query_string( const char* qs, t_input& input ) { const regex NAME_VALUE_PATTERN("([\\w+%]+)=([^&]*)"); const string query(qs); auto words_begin = sregex_iterator(query.begin(), query.end(), NAME_VALUE_PATTERN); auto words_end = sregex_iterator(); for (auto it = words_begin; it != words_end; it++) { const string name((*it)[1]); const char* value = (*it)[2].str().c_str(); if (name == "jd_et") { sscanf(value,"%lf",&(input.jd_et)); } else if (name == "lon") { sscanf(value,"%lf",&(input.lon)); } else if (name == "lat") { sscanf(value,"%lf",&(input.lat)); } else if (name == "from") { sscanf(value,"%lf",&(input.from)); } else if (name == "to") { sscanf(value,"%lf",&(input.to)); } else if (name == "filter") { sscanf(value,"%d",&(input.filter)); } } } int main( int argc, char** argv) { // Some defaults t_input input = { 2451545.,7.,52.,2452500.,2452501.,0b11111 }; if (argc>=2) { // For tests parse_query_string(argv[1],input); } else { // In CGI mode const char* query_string = getenv("QUERY_STRING"); if (query_string) { parse_query_string(query_string,input); } } cout << "HTTP/1.1 200 OK\nContent-Type:application/json;charset=utf-8\n\n"; Horoscope h(input.jd_et,input.lon,input.lat); // Default filter: 0b11111 = Down to and including ⚹ Aspectarium a = h.getAspectarium( input.filter ); multimap<double,Transit> t = transits(input.from,input.to,a); // Output cout << "{ \"data\":" ; print(cout,t); cout << "}" << endl; // Teardown - becomes relevant when code is shifted into shared library teardown( ); return 0; }
Optional Paste Settings
Category:
None
Cryptocurrency
Cybersecurity
Fixit
Food
Gaming
Haiku
Help
History
Housing
Jokes
Legal
Money
Movies
Music
Pets
Photo
Science
Software
Source Code
Spirit
Sports
Travel
TV
Writing
Tags:
Syntax Highlighting:
None
Bash
C
C#
C++
CSS
HTML
JSON
Java
JavaScript
Lua
Markdown (PRO members only)
Objective C
PHP
Perl
Python
Ruby
Swift
4CS
6502 ACME Cross Assembler
6502 Kick Assembler
6502 TASM/64TASS
ABAP
AIMMS
ALGOL 68
APT Sources
ARM
ASM (NASM)
ASP
ActionScript
ActionScript 3
Ada
Apache Log
AppleScript
Arduino
Asymptote
AutoIt
Autohotkey
Avisynth
Awk
BASCOM AVR
BNF
BOO
Bash
Basic4GL
Batch
BibTeX
Blitz Basic
Blitz3D
BlitzMax
BrainFuck
C
C (WinAPI)
C Intermediate Language
C for Macs
C#
C++
C++ (WinAPI)
C++ (with Qt extensions)
C: Loadrunner
CAD DCL
CAD Lisp
CFDG
CMake
COBOL
CSS
Ceylon
ChaiScript
Chapel
Clojure
Clone C
Clone C++
CoffeeScript
ColdFusion
Cuesheet
D
DCL
DCPU-16
DCS
DIV
DOT
Dart
Delphi
Delphi Prism (Oxygene)
Diff
E
ECMAScript
EPC
Easytrieve
Eiffel
Email
Erlang
Euphoria
F#
FO Language
Falcon
Filemaker
Formula One
Fortran
FreeBasic
FreeSWITCH
GAMBAS
GDB
GDScript
Game Maker
Genero
Genie
GetText
Go
Godot GLSL
Groovy
GwBasic
HQ9 Plus
HTML
HTML 5
Haskell
Haxe
HicEst
IDL
INI file
INTERCAL
IO
ISPF Panel Definition
Icon
Inno Script
J
JCL
JSON
Java
Java 5
JavaScript
Julia
KSP (Kontakt Script)
KiXtart
Kotlin
LDIF
LLVM
LOL Code
LScript
Latex
Liberty BASIC
Linden Scripting
Lisp
Loco Basic
Logtalk
Lotus Formulas
Lotus Script
Lua
M68000 Assembler
MIX Assembler
MK-61/52
MPASM
MXML
MagikSF
Make
MapBasic
Markdown (PRO members only)
MatLab
Mercury
MetaPost
Modula 2
Modula 3
Motorola 68000 HiSoft Dev
MySQL
Nagios
NetRexx
Nginx
Nim
NullSoft Installer
OCaml
OCaml Brief
Oberon 2
Objeck Programming Langua
Objective C
Octave
Open Object Rexx
OpenBSD PACKET FILTER
OpenGL Shading
Openoffice BASIC
Oracle 11
Oracle 8
Oz
PARI/GP
PCRE
PHP
PHP Brief
PL/I
PL/SQL
POV-Ray
ParaSail
Pascal
Pawn
Per
Perl
Perl 6
Phix
Pic 16
Pike
Pixel Bender
PostScript
PostgreSQL
PowerBuilder
PowerShell
ProFTPd
Progress
Prolog
Properties
ProvideX
Puppet
PureBasic
PyCon
Python
Python for S60
QBasic
QML
R
RBScript
REBOL
REG
RPM Spec
Racket
Rails
Rexx
Robots
Roff Manpage
Ruby
Ruby Gnuplot
Rust
SAS
SCL
SPARK
SPARQL
SQF
SQL
SSH Config
Scala
Scheme
Scilab
SdlBasic
Smalltalk
Smarty
StandardML
StoneScript
SuperCollider
Swift
SystemVerilog
T-SQL
TCL
TeXgraph
Tera Term
TypeScript
TypoScript
UPC
Unicon
UnrealScript
Urbi
VB.NET
VBScript
VHDL
VIM
Vala
Vedit
VeriLog
Visual Pro Log
VisualBasic
VisualFoxPro
WHOIS
WhiteSpace
Winbatch
XBasic
XML
XPP
Xojo
Xorg Config
YAML
YARA
Z80 Assembler
ZXBasic
autoconf
jQuery
mIRC
newLISP
q/kdb+
thinBasic
Paste Expiration:
Never
Burn after read
10 Minutes
1 Hour
1 Day
1 Week
2 Weeks
1 Month
6 Months
1 Year
Paste Exposure:
Public
Unlisted
Private
Folder:
(members only)
Password
NEW
Enabled
Disabled
Burn after read
NEW
Paste Name / Title:
Create New Paste
Hello
Guest
Sign Up
or
Login
Sign in with Facebook
Sign in with Twitter
Sign in with Google
You are currently not logged in, this means you can not edit or delete anything you paste.
Sign Up
or
Login
Public Pastes
Untitled
8 min ago | 0.14 KB
Untitled
26 min ago | 0.06 KB
Untitled
1 hour ago | 7.75 KB
Untitled
3 hours ago | 16.07 KB
Untitled
7 hours ago | 9.93 KB
Inoreader custom CSS
CSS | 9 hours ago | 0.20 KB
Untitled
9 hours ago | 8.11 KB
Untitled
11 hours ago | 9.50 KB
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the
Cookies Policy
.
OK, I Understand
Not a member of Pastebin yet?
Sign Up
, it unlocks many cool features!