001/* 002 * Shredzone Commons - suncalc 003 * 004 * Copyright (C) 2017 Richard "Shred" Körber 005 * http://commons.shredzone.org 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 013 */ 014package org.shredzone.commons.suncalc; 015 016import static java.lang.Math.toDegrees; 017import static org.shredzone.commons.suncalc.util.ExtendedMath.refraction; 018 019import org.shredzone.commons.suncalc.param.Builder; 020import org.shredzone.commons.suncalc.param.GenericParameter; 021import org.shredzone.commons.suncalc.param.LocationParameter; 022import org.shredzone.commons.suncalc.param.TimeParameter; 023import org.shredzone.commons.suncalc.util.BaseBuilder; 024import org.shredzone.commons.suncalc.util.JulianDate; 025import org.shredzone.commons.suncalc.util.Sun; 026import org.shredzone.commons.suncalc.util.Vector; 027 028/** 029 * Calculates the position of the sun. 030 */ 031public class SunPosition { 032 033 private final double azimuth; 034 private final double altitude; 035 private final double trueAltitude; 036 private final double distance; 037 038 private SunPosition(double azimuth, double altitude, double trueAltitude, double distance) { 039 this.azimuth = (toDegrees(azimuth) + 180.0) % 360.0; 040 this.altitude = toDegrees(altitude); 041 this.trueAltitude = toDegrees(trueAltitude); 042 this.distance = distance; 043 } 044 045 /** 046 * Starts the computation of {@link SunPosition}. 047 * 048 * @return {@link Parameters} to set. 049 */ 050 public static Parameters compute() { 051 return new SunPositionBuilder(); 052 } 053 054 /** 055 * Collects all parameters for {@link SunPosition}. 056 */ 057 public interface Parameters extends 058 GenericParameter<Parameters>, 059 LocationParameter<Parameters>, 060 TimeParameter<Parameters>, 061 Builder<SunPosition> { 062 } 063 064 /** 065 * Builder for {@link SunPosition}. Performs the computations based on the parameters, 066 * and creates a {@link SunPosition} object that holds the result. 067 */ 068 private static class SunPositionBuilder extends BaseBuilder<Parameters> implements Parameters { 069 @Override 070 public SunPosition execute() { 071 if (!hasLocation()) { 072 throw new IllegalArgumentException("Geolocation is missing."); 073 } 074 075 JulianDate t = getJulianDate(); 076 077 Vector horizontal = Sun.positionHorizontal(t, getLatitudeRad(), getLongitudeRad()); 078 double hRef = refraction(horizontal.getTheta()); 079 080 return new SunPosition(horizontal.getPhi(), 081 horizontal.getTheta() + hRef, 082 horizontal.getTheta(), 083 horizontal.getR()); 084 } 085 } 086 087 /** 088 * The visible sun altitude above the horizon, in degrees. 089 * <p> 090 * {@code 0.0} means the sun's center is at the horizon, {@code 90.0} at the zenith 091 * (straight over your head). Atmospheric refraction is taken into account. 092 * 093 * @see #getTrueAltitude() 094 */ 095 public double getAltitude() { 096 return altitude; 097 } 098 099 /** 100 * The true sun altitude above the horizon, in degrees. 101 * <p> 102 * {@code 0.0} means the sun's center is at the horizon, {@code 90.0} at the zenith 103 * (straight over your head). 104 * 105 * @see #getAltitude() 106 */ 107 public double getTrueAltitude() { 108 return trueAltitude; 109 } 110 111 /** 112 * Sun azimuth, in degrees, north-based. 113 * <p> 114 * This is the direction along the horizon, measured from north to east. For example, 115 * {@code 0.0} means north, {@code 135.0} means southeast, {@code 270.0} means west. 116 */ 117 public double getAzimuth() { 118 return azimuth; 119 } 120 121 /** 122 * Sun's distance, in kilometers. 123 */ 124 public double getDistance() { 125 return distance; 126 } 127 128 @Override 129 public String toString() { 130 StringBuilder sb = new StringBuilder(); 131 sb.append("SunPosition[azimuth=").append(azimuth); 132 sb.append("°, altitude=").append(altitude); 133 sb.append("°, true altitude=").append(trueAltitude); 134 sb.append("°, distance=").append(distance).append(" km]"); 135 return sb.toString(); 136 } 137 138}