【发布时间】:2016-01-20 18:16:44
【问题描述】:
我搜索了所有互联网,但没有找到问题的答案。我正在使用osmdroid,我想在多边形上添加网格,如图所示。我在 stackoverflow 中找到了一个类似的question,但这个问题没有答案。那么请告诉我这可能吗?
【问题讨论】:
标签: android osmdroid offlineapps mapping
我搜索了所有互联网,但没有找到问题的答案。我正在使用osmdroid,我想在多边形上添加网格,如图所示。我在 stackoverflow 中找到了一个类似的question,但这个问题没有答案。那么请告诉我这可能吗?
【问题讨论】:
标签: android osmdroid offlineapps mapping
@Mker 给出了一个很好的起点:BitmapShader。
这是一个示例代码:
public class GridPolygon extends Polygon {
private BitmapShader bitmapShader;
public GridPolygon(Context ctx) {
super(ctx);
}
public void setPatternBMP(@NonNull final Bitmap patternBMP) {
bitmapShader = new BitmapShader(patternBMP, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mFillPaint.setShader(bitmapShader);
}
}
用法:
final GridPolygon polygon = new GridPolygon(context);
polygon.setPoints(geoData);
polygon.setFillColor(fillColor);
polygon.setStrokeColor(strokeColor);
polygon.setStrokeWidth(strokeWidth);
polygon.setPatternBMP(BitmapFactory.decodeResource(getResources(), R.drawable.pattern));
map.getOverlays().add(polygon);
map.invalidate();
但如果您尝试移动多边形,您可能会感到困惑 - 位图不想移动:
为避免这种情况,您应该计算着色器的偏移量:
public class GridPolygon extends Polygon {
private BitmapShader bitmapShader;
private IGeoPoint lastCenterGeoPoint;
private int xOffset = 0;
private int yOffset = 0;
public GridPolygon(Context ctx) {
super(ctx);
}
public void setPatternBMP(@NonNull final Bitmap patternBMP) {
bitmapShader = new BitmapShader(patternBMP, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
mFillPaint.setShader(bitmapShader);
}
protected void recalculateMatrix(@NonNull final MapView mapView) {
//final int mapSize = TileSystem.MapSize(mapView.getZoomLevel());
final Projection projection = mapView.getProjection();
final IGeoPoint geoPoint = mapView.getMapCenter();
if (lastCenterGeoPoint == null) lastCenterGeoPoint = geoPoint;
final Point point = projection.toPixels(geoPoint, null);
final Point lastCenterPoint = projection.toPixels(lastCenterGeoPoint, null);
xOffset += lastCenterPoint.x - point.x;
yOffset += lastCenterPoint.y - point.y;
xOffset %= 100; // 100 is pixel size of shader image
yOffset %= 100;
final Matrix matrix = new Matrix();
matrix.reset();
matrix.setScale(1,1);
matrix.preTranslate(xOffset, yOffset);
//matrix.setTranslate(xOffset, yOffset);
bitmapShader.setLocalMatrix(matrix);
mFillPaint.setShader(bitmapShader);
lastCenterGeoPoint = geoPoint;
}
@Override
protected void draw(Canvas canvas, MapView mapView, boolean shadow) {
recalculateMatrix(mapView);
super.draw(canvas, mapView, shadow);
}
}
结果:
【讨论】:
是的,这是可能的。
有一些潜在的解决方案。 1)假设有人很好地制作了满足您需求的kml文件,则可以使用osmbonuspack直接导入kml文件。
2) 以编程方式自己制作。所以你有一些任务。
a) 将多边形设为叠加层 b) 将网格作为叠加层 c) 按该顺序将它们添加到地图视图中。这应该使网格位于多边形的顶部。
现在进入细节。制作多边形是微不足道的,所以不会在这里介绍。
制作网格也不是太难。您需要知道网格的边界,然后从东、西边界以从北边界到南边界的一定间隔放置线。然后对南北线做相反的事情。日期变更线、赤道和两极有特殊情况,请记住这一点。
在这种情况下计算行间隔有点简单,您可以通过两种方式解决它。使用十进制的固定间隔或根据缩放级别计算。后面的部分更难,但通常会提供更好的可视化效果(当您放大时,网格会重新绘制并且在该缩放级别看起来更合适)。
重要提示,对于 osmbonuspack 和 osmdroid,如果您提供的覆盖线超出视图边界(如果硬件加速已关闭),您可能会遇到内存不足错误。如果启用了硬件加速,那么如果起点和终点都在屏幕外一定的距离,则线条可能根本不显示。长话短说,对于相对较小的距离,您应该没问题,否则,您必须在地图平移和缩放时剪辑视图边界。
我用 osmbonuspack 做了类似的事情来显示纬度/经度网格线,这些网格线会随着您的放大和平移而调整(意味着间隔会根据缩放级别进行调整)。如果这是一个要求,那么您也许可以重用代码,该代码基本上计算了绘制网格的每条线的距离和位置。
【讨论】:
现在,如果您只想将网格绘制为图案(对网格线位置没有限制),则应该有一个简单的替代方案,即使用“着色器”:
fillPaint.setShader(patternBMPshader);
完整示例:http://code.tutsplus.com/tutorials/android-sdk-drawing-with-pattern-fills--mobile-19527
坏消息,多边形填充涂料没有吸气剂。好消息,该属性是受保护的,而不是私有的。 所以你可以继承 Polygon,并添加 getter:
Paint getFillPaint(){
return mFillPaint;
}
【讨论】: