Skip to content

Commit

Permalink
Location renderer with many improvements and fixes, closes openscienc…
Browse files Browse the repository at this point in the history
  • Loading branch information
devemux86 committed Sep 17, 2016
1 parent 7cdeacd commit 769dd69
Show file tree
Hide file tree
Showing 4 changed files with 338 additions and 290 deletions.
3 changes: 2 additions & 1 deletion docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
- Native libraries for all platforms [#14](https://github.com/mapsforge/vtm/issues/14)
- Line stipple and texture rendering [#105](https://github.com/mapsforge/vtm/issues/105)
- Layer groups [#99](https://github.com/mapsforge/vtm/issues/99) [#103](https://github.com/mapsforge/vtm/issues/103)
- Map scale bar multi-platform [#84](https://github.com/mapsforge/vtm/issues/84)
- Location renderer [#171](https://github.com/mapsforge/vtm/issues/171)
- Map scale bar [#84](https://github.com/mapsforge/vtm/issues/84)
- libGDX layer gestures [#151](https://github.com/mapsforge/vtm/issues/151)
- LWJGL desktop libGDX backend [#129](https://github.com/mapsforge/vtm/issues/129)
- Render theme area tessellation option [#37](https://github.com/mapsforge/vtm/issues/37)
Expand Down
8 changes: 5 additions & 3 deletions vtm-app/src/org/oscim/app/location/Compass.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright 2013 Ahmad Saleem
* Copyright 2013 Hannes Janetzek
* Copyright 2016 devemux86
*
* 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
Expand All @@ -13,7 +14,6 @@
* 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.app.location;

import android.content.Context;
Expand All @@ -31,10 +31,11 @@
import org.oscim.event.Event;
import org.oscim.layers.Layer;
import org.oscim.map.Map;
import org.oscim.renderer.LocationRenderer;

@SuppressWarnings("deprecation")
public class Compass extends Layer implements SensorEventListener,
Map.UpdateListener {
public class Compass extends Layer implements SensorEventListener, Map.UpdateListener,
LocationRenderer.Callback {

// final static Logger log = LoggerFactory.getLogger(Compass.class);

Expand Down Expand Up @@ -84,6 +85,7 @@ public Compass(Context context, Map map) {
setEnabled(false);
}

@Override
public synchronized float getRotation() {
return mCurRotation;
}
Expand Down
297 changes: 11 additions & 286 deletions vtm-app/src/org/oscim/app/location/LocationOverlay.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,44 +16,29 @@
*/
package org.oscim.app.location;

import android.os.SystemClock;

import org.oscim.backend.GL;
import org.oscim.core.Box;
import org.oscim.core.MercatorProjection;
import org.oscim.core.Point;
import org.oscim.core.Tile;
import org.oscim.layers.Layer;
import org.oscim.map.Map;
import org.oscim.renderer.GLShader;
import org.oscim.renderer.GLState;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.LayerRenderer;
import org.oscim.renderer.MapRenderer;
import org.oscim.utils.FastMath;
import org.oscim.utils.math.Interpolation;

import static org.oscim.backend.GLAdapter.gl;
import org.oscim.renderer.LocationRenderer;

public class LocationOverlay extends Layer {
private final int SHOW_ACCURACY_ZOOM = 16;

private final Point mLocation = new Point();
private double mRadius;

private final Compass mCompass;
private final LocationRenderer mLocationRenderer;

public LocationOverlay(Map map, Compass compass) {
super(map);
mRenderer = new LocationIndicator(map);
mCompass = compass;

mRenderer = mLocationRenderer = new LocationRenderer(mMap, this);
mLocationRenderer.setCallback(compass);
}

public void setPosition(double latitude, double longitude, double accuracy) {
mLocation.x = MercatorProjection.longitudeToX(longitude);
mLocation.y = MercatorProjection.latitudeToY(latitude);
mRadius = accuracy / MercatorProjection.groundResolution(latitude, 1);
((LocationIndicator) mRenderer).animate(true);
double x = MercatorProjection.longitudeToX(longitude);
double y = MercatorProjection.latitudeToY(latitude);
double radius = accuracy / MercatorProjection.groundResolution(latitude, 1);
mLocationRenderer.setLocation(x, y, radius);
mLocationRenderer.animate(true);
}

@Override
Expand All @@ -64,268 +49,8 @@ public void setEnabled(boolean enabled) {
super.setEnabled(enabled);

if (!enabled)
((LocationIndicator) mRenderer).animate(false);
mLocationRenderer.animate(false);

mCompass.setEnabled(enabled);
}

public class LocationIndicator extends LayerRenderer {
private int mShaderProgram;
private int hVertexPosition;
private int hMatrixPosition;
private int hScale;
private int hPhase;
private int hDirection;

private final float CIRCLE_SIZE = 60;

private final static long ANIM_RATE = 50;
private final static long INTERVAL = 2000;

private final Point mIndicatorPosition = new Point();

private final Point mScreenPoint = new Point();
private final Box mBBox = new Box();

private boolean mInitialized;

private boolean mLocationIsVisible;

private boolean mRunAnim;
private long mAnimStart;

public LocationIndicator(final Map map) {
super();
}

private void animate(boolean enable) {
if (mRunAnim == enable)
return;

mRunAnim = enable;
if (!enable)
return;

final Runnable action = new Runnable() {
private long lastRun;

@Override
public void run() {
if (!mRunAnim)
return;

long diff = SystemClock.elapsedRealtime() - lastRun;
mMap.postDelayed(this, Math.min(ANIM_RATE, diff));
mMap.render();
}
};

mAnimStart = SystemClock.elapsedRealtime();
mMap.postDelayed(action, ANIM_RATE);
}

private float animPhase() {
return (float) ((MapRenderer.frametime - mAnimStart) % INTERVAL) / INTERVAL;
}

@Override
public void update(GLViewport v) {

if (!mInitialized) {
init();
mInitialized = true;
}

if (!isEnabled()) {
setReady(false);
return;
}

if (!v.changed() && isReady())
return;

setReady(true);

int width = mMap.getWidth();
int height = mMap.getHeight();

// clamp location to a position that can be
// savely translated to screen coordinates
v.getBBox(mBBox, 0);

double x = mLocation.x;
double y = mLocation.y;

if (!mBBox.contains(mLocation)) {
x = FastMath.clamp(x, mBBox.xmin, mBBox.xmax);
y = FastMath.clamp(y, mBBox.ymin, mBBox.ymax);
}

// get position of Location in pixel relative to
// screen center
v.toScreenPoint(x, y, mScreenPoint);

x = mScreenPoint.x + width / 2;
y = mScreenPoint.y + height / 2;

// clip position to screen boundaries
int visible = 0;

if (x > width - 5)
x = width;
else if (x < 5)
x = 0;
else
visible++;

if (y > height - 5)
y = height;
else if (y < 5)
y = 0;
else
visible++;

mLocationIsVisible = (visible == 2);

// set location indicator position
v.fromScreenPoint(x, y, mIndicatorPosition);
}

@Override
public void render(GLViewport v) {

GLState.useProgram(mShaderProgram);
GLState.blend(true);
GLState.test(false, false);

GLState.enableVertexArrays(hVertexPosition, -1);
MapRenderer.bindQuadVertexVBO(hVertexPosition/*, true*/);

float radius = CIRCLE_SIZE;

animate(true);
boolean viewShed = false;
if (!mLocationIsVisible /* || pos.zoomLevel < SHOW_ACCURACY_ZOOM */) {
//animate(true);
} else {
if (v.pos.zoomLevel >= SHOW_ACCURACY_ZOOM)
radius = (float) (mRadius * v.pos.scale);

viewShed = true;
//animate(false);
}
gl.uniform1f(hScale, radius);

double x = mIndicatorPosition.x - v.pos.x;
double y = mIndicatorPosition.y - v.pos.y;
double tileScale = Tile.SIZE * v.pos.scale;

v.mvp.setTransScale((float) (x * tileScale), (float) (y * tileScale), 1);
v.mvp.multiplyMM(v.viewproj, v.mvp);
v.mvp.setAsUniform(hMatrixPosition);

if (!viewShed) {
float phase = Math.abs(animPhase() - 0.5f) * 2;
//phase = Interpolation.fade.apply(phase);
phase = Interpolation.swing.apply(phase);

gl.uniform1f(hPhase, 0.8f + phase * 0.2f);
} else {
gl.uniform1f(hPhase, 1);
}

if (viewShed && mLocationIsVisible) {
float rotation = mCompass.getRotation() - 90;
gl.uniform2f(hDirection,
(float) Math.cos(Math.toRadians(rotation)),
(float) Math.sin(Math.toRadians(rotation)));
} else {
gl.uniform2f(hDirection, 0, 0);
}

gl.drawArrays(GL.TRIANGLE_STRIP, 0, 4);
}

private boolean init() {
int shader = GLShader.createProgram(vShaderStr, fShaderStr);
if (shader == 0)
return false;

mShaderProgram = shader;
hVertexPosition = gl.getAttribLocation(shader, "a_pos");
hMatrixPosition = gl.getUniformLocation(shader, "u_mvp");
hPhase = gl.getUniformLocation(shader, "u_phase");
hScale = gl.getUniformLocation(shader, "u_scale");
hDirection = gl.getUniformLocation(shader, "u_dir");

return true;
}

private final static String vShaderStr = ""
+ "precision mediump float;"
+ "uniform mat4 u_mvp;"
+ "uniform float u_phase;"
+ "uniform float u_scale;"
+ "attribute vec2 a_pos;"
+ "varying vec2 v_tex;"
+ "void main() {"
+ " gl_Position = u_mvp * vec4(a_pos * u_scale * u_phase, 0.0, 1.0);"
+ " v_tex = a_pos;"
+ "}";

private final static String fShaderStr = ""
+ "precision mediump float;"
+ "varying vec2 v_tex;"
+ "uniform float u_scale;"
+ "uniform float u_phase;"
+ "uniform vec2 u_dir;"

+ "void main() {"
+ " float len = 1.0 - length(v_tex);"
+ " if (u_dir.x == 0.0 && u_dir.y == 0.0){"
+ " gl_FragColor = vec4(0.2, 0.2, 0.8, 1.0) * len;"
+ " } else {"
/// outer ring
+ " float a = smoothstep(0.0, 2.0 / u_scale, len);"
/// inner ring
+ " float b = 0.5 * smoothstep(4.0 / u_scale, 5.0 / u_scale, len);"
/// center point
+ " float c = 0.5 * (1.0 - smoothstep(14.0 / u_scale, 16.0 / u_scale, 1.0 - len));"
+ " vec2 dir = normalize(v_tex);"
+ " float d = 1.0 - dot(dir, u_dir); "
/// 0.5 width of viewshed
+ " d = clamp(step(0.5, d), 0.4, 0.7);"
/// - subtract inner from outer to create the outline
/// - multiply by viewshed
/// - add center point
+ " a = d * (a - (b + c)) + c;"
+ " gl_FragColor = vec4(0.2, 0.2, 0.8, 1.0) * a;"
+ "}}";

//private final static String fShaderStr = ""
// + "precision mediump float;"
// + "varying vec2 v_tex;"
// + "uniform float u_scale;"
// + "uniform float u_phase;"
// + "uniform vec2 u_dir;"
// + "void main() {"
// + " float len = 1.0 - length(v_tex);"
// /// outer ring
// + " float a = smoothstep(0.0, 2.0 / u_scale, len);"
// /// inner ring
// + " float b = 0.8 * smoothstep(3.0 / u_scale, 4.0 / u_scale, len);"
// /// center point
// + " float c = 0.5 * (1.0 - smoothstep(14.0 / u_scale, 16.0 / u_scale, 1.0 - len));"
// + " vec2 dir = normalize(v_tex);"
// + " float d = dot(dir, u_dir); "
// /// 0.5 width of viewshed
// + " d = clamp(smoothstep(0.7, 0.7 + 2.0/u_scale, d) * len, 0.0, 1.0);"
// /// - subtract inner from outer to create the outline
// /// - multiply by viewshed
// /// - add center point
// + " a = max(d, (a - (b + c)) + c);"
// + " gl_FragColor = vec4(0.2, 0.2, 0.8, 1.0) * a;"
// + "}";

}
}
Loading

0 comments on commit 769dd69

Please sign in to comment.