private void drawClosingLine2(VesselElements ve, double firstx, double firsty, double firstz, double lastx, double lasty, double lastz) { Vector3 First = new Vector3((float)firstx, (float)firsty, (float)firstz); Vector3 Last = new Vector3((float)lastx, (float)lasty, (float)lastz); double[] result = new double[3]; double[] location = new double[3]; for (float i = 0.0f; i <= 1.0f; i += 0.1f) { Vector3 point = Vector3.Slerp(First, Last, i); point.Normalize(); result[0] = point.x; result[1] = point.y; result[2] = point.z; Coordinate.transformICRStoGCS(ve, result, location); if (i == 0.5f) { Debug.Log("First=" + firstx + ":" + firsty + ":" + firstz); Debug.Log("Last=" + lastx + ":" + lasty + ":" + lastz); Debug.Log("result=" + result[0] + ":" + result[1] + ":" + result[2]); Debug.Log("result=" + location[0] + ":" + location[1]); } drawShadowTexture(location[0], location[1], Color.red); } }
//本影・半影の輪郭を計算する。qは角度で与えられる private static void getOutline(VesselElements ve, double l, double tan, double q, double[] result) { if (result.Length != 3) { return; } double x = 0.0; double y = 0.0; double z = 1.0; //zの初期値 double Q = q / 180 * Math.PI; double lastz = 0.0; //前のzの値 double delta = 0.0; double cos_d = Math.Cos(ve.getDeclination() / 180 * Math.PI); double sin_d = Math.Sin(ve.getDeclination() / 180 * Math.PI); double cos_d2 = cos_d * cos_d; int count = 0; while (Math.Abs(z - lastz) > 10e-7)//zが10の-7乗未満に収束しない場合ループ { lastz = z; delta = l - z * tan; x = ve.getX0() + delta * Math.Cos(Q); y = ve.getY0() + delta * Math.Sin(Q); double x2 = x * x; double y2 = y * y; z = (-Constants.e2 * y * cos_d * sin_d + Math.Sqrt((1 - Constants.e2) * (1.0 - x2 - y2 - Constants.e2 * (1.0 - x2) * cos_d2))) / (1.0 - Constants.e2 * cos_d2); if (count++ > 10) { break; //10回を超えたら強制的に打ち切り } } result[0] = x; result[1] = y; result[2] = z; }
//基準面上の半影における点の偏角Qを計算する public static double getPenumbralQ(VesselElements ve, double[] point) { if (point == null || point.Length != 3) { return(Double.NaN); } double delta = ve.getL1() - point[2] * ve.getTanf1(); double Q = Math.Acos((point[0] - ve.getX0()) / delta) / Math.PI * 180.0; if ((point[1] - ve.getY0()) < 0.0) { Q = -Q; //y方向が負ならば角度を反転する。 } if (Q < 0.0) { Q += 360.0; } return(Q); }
//半影と地球外周楕円の交点を計算する public static void getCrossPoint(VesselElements ve, double[] result1, double[] result2) { if (result1.Length != 3 || result2.Length != 3) { return; } double x0 = ve.getX0(); double y0 = ve.getY0(); double l1 = ve.getL1(); double r0 = Math.Sqrt(x0 * x0 + y0 * y0); double theta = Math.Atan2(y0, x0); //ラジアン。変換しない。 double d = ve.getDeclination() / 180.0 * Math.PI; double cos_d = Math.Cos(d); double sin_d = Math.Sin(d); double E2 = (Constants.e2 * cos_d * cos_d) / (1.0 - Constants.e2 * sin_d * sin_d); double rhoplus = 1.0; //初期値 double gammaplus = 0.0; int count = 0; //正の値の近似計算 while (true) { double angle = Math.Acos((r0 * r0 + rhoplus * rhoplus - l1 * l1) / (2.0 * r0 * rhoplus)); //近似計算//正の値 if (angle < 0.0) { angle = -angle; } gammaplus = angle + theta; double newrhoplus = Math.Sqrt((1.0 - E2) / (1.0 - E2 * Math.Cos(gammaplus) * Math.Cos(gammaplus))); double dif = Math.Abs(newrhoplus - rhoplus); rhoplus = newrhoplus; if (dif < 10e-7) { break; } if (count++ > 8) { break; } } double rhominus = 1.0; double gammaminus = 0.0; count = 0; //負の値の近似計算 while (true) { double angle = Math.Acos((r0 * r0 + rhominus * rhominus - l1 * l1) / (2.0 * r0 * rhominus)); //近似計算//正の値 if (angle > 0.0) { angle = -angle; } gammaminus = angle + theta; double newrhominus = Math.Sqrt((1.0 - E2) / (1.0 - E2 * Math.Cos(gammaminus) * Math.Cos(gammaminus))); double dif = Math.Abs(newrhominus - rhominus); rhominus = newrhominus; if (dif < 10e-7) { break; } if (count++ > 8) { break; } } result1[0] = rhoplus * Math.Cos(gammaplus); result1[1] = rhoplus * Math.Sin(gammaplus); result1[2] = 0.0; result2[0] = rhominus * Math.Cos(gammaminus); result2[1] = rhominus * Math.Sin(gammaminus); result2[2] = 0.0; // System.out.println("rhoplus = " + rhoplus + " rhominus =" + rhominus); }
//半影の輪郭を計算する public static void getPenumbralOutline(VesselElements ve, double q, double[] result) { getOutline(ve, ve.getL1(), ve.getTanf1(), q, result); }
//食分を計算する public static void getD(VesselElements ve, double longitude, double latitude, double altitude)//, double[] result) { longitude = longitude / 180.0 * Math.PI; latitude = latitude / 180.0 * Math.PI; //測地緯度と地心緯度の差を計算 double deltalat = 3.3584196 * 0.001 * Math.Sin(2 * latitude) - 5.635 * 0.000001 * Math.Sin(4 * latitude) + 1.7 * Math.Pow(10, -8) * Math.Sin(8 * latitude); //地心直交座標を計算 double sinlat = Math.Sin(latitude); double N = 1 / Math.Sqrt(1 - Constants.e2 * sinlat * sinlat); double u = (N + altitude) * Math.Cos(latitude) * Math.Cos(longitude); double v = (N + altitude) * Math.Cos(latitude) * Math.Sin(longitude); double w = (N * (1.0 - Constants.e2) + altitude) * Math.Sin(latitude); //基準座標 double myu = ve.getMyu(); double d = ve.getDeclination(); double x = u * Math.Sin(myu) + v * Math.Cos(myu); double y = -u *Math.Cos(myu) * Math.Sin(d) + v * Math.Sin(myu) * Math.Sin(d) + w * Math.Cos(d); double z = u * Math.Cos(myu) * Math.Cos(d) - v * Math.Sin(myu) * Math.Cos(d) + w * Math.Sin(d); //r,deltaを計算する double r = Math.Sqrt(x * x + y * y + z * z); double xdiff = x - ve.getX0(); double ydiff = y - ve.getY0(); double delta = Math.Sqrt(xdiff * xdiff + ydiff * ydiff); //cosQ, sinQを計算する double cosQ = xdiff / delta; double sinQ = ydiff / delta; //月の北極方向角を計算する double tanphai = (xdiff / ydiff) + 0.0000426 * xdiff * Math.Tan(d) / (sinQ * sinQ); double moon_angle_to_northpole = Math.Atan(tanphai) / Math.PI * 180; if (moon_angle_to_northpole < 0) { moon_angle_to_northpole += 360; } else if (moon_angle_to_northpole > 360) { moon_angle_to_northpole -= 360; } if (ydiff > 0) { if (moon_angle_to_northpole > 270 | moon_angle_to_northpole < 90) { moon_angle_to_northpole += 180; } } else if (ydiff < 0) { if (moon_angle_to_northpole > 90 & moon_angle_to_northpole < 270) { moon_angle_to_northpole += 180; } } if (moon_angle_to_northpole > 360) { moon_angle_to_northpole -= 360; } //天頂の北極方位角を計算する double tannyu = x / y - delta * latitude * r * x * Math.Cos(d) / (y * y * Math.Cos(latitude)); double zenith_angle_to_northpole = Math.Atan(tannyu) / Math.PI * 180; if (zenith_angle_to_northpole < 0) { zenith_angle_to_northpole += 360; } else if (zenith_angle_to_northpole > 360) { zenith_angle_to_northpole -= 360; } if (y < 0) { if (zenith_angle_to_northpole > 270 | zenith_angle_to_northpole < 90) { zenith_angle_to_northpole += 180; } } else if (y > 0) { if (zenith_angle_to_northpole > 90 & zenith_angle_to_northpole < 270) { zenith_angle_to_northpole += 180; } } if (zenith_angle_to_northpole > 360) { zenith_angle_to_northpole -= 360; } double omega = moon_angle_to_northpole - zenith_angle_to_northpole; if (Math.Abs(omega) > 180) { if (omega < 0) { omega += 360; } else if (omega > 0) { omega -= 360; } } //omega = omega / Math.PI * 180.0; // Debug.Log("omega= " + omega); //食分を求める double D = (ve.getL1() - z * ve.getTanf1() - delta) / (ve.getL1() + ve.getL2() - z * (ve.getTanf1() + ve.getTanf2())); //debug /* * Debug.Log("deltalat = " + deltalat); * Debug.Log("x0 = "+ ve.getX0()); * Debug.Log("y0 = " + ve.getY0()); * Debug.Log("d = " + (ve.getDeclination() / Math.PI * 180.0)); * Debug.Log("l1 = " + ve.getL1()); * Debug.Log("l2 = " + ve.getL2()); * Debug.Log("tanf1 = " + ve.getTanf1()); * Debug.Log("tanf2 = " + ve.getTanf2()); * Debug.Log("myu = " + myu); * Debug.Log("x = " + x); * Debug.Log("y = " + y); * Debug.Log("z = " + z); * Debug.Log("r = " + r); * Debug.Log("delta = " + delta); * Debug.Log("sinQ = " + sinQ); * Debug.Log("(x - x0)/ (y - y0) = " + (xdiff / ydiff)); * Debug.Log("pais(x-x0)tan(d) / sin2 Q = " + (0.0000426 * xdiff * Math.Tan(d) / (sinQ * sinQ))); * Debug.Log("Tan(phai) = " + tanphai); * Debug.Log("phai = " + moon_angle_to_northpole); * Debug.Log("x / y = " + (x / y)); * Debug.Log("delta phai = " + (delta * latitude * r * x * Math.Cos(d) / (y * y * Math.Cos(latitude)))); * Debug.Log("tan(nyu) = " + tannyu); * Debug.Log("nyu = " + zenith_angle_to_northpole); * Debug.Log("omega = " + omega); * Debug.Log("D=" + D); */ //debug終わり }
//画面を更新する(球体地図) public void updateScreen2() { double hinode_keido, hinoiri_keido, asayake, higure; int hinoiriX = 0, hinodeX = 0; int asayakeX = 0, higureX = 0; double x, y; double halfPI = Math.PI / 2.0; //double scrDist = (scrWidth / 2.0) / Math.Tan(scrAngle / 180.0 * Math.PI); //if (screen == null | screen2 == null) return; //イメージを初期化 Color opaque = new Color(0, 0, 0, 0); for (int i = 0; i < shadow.width; i++) { for (int j = 0; j < shadow.height; j++) { shadow.SetPixel(i, j, opaque); } } EquatorialCoordinate sun = new EquatorialCoordinate(); EquatorialCoordinate moon = new EquatorialCoordinate(); double[] result = new double[3]; double[] result2 = new double[3]; double[] location = new double[2]; double asc = 0.0; double dec = 0.0; double moonasc = 0.0; double moondec = 0.0; try { SunAndMoon.getSunRightAscension(utc, result); sun.setRightAscension(result[0]); sun.setCelestialDeclination(result[1]); sun.setDistance(result[2]); asc = result[0]; //赤経 dec = result[1]; //赤緯 SunAndMoon.getMoonRightAscension(utc, result); moon.setRightAscension(result[0]); moon.setCelestialDeclination(result[1]); moon.setDistance(result[2]); moonasc = result[0]; moondec = result[1]; } catch (Exception) { Debug.Log("Exception1 "); return; } double phai0 = Almanac.getGreenidgeSiderealTime(utc);//グリニッジ恒星時 //恒星時をもとに、背景の回転を行う(恒星時は春分点の時角) Material skybox = RenderSettings.skybox; skybox.SetFloat("_Rotation", (float)-phai0);//時角のマイナス方向に回転。skyboxのマテリアルは左右が逆 //太陽位置計算(orbiterと同じコード) { double Theta = phai0 - asc; if (Theta < 0) { Theta += 360.0; } double DegToRad = Math.PI / 180; double denominator = (Math.Sin(dec * DegToRad) * Math.Cos(90.0 * DegToRad) - Math.Cos(dec * DegToRad) * Math.Sin(90.0 * DegToRad) * Math.Cos(Theta * DegToRad)); double A = Math.Atan((-Math.Cos(dec * DegToRad) * Math.Sin(Theta * DegToRad)) / denominator); double h = Math.Asin(Math.Sin(dec * DegToRad) * Math.Sin(90.0 * DegToRad) + Math.Cos(dec * DegToRad) * Math.Cos(90.0 * DegToRad) * Math.Cos(Theta * DegToRad)); A = A / DegToRad; h = h / DegToRad; //Arctanの象限を検討せよ if (denominator > 0) { //何故か解説書とは逆だが、分母が正の時に180度加算して象限を変える必要がある A += 180.0; } Vector3 sunvector = new Vector3(1.0f, 0.0f, 0.0f); sunvector = Quaternion.Euler(0.0f, 0.0f, (float)h) * sunvector; sunvector = Quaternion.Euler(0.0f, (float)A, 0.0f) * sunvector; float ratio = 1500.0f / sunvector.magnitude; sunvector *= ratio; GameObject game = GameObject.Find("Directional Light"); if (game != null) { game.transform.position = sunvector; Vector3 forward = sunvector; forward.Normalize(); game.transform.forward = -forward; } } //日の出・日の入りの同時線を描く double dist = sun.getDistance(); double parallax = SunAndMoon.getSunParallax(dist);//太陽視差 double k = SunAndMoon.getSunriseAltitude(SunAndMoon.getSunDiameter(dist), 0.0, SunAndMoon.refraction, parallax); double celestialdeclination = sun.getCelestialDeclination(); for (int i = -90; i < 90; i++) { //緯度を取得 double latitude = i;//getLatitudeFromY(Yequator - i); //緯度を元に時角を計算する double jikaku = SunAndMoon.getTimeAngle(k, celestialdeclination, latitude); if (!Double.IsNaN(jikaku))//時角がNaNでない { hinode_keido = SunAndMoon.reviseAngle(-jikaku + sun.getRightAscension() - phai0); hinoiri_keido = SunAndMoon.reviseAngle(jikaku + sun.getRightAscension() - phai0); // hinodeX =(int)getXfromLongitude(hinode_keido); // hinoiriX = (int)getXfromLongitude(hinoiri_keido);//昼側か調べる drawShadowTexture(hinode_keido, latitude, Color.white); drawShadowTexture(hinoiri_keido, latitude, Color.white); } } //輪郭の描画 VesselElements ve = new VesselElements(sun, moon, utc); SolarEclipse.getCrossPoint(ve, result, result2); double maxQ = SolarEclipse.getPenumbralQ(ve, result); double minQ = SolarEclipse.getPenumbralQ(ve, result2); //Debug.Log("MaxQ = " + maxQ + " minQ = " + minQ); //月位置計算(orbiterと同じコード) { double Theta = phai0 - moonasc; if (Theta < 0) { Theta += 360.0; } double DegToRad = Math.PI / 180; double denominator = (Math.Sin(moondec * DegToRad) * Math.Cos(90.0 * DegToRad) - Math.Cos(moondec * DegToRad) * Math.Sin(90.0 * DegToRad) * Math.Cos(Theta * DegToRad)); double A = Math.Atan((-Math.Cos(moondec * DegToRad) * Math.Sin(Theta * DegToRad)) / denominator); double h = Math.Asin(Math.Sin(moondec * DegToRad) * Math.Sin(90.0 * DegToRad) + Math.Cos(moondec * DegToRad) * Math.Cos(90.0 * DegToRad) * Math.Cos(Theta * DegToRad)); A = A / DegToRad; h = h / DegToRad; //Arctanの象限を検討せよ if (denominator > 0) { //何故か解説書とは逆だが、分母が正の時に180度加算して象限を変える必要がある A += 180.0; } Vector3 sunvector = new Vector3(1.0f, 0.0f, 0.0f); sunvector = Quaternion.Euler(0.0f, 0.0f, (float)h) * sunvector; sunvector = Quaternion.Euler(0.0f, (float)A, 0.0f) * sunvector; float ratio = (float)(moon.getDistance() * Constants.AUde * 3.16f) / sunvector.magnitude; sunvector *= ratio; // // Debug.Log("moondist = " + moon.getDistance()); GameObject game = GameObject.Find("Moon"); if (game != null) { game.transform.position = sunvector; } } /* Vector3 moonPos = new Vector3((float)ve.getX0(), (float)ve.getY0(), (float)ve.getZ0()); * moonPos.Normalize(); * moonPos *= 20; * GameObject moonobj = GameObject.Find("Moon"); * * if (moonobj!= null) * { * moonobj.transform.position = moonPos; * } */ //半影の描画 if (Double.IsNaN(maxQ) && Double.IsNaN(minQ)) { double first_longitude = Double.NaN; double first_latitude = Double.NaN; double last_longitude = Double.NaN; double last_latitude = Double.NaN; for (double i = 0.0; i <= 360.0; i += 0.2) { SolarEclipse.getPenumbralOutline(ve, i, result); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { continue; //NaNが含まれていたらスキップする } if (first_longitude == double.NaN | first_latitude == double.NaN) { first_longitude = result[0]; first_latitude = result[1]; } last_longitude = result[0]; last_latitude = result[1]; Coordinate.transformICRStoGCS(ve, result, location); drawShadowTexture(location[0], location[1], Color.red); } //Debug.Log(first_longitude + ":" + first_latitude + "::" + last_longitude + ":" + last_latitude); } else if (!Double.IsNaN(maxQ) && !Double.IsNaN(minQ)) { double first_x = double.NaN; double first_y = double.NaN; double first_z = double.NaN; double last_x = double.NaN; double last_y = double.NaN; double last_z = double.NaN; if ((maxQ - minQ) >= 0.0) { maxQ -= 360.0; } SolarEclipse.getPenumbralOutline(ve, maxQ, result); Coordinate.transformICRStoGCS(ve, result, location); //Debug.Log("MaxQ :" + location[0] + ":" + location[1]+ ":" + maxQ); SolarEclipse.getPenumbralOutline(ve, minQ, result); Coordinate.transformICRStoGCS(ve, result, location); //Debug.Log("MinQ :" + location[0] + ":" + location[1] + ":" + minQ); /* * //maxQが通常の計算でNaNとなる場合に備えて、強制的に描画する。 * SolarEclipse.getPenumbralOutline(ve, maxQ, result); * result[2] = -0.01;//強制的に基準面に設定する * Coordinate.transformICRStoGCS(ve, result, location); * drawShadowTexture(location[0], location[1], Color.black); */ for (double i = maxQ /*Math.Ceiling(maxQ)*/; i < minQ; i += 0.2) { SolarEclipse.getPenumbralOutline(ve, i, result); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { continue; //NaNが含まれていたらスキップする } if (Double.IsNaN(first_x) | Double.IsNaN(first_y) | Double.IsNaN(first_z)) { first_x = result[0]; first_y = result[1]; first_z = result[2]; } last_x = result[0]; last_y = result[1]; last_z = result[2]; Coordinate.transformICRStoGCS(ve, result, location); drawShadowTexture(location[0], location[1], Color.red); } { SolarEclipse.getPenumbralOutline(ve, minQ, result); if (!Double.IsNaN(result[0]) & !Double.IsNaN(result[1]) & !Double.IsNaN(result[2])) { Coordinate.transformICRStoGCS(ve, result, location); last_x = result[0]; last_y = result[2]; last_z = result[1]; drawShadowTexture(location[0], location[1], Color.red); } } //drawClosingLine2(ve, first_x, first_y, first_z, last_x, last_y, last_z); //Debug.Log(first_longitude + ":" + first_latitude + "::" + last_longitude + ":" + last_latitude); /* * //minQが通常の計算でNaNとなる場合に備えて、強制的に描画する。 * SolarEclipse.getPenumbralOutline(ve, minQ, result); * result[2] = -0.01;//強制的に基準面に設定する * Coordinate.transformICRStoGCS(ve, result, location); * drawShadowTexture(location[0], location[1], Color.red); */ } //本影の描画 for (int i = 0; i <= 360; i += 5) { SolarEclipse.getUmbralOutline(ve, (double)i, result); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { continue; //NaNが含まれていたらスキップする } Coordinate.transformICRStoGCS(ve, result, location); drawShadowTexture(location[0], location[1], Color.black); } GameObject earthobj = GameObject.Find("perfectsphere"); Material[] mats = earthobj.GetComponent <Renderer>().materials; Debug.Log("elements =" + mats.Length); mats[0].SetTexture("_MainTex", (Texture)shadow); //mats[1].SetTexture("_EmissionMap", shadow); //repaint(); }
public void drawLines() { //テクスチャ初期化 Color opaque = new Color(0, 0, 0, 0); for (int i = 0; i < shadow.width; i++) { for (int j = 0; j < shadow.height; j++) { shadow.SetPixel(i, j, opaque); } } EquatorialCoordinate sun = new EquatorialCoordinate(); EquatorialCoordinate moon = new EquatorialCoordinate(); double[] result = new double[3]; double[] result2 = new double[3]; double[] location = new double[2]; double asc = 0.0; double dec = 0.0; double moonasc = 0.0; double moondec = 0.0; try { SunAndMoon.getSunRightAscension(utc, result); sun.setRightAscension(result[0]); sun.setCelestialDeclination(result[1]); sun.setDistance(result[2]); asc = result[0]; //赤経 dec = result[1]; //赤緯 SunAndMoon.getMoonRightAscension(utc, result); moon.setRightAscension(result[0]); moon.setCelestialDeclination(result[1]); moon.setDistance(result[2]); moonasc = result[0]; moondec = result[1]; } catch (Exception) { Debug.Log("Exception1 "); return; } double phai0 = Almanac.getGreenidgeSiderealTime(utc);//グリニッジ恒星時 //太陽位置を計算してライトの位置と向きを変更する { //恒星時をもとに、背景の回転を行う(恒星時は春分点の時角) Material skybox = RenderSettings.skybox; skybox.SetFloat("_Rotation", (float)-phai0);//時角のマイナス方向に回転。skyboxのマテリアルは左右が逆 //赤緯・赤経は北極から見て時計回り。自覚、恒星時は反時計回り。時角に合わせて計算する //float ramda = -(float)((-asc + phai0) * DegToRad);これを書き換えて下の式になる float ramda = (float)((asc - phai0) * DegToRad); float psy = (float)(dec * DegToRad); float sundistance = 400; float x = Mathf.Cos(psy) * Mathf.Cos(ramda) * sundistance; float y = Mathf.Cos(psy) * Mathf.Sin(ramda) * sundistance; float z = Mathf.Sin(psy) * sundistance; GameObject light = GameObject.Find("Directional Light"); Vector3 sunpos = light.transform.position; sunpos.Set(x, z, y); light.transform.position = sunpos; sunpos.Normalize(); sunpos *= -1; light.transform.forward = sunpos; } /* * //日の出・日の入りの同時線を描く * { * double dist = sun.getDistance(); * double parallax = SunAndMoon.getSunParallax(dist);//太陽視差 * double k = SunAndMoon.getSunriseAltitude(SunAndMoon.getSunDiameter(dist), 0.0, SunAndMoon.refraction, parallax); * double celestialdeclination = sun.getCelestialDeclination(); * * for (int i = -90; i < 90; i++) * { * //緯度を取得 * double latitude = i;//getLatitudeFromY(Yequator - i); * * //緯度を元に時角を計算する * double jikaku = SunAndMoon.getTimeAngle(k, celestialdeclination, latitude); * * if (!Double.IsNaN(jikaku))//時角がNaNでない * { * double hinode_keido = SunAndMoon.reviseAngle(-jikaku + sun.getRightAscension() - phai0); * double hinoiri_keido = SunAndMoon.reviseAngle(jikaku + sun.getRightAscension() - phai0); * // hinodeX =(int)getXfromLongitude(hinode_keido); * // hinoiriX = (int)getXfromLongitude(hinoiri_keido);//昼側か調べる * drawShadowTexture(hinode_keido, latitude, Color.white); * drawShadowTexture(hinoiri_keido, latitude, Color.white); * } * } * } */ //輪郭の描画 //ベッセル数 VesselElements ve = new VesselElements(sun, moon, utc); SolarEclipse.getCrossPoint(ve, result, result2); //月影と地球外円との交点を調べる double maxQ = SolarEclipse.getPenumbralQ(ve, result); double minQ = SolarEclipse.getPenumbralQ(ve, result2); //Debug.Log("MaxQ = " + maxQ + " minQ = " + minQ); //半影の描画 if (Double.IsNaN(maxQ) && Double.IsNaN(minQ)) { //交点が存在しない場合。月影がすべて地球上に投射されている。 double first_longitude = Double.NaN; double first_latitude = Double.NaN; double last_longitude; double last_latitude; Color gray = new Color(0, 0, 0, 0.4f); //初期の点 SolarEclipse.getPenumbralOutline(ve, 0.0, result); Coordinate.transformICRStoGCS(ve, result, location); last_longitude = location[0]; last_latitude = location[1]; bool fill = true; for (double i = 1.0; i <= 360.0; i += 1.0) { SolarEclipse.getPenumbralOutline(ve, i, result2); if (Double.IsNaN(result2[0]) | Double.IsNaN(result2[1]) | Double.IsNaN(result2[2])) { fill = false; continue;//NaNが含まれていたらスキップする } Coordinate.transformICRStoGCS(ve, result2, location); // drawShadowTexture(location[0], location[1], gray); //Debug.Log("i=" + i + ":" +location[0] + ":" + location[1]); drawOutline(last_longitude, last_latitude, location[0], location[1], Color.red); last_longitude = location[0]; last_latitude = location[1]; } if (fill) { fillShadow(last_longitude - 2, last_latitude, shadow, gray); } /* * byte[] pngData = shadow.EncodeToPNG(); // pngのバイト情報を取得. * * // ファイルダイアログの表示. * string filePath = EditorUtility.SaveFilePanel("Save Texture", "", shadow.name + ".png", "png"); * * if (filePath.Length > 0) * { * // pngファイル保存. * File.WriteAllBytes(filePath, pngData); * } */ //Debug.Log(first_longitude + ":" + first_latitude + "::" + last_longitude + ":" + last_latitude); } else if (!Double.IsNaN(maxQ) && !Double.IsNaN(minQ))//交点が存在する { double first_x = double.NaN; double first_y = double.NaN; double first_z = double.NaN; double last_x = double.NaN; double last_y = double.NaN; double last_z = double.NaN; Color gray = new Color(0, 0, 0, 0.4f); if ((maxQ - minQ) >= 0.0) { maxQ -= 360.0; } SolarEclipse.getPenumbralOutline(ve, maxQ, result); Coordinate.transformICRStoGCS(ve, result, location); //Debug.Log("MaxQ :" + location[0] + ":" + location[1]+ ":" + maxQ); SolarEclipse.getPenumbralOutline(ve, minQ, result); Coordinate.transformICRStoGCS(ve, result, location); //Debug.Log("MinQ :" + location[0] + ":" + location[1] + ":" + minQ); /* * //maxQが通常の計算でNaNとなる場合に備えて、強制的に描画する。 * SolarEclipse.getPenumbralOutline(ve, maxQ, result); * result[2] = -0.01;//強制的に基準面に設定する * Coordinate.transformICRStoGCS(ve, result, location); * drawShadowTexture(location[0], location[1], Color.black); */ for (double i = maxQ /*Math.Ceiling(maxQ)*/; i < minQ; i += 0.2) { SolarEclipse.getPenumbralOutline(ve, i, result); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { continue; //NaNが含まれていたらスキップする } if (Double.IsNaN(first_x) | Double.IsNaN(first_y) | Double.IsNaN(first_z)) { first_x = result[0]; first_y = result[1]; first_z = result[2]; } last_x = result[0]; last_y = result[1]; last_z = result[2]; Coordinate.transformICRStoGCS(ve, result, location); drawShadowTexture(location[0], location[1], gray); } { SolarEclipse.getPenumbralOutline(ve, minQ, result); if (!Double.IsNaN(result[0]) & !Double.IsNaN(result[1]) & !Double.IsNaN(result[2])) { Coordinate.transformICRStoGCS(ve, result, location); last_x = result[0]; last_y = result[2]; last_z = result[1]; drawShadowTexture(location[0], location[1], gray); } } } //本影の描画 for (int i = 0; i <= 360; i += 5) { SolarEclipse.getUmbralOutline(ve, (double)i, result); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { continue; //NaNが含まれていたらスキップする } Coordinate.transformICRStoGCS(ve, result, location); drawShadowTexture(location[0], location[1], Color.black); } // shadow.Apply(); }
public static void transformICRStoGCS(VesselElements ve, double[] point, double[] result) { if (result.Length != 2) { return; } double d = ve.getDeclination();//ラジアン //変換行列を生成(縦配置) double[][] transmatrix = new double[][] { new double[3], new double[3], new double[3] }; double[] coordinate1 = new double[] { point[0], point[1], point[2] }; double[] coordinate2 = new double[3]; double angle = d - (Math.PI / 2.0); transmatrix[0][0] = 1.0; transmatrix[0][1] = 0.0; transmatrix[0][2] = 0.0; transmatrix[1][0] = 0.0; transmatrix[1][1] = Math.Cos(angle); transmatrix[1][2] = -Math.Sin(angle); transmatrix[2][0] = 0.0; transmatrix[2][1] = Math.Sin(angle); transmatrix[2][2] = Math.Cos(angle); Matrix.multiplication31type2(transmatrix, coordinate1, coordinate2); angle = (ve.getGreenidgeSiderealTime() / 180.0 * Math.PI) - ve.getAscension() - (Math.PI / 2.0); transmatrix[0][0] = Math.Cos(angle); transmatrix[0][1] = -Math.Sin(angle); transmatrix[0][2] = 0.0; transmatrix[1][0] = Math.Sin(angle); transmatrix[1][1] = Math.Cos(angle); transmatrix[1][2] = 0.0; transmatrix[2][0] = 0.0; transmatrix[2][1] = 0.0; transmatrix[2][2] = 1.0; Matrix.multiplication31type2(transmatrix, coordinate2, coordinate1); result[0] = Math.Atan2(coordinate1[1], coordinate1[0]) / Math.PI * 180.0; //経度 //緯度を求める double denominator = Math.Sqrt(coordinate1[0] * coordinate1[0] + coordinate1[1] * coordinate1[1]); //root(u* u + v* v); double coequation1 = coordinate1[2] / denominator; double coequation2 = Constants.e2 / denominator; double tan_phai = coequation1; double lasttan_phai = -tan_phai;//tan_phaiと一致させないための工夫。 int count = 0; while (Math.Abs(tan_phai - lasttan_phai) > 10e-7) { lasttan_phai = tan_phai; tan_phai = coequation1 + coequation2 * (lasttan_phai / Math.Sqrt(1.0 + (1.0 - Constants.e2) * lasttan_phai * lasttan_phai)); if (count++ > 10) { break; } } result[1] = Math.Atan(tan_phai) / Math.PI * 180.0; //緯度 }
//地球に写る月の影の輪郭を描く public void drawLines(DateTime utc) { EquatorialCoordinate sun = new EquatorialCoordinate(); EquatorialCoordinate moon = new EquatorialCoordinate(); double[] result = new double[3]; double[] result2 = new double[3]; double[] dataset = new double[7]; double[] location = new double[2]; double asc = 0.0; double dec = 0.0; double moonasc = 0.0; double moondec = 0.0; double phai0; if (mode == PLAYMODE) { dataholder.getPositions(utc, dataset); asc = dataset[0]; dec = dataset[1]; sun.setRightAscension(dataset[0]); sun.setCelestialDeclination(dataset[1]); sun.setDistance(dataset[2]); moon.setRightAscension(dataset[3]); moon.setCelestialDeclination(dataset[4]); moon.setDistance(dataset[5]); moonasc = dataset[3]; moondec = dataset[4]; phai0 = dataset[6]; } else if (mode == RECORDMODE) { try { SunAndMoon.getSunRightAscension(utc, result); asc = result[0]; dec = result[1]; sun.setRightAscension(result[0]); sun.setCelestialDeclination(result[1]); sun.setDistance(result[2]); SunAndMoon.getMoonRightAscension(utc, result); moon.setRightAscension(result[0]); moon.setCelestialDeclination(result[1]); moon.setDistance(result[2]); moonasc = result[0]; moondec = result[1]; } catch (Exception) { /* Debug.Log("Exception1 ");*/ return; } phai0 = Almanac.getGreenidgeSiderealTime(utc);//グリニッジ恒星時 //記録する dataholder.setPositions(asc, dec, sun.getDistance(), moonasc, moondec, moon.getDistance(), phai0, utc); } else { return; } //輪郭の描画 //ベッセル数 VesselElements ve = new VesselElements(sun, moon, utc); // SolarEclipse.getD(ve, 143.009267, 42.7396185, 0); SolarEclipse.getCrossPoint(ve, result, result2); //月影と地球外円との交点を調べる double maxQ = SolarEclipse.getPenumbralQ(ve, result); double minQ = SolarEclipse.getPenumbralQ(ve, result2); //Debug.Log("MaxQ = " + maxQ + " minQ = " + minQ); //半影の描画 if (Double.IsNaN(maxQ) && Double.IsNaN(minQ)) { clearTexture(); //交点が存在しない場合。月影がすべて地球上に投射されている。 double last_longitude; double last_latitude; Color gray = new Color(0, 0, 0, 0.4f); //初期の点 SolarEclipse.getPenumbralOutline(ve, 0.0, result); Coordinate.transformICRStoGCS(ve, result, location); last_longitude = location[0]; last_latitude = location[1]; double max_lat = -90, min_lat = 90; double east_lon = location[0]; double west_lon = double.NaN; //bool for (double i = 1.0; i <= 360.0; i += 1.0) { SolarEclipse.getPenumbralOutline(ve, i, result2); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { continue;//NaNが含まれていたらスキップする } Coordinate.transformICRStoGCS(ve, result2, location); if (double.IsNaN(location[0]) | double.IsNaN(location[1])) { continue; } //値の取得で例外が発生したら、処理をスキップする try { drawOutline(last_longitude, last_latitude, location[0], location[1], shadow, sunoutline); } catch (Exception ex) { continue; } last_longitude = location[0]; last_latitude = location[1]; if (i == 180.0) { west_lon = location[0]; } if (max_lat < last_latitude) { max_lat = last_latitude; } if (min_lat > last_latitude) { min_lat = last_latitude; } } if (!double.IsNaN(west_lon) & !double.IsNaN(east_lon)) { if (west_lon > east_lon) { east_lon += 360.0; } Point paintpoint = getScreenPoint((east_lon + west_lon) / 2, (max_lat + min_lat) / 2); fillShadowEx(paintpoint.x, paintpoint.y, shadow, shadowcolor); // Debug.Log("west= " + west_lon + " east=" +east_lon) ; } } else if (!Double.IsNaN(maxQ) && !Double.IsNaN(minQ))//交点が存在する { double first_longitude; double first_latitude; double last_longitude; double last_latitude; clearTexture(); Color gray = new Color(0, 0, 0, 0.4f); if ((maxQ - minQ) >= 0.0) { maxQ -= 360.0; } SolarEclipse.getPenumbralOutline(ve, maxQ, result); Coordinate.transformICRStoGCS(ve, result, location); //Debug.Log("MaxQ :" + location[0] + ":" + location[1]+ ":" + maxQ); SolarEclipse.getPenumbralOutline(ve, minQ, result); Coordinate.transformICRStoGCS(ve, result, location); //初期の点 double delta = 0.0; while (true) { SolarEclipse.getPenumbralOutline(ve, maxQ + delta, result); if (Double.IsNaN(result[0]) | Double.IsNaN(result[1]) | Double.IsNaN(result[2])) { delta += 0.1; } else { break; } if (delta > 5.0) { break; } } Coordinate.transformICRStoGCS(ve, result, location); first_longitude = last_longitude = location[0]; first_latitude = last_latitude = location[1]; // double max_lon = 0, max_lat = -90, min_lon = 360, min_lat = 90; for (double i = maxQ + delta + 0.5; i < minQ; i += 0.5) { SolarEclipse.getPenumbralOutline(ve, i, result2); if (Double.IsNaN(result2[0]) | Double.IsNaN(result2[1]) | Double.IsNaN(result2[2])) { continue;//NaNが含まれていたらスキップする } Coordinate.transformICRStoGCS(ve, result2, location); //値の取得で例外が発生したら、処理をスキップする if (double.IsNaN(location[0]) | double.IsNaN(location[1])) { continue; } try { drawOutline(last_longitude, last_latitude, location[0], location[1], shadow, sunoutline); } catch (Exception e) { continue; } last_longitude = location[0]; last_latitude = location[1]; } SolarEclipse.getPenumbralOutline(ve, minQ, result); if (!Double.IsNaN(result[0]) & !Double.IsNaN(result[1]) & !Double.IsNaN(result[2])) { Coordinate.transformICRStoGCS(ve, result, location); if (!double.IsNaN(location[0]) & !double.IsNaN(location[1])) { drawOutline(last_longitude, last_latitude, location[0], location[1], shadow, sunoutline); last_longitude = location[0]; last_latitude = location[1]; } } //同時線を描く { //日の出・日の入りの同時線を描く int alllength = getSunLine(sun, phai0); //終点から同時線までの最短の線を描く Point pnt = getScreenPoint(last_longitude, last_latitude); double leastdistance = double.MaxValue; int finishindex = -1; //終点と最も近い点のインデックス if (pnt.x < 0) { pnt.x += shadow.width; } else if (pnt.x >= shadow.width) { pnt.x -= shadow.width; } if (pnt.y < 0) { pnt.y = 0; } else if (pnt.y >= shadow.width) { pnt.y = shadow.width; } for (int i = 0; i < alllength; i++) { double xdiff = Math.Abs(pnt.x - sunline[i * 2]); if (xdiff > shadow.width / 2) { xdiff = shadow.width - xdiff; } double ydiff = pnt.y - sunline[i * 2 + 1]; double length = Math.Sqrt(xdiff * xdiff + ydiff * ydiff); if (length < leastdistance) { leastdistance = length; finishindex = i; } } if (finishindex != -1 & leastdistance != double.MaxValue) { if (!double.IsNaN(last_longitude) & !double.IsNaN(last_latitude)) { drawScreenOutline(pnt.x, pnt.y, sunline[finishindex * 2], sunline[finishindex * 2 + 1], sunoutline); } } //開始点から同時線までの最短の線を描く pnt = getScreenPoint(first_longitude, first_latitude); leastdistance = double.MaxValue; int startindex = -1; //始点と最も近い点のインデックス if (pnt.x < 0) { pnt.x += shadow.width; } else if (pnt.x >= shadow.width) { pnt.x -= shadow.width; } if (pnt.y < 0) { pnt.y = 0; } else if (pnt.y >= shadow.width) { pnt.y = shadow.width; } for (int i = 0; i < alllength; i++) { double xdiff = Math.Abs(pnt.x - sunline[i * 2]); if (xdiff > shadow.width / 2) { xdiff = shadow.width - xdiff; } double ydiff = pnt.y - sunline[i * 2 + 1]; double length = Math.Sqrt(xdiff * xdiff + ydiff * ydiff); if (length < leastdistance) { leastdistance = length; startindex = i; } } if (startindex != -1 & leastdistance != double.MaxValue) { if (!double.IsNaN(last_longitude) & !double.IsNaN(last_latitude)) { drawScreenOutline(pnt.x, pnt.y, sunline[startindex * 2], sunline[startindex * 2 + 1], sunoutline); } } //判定を正確にするため、同時線は最後に描く。alllengthは要素数だから、マイナスしない for (int i = 0; i < alllength; i++) { drawScreenPixel(sunline[i * 2], sunline[i * 2 + 1], boundscolor); } //影の中を塗る int middlepoint = -1; if (Math.Abs(finishindex - startindex) > (alllength / 2)) { middlepoint = (finishindex + startindex + alllength) / 2; if (middlepoint >= alllength) { middlepoint -= alllength; } else if (middlepoint < 0) { middlepoint += alllength; } } else { middlepoint = (finishindex + startindex) / 2; } getInnerPoint(sunline[middlepoint * 2], sunline[middlepoint * 2 + 1], shadow);//塗の指示 }//同時線の描画の終わり } //半影の描画の終わり else if (!Double.IsNaN(maxQ) | !Double.IsNaN(minQ)) /*Debug.Log("minQ or maxQ is NaN");*/ } {