Advertisement
rplantiko

Compute a transit list

Nov 26th, 2016
564
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 20.85 KB | None | 0 0
  1. // Compute a list of transits over aspects of a given horoscope
  2. // Also compute the enter and leave times into the 1° orb of each aspect
  3.  
  4. #include <iostream>
  5. #include <iomanip>
  6. #include <vector>
  7. #include <regex>
  8. #include <map>
  9. #include <math.h>
  10.  
  11. #include "swephexp.h"
  12.  
  13. struct t_input {
  14.   double jd_et,lon,lat;
  15.   double from,to;
  16.   unsigned int filter;
  17. };
  18.  
  19. using namespace std;
  20.  
  21. // Difference on the arc (taking account of the gap 360->0)
  22. inline double arcdiff(double x, double y) {
  23.   double z = x - y;
  24.   return ( (z >= -180) && (z < 180)) ? z :
  25.     z - floor(z/360+.5)*360;
  26. }
  27.  
  28. // Reduce a degree value to the [0...360[
  29. inline double fmod360( double x ) {
  30.   return (x < 360 && x >= 0) ? x :
  31.     x - floor(x/360)*360;
  32. }
  33.  
  34. // An ecliptical position (only longitude may be filled)
  35. // Also keeps track of possible warnings during computation
  36. class Position {
  37.   public:
  38.     Position() : Position(0.) {}
  39.     Position(const double lon, const string& warning = "") {
  40.       this->lon   = lon;
  41.       this->lat   = 0;
  42.       this->dist  = 0;
  43.       this->vlon  = 0;
  44.       this->vlat  = 0;
  45.       this->vdist = 0;
  46.       this->warning = warning;
  47.     }
  48.     Position(const double *xx, const string& warning ="") {
  49.       this->lon   = xx[0];
  50.       this->lat   = xx[1];
  51.       this->dist  = xx[2];
  52.       this->vlon  = xx[3];
  53.       this->vlat  = xx[4];
  54.       this->vdist = xx[5];
  55.       this->warning = warning;
  56.     }
  57.     double lon, lat, dist;
  58.     double vlon,vlat,vdist;
  59.     string warning;
  60.     bool has_warnings() {
  61.       return !warning.empty();
  62.     }
  63.     void toStream(ostream &str) const {
  64.       str << lon;
  65.     }
  66. };
  67.  
  68. // Ouput of a position
  69. ostream & operator<<(ostream & Str, Position const & p) {
  70.   p.toStream(Str);
  71.   return Str;
  72. }
  73.  
  74. class ComputationError {
  75. public:
  76.   ComputationError(const string message) : message(message) {}
  77.   string message;
  78. };
  79.  
  80. // The minimum which is necessary for computing a horoscope: jd, lon, lat
  81. class HoroscopeBasicData {
  82. public:
  83.   double jd_et,lon,lat;
  84.   bool initial = true;
  85.   HoroscopeBasicData() {}
  86.   HoroscopeBasicData(double jd_et,double lon, double lat) : jd_et(jd_et),lon(lon),lat(lat) {
  87.     initial = false;
  88.   }
  89.   bool operator == (const HoroscopeBasicData& h) {
  90.     return h.jd_et == jd_et && h.lon == lon && h.lat == lat;
  91.   }
  92.   bool operator != (const HoroscopeBasicData& h) {
  93.     return h.jd_et != jd_et || h.lon != lon || h.lat != lat;
  94.   }
  95. };
  96.  
  97.  
  98. // An astrological object
  99. // abstraction of all computable points of a Horoscope
  100. // (like planets, asteroids, fixed stars, house cusps, midpoints, ...)
  101. class AstroObject {
  102.  
  103. public:
  104.   const string name;
  105.   const string symbol;
  106.   unsigned int aspectStrength = 0x7f; // Default: aspects of all groups
  107.  
  108.   AstroObject(const string& name, const string& symbol) :
  109.      name(name),symbol(symbol) {}    
  110.   AstroObject(const char* name, const char* symbol) : name(name), symbol(symbol) {}
  111.  
  112.   virtual Position compute( const HoroscopeBasicData& data ) const throw(ComputationError) = 0;
  113.   virtual ~AstroObject() {}
  114.  
  115. protected:
  116.   friend ostream& operator<<(ostream&, const AstroObject&);
  117.    
  118. };
  119. ostream& operator<<(ostream &strm, const AstroObject &a) {
  120.   return strm << a.symbol ;
  121. }
  122.  
  123. // I define an ephemeris object by computability via a swe_calc() call
  124. class EphemerisObject : public AstroObject {
  125. public:
  126.   EphemerisObject(const string& name, const string& symbol, const int number):
  127.     AstroObject(name,symbol), ipl(number) {
  128.   }  
  129.   Position compute( const HoroscopeBasicData& data ) const throw(ComputationError) {
  130.     double xx[6];
  131.     char serr[256];
  132.     int iflag = SEFLG_SPEED;
  133.     int rc = swe_calc( data.jd_et, ipl, iflag, xx, serr);
  134.     if (rc < 0) {
  135.       throw ComputationError(string(serr));
  136.     }
  137.     return Position(xx,rc > 0 ? string(serr) : "");
  138.   }
  139. private:
  140.   int ipl;
  141. };
  142.  
  143.  
  144. class Planet : public EphemerisObject {
  145. public:
  146.   Planet(const string& name, const string& symbol, const int number):
  147.     EphemerisObject(name,symbol,number) {
  148.   }    
  149. };
  150.  
  151. // We want to treat a single house cusp like any other AstroObject
  152. // On the other hand, swe_houses gives us all the house cusps at once
  153. // For efficiency, we have a class Houses treating the complete group...
  154. class Houses;
  155.  
  156. // ... and a class House representing a single house cusp
  157. class House : public AstroObject {
  158. public:
  159.   House(const char* name, const char* symbol, const int number, Houses *houses):
  160.     AstroObject(name,symbol), number(number), houses(houses) {
  161.     // Intermediate house cusps: ☌☌ only
  162.     // Angles: ☌☌, □□, △△ (respect symmetry of AC/DC and MC/IC)
  163.     switch (number) {
  164.       case 1:
  165.       case 10:
  166.        aspectStrength = 0b1101;
  167.        break;
  168.       default:
  169.        aspectStrength = 0b1;
  170.     }
  171.   }
  172.   Position compute( const HoroscopeBasicData& data ) const throw(ComputationError);
  173. private:
  174.   int number;  
  175. // Reference to a Houses instance, which computes all the house cusps
  176.   Houses* houses;
  177.  
  178. };
  179.  
  180.  
  181. class Houses {
  182. public:
  183.   struct t_cusp {
  184.     const char * name, *symbol;
  185.   };
  186.   Houses(int hsys = 'P',  // Default: Placidus
  187.       const t_cusp cusps[] = (t_cusp[]) {
  188.       {"ASC","AC"},
  189.       {"Haus 2","H2"},
  190.       {"Haus 3","H3"},
  191.       {"IC","IC"},
  192.       {"Haus 5","H5"},
  193.       {"Haus 6","H6"},
  194.       {"DSC","DC"},
  195.       {"Haus 8","H8"},
  196.       {"Haus 9","H9"},
  197.       {"MC","MC"},
  198.       {"Haus 11","H11"},
  199.       {"Haus 12","H12"},
  200.       {NULL,NULL}
  201.     }) : hsys(hsys) {
  202.     for (int i=0;cusps[i].name != NULL;i++) {
  203.       this->cusps.push_back( new House( cusps[i].name, cusps[i].symbol, i+1, this) );
  204.     }
  205.   }
  206.   vector<const AstroObject*> cusps;
  207.   int hsys;
  208.  
  209.   map<const AstroObject*,Position> compute( const HoroscopeBasicData& data ) throw(ComputationError);
  210.   Position compute( const HoroscopeBasicData& data, const int number ) throw(ComputationError);
  211.  
  212. private:
  213.   HoroscopeBasicData data;
  214.   vector<Position> positions;
  215.  
  216. };
  217.  
  218. // Default values: 12 house cusps, Placidus
  219. Houses* housesDefault = new Houses();
  220.  
  221. // Default: the ten most commonly used astrological planets, plus lunar node
  222. vector<const AstroObject*> planetsDefault = {
  223.   new Planet("Sonne","☉",0),
  224.   new Planet("Mond","☽",1),
  225.   new Planet("Merkur","☿",2),
  226.   new Planet("Venus","♀",3),
  227.   new Planet("Mars","♂",4),
  228.   new Planet("Jupiter","♃",5),
  229.   new Planet("Saturn","♄",6),
  230.   new Planet("Uranus","⛢",7),
  231.   new Planet("Neptun","♆",8),
  232.   new Planet("Pluto","♇",9),
  233.   new Planet("Mondknoten","☊",10)
  234. };
  235.  
  236.  
  237. // Descriptive class, only keeps a vector of AstroObjects, in particular house cusps
  238. // Has a compute() method for getting all the positions in a concrete Horoscope
  239. class HoroscopeParts {
  240. public:
  241.   HoroscopeParts( vector<const AstroObject*>& planets, Houses* houses ) : planets(planets),houses(houses) {}
  242.   map<const AstroObject*,Position> compute( const HoroscopeBasicData& data ) const {
  243.     map<const AstroObject*,Position> result;
  244.     for (const AstroObject* p : planets ) {
  245.       result[p] = p->compute( data );
  246.     }
  247.     map<const AstroObject*,Position> hpos = houses->compute( data );
  248.     result.insert( hpos.begin(), hpos.end() );
  249.     return result;
  250.   }
  251. private:
  252.   vector<const AstroObject*> planets;
  253.   Houses* houses;
  254. };
  255.  
  256. HoroscopeParts horoscopePartsDefault( planetsDefault, housesDefault);
  257.  
  258. // Implements the swe_houses() call
  259. map<const AstroObject*,Position> Houses::compute(const HoroscopeBasicData& data) throw (ComputationError) {
  260.   map<const AstroObject*,Position> result;
  261.   this->data = data;
  262.   positions.clear();
  263.   double houses[13], ascmc[10];
  264.   swe_houses( data.jd_et - swe_deltat( data.jd_et), data.lat, data.lon, hsys, houses, ascmc);
  265.   for (int i=0;i<12;i++) {
  266.     Position p = Position( houses[i+1] );
  267.     result[ cusps[i] ] = p;
  268.     positions.push_back( p );
  269.   }
  270.   return result;
  271. }
  272.  
  273. // Give back a single house cusp position
  274. Position Houses::compute( const HoroscopeBasicData& data, const int number ) throw(ComputationError) {
  275.     if (this->data.initial ||
  276.         data.jd_et != this->data.jd_et ||
  277.         data.lon   != this->data.lon   ||
  278.         data.lat   != this->data.lat ) {
  279.       compute( data );
  280.     }
  281.     return positions[number-1];
  282. }
  283.  
  284. // The same, viewed from inside of AstroObject
  285. Position House::compute( const HoroscopeBasicData& data ) const throw(ComputationError) {
  286.   return houses->compute(data,number);
  287. }
  288.  
  289. // Descriptive class, objects representing single aspects
  290. class Aspect {
  291. public:
  292.   Aspect(
  293.     const char* name,
  294.     const char* symbol,
  295.     int strength,
  296.     double angle) : name(name), symbol(symbol), strength(strength), angle(angle) {}
  297.   string name;
  298.   string symbol;
  299.   unsigned int strength;
  300.   double angle;
  301.   ostream& toStream( ostream& str ) const {
  302.     str << symbol;
  303.     return str;
  304.   }
  305. };
  306.  
  307. ostream & operator<<(ostream & str, Aspect const & a) {
  308.   return a.toStream(str);
  309. }
  310.  
  311. // The aspects in use, and their groups
  312. vector<Aspect> aspects = {
  313.   { "Konjunktion",        "☌",  0x01, 0  },
  314.   { "Halbsextil",         "⚺",  0x40, 30 },
  315.   { "Halbquadrat",        "∠",  0x20, 45 },
  316.   { "Sextil",             "⚹",  0x10, 60 },
  317.   { "Quadrat",            "□",  0x04, 90 },
  318.   { "Trigon",             "△",  0x08, 120 },
  319.   { "Anderthalbquadrat",  "⚼",  0x20, 135},
  320.   { "Quincunx",           "⚻",  0x40, 150},
  321.   { "Opposition",         "☍",  0x02, 180}
  322. };
  323.  
  324. enum Direction {
  325.   LEFT,
  326.   RIGHT
  327. };
  328.  
  329. // Descriptive structure for an aspect to a planet (to an AstroObject)
  330. class AspectPoint {
  331. public:
  332.   const Aspect* aspect;       // Aspect...
  333.   const AstroObject* object;  // ...to this AstroObject
  334.   const Direction direction;  // ...RIGHT = in forward, LEFT = in backward zodiac direction
  335.   const int bound;            // Usually zero, but +1 or -1 for aspect boundaries
  336.  
  337. };
  338.  
  339. ostream & operator<<(ostream & str, AspectPoint const & ap) {
  340.   str << *(ap.aspect) << *(ap.object);
  341.   return str;
  342. }
  343.  
  344.  
  345. // Compputes an aspect wreath from a map of AstroObjects with positions
  346. class Aspectarium {
  347. public:
  348.   multimap<double,AspectPoint> wreath;
  349.   Aspectarium(const map<const AstroObject*,Position> p, const unsigned int filter = 0xff, const vector<Aspect>& aspects = aspects) {
  350.     for (auto o : p) {      
  351.       for (const Aspect& a: aspects) {
  352.         if (!(a.strength & filter )) continue;
  353.         if (!(o.first->aspectStrength & a.strength)) continue;
  354.         addAspect(o.first,o.second.lon,RIGHT,a);
  355.         if (a.symbol != "☌" && a.symbol != "☍") {
  356.           addAspect(o.first,o.second.lon,LEFT,a);
  357.         }        
  358.       }
  359.     }
  360.   }
  361.  
  362.   multimap<double,AspectPoint> wreath_enriched_with_boundaries() const {
  363.     multimap<double,AspectPoint> result = wreath;
  364.     for (auto it : wreath) {
  365.       result.insert( pair<double,AspectPoint>(
  366.         fmod360(it.first-1),
  367.         AspectPoint({ it.second.aspect,it.second.object,it.second.direction,-1 })
  368.       ));
  369.       result.insert( pair<double,AspectPoint>(
  370.         fmod360(it.first+1),
  371.         AspectPoint({ it.second.aspect,it.second.object,it.second.direction,+1 })
  372.       ));
  373.     }
  374.   return result;
  375.   }
  376.  
  377.   ostream& toStream( ostream& str) const {
  378.     for (auto a: wreath) {
  379.       AspectPoint ap = a.second;
  380.       str << setw(12) << setprecision(4) << fixed << a.first << " : " << ap << endl;
  381.     }
  382.     return str;
  383.   }
  384. private:
  385.   void addAspect(const AstroObject* o, const double pos, const Direction direction, const Aspect& a) {
  386.     double l = fmod360( pos + a.angle * (direction == RIGHT ? 1 : -1) );
  387.     AspectPoint ap({ &a, o, direction, 0 });
  388.     wreath.insert( pair<double,AspectPoint>(l,ap));
  389.   }  
  390.  
  391. };
  392.  
  393. ostream & operator<<(ostream & str, Aspectarium const & a) {
  394.   a.toStream(str);
  395.   return str;
  396. }
  397.  
  398.  
  399. // Class Horoscope, basically wraps a map of AstroObjects together with their positions
  400. class Horoscope : public HoroscopeBasicData {
  401. public:
  402.   Horoscope(double jd_et,double lon, double lat,const HoroscopeParts& hp = horoscopePartsDefault) : HoroscopeBasicData(jd_et,lon,lat) {
  403.     p = hp.compute((HoroscopeBasicData)*this);
  404.   }
  405.  
  406.   Aspectarium getAspectarium( unsigned int aspect_filter = 0xff) {
  407.     return Aspectarium( p, aspect_filter );
  408.   }
  409.  
  410.   void toStream(ostream &str) const {
  411.     for (auto const& pos: p) {
  412.       str << setw(20) << *(pos.first) << ": " << pos.second << endl;
  413.     }
  414.   }  
  415.  
  416. private:
  417.   map<const AstroObject*,Position> p;
  418.  
  419. };
  420.  
  421. ostream & operator<<(ostream & Str, Horoscope const & h) {
  422.   h.toStream(Str);
  423.   return Str;
  424. }
  425.  
  426. // Position with time
  427. typedef struct {
  428.   double jd_et;
  429.   Position pos;
  430. } t_position;
  431.  
  432. // Any interval
  433. typedef struct {
  434.   double from, to;
  435. } t_interval;
  436.  
  437. // Compute the time of a transit
  438. double transit_time(
  439.   double lon,
  440.   const t_position last,
  441.   const t_position next) {
  442.  
  443.   double jd_et;
  444.  
  445.   if (next.pos.lon == last.pos.lon) return (last.pos.lon == lon) ? last.jd_et : NAN;
  446.  
  447. // To keep it simple, we use linear interpolation
  448. // Could improve by cubic interpolation, employing also last.pos.vlon and next.pos.vlon
  449.   jd_et =
  450.     (next.jd_et-last.jd_et)*arcdiff(lon,last.pos.lon)/arcdiff(next.pos.lon,last.pos.lon)
  451.     + last.jd_et;
  452.  
  453.   return jd_et;
  454.  
  455. }
  456.  
  457. // An object of class Transit represents a single transit
  458. // a current AstroObject is crossing an aspect to a given AstroObject (from the base horoscope)
  459. class Transit {  
  460. public:
  461.   double jd_et,lon;
  462.   const AstroObject* current;
  463.   AspectPoint aspect;
  464.   Direction direction;
  465.   double jd_begin, jd_end;
  466.  
  467.  
  468.   // Current planet is entering the orbis
  469.   // - either it is moving directly, and the bound is -1
  470.   // - or it is moving retrogradely, and the bound is +1
  471.   bool entering() const {
  472.     return (
  473.       (aspect.bound == -1 && direction == RIGHT) ||
  474.       (aspect.bound == +1  && direction == LEFT)
  475.     );    
  476.   }
  477.  
  478.   // Current planet is leaving the orbis
  479.   // - either it is moving directly, and the bound is +1
  480.   // - or it is moving retrogradely, and the bound is -1
  481.   bool leaving() const {
  482.     return (
  483.       (aspect.bound == -1 && direction == LEFT) ||
  484.       (aspect.bound == +1  && direction == RIGHT)
  485.     );    
  486.   }
  487.  
  488.   // Consider two transit objects as equal if the aspect formulae are identical
  489.   // here, we do distinguish right from left aspects
  490.   bool operator==(const Transit& t) const {
  491.     return (
  492.      current       == t.current &&
  493.      aspect.aspect == t.aspect.aspect &&
  494.      aspect.object == t.aspect.object &&
  495.      aspect.direction == t.aspect.direction );
  496.   }
  497. };
  498.  
  499. // Output a transit list as JSON object
  500. void print(ostream & Str, const multimap<double,Transit>& t) {
  501.   bool first = true;
  502.   Str << "[" << endl;
  503.   for ( auto it : t ) {
  504.     if (!first) {
  505.       Str << "," << endl;
  506.     }
  507.     Str << "["
  508.          << setw(14) << setprecision(5) << fixed << it.first << ", "
  509.          << setw(14) << setprecision(5) << fixed << it.second.jd_begin << ", "
  510.          << setw(14) << setprecision(5) << fixed << it.second.jd_end << ", "
  511.          << setw(8) << setprecision(4) << it.second.lon << ", "
  512.          << "\"" << *(it.second.current)
  513.          << (it.second.direction == LEFT ? "℞" :"")
  514.          << (it.second.aspect.bound == -1 ? "LB " :"")
  515.          << (it.second.aspect.bound == 1 ? "RB " :"")
  516.          << it.second.aspect << "\"]";
  517.     first = false;
  518.   }
  519.   Str << endl << "]";
  520. }
  521.  
  522. // Output an aspect wreath as a list (plain text, not JSON)
  523. void print(ostream & Str, const multimap<double,AspectPoint>& w) {
  524.   for (auto it: w) {
  525.     Str << setw(14) << setprecision(5) << fixed << it.first << ": ";
  526.     Str << it.second << endl;
  527.   }
  528. }
  529.  
  530. // Find all the aspects from the wreath falling into the given interval,
  531. // and compute the exact transit time for each of them
  532. multimap<double,Transit> transits_from_interval(
  533.   const t_interval& interval,
  534.   const AstroObject* o,
  535.   const t_position last,
  536.   const t_position next,
  537.   const multimap<double,AspectPoint>& wreath) {
  538.  
  539.   multimap<double,Transit> r;
  540.   for (auto it = wreath.lower_bound( interval.from );
  541.        it != wreath.end() && it->first < interval.to;
  542.        ++it ) {
  543.     double jd_et = transit_time(it->first,last,next);
  544.     r.insert( pair<double,Transit>(
  545.       jd_et,
  546.       Transit({
  547.         jd_et,
  548.         it->first,
  549.         o,
  550.         it->second,
  551.         (arcdiff(next.pos.lon,last.pos.lon)<0) ? LEFT: RIGHT })
  552.     ));
  553.   }
  554.   return r;
  555. }
  556.  
  557. // Decompose an interval on the circle into parts on [0...360]
  558. // Take account of the discontinuity 360->0
  559. // Take account of retrograde motion (input.from may well be > input.to)
  560. vector<t_interval> get_segments(const t_interval& input) {
  561.   if (arcdiff(input.to,input.from)>0) {
  562.     if (input.to > input.from) {
  563.       return vector<t_interval>({input});
  564.     } else {
  565.       return vector<t_interval>({
  566.         { input.from, 360.},
  567.         { 0., input.to }
  568.       });
  569.     }
  570.   } else {
  571.     if (input.to < input.from) {
  572.       return vector<t_interval>({{input.to,input.from}});
  573.     } else {
  574.       return vector<t_interval>({
  575.         { input.to, 360.},
  576.         { 0., input.from}
  577.       });
  578.     }    
  579.   }
  580. }
  581.  
  582. // Compute all transits in the given interval,
  583. // including the times when the aspect is entered and left by the current AstroObject
  584. multimap<double,Transit> transits(double from, double to, const Aspectarium& a, vector<const AstroObject*>& planets = planetsDefault) {
  585.  
  586. // Enrich the aspect wreath with aspect boundaries (i.e. aspect locus +1° / -1°)
  587.   multimap<double,AspectPoint> wreath = a.wreath_enriched_with_boundaries( );
  588.  
  589. // For each planet:
  590. // Compute the times where it passes the aspects of the 'enriched wreath'
  591.   multimap<double,Transit> r;
  592.   for (const AstroObject* o : planets) {
  593.     Position last = o->compute( HoroscopeBasicData(from,0,0) );
  594.     for (double t = from+1; t<=to; t+=1) {
  595.       Position next = o->compute( HoroscopeBasicData(t,0,0) );
  596.       vector<t_interval> v = get_segments({ last.lon, next.lon });
  597.       for (t_interval iv: v) {
  598.         multimap<double,Transit> s = transits_from_interval(
  599.           iv,
  600.           o,
  601.           (t_position) { t-1, last },
  602.           (t_position) { t, next },
  603.           wreath
  604.         );
  605.         r.insert(s.begin(),s.end());
  606.       }
  607.       last = next;
  608.     }
  609.   }
  610.  
  611. // For each transit: adjoin the time when it enters and leaves the orbis
  612.   multimap<double,Transit> result;
  613.   for (auto it = r.begin(); it != r.end(); ++it) {
  614.     if (it->second.aspect.bound == 0) {
  615.  
  616. // Scan backwards in longitude, when did the planet enter the aspect orb
  617.       it->second.jd_begin = from;
  618.       for (auto it1 = it; it1 != r.begin();--it1) {
  619.         if (it1->second == it->second &&
  620.             it1->second.entering()) {
  621.           it->second.jd_begin = it1->first;
  622.           break;
  623.         }
  624.       }
  625.  
  626. // Scan forward in longitude, when did the planet leave the aspect orb
  627.       it->second.jd_end = to;
  628.       for (auto it2 = next(it); it2 != r.end();++it2) {
  629.         if (it2->second == it->second &&
  630.             it2->second.leaving() ) {
  631.           it->second.jd_end = it2->first;
  632.           break;
  633.         }
  634.       }
  635.  
  636.       result.insert(*it);
  637.     }
  638.   }  
  639.   return result;
  640. }
  641.  
  642.  
  643.  
  644. void teardown() {
  645.  
  646.   for (auto p: planetsDefault) {
  647.     delete p;
  648.   }
  649.  
  650. }
  651.  
  652. void parse_query_string( const char* qs, t_input& input ) {
  653.    
  654.     const regex NAME_VALUE_PATTERN("([\\w+%]+)=([^&]*)");
  655.     const string query(qs);
  656.     auto words_begin = sregex_iterator(query.begin(), query.end(), NAME_VALUE_PATTERN);
  657.     auto words_end = sregex_iterator();
  658.  
  659.     for (auto it = words_begin; it != words_end; it++) {
  660.       const string name((*it)[1]);
  661.       const char* value = (*it)[2].str().c_str();
  662.       if (name == "jd_et") {
  663.          sscanf(value,"%lf",&(input.jd_et));
  664.       }
  665.       else if (name == "lon") {
  666.          sscanf(value,"%lf",&(input.lon));
  667.       }
  668.       else if (name == "lat") {
  669.          sscanf(value,"%lf",&(input.lat));
  670.       }
  671.       else if (name == "from") {
  672.          sscanf(value,"%lf",&(input.from));
  673.       }
  674.       else if (name == "to") {
  675.          sscanf(value,"%lf",&(input.to));
  676.       }
  677.       else if (name == "filter") {
  678.          sscanf(value,"%d",&(input.filter));
  679.       }
  680.     }      
  681.  
  682. }
  683.  
  684. int main( int argc, char** argv) {
  685.  
  686.   // Some defaults
  687.   t_input input = { 2451545.,7.,52.,2452500.,2452501.,0b11111 };
  688.  
  689.   if (argc>=2) {
  690.     // For tests
  691.     parse_query_string(argv[1],input);
  692.   } else {
  693.     // In CGI mode
  694.     const char* query_string = getenv("QUERY_STRING");
  695.     if (query_string) {
  696.       parse_query_string(query_string,input);
  697.     }
  698.   }
  699.  
  700.   cout << "HTTP/1.1 200 OK\nContent-Type:application/json;charset=utf-8\n\n";
  701.  
  702.   Horoscope h(input.jd_et,input.lon,input.lat);
  703.  
  704. // Default filter: 0b11111 = Down to and including ⚹
  705.   Aspectarium a = h.getAspectarium( input.filter );
  706.   multimap<double,Transit> t = transits(input.from,input.to,a);
  707.  
  708. // Output
  709.   cout << "{ \"data\":" ;
  710.   print(cout,t);
  711.   cout << "}" << endl;
  712.  
  713. // Teardown - becomes relevant when code is shifted into shared library
  714.   teardown( );
  715.  
  716.   return 0;
  717.  
  718. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement