org.oscim.renderer.light.Sun Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
/*
* Copyright 2019 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
package org.oscim.renderer.light;
import org.oscim.backend.DateTimeAdapter;
import org.oscim.backend.canvas.Color;
import org.oscim.utils.ColorUtil;
import org.oscim.utils.geom.GeometryUtils;
import org.oscim.utils.math.MathUtils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* See https://lexikon.astronomie.info/zeitgleichung
*/
public class Sun {
public static float SHADOW_ALPHA = 0.3f;
private static final DateTimeAdapter date = DateTimeAdapter.instance;
private float mSunrise; // in hours
private float mSunset; // in hours
private float mLatitude; // in degree
private float mLongitude; // in degree
private int mDayOfYear; // up to 366
private float mProgress; // 0 to 2
private float[] mSunPos = new float[3];
private int mLightColor;
private Map mColorMap;
/**
* Track sun position (accuracy of ~1 minute).
*/
public Sun() {
// Init defaults
mDayOfYear = date.getDayOfYear();
setCoordinates(0, 0);
mLightColor = Color.get(SHADOW_ALPHA, 255, 255, 255);
setProgress(0.4f);
updatePosition();
}
/**
* @return the latitude where the sun is in zenith
*/
private float declination() {
return (float) (0.4095 * Math.sin(0.016906 * (mDayOfYear - 80.086)));
}
/**
* The discrepancy of mean time and sun time.
*
* @return discrepancy in hours
*/
private float discrepancyMeanTime() {
return (float) (-0.171 * Math.sin(0.0337 * mDayOfYear + 0.465) - 0.1299 * Math.sin(0.01787 * mDayOfYear - 0.168));
}
/**
* RGB - the color of sun.
* A - the diffuse of shadow.
*/
public int getColor() {
return mLightColor;
}
/**
* Get the colors of day cycle.
*
* @return the color map
*/
public Map getColorMap() {
return mColorMap;
}
public float getLatitude() {
return mLatitude;
}
public float getLongitude() {
return mLongitude;
}
public float[] getPosition() {
return mSunPos;
}
public float getProgress() {
return mProgress;
}
/**
* @return the local sunrise time in hours.
*/
public float getSunrise() {
return mSunrise;
}
/**
* @return the local sunset time in hours.
*/
public float getSunset() {
return mSunset;
}
private void initDefaultColorMap() {
mColorMap = new HashMap<>();
mColorMap.put(0.0f, Color.get((int) (255 * SHADOW_ALPHA), 150, 120, 140)); // Sunrise
mColorMap.put(0.04f, Color.get((int) (255 * SHADOW_ALPHA), 205, 170, 160));
mColorMap.put(0.1f, Color.get((int) (255 * SHADOW_ALPHA), 245, 240, 215));
mColorMap.put(0.2f, Color.get((int) (255 * SHADOW_ALPHA), 255, 255, 255)); // Forenoon
mColorMap.put(0.8f, Color.get((int) (255 * SHADOW_ALPHA), 255, 255, 255)); // Afternoon
mColorMap.put(0.99f, Color.get((int) (255 * SHADOW_ALPHA), 255, 220, 230));
mColorMap.put(1.0f, Color.get((int) (255 * SHADOW_ALPHA), 100, 100, 130)); // Sunset
mColorMap.put(1.9f, Color.get((int) (255 * SHADOW_ALPHA), 100, 100, 130)); // Night
}
/**
* @param color RGB - the color of sun, A - the diffuse of shadow
*/
public void setColor(int color) {
mLightColor = color;
}
/**
* Set the colors of day cycle.
*/
public void setColorMap(Map colorMap) {
mColorMap = colorMap;
}
public void setCoordinates(float latitude, float longitude) {
mLatitude = latitude;
mLongitude = longitude;
updateToDay();
}
/**
* Customize day of the year.
*/
public void setDayOfYear(int day) {
mDayOfYear = day;
}
public void setPosition(float x, float y, float z) {
mSunPos[0] = x;
mSunPos[1] = y;
mSunPos[2] = z;
mSunPos = GeometryUtils.normalize(mSunPos);
}
/**
* Customize progress.
*/
public void setProgress(float progress) {
mProgress = progress;
}
/**
* Customize progress with specified time.
*
* @param hour the hour [0..23]
* @param minute the minute [0..59]
* @param second the second [0..59]
* @return the progress in range 0 to 2
*/
public float setProgress(int hour, int minute, int second) {
float time = hour;
time += minute / 60f;
time += second / 3600f;
float progress = (time - mSunrise) / (mSunset - mSunrise);
if (progress > 1f || progress < 0f) {
progress = ((time + 24 - mSunset) % 24) / (mSunrise + 24 - mSunset);
progress += 1;
}
mProgress = MathUtils.clamp(progress, 0f, 2f);
return mProgress;
}
/**
* @param h the offset of horizon (in radians) e.g. bend of earth / atmosphere etc.
* @return the difference of sunrise or sunset to noon
*/
private float timeDiff(float h) {
float lat = mLatitude * MathUtils.degreesToRadians;
float declination = declination();
return (float) (12 * Math.acos((Math.sin(h) - Math.sin(lat) * Math.sin(declination)) / (Math.cos(lat) * Math.cos(declination))) / Math.PI);
}
/**
* Update sun progress, position and color to current date time.
*/
public void update() {
updateProgress();
updatePosition();
updateColor();
}
public int updateColor() {
if (mColorMap == null)
initDefaultColorMap();
float progressStart, progressEnd;
Iterator prIter = mColorMap.keySet().iterator();
progressStart = progressEnd = prIter.next();
while (prIter.hasNext()) {
float progress = prIter.next();
if (((mProgress + 2f - progress) % 2f) < ((mProgress + 2f - progressStart) % 2f))
progressStart = progress;
else if (((progress + 2f - mProgress) % 2f) < ((progressEnd + 2f - mProgress) % 2f))
progressEnd = progress;
}
if (progressStart == progressEnd) {
mLightColor = mColorMap.get(progressStart);
return mLightColor;
}
float fraction = ((mProgress + 2f - progressStart) % 2f) / ((progressEnd + 2f - progressStart) % 2f);
int colorStart = mColorMap.get(progressStart);
int colorEnd = mColorMap.get(progressEnd);
mLightColor = ColorUtil.blend(colorStart, colorEnd, fraction);
return mLightColor;
}
/**
* Very simple normalized sun coordinates.
*/
public float[] updatePosition() {
mSunPos[0] = (float) Math.cos(mProgress * Math.PI);
mSunPos[1] = (float) Math.sin(mProgress * Math.PI);
mSunPos[2] = 3 * mSunPos[1];
mSunPos = GeometryUtils.normalize(mSunPos);
return mSunPos;
}
/**
* The progress
* of the daylight in range 0 (sunrise) to 1 (sunset) and
* of the night in range 1 (sunset) to 2 (sunrise).
*
* @return the progress in range 0 to 2
*/
public float updateProgress() {
return setProgress(date.getHour(), date.getMinute(), date.getSecond());
}
/**
* Calculate the sunrise and sunset of set day (local time).
*/
public void updateToDay() {
float h = -0.0145f; // -50 latitude minutes
float diff = timeDiff(h);
float discp = discrepancyMeanTime();
float calc = 12 - discp - (mLongitude / 15f) + (date.getTimeZoneOffset() / (60f * 60f * 1000f));
mSunrise = calc - diff;
mSunset = calc + diff;
}
}