5

Ich versuche, ein Problem mit dem Zeichnen eines Pfades von riesigen (100k +) Set von GeoPoints zu einem MapView auf Android zu lösen. Erstens möchte ich sagen, ich habe StackOverflow viel durchsucht und habe keine Antwort gefunden. Der Flaschenhals meines Codes ist nicht wirklich in Leinwand, sondern Projection.toPixels(GeoPoint, Point) oder Rect.contains(point.x, point.y) Methode .. Ich überspringen Punkte nicht sichtbar auf dem Bildschirm und Außerdem wird nur jeder n-te Punkt entsprechend der aktuellen Zoomstufe angezeigt. Wenn die Karte gezoomt wird, möchte ich einen möglichst genauen Pfad anzeigen, so dass ich Null- (oder fast Null-) Punkte überspringen kann, so dass ich beim Auffinden von sichtbaren Punkten die Projektionsmethode für jeden einzelnen Punkt in der Sammlung aufrufen muss. Und das benötigt wirklich viel Zeit (nicht Sekunden, aber das Karten-Panning ist nicht flüssig und ich teste es nicht auf HTC Wildfire :)). Ich habe versucht, berechnete Punkte zu cachen, aber da die Punkte nach jedem Karten-Schwenken/Zoomen neu berechnet werden, hat es überhaupt nicht geholfen.Zeichnen (Filtern) 100k + Punkte MapView in Android

Ich dachte über die Verwendung von einer Art von Prune und Suchalgorithmus statt iterieren das Array, aber ich fand heraus, dass die Eingabedaten nicht sortiert ist (ich kann keinen Zweig zwischen zwei unsichtbare Punkte gestapelt). Das könnte ich mit einfacher Sortierung am Anfang lösen, bin mir aber immer noch nicht sicher, ob selbst die logarithmische Zählung von getProjection() und Rect.contains(point.x, point.y) Aufrufe statt linearer das Leistungsproblem lösen würde.

Unten ist mein aktueller Code. Bitte hilf mir, wenn du weißt, wie du das besser machen kannst. Danke vielmals!

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

Also habe ich etwas Tracing gemacht und etwa 85% Last nimmt die 'Projection.toPixels()' Methode..Es muss einen Weg geben, wie man das optimiert:/ – simekadam

+0

Eine andere Möglichkeit könnte eine Art von Mapping..Like sein HashMap mit coord als key..Wie teilen Sie Welt in rechteckige Segmente und filtern Sie diese dann nach dem aktuellen mapView-Status. Dann nimm es von HashMap und zeige es an. Aber das sieht ziemlich kompliziert aus :) Denkst du es ist möglich? Nur ob es Sinn macht oder nicht .. – simekadam

Antwort

3

Also habe ich herausgefunden, wie man alles viel schneller macht! Ich werde es hier posten, jemand könnte es möglicherweise in der Zukunft nützlich finden. Es hat sich herausgestellt, dass die Verwendung von projection.toPixels() wirklich die Anwendungsleistung beeinträchtigen kann. Also dachte ich, dass das so besser, als jeden einzelnen GeoPoint nehmen, wandelt es in Point und dann prüfen, ob es in den Kartenansichtsfenstern enthalten ist, ist, wenn ich zähle Actuall Ansichtsfenster Radius der Karte, wie folgend:

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

Der Radius ist in ergebnisse2 [0] ..

Dann kann ich jeden einzelnen GeoPoint nehmen und den Abstand zwischen ihm und der Mitte der Karte mapView.getMapCenter() zählen. Dann kann ich den Radius mit dem berechneten Abstand vergleichen und entscheiden, ob der Punkt nicht angezeigt wird.

Also das ist es, hoffe es wird hilfreich sein.