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.*; 017 018import org.shredzone.commons.suncalc.param.Builder; 019import org.shredzone.commons.suncalc.param.GenericParameter; 020import org.shredzone.commons.suncalc.param.TimeParameter; 021import org.shredzone.commons.suncalc.util.BaseBuilder; 022import org.shredzone.commons.suncalc.util.JulianDate; 023import org.shredzone.commons.suncalc.util.Moon; 024import org.shredzone.commons.suncalc.util.Sun; 025import org.shredzone.commons.suncalc.util.Vector; 026 027/** 028 * Calculates the illumination of the moon. 029 */ 030public class MoonIllumination { 031 032 private final double fraction; 033 private final double phase; 034 private final double angle; 035 036 private MoonIllumination(double fraction, double phase, double angle) { 037 this.fraction = fraction; 038 this.phase = phase; 039 this.angle = angle; 040 } 041 042 /** 043 * Starts the computation of {@link MoonIllumination}. 044 * 045 * @return {@link Parameters} to set. 046 */ 047 public static Parameters compute() { 048 return new MoonIlluminationBuilder(); 049 } 050 051 /** 052 * Collects all parameters for {@link MoonIllumination}. 053 */ 054 public interface Parameters extends 055 GenericParameter<Parameters>, 056 TimeParameter<Parameters>, 057 Builder<MoonIllumination> { 058 } 059 060 /** 061 * Builder for {@link MoonIllumination}. Performs the computations based on the 062 * parameters, and creates a {@link MoonIllumination} object that holds the result. 063 */ 064 private static class MoonIlluminationBuilder extends BaseBuilder<Parameters> implements Parameters { 065 @Override 066 public MoonIllumination execute() { 067 JulianDate t = getJulianDate(); 068 Vector s = Sun.position(t); 069 Vector m = Moon.position(t); 070 double phi = PI - acos(m.dot(s) / (m.getR() * s.getR())); 071 Vector sunMoon = m.cross(s); 072 double angle = atan2( 073 cos(s.getTheta()) * sin(s.getPhi() - m.getPhi()), 074 sin(s.getTheta()) * cos(m.getTheta()) - cos(s.getTheta()) * sin(m.getTheta()) * cos(s.getPhi() - m.getPhi()) 075 ); 076 077 return new MoonIllumination( 078 (1 + cos(phi)) / 2, 079 toDegrees(phi * signum(sunMoon.getTheta())), 080 toDegrees(angle)); 081 } 082 } 083 084 /** 085 * Illuminated fraction. {@code 0.0} indicates new moon, {@code 1.0} indicates full 086 * moon. 087 */ 088 public double getFraction() { 089 return fraction; 090 } 091 092 /** 093 * Moon phase. Starts at {@code -180.0} (new moon, waxing), passes {@code 0.0} (full 094 * moon) and moves toward {@code 180.0} (waning, new moon). 095 * <p> 096 * Note that for historical reasons, the range of this phase is different to the 097 * moon phase angle used in {@link MoonPhase}. 098 */ 099 public double getPhase() { 100 return phase; 101 } 102 103 /** 104 * The angle of the moon illumination relative to earth. The moon is waxing if the 105 * angle is negative, and waning if positive. 106 * <p> 107 * By subtracting {@link MoonPosition#getParallacticAngle()} from {@link #getAngle()}, 108 * one can get the zenith angle of the moons bright limb (anticlockwise). The zenith 109 * angle can be used do draw the moon shape from the observer's perspective (e.g. the 110 * moon lying on its back). 111 */ 112 public double getAngle() { 113 return angle; 114 } 115 116 /** 117 * The closest {@link MoonPhase.Phase} that is matching the moon's angle. 118 * 119 * @return Closest {@link MoonPhase.Phase} 120 * @since 2.12 121 */ 122 public MoonPhase.Phase getClosestPhase() { 123 return MoonPhase.Phase.toPhase(phase + 180.0); 124 } 125 126 @Override 127 public String toString() { 128 StringBuilder sb = new StringBuilder(); 129 sb.append("MoonIllumination[fraction=").append(fraction); 130 sb.append(", phase=").append(phase); 131 sb.append("°, angle=").append(angle); 132 sb.append("°]"); 133 return sb.toString(); 134 } 135 136}