谷歌地图颤动检查点是否在多边形内

问题描述 投票:0回答:5

我正在使用 google-maps-flutter 插件开发 flutter 项目,我想检查用户位置是否位于我在地图上创建的多边形内。有一种使用 JavaScript api(containsLocation() 方法)的简单方法,但对于 flutter,我只找到了一个第三方插件,google_map_polyutil,它仅适用于 android,当我运行我的应用程序时,我遇到了安全蠕虫。还有其他方法吗?

google-maps flutter dart geometry geofencing
5个回答
22
投票

我找到了this答案,只是修改了一些小东西以与 dart 一起使用,我对硬编码的多边形进行了测试。列表 _area 是我的多边形,而 _polygons 是我的地图控制器所必需的。

final Set<Polygon> _polygons = {};
List<LatLng> _area = [
LatLng(-17.770992200, -63.207739700),
LatLng(-17.776386600, -63.213576200),
LatLng(-17.778348200, -63.213576200),
LatLng(-17.786848100, -63.214262900),
LatLng(-17.798289700, -63.211001300),
LatLng(-17.810547700, -63.200701600),
LatLng(-17.815450600, -63.185252100),
LatLng(-17.816267800, -63.170660900),
LatLng(-17.800741300, -63.153838100),
LatLng(-17.785867400, -63.150919800),
LatLng(-17.770501800, -63.152636400),
LatLng(-17.759712400, -63.160361200),
LatLng(-17.755952300, -63.169802600),
LatLng(-17.752519100, -63.186625400),
LatLng(-17.758404500, -63.195551800),
LatLng(-17.770992200, -63.206538100),
LatLng(-17.770996000, -63.207762500)];

函数这样结束:

bool _checkIfValidMarker(LatLng tap, List<LatLng> vertices) {
    int intersectCount = 0;
    for (int j = 0; j < vertices.length - 1; j++) {
      if (rayCastIntersect(tap, vertices[j], vertices[j + 1])) {
        intersectCount++;
      }
    }

    return ((intersectCount % 2) == 1); // odd = inside, even = outside;
  }

  bool rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
    double aY = vertA.latitude;
    double bY = vertB.latitude;
    double aX = vertA.longitude;
    double bX = vertB.longitude;
    double pY = tap.latitude;
    double pX = tap.longitude;

    if ((aY > pY && bY > pY) || (aY < pY && bY < pY) || (aX < pX && bX < pX)) {
      return false; // a and b can't both be above or below pt.y, and a or
      // b must be east of pt.x
    }

    double m = (aY - bY) / (aX - bX); // Rise over run
    double bee = (-aX) * m + aY; // y = mx + b
    double x = (pY - bee) / m; // algebra is neat!

    return x > pX;
  }

注意 Polygons 属性和 onTap 方法。我试图检查在地图中创建的标记是否在我的多边形内:

GoogleMap(
                          initialCameraPosition: CameraPosition(
                            target: target, //LatLng(0, 0),
                            zoom: 16,
                          ),
                          zoomGesturesEnabled: true,
                          markers: markers,
                          polygons: _polygons,
                          onMapCreated: (controller) =>
                              _mapController = controller,
                          onTap: (latLng) {
                            _getAddress(latLng);
                          },
                        )

然后我在 _getAddress 方法中使用了以下调用:

_checkIfValidMarker(latLng, _area);

我希望它能帮助你创造你需要的东西。


6
投票

最简单的使用方法 - https://pub.dev/packages/maps_toolkit

isLocationOnPath
方法。


2
投票

最简单的使用方法 - https://pub.dev/packages/maps_toolkit

with PolygonUtil.containsLocation - 计算给定点是否位于指定多边形内。


1
投票

L。 Chi的回答确实有帮助。 但由于我的点非常接近,如果

rayCastIntersect
等于
aX
,则 
bX

可能会得到错误的布尔返回

因此,我只需在计算

