private static double[] __Yn = new double[1]; //年计数 #endregion #region 转换时新增加的方法 /// <summary> /// 新增方法: 计算节气, 并返回计算的节气总数, 在调用本方法并读取 SSQ.ZQ 数据后, 应该清零 SSQ.ZQ /// </summary> /// <param name="jd"></param> /// <param name="calcMultiPeriod"></param> /// <returns></returns> public static int calcJieQi(double jd, bool calcMultiPeriod) { LunarInfoListT <double> A = SSQ.ZQ; double[] B = SSQ.HS; // 中气表,日月合朔表(整日) int i; double W; if (!calcMultiPeriod) // 只计算某年的节气 { W = LunarHelper.int2((jd - 355 + 183) / 365.2422) * 365.2422 + 355; // 355是2000.12冬至,得到较靠近jd的冬至估计值 if (SSQ.calc(W, "气") > jd) { W -= 365.2422; } for (i = 0; i < 25; i++) { A[i] = SSQ.calc(W + 15.2184 * i, "气"); // 25个节气时刻(北京时间),从冬至开始到下一个冬至以后 } A.pe1 = SSQ.calc(W - 15.2, "气"); A.pe2 = SSQ.calc(W - 30.4, "气"); // 补算二气,确保一年中所有月份的“气”全部被计算在内 } else // 需计算从霜降至下 2 个大寒之后的节气, 用于计算指定日期的所属节气, 上一节气, 下一节气等信息 { W = LunarHelper.int2((jd - 355 + 183) / 365.2422) * 365.2422 + 296; // 296是2000.10.23霜降(距200.1.1的天数),得到较靠近jd的霜降估计值 if (SSQ.calc(W, "气") > jd) { W -= 365.2422; } for (i = 0; i < 31; i++) { A[i] = SSQ.calc(W + 15.2184 * i, "气"); // 31个节气时刻(北京时间),从霜降至开始到下 2 个大寒以后 } } return((!calcMultiPeriod ? 25 : 31)); }
/// <summary> /// 从 Xml 对象中读取农历节日的定义 /// </summary> /// <returns></returns> private static xList <OB> getLunarFeasts() { const string xPath = "SharpSxwnl/SxwnlData/Data[@Id = 'obb_getDayName']"; xList <OB> result = new xList <OB>(); if (LunarHelper.SxwnlXmlData != null) { XmlNodeList foundNodeList = LunarHelper.SxwnlXmlData.SelectNodes(xPath); if (foundNodeList.Count > 0) { for (int i = 0; i < foundNodeList.Count; i++) { for (int j = 0; j < foundNodeList[i].ChildNodes.Count; j++) { result.Add(new OB()); // 添加日对象来记录节点信息 XmlAttributeCollection xmlAttr = foundNodeList[i].ChildNodes[j].Attributes; result[result.Count - 1].Lmc = xmlAttr.GetNamedItem("Day").InnerText; result[result.Count - 1].A = xmlAttr.GetNamedItem("A").InnerText; result[result.Count - 1].B = xmlAttr.GetNamedItem("B").InnerText; result[result.Count - 1].C = xmlAttr.GetNamedItem("C").InnerText; result[result.Count - 1].Fjia = LunarHelper.VAL(xmlAttr.GetNamedItem("Fjia").InnerText) == 0 ? 0 : 1; } } } } return(result); }
/// <summary> /// 儒略日数转公历 /// </summary> /// <param name="jd">儒略日</param> public static void setFromJD(double jd) { jd += 0.5; double A = LunarHelper.int2(jd), F = jd - A, D; //取得日数的整数部份A及小数部分F if (A >= 2299161) { D = LunarHelper.int2((A - 1867216.25) / 36524.25); A += 1 + D - LunarHelper.int2(D / 4); } A += 1524; //向前移4年零2个月 JD.Y = LunarHelper.int2((A - 122.1) / 365.25); //年 D = A - LunarHelper.int2(365.25 * JD.Y); //去除整年日数后余下日数 JD.M = LunarHelper.int2(D / 30.6001); //月数 JD.D = D - LunarHelper.int2(JD.M * 30.6001); //去除整月日数后余下日数 JD.Y -= 4716; JD.M--; if (JD.M > 12) { JD.M -= 12; } if (JD.M <= 2) { JD.Y++; } //日的小数转为时分秒 F *= 24; JD.h = LunarHelper.int2(F); F -= JD.h; F *= 60; JD.m = LunarHelper.int2(F); F -= JD.m; F *= 60; JD.s = F; }
/// <summary> /// 把太阳月亮信息形成纯文本字符串 /// </summary> /// <param name="fs">是否显示ΔT, 黄经章等信息</param> /// <returns></returns> public string toText(double fs) { StringBuilder sb = new StringBuilder(); sb.Append("平太阳 " + JD.timeStr(this.pty) + " 真太阳 " + JD.timeStr(this.zty) + "\r\n"); sb.Append("时差 " + LunarHelper.m2fm(this.sc * 86400, 2, 1) + " 月亮被照亮 " + (this.mIll * 100).ToString("F2") + "% "); sb.Append("\r\n"); sb.Append("\r\n表一 月亮 太阳\r\n"); sb.Append("视黄经 " + LunarHelper.rad2str(this.mHJ, 0) + " " + LunarHelper.rad2str(this.sHJ, 0) + "\r\n"); sb.Append("视黄纬 " + LunarHelper.rad2str(this.mHW, 0) + " " + LunarHelper.rad2str(this.sHW, 0) + "\r\n"); sb.Append("视赤经 " + LunarHelper.rad2str(this.mCJ, 1) + " " + LunarHelper.rad2str(this.sCJ, 1) + "\r\n"); sb.Append("视赤纬 " + LunarHelper.rad2str(this.mCW, 0) + " " + LunarHelper.rad2str(this.sCW, 0) + "\r\n"); sb.Append("距离 " + this.mR.ToString("F0") + "千米 " + this.sR.ToString("F6") + "AU" + "\r\n"); sb.Append("\r\n表二 月亮 太阳\r\n"); sb.Append("方位角 " + LunarHelper.rad2str(this.mPJ, 0) + " " + LunarHelper.rad2str(this.sPJ, 0) + "\r\n"); sb.Append("高度角 " + LunarHelper.rad2str(this.mPW, 0) + " " + LunarHelper.rad2str(this.sPW, 0) + "\r\n"); sb.Append("时角 " + LunarHelper.rad2str(this.mShiJ, 0) + " " + LunarHelper.rad2str(this.sShiJ, 0) + "\r\n"); sb.Append("视半径(观测点) " + LunarHelper.m2fm(this.mRad, 2, 0) + " " + LunarHelper.m2fm(this.sRad, 2, 0) + "\r\n"); if (fs != 0) { sb.Append("\r\n力学时 " + JD.setFromJD_str(this.T + LunarHelper.J2000)); sb.Append(" ΔT=" + (this.dt * 86400).ToString("F1") + "秒\r\n"); sb.Append("黄经章 " + (this.dL / LunarHelper.pi2 * 360 * 3600).ToString("F2") + "\" "); sb.Append("交角章 " + (this.dE / LunarHelper.pi2 * 360 * 3600).ToString("F2") + "\" "); sb.Append("\r\nε=" + LunarHelper.trim(LunarHelper.rad2str(this.E, 0))); } return(sb.ToString()); }
/// <summary> /// 时差计算(高精度) /// </summary> /// <param name="t"></param> /// <returns></returns> public static double shiCha(double t) { double t2 = t * t, t3 = t2 * t, t4 = t3 * t, t5 = t4 * t; double L = (1753469512 + 628331965331.8 * t + 5296.74 * t2 + 0.432 * t3 - 0.1124 * t4 - 0.00009 * t5 + 630 * Math.Cos(6 + 0.3 * t)) / 1000000000 + Math.PI - 20.5 / LunarHelper.rad; double E, dE, dL; double[] z = new double[2]; // C#: 待定(?) dL = -17.2 * Math.Sin(2.1824 - 33.75705 * t) / LunarHelper.rad; //黄经章 dE = 9.2 * Math.Cos(2.1824 - 33.75705 * t) / LunarHelper.rad; //交角章 E = ZB.hcjj(t) + dE; //真黄赤交角 //地球坐标 z[0] = XL.E_Lon(t, 50) + Math.PI + ZB.gxc_sunLon(t) + dL; z[1] = -(2796 * Math.Cos(3.1987 + 8433.46616 * t) + 1016 * Math.Cos(5.4225 + 550.75532 * t) + 804 * Math.Cos(3.88 + 522.3694 * t)) / 1000000000; ZB.llrConv(z, E); //z太阳地心赤道坐标 z[0] -= dL * Math.Cos(E); L = LunarHelper.rad2mrad(L - z[0]); if (L > Math.PI) { L -= LunarHelper.pi2; } return(L / LunarHelper.pi2); //单位是周(天) }
/// <summary> /// 求空间两点连线与地球的交点(靠近点1的交点),返回在ZB.le_J,le_W,赤道坐标。R1,R2单位是千米 /// </summary> /// <param name="J1"></param> /// <param name="W1"></param> /// <param name="R1"></param> /// <param name="J2"></param> /// <param name="W2"></param> /// <param name="R2"></param> public static void line_earth(double J1, double W1, double R1, double J2, double W2, double R2) { double x1 = R1 * Math.Cos(W1) * Math.Cos(J1), y1 = R1 * Math.Cos(W1) * Math.Sin(J1), z1 = R1 * Math.Sin(W1); double x2 = R2 * Math.Cos(W2) * Math.Cos(J2), y2 = R2 * Math.Cos(W2) * Math.Sin(J2), z2 = R2 * Math.Sin(W2); double dx = x2 - x1, dy = y2 - y1, dz = z2 - z1, f = 0.99664719, r = LunarHelper.cs_rEar; //直线参数及地球参数 double x, y, z, lh = 0; if (Math.Abs(dx) < Math.Abs(dy)) //必要时仑换 { lh = dx; dx = dy; dy = lh; lh = x1; x1 = y1; y1 = lh; lh = 1; } double a = dy / dx, b = y1 - a * x1, c = dz / dx / f, d = z1 / f - c * x1; double A = a * a + c * c + 1, B = a * b + c * d, C = b * b + d * d - r * r, D = B * B - A * C; if (D < 0) { ZB.le_J = ZB.le_W = 100; return; } //返回100表示无解 D = Math.Sqrt(D); if (x1 + B / A < 0) { D = -D; } x = (-B + D) / A; y = a * x + b; z = (c * x + d) / f; ZB.le_R1 = Math.Sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1) + (z - z1) * (z - z1)); if (lh != 0) { lh = x; x = y; y = lh; } ZB.le_W = Math.Atan(z / Math.Sqrt(x * x + y * y)); ZB.le_J = LunarHelper.rad2mrad(Math.Atan2(y, x)); }
/// <summary> /// 将度分秒转换为弧度值(只作简单转化, 要求传递的格式严格遵守"度分秒"的格式, 如: 0°0'31.49" /// </summary> /// <param name="d"></param> /// <returns></returns> public static double str2rad(string d) { double result = 0; string strSpliter = "°'\""; char[] spliters = strSpliter.ToCharArray(); string[] strD = d.Split(spliters, StringSplitOptions.RemoveEmptyEntries); if (strD.Length > 0) { double a = 0, b = 0, c = 0; a = LunarHelper.VAL(strD[0]) / 180 * Math.PI; // 1°= 1/180*PI ≈ 0.017453292519943 弧度 if (strD.Length > 1) { b = LunarHelper.VAL(strD[1]) / 60 / 180 * Math.PI; // 1' = (1/60)°≈ 0.000290888208666 弧度 if (strD.Length > 2) { c = LunarHelper.VAL(strD[2]) / 60 / 180 / 60 * Math.PI; // 1" = (1/60)' ≈ 0.000004848136811 弧度 } } if (a > 0) { result = a + b + c; } else { result = a - b - c; } } return(result); }
/// <summary> /// 计算本月所有日期的日十二建信息 /// </summary> private void CalcRiJianThisMonth() { OB lunOb; string yuejian = String.Empty; //OB ob = new OB(); for (int i = 0; i < this.dn; i++) // 遍历月 { lunOb = this.lun[i]; //if (i == 0 || lunOb.jqmc.Trim().Length > 0 || lunOb.Ljq.Trim().Length > 0) // 每月第 1 日, 或遇到了交节气日, 则计算该日的所属节气等 //{ // ob.y = lunOb.y; // ob.m = lunOb.m; // ob.d = lunOb.d; // this.CalcJieQiInfo(ob, CalcJieQiType.CalcJie); //} //yuejian = ob.ThisJieQi.YueJian; //if (ob.ThisJieQi.DifferentTime) // yuejian = LunarHelper.SUBSTRING(lunOb.Lmonth2, 1, 1); // 调整为实历 // 可直接使用该属性的月建而无需再次计算节气, 但上述被注释的代码也可用(主要为了测试 CalcJieQiInfo 方法, 暂保留) yuejian = LunarHelper.SUBSTRING(lunOb.Lmonth2, 1, 1); lunOb.Ri12Jian = this.GetRi12Jian(yuejian, LunarHelper.SUBSTRING(lunOb.Lday2, 1, 1)); // 计算日十二建 } }
/// <summary> /// 传入普通纪年或天文纪年,传回天文纪年 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="c">普通纪年或天文纪年, 泛型, 支持数值或字符串</param> /// <returns></returns> public static int year2Ayear <T>(T c) { int y; Regex regexToReplace = new Regex(@"[^0-9Bb\*-]"); // C#: 匹配字符: 数字0-9, B, b, *, - string strC = regexToReplace.Replace(c.ToString(), ""); // C#: 去除无效字符 string q = strC.Substring(0, 1); if (q == "B" || q == "b" || q == "*") //通用纪年法(公元前) { y = 1 - LunarHelper.VAL(strC.Substring(1), 1); if (y > 0) { MessageBox.Show("通用纪法的公元前纪法从 B.C.1 年开始,并且没有公元 0 年!", "信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); return(-10000); } } else { y = LunarHelper.VAL(strC, 1); } if (y < -4712) { MessageBox.Show("不得小于 B.C.4713 年!", "信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); return(-10000); } if (y > 9999) { MessageBox.Show("超过9999年的农历计算很不准。", "信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); } return(y); }
/// <summary> /// 按交节干支生成 html 年历 /// </summary> /// <param name="y"></param> /// <returns></returns> public string nianLi2HTML(double y) { int i, j; StringBuilder s = new StringBuilder(); // C#: 为提高字符串处理效率, 使用 StringBuilder StringBuilder s1 = new StringBuilder(); // C#: 为提高字符串处理效率, 使用 StringBuilder double v, v2, qi = 0; SSQ.calcY(LunarHelper.int2((y - 2000) * 365.2422 + 180)); for (i = 0; i < 14; i++) { if (SSQ.HS[i + 1] > SSQ.ZQ[24]) { break; //已包含下一年的冬至 } if (SSQ.leap != 0 && i == SSQ.leap) { s1.Append("闰"); } else { s1.Append("·"); } s1.Append(SSQ.ym[i]); if (s1.ToString().Length < 3) { s1.Append("月"); } s1.Append(SSQ.dx[i] > 29 ? "大" : "小"); v = SSQ.HS[i] + LunarHelper.J2000; s1.Append(" " + obb.Gan[(int)((v + 9) % 10)] + obb.Zhi[(int)((v + 1) % 12)]); s1.Append(" " + JD.setFromJD_str(v).Substring(6, 5)); for (j = -2; j < 24; j++) { if (j >= 0) { qi = SSQ.ZQ[j]; } if (j == -1) { qi = SSQ.ZQ.pe1; } if (j == -2) { qi = SSQ.ZQ.pe2; } if (qi < SSQ.HS[i] || qi >= SSQ.HS[i + 1]) { continue; } v2 = qi + LunarHelper.J2000; s1.Append(" " + obb.rmc[(int)(v2 - v)] + obb.Gan[(int)((v2 + 9) % 10)] + obb.Zhi[(int)((v2 + 1) % 12)]); s1.Append(obb.jqmc[(j + 24) % 24] + JD.setFromJD_str(qi + LunarHelper.J2000).Substring(6, 5)); } s.Append(s1.ToString() + "<br>"); s1.Remove(0, s1.Length); // C#: 在转换时将原来的字符串 s1 改写为 StringBuiler, 因此添加本句 } return(s.ToString()); }
/// <summary> /// 命理八字计算(普通计算, 不转换为当地真太阳时), 并保存到日对象 ob 中 /// </summary> /// <param name="jd">格林尼治UT(J2000起算)</param> /// <param name="J">本地经度</param> /// <param name="ob">日对象</param> /// <param name="southernHemisphere">南半球的标志</param> public static void mingLiBaZiNormal(double jd, double J, OB ob, BaZiTypeS baziTypeS) { int i; string c; double v; double jd2 = jd + JD.deltatT2(jd); // 力学时 double w = XL.S_aLon(jd2 / 36525, -1); // 此刻太阳视黄经 double k = LunarHelper.int2((w / LunarHelper.pi2 * 360 + 45 + 15 * 360) / 30); // 1984年立春起算的节气数(不含中气) //---------------------------------------------------------------------------------------------- // C#: 注: 仅有下列代码段与 mingLiBaZi 方法中的代码不同, 其余部分都是相同的 //---------------------------------------------------------------------------------------------- jd += 0 - J / Math.PI / 2; // 将格林尼治UT(J2000起算), 转换为本地时间, 不必考虑真太阳与平太阳时之间的时差 ob.bz_zty = ""; // 真太阳时置空串 ob.bz_pty = JD.timeStr(jd); // 计算平太阳时 jd += 13d / 24d; // 转为前一日23点起算(原jd为本日中午12点起算) // C#: 注意数据类型 double D = Math.Floor(jd), SC = LunarHelper.int2((jd - D) * 12); // 日数与时辰 v = LunarHelper.int2(k / 12 + 6000000); ob.bz_jn = obb.Gan[(int)(v % 10)] + obb.Zhi[(int)(v % 12)]; v = k + 2 + 60000000; ob.bz_jy = obb.Gan[(int)(v % 10)] + obb.Zhi[(int)(v % 12)]; // C#: 新增的代码段, 计算南半球八字(仅纪月不同) switch (baziTypeS) { case BaZiTypeS.TianChongDiChong: ob.bz_jy = obb.Gan[(int)((v + 4) % 10)] + obb.Zhi[(int)((v + 6) % 12)]; break; case BaZiTypeS.TianKeDiChong: ob.bz_jy = obb.Gan[(int)((v + 6) % 10)] + obb.Zhi[(int)((v + 6) % 12)]; break; case BaZiTypeS.TianTongDiChong: ob.bz_jy = obb.Gan[(int)((v + 0) % 10)] + obb.Zhi[(int)((v + 6) % 12)]; break; default: break; } v = D - 6 + 9000000; ob.bz_jr = obb.Gan[(int)(v % 10)] + obb.Zhi[(int)(v % 12)]; v = (D - 1) * 12 + 90000000 + SC; ob.bz_js = obb.Gan[(int)(v % 10)] + obb.Zhi[(int)(v % 12)]; v -= SC; ob.bz_JS = ""; // 全天纪时表 for (i = 0; i < 13; i++) { // 一天中包含有13个纪时 c = obb.Gan[(int)((v + i) % 10)] + obb.Zhi[(int)((v + i) % 12)]; // 各时辰的八字 if (SC == i) { ob.bz_js = c; // c = "<font color=red>" + c + "</font>"; //红色显示这时辰 // C#: 注释, 即取消格式显示 } ob.bz_JS += (i != 0 ? " " : "") + c; } }
/// <summary> /// 传入天文纪年,传回显示用的常规纪年 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="y">天文纪年, 泛型, 支持数值或字符串</param> /// <returns></returns> public static string Ayear2year <T>(T y) { int result = LunarHelper.VAL(y.ToString(), 1); if (result <= 0) { return("B" + (-result + 1)); } return(result.ToString()); }
/// <summary> /// 多天升中降计算,jd是当地起始儒略日(中午时刻),sq是时区 /// </summary> /// <param name="jd"></param> /// <param name="n"></param> /// <param name="Jdl"></param> /// <param name="Wdl"></param> /// <param name="sq"></param> public static void calcRTS(double jd, double n, double Jdl, double Wdl, double sq) { int i; double c; LunarInfoListT <double> r; // C#: 不需要实例化, 因此注释语句的后半部分: = new LunarInfoListT<double>(3, 0d); // C#: 由于将 rts 设置为自动实现的公共属性, 故添加了以下代码段来初始化 if (SZJ.rts == null) { SZJ.rts = new LunarInfoListT <LunarInfoListT <double> >(); } if (SZJ.rts.Count == 0) { for (i = 0; i < 31; i++) { SZJ.rts.Add(new LunarInfoListT <double>()); // SZJ.rts[i] = new LunarInfoListT(); } } SZJ.L = Jdl; SZJ.fa = Wdl; sq /= 24; //设置站点参数 for (i = 0; i < n; i++) { r = SZJ.rts[i]; r.Ms = r.Mz = r.Mj = ""; } for (i = -1; i <= n; i++) { if (i >= 0 && i < n) { //太阳 r = SZJ.St(jd + i + sq); ((SZJ.rts[i])).s = JD.timeStr(r.s__ - sq); //升 ((SZJ.rts[i])).z = JD.timeStr(r.z__ - sq); //中 ((SZJ.rts[i])).j = JD.timeStr(r.j__ - sq); //降 ((SZJ.rts[i])).c = JD.timeStr(r.c__ - sq); //晨 ((SZJ.rts[i])).h = JD.timeStr(r.h__ - sq); //昏 ((SZJ.rts[i])).ch = JD.timeStr(r.h__ - r.c__ - 0.5); //光照时间,timeStr()内部+0.5,所以这里补上-0.5 ((SZJ.rts[i])).sj = JD.timeStr(r.j__ - r.s__ - 0.5); //昼长 } r = SZJ.Mt(jd + i + sq); //月亮 c = LunarHelper.int2(r.s__ - sq + 0.5) - jd; if (c >= 0 && c < n) { (SZJ.rts[(int)c]).Ms = JD.timeStr(r.s__ - sq); } c = LunarHelper.int2(r.z__ - sq + 0.5) - jd; if (c >= 0 && c < n) { (SZJ.rts[(int)c]).Mz = JD.timeStr(r.z__ - sq); } c = LunarHelper.int2(r.j__ - sq + 0.5) - jd; if (c >= 0 && c < n) { (SZJ.rts[(int)c]).Mj = JD.timeStr(r.j__ - sq); } } SZJ.rts.dn = n; }
/// <summary> /// 球面坐标旋转 /// </summary> /// <param name="JW"></param> /// <param name="E"></param> public static void llrConv(double[] JW, double E) { //黄道赤道坐标变换,赤到黄E取负 double sinE = Math.Sin(E), cosE = Math.Cos(E); double sinJ = Math.Sin(JW[0]), cosJ = Math.Cos(JW[0]); double sinW = Math.Sin(JW[1]), cosW = Math.Cos(JW[1]), tanW = Math.Tan(JW[1]); JW[0] = Math.Atan2(sinJ * cosE - tanW * sinE, cosJ); JW[1] = Math.Asin(cosE * sinW + sinE * cosW * sinJ); JW[0] = LunarHelper.rad2mrad(JW[0]); }
/// <summary> /// 求角度差(未测试) /// </summary> /// <param name="J1"></param> /// <param name="W1"></param> /// <param name="J2"></param> /// <param name="W2"></param> /// <returns></returns> public static double j1_j2(double J1, double W1, double J2, double W2) { double dJ = LunarHelper.rad2rrad(J1 - J2), dW = W1 - W2; if (Math.Abs(dJ) < 1 / 1000 && Math.Abs(dW) < 1 / 1000) { dJ *= Math.Cos((W1 + W2) / 2); return(Math.Sqrt(dJ * dJ + dW * dW)); } return(Math.Acos(Math.Sin(W1) * Math.Sin(W2) + Math.Cos(W1) * Math.Cos(W2) * Math.Cos(dJ))); }
/// <summary> /// 球面坐标旋转 /// </summary> /// <param name="JW"></param> /// <param name="E"></param> public static void llrConv(LunarInfoListT <double> JW, double E) // C#: 新扩展出来的方法 { //黄道赤道坐标变换,赤到黄E取负 double sinE = Math.Sin(E), cosE = Math.Cos(E); double sinJ = Math.Sin((JW[0])), cosJ = Math.Cos((JW[0])); double sinW = Math.Sin((JW[1])); double cosW = Math.Cos((JW[1])); double tanW = Math.Tan((JW[1])); JW[0] = Math.Atan2(sinJ * cosE - tanW * sinE, cosJ); JW[1] = Math.Asin(cosE * sinW + sinE * cosW * sinJ); JW[0] = LunarHelper.rad2mrad((JW[0])); }
/// <summary> /// 回历计算, 并保存信息到日对象中 /// </summary> /// <param name="d0">2000.0起算儒略日,北京时12:00</param> /// <param name="r">日对象</param> public static void getHuiLi(double d0, OB r) { // 以下算法使用Excel测试得到,测试时主要关心年临界与月临界 double z, y, m, d; d = d0 + 503105; z = LunarHelper.int2((d + 0.1) / 10631); // 10631为一周期(30年) d -= z * 10631; y = LunarHelper.int2((d + 0.5) / 354.366); // 加0.5的作用是保证闰年正确(一周中的闰年是第2,5,7,10,13,16,18,21,24,26,29年) d -= LunarHelper.int2(y * 354.366 + 0.5); m = LunarHelper.int2((d + 0.11) / 29.51); // 分子加0.11,分每加0.01的作用是第354或355天的的月分保持为12月(m=11) d -= LunarHelper.int2(m * 29.51 + 0.5); r.Hyear = z * 30 + y + 1; r.Hmonth = m + 1; r.Hday = d + 1; }
/// <summary> /// 计算八字 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="ob">日对象</param> /// <param name="type">八字类型</param> /// <param name="curTZ">时区</param> /// <param name="year">年</param> /// <param name="month">月</param> /// <param name="day">日</param> /// <param name="time">时间串</param> /// <param name="longitudeStr">经度(度分秒格式)</param> /// <returns>八字字符串</returns> public static string ML_calc <T>(OB ob, BaZiType type, double curTZ, T year, T month, T day, string time, string longitudeStr, BaZiTypeS baziTypes) { double y = LunarHelper.year2Ayear(year); if (y == -10000) { return(String.Empty); } string timeName = (type == BaZiType.ZtyBaZi ? "真太阳 " : (type == BaZiType.PtyBaZi ? "平太阳 " : "北京时间 ")); double t = LunarHelper.timeStr2hour(time); double longitude; if (type == BaZiType.EL120BaZi) { longitude = LunarHelper.str2rad("-120°"); // 解析东经120°经度为弧度 } else { longitude = LunarHelper.str2rad(longitudeStr); // 解析经度为弧度 } double jd = JD.JD__(y, LunarHelper.VAL(month.ToString()), LunarHelper.VAL(day.ToString()) + t / 24); if (type == BaZiType.ZtyBaZi) { obb.mingLiBaZi(jd + curTZ / 24 - LunarHelper.J2000, longitude, ob, baziTypes); // 八字计算, 独立于 Lunar 类 timeName += ob.bz_zty; } else { obb.mingLiBaZiNormal(jd + curTZ / 24 - LunarHelper.J2000, longitude, ob, baziTypes); // 八字计算, 独立于 Lunar 类 timeName += ob.bz_pty; } // C#: 新增的代码段 JD.setFromJD(jd); double yearAjusted = JD.Y; double monthAjusted = JD.M; double dayAjusted = JD.D; return("[日标]:" + "公历 " + yearAjusted + "-" + monthAjusted + "-" + dayAjusted + " 儒略日数 " + LunarHelper.int2(jd + 0.5) + " 距2000年首" + LunarHelper.int2(jd + 0.5 - LunarHelper.J2000) + "日" + "\r\n[八字]:" + ob.bz_jn + "年 " + ob.bz_jy + "月 " + ob.bz_jr + "日 " + ob.bz_js + "时 " + timeName + "\r\n[纪时]:" + ob.bz_JS + "\r\n[时标]:" + "23 01 03 05 07 09 11 13 15 17 19 21 23"); }
/// <summary> /// 章动同时影响恒星时和天体坐标,所以不计算章动。返回时角及赤经纬 /// </summary> /// <param name="jd"></param> /// <param name="H0"></param> /// <param name="z"></param> public static void Mcoord(double jd, double H0, LunarInfoListT <double> z) { XL.M_coord((jd + SZJ.dt) / 36525, z, 30, 20, 8); //低精度月亮赤经纬 ZB.llrConv(z, SZJ.E); //转为赤道坐标 z.H = LunarHelper.rad2mrad(ZB.gst(jd, SZJ.dt) - SZJ.L - z[0]); if (z.H > Math.PI) { z.H -= LunarHelper.pi2; //得到此刻天体时角 } if (H0 != 0) { z.H0 = SZJ.getH(0.7275 * LunarHelper.cs_rEar / z[2] - 34 * 60 / LunarHelper.rad, z[1]); //升起对应的时角 } }
/// <summary> /// 章动同时影响恒星时和天体坐标,所以不计算章动。返回时角及赤经纬 /// </summary> /// <param name="jd"></param> /// <param name="H0"></param> /// <param name="H1"></param> /// <param name="z"></param> public static void Scoord(double jd, double H0, double H1, LunarInfoListT <double> z) { z[0] = XL.E_Lon((jd + SZJ.dt) / 36525, 5) + Math.PI - 20.5 / LunarHelper.rad; //太阳坐标(修正了光行差) z[1] = 0d; z[2] = 1d; // C#: 添加 d, 强制为 double 类型, 否则在把该元素显式转换为 double 时会出错 ZB.llrConv(z, SZJ.E); // 转为赤道坐标 z.H = LunarHelper.rad2rrad(ZB.gst(jd, SZJ.dt) - SZJ.L - z[0]); //得到此刻天体时角 if (H0 != 0) { z.H0 = SZJ.getH(-50 * 60 / LunarHelper.rad, z[1]); //地平以下50分 } if (H1 != 0) { z.H1 = SZJ.getH(-Math.PI / 30, z[1]); // 地平以下6度 } }
/// <summary> /// 时差计算(低精度),误差约在1秒以内 /// </summary> /// <param name="t"></param> /// <returns></returns> public static double shiCha2(double t) { double L = (1753469512 + 628331965331.8 * t + 5296.74 * t * t) / 1000000000 + Math.PI; double[] z = new double[2]; // C#: 待定(?) double E = (84381.4088 - 46.836051 * t) / LunarHelper.rad; z[0] = XL.E_Lon(t, 5) + Math.PI; z[1] = 0; // 地球坐标 ZB.llrConv(z, E); // z太阳地心赤道坐标 L = LunarHelper.rad2mrad(L - z[0]); if (L > Math.PI) { L -= LunarHelper.pi2; } return(L / LunarHelper.pi2); // 单位是周(天) }
/// <summary> /// 计算ML0或ML1或ML2 /// </summary> /// <param name="ob"></param> /// <param name="t"></param> /// <param name="n"></param> /// <returns></returns> public static double Mnn(double[][] ob, double t, double n) { int i, j; double[] F; double N, v = 0, tn = 1, c; double t2 = t * t, t3 = t2 * t, t4 = t3 * t, t5 = t4 * t, tx = t - 10; if (ob == XL.ML) { v += (3.81034409 + 8399.684730072 * t - 3.319e-05 * t2 + 3.11e-08 * t3 - 2.033e-10 * t4) * LunarHelper.rad; //月球平黄经(弧度) v += 5028.792262 * t + 1.1124406 * t2 + 0.00007699 * t3 - 0.000023479 * t4 - 0.0000000178 * t5; //岁差(角秒) if (tx > 0) { v += -0.866 + 1.43 * tx + 0.054 * tx * tx; // 对公元3000年至公元5000年的拟合,最大误差小于10角秒 } } //t2 /= 1e4; t3 /= 1e8; t4 /= 1e8; // C#: 此处的计算可能会导致数据精度过低, 故注释, 在下面引用的地方进行修改 n *= 6; if (n < 0) { n = ob[0].Length; } for (i = 0; i < ob.Length; i++) // C#: 注释循环变量中步长计算的后半语句: , tn *= t) { F = ob[i]; N = LunarHelper.int2(n * F.Length / ob[0].Length + 0.5); if (i != 0) { N += 6; } if (N >= F.Length) { N = F.Length; } for (j = 0, c = 0; j < N; j += 6) { // c += F[j] * Math.Cos(F[j + 1] + t * F[j + 2] + t2 * F[j + 3] + t3 * F[j + 4] + t4 * F[j + 5]); // C#: 原语句, 因可能导致数据精度过低, 故修改如下 c += F[j] * Math.Cos(F[j + 1] + t * F[j + 2] + t2 * F[j + 3] / 1e4 + t3 * F[j + 4] / 1e8 + t4 * F[j + 5] / 1e8); // C#: 新语句 } // v += c * tn; // C#: 注释此句并改写如下 v += c * tn * Math.Pow(t, i); } if (ob != XL.MR) { v /= LunarHelper.rad; } return(v); }
/// <summary> /// 公历转儒略日 /// </summary> /// <param name="y">年</param> /// <param name="m">月</param> /// <param name="d">日</param> /// <returns></returns> public static double JD__(double y, double m, double d) // C#: 为了避免与类名相同而冲突(被视为构造函数), 按转换规范 1 为方法名添加下划线 { double n = 0, G = 0; if (y * 372 + m * 31 + LunarHelper.int2(d) >= 588829) { G = 1; //判断是否为格里高利历日1582*372+10*31+15 } if (m <= 2) { m += 12; y--; } if (G != 0) { n = LunarHelper.int2(y / 100); n = 2 - n + LunarHelper.int2(n / 4); } //加百年闰 return(LunarHelper.int2(365.25 * (y + 4716) + 0.01) + LunarHelper.int2(30.6001 * (m + 1)) + d + n - 1524.5); }
/// <summary> /// 秒转为分秒 /// </summary> /// <param name="v">要转换的秒</param> /// <param name="fx">小数点位数</param> /// <param name="fs">为 1 转为"分秒"格式, 否则转为"角分秒"格式</param> /// <returns></returns> public static string m2fm(double v, int fx, int fs) { string gn = ""; if (v < 0) { v = -v; gn = "-"; } double f = LunarHelper.int2(v / 60), m = v - f * 60; if (fs != 0) { return(gn + f + "分" + m.ToString("F" + fx) + "秒"); } else { return(gn + f + "'" + m.ToString("F" + fx) + "\""); } }
/// <summary> /// 月亮到中升降时刻计算,传入jd含义与St()函数相同 /// </summary> /// <param name="jd"></param> /// <returns></returns> public static LunarInfoListT <double> Mt(double jd) { SZJ.dt = JD.deltatT2(jd); SZJ.E = ZB.hcjj(jd / 36525); jd -= LunarHelper.mod2(0.1726222 + 0.966136808032357 * jd - 0.0366 * SZJ.dt - SZJ.L / LunarHelper.pi2, 1); //查找最靠近当日中午的月上中天,mod2的第1参数为本地时角近似值 LunarInfoListT <double> r = new LunarInfoListT <double>(3, 0d); double sv = LunarHelper.pi2 * 0.966; r.z__ = r.s__ = r.j__ = r.c__ = r.h__ = jd; SZJ.Mcoord(jd, 1, r); //月亮坐标 r.s__ += (-r.H0 - r.H) / sv; r.j__ += (r.H0 - r.H) / sv; r.z__ += (0 - r.H) / sv; SZJ.Mcoord(r.s__, 1, r); r.s__ += (-r.H0 - r.H) / sv; SZJ.Mcoord(r.j__, 1, r); r.j__ += (+r.H0 - r.H) / sv; SZJ.Mcoord(r.z__, 0, r); r.z__ += (0 - r.H) / sv; return(r); }
/// <summary> /// 时间串转为小时 /// </summary> /// <param name="s">时间串</param> /// <returns></returns> public static double timeStr2hour(string s) { Regex regexToReplace = new Regex(@"[^0-9:]"); // C#: 匹配字符: 数字0-9, : int a, b, c; string[] timeStr = regexToReplace.Replace(s, "").Split(':'); // C#: 去除无效字符后, 按 : 分隔字符串 for (int i = 0; i < timeStr.Length; i++) // C#: 即使参数 s 为空串, 也会产生一个数组元素 { if (timeStr[i].Length == 0) // C#: 把空串设置为 "0" { timeStr[i] = "0"; } } switch (timeStr.Length) { case 1: { // C#: 为避免 Substring 方法超出范围取子串引发异常, 改用本类中的静态方法 SUBSTRING a = LunarHelper.VAL(LunarHelper.SUBSTRING(timeStr[0], 0, 2), 1); b = LunarHelper.VAL(LunarHelper.SUBSTRING(timeStr[0], 2, 2), 1); c = LunarHelper.VAL(LunarHelper.SUBSTRING(timeStr[0], 4, 2), 1); break; } case 2: { a = LunarHelper.VAL(timeStr[0], 1); b = LunarHelper.VAL(timeStr[1], 1); c = 0; break; } default: { a = LunarHelper.VAL(timeStr[0], 1); b = LunarHelper.VAL(timeStr[1], 1); c = LunarHelper.VAL(timeStr[2], 1); break; } } return(a + b / 60d + c / 3600d); }
/// <summary> /// 提取jd中的时间(去除日期) /// </summary> /// <param name="jd"></param> /// <returns></returns> public static string timeStr(double jd) { double h, m, s; jd += 0.5; jd = (jd - LunarHelper.int2(jd)); jd *= 24; h = LunarHelper.int2(jd); jd -= h; jd *= 60; m = LunarHelper.int2(jd); jd -= m; jd *= 60; s = LunarHelper.int2(jd + 0.5); if (s >= 60) { s -= 60; m++; } if (m >= 60) { m -= 60; h++; } string hStr = "0" + h, mStr = "0" + m, sStr = "0" + s; return(hStr.Substring(hStr.Length - 2, 2) + ':' + mStr.Substring(mStr.Length - 2, 2) + ':' + sStr.Substring(sStr.Length - 2, 2)); }
/// <summary> /// 把太阳月亮信息形成 HTML 字符串 /// </summary> /// <param name="fs">是否显示ΔT, 黄经章等信息</param> /// <returns></returns> public string toHTML(double fs) { StringBuilder sb = new StringBuilder(); sb.Append("<table width='100%' cellspacing=1 cellpadding=0 bgcolor='#FFC0C0'>"); sb.Append("<tr><td bgcolor=white align=center>"); sb.Append("平太阳 " + JD.timeStr(this.pty) + " 真太阳 <font color=red>" + JD.timeStr(this.zty) + "</font><br>"); sb.Append("时差 " + LunarHelper.m2fm(this.sc * 86400, 2, 1) + " 月亮被照亮 " + (this.mIll * 100).ToString("F2") + "% "); sb.Append("</td></tr>"); sb.Append("<tr><td bgcolor=white><center><pre style='margin-top: 0; margin-bottom: 0'><font color=blue><b>表一 月亮 太阳</b></font>\r\n"); sb.Append("视黄经 " + LunarHelper.rad2str(this.mHJ, 0) + " " + LunarHelper.rad2str(this.sHJ, 0) + "\r\n"); sb.Append("视黄纬 " + LunarHelper.rad2str(this.mHW, 0) + " " + LunarHelper.rad2str(this.sHW, 0) + "\r\n"); sb.Append("视赤经 " + LunarHelper.rad2str(this.mCJ, 1) + " " + LunarHelper.rad2str(this.sCJ, 1) + "\r\n"); sb.Append("视赤纬 " + LunarHelper.rad2str(this.mCW, 0) + " " + LunarHelper.rad2str(this.sCW, 0) + "\r\n"); sb.Append("距离 " + this.mR.ToString("F0") + "千米 " + this.sR.ToString("F6") + "AU" + "\r\n"); sb.Append("</pre></center></td></tr>"); sb.Append("<tr><td bgcolor=white><center><pre style='margin-top: 0; margin-bottom: 0'><font color=blue><b>表二 月亮 太阳</b></font>\r\n"); sb.Append("方位角 " + LunarHelper.rad2str(this.mPJ, 0) + " " + LunarHelper.rad2str(this.sPJ, 0) + "\r\n"); sb.Append("高度角 " + LunarHelper.rad2str(this.mPW, 0) + " " + LunarHelper.rad2str(this.sPW, 0) + "\r\n"); sb.Append("时角 " + LunarHelper.rad2str(this.mShiJ, 0) + " " + LunarHelper.rad2str(this.sShiJ, 0) + "\r\n"); sb.Append("视半径(观测点) " + LunarHelper.m2fm(this.mRad, 2, 0) + " " + LunarHelper.m2fm(this.sRad, 2, 0) + "\r\n"); sb.Append("</pre></center></td></tr>"); if (fs != 0) { sb.Append("<tr><td bgcolor=white align=center>"); sb.Append("力学时 " + JD.setFromJD_str(this.T + LunarHelper.J2000)); sb.Append(" ΔT=" + (this.dt * 86400).ToString("F1") + "秒<br>"); sb.Append("黄经章 " + (this.dL / LunarHelper.pi2 * 360 * 3600).ToString("F2") + "\" "); sb.Append("交角章 " + (this.dE / LunarHelper.pi2 * 360 * 3600).ToString("F2") + "\" "); sb.Append("ε=" + LunarHelper.trim(LunarHelper.rad2str(this.E, 0))); sb.Append("</td></tr>"); } sb.Append("</table>"); return(sb.ToString()); }
/// <summary> /// 日期转为串 /// </summary> /// <returns></returns> public static string toStr() { string Y = " " + JD.Y, M = "0" + JD.M, D = "0" + JD.D; double h = JD.h, m = JD.m, s = LunarHelper.int2(JD.s + .5); if (s >= 60) { s -= 60; m++; } if (m >= 60) { m -= 60; h++; } string hStr = "0" + h, mStr = "0" + m, sStr = "0" + s; Y = Y.Substring(Y.Length - 5, 5); M = M.Substring(M.Length - 2, 2); D = D.Substring(D.Length - 2, 2); hStr = hStr.Substring(hStr.Length - 2, 2); mStr = mStr.Substring(mStr.Length - 2, 2); sStr = sStr.Substring(sStr.Length - 2, 2); return(Y + "-" + M + "-" + D + " " + hStr + ":" + mStr + ":" + sStr); }
/// <summary> /// 太阳到中升降时刻计算,传入jd是当地中午12点时间对应的2000年首起算的格林尼治时间UT /// </summary> /// <param name="jd"></param> /// <returns></returns> public static LunarInfoListT <double> St(double jd) { SZJ.dt = JD.deltatT2(jd); SZJ.E = ZB.hcjj(jd / 36525); jd -= LunarHelper.mod2(jd - SZJ.L / LunarHelper.pi2, 1); //查找最靠近当日中午的日上中天,mod2的第1参数为本地时角近似值 LunarInfoListT <double> r = new LunarInfoListT <double>(3, 0d); double sv = LunarHelper.pi2; r.z__ = r.s__ = r.j__ = r.c__ = r.h__ = jd; SZJ.Scoord(jd, 1, 1, r); //太阳坐标 r.s__ += (-r.H0 - r.H) / sv; //升起 r.j__ += (r.H0 - r.H) / sv; //降落 r.c__ += (-r.H1 - r.H) / sv; //民用晨 r.h__ += (r.H1 - r.H) / sv; //民用昏 r.z__ += (0 - r.H) / sv; //中天 SZJ.Scoord(r.s__, 1, 0, r); r.s__ += (-r.H0 - r.H) / sv; SZJ.Scoord(r.j__, 1, 0, r); r.j__ += (+r.H0 - r.H) / sv; SZJ.Scoord(r.c__, 0, 1, r); r.c__ += (-r.H1 - r.H) / sv; SZJ.Scoord(r.h__, 0, 1, r); r.h__ += (+r.H1 - r.H) / sv; SZJ.Scoord(r.z__, 0, 0, r); r.z__ += (0 - r.H) / sv; return(r); }