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.*; 017import static org.shredzone.commons.suncalc.util.ExtendedMath.equatorialToHorizontal; 018import static org.shredzone.commons.suncalc.util.ExtendedMath.refraction; 019 020import org.shredzone.commons.suncalc.param.Builder; 021import org.shredzone.commons.suncalc.param.GenericParameter; 022import org.shredzone.commons.suncalc.param.LocationParameter; 023import org.shredzone.commons.suncalc.param.TimeParameter; 024import org.shredzone.commons.suncalc.util.BaseBuilder; 025import org.shredzone.commons.suncalc.util.JulianDate; 026import org.shredzone.commons.suncalc.util.Moon; 027import org.shredzone.commons.suncalc.util.Vector; 028 029/** 030 * Calculates the position of the moon. 031 */ 032public class MoonPosition { 033 034 private final double azimuth; 035 private final double altitude; 036 private final double distance; 037 private final double parallacticAngle; 038 039 private MoonPosition(double azimuth, double altitude, double distance, double parallacticAngle) { 040 this.azimuth = (toDegrees(azimuth) + 180.0) % 360.0; 041 this.altitude = toDegrees(altitude); 042 this.distance = distance; 043 this.parallacticAngle = toDegrees(parallacticAngle); 044 } 045 046 /** 047 * Starts the computation of {@link MoonPosition}. 048 * 049 * @return {@link Parameters} to set. 050 */ 051 public static Parameters compute() { 052 return new MoonPositionBuilder(); 053 } 054 055 /** 056 * Collects all parameters for {@link MoonPosition}. 057 */ 058 public interface Parameters extends 059 GenericParameter<Parameters>, 060 LocationParameter<Parameters>, 061 TimeParameter<Parameters>, 062 Builder<MoonPosition> { 063 } 064 065 /** 066 * Builder for {@link MoonPosition}. Performs the computations based on the 067 * parameters, and creates a {@link MoonPosition} object that holds the result. 068 */ 069 private static class MoonPositionBuilder extends BaseBuilder<Parameters> implements Parameters { 070 @Override 071 public MoonPosition execute() { 072 JulianDate t = getJulianDate(); 073 074 double phi = getLatitudeRad(); 075 double lambda = getLongitudeRad(); 076 077 Vector mc = Moon.position(t); 078 double h = t.getGreenwichMeanSiderealTime() + lambda - mc.getPhi(); 079 080 Vector horizontal = equatorialToHorizontal(h, mc.getTheta(), mc.getR(), phi); 081 082 double hRef = refraction(horizontal.getTheta()); 083 084 double pa = atan2(sin(h), tan(phi) * cos(mc.getTheta()) - sin(mc.getTheta()) * cos(h)); 085 086 return new MoonPosition(horizontal.getPhi(), horizontal.getTheta() + hRef, mc.getR(), pa); 087 } 088 } 089 090 /** 091 * Moon altitude above the horizon, in degrees. 092 * <p> 093 * {@code 0.0} means the moon's center is at the horizon, {@code 90.0} at the zenith 094 * (straight over your head). 095 */ 096 public double getAltitude() { 097 return altitude; 098 } 099 100 /** 101 * Moon azimuth, in degrees, north-based. 102 * <p> 103 * This is the direction along the horizon, measured from north to east. For example, 104 * {@code 0.0} means north, {@code 135.0} means southeast, {@code 270.0} means west. 105 */ 106 public double getAzimuth() { 107 return azimuth; 108 } 109 110 /** 111 * Distance to the moon in kilometers. 112 */ 113 public double getDistance() { 114 return distance; 115 } 116 117 /** 118 * Parallactic angle of the moon, in degrees. 119 */ 120 public double getParallacticAngle() { 121 return parallacticAngle; 122 } 123 124 @Override 125 public String toString() { 126 StringBuilder sb = new StringBuilder(); 127 sb.append("MoonPosition[azimuth=").append(azimuth); 128 sb.append("°, altitude=").append(altitude); 129 sb.append("°, distance=").append(distance); 130 sb.append(" km, parallacticAngle=").append(parallacticAngle); 131 sb.append("°]"); 132 return sb.toString(); 133 } 134 135}