2008-09-16 17 views
22

Estoy buscando puntos de agrupamiento en un mapa (lat/longs). ¿Hay alguna recomendación sobre un algoritmo adecuado que sea rápido y escalable?Algoritmo de agrupamiento para asignación Aplicación


@Gilligan: Sí - Tengo una serie de lat/lngs, y una ventana gráfica del mapa. Intento agrupar los puntos que están muy juntos para eliminar el desorden.

Ya tengo una solución al problema (see here), solo me pregunto si existe algún algoritmo formal que resuelva el problema de manera eficiente.

+0

¿Está basada en la agrupación de las ubicaciones físicas dadas por la latitud y longitud? –

+0

¿Podría publicar algún código que muestre lo que quiere lograr? Estoy confundido en cuanto a qué quiere decir con "agrupamiento". ¿Los estás tramando en un mapa del mundo? – Gilligan

Respuesta

6

Para una aplicación de tierra virtual, he utilizado la agrupación descrita here. Es rapidísimo y fácilmente extensible.

4

Puede ver la indexación de todos sus puntos usando un esquema QuadTile, y luego basándose en la escala, más abajo de las divisiones cuádruples. Todos los puntos ubicados de forma similar estarán cerca el uno del otro en su índice, permitiendo que la agrupación se realice de manera eficiente.

QuadTiles son un ejemplo de Morton Codes, y hay un ejemplo de pitón vinculado a ese artículo de wikipedia que puede ayudar.

1

Miré a diversas bibliotecas y los encontré tan complejo no podía entender una palabra, así que decidí hacer mi propio algoritmo de agrupamiento

Aquí va mi código en 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); 
    } 

// Esto calcula la distancia entre los píxeles de remolque lat puntos largos a un nivel de zoom determinado

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

// la función principal que realmente calcula los racimos 1. ArrayList of lat long points se itera a la longitud. 2. lazo interno una copia del mismo arraylist se itera desde la posición i + 1, es decir, dejando el índice del ciclo superior 3. El 0º elemento se toma como el centro del centroide y todos los otros puntos se comparan si su distancia de píxeles es muy inferior en el clúster 4. elimine todos los elementos de la lista de arrays superior y copie la lista de arrays que ha formado el clúster 5 reinicie el proceso reiniciando el índice de 0; 6 si el centroide seleccionado no tiene racimos entonces ese elemento no se elimina

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 
+0

¿Alguna explicación textual por favor? –

+0

En general, se desaconsejan las respuestas con solo el código ... incluya más información sobre cómo se usará este código/cómo se resuelve el problema. –

+0

Hola Parag y Coley Brigman el código tiene comentarios en línea.¿Pueden ustedes decirme exactamente qué parte quieren que explique? Haré eso – user1530779

Cuestiones relacionadas