diff options
Diffstat (limited to 'src/ru/olamedia/astronomy')
-rw-r--r-- | src/ru/olamedia/astronomy/BaseUtils.java | 89 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/Declination.java | 33 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/FullMoonChecker.java | 41 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/JulianDate.java | 61 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/MinuntesAndSecondsBase.java | 41 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/MoonChecker.java | 26 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/MoonPhaseFinder.java | 135 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/MoonPosition.java | 185 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/NewMoonChecker.java | 41 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/README | 19 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/RightAscension.java | 32 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/SunCalendar.java | 284 | ||||
-rw-r--r-- | src/ru/olamedia/astronomy/SunPosition.java | 95 |
13 files changed, 1082 insertions, 0 deletions
diff --git a/src/ru/olamedia/astronomy/BaseUtils.java b/src/ru/olamedia/astronomy/BaseUtils.java new file mode 100644 index 0000000..99d351a --- /dev/null +++ b/src/ru/olamedia/astronomy/BaseUtils.java @@ -0,0 +1,89 @@ +package ru.olamedia.astronomy; + +// package com.bradsbrain.simpleastronomy; +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.text.DateFormat; +import static java.text.DateFormat.SHORT; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +public final class BaseUtils { + + public static double exactDaysSince(Calendar myCal, double epoch) { + return JulianDate.makeJulianDateUsingMyModified(myCal) - epoch; + } + + public static Calendar getSafeLocalCopy(long millis) { + // safe local copy + Calendar myCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + myCal.clear(); + myCal.setTimeInMillis(millis); + return myCal; + } + + public static double adjustTo360Range(double valToAdjust) { + double howMany = Math.floor(valToAdjust / 360); + double adjustedValue = valToAdjust - (howMany * 360); + return adjustedValue; + } + + public static double sinDegrees(double angleInDegrees) { + return Math.sin(Math.toRadians(angleInDegrees)); + } + + public static double cosDegrees(double angleInDegrees) { + return Math.cos(Math.toRadians(angleInDegrees)); + } + + public static double useLessPrecision(double d, int precision) { + double digits = Math.pow(10, precision); + return Math.round(d * digits) / digits; + } + + /** + * Useful date-to-string formatting which I found myself using a lot + * + * @param moonDate + * @return the date in GMT timezone + */ + public static String formatDateForGMT(Date moonDate) { + DateFormat sdf = SimpleDateFormat.getDateInstance(SHORT); + ((SimpleDateFormat) sdf).applyPattern("yyyy-MM-dd"); + ((SimpleDateFormat) sdf).setTimeZone(TimeZone.getTimeZone("GMT")); + return sdf.format(moonDate); + } + + /** + * Useful date-to-string formatting which I found myself using a lot + * + * @param moonDate + * @param tz + * the timezone with which to format the date + * @return the date in whatever timezone is default + */ + public static String formatDateAsShortDateLocalTime(Date moonDate, + TimeZone tz) { + DateFormat sdf = SimpleDateFormat.getDateInstance(SHORT); + sdf.setTimeZone(tz); + ((SimpleDateFormat) sdf).applyPattern("yyyy-MM-dd"); + return sdf.format(moonDate); + } + +}
\ No newline at end of file diff --git a/src/ru/olamedia/astronomy/Declination.java b/src/ru/olamedia/astronomy/Declination.java new file mode 100644 index 0000000..0798ffc --- /dev/null +++ b/src/ru/olamedia/astronomy/Declination.java @@ -0,0 +1,33 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +public class Declination extends MinuntesAndSecondsBase { + private int degrees; + + public Declination(int degrees, int minutes, int seconds) { + this.degrees = degrees; + setMinutes(minutes); + setSeconds(seconds); + } + + public int getDegrees() { + return degrees; + } + +} diff --git a/src/ru/olamedia/astronomy/FullMoonChecker.java b/src/ru/olamedia/astronomy/FullMoonChecker.java new file mode 100644 index 0000000..84589ab --- /dev/null +++ b/src/ru/olamedia/astronomy/FullMoonChecker.java @@ -0,0 +1,41 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +public class FullMoonChecker extends MoonChecker { + + private static final double VERY_LARGE_ANGLE = 180.10; + private static final double VERY_LARGE_PERCENT = 99.999; + + /** + * A new moon would be at a very small angle + */ + @Override + public boolean isCorrectAngle(double d) { + return d > VERY_LARGE_ANGLE; + } + + /** + * A new moon would be at a very small percent visible + */ + @Override + public boolean isCorrectPercent(double d) { + return d > VERY_LARGE_PERCENT; + } + +} diff --git a/src/ru/olamedia/astronomy/JulianDate.java b/src/ru/olamedia/astronomy/JulianDate.java new file mode 100644 index 0000000..94303df --- /dev/null +++ b/src/ru/olamedia/astronomy/JulianDate.java @@ -0,0 +1,61 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +import java.util.Calendar; + +/** + * Heavily based on procedures as documented in the book + * "Practical Astronomy with Your Calculator", 3rd Edition, by Peter + * Duffett-Smith, Cambridge University Press, 1988, 1990, 1992 + * + * @author bradparks + */ +public class JulianDate { + + /** + * This method is a simplification of formula in Section 3 of PAwyC3. We'll + * assume we're only talking about Gregorian Calendar dates because really, + * we don't care a whole lot about past dates. + * + * @param cal + * @return + */ + + public static double makeJulianDateUsingMyModified(Calendar cal) { + Calendar myCal = BaseUtils.getSafeLocalCopy(cal.getTimeInMillis()); + // step 1 + int year = myCal.get(Calendar.YEAR); + int month = myCal.get(Calendar.MONTH) + 1; // fix the January=0 + double day = myCal.get(Calendar.DAY_OF_MONTH); + double hour = myCal.get(Calendar.HOUR_OF_DAY) / 24.0; + double minute = myCal.get(Calendar.MINUTE) / 24.0 / 60.0; + double second = myCal.get(Calendar.SECOND) / 24.0 / 60.0 / 60.0; + + // step 2 + if (month <= 2) { + year--; + month += 12; + } + + // step 6 + return 1720995.5 + Math.floor(365.243 * year) + + Math.floor(30.6 * ++month) + day + hour + minute + second; + } + +}
\ No newline at end of file diff --git a/src/ru/olamedia/astronomy/MinuntesAndSecondsBase.java b/src/ru/olamedia/astronomy/MinuntesAndSecondsBase.java new file mode 100644 index 0000000..89fab6d --- /dev/null +++ b/src/ru/olamedia/astronomy/MinuntesAndSecondsBase.java @@ -0,0 +1,41 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +public abstract class MinuntesAndSecondsBase { + + private int minutes; + private int seconds; + + public int getMinutes() { + return minutes; + } + + protected void setMinutes(int minutes) { + this.minutes = minutes; + } + + public int getSeconds() { + return seconds; + } + + protected void setSeconds(int seconds) { + this.seconds = seconds; + } + +}
\ No newline at end of file diff --git a/src/ru/olamedia/astronomy/MoonChecker.java b/src/ru/olamedia/astronomy/MoonChecker.java new file mode 100644 index 0000000..069e67a --- /dev/null +++ b/src/ru/olamedia/astronomy/MoonChecker.java @@ -0,0 +1,26 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +public abstract class MoonChecker { + + public abstract boolean isCorrectAngle(double d); + + public abstract boolean isCorrectPercent(double d); + +} diff --git a/src/ru/olamedia/astronomy/MoonPhaseFinder.java b/src/ru/olamedia/astronomy/MoonPhaseFinder.java new file mode 100644 index 0000000..8e9c837 --- /dev/null +++ b/src/ru/olamedia/astronomy/MoonPhaseFinder.java @@ -0,0 +1,135 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +import java.util.Calendar; +import java.util.Date; + +public class MoonPhaseFinder { + + private static final int NUM_STEP_MINUTES = 1; + + private static MoonChecker newMoonChecker = new NewMoonChecker(); + private static MoonChecker fullMoonChecker = new FullMoonChecker(); + + public enum MoonPhase { + NEW, + WAXINGCRESCENT, + FIRSTQUARTER, + WAXINGGIBBOUS, + FULL, + WANINGGIBBOUS, + LASTQUARTER, + WANINGCRESCENT; + + + static MoonPhase finder(double percent) { + return FULL; + } + + } + + /** + * Someday this will return a descriptive MoonPhase enum when handed a cal/date + * + * @param cal + * @return + */ + public static MoonPhase findMoonPhaseAt(Calendar cal) { + return null; + } + + public static Date findFullMoonFollowing(Calendar cal) { + return findDatePassingBounds(cal, fullMoonChecker); + } + + public static Date findNewMoonFollowing(Calendar cal) { + return findDatePassingBounds(cal, newMoonChecker); + } + + public static Date findFullMoonFollowing(Date date) { + long time = date.getTime(); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return findDatePassingBounds(cal, fullMoonChecker); + } + + public static Date findNewMoonFollowing(Date date) { + long time = date.getTime(); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return findDatePassingBounds(cal, newMoonChecker); + } + + /** + * TODO: This loop isn't very efficient, come up with a better implementation + * + * @param cal the calendar date for which to compute the moon position + * @param moonChecker the NewMoon or FullMoon checker + * @return the forward date which passes the given bounds provided + */ + private static Date findDatePassingBounds(Calendar cal, MoonChecker moonChecker) { + Calendar myCal = BaseUtils.getSafeLocalCopy(cal.getTimeInMillis()); + Calendar thirtyOneDaysLater = Calendar.getInstance(); + thirtyOneDaysLater.setTimeInMillis(myCal.getTimeInMillis()); + thirtyOneDaysLater.add(Calendar.DAY_OF_MONTH, 31); + // if we don't find a new moon after 31 days we're not going to find it. days between phases is ~29.5 + while (myCal.before(thirtyOneDaysLater)) { + myCal.add(Calendar.MINUTE, NUM_STEP_MINUTES); + double percent = 100 * MoonPhaseFinder.getMoonVisiblePercent(myCal); + double angle = MoonPhaseFinder.getMoonAngle(myCal); + if (moonChecker.isCorrectAngle(angle) && moonChecker.isCorrectPercent(percent)) { + return myCal.getTime(); + } + } + return null; + } + + /** + * Returns a (much-too-)high-precision value for the amount of moon visible. + * Value will be somewhere in the range 0% to 100% (i.e. 0.00 to 1.00) + * + * @param cal + * @return percent of moon which is visible + */ + public static double getMoonVisiblePercent(Calendar cal) { + double moonAngle = getMoonAngle(cal); + return BaseUtils.useLessPrecision(0.5 * (1 - BaseUtils.cosDegrees(moonAngle)), 3); + } + + /** + * The moon angle. For that we need the sun's position and the moon's position. </br> + * The moon angle will be in the range 0 to 360. <br/> + * 0 or 360 is NEW, 180 is FULL + * + * @param cal + * @return the angle of the moon in relation to the earth + */ + public static double getMoonAngle(Calendar cal) { + Calendar myCal = BaseUtils.getSafeLocalCopy(cal.getTimeInMillis()); + SunPosition sunPos = new SunPosition(myCal); + MoonPosition moonPos = new MoonPosition(myCal); + + double angleAge = moonPos.getTrueLongitude() - sunPos.getEclipticLongitude(); + if (angleAge < 0) { + return 360 + angleAge; + } + return angleAge; + } + +} diff --git a/src/ru/olamedia/astronomy/MoonPosition.java b/src/ru/olamedia/astronomy/MoonPosition.java new file mode 100644 index 0000000..e20349f --- /dev/null +++ b/src/ru/olamedia/astronomy/MoonPosition.java @@ -0,0 +1,185 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +import static ru.olamedia.astronomy.BaseUtils.sinDegrees; + +import java.util.Calendar; + +public class MoonPosition { + // some handy constants + private double EPOCH = 2447891.5; // 1990 January 0.0 + private double MEAN_LONGITUDE_AT_EPOCH = 318.351648; + private double MEAN_LONGITUDE_OF_PERIGREE_AT_EPOCH = 36.340410; + + /** + * The True Longitude + */ + private double trueOrbitalLongitude; + + /** + * This is from section 65, page 144 + * + * @param cal + * the calendar date for which to compute the moon position + */ + public MoonPosition(Calendar cal) { + Calendar myCal = BaseUtils.getSafeLocalCopy(cal.getTimeInMillis()); + double daysSince = BaseUtils.exactDaysSince(myCal, EPOCH); + + // l + double moonMeanLongitude = computeMeanLongitude(daysSince); + // M m + double moonMeanAnomaly = computeMeanAnomaly(daysSince, + moonMeanLongitude); + + SunPosition sunPos = new SunPosition(myCal); + + MoonCorrections corrections = new MoonCorrections(moonMeanLongitude, + moonMeanAnomaly, sunPos.getEclipticLongitude(), + sunPos.getMeanAnomaly()); + trueOrbitalLongitude = corrections.getCorrectedLongitude() + - corrections.getVariationCorrection(); + } + + public double getTrueLongitude() { + return trueOrbitalLongitude; + } + + /** + * Compute the Moon Mean Longitude l + * + * @param daysSince + * @return + */ + private double computeMeanLongitude(double daysSince) { + double moonMeanLongitude = 13.1763966 * daysSince + + MEAN_LONGITUDE_AT_EPOCH; + return BaseUtils.adjustTo360Range(moonMeanLongitude); + } + + /** + * Compute the Moon Mean Anomaly M m + * + * @param daysSince + * @param moonMeanLongitude + * @return + */ + private double computeMeanAnomaly(double daysSince, double moonMeanLongitude) { + double moonMeanAnomaly = moonMeanLongitude - (0.1114041 * daysSince) + - MEAN_LONGITUDE_OF_PERIGREE_AT_EPOCH; + return BaseUtils.adjustTo360Range(moonMeanAnomaly); + } + + /** + * Private internal class used for lots of computations and corrections + */ + private static class MoonCorrections { + private double moonMeanLongitude; + private double moonMeanAnomaly; + private double sunLongitude; + private double sunMeanAnomaly; + + MoonCorrections(double moonMeanLongitude, double moonMeanAnomaly, + double sunLongitude, double sunMeanAnomaly) { + this.moonMeanAnomaly = moonMeanAnomaly; + this.sunMeanAnomaly = sunMeanAnomaly; + this.moonMeanLongitude = moonMeanLongitude; + this.sunLongitude = sunLongitude; + } + + /** + * V + * + * @return + */ + public double getVariationCorrection() { + return 0.6583 * sinDegrees(2 * (getCorrectedLongitude() - sunLongitude)); + } + + /** + * l' + * + * @return + */ + public double getCorrectedLongitude() { + return moonMeanLongitude + getEvictionCorrection() + + getCorrectionForEquationCentre() + - getAnnualEquationCorrection() + + getYetAnotherCorrectionTerm(); + } + + /** + * A 4 + * + * @return + */ + private double getYetAnotherCorrectionTerm() { + return 0.214 * sinDegrees(2 * getMoonCorrectedAnomaly()); + } + + /** + * E c + * + * @return + */ + private double getCorrectionForEquationCentre() { + return 6.2886 * sinDegrees(getMoonCorrectedAnomaly()); + } + + /** + * M' m + * + * @return + */ + private double getMoonCorrectedAnomaly() { + return moonMeanAnomaly + getEvictionCorrection() + - getAnnualEquationCorrection() + - getUnnamedThirdCorrection(); + } + + /** + * E v + * + * @return + */ + public double getEvictionCorrection() { + double C = moonMeanLongitude - sunLongitude; + return 1.2739 * sinDegrees(2.0 * C - moonMeanAnomaly); + } + + /** + * A e + * + * @return + */ + public double getAnnualEquationCorrection() { + return 0.1858 * sinDegrees(sunMeanAnomaly); + } + + /** + * A 3 + * + * @return + */ + public double getUnnamedThirdCorrection() { + return 0.37 * sinDegrees(sunMeanAnomaly); + } + } + +}
\ No newline at end of file diff --git a/src/ru/olamedia/astronomy/NewMoonChecker.java b/src/ru/olamedia/astronomy/NewMoonChecker.java new file mode 100644 index 0000000..d8472fd --- /dev/null +++ b/src/ru/olamedia/astronomy/NewMoonChecker.java @@ -0,0 +1,41 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +public class NewMoonChecker extends MoonChecker { + + private static final double VERY_SMALL_ANGLE = 0.01; + private static final double VERY_SMALL_PERCENT = 0.01; + + /** + * A new moon would be at a very small angle + */ + @Override + public boolean isCorrectAngle(double d) { + return d < VERY_SMALL_ANGLE; + } + + /** + * A new moon would be at a very small percent visible + */ + @Override + public boolean isCorrectPercent(double d) { + return d < VERY_SMALL_PERCENT; + } + +} diff --git a/src/ru/olamedia/astronomy/README b/src/ru/olamedia/astronomy/README new file mode 100644 index 0000000..13d2655 --- /dev/null +++ b/src/ru/olamedia/astronomy/README @@ -0,0 +1,19 @@ + +simple-astronomy-lib +A simple astronomy Java library for calculating moon phase, solar eclipses, etc. + +http://code.google.com/p/simple-astronomy-lib/ + +import java.util.Calendar; +import java.util.TimeZone; +import com.bradsbrain.simpleastronomy.MoonPhaseFinder; + +public class WerewolfCheck { + public static void main(String[] args) { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("America/Chicago")); + cal.clear(); + cal.set(2011, Calendar.JUNE, 12); + + System.out.println("The next full moon is on: " + MoonPhaseFinder.findFullMoonFollowing(cal)); + } +}
\ No newline at end of file diff --git a/src/ru/olamedia/astronomy/RightAscension.java b/src/ru/olamedia/astronomy/RightAscension.java new file mode 100644 index 0000000..a321eee --- /dev/null +++ b/src/ru/olamedia/astronomy/RightAscension.java @@ -0,0 +1,32 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +public class RightAscension extends MinuntesAndSecondsBase { + private int hours; + + public RightAscension(int hours, int minutes, int seconds) { + this.hours = hours; + setMinutes(minutes); + setSeconds(seconds); + } + + public int getHours() { + return hours; + } +}
\ No newline at end of file diff --git a/src/ru/olamedia/astronomy/SunCalendar.java b/src/ru/olamedia/astronomy/SunCalendar.java new file mode 100644 index 0000000..05ec596 --- /dev/null +++ b/src/ru/olamedia/astronomy/SunCalendar.java @@ -0,0 +1,284 @@ +package ru.olamedia.astronomy; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +/** + * Sun position calculations + * + * @author olamedia + * + */ +@SuppressWarnings("unused") +public class SunCalendar extends GregorianCalendar { + /** + * + */ + private static final long serialVersionUID = 2708738531759361416L; + double jd; + double jcycle; + double meanLongitude; // L + private double latitude; + private double longitude; + + public double getLongitude() { // User longitude at Earth + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + private double to360(double v) { + double v360 = v - Math.floor(v / 360) * 360; + while (v360 < 0) { + v360 += 360; + } + return v360; + } + + private void computePosition() { + // These orbital elements are thus valid for the Sun's (apparent) orbit + // around the Earth. + // All angular values are expressed in degrees: + double w = 282.9404 + 4.70935E-5 * jd; // (longitude of perihelion) + // 282.9404_deg + 4.70935E-5_deg + // * jd + double a = 1.000000; // (mean distance, a.u.) + double e = 0.016709 - 1.151E-9 * jd; // (eccentricity) + double M = to360(356.0470 + 0.9856002585 * jd);// (mean anomaly) + // 356.0470_deg + + // 0.9856002585_deg * jd + double oblecl = 23.4393 - 3.563E-7 * jd; // (obliquity of the ecliptic) + // 23.4393_deg - + // 3.563E-7_deg * jd + double L = w + M; // Sun's mean longitude + meanLongitude = L; + // Let's go on computing an auxiliary angle, the eccentric anomaly. + // Since the eccentricity of the Sun's (i.e. the Earth's) orbit is so + // small, 0.017, + // a first approximation of E will be accurate enough. Below E and M are + // in degrees: + double E = M + (180 / Math.PI) * e * Math.sin(M) + * (1 + e * Math.cos(M)); // (eccentric anomaly) + // Now we compute the Sun's rectangular coordinates in the plane of the + // ecliptic, where the X axis points towards the perihelion: + double x = Math.cos(E) - e; // x = r * Math.cos(v) = Math.cos(E) - e + double y = Math.sin(E) * Math.sqrt(1 - e * e); // y = r * Math.sin(v) = + // Math.sin(E) * sqrt(1 + // - e*e) + + // Convert to distance and true anomaly: + double r = Math.sqrt(x * x + y * y); + double v = Math.atan2(y, x); + + double lon = v + w; + } + + double UT; // UT is the same as Greenwich time + + public void computeSidetime() { + double GMST0 = to360(meanLongitude + 180) / 15; + double LON = 15; // Central Europe (at 15 deg east longitude = +15 + // degrees long) on 19 april 1990 at 00:00 UT + + // LON is the terrestial longitude in degrees (western longitude is + // negative, eastern positive). + // To "convert" the longitude from degrees to hours we divide it by 15 + double SIDTIME = GMST0 + UT + LON / 15; + // To compute the altitude and azimuth + // we also need to know the Hour Angle, HA. + + // The Hour Angle is zero when the clestial body + // is in the meridian i.e. in the south + // (or, from the southern heimsphere, in the north) - + // this is the moment when the celestial body + // is at its highest above the horizon. + + // The Hour Angle increases with time + // (unless the object is moving faster than the Earth rotates; + // this is the case for most artificial satellites). + // It is computed from: + // RA - Right Ascension + // double HA = SIDTIME - RA; + } + + /* + * Local Standard Time Meridian (LSTM) The Local Standard Time Meridian + * (LSTM) is a reference meridian used for a particular time zone and is + * similar to the Prime Meridian, which is used for Greenwich Mean Time. + */ + public double getLocalStandardTimeMeridian() { + return 15 * this.getTimeZone().getOffset(this.getTimeInMillis()); + } + + /* + * Equation of Time (EoT) + * + * The equation of time (EoT) (in minutes) is an empirical equation that + * corrects for the eccentricity of the Earth's orbit and the Earth's axial + * tilt. where B in degrees and d is the number of days since the start of + * the year. The time correction EoT is plotted in the figure below. + */ + public double getEquationOfTime() { + double B = getB(); + return ((double) 9.87 * Math.sin(2 * B) - 7.53 * Math.cos(B) - 1.5 * Math + .sin(B)); + } + + /* + * Time Correction Factor (TC) + * + * The net Time Correction Factor (in minutes) accounts for the variation of + * the Local Solar Time (LST) within a given time zone due to the longitude + * variations within the time zone and also incorporates the EoT above. + * + * The factor of 4 minutes comes from the fact that the Earth rotates 1° + * every 4 minutes. + */ + public double getTimeCorrectionFactor() { + // FIX LATER + return 0;// 4 * (getLocalStandardTimeMeridian() - getLongitude()) + // + getEquationOfTime(); + } + + /* + * Local Solar Time (LST) + * + * The Local Solar Time (LST) can be found by using the previous two + * corrections to adjust the local time (LT). + */ + public double getLocalSolarTime() { + return (double) get(Calendar.HOUR_OF_DAY) + (double) get(Calendar.MINUTE) / 60 + + (double) get(Calendar.SECOND) / (60 * 60) + getTimeCorrectionFactor() + / 60; + } + + /* + * Hour Angle (HRA) + * + * The Hour Angle converts the local solar time (LST) into the number of + * degrees which the sun moves across the sky. By definition, the Hour Angle + * is 0° at solar noon. Since the Earth rotates 15° per hour, each hour away + * from solar noon corresponds to an angular motion of the sun in the sky of + * 15°. In the morning the hour angle is negative, in the afternoon the hour + * angle is positive. + */ + public double getHourAngle() { + return 15 * (getLocalSolarTime() - 12); // 15°(LST-12) + } + + /* + * Declination + * + * The declination angle has been previously given as: + * + * Where d is the number of days since the start of the year. + */ + public double getDeclination() { + return (double) 23.45 * Math.sin(getB()); + } + + public double getElevationAngle() { + // φ is the latitude of the location of interest + // δ is the declination angle + // elevation angle at solar noon: + // α = 90 - φ + δ (Northern Hemisphere: +90° North pole) + // α = 90 + φ - δ (Southern Hemisphere: -90° South pole) + // 90 + (getLatitude() - getDeclination()) + // * (getLatitude() > 0 ? -1 : 1); + return Math.pow( + Math.sin(Math.sin(getDeclination()) * Math.sin(getLatitude()) + + Math.cos(getDeclination()) * Math.cos(getLatitude()) + * Math.cos(getHourAngle()) + + ), -1); + } + + public double getZenithAngle() { + return 90 - getElevationAngle(); + } + + public double getSunrise() { + // Sunrise=12−1/150 cos−1(−sinφ sinδ cosφ cosδ)−TC/60 + double delta = getLongitude() + radToDeg(getHourAngleSunrise()); + double UTCsec = (720 - (4.0 * delta) - getEquationOfTime()) * 60; + double sec = UTCsec + + (this.getTimeZone().getOffset(getTimeInMillis()) / 1000);// in + // minutes, + // UTC + return (double) (int) sec / (60 * 60); + } + + public double getSunset() { + // Sunset=12+1/150 cos−1(−sinφ sinδ cosφ cosδ)−TC/60 + double lw = getLongitude(); + return (getHourAngle() + lw) / 360; + // 2451545.009 + + jcycle + // + 0.0053 * Math.sin(M) - 0.0069 * Math.sin(2*lamb); + + // return 12 + // + 15 + // * Math.pow( + // Math.cos(-Math.tan(getLatitude()) + // * Math.tan(getDeclination())), -1) + // - getTimeCorrectionFactor() / 60; + } + + public double radToDeg(double angleRad) { + return (180.0 * angleRad / Math.PI); + } + + public double degToRad(double angleDeg) { + return (Math.PI * angleDeg / 180.0); + } + + public double getHourAngleSunrise() { + double latRad = degToRad(getLatitude()); + double sdRad = degToRad(getDeclination()); + double HAarg = (Math.cos(degToRad(90.833)) + / (Math.cos(latRad) * Math.cos(sdRad)) - Math.tan(latRad) + * Math.tan(sdRad)); + double HA = Math.acos(HAarg); + return (HA); // in radians (for sunset, use -HA) + } + + public double getB() { + return ((double) 360 / 365) + * (double) (this.get(Calendar.DAY_OF_YEAR) - 81); + } + + public SunCalendar(Calendar cal, double longitude, // West-East + double latitude // +90° North-South -90° + ) { + super(); + this.setTimeZone(cal.getTimeZone()); + this.setTime(cal.getTime()); + this.setLongitude(longitude); + // Arctic Circle 66° 33′ 39″ N + // Tropic of Cancer 23° 26′ 21″ N + // Tropic of Capricorn 23° 26′ 21″ S + // Antarctic Circle 66° 33′ 39" S + this.setLatitude(latitude); + // computePosition(); + // computeSidetime(); + } + + public void update() { + jd = JulianDate.makeJulianDateUsingMyModified(this); + // Here lw is the longitude west (west is positive, east is negative) + // of the observer on the Earth; + jcycle = jd - 2451545.009 - getLongitude() / 360; + } + +} diff --git a/src/ru/olamedia/astronomy/SunPosition.java b/src/ru/olamedia/astronomy/SunPosition.java new file mode 100644 index 0000000..48209ed --- /dev/null +++ b/src/ru/olamedia/astronomy/SunPosition.java @@ -0,0 +1,95 @@ +package ru.olamedia.astronomy; + +/* + * Copyright 2011 Brad Parks + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +//package com.bradsbrain.simpleastronomy; + +import java.util.Calendar; + +public class SunPosition { + // some handy constants + private double EPOCH = 2447891.5; // 1990 January 0.0 + private double ECLIPTIC_LONGITUDE_OF_PERIGREE = 282.768422; + private double ECLIPTIC_LONGITUDE_AT_EPOCH_1990 = 279.403303; + private double ECCENTRICITY_OF_ORBIT = 0.016713; + + /** + * The geocentric ecliptic longitude. <br> + * Calculation is good to 3 decimal places <br> + * me: 337.44406603442917, book: 337.444194 + */ + private double geoEclipticLongitude = 0; // oft represented as a lambda with + // little circle+dot + /** + * The mean anomaly + */ + private double meanAnomaly = 0; // oft represented as capital M with little + // circle+dot + + public SunPosition(Calendar cal) { + Calendar myCal = BaseUtils.getSafeLocalCopy(cal.getTimeInMillis()); + + double daysSince = BaseUtils.exactDaysSince(myCal, EPOCH); + + double N = (360 / 365.242191 * daysSince) % 360; + if (N < 0) { + N += 360; + } + + meanAnomaly = computeMeanAnomaly(N); + geoEclipticLongitude = computeGeoEclipticLongitude(N); + } + + private double computeGeoEclipticLongitude(double nValue) { + double Ec = (360.0 / Math.PI) * ECCENTRICITY_OF_ORBIT + * Math.sin(Math.toRadians(meanAnomaly)); + double preliminaryLongitude = nValue + Ec + + ECLIPTIC_LONGITUDE_AT_EPOCH_1990; + if (preliminaryLongitude > 360) { + preliminaryLongitude -= 360; + } + return preliminaryLongitude; + } + + private double computeMeanAnomaly(double nValue) { + double someMean = nValue + ECLIPTIC_LONGITUDE_AT_EPOCH_1990 + - ECLIPTIC_LONGITUDE_OF_PERIGREE; + return someMean < 0 ? someMean + 360 : someMean; + } + + /** + * TODO: implement this someday + */ + public RightAscension getRightAscension() { + return null; + } + + /** + * TODO: implement this someday + */ + public Declination getDeclination() { + return null; + } + + public double getEclipticLongitude() { + return geoEclipticLongitude; + } + + public double getMeanAnomaly() { + return meanAnomaly; + } + +}
\ No newline at end of file |