当前位置: 首页 > 知识库问答 >
问题:

用图标填充多边形

养聪
2023-03-14

我可以在Google地图中绘制多边形。现在,当我在地图上绘制完该区域的多边形时,我想用相同的图标填充该多边形。我可以用颜色填充多边形,但我想用边框有一些填充和图标之间有一些指定空间的图标填充它。我该怎么做?

共有1个答案

沈成天
2023-03-14

Google Maps Android SDK没有“从盒子中取出”的解决方案,但您可以使用一些变通方法。

太长,读不下去了

假设需要填充公园多边形:

final List<LatLng> polygonPoints = new ArrayList<>();
polygonPoints.add(new LatLng(50.444477, 30.498976));
polygonPoints.add(new LatLng(50.445290, 30.500864));
polygonPoints.add(new LatLng(50.443958, 30.508921));
polygonPoints.add(new LatLng(50.443247, 30.508642));
polygonPoints.add(new LatLng(50.442830, 30.508878));
polygonPoints.add(new LatLng(50.440965, 30.508256));
polygonPoints.add(new LatLng(50.441949, 30.501443));

final Polygon polygon = mGoogleMap.addPolygon(new PolygonOptions()
        .addAll(polygonPoints)
        .strokeColor(Color.BLUE)
        .fillColor(Color.argb(20, 0, 255, 0)));

带有树图标(R.drawable.ic\U forest):

您可以通过以下方式完成:

1) 通过带有自定义(树)图标的标记“填充”。为此,您需要找到多边形边界矩形,并在循环中添加标记为正方形。对于仅在多边形内部添加标记,可以使用PolyUtil。containsLocation()来自谷歌地图Android API实用程序库:

LatLngBounds bounds = getPolygonBounds(polygon.getPoints());

BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.ic_forest);

double boundHeight = bounds.northeast.latitude - bounds.southwest.latitude;
double boundWidth = bounds.northeast.longitude - bounds.southwest.longitude;

double gridCntLat = 5;  // 5 icons vertically
double gridCntLon = 5;  // 5 icons horizontally

double dLat = (bounds.northeast.latitude - bounds.southwest.latitude) / gridCntLat;
double dLng = (bounds.northeast.longitude - bounds.southwest.longitude) / gridCntLon;

double lat = dLat + bounds.southwest.latitude;

while (lat < bounds.northeast.latitude) {
    double lon = dLng + bounds.southwest.longitude;
    while (lon < bounds.northeast.longitude) {

        LatLng iconPos = new LatLng(lat, lon);

        if (PolyUtil.containsLocation(iconPos, polygonPoints, true)) {
            MarkerOptions markerOptions = new MarkerOptions().position(iconPos)
                    .draggable(false)
                    .flat(true)
                    .icon(icon);
            mGoogleMap.addMarker(markerOptions);
        }
        lon += dLng;
    }
    lat += dLat;
}

其中getPolygonBounds()是:

private LatLngBounds getPolygonBounds(List<LatLng> polygon) {
    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    for(int i = 0 ; i < polygon.size() ; i++) {
        builder.include(polygon.get(i));
    }
    LatLngBounds bounds = builder.build();
    return  bounds;
}

和私有GoogleMap mGoogleMap。。。

@Override
public void onMapReady(GoogleMap googleMap) {
    mGoogleMap = googleMap;
    ...
}

结果你得到了这样的东西:

这是最简单的解决方案,但一些图标可能部分位于多边形边界之外(您可以通过MarkerOptions.anchor()方法稍微调整它们,还可以设置MarkerOptions。平坦(true)如果希望标记图标随多边形旋转),并且对于大量标记,贴图开始滞后。

2)使用“动态”(为每个多边形以编程方式创建)GroundOverlay。为此,您还需要确定多边形矩形边界,并以像素为单位创建具有相同比例的覆盖位图(您还需要将其限制在较大的一侧以避免内存不足(OOM)错误)。注意,您需要使用投影来计算矩形边界,因为不同纬度和经度的LatLng度以米为单位和以像素为单位的大小不同。

