【问题标题】:How do I calculate the center of a polygon in Google Maps Android API v2?如何在 Google Maps Android API v2 中计算多边形的中心?
【发布时间】:2013-08-28 17:56:45
【问题描述】:

我已经使用几个纬度,经度点在谷歌地图上绘制了一个多边形。但是现在我需要在多边形的中心放置一个标记,我需要它的中心坐标。如何计算中心点。

以下是在地图上添加多边形的代码:

for (Warning w : warningsList) {
            // Instantiates a new Polygon object and adds points
            PolygonOptions rectOptions = new PolygonOptions();
            List<PolyPoints> pp = w.getPolyPoints();
            for (PolyPoints p : pp) {
                rectOptions.add(new LatLng(Double.valueOf(p.getLatitude()),
                        Double.valueOf(p.getLongitude())));
            }

                mMap.addPolygon(rectOptions.strokeColor(Color.GREEN)
                        .fillColor(Color.RED).strokeWidth(STROKE_WIDTH));

        }

我发现了类似的 question 已得到回答,但这是针对 JavaScript Api 的。在我的情况下,他们有什么方法可以使用相同的解决方案吗?

【问题讨论】:

  • 有什么代码可以提供给我们吗?
  • @kolonelpeteruk 我添加了一些代码,显示了我如何在地图上添加多边形。
  • 你想实现什么样的中心?重心?边界中心?您尝试过实施哪一个?
  • @MaciejGórski 边界中心。

标签: android google-maps-android-api-2 android-maps-v2


【解决方案1】:

下面的代码我用来找到多边形的中心点。它也对我有用

private LatLng getPolygonCenterPoint(ArrayList<LatLng> polygonPointsList){
        LatLng centerLatLng = null;
        Builder builder = new LatLngBounds.Builder(); 
        for(int i = 0 ; i < polygonPointsList.size() ; i++) 
        {          
            builder.include(polygonPointsList.get(i));
        }
        LatLngBounds bounds = builder.build();
        centerLatLng =  bounds.getCenter();

        return centerLatLng;
    }

