package org.mtransit.android.ui.view;
import org.mtransit.android.commons.Constants;
import org.mtransit.android.commons.MTLog;
import org.mtransit.android.commons.SensorUtils;
import org.mtransit.android.commons.ui.view.MTView;
import org.mtransit.android.data.POIManager;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.location.Location;
import android.util.AttributeSet;
public class MTCompassView extends MTView {
private static final String TAG = MTCompassView.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private int headingInDegree = -1; // 0-360°
private Paint compassPaint;
private RectF bounds;
private float boundsExactCenterX;
private float boundsExactCenterY;
private Path headingArrayPath;
public MTCompassView(Context context) {
super(context);
init();
}
public MTCompassView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MTCompassView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
if (Constants.LOG_VIEW_LIFECYCLE) {
MTLog.v(this, "init()");
}
this.compassPaint = new Paint();
if (!isInEditMode()) {
this.compassPaint.setColor(POIManager.getDefaultDistanceAndCompassColor(getContext()));
}
this.compassPaint.setAntiAlias(true);
}
public void setColor(int color) {
this.compassPaint.setColor(color);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (this.headingInDegree >= 0) {
canvas.rotate(this.headingInDegree, this.boundsExactCenterX, this.boundsExactCenterY);
canvas.drawPath(this.headingArrayPath, this.compassPaint);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
float innerCircleDiameter = Math.min(w, h);
float left = w > innerCircleDiameter ? (w - innerCircleDiameter) / 2 : 0;
float top = h > innerCircleDiameter ? (h - innerCircleDiameter) / 2 : 0;
float right = left + innerCircleDiameter;
float bottom = top + innerCircleDiameter;
left += getPaddingLeft();
top += getPaddingTop();
right -= getPaddingRight();
bottom -= getPaddingBottom();
this.bounds = new RectF(left, top, right, bottom);
this.boundsExactCenterX = left + (this.bounds.right - this.bounds.left) / 2;
this.boundsExactCenterY = top + (this.bounds.bottom - this.bounds.top) / 2;
this.headingArrayPath = getHeadingArrow();
}
private Path getHeadingArrow() {
Path path = new Path();
// we want to crossing between the inner circle and the quarter of the width or the circle
float innerCircleWidth = this.bounds.right - this.bounds.left;
float innerCircleRadius = innerCircleWidth / 2;
float x = this.bounds.left + -(innerCircleWidth / 4);
float y = (float) Math.sqrt(Math.pow(innerCircleRadius, 2) - Math.pow(x, 2));
float innerCircleBottom = this.bounds.top + innerCircleRadius + y;
float arrowWidth = innerCircleRadius / 2;
path.moveTo(this.boundsExactCenterX, this.bounds.top); // center top
path.lineTo(this.boundsExactCenterX - arrowWidth, innerCircleBottom); // "/"
path.lineTo(this.boundsExactCenterX, this.boundsExactCenterY + arrowWidth / 2); // "/"
path.lineTo(this.boundsExactCenterX + arrowWidth, innerCircleBottom); // "\"
// path.lineTo(this.boundsExactCenterX, this.bounds.top); // "\" // not mandatory
path.close();
return path;
}
private Double lat;
private Double lng;
public void generateAndSetHeading(Location location, int lastCompassInDegree, float locationDeclination) {
if (this.lat == null || this.lng == null || location == null) {
return;
}
float compassRotation = SensorUtils.getCompassRotationInDegree(location.getLatitude(), location.getLongitude(), this.lat, this.lng,
lastCompassInDegree, locationDeclination);
setHeadingInDegree((int) compassRotation);
}
public void setLatLng(Double lat, Double lng) {
this.lat = lat;
this.lng = lng;
}
public void setHeadingInDegree(int headingInDegree) {
headingInDegree = SensorUtils.convertToPosivite360Degree(headingInDegree); // should not be necessary anymore
if (this.headingInDegree != headingInDegree) {
this.headingInDegree = headingInDegree;
invalidate();
}
}
public void resetHeading() {
if (this.headingInDegree < 0) {
return; // skip
}
this.headingInDegree = -1; // no data
invalidate();
}
public boolean isHeadingSet() {
return this.headingInDegree >= 0;
}
}