5

Estoy tratando de resolver un problema con el trazado de una ruta de enorme (100k +) conjunto de GeoPoints a un MapView en Android. En primer lugar, me gustaría decir que he buscado mucho en StackOverflow y que no he encontrado una respuesta. El cuello de botella de mi código no está realmente en el lienzo, pero Projection.toPixels(GeoPoint, Point) o Rect.contains(point.x, point.y) método ... Estoy omitiendo puntos no visibles en la pantalla y también muestra solo cada enésimo punto según el nivel de zoom actual. Cuando se acerca el mapa, quiero mostrar la ruta más precisa posible, por lo que omito cero (o casi cero) puntos, de modo que cuando encuentre puntos visibles, necesito llamar al método de proyección para cada punto de la colección. Y eso es lo que realmente lleva mucho tiempo (no segundos, pero el paneo del mapa no es fluido y no lo estoy probando en HTC Wildfire :)). Traté de almacenar en caché los puntos calculados, pero dado que los puntos se vuelven a calcular después de cada desplazamiento/acercamiento del mapa, no han ayudado en absoluto al .Dibujo (filtrado) 100k + puntos a MapView en Android

Pensé en el uso de algún tipo de algoritmo de poda y búsqueda en lugar de iterar la matriz, pero calculé que los datos de entrada no están ordenados (no puedo tirar ninguna rama apilada entre dos puntos invisibles). Eso podría ser posible resolver con un simple tipo al principio, pero todavía no estoy seguro de que ni siquiera el recuento logarítmico de getProjection() y Rect.contains(point.x, point.y) llamadas en lugar de lineal resolvería el problema de rendimiento.

Bellow es mi código actual. Por favor, ayúdame si sabes cómo mejorar esto. ¡Muchas gracias!

public void drawPath(MapView mv, Canvas canvas) { 
    displayed = false; 

    tmpPath.reset(); 

    int zoomLevel = mapView.getZoomLevel(); 
    int skippedPoints = (int) Math.pow(2, (Math.max((19 - zoomLevel), 0))); 
    int mPointsSize = mPoints.size(); 
    int mPointsLastIndex = mPointsSize - 1; 
    int stop = mPointsLastIndex - skippedPoints; 

    mapView.getDrawingRect(currentMapBoundsRect); 
    Projection projection = mv.getProjection(); 

    for (int i = 0; i < mPointsSize; i += skippedPoints) { 

     if (i > stop) { 
      break; 
     } 
//HERE IS THE PROBLEM I THINK - THIS METHOD AND THE IF CONDITION BELOW 
     projection.toPixels(mPoints.get(i), point); 

     if (currentMapBoundsRect.contains(point.x, point.y)) { 
      if (!displayed) { 
       Point tmpPoint = new Point(); 
       projection.toPixels(mPoints.get(Math.max(i - 1, 0)), 
         tmpPoint); 
       tmpPath.moveTo(tmpPoint.x, tmpPoint.y); 
       tmpPath.lineTo(point.x, point.y); 
       displayed = true; 
      } else { 

       tmpPath.lineTo(point.x, point.y); 

      } 

     } else if (displayed) { 
      tmpPath.lineTo(point.x, point.y); 
      displayed = false; 

     } 

    } 

    canvas.drawPath(tmpPath, this.pathPaint); 

} 
+0

Así que he realizado un seguimiento y aproximadamente el 85% de carga toma el método 'Projection.toPixels()' ... Debe haber una forma de optimizar eso:/ – simekadam

+0

Otra forma podría ser usar algún tipo de mapeo..Me gusta HashMap con coordenadas como clave. Como dividir el mundo en segmentos rectangulares y luego filtrarlos según el estado de vista de mapa actual. A continuación, tómelo de HashMap y despliegue. Pero esto se ve bastante complicado :) ¿Crees que es posible? Solo si tiene sentido o no ... – simekadam

Respuesta

3

¡Así que descubrí cómo hacerlo todo mucho más rápido! Lo publicaré aquí, alguien podría encontrarlo útil en el futuro. Ha surgido que el uso de projection.toPixels() puede dañar realmente el rendimiento de la aplicación. Así que me di cuenta de que mucho mejor que tomar cada GeoPoint, convertirlo a Point y compruebe si está contenida en la ventanilla del mapa es, cuando cuente Actuall radio de la ventana gráfica del mapa de la siguiente manera:

mapView.getGlobalVisibleRect(currentMapBoundsRect); 
    GeoPoint point1 = projection.fromPixels(currentMapBoundsRect.centerX(), currentMapBoundsRect.centerY()); 
    GeoPoint point2 = projection.fromPixels(currentMapBoundsRect.left, currentMapBoundsRect.top); 
    float[] results2 = new float[3]; 
    Location.distanceBetween(point1.getLatitudeE6()/1E6, point1.getLongitudeE6()/1E6, point2.getLatitudeE6()/1E6, point2.getLongitudeE6()/1E6, results2); 

El radio está en results2 [0] ..

Luego puedo tomar cada GeoPoint y contar la distancia entre él y el centro del mapa mapView.getMapCenter(). Luego, puedo comparar el radio con la distancia calculada y decidir si no mostrar el punto.

Así que eso es todo, espero que sea útil.

Cuestiones relacionadas