【讨论】:

    【解决方案2】:

    下面是我现在用来查找多边形中心的代码:-

    public static double[] centroid(List<PolyPoints> points) {
            double[] centroid = { 0.0, 0.0 };
    
            for (int i = 0; i < points.size(); i++) {
                centroid[0] += points.get(i).getLatitude();
                centroid[1] += points.get(i).getLongitude();
            }
    
            int totalPoints = points.size();
            centroid[0] = centroid[0] / totalPoints;
            centroid[1] = centroid[1] / totalPoints;
    
            return centroid;
        }
    

    【讨论】:

      【解决方案3】:
      private static LatLng getCenterOfPolygon(List<LatLng> latLngList) {
              double[] centroid = {0.0, 0.0};
              for (int i = 0; i < latLngList.size(); i++) {
                  centroid[0] += latLngList.get(i).latitude;
                  centroid[1] += latLngList.get(i).longitude;
              }
              int totalPoints = latLngList.size();
              return new LatLng(centroid[0] / totalPoints, centroid[1] / totalPoints);
          }
      

      【讨论】:

        【解决方案4】:

        我已经用两种方法完成了。但它适用于任何形状...

        private static double area(ArrayList<LatLng> arr) {
            double area=0;
            int nPts = arr.size();
            int j=nPts-1;
            LatLng p1; LatLng p2;
            for (int i=0;i<nPts;j=i++) {
        
                p1=arr.get(i); p2=arr.get(j);
                area+=p1.latitude*p2.longitude;
                area-=p1.longitude*p2.latitude;
            }
            area/=2;
        
            return area;
        };
        
        public static LatLng Centroid (ArrayList<LatLng> pts) {
            int nPts = pts.size();
            double x=0; double y=0;
            double f;
            int j=nPts-1;
            LatLng p1; LatLng p2;
        
            for (int i=0;i<nPts;j=i++) {
                p1=pts.get((i)); p2=pts.get(j);
                f=p1.latitude*p2.longitude-p2.latitude*p1.longitude;
                x+=(p1.latitude+p2.latitude)*f;
                y+=(p1.longitude+p2.longitude)*f;
            }
        
            f=area(pts)*6;
        
            return new LatLng(x/f, y/f);
        };
        

        只需在您的类中调用 Centroid Method 并将您的 LatLng 数组作为参数传递。确保您传递的数组列表是 LatLng 数组列表

        LatLng polyCentroid = Centroid(list);

        mMap.addMarker(new MarkerOptions() .position(polyCentroid));

        【讨论】:

          【解决方案5】:

          blogpost 之后,我创建了一个 Kotlin 版本。 我将它实现为Polygon 扩展。

          package com.example.diman.googlemapsplayground
          
          import com.google.android.gms.maps.model.LatLng
          import com.google.android.gms.maps.model.LatLngBounds
          import com.google.android.gms.maps.model.Polygon
          import com.google.maps.android.PolyUtil
          import com.google.maps.android.SphericalUtil
          
          /**
           * Find approximate center of a polygon.
           * Reference: https://moduscreate.com/blog/placing-markers-inside-polygons-with-google-maps/
           *
           * Algorithm:
           * If the bounding box center point is inside the polygon, return center point.
           * Otherwise, sample points at fixed percentages of the bounding box’s height North and South of the center point.
           * Sample points at fixed percentages of the bounding box’s width East and West of the center point.
           * Stop when we find the first point that is inside the area of the polygon, and drop the marker there.
           */
          fun Polygon.getApproximateCenter(): LatLng {
            // Calc bounds first
            val boundsBuilder = LatLngBounds.builder()
            points.forEach {
              boundsBuilder.include(it)
            }
            val polygonBounds = boundsBuilder.build()
          
            val centerPoint = polygonBounds.center
          
            // Center point is inside the polygon, return it
            if (PolyUtil.containsLocation(centerPoint, points, true)) {
              return centerPoint
            }
          
            // Center point is out of bounds
            // Sample points at fixed percentages of the bounding box’s width East and West of the center point.
            val maxSearchSteps = 10
            var testPos: LatLng = centerPoint
          
            // Calculate NorthWest point so we can work out height of polygon NW->SE
            val northWest = LatLng(polygonBounds.northeast.latitude, polygonBounds.southwest.longitude)
          
            // Work out how tall and wide the bounds are and what our search
            // increment will be
            val boundsHeight = SphericalUtil.computeDistanceBetween(northWest, polygonBounds.southwest)
            val heightIncr = boundsHeight / maxSearchSteps
          
            val boundsWidth = SphericalUtil.computeDistanceBetween(northWest, polygonBounds.northeast)
            val widthIncr = boundsWidth / maxSearchSteps
          
            // Expand out from Centroid and find a point within polygon at
            // 0, 90, 180, 270 degrees
            for (n in 1..maxSearchSteps) {
              // Test point North of Centroid
              testPos = SphericalUtil.computeOffset(
                  centerPoint,
                  (heightIncr * n),
                  0.0
              )
              if (PolyUtil.containsLocation(testPos, points, true)) {
                break
              }
          
              // Test point East of Centroid
              testPos = SphericalUtil.computeOffset(
                  centerPoint,
                  (widthIncr * n),
                  90.0
              )
              if (PolyUtil.containsLocation(testPos, points, true)) {
                break
              }
          
              // Test point South of Centroid
              testPos = SphericalUtil.computeOffset(
                  centerPoint,
                  (heightIncr * n),
                  180.0
              )
              if (PolyUtil.containsLocation(testPos, points, true)) {
                break
              }
          
              // Test point West of Centroid
              testPos = SphericalUtil.computeOffset(
                  centerPoint,
                  (widthIncr * n),
                  270.0
              )
              if (PolyUtil.containsLocation(testPos, points, true)) {
                break
              }
            }
          
            return testPos
          }
          

          注意,将PolyUtilSphericalUtil 添加到gradle:

          implementation 'com.google.maps.android:android-maps-utils:0.4.3'

          【讨论】:

            【解决方案6】:
            Builder builder = new LatLngBounds.Builder(); 
            

            【讨论】:

            • 这个答案没有解释提供的代码 sn-p 也不完整。在这里只制作一个对象是没有意义的。请提供完整的代码和解释。
            猜你喜欢
            • 1970-01-01
            • 2012-12-03
            • 1970-01-01
            • 2016-07-20
            • 1970-01-01
            • 2013-05-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多