001 /* 002 * Zmanim Java API 003 * Copyright (C) 2004-2007 Eliyahu Hershfeld 004 * 005 * This program is free software; you can redistribute it and/or modify it under the terms of the 006 * GNU General Public License as published by the Free Software Foundation; either version 2 of the 007 * License, or (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 010 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 011 * General Public License for more details. 012 * 013 * You should have received a copy of the GNU General Public License along with this program; if 014 * not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA 015 * 02111-1307, USA or connect to: http://www.fsf.org/copyleft/gpl.html 016 */ 017 package net.sourceforge.zmanim.util; 018 019 import java.util.Calendar; 020 021 import net.sourceforge.zmanim.AstronomicalCalendar; 022 023 /** 024 * Implementation of sunrise and sunset methods to calculate astronomical times. 025 * This implementation is a port of the C++ algorithm written by Ken Bloom for 026 * the sourceforge.net <a href="http://sourceforge.net/projects/zmanim/">Zmanim</a> 027 * project. Ken's algorithm is based on the US Naval Almanac algorithm. Added to 028 * Ken's code is adjustment of the zenith to account for elevation. 029 * 030 * @author © Ken Bloom 2003 - 2004 031 * @author © Eliyahu Hershfeld 2004 - 2007 032 * @version 1.1 033 */ 034 public class ZmanimCalculator extends AstronomicalCalculator { 035 036 public String getCalculatorName(){ 037 return "US Naval Almanac Algorithm"; 038 } 039 040 /** 041 * @see net.sourceforge.zmanim.util.AstronomicalCalculator#getUTCSunrise(AstronomicalCalendar, 042 * double, boolean) 043 */ 044 public double getUTCSunrise(AstronomicalCalendar astronomicalCalendar, 045 /*GeoLocation geoLocation,*/ double zenith, boolean adjustForElevation) { 046 // zenith = adjustZenithForElevation(astronomicalCalendar, zenith, 047 // geoLocation.getElevation()); 048 // double elevationAdjustment = this.getElevationAdjustment(zenith, 049 // geoLocation.getElevation()); 050 // double refractionAdjustment = this.getRefraction(zenith); 051 // zenith = zenith + elevationAdjustment + refractionAdjustment; 052 if(adjustForElevation){ 053 zenith = adjustZenith(zenith, astronomicalCalendar.getGeoLocation().getElevation()); 054 } else { 055 zenith = adjustZenith(zenith, 0); 056 } 057 058 // step 1: First calculate the day of the year 059 // NOT NEEDED in this implementation 060 061 // step 2: convert the longitude to hour value and calculate an 062 // approximate time 063 double lngHour = astronomicalCalendar.getGeoLocation().getLongitude() / 15; 064 065 double t = astronomicalCalendar.getCalendar().get(Calendar.DAY_OF_YEAR) 066 + ((6 - lngHour) / 24); // use 18 for 067 // sunset instead 068 // of 6 069 070 // step 3: calculate the sun's mean anomaly 071 double m = (0.9856 * t) - 3.289; 072 073 // step 4: calculate the sun's true longitude 074 double l = m + (1.916 * Math.sin(Math.toRadians(m))) 075 + (0.020 * Math.sin(Math.toRadians(2 * m))) + 282.634; 076 while (l < 0) { 077 double Lx = l + 360; 078 l = Lx; 079 } 080 while (l >= 360) { 081 double Lx = l - 360; 082 l = Lx; 083 } 084 085 // step 5a: calculate the sun's right ascension 086 double RA = Math.toDegrees(Math.atan(0.91764 * Math.tan(Math 087 .toRadians(l)))); 088 089 while (RA < 0) { 090 double RAx = RA + 360; 091 RA = RAx; 092 } 093 while (RA >= 360) { 094 double RAx = RA - 360; 095 RA = RAx; 096 } 097 098 // step 5b: right ascension value needs to be in the same quadrant as L 099 double lQuadrant = Math.floor(l / 90) * 90; 100 double raQuadrant = Math.floor(RA / 90) * 90; 101 RA = RA + (lQuadrant - raQuadrant); 102 103 // step 5c: right ascension value needs to be converted into hours 104 RA /= 15; 105 106 // step 6: calculate the sun's declination 107 double sinDec = 0.39782 * Math.sin(Math.toRadians(l)); 108 double cosDec = Math.cos(Math.asin(sinDec)); 109 110 // step 7a: calculate the sun's local hour angle 111 double cosH = (Math.cos(Math.toRadians(zenith)) - (sinDec * Math 112 .sin(Math.toRadians(astronomicalCalendar.getGeoLocation().getLatitude())))) 113 / (cosDec * Math.cos(Math.toRadians(astronomicalCalendar.getGeoLocation().getLatitude()))); 114 115 // the following line would throw an Exception if the sun never rose. 116 // this is not needed since the calculation will return a Double.NaN 117 // if (cosH > 1) throw new Exception("doesnthappen"); 118 119 // FOR SUNSET use the following instead of the above if statement. 120 // if (cosH < -1) 121 122 // step 7b: finish calculating H and convert into hours 123 double H = 360 - Math.toDegrees(Math.acos(cosH)); 124 125 // FOR SUNSET remove "360 - " from the above 126 127 H = H / 15; 128 129 // step 8: calculate local mean time 130 131 double T = H + RA - (0.06571 * t) - 6.622; 132 133 // step 9: convert to UTC 134 double UT = T - lngHour; 135 while (UT < 0) { 136 double UTx = UT + 24; 137 UT = UTx; 138 } 139 while (UT >= 24) { 140 double UTx = UT - 24; 141 UT = UTx; 142 } 143 return UT; 144 } 145 146 /** 147 * @see net.sourceforge.zmanim.util.AstronomicalCalculator#getUTCSunset(AstronomicalCalendar, 148 * double, boolean) 149 */ 150 public double getUTCSunset(AstronomicalCalendar astronomicalCalendar, 151 /*GeoLocation geoLocation,*/ double zenith, boolean adjustForElevation) { 152 // zenith = adjustZenithForElevation(astronomicalCalendar, zenith, 153 // geoLocation.getElevation()); 154 // double elevationAdjustment = this.getElevationAdjustment(zenith, 155 // geoLocation.getElevation()); 156 // double refractionAdjustment = this.getRefraction(zenith); 157 // zenith = zenith + elevationAdjustment + refractionAdjustment; 158 159 if(adjustForElevation){ 160 zenith = adjustZenith(zenith, astronomicalCalendar.getGeoLocation().getElevation()); 161 } else { 162 zenith = adjustZenith(zenith, 0); 163 } 164 165 // step 1: First calculate the day of the year 166 // int calendarDayOfYear = calelendar.DAY_OF_YEAR; 167 168 // int N=theday - date(1,1,theday.year()) + 1; 169 int N = astronomicalCalendar.getCalendar().get(Calendar.DAY_OF_YEAR); 170 171 // step 2: convert the longitude to hour value and calculate an 172 // approximate time 173 double lngHour = astronomicalCalendar.getGeoLocation().getLongitude() / 15; 174 175 double t = N + ((18 - lngHour) / 24); 176 177 // step 3: calculate the sun's mean anomaly 178 double M = (0.9856 * t) - 3.289; 179 180 // step 4: calculate the sun's true longitude 181 double L = M + (1.916 * Math.sin(Math.toRadians(M))) 182 + (0.020 * Math.sin(Math.toRadians(2 * M))) + 282.634; 183 while (L < 0) { 184 double Lx = L + 360; 185 L = Lx; 186 } 187 while (L >= 360) { 188 double Lx = L - 360; 189 L = Lx; 190 } 191 192 // step 5a: calculate the sun's right ascension 193 double RA = Math.toDegrees(Math.atan(0.91764 * Math.tan(Math 194 .toRadians(L)))); 195 while (RA < 0) { 196 double RAx = RA + 360; 197 RA = RAx; 198 } 199 while (RA >= 360) { 200 double RAx = RA - 360; 201 RA = RAx; 202 } 203 204 // step 5b: right ascension value needs to be in the same quadrant as L 205 double Lquadrant = Math.floor(L / 90) * 90; 206 double RAquadrant = Math.floor(RA / 90) * 90; 207 RA = RA + (Lquadrant - RAquadrant); 208 209 // step 5c: right ascension value needs to be converted into hours 210 RA /= 15; 211 212 // step 6: calculate the sun's declination 213 double sinDec = 0.39782 * Math.sin(Math.toRadians(L)); 214 double cosDec = Math.cos(Math.asin(sinDec)); 215 216 // step 7a: calculate the sun's local hour angle 217 double cosH = (Math.cos(Math.toRadians(zenith)) - (sinDec * Math 218 .sin(Math.toRadians(astronomicalCalendar.getGeoLocation().getLatitude())))) 219 / (cosDec * Math.cos(Math.toRadians(astronomicalCalendar.getGeoLocation().getLatitude()))); 220 221 // the following line would throw an Exception if the sun never set. 222 // this is not needed since the calculation will return a Double.NaN 223 // if (cosH < -1) throw new ZmanimException("doesnthappen"); 224 225 // step 7b: finish calculating H and convert into hours 226 double H = Math.toDegrees(Math.acos(cosH)); 227 H = H / 15; 228 229 // step 8: calculate local mean time 230 231 double T = H + RA - (0.06571 * t) - 6.622; 232 233 // step 9: convert to UTC 234 double UT = T - lngHour; 235 while (UT < 0) { 236 double UTx = UT + 24; 237 UT = UTx; 238 } 239 while (UT >= 24) { 240 double UTx = UT - 24; 241 UT = UTx; 242 } 243 return UT; 244 } 245 }