Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 133 additions & 1 deletion src/main/java/com/kosherjava/zmanim/util/GeoLocation.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ public class GeoLocation implements Cloneable {
* @see #setElevation(double)
*/
private double elevation;

/**
* The elevation in Meters above sea level of the horizon at the point where the sun rises that day.
* This point is not simply due east and shifts through the year as the sunrise azimuth changes with the season.
* Defaults to 0.
* @see #getHorizonElevationAtSunrise()
* @see #setHorizonElevationAtSunrise(double)
* @see #getSunriseElevation()
*/
private double horizonElevationAtSunrise = 0;

/**
* The elevation in Meters above sea level of the horizon at the point where the sun sets that day.
* This point is not simply due west and shifts through the year as the sunset azimuth changes with the season.
* Defaults to 0.
* @see #getHorizonElevationAtSunset()
* @see #setHorizonElevationAtSunset(double)
* @see #getSunsetElevation()
*/
private double horizonElevationAtSunset = 0;

/**
* Constant for a distance type calculation.
Expand Down Expand Up @@ -118,6 +138,87 @@ public void setElevation(double elevation) {
this.elevation = elevation;
}

/**
* Method to return the elevation in Meters above sea level of the horizon at the point where the sun rises that day.
*
* @return the horizon elevation at sunrise in Meters.
* @see #setHorizonElevationAtSunrise(double)
*/
public double getHorizonElevationAtSunrise() {
return horizonElevationAtSunrise;
}

/**
* Method to set the elevation in Meters above sea level of the horizon at the point where the sun rises that day.
* This point is not simply due east and shifts through the year as the sunrise azimuth changes with the season.
* Sunrise is calculated with the observer's height above this horizon instead of above sea level.
* @param horizonElevationAtSunrise the horizon elevation at sunrise in Meters. An IllegalArgumentException will be thrown
* if the value is a negative, {@link java.lang.Double#isNaN(double)} or {@link java.lang.Double#isInfinite(double)}.
* @see #getSunriseElevation()
*/
public void setHorizonElevationAtSunrise(double horizonElevationAtSunrise) {
validateHorizonElevation(horizonElevationAtSunrise);
this.horizonElevationAtSunrise = horizonElevationAtSunrise;
}

/**
* Method to return the elevation in Meters above sea level of the horizon at the point where the sun sets that day.
*
* @return the horizon elevation at sunset in Meters.
* @see #setHorizonElevationAtSunset(double)
*/
public double getHorizonElevationAtSunset() {
return horizonElevationAtSunset;
}

/**
* Method to set the elevation in Meters above sea level of the horizon at the point where the sun sets that day.
* This point is not simply due west and shifts through the year as the sunset azimuth changes with the season.
* Sunset is calculated with the observer's height above this horizon instead of above sea level.
* @param horizonElevationAtSunset the horizon elevation at sunset in Meters. An IllegalArgumentException will be thrown
* if the value is a negative, {@link java.lang.Double#isNaN(double)} or {@link java.lang.Double#isInfinite(double)}.
* @see #getSunsetElevation()
*/
public void setHorizonElevationAtSunset(double horizonElevationAtSunset) {
validateHorizonElevation(horizonElevationAtSunset);
this.horizonElevationAtSunset = horizonElevationAtSunset;
}

/**
* Throws if a horizon elevation is not a usable height in Meters above sea level.
* @param horizonElevation the value to check.
*/
private static void validateHorizonElevation(double horizonElevation) {
if (horizonElevation < 0) {
throw new IllegalArgumentException("Horizon elevation cannot be negative");
}
if (Double.isNaN(horizonElevation) || Double.isInfinite(horizonElevation)) {
throw new IllegalArgumentException("Horizon elevation cannot be NaN or infinite");
}
}

/**
* The height in Meters of the observer above the {@link #getHorizonElevationAtSunrise() sunrise horizon}.
* A higher horizon returns 0, since <em>halachically</em> land blocking the sun does not delay sunrise.
*
* @return the observer's height above the sunrise horizon in Meters, never negative. With the default sea-level horizon
* this is the same as {@link #getElevation()}.
*/
public double getSunriseElevation() {
return Math.max(elevation - horizonElevationAtSunrise, 0);
}

/**
* The height in Meters of the observer above the {@link #getHorizonElevationAtSunset() sunset horizon}.
* A higher horizon returns 0, since <em>halachically</em> land blocking the sun does not make sunset earlier.
*
* @return the observer's height above the sunset horizon in Meters, never negative. With the default sea-level horizon
* this is the same as {@link #getElevation()}.
*/
public double getSunsetElevation() {
return Math.max(elevation - horizonElevationAtSunset, 0);
}

/**
* GeoLocation constructor with parameters for all required fields.
*
Expand Down Expand Up @@ -153,6 +254,30 @@ public GeoLocation(String name, double latitude, double longitude, double elevat
setZoneId(zoneId);
}

/**
* GeoLocation constructor for a location whose horizon at sunrise or sunset is not at sea level.
*
* @param name The location name for display, for example "Lakewood, NJ".
* @param latitude the latitude as a {@code double}, for example 40.096 for Lakewood, NJ. <b>Note:</b> For latitudes south of
* the equator, a negative value should be used.
* @param longitude the longitude as a {@code double}, for example -74.222 for Lakewood, NJ. <b>Note:</b> For longitudes west
* of the <a href="https://en.wikipedia.org/wiki/Prime_Meridian">Prime Meridian</a> (Greenwich), a negative value should
* be used.
* @param elevation the elevation above sea level in Meters.
* @param horizonElevationAtSunrise the elevation above sea level in Meters of the horizon at the point where the sun rises
* that day.
* @param horizonElevationAtSunset the elevation above sea level in Meters of the horizon at the point where the sun sets
* that day.
* @param zoneId the {@code ZoneId} for the location.
* @see #setHorizonElevationAtSunrise(double)
*/
public GeoLocation(String name, double latitude, double longitude, double elevation, double horizonElevationAtSunrise,
double horizonElevationAtSunset, ZoneId zoneId) {
this(name, latitude, longitude, elevation, zoneId);
setHorizonElevationAtSunrise(horizonElevationAtSunrise);
setHorizonElevationAtSunset(horizonElevationAtSunset);
}

/**
* Default GeoLocation constructor will set location to the Prime Meridian at Greenwich, England and a {@code ZoneId}
* of GMT. The longitude will be set to 0 and the latitude will be 51.4772 to match the location of the <a
Expand Down Expand Up @@ -487,6 +612,8 @@ public String toXML() {
"\t<Latitude>" + getLatitude() + "</Latitude>\n" +
"\t<Longitude>" + getLongitude() + "</Longitude>\n" +
"\t<Elevation>" + getElevation() + " Meters" + "</Elevation>\n" +
"\t<HorizonElevationAtSunrise>" + getHorizonElevationAtSunrise() + " Meters" + "</HorizonElevationAtSunrise>\n" +
"\t<HorizonElevationAtSunset>" + getHorizonElevationAtSunset() + " Meters" + "</HorizonElevationAtSunset>\n" +
"\t<TimezoneName>" + getZoneId().getId() + "</TimezoneName>\n" +
"\t<TimeZoneDisplayName>" + getZoneId().getDisplayName(TextStyle.FULL, Locale.ENGLISH) + "</TimeZoneDisplayName>\n" +
"</GeoLocation>";
Expand All @@ -509,6 +636,8 @@ public boolean equals(Object object) {
return Double.compare(this.latitude, geo.latitude) == 0
&& Double.compare(this.longitude, geo.longitude) == 0
&& Double.compare(this.elevation, geo.elevation) == 0
&& Double.compare(this.horizonElevationAtSunrise, geo.horizonElevationAtSunrise) == 0
&& Double.compare(this.horizonElevationAtSunset, geo.horizonElevationAtSunset) == 0
&& Objects.equals(this.locationName, geo.locationName)
&& Objects.equals(this.zoneId, geo.zoneId);
}
Expand All @@ -518,7 +647,8 @@ public boolean equals(Object object) {
*/
@Override
public int hashCode() {
return Objects.hash(getClass(), this.latitude, this.longitude, this.elevation, this.locationName, this.zoneId);
return Objects.hash(getClass(), this.latitude, this.longitude, this.elevation, this.horizonElevationAtSunrise,
this.horizonElevationAtSunset, this.locationName, this.zoneId);
}

/**
Expand All @@ -530,6 +660,8 @@ public String toString() {
"\nLatitude:\t\t\t" + getLatitude() + "\u00B0" +
"\nLongitude:\t\t\t" + getLongitude() + "\u00B0" +
"\nElevation:\t\t\t" + getElevation() + " Meters" +
"\nHorizon Elevation At Sunrise:\t" + getHorizonElevationAtSunrise() + " Meters" +
"\nHorizon Elevation At Sunset:\t" + getHorizonElevationAtSunset() + " Meters" +
"\nTimezone ID:\t\t\t" + getZoneId().getId() +
"\nTimezone Display Name:\t\t" + getZoneId().getDisplayName(TextStyle.FULL, Locale.ENGLISH);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,14 @@ public double getUTCSunset(LocalDate dt, GeoLocation geoLocation, double zenith,
*/
private double getUTCSunRiseSet(LocalDate localDate, GeoLocation geoLocation, double zenith,
boolean adjustForElevation, SolarEvent solarEvent) {
double elevation = adjustForElevation ? geoLocation.getElevation() : 0;
double elevation = 0;
if (adjustForElevation) {
if (solarEvent == SolarEvent.SUNRISE) {
elevation = geoLocation.getSunriseElevation();
} else {
elevation = geoLocation.getSunsetElevation();
}
}
double adjustedZenith = adjustZenith(zenith, elevation, localDate);
double riseSet = getSunRiseSetUTC(localDate, geoLocation.getLatitude(), -geoLocation.getLongitude(),
adjustedZenith, solarEvent);
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/com/kosherjava/zmanim/util/NOAACalculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,14 @@ public double getUTCSunset(LocalDate dt, GeoLocation geoLocation, double zenith,
*/
private double getUTCSunRiseSet(LocalDate localDate, GeoLocation geoLocation, double zenith, boolean adjustForElevation,
SolarEvent solarEvent) {
double elevation = adjustForElevation ? geoLocation.getElevation() : 0;
double elevation = 0;
if (adjustForElevation) {
if (solarEvent == SolarEvent.SUNRISE) {
elevation = geoLocation.getSunriseElevation();
} else {
elevation = geoLocation.getSunsetElevation();
}
}
double adjustedZenith = adjustZenith(zenith, elevation, localDate);
double riseSet = getSunRiseSetUTC(localDate, geoLocation.getLatitude(), -geoLocation.getLongitude(),
adjustedZenith, solarEvent);
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/com/kosherjava/zmanim/util/SPACalculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,14 @@ public double getUTCSunset(LocalDate dt, GeoLocation geoLocation, double zenith,
*/
private double getUTCSunRiseSet(LocalDate localDate, GeoLocation geoLocation, double zenith,
boolean adjustForElevation, SolarEvent solarEvent) {
double elevation = adjustForElevation ? geoLocation.getElevation() : 0;
double elevation = 0;
if (adjustForElevation) {
if (solarEvent == SolarEvent.SUNRISE) {
elevation = geoLocation.getSunriseElevation();
} else {
elevation = geoLocation.getSunsetElevation();
}
}
double adjustedZenith = adjustZenith(zenith, elevation, localDate);
double riseSet = solveRiseSet(localDate, geoLocation, adjustedZenith, solarEvent);
if (Double.isNaN(riseSet)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ public String getCalculatorName() {

@Override
public double getUTCSunrise(LocalDate localDate, GeoLocation geoLocation, double zenith, boolean adjustForElevation) {
double elevation = adjustForElevation ? geoLocation.getElevation() : 0;
double elevation = adjustForElevation ? geoLocation.getSunriseElevation() : 0;
double adjustedZenith = adjustZenith(zenith, elevation, localDate);
return getTimeUTC(localDate, geoLocation, adjustedZenith, true);
}

@Override
public double getUTCSunset(LocalDate localDate, GeoLocation geoLocation, double zenith, boolean adjustForElevation) {
double elevation = adjustForElevation ? geoLocation.getElevation() : 0;
double elevation = adjustForElevation ? geoLocation.getSunsetElevation() : 0;
double adjustedZenith = adjustZenith(zenith, elevation, localDate);
return getTimeUTC(localDate, geoLocation, adjustedZenith, false);
}
Expand Down
Loading