// Update is called once per frame void Update() { if (menuvisible | helpvisible | chooser.enabled) { return; } //処理開始 interval += Time.deltaTime; if (interval > 0.1f & ready & !chooser.getEnabled()) { //終了時刻よりあとの時刻か if (current.CompareTo(finish) > 0) { if (shadowrenderer.getMode() == UmbralShadowRenderer.RECORDMODE) { String filename = EclipseCalendar.getDateString(start.Year, start.Month, start.Day); currenteclipsedata.writeJSON(filename + ".json"); saveTexture(filename, result); if (umbralshadow != null) { saveTexture(filename + "_umbra", umbralshadow); } return; ready = false; interval = 0.0f; } else if (shadowrenderer.getMode() == UmbralShadowRenderer.PLAYMODE) { current = new DateTime(start.Year, start.Month, start.Day, start.Hour, start.Minute, 0, DateTimeKind.Utc); } } clock.setTime(current); //影描画 shadowrenderer.drawLines(current); //テクスチャに結果を描き込む if (shadowrenderer.getMode() == UmbralShadowRenderer.RECORDMODE) { writeResult(earthshadow, result); } //地球の昼夜を描く currenteclipsedata.getPositions(current, posdata); shadowrenderer.drawNightSide(posdata); earthshadow.Apply(); //時間を一つ進める current = current.AddMinutes(1.0); interval = 0.0f; } if (Application.platform == RuntimePlatform.Android & !chooser.enabled & !helpvisible) { // エスケープキー取得 if (Input.GetKeyDown(KeyCode.Escape)) { // アプリケーション終了処理 Application.Quit(); return; } } }
void Update() { //画角値の確認 if (!calibrated) { if (Calibration.calibrated) { horizontalFOV = Calibration.horizontal; verticalFOV = Calibration.vertical; calibrated_orientation = (int)Calibration.deviceOrientation; appdata.HorizontalAngle = horizontalFOV; appdata.VerticalAngle = verticalFOV; appdata.saveApplicationData(); calibrated = true; } else { #if UNITY_ANDROID // Javaのオブジェクトを作成 AndroidJavaClass nativeDialog = new AndroidJavaClass("studio.beautifulworld.dialoglibrary.MenuDialog"); // Context(Activity)オブジェクトを取得する AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); AndroidJavaObject context = unityPlayer.GetStatic <AndroidJavaObject>("currentActivity"); // AndroidのUIスレッドで動かす context.Call("runOnUiThread", new AndroidJavaRunnable(() => { // ダイアログ表示のstaticメソッドを呼び出す nativeDialog.CallStatic( "showMessages", context, "お知らせ", "画角の値が記録されていません。\nキャリブレーションを実行します。"); })); #endif moveToCalibration(); } } //データ選択・又は地点選択の場合、以後の処理はしない if (chooser.enabled | pointchooser.enabled | helpvisible) { return; } //処理開始 interval += Time.deltaTime; if (interval > 0.1f & ready) { currenteclipsedata.getPositions(current, posdata); clock.setTime(current); if (!Input.location.isEnabledByUser) { state = LOCATION_UNAVAILABLE; } else { LocationInfo locinfo = Input.location.lastData; magnetism = false; if (locinfo.longitude > 122.5f & locinfo.longitude <150.0f& locinfo.latitude> 23.0f & locinfo.latitude < 45.5f) { magnetism = true; //磁気偏角計算 float declination_angle = TerrestrialMagnetism.getMagneticDeclination(locinfo.longitude, locinfo.latitude); declination = Quaternion.Euler(0.0f, declination_angle, 0.0f); } float height = 0;//高度 if (locationmode == CURRENT_LOCATION) { longitude = locinfo.longitude; latitude = locinfo.latitude; height = locinfo.altitude; } float[,] matrix = caliculation.getMatrix(longitude, latitude, height); float[,] inverse = caliculation.getInverseMatrix(matrix); //debug /* * //分、秒を含めて時間で表す * double hour = current.Hour +9+ current.Minute / 60.0 + current.Second / 3600.0; * double T = StarPosition.getTime(current.Year, current.Month, current.Day, hour); * //太陽の黄経を計算するelon:ecliptic longitude * double elon = StarPosition.getSunEclipticLongitude(T); * //黄道傾角を計算する * double e = StarPosition.getInclination(T);// * //太陽の赤経に変換 * double asc = StarPosition.getRightAscension(elon, e);// * //太陽の赤緯に変換 * double dec = StarPosition.getDeclination(elon, e);// //恒星時を計算する * double phai0 = StarPosition.getSidereal(T, hour / 24.0, longitude);//経過時間を引く必要があるので時間を別に与える */ //食分計算 //VesselElements ve = new VesselElements(posdata[EclipseData.SUN_ASC], posdata[EclipseData.SUN_DEC], posdata[EclipseData.SUN_DIST], //posdata[EclipseData.MOON_ASC], posdata[EclipseData.MOON_DEC], posdata[EclipseData.MOON_DIST], current); double phai = posdata[EclipseData.PHAI] + longitude;// longitude;//地方恒星時=グリニッジ恒星時+経度。恒星時は反時計回り、経度は時計回り //太陽の方位・高度を計算する sun_direction = StarPosition.getSunDirection(posdata[EclipseData.SUN_ASC], posdata[EclipseData.SUN_DEC], latitude, phai); sun_altitude = StarPosition.getSunAltitude(posdata[EclipseData.SUN_ASC], posdata[EclipseData.SUN_DEC], latitude, phai); //コンパス空間に写像する //太陽の方向ベクトルを求める double sunz = Math.Sin(sun_altitude / RadToDeg); double suny = Math.Cos(sun_altitude / RadToDeg); double sunx = suny * Math.Cos((90.0 - sun_direction) / RadToDeg); suny = suny * Math.Sin((90.0 - sun_direction) / RadToDeg); double[] sun_vector = new double[] { sunx, suny, sunz };//角度から算出したベクトルなので、現在位置は引く必要はない //太陽への方向ベクトル単位化 double norm = Math.Sqrt(sun_vector[0] * sun_vector[0] + sun_vector[1] * sun_vector[1] + sun_vector[2] * sun_vector[2]); sun_vector[0] /= norm; sun_vector[1] /= norm; sun_vector[2] /= norm; //太陽の方向が地平線の下 if (sun_vector[2] < 0.0f) { state = UNDER_HORIZON; } else { //デバイスの向きを検出する Quaternion gyro = Input.gyro.attitude; camrotation.Set(-gyro.x, -gyro.y, gyro.z, gyro.w); camrotation = Quaternion.Euler(90.0f, 0.0f, 0.0f) * camrotation; //向き検出・終わり //デバイス座標系に変換 Quaternion inverseQ = Quaternion.Inverse(camrotation); Vector3[] sunandmoon = new Vector3[2]; sunandmoon[0] = inverseQ * new Vector3((float)sun_vector[0], (float)sun_vector[2], (float)sun_vector[1]); //sunandmoon[1] = inverseQ * new Vector3((float)moon_vector[0], (float)moon_vector[2], (float)moon_vector[1]); //最後に有効になったデバイス向きを取得する DeviceOrientation orientation = camview.getLastOrienation(); //画角とタンジェント値を得る float[] viewangles = new float[2]; getViewAngle(orientation, viewangles); float verticalFOV = viewangles[1] / RadToDeg; float horizontalFOV = viewangles[0] / RadToDeg; float screen_tangent_horizontal = Mathf.Tan(horizontalFOV); float screen_tangent_vertical = Mathf.Tan(verticalFOV); float ratio = 0.5f / (screen_tangent_vertical * 2); for (int i = 0; i < 1; i++) { //磁気補正 if (magnetism) { sunandmoon[i] = declination * sunandmoon[i]; } //後ろの場合も見えないので、手順をスキップする。 float x_angle = Mathf.Atan(sunandmoon[i].x / sunandmoon[i].z); float y_angle = Mathf.Atan(sunandmoon[i].y / sunandmoon[i].z); if (Mathf.Abs(x_angle) < horizontalFOV & Mathf.Abs(y_angle) < verticalFOV & sunandmoon[i].z > 0) { float screenX = Mathf.Tan(x_angle) / screen_tangent_horizontal * Screen.width / 2 + Screen.width / 2 - images[SUNIMAGE].width / 2; float screenY = Screen.height / 2 - Mathf.Tan(y_angle) / screen_tangent_vertical * Screen.height / 2 - images[SUNIMAGE].height / 2; //datas.targetposition.Set(x, y, targetbox.width, targetbox.height); switch (i) { case 0: state = INSIDE_SCREEN; sunrect.Set(screenX, screenY, images[SUNIMAGE].width * ratio, images[SUNIMAGE].height * ratio); break; //case 1: moonSeeable = true; moonrect.Set(screenX, screenY, moonbox.width * ratio, moonbox.height * ratio); break; } blink = true; blinkinterval = 0.0f; } else { state = OUTSIDE_SCREEN; //太陽の位置を示すアイコンを決める getGuideImage(sunandmoon[0]); } }//for終わり } //デバイス座標系に変換・終わり } //時間を一つ進める current = current.AddMinutes(1.0); //終了時刻よりあとの時刻か if (current.CompareTo(finish) > 0) { current = new DateTime(start.Year, start.Month, start.Day, start.Hour, start.Minute, 0, DateTimeKind.Utc); } // interval = 0.0f; } //アプリケーションの終了 if (Application.platform == RuntimePlatform.Android) { // エスケープキー取得 if (Input.GetKeyDown(KeyCode.Escape)) { Input.gyro.enabled = false; Input.location.Stop(); Input.compass.enabled = false; // アプリケーション終了処理 Application.Quit(); return; } } }
//地球に写る月の影の輪郭を描く 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");*/ } {
// Update is called once per frame void Update() { if (datachooser.enabled | helpvisible) { return; } //処理開始 interval += Time.deltaTime; if (interval > 0.1f & ready) { currenteclipsedata.getPositions(current, posdata); //影描画 shadowrenderer.drawLines(current); earthshadow.Apply(); //時計に時間を通知 clock.setTime(current); //太陽位置を計算してライトの位置と向きを変更する { //恒星時をもとに、背景の回転を行う(恒星時は春分点の時角) Material skybox = RenderSettings.skybox; skybox.SetFloat("_Rotation", (float)-posdata[EclipseData.PHAI]);//時角のマイナス方向に回転。skyboxのマテリアルは左右が逆 //赤緯・赤経は北極から見て時計回り。時角、恒星時は反時計回り。時角に合わせて計算する //float ramda = -(float)((-asc + phai0) * DegToRad);これを書き換えて下の式になる float ramda = (float)((posdata[EclipseData.SUN_ASC] - posdata[EclipseData.PHAI]) * DegToRad); float psy = (float)(posdata[EclipseData.SUN_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; Vector3 sunpos = sunlight.transform.position; sunpos.Set(x, z, y); sunlight.transform.position = sunpos; sunpos.Normalize(); sunpos *= -1; sunlight.transform.forward = sunpos; } //時間を一つ進める current = current.AddMinutes(1.0); //終了時刻よりあとの時刻か if (current.CompareTo(finish) > 0) { current = new DateTime(start.Year, start.Month, start.Day, start.Hour, start.Minute, 0, DateTimeKind.Utc); } interval = 0.0f; } //ピンチ操作 //タッチによるスワイプを取得する //画面の縮小拡大を取得する if (Application.platform == RuntimePlatform.Android) { if (Input.touchCount == 0) { //windows の場合はコメントアウト if (pinch) { pinch = false; } if (pressed) { pressed = false; } } else if (Input.touchCount == 1 & lastTouchCount > 1) { if (pinch) { pinch = false; } Touch[] touches = Input.touches; Vector2 fingerpos = touches[0].position; lastx = fingerpos.x; lasty = fingerpos.y; //画面は左上が原点、マウスは左下が原点。なぜかタッチは左上原点のようだ。 pressed = true; lastTouchCount = Input.touchCount; } else if (Input.touchCount > 1) { if (pressed) { pressed = false; } if (!pinch) { pinch = true; lastRadius = 0.0f; lastTouchCount = Input.touchCount; } float Xamount = 0.0f; float Yamount = 0.0f; Touch[] alltouch = Input.touches; foreach (Touch t in alltouch) { Vector2 pos = t.position; Xamount += pos.x; Yamount += pos.y; } float Xcenter = Xamount / Input.touchCount; float Ycenter = Yamount / Input.touchCount; float largestRadius = 0.0f; foreach (Touch t in alltouch) { Vector2 pos = t.position; float xdiff = pos.x - Xcenter; float ydiff = pos.y - Ycenter; float length = Mathf.Sqrt(xdiff * xdiff + ydiff * ydiff); if (length > largestRadius) { largestRadius = length; } } if (lastRadius != 0.0f & lastTouchCount == Input.touchCount) { //カメラ画角の変更 float angleaddition = (lastRadius - largestRadius) * 0.05f; maincam.fieldOfView = maincam.fieldOfView + angleaddition; //画角の最小・最大角度はここでコントロールする if (maincam.fieldOfView <= leastAngle) { maincam.fieldOfView = leastAngle; } else if (maincam.fieldOfView >= largestAngle) { maincam.fieldOfView = largestAngle; } } lastTouchCount = Input.touchCount; lastRadius = largestRadius; } } //ピンチ操作・終わり //マウス検知 if (Input.GetMouseButtonDown(0)) { Vector3 mousepos = Input.mousePosition; float x = mousepos.x; float y = Screen.height - mousepos.y; //画面は左上が原点、マウス(タッチ)は左下が原点 if (!pressed) { pressed = true; } lastx = mousepos.x; lasty = mousepos.y; } //左ボタン上がった if (Input.GetMouseButtonUp(0)) { if (pressed) { pressed = false; } //if (slidertapped) slidertapped = false; } if (pressed) { float xdiff = Input.mousePosition.x - lastx; float ydiff = Input.mousePosition.y - lasty; if (xdiff != 0.0f | ydiff != 0.0f) { positionUpdated(xdiff, ydiff); } lastx = Input.mousePosition.x; lasty = Input.mousePosition.y; } if (Application.platform == RuntimePlatform.Android) { // エスケープキー取得 if (Input.GetKeyDown(KeyCode.Escape)) { // アプリケーション終了処理 Application.Quit(); return; } } }