aX == bX
之前添加
m
条件检查即可。

bool rayCastIntersect(LatLng tap, LatLng vertA, LatLng vertB) {
    double aY = vertA.latitude;
    double bY = vertB.latitude;
    double aX = vertA.longitude;
    double bX = vertB.longitude;
    double pY = tap.latitude;
    double pX = tap.longitude;

    if ((aY > pY && bY > pY) || (aY < pY && bY < pY) || (aX < pX && bX < pX)) {
      return false; // a and b can't both be above or below pt.y, and a or
      // b must be east of pt.x
    }

    if (aX == bX) {
      return true;
    }
    double m = (aY - bY) / (aX - bX); // Rise over run
    double bee = (-aX) * m + aY; // y = mx + b
    double x = (pY - bee) / m; // algebra is neat!

    return x > pX;
}

0
投票

我偶然发现了这篇文章,因为我想解决我的代码中的类似问题。不幸的是,这两个答案都错过了一个边缘情况,以及 Poly 库中的颤振点

如果 on 边是垂直边,则 m 将为无穷大。还可以通过检查该点是否位于边缘两个点的西侧(或“左侧”)来避免这种情况,因为该条件对于垂直边缘始终成立。 为了充分理解这个问题,我推荐这个视频。

改进代码:

class Point {
  Point({required this.x, required this.y});

  /// X axis coordinate or longitude
  double x;

  /// Y axis coordinate or latitude
  double y;
}

class Poly {
  /// Check if a Point [point] is inside a polygon representing by a List of Point [vertices]
  /// by using a Ray-Casting algorithm
  static bool isPointInPolygon(Point point, List<Point> vertices) {
    int intersectCount = 0;
    for (int i = 0; i < vertices.length; i += 1) {
      if (Poly.rayCastIntersect(point, vertices[i], vertices[(i + 1)%vertices.length])) {
        intersectCount += 1;
      }
    }
    if( intersectCount != 0){
      print(intersectCount);
    }
    return (intersectCount % 2) == 1;
  }

  /// Ray-Casting algorithm implementation
  /// Calculate whether a horizontal ray cast eastward from [point] 
  /// will intersect with the line between [vertA] and [vertB]
  /// Refer to `https://en.wikipedia.org/wiki/Point_in_polygon` for more explanation
  /// or the example comment bloc at the end of this file
  static bool rayCastIntersect(Point point, Point vertA, Point vertB) {
    final double aY = vertA.y;
    final double bY = vertB.y;
    final double aX = vertA.x;
    final double bX = vertB.x;
    final double pY = point.y;
    final double pX = point.x;

    if ((aY > pY && bY > pY) || (aY < pY && bY < pY) || (aX < pX && bX < pX)) {
      // The case where the ray does not possibly pass through the polygon edge,
      // because both points A and B are above/below the line,
      // or both are to the left/west of the starting point
      // (as the line travels eastward into the polygon).
      // Therefore we should not perform the check and simply return false.
      // If we did not have this check we would get false positives.
      return false;
    }

    if (pX < aX && pX < bX) {
      // The case where the point is to the left(west) of both points A and B,
      // So we dont need to check, because the ray will certanly intersect with the polygon edge.
      return true;
    }

    // y = mx + b : Standard linear equation
    // (y-b)/m = x : Formula to solve for x

    // M is rise over run -> the slope or angle between vertices A and B.
    double m = (aY - bY) / (aX - bX);
    // B is the Y-intercept of the line between vertices A and B
    final double b = ((aX * -1) * m) + aY;
    // We want to find the X location at which a flat horizontal ray at Y height
    // of pY would intersect with the line between A and B.
    // So we use our rearranged Y = MX+B, but we use pY as our Y value
    final double x = (pY - b) / m;

    // If the value of X
    // (the x point at which the ray intersects the line created by points A and B)
    // is "ahead" of the point's X value, then the ray can be said to intersect with the polygon.
    return x > pX;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.