/*
* 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.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.location.Location;
import android.preference.PreferenceManager;
import android.util.TypedValue;
import android.view.MotionEvent;
import org.mapsforge.android.maps.MapView;
import org.mapsforge.android.maps.Projection;
import org.mapsforge.core.model.GeoPoint;
import eu.geopaparazzi.library.database.GPLog;
import eu.geopaparazzi.library.features.EditManager;
import eu.geopaparazzi.library.util.MercatorUtils;
import eu.geopaparazzi.core.GeopaparazziApplication;
import eu.geopaparazzi.core.R;
import eu.geopaparazzi.core.maptools.MapTool;
import eu.geopaparazzi.core.utilities.Constants;
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 TapMeasureTool extends MapTool {
private final Paint measurePaint = new Paint();
private final Paint measureTextPaint = new Paint();
private Path measurePath = new Path();
private float measuredDistance = Float.NaN;
private String distanceString;
private float lastX = -1;
private float lastY = -1;
private final Point tmpP = new Point();
private final Rect rect = new Rect();
private StringBuilder textBuilder = new StringBuilder();
private boolean doImperial = false;
/**
* Constructor.
*
* @param mapView the mapview reference.
*/
public TapMeasureTool( MapView mapView ) {
super(mapView);
Context context = GeopaparazziApplication.getInstance().getApplicationContext();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
doImperial = preferences.getBoolean(Constants.PREFS_KEY_IMPERIAL, false);
measurePaint.setAntiAlias(true);
measurePaint.setColor(Color.DKGRAY);
measurePaint.setStrokeWidth(3f);
measurePaint.setStyle(Paint.Style.STROKE);
measureTextPaint.setAntiAlias(true);
int pixel = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, context.getResources().getDisplayMetrics());
measureTextPaint.setTextSize(pixel);
measureTextPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
distanceString = context.getString(R.string.distance);
}
public void activate() {
if (mapView != null)
mapView.setClickable(false);
}
public void onToolDraw( Canvas canvas ) {
int cWidth = canvas.getWidth();
// RectF retfF = new RectF();
// measurePath.computeBounds(retfF, true);
// GPLog.androidLog(-1, "DRAWINFOLINE: " + retfF);
canvas.drawPath(measurePath, measurePaint);
int upper = 70;
int delta = 5;
measureTextPaint.getTextBounds(distanceString, 0, distanceString.length(), rect);
int textWidth = rect.width();
int textHeight = rect.height();
int x = cWidth / 2 - textWidth / 2;
canvas.drawText(distanceString, x, upper, measureTextPaint);
textBuilder.setLength(0);
if (doImperial) {
double distanceInFeet = MercatorUtils.toFeet(measuredDistance);
textBuilder.append(String.valueOf((int) distanceInFeet));
textBuilder.append(" ft"); //$NON-NLS-1$
} else {
textBuilder.append(String.valueOf((int) measuredDistance));
textBuilder.append(" m"); //$NON-NLS-1$
}
String distanceText = textBuilder.toString();
measureTextPaint.getTextBounds(distanceText, 0, distanceText.length(), rect);
textWidth = rect.width();
x = cWidth / 2 - textWidth / 2;
canvas.drawText(distanceText, x, upper + delta + textHeight, measureTextPaint);
if (GPLog.LOG_HEAVY)
GPLog.addLogEntry(this, "Drawing measure path text: " + upper); //$NON-NLS-1$
}
public boolean onToolTouchEvent( MotionEvent event ) {
if (mapView == null || mapView.isClickable()) {
return false;
}
Projection pj = mapView.getProjection();
// handle drawing
float currentX = event.getX();
float currentY = event.getY();
tmpP.set(round(currentX), round(currentY));
int action = event.getAction();
switch( action ) {
case MotionEvent.ACTION_DOWN:
measuredDistance = 0;
measurePath.reset();
GeoPoint firstGeoPoint = pj.fromPixels(round(currentX), round(currentY));
pj.toPixels(firstGeoPoint, tmpP);
measurePath.moveTo(tmpP.x, tmpP.y);
lastX = currentX;
lastY = currentY;
if (GPLog.LOG_HEAVY)
GPLog.addLogEntry(this, "TOUCH: " + tmpP.x + "/" + tmpP.y); //$NON-NLS-1$//$NON-NLS-2$
break;
case MotionEvent.ACTION_MOVE:
float dx = currentX - lastX;
float dy = currentY - lastY;
if (abs(dx) < 1 && abs(dy) < 1) {
lastX = currentX;
lastY = currentY;
return true;
}
GeoPoint currentGeoPoint = pj.fromPixels(round(currentX), round(currentY));
pj.toPixels(currentGeoPoint, tmpP);
measurePath.lineTo(tmpP.x, tmpP.y);
if (GPLog.LOG_HEAVY)
GPLog.addLogEntry(this, "DRAG: " + tmpP.x + "/" + tmpP.y); //$NON-NLS-1$ //$NON-NLS-2$
// the measurement
GeoPoint previousGeoPoint = pj.fromPixels(round(lastX), round(lastY));
Location l1 = new Location("gps"); //$NON-NLS-1$
l1.setLatitude(previousGeoPoint.getLatitude());
l1.setLongitude(previousGeoPoint.getLongitude());
Location l2 = new Location("gps"); //$NON-NLS-1$
l2.setLatitude(currentGeoPoint.getLatitude());
l2.setLongitude(currentGeoPoint.getLongitude());
float distanceTo = l1.distanceTo(l2);
lastX = currentX;
lastY = currentY;
measuredDistance = measuredDistance + distanceTo;
EditManager.INSTANCE.invalidateEditingView();
break;
case MotionEvent.ACTION_UP:
if (GPLog.LOG_HEAVY)
GPLog.addLogEntry(this, "UNTOUCH: " + tmpP.x + "/" + tmpP.y); //$NON-NLS-1$//$NON-NLS-2$
break;
}
return true;
}
public void disable() {
if (mapView != null) {
mapView.setClickable(true);
mapView = null;
}
measuredDistance = 0;
measurePath = null;
}
@Override
public void onViewChanged() {
// ignore
}
}