    001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.4_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    }