然后,您需要在创建的位图画布上绘制多边形。为此,您可以使用Path对象,将重新计算的LatLng多边形点转换为以像素为单位的本地覆盖位图坐标。您应该使用简单的比例,而不是Projection.toScreenloc()

screenPoint.x = (int) (width * (latLng.longitude - bounds.southwest.longitude) / boundWidth);
screenPoint.y = height - (int) (height * (latLng.latitude - bounds.southwest.latitude) / boundHeight);  // y-axis of screen is inverted to Lat

要使用图标的位图填充覆盖位图上的多边形,可以使用着色器,并将其设置为使用绘制对象。setShader()。最后,您可以在GoogleMap对象上添加创建的位图作为地面覆盖。用tileBitmap填充多边形的方法的完整源代码:

private GroundOverlay fillPoly(Projection projection, Polygon polygon, Bitmap tileBitmap, float transparency) {
    LatLngBounds bounds = getPolygonBounds(polygon.getPoints());

    double boundHeight = bounds.northeast.latitude - bounds.southwest.latitude;
    double boundWidth = bounds.northeast.longitude - bounds.southwest.longitude;

    Point northEast = projection.toScreenLocation(bounds.northeast);
    Point southWest = projection.toScreenLocation(bounds.southwest);

    int screenBoundHeight = northEast.y - southWest.y;
    int screenBoundWidth = northEast.x - southWest.x;

    // determine overlay bitmap size
    double k = Math.abs((double) screenBoundHeight / (double) screenBoundWidth);
    int overlayWidth;
    int overlayHeight;
    if (Math.abs(boundWidth) > Math.abs(boundHeight)) {
        overlayWidth = OVERLAY_MAX_SIZE;
        overlayHeight = (int) (overlayWidth * k);
    } else {
        overlayHeight = OVERLAY_MAX_SIZE;
        overlayWidth = (int) (overlayHeight * k);
    }

    // create overlay bitmap
    Bitmap overlayBitmap = createOverlayBitmap(overlayWidth, overlayHeight, bounds, polygon.getPoints(), tileBitmap);

    // create ground overlay
    GroundOverlayOptions overlayOptions = new GroundOverlayOptions()
            .image(BitmapDescriptorFactory.fromBitmap(overlayBitmap))
            .transparency(transparency)
            .positionFromBounds(bounds);

    return mGoogleMap.addGroundOverlay(overlayOptions);
}

其中,createOverlayBitmap()是:

private Bitmap createOverlayBitmap(int width, int height, LatLngBounds bounds, List<LatLng> polygon, Bitmap tileBitmap) {
    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);

    Path path = new Path();
    BitmapShader shader = new BitmapShader(tileBitmap,
            Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

    Paint paint = new Paint();
    paint.setStyle(Paint.Style.FILL);
    paint.setStrokeWidth(10);
    paint.setAntiAlias(true);
    paint.setShader(shader);

    List<Point> screenPoints = new ArrayList<>(polygon.size());

    double boundHeight = bounds.northeast.latitude - bounds.southwest.latitude;
    double boundWidth = bounds.northeast.longitude - bounds.southwest.longitude;

    for (int i = 0; i < polygon.size(); i++) {
        LatLng latLng = polygon.get(i);
        Point screenPoint = new Point();
        screenPoint.x = (int) (width * (latLng.longitude - bounds.southwest.longitude) / boundWidth);
        screenPoint.y = height - (int) (height * (latLng.latitude - bounds.southwest.latitude) / boundHeight);
        screenPoints.add(screenPoint);
    }

    path.moveTo(screenPoints.get(0).x, screenPoints.get(0).y);
    for (int i = 1; i < polygon.size(); i++) {
        path.lineTo(screenPoints.get(i).x, screenPoints.get(i).y);
    }
    path.close();

    canvas.drawPath(path, paint);

    return bitmap;
}

您可以这样使用它:

