001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wpvs/utils/SunPosition.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005       Department of Geography, University of Bonn
006     and
007       lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035    ----------------------------------------------------------------------------*/
036    
037    package org.deegree.ogcwebservices.wpvs.utils;
038    
039    import java.util.Calendar;
040    import java.util.GregorianCalendar;
041    
042    /**
043     *
044     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
045     * @author last edited by: $Author: mschneider $
046     * @version $Revision: 18195 $ $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
047     */
048    public class SunPosition {
049    
050        private int year;
051        private int month;
052        private int day;
053        private int hour;
054        private int minute;
055        private double daysSinceVernalEquinox;
056    
057        /**
058         * Constructs a sunposition at the currenttime
059         */
060        public SunPosition(){
061          GregorianCalendar calendar = new GregorianCalendar();
062          this.year = calendar.get( Calendar.YEAR );
063          this.month = calendar.get( Calendar.MONTH ) + 1;
064          this.day = calendar.get( Calendar.DAY_OF_MONTH );
065          this.hour = calendar.get( Calendar.HOUR_OF_DAY );
066          this.minute = calendar.get( Calendar.MINUTE );
067          daysSinceVernalEquinox = getDaySinceVernalEquinox( );
068        }
069        /**
070         * Constructs a sunposition with the given Calendar
071         * @param calendar a given Calendar
072         */
073        public SunPosition( Calendar calendar ){
074          this( calendar.get( Calendar.YEAR ),
075                calendar.get( Calendar.MONTH ) + 1,
076                calendar.get( Calendar.DAY_OF_MONTH ),
077                calendar.get( Calendar.HOUR_OF_DAY ),
078                calendar.get( Calendar.MINUTE ) );
079        }
080    
081        /**
082         * @param year
083         * @param month
084         * @param day
085         * @param hour
086         * @param minute
087         */
088        public SunPosition( int year, int month, int day, int hour, int minute ){
089            this.year = year;
090            this.month = month;
091            if( month <= 0 || month > 12 )
092                this.month = 1;
093            this.day = day;
094            if( day <= 0 || day > 32 )
095                this.day = 1;
096            this.hour = hour;
097            if( hour < 0 || hour >=24 )
098                this.hour = 0;
099            this.minute = minute;
100            if( minute < 0 || minute >= 60 )
101                this.minute = 0;
102    
103            daysSinceVernalEquinox = getDaySinceVernalEquinox( );
104        }
105        /**
106         * calculates the solar altitude for given latitude, year, month, date, hour
107         * and minute
108         * @param latitude latitude of the the viewers position
109         * @return the solar altitud fo given latitude
110         */
111        public double getVerticalSunposition( double latitude )
112        {
113            // Hour Angle (H),
114            // Solar Declination (D),
115            // Latitude (L)
116            // solar altitude (A).
117            // sin(A) = sin(D)*sin(L) + cos(D)*cos(L)*cos(H)
118            double rad23_5 = 0.41015237421866745057706;
119            //double days = getDaySinceVernalEquinox( year, month, date );
120            double sinD = Math.sin( rad23_5 ) * Math.sin( Math.toRadians(  daysSinceVernalEquinox * 360.0 / 365.0 ) );
121            double cosD = Math.cos( Math.asin( sinD ) );
122            // the sun hour angle is zero when the object is on the meridian
123            double h = getHorizontalSunPosition( ) - Math.toRadians(180);
124            double radL = Math.toRadians( latitude );
125            double sinA = sinD * Math.sin(radL) + cosD * Math.cos(radL) * Math.cos(h);
126    
127            return Math.asin( sinA );
128        }
129    
130        /**
131         * calculates the horizontal angle of the sun depending only on hour and minute!
132         * @return the horizontal angle
133         */
134        public double getHorizontalSunPosition( )
135        {
136            double d = hour + minute/60.0;
137            d = 180 + (( d - 12 ) * 15.0);
138            return Math.toRadians(d);
139        }
140    
141        /**
142         * caluculates for a given date the number of days since the last vernal(spring)
143         * equinox. (leap years are considered)
144         */
145        private double getDaySinceVernalEquinox( )
146        {
147            //0 for january
148            GregorianCalendar calendar = new GregorianCalendar( year, 2, 21 );
149            int vEq = calendar.get( Calendar.DAY_OF_YEAR );
150            calendar = new GregorianCalendar( year, month-1, day-1 );
151            int doy = calendar.get( Calendar.DAY_OF_YEAR );
152            if ( doy < vEq ) {
153                doy = ( (calendar.isLeapYear(year)?366:365) - vEq ) + doy;
154            }
155            return doy-vEq;
156        }
157    
158    }