public Int32 swe_nod_aps(double tjd_et, Int32 ipl, Int32 iflag, Int32 method, double[] xnasc, double[] xndsc, double[] xperi, double[] xaphe, ref string serr) { int ij, i, j; Int32 iplx; Int32 ipli; int istart, iend; Int32 iflJ2000; double plm; double t = (tjd_et - Sweph.J2000) / 36525, dt; double[] x = new double[6], xx = new double[24], xobs = new double[6], x2000 = new double[6]; double[][] xpos = CreateArray<double>(3, 6); double[] xnorm = new double[6]; double[] xposm = new double[6]; double[][] xn = CreateArray<double>(3, 6), xs = CreateArray<double>(3, 6); double[][] xq = CreateArray<double>(3, 6), xa = CreateArray<double>(3, 6); double[] xobs2 = new double[6], x2 = new double[6]; CPointer<double> xna, xnd, xpe, xap, xp; double incl, sema, ecce, parg, ea, vincl, vsema, vecce, pargx, eax; Sweph.plan_data pedp = SE.Sweph.swed.pldat[Sweph.SEI_EARTH]; Sweph.plan_data psbdp = SE.Sweph.swed.pldat[Sweph.SEI_SUNBARY]; Sweph.plan_data pldat = new Sweph.plan_data(); CPointer<double> xsun = psbdp.x; CPointer<double> xear = pedp.x; CPointer<double> ep; double Gmsm, dzmin; double rxy, rxyz, fac, sgn; double sinnode, cosnode, sinincl, cosincl, sinu, cosu, sinE, cosE, cosE2; double uu, ny, ny2, c2, v2, pp, ro, ro2, rn, rn2; Sweph.epsilon oe; bool is_true_nodaps = false; bool do_aberr = 0 == (iflag & (SwissEph.SEFLG_TRUEPOS | SwissEph.SEFLG_NOABERR)); bool do_defl = 0 == (iflag & SwissEph.SEFLG_TRUEPOS) && 0 == (iflag & SwissEph.SEFLG_NOGDEFL); bool do_focal_point = (method & SwissEph.SE_NODBIT_FOPOINT) != 0; bool ellipse_is_bary = false; Int32 iflg0; iflag &= ~(SwissEph.SEFLG_JPLHOR | SwissEph.SEFLG_JPLHOR_APPROX); /* function calls for Pluto with asteroid number 134340 * are treated as calls for Pluto as main body SE_PLUTO */ if (ipl == SwissEph.SE_AST_OFFSET + 134340) ipl = SwissEph.SE_PLUTO; xna = xx; xnd = xx.GetPointer(6); xpe = xx.GetPointer(12); xap = xx.GetPointer(18); xpos[0][0] = 0; /* to shut up mint */ /* to get control over the save area: */ SE.Sweph.swi_force_app_pos_etc(); method %= SwissEph.SE_NODBIT_FOPOINT; ipli = ipl; if (ipl == SwissEph.SE_SUN) ipli = SwissEph.SE_EARTH; if (ipl == SwissEph.SE_MOON) { do_defl = false; if (0 == (iflag & SwissEph.SEFLG_HELCTR)) do_aberr = false; } iflg0 = (iflag & (SEFLG_EPHMASK | SwissEph.SEFLG_NONUT)) | SwissEph.SEFLG_SPEED | SwissEph.SEFLG_TRUEPOS; if (ipli != SwissEph.SE_MOON) iflg0 |= SwissEph.SEFLG_HELCTR; if (ipl == SwissEph.SE_MEAN_NODE || ipl == SwissEph.SE_TRUE_NODE || ipl == SwissEph.SE_MEAN_APOG || ipl == SwissEph.SE_OSCU_APOG || ipl < 0 || (ipl >= SwissEph.SE_NPLANETS && ipl <= SwissEph.SE_AST_OFFSET)) { /*(ipl >= SE_FICT_OFFSET && ipl - SE_FICT_OFFSET < SE_NFICT_ELEM)) */ serr = C.sprintf("nodes/apsides for planet %5.0f are not implemented", (double)ipl); if (xnasc != null) for (i = 0; i <= 5; i++) xnasc[i] = 0; if (xndsc != null) for (i = 0; i <= 5; i++) xndsc[i] = 0; if (xaphe != null) for (i = 0; i <= 5; i++) xaphe[i] = 0; if (xperi != null) for (i = 0; i <= 5; i++) xperi[i] = 0; return SwissEph.ERR; } for (i = 0; i < 24; i++) xx[i] = 0; /*************************************** * mean nodes and apsides ***************************************/ /* mean points only for Sun - Neptune */ if ((method == 0 || (method & SwissEph.SE_NODBIT_MEAN) != 0) && ((ipl >= SwissEph.SE_SUN && ipl <= SwissEph.SE_NEPTUNE) || ipl == SwissEph.SE_EARTH)) { if (ipl == SwissEph.SE_MOON) { double[] xdummy = new double[] { xna[0], xna[3], xpe[0], xpe[3] }; SE.SwemMoon.swi_mean_lunar_elements(tjd_et, ref xdummy[0], ref xdummy[1], ref xdummy[2], ref xdummy[3]); xna[0] = xdummy[0]; xna[3] = xdummy[1]; xpe[0] = xdummy[2]; xpe[3] = xdummy[3]; incl = Sweph.MOON_MEAN_INCL; vincl = 0; ecce = Sweph.MOON_MEAN_ECC; vecce = 0; sema = Sweph.MOON_MEAN_DIST / Sweph.AUNIT; vsema = 0; } else { iplx = ipl_to_elem[ipl]; ep = el_incl[iplx]; incl = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t; vincl = ep[1] / 36525; ep = el_sema[iplx]; sema = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t; vsema = ep[1] / 36525; ep = el_ecce[iplx]; ecce = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t; vecce = ep[1] / 36525; ep = el_node[iplx]; /* ascending node */ xna[0] = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t; xna[3] = ep[1] / 36525; /* perihelion */ ep = el_peri[iplx]; xpe[0] = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t; xpe[3] = ep[1] / 36525; } /* descending node */ xnd[0] = SE.swe_degnorm(xna[0] + 180); xnd[3] = xna[3]; /* angular distance of perihelion from node */ parg = xpe[0] = SE.swe_degnorm(xpe[0] - xna[0]); pargx = xpe[3] = SE.swe_degnorm(xpe[0] + xpe[3] - xna[3]); /* transform from orbital plane to mean ecliptic of date */ SE.swe_cotrans(xpe, xpe, -incl); /* xpe+3 is aux. position, not speed!!! */ SE.swe_cotrans(xpe + 3, xpe + 3, -incl - vincl); /* add node again */ xpe[0] = SE.swe_degnorm(xpe[0] + xna[0]); /* xpe+3 is aux. position, not speed!!! */ xpe[3] = SE.swe_degnorm(xpe[3] + xna[0] + xna[3]); /* speed */ xpe[3] = SE.swe_degnorm(xpe[3] - xpe[0]); /* heliocentric distance of perihelion and aphelion */ xpe[2] = sema * (1 - ecce); xpe[5] = (sema + vsema) * (1 - ecce - vecce) - xpe[2]; /* aphelion */ xap[0] = SE.swe_degnorm(xpe[0] + 180); xap[1] = -xpe[1]; xap[3] = xpe[3]; xap[4] = -xpe[4]; if (do_focal_point) { xap[2] = sema * ecce * 2; xap[5] = (sema + vsema) * (ecce + vecce) * 2 - xap[2]; } else { xap[2] = sema * (1 + ecce); xap[5] = (sema + vsema) * (1 + ecce + vecce) - xap[2]; } /* heliocentric distance of nodes */ ea = Math.Atan(Math.Tan(-parg * SwissEph.DEGTORAD / 2) * Math.Sqrt((1 - ecce) / (1 + ecce))) * 2; eax = Math.Atan(Math.Tan(-pargx * SwissEph.DEGTORAD / 2) * Math.Sqrt((1 - ecce - vecce) / (1 + ecce + vecce))) * 2; xna[2] = sema * (Math.Cos(ea) - ecce) / Math.Cos(parg * SwissEph.DEGTORAD); xna[5] = (sema + vsema) * (Math.Cos(eax) - ecce - vecce) / Math.Cos(pargx * SwissEph.DEGTORAD); xna[5] -= xna[2]; ea = Math.Atan(Math.Tan((180 - parg) * SwissEph.DEGTORAD / 2) * Math.Sqrt((1 - ecce) / (1 + ecce))) * 2; eax = Math.Atan(Math.Tan((180 - pargx) * SwissEph.DEGTORAD / 2) * Math.Sqrt((1 - ecce - vecce) / (1 + ecce + vecce))) * 2; xnd[2] = sema * (Math.Cos(ea) - ecce) / Math.Cos((180 - parg) * SwissEph.DEGTORAD); xnd[5] = (sema + vsema) * (Math.Cos(eax) - ecce - vecce) / Math.Cos((180 - pargx) * SwissEph.DEGTORAD); xnd[5] -= xnd[2]; /* no light-time correction because speed is extremely small */ for (i = 0, xp = xx; i < 4; i++, xp += 6) { /* to cartesian coordinates */ xp[0] *= SwissEph.DEGTORAD; xp[1] *= SwissEph.DEGTORAD; xp[3] *= SwissEph.DEGTORAD; xp[4] *= SwissEph.DEGTORAD; SE.SwephLib.swi_polcart_sp(xp, xp); } /*************************************** * "true" or osculating nodes and apsides ***************************************/ } else { /* first, we need a heliocentric distance of the planet */ if (SE.swe_calc(tjd_et, ipli, iflg0, x, ref serr) == SwissEph.ERR) return SwissEph.ERR; iflJ2000 = (iflag & SEFLG_EPHMASK) | SwissEph.SEFLG_J2000 | SwissEph.SEFLG_EQUATORIAL | SwissEph.SEFLG_XYZ | SwissEph.SEFLG_TRUEPOS | SwissEph.SEFLG_NONUT | SwissEph.SEFLG_SPEED; ellipse_is_bary = false; if (ipli != SwissEph.SE_MOON) { if ((method & SwissEph.SE_NODBIT_OSCU_BAR) != 0 && x[2] > 6) { iflJ2000 |= SwissEph.SEFLG_BARYCTR; /* only planets beyond Jupiter */ ellipse_is_bary = true; } else { iflJ2000 |= SwissEph.SEFLG_HELCTR; } } /* we need three positions and three speeds * for three nodes/apsides. from the three node positions, * the speed of the node will be computed. */ if (ipli == SwissEph.SE_MOON) { dt = Sweph.NODE_CALC_INTV; dzmin = 1e-15; Gmsm = Sweph.GEOGCONST * (1 + 1 / Sweph.EARTH_MOON_MRAT) / Sweph.AUNIT / Sweph.AUNIT / Sweph.AUNIT * 86400.0 * 86400.0; } else { if ((ipli >= SwissEph.SE_MERCURY && ipli <= SwissEph.SE_PLUTO) || ipli == SwissEph.SE_EARTH) plm = 1 / plmass[ipl_to_elem[ipl]]; else plm = 0; dt = Sweph.NODE_CALC_INTV * 10 * x[2]; dzmin = 1e-15 * dt / Sweph.NODE_CALC_INTV; Gmsm = Sweph.HELGRAVCONST * (1 + plm) / Sweph.AUNIT / Sweph.AUNIT / Sweph.AUNIT * 86400.0 * 86400.0; } if ((iflag & SwissEph.SEFLG_SPEED) != 0) { istart = 0; iend = 2; } else { istart = iend = 0; dt = 0; } for (i = istart, t = tjd_et - dt; i <= iend; i++, t += dt) { if (istart == iend) t = tjd_et; if (SE.swe_calc(t, ipli, iflJ2000, xpos[i], ref serr) == SwissEph.ERR) return SwissEph.ERR; /* the EMB is used instead of the earth */ if (ipli == SwissEph.SE_EARTH) { if (SE.swe_calc(t, SwissEph.SE_MOON, iflJ2000 & ~(SwissEph.SEFLG_BARYCTR | SwissEph.SEFLG_HELCTR), xposm, ref serr) == SwissEph.ERR) return SwissEph.ERR; for (j = 0; j <= 2; j++) xpos[i][j] += xposm[j] / (Sweph.EARTH_MOON_MRAT + 1.0); } SE.Sweph.swi_plan_for_osc_elem(iflg0, t, xpos[i]); } for (i = istart; i <= iend; i++) { if (Math.Abs(xpos[i][5]) < dzmin) xpos[i][5] = dzmin; fac = xpos[i][2] / xpos[i][5]; sgn = xpos[i][5] / Math.Abs(xpos[i][5]); for (j = 0; j <= 2; j++) { xn[i][j] = (xpos[i][j] - fac * xpos[i][j + 3]) * sgn; xs[i][j] = -xn[i][j]; } } for (i = istart; i <= iend; i++) { /* node */ rxy = Math.Sqrt(xn[i][0] * xn[i][0] + xn[i][1] * xn[i][1]); cosnode = xn[i][0] / rxy; sinnode = xn[i][1] / rxy; /* inclination */ SE.SwephLib.swi_cross_prod(xpos[i], xpos[i].GetPointer(3), xnorm); rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1]; c2 = (rxy + xnorm[2] * xnorm[2]); rxyz = Math.Sqrt(c2); rxy = Math.Sqrt(rxy); sinincl = rxy / rxyz; cosincl = Math.Sqrt(1 - sinincl * sinincl); if (xnorm[2] < 0) cosincl = -cosincl; /* retrograde asteroid, e.g. 20461 Dioretsa */ /* argument of latitude */ cosu = xpos[i][0] * cosnode + xpos[i][1] * sinnode; sinu = xpos[i][2] / sinincl; uu = Math.Atan2(sinu, cosu); /* semi-axis */ rxyz = Math.Sqrt(SE.Sweph.square_sum(xpos[i])); v2 = SE.Sweph.square_sum((xpos[i].GetPointer(3))); sema = 1 / (2 / rxyz - v2 / Gmsm); /* eccentricity */ pp = c2 / Gmsm; ecce = Math.Sqrt(1 - pp / sema); /* eccentric anomaly */ cosE = 1 / ecce * (1 - rxyz / sema); sinE = 1 / ecce / Math.Sqrt(sema * Gmsm) * SE.Sweph.dot_prod(xpos[i], (xpos[i].GetPointer(3))); /* true anomaly */ ny = 2 * Math.Atan(Math.Sqrt((1 + ecce) / (1 - ecce)) * sinE / (1 + cosE)); /* distance of perihelion from ascending node */ xq[i][0] = SE.SwephLib.swi_mod2PI(uu - ny); xq[i][1] = 0; /* latitude */ xq[i][2] = sema * (1 - ecce); /* distance of perihelion */ /* transformation to ecliptic coordinates */ SE.SwephLib.swi_polcart(xq[i], xq[i]); SE.SwephLib.swi_coortrf2(xq[i], xq[i], -sinincl, cosincl); SE.SwephLib.swi_cartpol(xq[i], xq[i]); /* adding node, we get perihelion in ecl. coord. */ xq[i][0] += Math.Atan2(sinnode, cosnode); xa[i][0] = SE.SwephLib.swi_mod2PI(xq[i][0] + Math.PI); xa[i][1] = -xq[i][1]; if (do_focal_point) { xa[i][2] = sema * ecce * 2; /* distance of aphelion */ } else { xa[i][2] = sema * (1 + ecce); /* distance of aphelion */ } SE.SwephLib.swi_polcart(xq[i], xq[i]); SE.SwephLib.swi_polcart(xa[i], xa[i]); /* new distance of node from orbital ellipse: * true anomaly of node: */ ny = SE.SwephLib.swi_mod2PI(ny - uu); ny2 = SE.SwephLib.swi_mod2PI(ny + Math.PI); /* eccentric anomaly */ cosE = Math.Cos(2 * Math.Atan(Math.Tan(ny / 2) / Math.Sqrt((1 + ecce) / (1 - ecce)))); cosE2 = Math.Cos(2 * Math.Atan(Math.Tan(ny2 / 2) / Math.Sqrt((1 + ecce) / (1 - ecce)))); /* new distance */ rn = sema * (1 - ecce * cosE); rn2 = sema * (1 - ecce * cosE2); /* old node distance */ ro = Math.Sqrt(SE.Sweph.square_sum(xn[i])); ro2 = Math.Sqrt(SE.Sweph.square_sum(xs[i])); /* correct length of position vector */ for (j = 0; j <= 2; j++) { xn[i][j] *= rn / ro; xs[i][j] *= rn2 / ro2; } } for (i = 0; i <= 2; i++) { if ((iflag & SwissEph.SEFLG_SPEED) != 0) { xpe[i] = xq[1][i]; xpe[i + 3] = (xq[2][i] - xq[0][i]) / dt / 2; xap[i] = xa[1][i]; xap[i + 3] = (xa[2][i] - xa[0][i]) / dt / 2; xna[i] = xn[1][i]; xna[i + 3] = (xn[2][i] - xn[0][i]) / dt / 2; xnd[i] = xs[1][i]; xnd[i + 3] = (xs[2][i] - xs[0][i]) / dt / 2; } else { xpe[i] = xq[0][i]; xpe[i + 3] = 0; xap[i] = xa[0][i]; xap[i + 3] = 0; xna[i] = xn[0][i]; xna[i + 3] = 0; xnd[i] = xs[0][i]; xnd[i + 3] = 0; } } is_true_nodaps = true; } /* to set the variables required in the save area, * i.e. ecliptic, nutation, barycentric sun, earth * we compute the planet */ if (ipli == SwissEph.SE_MOON && (iflag & (SwissEph.SEFLG_HELCTR | SwissEph.SEFLG_BARYCTR)) != 0) { SE.Sweph.swi_force_app_pos_etc(); if (SE.swe_calc(tjd_et, SwissEph.SE_SUN, iflg0, x, ref serr) == SwissEph.ERR) return SwissEph.ERR; } else { if (SE.swe_calc(tjd_et, ipli, iflg0 | (iflag & SwissEph.SEFLG_TOPOCTR), x, ref serr) == SwissEph.ERR) return SwissEph.ERR; } /*********************** * position of observer ***********************/ if ((iflag & SwissEph.SEFLG_TOPOCTR) != 0) { /* geocentric position of observer */ if (SE.Sweph.swi_get_observer(tjd_et, iflag, false, xobs, ref serr) != SwissEph.OK) return SwissEph.ERR; /*for (i = 0; i <= 5; i++) xobs[i] = swed.topd.xobs[i];*/ } else { for (i = 0; i <= 5; i++) xobs[i] = 0; } if ((iflag & (SwissEph.SEFLG_HELCTR | SwissEph.SEFLG_BARYCTR)) != Sweph.B1950) { if ((iflag & SwissEph.SEFLG_HELCTR) != 0 && 0 == (iflag & SwissEph.SEFLG_MOSEPH)) for (i = 0; i <= 5; i++) xobs[i] = xsun[i]; } else if (ipl == SwissEph.SE_SUN && 0 == (iflag & SwissEph.SEFLG_MOSEPH)) { for (i = 0; i <= 5; i++) xobs[i] = xsun[i]; } else { /* barycentric position of observer */ for (i = 0; i <= 5; i++) xobs[i] += xear[i]; } /* ecliptic obliqity */ if ((iflag & SwissEph.SEFLG_J2000) != 0) oe = SE.Sweph.swed.oec2000; else oe = SE.Sweph.swed.oec; /************************************************* * conversions shared by mean and osculating points *************************************************/ for (ij = 0, xp = xx; ij < 4; ij++, xp += 6) { /* no nodes for earth */ if (ipli == SwissEph.SE_EARTH && ij <= 1) { for (i = 0; i <= 5; i++) xp[i] = 0; continue; } /********************* * to equator *********************/ if (is_true_nodaps && 0 == (iflag & SwissEph.SEFLG_NONUT)) { SE.SwephLib.swi_coortrf2(xp, xp, -SE.Sweph.swed.nut.snut, SE.Sweph.swed.nut.cnut); if ((iflag & SwissEph.SEFLG_SPEED) != 0) SE.SwephLib.swi_coortrf2(xp + 3, xp + 3, -SE.Sweph.swed.nut.snut, SE.Sweph.swed.nut.cnut); } SE.SwephLib.swi_coortrf2(xp, xp, -oe.seps, oe.ceps); SE.SwephLib.swi_coortrf2(xp + 3, xp + 3, -oe.seps, oe.ceps); if (is_true_nodaps) { /**************************** * to mean ecliptic of date ****************************/ if (0 == (iflag & SwissEph.SEFLG_NONUT)) SE.Sweph.swi_nutate(xp, iflag, true); } /********************* * to J2000 *********************/ SE.SwephLib.swi_precess(xp, tjd_et, iflag, Sweph.J_TO_J2000); if ((iflag & SwissEph.SEFLG_SPEED) != 0) SE.Sweph.swi_precess_speed(xp, tjd_et, iflag, Sweph.J_TO_J2000); /********************* * to barycenter *********************/ if (ipli == SwissEph.SE_MOON) { for (i = 0; i <= 5; i++) xp[i] += xear[i]; } else { if (0 == (iflag & SwissEph.SEFLG_MOSEPH) && !ellipse_is_bary) for (j = 0; j <= 5; j++) xp[j] += xsun[j]; } /********************* * to correct center *********************/ for (j = 0; j <= 5; j++) xp[j] -= xobs[j]; /* geocentric perigee/apogee of sun */ if (ipl == SwissEph.SE_SUN && 0 == (iflag & (SwissEph.SEFLG_HELCTR | SwissEph.SEFLG_BARYCTR))) for (j = 0; j <= 5; j++) xp[j] = -xp[j]; /********************* * light deflection *********************/ dt = Math.Sqrt(SE.Sweph.square_sum(xp)) * Sweph.AUNIT / Sweph.CLIGHT / 86400.0; if (do_defl) SE.Sweph.swi_deflect_light(xp, dt, iflag); /********************* * aberration *********************/ if (do_aberr) { SE.Sweph.swi_aberr_light(xp, xobs, iflag); /* * Apparent speed is also influenced by * the difference of speed of the earth between t and t-dt. * Neglecting this would result in an error of several 0.1" */ if ((iflag & SwissEph.SEFLG_SPEED) != 0) { /* get barycentric sun and earth for t-dt into save area */ if (SE.swe_calc(tjd_et - dt, ipli, iflg0 | (iflag & SwissEph.SEFLG_TOPOCTR), x2, ref serr) == SwissEph.ERR) return SwissEph.ERR; if ((iflag & SwissEph.SEFLG_TOPOCTR) != 0) { /* geocentric position of observer */ /* if (swi_get_observer(tjd_et - dt, iflag, FALSE, xobs, serr) != OK) return ERR;*/ for (i = 0; i <= 5; i++) xobs2[i] = SE.Sweph.swed.topd.xobs[i]; } else { for (i = 0; i <= 5; i++) xobs2[i] = 0; } if ((iflag & (SwissEph.SEFLG_HELCTR | SwissEph.SEFLG_BARYCTR)) != 0) { if ((iflag & SwissEph.SEFLG_HELCTR) != 0 && 0 == (iflag & SwissEph.SEFLG_MOSEPH)) for (i = 0; i <= 5; i++) xobs2[i] = xsun[i]; } else if (ipl == SwissEph.SE_SUN && 0 == (iflag & SwissEph.SEFLG_MOSEPH)) { for (i = 0; i <= 5; i++) xobs2[i] = xsun[i]; } else { /* barycentric position of observer */ for (i = 0; i <= 5; i++) xobs2[i] += xear[i]; } for (i = 3; i <= 5; i++) xp[i] += xobs[i] - xobs2[i]; /* The above call of swe_calc() has destroyed the * parts of the save area * (i.e. bary sun, earth nutation matrix!). * to restore it: */ if (SE.swe_calc(tjd_et, SwissEph.SE_SUN, iflg0 | (iflag & SwissEph.SEFLG_TOPOCTR), x2, ref serr) == SwissEph.ERR) return SwissEph.ERR; } } /********************* * precession *********************/ /* save J2000 coordinates; required for sidereal positions */ for (j = 0; j <= 5; j++) x2000[j] = xp[j]; if (0 == (iflag & SwissEph.SEFLG_J2000)) { SE.SwephLib.swi_precess(xp, tjd_et, iflag, Sweph.J2000_TO_J); if ((iflag & SwissEph.SEFLG_SPEED) != 0) SE.Sweph.swi_precess_speed(xp, tjd_et, iflag, Sweph.J2000_TO_J); } /********************* * nutation *********************/ if (0 == (iflag & SwissEph.SEFLG_NONUT)) SE.Sweph.swi_nutate(xp, iflag, false); /* now we have equatorial cartesian coordinates; keep them */ for (j = 0; j <= 5; j++) pldat.xreturn[18 + j] = xp[j]; /************************************************ * transformation to ecliptic. * * with sidereal calc. this will be overwritten * * afterwards. * ************************************************/ SE.SwephLib.swi_coortrf2(xp, xp, oe.seps, oe.ceps); if ((iflag & SwissEph.SEFLG_SPEED) != 0) SE.SwephLib.swi_coortrf2(xp + 3, xp + 3, oe.seps, oe.ceps); if (0 == (iflag & SwissEph.SEFLG_NONUT)) { SE.SwephLib.swi_coortrf2(xp, xp, SE.Sweph.swed.nut.snut, SE.Sweph.swed.nut.cnut); if ((iflag & SwissEph.SEFLG_SPEED) != 0) SE.SwephLib.swi_coortrf2(xp + 3, xp + 3, SE.Sweph.swed.nut.snut, SE.Sweph.swed.nut.cnut); } /* now we have ecliptic cartesian coordinates */ for (j = 0; j <= 5; j++) pldat.xreturn[6 + j] = xp[j]; /************************************ * sidereal positions * ************************************/ if ((iflag & SwissEph.SEFLG_SIDEREAL) != 0) { /* project onto ecliptic t0 */ if ((SE.Sweph.swed.sidd.sid_mode & SwissEph.SE_SIDBIT_ECL_T0) != 0) { if (SE.Sweph.swi_trop_ra2sid_lon(x2000, pldat.xreturn.GetPointer(6), pldat.xreturn.GetPointer(18), iflag, ref serr) != SwissEph.OK) return SwissEph.ERR; /* project onto solar system equator */ } else if ((SE.Sweph.swed.sidd.sid_mode & SwissEph.SE_SIDBIT_SSY_PLANE) != 0) { if (SE.Sweph.swi_trop_ra2sid_lon_sosy(x2000, pldat.xreturn.GetPointer(6), pldat.xreturn.GetPointer(18), iflag, ref serr) != SwissEph.OK) return SwissEph.ERR; } else { /* traditional algorithm */ SE.SwephLib.swi_cartpol_sp(pldat.xreturn.GetPointer(6), pldat.xreturn); pldat.xreturn[0] -= SE.swe_get_ayanamsa(tjd_et) * SwissEph.DEGTORAD; SE.SwephLib.swi_polcart_sp(pldat.xreturn, pldat.xreturn.GetPointer(6)); } } if ((iflag & SwissEph.SEFLG_XYZ) != 0 && (iflag & SwissEph.SEFLG_EQUATORIAL) != 0) { for (j = 0; j <= 5; j++) xp[j] = pldat.xreturn[18 + j]; continue; } if ((iflag & SwissEph.SEFLG_XYZ) != 0) { for (j = 0; j <= 5; j++) xp[j] = pldat.xreturn[6 + j]; continue; } /************************************************ * transformation to polar coordinates * ************************************************/ SE.SwephLib.swi_cartpol_sp(pldat.xreturn.GetPointer(18), pldat.xreturn.GetPointer(12)); SE.SwephLib.swi_cartpol_sp(pldat.xreturn.GetPointer(6), pldat.xreturn); /********************** * radians to degrees * **********************/ if ((iflag & SwissEph.SEFLG_RADIANS) == 0) { for (j = 0; j < 2; j++) { pldat.xreturn[j] *= SwissEph.RADTODEG; /* ecliptic */ pldat.xreturn[j + 3] *= SwissEph.RADTODEG; pldat.xreturn[j + 12] *= SwissEph.RADTODEG; /* equator */ pldat.xreturn[j + 15] *= SwissEph.RADTODEG; } } if ((iflag & SwissEph.SEFLG_EQUATORIAL) != 0) { for (j = 0; j <= 5; j++) xp[j] = pldat.xreturn[12 + j]; continue; } else { for (j = 0; j <= 5; j++) xp[j] = pldat.xreturn[j]; continue; } } for (i = 0; i <= 5; i++) { if (i > 2 && 0 == (iflag & SwissEph.SEFLG_SPEED)) xna[i] = xnd[i] = xpe[i] = xap[i] = 0; if (xnasc != null) xnasc[i] = xna[i]; if (xndsc != null) xndsc[i] = xnd[i]; if (xperi != null) xperi[i] = xpe[i]; if (xaphe != null) xaphe[i] = xap[i]; } return SwissEph.OK; }
/* Moshier ephemeris. * computes heliocentric cartesian equatorial coordinates of * equinox 2000 * for earth and a planet * tjd julian day * ipli internal SWEPH planet number * xp array of 6 doubles for planet's position and speed * xe earth's * serr error string */ public int swi_moshplan(double tjd, int ipli, bool do_save, CPointer <double> xpret, CPointer <double> xeret, ref string serr) { int i; bool do_earth = false; double[] dx = new double[3], x2 = new double[3], xxe = new double[6], xxp = new double[6]; double[] xp, xe; double dt; string s = String.Empty; int iplm = pnoint2msh[ipli]; Sweph.plan_data pdp = SE.Sweph.swed.pldat[ipli]; Sweph.plan_data pedp = SE.Sweph.swed.pldat[Sweph.SEI_EARTH]; double seps2000 = SE.Sweph.swed.oec2000.seps; double ceps2000 = SE.Sweph.swed.oec2000.ceps; if (do_save) { xp = pdp.x; xe = pedp.x; } else { xp = xxp; xe = xxe; } if (do_save || ipli == Sweph.SEI_EARTH || xeret != null) { do_earth = true; } /* tjd beyond ephemeris limits, give some margin for spped at edge */ if (tjd < Sweph.MOSHPLEPH_START - 0.3 || tjd > Sweph.MOSHPLEPH_END + 0.3) { s = C.sprintf("jd %f outside Moshier planet range %.2f .. %.2f ", tjd, Sweph.MOSHPLEPH_START, Sweph.MOSHPLEPH_END); serr = (serr ?? String.Empty) + s; return(SwissEph.ERR); } /* earth, for geocentric position */ if (do_earth) { if (tjd == pedp.teval && pedp.iephe == SwissEph.SEFLG_MOSEPH) { xe = pedp.x; } else { /* emb */ swi_moshplan2(tjd, pnoint2msh[Sweph.SEI_EMB], xe); /* emb hel. ecl. 2000 polar */ SE.SwephLib.swi_polcart(xe, xe); /* to cartesian */ SE.SwephLib.swi_coortrf2(xe, xe, -seps2000, ceps2000); /* and equator 2000 */ embofs_mosh(tjd, xe); /* emb -> earth */ if (do_save) { pedp.teval = tjd; pedp.xflgs = -1; pedp.iephe = SwissEph.SEFLG_MOSEPH; } /* one more position for speed. */ swi_moshplan2(tjd - Sweph.PLAN_SPEED_INTV, pnoint2msh[Sweph.SEI_EMB], x2); SE.SwephLib.swi_polcart(x2, x2); SE.SwephLib.swi_coortrf2(x2, x2, -seps2000, ceps2000); embofs_mosh(tjd - Sweph.PLAN_SPEED_INTV, x2);/**/ for (i = 0; i <= 2; i++) { dx[i] = (xe[i] - x2[i]) / Sweph.PLAN_SPEED_INTV; } /* store speed */ for (i = 0; i <= 2; i++) { xe[i + 3] = dx[i]; } } if (xeret != null) { for (i = 0; i <= 5; i++) { xeret[i] = xe[i]; } } } /* earth is the planet wanted */ if (ipli == Sweph.SEI_EARTH) { xp = xe; } else { /* other planet */ /* if planet has already been computed, return */ if (tjd == pdp.teval && pdp.iephe == SwissEph.SEFLG_MOSEPH) { xp = pdp.x; } else { swi_moshplan2(tjd, iplm, xp); SE.SwephLib.swi_polcart(xp, xp); SE.SwephLib.swi_coortrf2(xp, xp, -seps2000, ceps2000); if (do_save) { pdp.teval = tjd;/**/ pdp.xflgs = -1; pdp.iephe = SwissEph.SEFLG_MOSEPH; } /* one more position for speed. * the following dt gives good speed for light-time correction */ //#if 0 // for (i = 0; i <= 2; i++) //dx[i] = xp[i] - pedp.x[i]; // dt = LIGHTTIME_AUNIT * Math.Sqrt(square_sum(dx)); //#endif dt = Sweph.PLAN_SPEED_INTV; swi_moshplan2(tjd - dt, iplm, x2); SE.SwephLib.swi_polcart(x2, x2); SE.SwephLib.swi_coortrf2(x2, x2, -seps2000, ceps2000); for (i = 0; i <= 2; i++) { dx[i] = (xp[i] - x2[i]) / dt; } /* store speed */ for (i = 0; i <= 2; i++) { xp[i + 3] = dx[i]; } } if (xpret != null) { for (i = 0; i <= 5; i++) { xpret[i] = xp[i]; } } } return(SwissEph.OK); } /* Prepare lookup table of sin and cos ( i*Lj ) * for required multiple angles */ void plan_sscc(int k, double arg, int n) { double cu, su, cv, sv, s; int i; su = Math.Sin(arg); cu = Math.Cos(arg); plan_ss[k, 0] = su; /* sin(L) */ plan_cc[k, 0] = cu; /* cos(L) */ sv = 2.0 * su * cu; cv = cu * cu - su * su; plan_ss[k, 1] = sv; /* sin(2L) */ plan_cc[k, 1] = cv; for (i = 2; i < n; i++) { s = su * cv + cu * sv; cv = cu * cv - su * sv; sv = s; plan_ss[k, i] = sv; /* sin( i+1 L ) */ plan_cc[k, i] = cv; } } /* Adjust position from Earth-Moon barycenter to Earth * * J = Julian day number * xemb = rectangular equatorial coordinates of Earth */ void embofs_mosh(double tjd, CPointer <double> xemb) { double T, M, a, L, B, p; double smp, cmp, s2mp, c2mp, s2d, c2d, sf, cf; double s2f, sx, cx; double[] xyz = new double[6]; double seps = SE.Sweph.swed.oec.seps; double ceps = SE.Sweph.swed.oec.ceps; int i; /* Short series for position of the Moon */ T = (tjd - Sweph.J1900) / 36525.0; /* Mean anomaly of moon (MP) */ a = SE.swe_degnorm(((1.44e-5 * T + 0.009192) * T + 477198.8491) * T + 296.104608); a *= SwissEph.DEGTORAD; smp = Math.Sin(a); cmp = Math.Cos(a); s2mp = 2.0 * smp * cmp; /* sin(2MP) */ c2mp = cmp * cmp - smp * smp; /* cos(2MP) */ /* Mean elongation of moon (D) */ a = SE.swe_degnorm(((1.9e-6 * T - 0.001436) * T + 445267.1142) * T + 350.737486); a = 2.0 * SwissEph.DEGTORAD * a; s2d = Math.Sin(a); c2d = Math.Cos(a); /* Mean distance of moon from its ascending node (F) */ a = SE.swe_degnorm(((-3.0e-7 * T - 0.003211) * T + 483202.0251) * T + 11.250889); a *= SwissEph.DEGTORAD; sf = Math.Sin(a); cf = Math.Cos(a); s2f = 2.0 * sf * cf; /* sin(2F) */ sx = s2d * cmp - c2d * smp; /* sin(2D - MP) */ cx = c2d * cmp + s2d * smp; /* cos(2D - MP) */ /* Mean longitude of moon (LP) */ L = ((1.9e-6 * T - 0.001133) * T + 481267.8831) * T + 270.434164; /* Mean anomaly of sun (M) */ M = SE.swe_degnorm(((-3.3e-6 * T - 1.50e-4) * T + 35999.0498) * T + 358.475833); /* Ecliptic longitude of the moon */ L = L + 6.288750 * smp + 1.274018 * sx + 0.658309 * s2d + 0.213616 * s2mp - 0.185596 * Math.Sin(SwissEph.DEGTORAD * M) - 0.114336 * s2f; /* Ecliptic latitude of the moon */ a = smp * cf; sx = cmp * sf; B = 5.128189 * sf + 0.280606 * (a + sx) /* sin(MP+F) */ + 0.277693 * (a - sx) /* sin(MP-F) */ + 0.173238 * (s2d * cf - c2d * sf); /* sin(2D-F) */ B *= SwissEph.DEGTORAD; /* Parallax of the moon */ p = 0.950724 + 0.051818 * cmp + 0.009531 * cx + 0.007843 * c2d + 0.002824 * c2mp; p *= SwissEph.DEGTORAD; /* Elongation of Moon from Sun */ L = SE.swe_degnorm(L); L *= SwissEph.DEGTORAD; /* Distance in au */ a = 4.263523e-5 / Math.Sin(p); /* Convert to rectangular ecliptic coordinates */ xyz[0] = L; xyz[1] = B; xyz[2] = a; SE.SwephLib.swi_polcart(xyz, xyz); /* Convert to equatorial */ SE.SwephLib.swi_coortrf2(xyz, xyz, -seps, ceps); /* Precess to equinox of J2000.0 */ SE.SwephLib.swi_precess(xyz, tjd, 0, Sweph.J_TO_J2000);/**/ /* now emb -> earth */ for (i = 0; i <= 2; i++) { xemb[i] -= xyz[i] / (Sweph.EARTH_MOON_MRAT + 1.0); } }