/*
* Geopaparazzi - Digital field mapping on Android based devices
* Copyright (C) 2016 HydroloGIS (www.hydrologis.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.geopaparazzi.core.maptools.tools;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.MotionEvent;
import org.mapsforge.android.maps.MapView;
import eu.geopaparazzi.library.features.EditManager;
import eu.geopaparazzi.library.sensors.OrientationSensor;
import eu.geopaparazzi.core.maptools.MapTool;
import static java.lang.Math.abs;
import static java.lang.Math.round;
/**
* A tool to measure by means of drawing on the map.
*
* @author Andrea Antonello (www.hydrologis.com)
*/
public class ViewingConeTool extends MapTool implements SensorEventListener {
private final Paint conePaint = new Paint();
private OrientationSensor orientationSensor;
private Path conePath = new Path();
private SensorManager sensorManager;
private Activity activity;
private float[] mGravity = null;
private float[] mGeomagnetic = null;
private float azimuth360 = -1;
/**
* Constructor.
*
* @param mapView the mapview reference.
*/
public ViewingConeTool(MapView mapView, Activity activity) {
super(mapView);
this.activity = activity;
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
conePaint.setAntiAlias(true);
conePaint.setColor(Color.RED);
conePaint.setStyle(Paint.Style.FILL);
conePaint.setAlpha(128);
}
public void activate() {
if (mapView != null)
mapView.setClickable(false);
sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
// orientationSensor = new OrientationSensor(sensorManager, null);
// orientationSensor.register(activity, SensorManager.SENSOR_DELAY_NORMAL);
//
// Sensor sensorGravity = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
// sensorManager.registerListener(this, sensorGravity, SensorManager.SENSOR_DELAY_NORMAL);
Sensor sensorAcc = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, sensorAcc, SensorManager.SENSOR_DELAY_NORMAL);
Sensor sensorMag = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sensorManager.registerListener(this, sensorMag, SensorManager.SENSOR_DELAY_NORMAL);
}
public void onToolDraw(Canvas canvas) {
double delta = 5;
// double azimuth = orientationSensor.getAzimuthDegrees();
int cWidth = canvas.getWidth();
int cHeight = canvas.getHeight();
int halfX = cWidth / 2;
int halfY = cHeight / 2;
conePath.reset();
conePath.moveTo(halfX, halfY);
double az1 = azimuth360 - delta;
if (az1 < 0) az1 = 360 + az1;
double az2 = azimuth360 + delta;
if (az2 > 360) az2 = az2 - 360;
// GPLog.addLogEntry(this, "1: " + halfX + "/" + halfY);
// GPLog.addLogEntry(this, "ang: " + az1 + "/" + az2);
moveToXYByAngle(cWidth, cHeight, halfX, halfY, az1);
moveToXYByAngle(cWidth, cHeight, halfX, halfY, az2);
conePath.lineTo(halfX, halfY);
canvas.drawPath(conePath, conePaint);
}
private void moveToXYByAngle(int cWidth, int cHeight, int halfX, int halfY, double az) {
float x = 0;
float y = 0;
if (az > 0 && az < 90) {
x = halfX + (float) (halfY * Math.tan(Math.toRadians(az)));
y = 0;
if (x > cWidth) {
y = halfY * (x - halfX) / x;
x = cWidth;
}
} else if (az > 90 && az < 180) {
az = az - 90;
x = halfX + (float) (halfY / Math.tan(Math.toRadians(az)));
y = cHeight;
if (x > cWidth) {
y = cHeight - halfY * (x - halfX) / x;
x = cWidth;
}
} else if (az > 180 && az < 270) {
az = az - 180;
x = halfX - (float) (halfY * Math.tan(Math.toRadians(az)));
y = cHeight;
if (x < 0) {
y = cHeight - halfY * (-x) / (-x + halfX);
x = 0;
}
} else if (az > 270 && az < 360) {
az = az - 270;
x = halfX - (float) (halfY / Math.tan(Math.toRadians(az)));
y = 0;
if (x < 0) {
y = halfY * (-x) / (-x + halfX);
x = 0;
}
} else if (az == 90) {
x = cWidth;
y = halfY;
} else if (az == 180) {
x = halfX;
y = cHeight;
} else if (az == 270) {
x = 0;
y = halfY;
} else if (az == 0) {
x = halfX;
y = 0;
}
conePath.lineTo(x, y);
// GPLog.addLogEntry(this, "2: " + x + "/" + y);
}
public boolean onToolTouchEvent(MotionEvent event) {
return false;
}
public void disable() {
if (sensorManager != null)
sensorManager.unregisterListener(this);
if (orientationSensor != null)
orientationSensor.unregister();
if (mapView != null) {
mapView.setClickable(true);
mapView = null;
}
conePath = null;
activity = null;
}
@Override
public void onViewChanged() {
// ignore
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
mGravity = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
mGeomagnetic = event.values;
if (mGravity != null && mGeomagnetic != null) {
float R[] = new float[9];
float I[] = new float[9];
if (SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic)) {
// orientation contains azimuth360, pitch and roll
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
float azRad = orientation[0]; // az between -PI and PI
if (azRad < 0) {
azRad = (float) (2 * Math.PI + azRad);
}
azimuth360 = (float) Math.toDegrees(azRad);
Log.i("AZIM", "AZ: " + azimuth360);
}
}
EditManager.INSTANCE.invalidateEditingView();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}