Bitmap tileBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_forest);   // create bitmap of fill icon
fillPoly(mGoogleMap.getProjection(), polygon, tileBitmap, 0.5f);

mGoogleMap.get投影()需要正确计算位图比例。如果您需要在地图渲染前使用mGoogleMap.get投影(),您应该使用andr的此解决方案。

因此,您得到了如下结果:

如果您需要“图标之间的某些指定空间”,则该空间应位于图标本身内部:

(h-水平空间,v-垂直空间)。

地面覆盖始终随地图缩放和旋转,如果需要缩放独立图标,则应使用其他方法。此外,对于大型叠加位图,设备可能没有足够的内存。

3) 使用平铺覆盖层。实际上,它类似于p.2,但覆盖为每个缩放级别生成的位图,并将其拆分为小的(例如256x256像素)平铺,以避免高内存消耗。您可以将生成的tile存储在设备文件系统中,并实现TileProvider,如Alex Vasilkov的“this”答案中所示;

4) 将基于MapView的视图与重写的dispatchDraw()一起使用,从中可以控制视图画布上绘制的所有内容。这是最好但复杂的解决方案

注意!这只是演示-不是完整的解决方案(例如,它没有测试阴性LatLng等)。

 类似资料:
  • 问题内容: 有人可以诊断我面临的问题吗?在运行演示时,您可以看到中间部分为空白,我需要填充整个区域。 提前谢谢了 问题答案: 多边形与自身相交。fillPolygon方法无法清楚地确定哪个点在哪个点以及哪个点在哪个点之外。从fillPolygon javadoc: 多边形内部的区域是使用偶数填充规则(也称为交替规则)定义的。 也许您可以将多边形分成三个单个的多边形。

  • 2D 上下文的两种基本绘图操作是填充和描边。填充,就是用指定的样式(颜色、渐变或图像)填充图形;描边,就是只在图形的边缘画线。大多数2D 上下文操作都会细分为填充和描边两个操作,而 ① 假设你想在Firefox 3 中使用<canvas>元素。虽然浏览器会为该标签创建一个DOM 对象,而且也可以引用它,但这个对象中并没有getContext()方法。(据作者回复)操作的结果取决于两个属性:fill

  • **有没有办法使用gganimate包对此地图进行动画处理,其中第一帧仅填充检测日期为2002年的多边形,第二帧填充的多边形,检测日期为2003年或更早(因此为2002年和2003年),第三帧用于检测日期为2004年或更早(2002年,2003年, 2004年),等等?**澄清:我希望所有县多边形始终可见,并且最初用白色填充,并且动画的每个帧都会根据检测年份添加县的填充。 我尝试使用与静态绘图,但

  • 我是android中GeoJson层的初学者。我想在GeoJson图层上填充一些颜色来绘制多边形。问题是我不能在GeoJson层上用额外的线填充多边形的颜色。 这是我的代码。 我想用颜色显示所有多边形。 下面是示例GeoJson数据。 {“类型”:“特征集合”,“特征”:[{“类型”:“特征”,“属性”:{“温度”:28.0,“默认单位”:“C”},“几何”:{“类型”:“多边形”,“坐标”:[[

  • 问题内容: 只是一个简单的查询,例如在模型中使用双引用。 模式/模型 询问 我已经尝试过类似的东西 实际上,只有人口之一在工作。 那么,如何让两个人口工作呢? 问题答案: 您已经在使用以下正确的语法: 也许订单中的ObjectId不在集合中?

  • 在Sketch中,每个图层最多可以有4个填充,你可以轻松地将一个半透明的渐变叠加在一个单色填充上面。具体做法是,点击位于第一个颜色填充后面的+按钮来添加第二个填充。你可以来回拖拽它们以重新排列顺序,或者将其拖拽到面板之外来删除它。 想要改变单个填充的颜色属性,点击相应的颜色填充按钮,然后可以修改颜色,也可以切换到渐变填充或图案填充。你可以通过点击每一个填充上面的复选框来禁用单个填充。 为一个图层添