UIView/CALayer Scaling-Performance-Problem am iPhone/iPod

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • UIView/CALayer Scaling-Performance-Problem am iPhone/iPod

    Hallo,

    Sorry für das Doppel-Posting, hab vorhin übersehen, dass es ein eigenes Forum für iOs gibt.

    meine App stellt einen Live-Graphen in Form eines Liniendiagrammes dar. Vereinfacht gesagt, es werden immer die Messwerte der letzten N Sekunden visualisiert. Der Benutzer kann per horizontaler Pinch-Gesture die Skalierung der x-Achse ändern und somit das dargestellte Intervall erhöhen oder reduzieren, oder per vertikaler Pinch-Gesture die Skalierung auf der y-Achse ändern, jeweils nur bis zu einem gewissen Maximum. Dabei kann es aber trotzdem passieren, dass ca. 25000 Messwerte gleichzeitig dargestellt werden müssen. Die Messwerte treffen sonst an sich zeitlich sequentiell ein. Zum Darstellen verwende ich einen eigenen UIView, mit eigenen CALayern, die ich mit Quartz 2D zeichne. Zwar ist es kein Problem, den Graphen laufend zu aktualisieren und so die bis zu 25000 Messwerte darzustellen, denn ich zeichne nur die neuen Punkte und buffere die vergangenen in CGLayern. Beim Skalieren hingegen, bekomm ich mit meinem bisherigen, "naiven" Ansatz allerdings Performance-Probleme. Derzeit wird der gesamte Graph einfach neu gezeichnet.

    Folgende Lösungsmöglichkeiten hab ich mir bereits überlegt:

    *) Reduktion der angezeigten Daten während eines Pinches und nur diese mit dem neuen Scale-Faktor neu zeichnen. Nach abgeschlossenem Pinch, zeichne ich den Graphen in höchster Detailstufe neu. Würde zwar performant laufen, allerdings bekäme ich während des Pinches Aliasing-Effekte rein. Peaks würden geglättet, oder sogar verschwinden.
    *) CGAffineTransformMakeScale auf transform-Property anwenden und abschließend wiederum mit neuem Scale-Faktor neu zeichnen. So macht es ja die Photo-App? Die Variante funktioniert zwar bei einem y-Scaling ganz gut, allerdings bei x-Scaling eher weniger. Es sei denn, ich rendere den Graphen immer vorher bei höchster Detailstufe in einem CGLayer. Mach ich das nicht, bekäme ich auch wieder Aliasing-Effekte rein, teils sogar noch gröbere als bei der vorhergehenden Variante.

    Bin sehr unentschlossen und weiß gerade nicht, welchen Weg ich einschlagen soll. Vielleicht hilft Open GL ES bei dem Problem, allerdings hab ich noch gar keine Erfahrungen damit. Da das Einarbeiten sehr lange dauert, wollte ich vorher fragen, ob es bei dem Problem überhaupt Sinn macht? Vielleicht sollte ich mir Cocos 2D zu Gemüte führen, oder habt ihr eine andere Idee? Wäre für jede Hilfe sehr dankbar.

    Hab auch gerade gesehen, dass es ein Alpha Release von CorePlot gibt. Hat jemand damit Erfahrungen und wäre das eine auch eine Option, denn mein Graph hat recht hohe Updateraten.

    Viele Grüße!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von aer0r ()

  • Nicht jeder Datenpunkt wird in einen eigenen Pixel gerendet. Die Punkte überschneiden sich teilweise. Rendere ich die maximale Zoomstufe, sieht das natürlich eher wie ein Band, als eine Linie aus. Einfach so kann ich die Datenmenge leider nicht reduzieren, d.h. nur 2% bzw. 4% der Punkte zeichnen, weil ich sonst wie bereits erwähnt, Aliasing-Effekte bekomme. Diese Variante hab ich ja auch schon probiert und sie funktioniert zwar von der Performance her schon, allerdings verfälscht sie das Ergebnis. Das Problem ist hier auch, dass ich nicht weiss, welche Daten weggelassen werden können.

    Oder mach ich beim Zeichnen grundsätzlich etwas falsch? Derzeit zeichne ich zuerst in einen CGLayer, um die bisherigen Daten zu buffern und um bei einer Aktualisierung nur die neuen Daten zeichnen zu müssen. Lasse ich den CGLayer weg, bekomm ich schon bei den Aktualisierungen Probleme. Danach zeichne ich den CGLayer in den CALayer, in dessen drawInContext: - Methode.
  • aer0r schrieb:

    Nicht jeder Datenpunkt wird in einen eigenen Pixel gerendet. Die Punkte überschneiden sich teilweise. Rendere ich die maximale Zoomstufe, sieht das natürlich eher wie ein Band, als eine Linie aus. Einfach so kann ich die Datenmenge leider nicht reduzieren, d.h. nur 2% bzw. 4% der Punkte zeichnen, weil ich sonst wie bereits erwähnt, Aliasing-Effekte bekomme. Diese Variante hab ich ja auch schon probiert und sie funktioniert zwar von der Performance her schon, allerdings verfälscht sie das Ergebnis.

    Das ist für mich schwierig zu beurteilen, da ich ja nicht weiß, wie Dein Graph aussieht.

    Du kannst für's zoomen auch einen eigenen Layer mit weniger Punkten verwenden...
    „Meine Komplikation hatte eine Komplikation.“
  • macmoonshine schrieb:

    Das ist für mich schwierig zu beurteilen, da ich ja nicht weiß, wie Dein Graph aussieht.

    Du kannst für's zoomen auch einen eigenen Layer mit weniger Punkten verwenden...

    Das mach ich eigentlich schon, nur kann ich die Lösung nicht beibehalten, da ich nicht weiss, welche Daten ich in dem Layer weglasse. Ich kann die Daten natürlich vorher auch Filtern bzw. Resamplen, allerdings bekäme ich immer noch Aliasing-Effekte und Maxima bzw. Minma würden teilweise nicht mehr aufscheinen.
  • Ich kann das im Moment auch nicht nachvollziehen. Wenn Du mehr Punkte hast als du anzeigen kannst, dann ist es definitiv sinnlos mehrere Punkte einfach übereinander zu zeichnen. Es muss eine Möglichkeit geben die Punkte vorher rechnerisch zu reduzieren. Mit welchem Algorhythmus muss du natürlich entscheiden. Ob du jetzt Mittelwerte bildest, oder maximal/Minimalwerte nimmst. Eventuell sogar ausreisser elemenierst. Ka, aber alles ist schneller als immer wieder 25000 Linien zu zeichnen.
    Wobei mir selbst das komisch vorkommt. Denn bei 25000 Punkten müßte sich das ganze ja eigentlich auf eine Art "SetPixel" reduzieren und 25000 Pixel zu modifizieren, sollte eigentlich auch ein Witz sein. Habe es aber noch nicht selber probiert. Kann mir aber auch nur schwer vorstellen, daß Coregraphics so lahm ist.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:

    Ich kann das im Moment auch nicht nachvollziehen. Wenn Du mehr Punkte hast als du anzeigen kannst, dann ist es definitiv sinnlos mehrere Punkte einfach übereinander zu zeichnen. Es muss eine Möglichkeit geben die Punkte vorher rechnerisch zu reduzieren. Mit welchem Algorhythmus muss du natürlich entscheiden. Ob du jetzt Mittelwerte bildest, oder maximal/Minimalwerte nimmst. Eventuell sogar ausreisser elemenierst. Ka, aber alles ist schneller als immer wieder 25000 Linien zu zeichnen.
    Wobei mir selbst das komisch vorkommt. Denn bei 25000 Punkten müßte sich das ganze ja eigentlich auf eine Art "SetPixel" reduzieren und 25000 Pixel zu modifizieren, sollte eigentlich auch ein Witz sein. Habe es aber noch nicht selber probiert. Kann mir aber auch nur schwer vorstellen, daß Coregraphics so lahm ist.

    Gruß

    Claus
    Datenreduktion mach ich ja. Beim Skalieren verwende ich derzeit eben eine geglättete Variante der Daten.

    Das Neuzeichnen ist auf einem älteren iPod (2nd Gen) sehr lahm, auf einem iPhone 3GS ist es weniger ein Problem. Eben dieses "SetPixel" hab ich mir von Open GL ES, oder einer Abstraktion davon erhofft. Hab aber keine Erfahrungen damit.
  • aer0r schrieb:

    Hab auch gerade gesehen, dass es ein Alpha Release von CorePlot gibt. Hat jemand damit Erfahrungen und wäre das eine auch eine Option, denn mein Graph hat recht hohe Updateraten.


    Ich hab' CorePlot mal vor zwei Monaten evaluiert. Ich fand' das API sehr sperrig, um ein einfaches Diagramm am Schirm zu haben, braucht's einiges an Aufwand. Außerdem war ich mit der Performance unzufrieden. Ich hab's dann wieder rausgeschmissen und selber gemacht. Allerdings muss man sagen, das das ein sehr dynamisches Projekt ist mit vielen Änderungen, insofern kann es jetzt schon ganz anders aussehen.

    ciao

    gandhi