Sun calculator (#655)
This commit is contained in:
parent
c06b2712a0
commit
eb3efa7a69
@ -71,6 +71,7 @@ public class BuildingRenderer extends ExtrusionRenderer {
|
||||
|
||||
@Override
|
||||
public void update(GLViewport v) {
|
||||
super.update(v);
|
||||
|
||||
int diff = (v.pos.zoomLevel - mZoomLimiter.getMinZoom());
|
||||
|
||||
|
@ -24,6 +24,7 @@ import org.oscim.core.Tile;
|
||||
import org.oscim.renderer.bucket.ExtrusionBucket;
|
||||
import org.oscim.renderer.bucket.ExtrusionBuckets;
|
||||
import org.oscim.renderer.bucket.RenderBuckets;
|
||||
import org.oscim.renderer.light.Sun;
|
||||
import org.oscim.utils.FastMath;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -45,11 +46,15 @@ public abstract class ExtrusionRenderer extends LayerRenderer {
|
||||
protected float mAlpha = 1;
|
||||
|
||||
private float mZLimit = Float.MAX_VALUE;
|
||||
private float[] mLightPos = new float[]{0.3f, 0.3f, 1f};
|
||||
|
||||
private Sun mSun;
|
||||
private boolean mEnableCurrentSunPos;
|
||||
|
||||
public ExtrusionRenderer(boolean mesh, boolean translucent) {
|
||||
mMesh = mesh;
|
||||
mTranslucent = translucent;
|
||||
|
||||
mSun = new Sun();
|
||||
}
|
||||
|
||||
public static class Shader extends GLShader {
|
||||
@ -115,6 +120,14 @@ public abstract class ExtrusionRenderer extends LayerRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public Sun getSun() {
|
||||
return mSun;
|
||||
}
|
||||
|
||||
public void enableCurrentSunPos(boolean enableSunPos) {
|
||||
mEnableCurrentSunPos = enableSunPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setup() {
|
||||
if (!mMesh)
|
||||
@ -125,6 +138,20 @@ public abstract class ExtrusionRenderer extends LayerRenderer {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(GLViewport viewport) {
|
||||
if (mEnableCurrentSunPos) {
|
||||
float lat = (float) viewport.pos.getLatitude();
|
||||
float lon = (float) viewport.pos.getLongitude();
|
||||
if (FastMath.abs(mSun.getLatitude() - lat) > 0.2f
|
||||
|| Math.abs(mSun.getLongitude() - lon) > 0.2f) {
|
||||
// location is only updated if necessary (not every frame)
|
||||
mSun.setCoordinates(lat, lon);
|
||||
}
|
||||
mSun.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderCombined(int vertexPointer, ExtrusionBuckets ebs) {
|
||||
|
||||
for (ExtrusionBucket eb = ebs.buckets(); eb != null; eb = eb.next()) {
|
||||
@ -171,7 +198,7 @@ public abstract class ExtrusionRenderer extends LayerRenderer {
|
||||
gl.depthFunc(GL.LESS);
|
||||
gl.uniform1f(s.uAlpha, mAlpha);
|
||||
gl.uniform1f(s.uZLimit, mZLimit);
|
||||
GLUtils.glUniform3fv(s.uLight, 1, mLightPos);
|
||||
GLUtils.glUniform3fv(s.uLight, 1, mSun.getPosition());
|
||||
|
||||
ExtrusionBuckets[] ebs = mExtrusionBucketSet;
|
||||
|
||||
|
267
vtm/src/org/oscim/renderer/light/Sun.java
Normal file
267
vtm/src/org/oscim/renderer/light/Sun.java
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<Float, Integer> 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<Float, Integer> 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<Float, Integer> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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<Float> 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;
|
||||
}
|
||||
|
||||
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() {
|
||||
// TODO Java8 replace with LocalDateTime
|
||||
// LocalDateTime date = new LocalDateTime();
|
||||
// float time = date.getHour();
|
||||
// time += date.getMinute() / 60f;
|
||||
// time += date.getSecond() / 3600f;
|
||||
|
||||
float time = date.getHour();
|
||||
time += date.getMinute() / 60f;
|
||||
time += date.getSecond() / 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user