【问题标题】:Clustering Algorithm for Mapping Application地图应用的聚类算法
【发布时间】:2010-09-09 14:10:36
【问题描述】:

我正在研究地图上的聚类点(纬度/经度)。对于快速且可扩展的合适算法是否有任何建议?

更具体地说,我有一系列纬度/经度坐标和地图视口。我正在尝试将靠近的点聚集在一起以消除混乱。

我已经有了问题的解决方案(see here),只是我想知道是否有任何正式的算法可以有效地解决问题。

【问题讨论】:

  • 您能否发布一些代码来显示您想要完成的任务?我对“聚类”的确切含义感到困惑。您是在世界地图上绘制它们吗?

标签: algorithm machine-learning maps artificial-intelligence cluster-analysis


【解决方案1】:

对于虚拟地球应用程序,我使用了所描述的集群 here。它速度极快且易于扩展。

【讨论】:

    【解决方案2】:

    Google Maps Hacks 对此有一个 hack,"Hack 69. Cluster Markers at High Zoom Levels"

    另外,请参阅Wikipedia on clustering algorithms

    【讨论】:

    • Google Map Hack 似乎在付费墙后面?
    【解决方案3】:

    您可以查看使用QuadTile 方案为您的所有点编制索引,然后根据比例进一步向下进行四分割。然后,所有相似位置的点将在您的索引中彼此靠近,从而有效地进行聚类。

    QuadTiles 是 Morton Codes 的一个示例,该维基百科文章中链接的一个 python 示例可能会有所帮助。

    【讨论】:

      【解决方案4】:

      我查看了各种库,发现它们非常复杂,一个词都看不懂,所以我决定制作自己的聚类算法

      这是我的 Java 代码

      static int OFFSET = 268435456;
          static double RADIUS = 85445659.4471;
          static double pi = 3.1444;
      
      public static double lonToX(double lon) {
              return Math.round(OFFSET + RADIUS * lon * pi / 180);
          }
      
          public static double latToY(double lat) {
              return Math.round(OFFSET
                      - RADIUS
                      * Math.log((1 + Math.sin(lat * pi / 180))
                              / (1 - Math.sin(lat * pi / 180))) / 2);
          }
      

      // 这会计算特定缩放级别下两个 lat long 点之间的像素距离

          public static int pixelDistance(double lat1, double lon1, double lat2,
                  double lon2, int zoom) {
              double x1 = lonToX(lon1);
              double y1 = latToY(lat1);
      
              double x2 = lonToX(lon2);
              double y2 = latToY(lat2);
      
              return (int) (Math
                      .sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2))) >> (21 - zoom);
          }
      

      // 实际计算簇的主函数 1. 经纬度点的 ArrayList 迭代到 length 。 2.内部循环从i+1位置迭代相同arraylist的副本,即离开顶部循环的索引 3.第0个元素作为质心的中心,如果像素距离很小,则比较所有其他点,将其添加到集群中 4.从顶部arraylist中删除所有元素并复制已形成集群的arraylist 5 通过从 0 重新初始化索引来重新启动进程; 6 如果选择的质心没有簇,则该元素不会被删除

      static ArrayList<Cluster> cluster(ArrayList<Marker> markers, int zoom) {
      
              ArrayList<Cluster> clusterList = new ArrayList<Cluster>();
      
              ArrayList<Marker> originalListCopy = new ArrayList<Marker>();
      
              for (Marker marker : markers) {
                  originalListCopy.add(marker);
              }
      
              /* Loop until all markers have been compared. */
              for (int i = 0; i < originalListCopy.size();) {
      
                  /* Compare against all markers which are left. */
      
                  ArrayList<Marker> markerList = new ArrayList<Marker>();
                  for (int j = i + 1; j < markers.size();) {
                      int pixelDistance = pixelDistance(markers.get(i).getLatitude(),
                              markers.get(i).getLongitude(), markers.get(j)
                                      .getLatitude(), markers.get(j).getLongitude(),
                              zoom);
      
                      if (pixelDistance < 40) {
      
                          markerList.add(markers.get(i));
                          markerList.add(markers.get(j));
      
                          markers.remove(j);
      
                          originalListCopy.remove(j);
                          j = i + 1;
                      } else {
                          j++;
                      }
      
                  }
      
                  if (markerList.size() > 0) {
                      Cluster cluster = new Cluster(clusterList.size(), markerList,
                              markerList.size() + 1, originalListCopy.get(i)
                                      .getLatitude(), originalListCopy.get(i)
                                      .getLongitude());
                      clusterList.add(cluster);
                      originalListCopy.remove(i);
                      markers.remove(i);
                      i = 0;
      
                  } else {
                      i++;
                  }
      
                  /* If a marker has been added to cluster, add also the one */
                  /* we were comparing to and remove the original from array. */
      
              }
              return clusterList;
          }
      
      Just pass in your array list here containing latitude and longitude
      
      then to display clusters
      here goes the function
      
      
      @Override
          public void onTaskCompleted(ArrayList<FlatDetails> flatDetailsList) {
      
              LatLngBounds.Builder builder = new LatLngBounds.Builder();
      
              originalListCopy = new ArrayList<FlatDetails>();
              ArrayList<Marker> markersList = new ArrayList<Marker>();
              for (FlatDetails detailList : flatDetailsList) {
      
                  markersList.add(new Marker(detailList.getLatitude(), detailList
                          .getLongitude(), detailList.getApartmentTypeString()));
      
                  originalListCopy.add(detailList);
      
                  builder.include(new LatLng(detailList.getLatitude(), detailList
                          .getLongitude()));
      
              }
      
              LatLngBounds bounds = builder.build();
              int padding = 0; // offset from edges of the map in pixels
              CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
      
              googleMap.moveCamera(cu);
      
              ArrayList<Cluster> clusterList = Utils.cluster(markersList,
                      (int) googleMap.getCameraPosition().zoom);
      
              // Removes all markers, overlays, and polylines from the map.
              googleMap.clear();
      
              // Zoom in, animating the camera.
              googleMap.animateCamera(CameraUpdateFactory.zoomTo(previousZoomLevel),
                      2000, null);
      
              CircleOptions circleOptions = new CircleOptions().center(point) //
                      // setcenter
                      .radius(3000) // set radius in meters
                      .fillColor(Color.TRANSPARENT) // default
                      .strokeColor(Color.BLUE).strokeWidth(5);
      
              googleMap.addCircle(circleOptions);
      
              for (Marker detail : markersList) {
      
                  if (detail.getBhkTypeString().equalsIgnoreCase("1 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk1)));
                  } else if (detail.getBhkTypeString().equalsIgnoreCase("2 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk_2)));
      
                  }
      
                  else if (detail.getBhkTypeString().equalsIgnoreCase("3 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk_3)));
      
                  } else if (detail.getBhkTypeString().equalsIgnoreCase("2.5 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk2)));
      
                  } else if (detail.getBhkTypeString().equalsIgnoreCase("4 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk_4)));
      
                  } else if (detail.getBhkTypeString().equalsIgnoreCase("5 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk5)));
      
                  } else if (detail.getBhkTypeString().equalsIgnoreCase("5+ BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk_5)));
      
                  }
      
                  else if (detail.getBhkTypeString().equalsIgnoreCase("2 BHK")) {
                      googleMap.addMarker(new MarkerOptions()
                              .position(
                                      new LatLng(detail.getLatitude(), detail
                                              .getLongitude()))
                              .snippet(String.valueOf(""))
                              .title("Flat" + flatDetailsList.indexOf(detail))
                              .icon(BitmapDescriptorFactory
                                      .fromResource(R.drawable.bhk_2)));
      
                  }
              }
      
              for (Cluster cluster : clusterList) {
      
                  BitmapFactory.Options options = new BitmapFactory.Options();
                  options.inMutable = true;
                  options.inPurgeable = true;
                  Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                          R.drawable.cluster_marker, options);
      
                  Canvas canvas = new Canvas(bitmap);
      
                  Paint paint = new Paint();
                  paint.setColor(getResources().getColor(R.color.white));
                  paint.setTextSize(30);
      
                  canvas.drawText(String.valueOf(cluster.getMarkerList().size()), 10,
                          40, paint);
      
                  googleMap.addMarker(new MarkerOptions()
                          .position(
                                  new LatLng(cluster.getClusterLatitude(), cluster
                                          .getClusterLongitude()))
                          .snippet(String.valueOf(cluster.getMarkerList().size()))
                          .title("Cluster")
                          .icon(BitmapDescriptorFactory.fromBitmap(bitmap)));
      
              }
      
          }
      
      
      
      
      ANY QUESTIONS OR DOUBTS PLEASE ASK WILL CLEAR THEM ALL ...........THANKS
      

      【讨论】:

      • 有什么文字解释吗?
      • 通常不鼓励仅使用代码的答案...请提供有关如何使用此代码/如何解决问题的更多信息。
      • 嗨 Parag 和 Coley Brigman,代码具有内联 cmets 。你们能告诉我你想让我解释什么部分吗?我会这样做的
      • 我相信这在 O(n^2) 时间内运行,你知道有没有比这更快的?我知道 K-means,但动态计算出 K 的最佳值也需要一些时间。
      • 嗨,Ayush Google 提供了一个集群库,因此您可以尝试一下 PS 它也以 O(n^2) 运行 这是链接尝试一下developers.google.com/maps/documentation/android/utility/…
      猜你喜欢
      • 2010-11-28
      • 2018-07-24
      • 2022-09-27
      • 1970-01-01
      • 2018-12-24
      • 2019-04-13
      • 2015-10-20
      • 2023-03-04
      相关资源
      最近更新 更多