在 osmdroid 奖励包中在多边形上绘制网格

Draw grid over polygon in osmdroid bonus pack

我搜索了所有互联网,但没有找到问题的答案。我正在使用 osmdroid,我想在多边形上添加网格,如图所示。我在 Whosebug 中找到了一个类似的 question 但这个问题没有答案。所以请告诉我这可能吗?

是的,这是可能的。

有一些可能的解决方案。 1) 假设有人好心制作了满足您需求的kml文件,可以直接使用osmbonuspack导入kml文件。

2) 以编程方式自行制作。所以你有几个任务。

a) 将多边形作为叠加层 b) 将网格作为叠加层 c) 按顺序将它们添加到地图视图中。这应该使网格位于多边形之上。

现在进入细节。制作多边形很简单,所以不会在这里介绍。

制作网格也不难。您需要知道网格的边界,然后在从北边界到南边界的某个间隔处放置来自东、西边界的线。然后对南北线做相反的事情。日期变更线、赤道和两极都有特殊情况,请记住这一点。

在这种情况下计算行间隔比较简单,您可以通过两种方式解决。使用以十进制度为单位的固定间隔或根据缩放级别进行计算。后面的部分更难,但通常会提供更好的可视化效果(当您放大时,网格会重新绘制并在该缩放级别看起来更合适)。

重要说明,对于 osmbonuspack 和 osmdroid,如果您提供的覆盖线超出视图范围(如果关闭硬件加速),您可能 运行 出现内存不足错误。如果启用了硬件加速,则如果起点和终点都离开屏幕一定距离,则线条可能根本不会显示。长话短说,对于相对较小的距离,你应该没问题,否则,你必须在地图平移和缩放时在视图边界处进行裁剪。

我用 osmbonuspack 做了类似的事情来显示 lat/lon 网格线,这些网格线会在您放大和平移时进行调整(这意味着间隔会根据缩放级别进行调整)。如果这是一项要求,那么您也许可以重用代码,该代码主要计算绘制网格的每条线的距离和位置。

现在,如果您只想将网格绘制为图案(对网格线位置没有限制),应该有一个简单的替代方法,使用 "shader":

fillPaint.setShader(patternBMPshader);

完整示例:http://code.tutsplus.com/tutorials/android-sdk-drawing-with-pattern-fills--mobile-19527

坏消息,没有 getter 的多边形填充涂料。好消息,该属性是受保护的,而不是私有的。 所以你可以子类化多边形,并添加 getter:

Paint getFillPaint(){
  return mFillPaint;
}

@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);
    }
}

结果:

Full source code.