-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6379 from grzesiek2010/COLLECT-6233
Show scale on map
- Loading branch information
Showing
11 changed files
with
640 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Drawer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
/* | ||
* This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), | ||
* licensed under the Apache License, Version 2.0. | ||
*/ | ||
package org.odk.collect.googlemaps.scaleview; | ||
|
||
import android.graphics.Canvas; | ||
import android.graphics.Paint; | ||
import android.graphics.Path; | ||
import android.graphics.Rect; | ||
import android.graphics.Typeface; | ||
|
||
public class Drawer { | ||
|
||
private final Paint textPaint = new Paint(); | ||
private final Paint strokePaint = new Paint(); | ||
private final Path strokePath = new Path(); | ||
|
||
private final Paint outlinePaint = new Paint(); | ||
private final Path outlineDiffPath = new Path(); | ||
private float outlineStrokeWidth = 2; // strokeWidth * 2 | ||
private float outlineStrokeDiff = outlineStrokeWidth / 2 / 2; // strokeWidth / 2 | ||
private float outlineTextStrokeWidth = 3; // density * 2 | ||
private boolean outlineEnabled = true; | ||
|
||
private float textHeight; | ||
private float horizontalLineY; | ||
|
||
private boolean expandRtlEnabled; | ||
private int viewWidth; | ||
|
||
private Scales scales = new Scales(null, null); | ||
|
||
Drawer(int color, float textSize, float strokeWidth, float density, boolean outlineEnabled, boolean expandRtlEnabled) { | ||
textPaint.setAntiAlias(true); | ||
textPaint.setColor(color); | ||
textPaint.setStyle(Paint.Style.FILL); | ||
textPaint.setTextSize(textSize); | ||
|
||
strokePaint.setAntiAlias(true); | ||
strokePaint.setColor(color); | ||
strokePaint.setStyle(Paint.Style.STROKE); | ||
strokePaint.setStrokeWidth(strokeWidth); | ||
|
||
outlinePaint.set(strokePaint); | ||
outlinePaint.setARGB(255, 255, 255, 255); | ||
outlineStrokeWidth = strokeWidth * 2; | ||
outlineStrokeDiff = strokeWidth / 2; | ||
outlineTextStrokeWidth = density * 2; | ||
this.outlineEnabled = outlineEnabled; | ||
this.expandRtlEnabled = expandRtlEnabled; | ||
|
||
update(); | ||
} | ||
|
||
private void update() { | ||
outlinePaint.setTextSize(textPaint.getTextSize()); | ||
outlinePaint.setTypeface(textPaint.getTypeface()); | ||
outlinePaint.setStrokeWidth(outlineTextStrokeWidth); | ||
|
||
Rect textRect = new Rect(); | ||
Paint highestPaint = outlineEnabled ? outlinePaint : textPaint; | ||
String possibleText = "1234567890kmift"; | ||
highestPaint.getTextBounds(possibleText, 0, possibleText.length(), textRect); | ||
textHeight = textRect.height(); | ||
|
||
horizontalLineY = textHeight + textHeight / 2; | ||
} | ||
|
||
int getWidth() { | ||
return (int) (scales.maxLength() + strokePaint.getStrokeWidth()); | ||
} | ||
|
||
int getHeight() { | ||
if (scales.bottom() != null) { | ||
return (int) (textHeight * 3 + outlineTextStrokeWidth / 2); | ||
} else { | ||
return (int) (horizontalLineY + strokePaint.getStrokeWidth()); | ||
} | ||
} | ||
|
||
void setScales(Scales scales) { | ||
this.scales = scales; | ||
} | ||
|
||
void setColor(int color) { | ||
textPaint.setColor(color); | ||
strokePaint.setColor(color); | ||
} | ||
|
||
void setTextSize(float textSize) { | ||
textPaint.setTextSize(textSize); | ||
update(); | ||
} | ||
|
||
void setTextFont(Typeface font) { | ||
textPaint.setTypeface(font); | ||
update(); | ||
} | ||
|
||
void setStrokeWidth(float strokeWidth) { | ||
strokePaint.setStrokeWidth(strokeWidth); | ||
outlineStrokeWidth = strokeWidth * 2; | ||
outlineStrokeDiff = strokeWidth / 2; | ||
update(); | ||
} | ||
|
||
void setOutlineEnabled(boolean enabled) { | ||
outlineEnabled = enabled; | ||
update(); | ||
} | ||
|
||
void setExpandRtlEnabled(boolean enabled) { | ||
expandRtlEnabled = enabled; | ||
} | ||
|
||
void setViewWidth(int width) { | ||
viewWidth = width; | ||
} | ||
|
||
void draw(Canvas canvas) { | ||
Scale top = scales.top(); | ||
if (top == null) { | ||
return; | ||
} | ||
if (expandRtlEnabled && viewWidth == 0) { | ||
expandRtlEnabled = false; | ||
} | ||
|
||
if (expandRtlEnabled) { | ||
outlinePaint.setTextAlign(Paint.Align.RIGHT); | ||
textPaint.setTextAlign(Paint.Align.RIGHT); | ||
} else { | ||
outlinePaint.setTextAlign(Paint.Align.LEFT); | ||
textPaint.setTextAlign(Paint.Align.LEFT); | ||
} | ||
|
||
if (outlineEnabled) { | ||
outlinePaint.setStrokeWidth(outlineTextStrokeWidth); | ||
canvas.drawText(top.text(), expandRtlEnabled ? viewWidth : 0, textHeight, outlinePaint); | ||
} | ||
canvas.drawText(top.text(), expandRtlEnabled ? viewWidth : 0, textHeight, textPaint); | ||
|
||
strokePath.rewind(); | ||
strokePath.moveTo(expandRtlEnabled ? (viewWidth - outlineStrokeDiff) : outlineStrokeDiff, horizontalLineY); | ||
strokePath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), horizontalLineY); | ||
if (outlineEnabled) { | ||
strokePath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight + outlineStrokeDiff); | ||
} else { | ||
strokePath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight); | ||
} | ||
|
||
Scale bottom = scales.bottom(); | ||
if (bottom != null) { | ||
|
||
if (bottom.length() > top.length()) { | ||
strokePath.moveTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), horizontalLineY); | ||
strokePath.lineTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), horizontalLineY); | ||
} else { | ||
strokePath.moveTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), horizontalLineY); | ||
} | ||
|
||
strokePath.lineTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), textHeight * 2); | ||
|
||
float bottomTextY = horizontalLineY + textHeight + textHeight / 2; | ||
if (outlineEnabled) { | ||
canvas.drawText(bottom.text(), expandRtlEnabled ? viewWidth : 0, bottomTextY, outlinePaint); | ||
} | ||
canvas.drawText(bottom.text(), expandRtlEnabled ? viewWidth : 0, bottomTextY, textPaint); | ||
} | ||
|
||
if (outlineEnabled) { | ||
outlinePaint.setStrokeWidth(outlineStrokeWidth); | ||
outlineDiffPath.rewind(); | ||
outlineDiffPath.moveTo(expandRtlEnabled ? viewWidth : 0, horizontalLineY); | ||
outlineDiffPath.lineTo(expandRtlEnabled ? (viewWidth - outlineStrokeDiff) : outlineStrokeDiff, horizontalLineY); | ||
outlineDiffPath.moveTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight + outlineStrokeDiff); | ||
outlineDiffPath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight); | ||
if (bottom != null) { | ||
outlineDiffPath.moveTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), textHeight * 2); | ||
outlineDiffPath.lineTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), textHeight * 2 + outlineStrokeDiff); | ||
} | ||
|
||
canvas.drawPath(outlineDiffPath, outlinePaint); | ||
canvas.drawPath(strokePath, outlinePaint); | ||
} | ||
|
||
canvas.drawPath(strokePath, strokePaint); | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleModel.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), | ||
* licensed under the Apache License, Version 2.0. | ||
*/ | ||
package org.odk.collect.googlemaps.scaleview; | ||
|
||
class MapScaleModel { | ||
|
||
private static final double EQUATOR_LENGTH_METERS = 40075016.686; | ||
private static final double EQUATOR_LENGTH_FEET = 131479713.537; | ||
|
||
private static final int FT_IN_MILE = 5280; | ||
|
||
private static final float[] METERS = {0.2f, 0.5f, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, | ||
2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000}; | ||
|
||
private static final float[] FT = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, | ||
FT_IN_MILE, 2 * FT_IN_MILE, 5 * FT_IN_MILE, 10 * FT_IN_MILE, 20 * FT_IN_MILE, 50 * FT_IN_MILE, | ||
100 * FT_IN_MILE, 200 * FT_IN_MILE, 500 * FT_IN_MILE, 1000 * FT_IN_MILE, 2000 * FT_IN_MILE}; | ||
|
||
private final float density; | ||
private int maxWidth; | ||
|
||
private float lastZoom = -1; | ||
private double lastLatitude = -100; | ||
|
||
private double tileSizeMetersAt0Zoom = EQUATOR_LENGTH_METERS / 256; | ||
private double tileSizeFeetAt0Zoom = EQUATOR_LENGTH_FEET / 256; | ||
|
||
MapScaleModel(float density) { | ||
this.density = density; | ||
} | ||
|
||
// returns true if width changed | ||
boolean updateMaxWidth(int width) { | ||
if (maxWidth != width) { | ||
maxWidth = width; | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
void setTileSize(int tileSize) { | ||
tileSizeMetersAt0Zoom = EQUATOR_LENGTH_METERS / tileSize; | ||
tileSizeFeetAt0Zoom = EQUATOR_LENGTH_FEET / tileSize; | ||
} | ||
|
||
void setPosition(float zoom, double latitude) { | ||
lastZoom = zoom; | ||
lastLatitude = latitude; | ||
} | ||
|
||
/** | ||
* See http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale | ||
*/ | ||
Scale update(boolean meters) { | ||
float zoom = lastZoom; | ||
double latitude = lastLatitude; | ||
if (zoom < 0 || Math.abs(latitude) > 90) { | ||
return null; | ||
} | ||
|
||
double tileSizeAtZoom0 = meters ? tileSizeMetersAt0Zoom : tileSizeFeetAt0Zoom; | ||
float[] distances = meters ? METERS : FT; | ||
|
||
final double resolution = tileSizeAtZoom0 / density * Math.cos(latitude * Math.PI / 180) / Math.pow(2, zoom); | ||
|
||
float distance = 0; | ||
int distanceIndex = distances.length; | ||
double screenDistance = maxWidth + 1; | ||
|
||
while (screenDistance > maxWidth && distanceIndex > 0) { | ||
distance = distances[--distanceIndex]; | ||
screenDistance = Math.abs(distance / resolution); | ||
} | ||
|
||
lastZoom = zoom; | ||
lastLatitude = latitude; | ||
return new Scale(text(distance, meters), (float) screenDistance); | ||
} | ||
|
||
private String text(float distance, boolean meters) { | ||
if (meters) { | ||
if (distance < 1) { | ||
return (int) (distance * 100) + " cm"; | ||
} else if (distance < 1000) { | ||
return (int) distance + " m"; | ||
} else { | ||
return (int) distance / 1000 + " km"; | ||
} | ||
} else { | ||
if (distance < FT_IN_MILE) { | ||
return (int) distance + " ft"; | ||
} else { | ||
return (int) distance / FT_IN_MILE + " mi"; | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.