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.util; 015 016import static java.lang.Math.*; 017 018/** 019 * Contains constants and mathematical operations that are not available in {@link Math}. 020 */ 021public final class ExtendedMath { 022 023 /** 024 * PI * 2 025 */ 026 public static final double PI2 = PI * 2.0; 027 028 /** 029 * Arc-Seconds per Radian. 030 */ 031 public static final double ARCS = toDegrees(3600.0); 032 033 /** 034 * Mean radius of the earth, in kilometers. 035 */ 036 public static final double EARTH_MEAN_RADIUS = 6371.0; 037 038 private ExtendedMath() { 039 // utility class without constructor 040 } 041 042 /** 043 * Returns the decimal part of a value. 044 * 045 * @param a 046 * Value 047 * @return Fraction of that value. It has the same sign as the input value. 048 */ 049 public static double frac(double a) { 050 return a % 1.0; 051 } 052 053 /** 054 * Performs a safe check if the given double is actually zero (0.0). 055 * <p> 056 * Note that "almost zero" returns {@code false}, so this method should not be used 057 * for comparing calculation results to zero. 058 * 059 * @param d 060 * double to check for zero. 061 * @return {@code true} if the value was zero, or negative zero. 062 */ 063 public static boolean isZero(double d) { 064 // This should keep squid:S1244 silent... 065 return !Double.isNaN(d) && round(signum(d)) == 0L; 066 } 067 068 /** 069 * Converts equatorial coordinates to horizontal coordinates. 070 * 071 * @param tau 072 * Hour angle (radians) 073 * @param dec 074 * Declination (radians) 075 * @param dist 076 * Distance of the object 077 * @param lat 078 * Latitude of the observer (radians) 079 * @return {@link Vector} containing the horizontal coordinates 080 */ 081 public static Vector equatorialToHorizontal(double tau, double dec, double dist, double lat) { 082 return Matrix.rotateY(PI / 2.0 - lat).multiply(Vector.ofPolar(tau, dec, dist)); 083 } 084 085 /** 086 * Creates a rotational {@link Matrix} for converting equatorial to ecliptical 087 * coordinates. 088 * 089 * @param t 090 * {@link JulianDate} to use 091 * @return {@link Matrix} for converting equatorial to ecliptical coordinates 092 */ 093 public static Matrix equatorialToEcliptical(JulianDate t) { 094 double jc = t.getJulianCentury(); 095 double eps = toRadians(23.43929111 - (46.8150 + (0.00059 - 0.001813 * jc) * jc) * jc / 3600.0); 096 return Matrix.rotateX(eps); 097 } 098 099 /** 100 * Returns the parallax for objects at the horizon. 101 * 102 * @param height 103 * Observer's height, in meters above sea level. Must not be negative. 104 * @param distance 105 * Distance of the sun, in kilometers. 106 * @return parallax, in radians 107 */ 108 public static double parallax(double height, double distance) { 109 return asin(EARTH_MEAN_RADIUS / distance) 110 - acos(EARTH_MEAN_RADIUS / (EARTH_MEAN_RADIUS + (height / 1000.0))); 111 } 112 113 /** 114 * Calculates the atmospheric refraction of an object at the given apparent altitude. 115 * <p> 116 * The result is only valid for positive altitude angles. If negative, 0.0 is 117 * returned. 118 * <p> 119 * Assumes an atmospheric pressure of 1010 hPa and a temperature of 10 °C. 120 * 121 * @param ha 122 * Apparent altitude, in radians. 123 * @return Refraction at this altitude 124 * @see <a href="https://en.wikipedia.org/wiki/Atmospheric_refraction">Wikipedia: 125 * Atmospheric Refraction</a> 126 */ 127 public static double apparentRefraction(double ha) { 128 if (ha < 0.0) { 129 return 0.0; 130 } 131 132 return PI / (tan(toRadians(ha + (7.31 / (ha + 4.4)))) * 10800.0); 133 } 134 135 /** 136 * Calculates the atmospheric refraction of an object at the given altitude. 137 * <p> 138 * The result is only valid for positive altitude angles. If negative, 0.0 is 139 * returned. 140 * <p> 141 * Assumes an atmospheric pressure of 1010 hPa and a temperature of 10 °C. 142 * 143 * @param h 144 * True altitude, in radians. 145 * @return Refraction at this altitude 146 * @see <a href="https://en.wikipedia.org/wiki/Atmospheric_refraction">Wikipedia: 147 * Atmospheric Refraction</a> 148 */ 149 public static double refraction(double h) { 150 if (h < 0.0) { 151 return 0.0; 152 } 153 154 // refraction formula, converted to radians 155 return 0.000296706 / tan(h + 0.00312537 / (h + 0.0890118)); 156 } 157 158}