Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.oscim.map.ViewController Maven / Gradle / Ivy
/*
* Copyright 2016-2019 devemux86
* Copyright 2017 Luca Osten
* Copyright 2018 Izumi Kawashima
* Copyright 2018 Mathieu De Brito
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* 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.map;
import org.oscim.core.MapPosition;
import org.oscim.core.Point;
import org.oscim.core.Tile;
import org.oscim.renderer.GLMatrix;
import org.oscim.utils.FastMath;
import org.oscim.utils.ThreadUtils;
import static org.oscim.utils.FastMath.clamp;
public class ViewController extends Viewport {
private float mPivotX = 0.0f;
private float mPivotY = 0.0f;
private final float[] mat = new float[16];
public void setViewSize(int width, int height) {
ThreadUtils.assertMainThread();
mHeight = height;
mWidth = width;
/* setup projection matrix:
* 0. scale to window coordinates
* 1. translate to VIEW_DISTANCE
* 2. apply projection
* setup inverse projection:
* 0. invert projection
* 1. invert translate to VIEW_DISTANCE */
float ratio = (mHeight / mWidth) * VIEW_SCALE;
GLMatrix.frustumM(mat, 0, -VIEW_SCALE, VIEW_SCALE,
ratio, -ratio, VIEW_NEAR, VIEW_FAR);
mProjMatrix.set(mat);
mTmpMatrix.setTranslation(0, 0, -VIEW_DISTANCE);
mProjMatrix.multiplyRhs(mTmpMatrix);
/* set inverse projection matrix (without scaling) */
mProjMatrix.get(mat);
GLMatrix.invertM(mat, 0, mat, 0);
mProjMatrixInverse.set(mat);
mProjMatrixUnscaled.copy(mProjMatrix);
/* scale to window coordinates */
mTmpMatrix.setScale(1 / mWidth, 1 / mWidth, 1 / mWidth);
mProjMatrix.multiplyRhs(mTmpMatrix);
updateMatrices();
}
/**
* Get pivot horizontal / vertical relative to view center.
* e.g. pivotY 0.5 is usually preferred for navigation, moving center to 25% of view height.
* Range is [-1, 1].
*/
public float[] getMapViewCenter() {
return new float[]{mPivotX, mPivotY};
}
/**
* Set pivot horizontal / vertical relative to view center.
* e.g. pivotY 0.5 is usually preferred for navigation, moving center to 25% of view height.
* Range is [-1, 1].
*/
public void setMapViewCenter(float pivotX, float pivotY) {
mPivotX = FastMath.clamp(pivotX, -1, 1) * 0.5f;
mPivotY = FastMath.clamp(pivotY, -1, 1) * 0.5f;
}
/**
* Moves this Viewport by the given amount of pixels.
*
* @param mx the amount of pixels to move the map horizontally.
* @param my the amount of pixels to move the map vertically.
*/
public synchronized void moveMap(float mx, float my) {
ThreadUtils.assertMainThread();
applyRotation(mx, my, mPos.bearing, mMovePoint);
double tileScale = mPos.scale * Tile.SIZE;
moveTo(mPos.x - mMovePoint.x / tileScale, mPos.y - mMovePoint.y / tileScale);
}
/* used by MapAnimator */
void moveTo(double x, double y) {
mPos.x = x;
mPos.y = y;
/* clamp latitude */
mPos.y = FastMath.clamp(mPos.y, 0, 1);
/* wrap longitude */
while (mPos.x > 1)
mPos.x -= 1;
while (mPos.x < 0)
mPos.x += 1;
/* limit longitude */
if (mPos.x > mMaxX)
mPos.x = mMaxX;
else if (mPos.x < mMinX)
mPos.x = mMinX;
/* limit latitude */
if (mPos.y > mMaxY)
mPos.y = mMaxY;
else if (mPos.y < mMinY)
mPos.y = mMinY;
}
/**
* @param mx the amount of pixels to move the map horizontally.
* @param my the amount of pixels to move the map vertically.
* @param bearing the bearing to rotate the map.
* @param out the position where to move.
*/
public static void applyRotation(double mx, double my, float bearing, Point out) {
if (out == null)
out = new Point();
if (bearing == 0) {
out.x = mx;
out.y = my;
} else {
double rad = Math.toRadians(bearing);
double rcos = Math.cos(rad);
double rsin = Math.sin(rad);
out.x = mx * rcos + my * rsin;
out.y = mx * -rsin + my * rcos;
}
}
/**
* Scale map by scale width center at pivot in pixel relative to
* view center. Map scale is clamp to MIN_SCALE and MAX_SCALE.
*
* @return true if scale was changed
*/
public boolean scaleMap(float scale, float pivotX, float pivotY) {
ThreadUtils.assertMainThread();
// just sanitize input
//scale = FastMath.clamp(scale, 0.5f, 2);
if (scale < 0.000001)
return false;
double newScale = mPos.scale * scale;
newScale = clamp(newScale, mMinScale, mMaxScale);
if (newScale == mPos.scale)
return false;
scale = (float) (newScale / mPos.scale);
mPos.scale = newScale;
if (pivotX != 0 || pivotY != 0) {
pivotX -= mWidth * mPivotX;
pivotY -= mHeight * mPivotY;
moveMap(pivotX * (1.0f - scale),
pivotY * (1.0f - scale));
}
return true;
}
/**
* Rotate map by radians around pivot. Pivot is in pixel relative
* to view center.
*/
public void rotateMap(double radians, float pivotX, float pivotY) {
ThreadUtils.assertMainThread();
double rsin = Math.sin(radians);
double rcos = Math.cos(radians);
pivotX -= mWidth * mPivotX;
pivotY -= mHeight * mPivotY;
float x = (float) (pivotX - pivotX * rcos + pivotY * rsin);
float y = (float) (pivotY - pivotX * rsin - pivotY * rcos);
moveMap(x, y);
setRotation(mPos.bearing + Math.toDegrees(radians));
}
public void setRotation(double degree) {
ThreadUtils.assertMainThread();
degree = FastMath.clampDegree(degree);
mPos.bearing = (float) degree;
updateMatrices();
}
public void rollMap(float move) {
setRoll(mPos.roll + move);
}
public void setRoll(double degree) {
ThreadUtils.assertMainThread();
degree = FastMath.clampDegree(degree);
mPos.roll = (float) degree;
updateMatrices();
}
public boolean tiltMap(float move) {
return setTilt(mPos.tilt + move);
}
public boolean setTilt(float tilt) {
ThreadUtils.assertMainThread();
tilt = limitTilt(tilt);
if (tilt == mPos.tilt)
return false;
mPos.tilt = tilt;
updateMatrices();
return true;
}
public void setMapPosition(MapPosition mapPosition) {
ThreadUtils.assertMainThread();
mPos.copy(mapPosition);
limitPosition(mPos);
// mPos.scale = clamp(mapPosition.scale, mMinScale, mMaxScale);
// mPos.x = mapPosition.x;
// mPos.y = mapPosition.y;
// mPos.tilt = limitTilt(mapPosition.tilt);
// mPos.bearing = mapPosition.bearing;
updateMatrices();
}
private void updateMatrices() {
/* - view matrix:
* 0. apply yaw
* 1. apply roll
* 2. apply pitch */
mRotationMatrix.setRotation(mPos.bearing, 0, 0, 1);
mTmpMatrix.setRotation(mPos.roll, 0, 1, 0);
mRotationMatrix.multiplyLhs(mTmpMatrix);
mTmpMatrix.setRotation(mPos.tilt, 1, 0, 0);
mRotationMatrix.multiplyLhs(mTmpMatrix);
mViewMatrix.copy(mRotationMatrix);
mTmpMatrix.setTranslation(mPivotX * mWidth, mPivotY * mHeight, 0);
mViewMatrix.multiplyLhs(mTmpMatrix);
mViewProjMatrix.multiplyMM(mProjMatrix, mViewMatrix);
mViewProjMatrix.get(mat);
GLMatrix.invertM(mat, 0, mat, 0);
mUnprojMatrix.set(mat);
}
public final Viewport mNextFrame = new Viewport();
/**
* synchronize on this object when doing multiple calls on it
*/
public final Viewport getSyncViewport() {
return mNextFrame;
}
boolean sizeChanged() {
synchronized (mNextFrame) {
return mNextFrame.sizeChanged(this);
}
}
public void syncViewport() {
synchronized (mNextFrame) {
mNextFrame.copy(this);
}
}
public boolean getSyncViewport(Viewport v) {
synchronized (mNextFrame) {
return v.copy(mNextFrame);
}
}
public boolean getSyncMapPosition(MapPosition mapPosition) {
synchronized (mNextFrame) {
return mNextFrame.getMapPosition(mapPosition);
}
}
}