2016-01-19 42 views
5

Poszukuję sposobu na wydajne narysowanie wykresu liniowego z dużą ilością punktów (do 10 000) na iOS. Wykres otrzymuje dane w czasie rzeczywistym i wymaga aktualizacji wiele razy na sekundę. Próbuję znaleźć sposób na wydajne narysowanie wykresu, aby nie maksymalizować procesora i nie blokować głównego wątku podczas rysowania.Rysowanie wykresów z dużą ilością punktów wydajnie na iOS

Obecnie tworzę UIBezierPath dla wykresu liniowego, w wątku tła, dodając wszystkie punkty i rysując je w CALayer (z włączonym rysunkiem asynchronicznym). Nie jest zbyt szybki, maksymalizuje procesor, a rysowanie jest tak powolne, że interfejs staje się opóźniony. Planuję dane w czasie rzeczywistym i teoretycznie mogę za każdym razem ponownie użyć tego samego UIBezierPath i po prostu dołączyć nowe punkty, jednak starsze wartości są odrzucane po pewnym czasie, co oznacza, że ​​punkty dla usuniętych wartości musiałyby zostać usunięte ze ścieżki Beziera , co nie jest możliwe.

Nie znalazłem niczego na temat wydajnego kreślenia dużych zbiorów danych na iOS, ale mam nadzieję, że są sposoby na wykorzystanie GPU do zwiększenia wydajności.

+0

Czy musisz narysować wszystkie 10k punktów? Nawet na ekranie iPada to wydaje się zbyt wygórowane ... (więcej punktów niż poziomy pikseli). Czy rozważałeś uśrednienie danych w mniejszym zestawie? – Hamish

+0

@ originaluser2 Całkowicie się zgadzam. Wykonuję jakąś pracę z klientem i nie udało mi się jeszcze wykluczyć ich z pomysłu wyciągnięcia tych wielu punktów. – JonasG

+0

dobrze, jeśli jesteś w stanie przekonać ich, uśrednianie jest najlepszym rozwiązaniem! Wątpię, czy będziesz w stanie wykorzystać dużo GPU bez wchodzenia w pełni w Metal/Open GL. Jestem prawie pewien, że 'UIBezierPath' używa głównie Core Graphics pod maską i to wszystko działa na CPU. – Hamish

Odpowiedz

0

końcu znalazłem implementację do rysowania wykresu z OpenGL: https://github.com/syedhali/EZAudio/blob/master/EZAudio/EZAudioPlotGL.m

To rzeczywiście bardzo proste i poprawa wydajności są ogromne.

W przypadku urządzeń z układem A7 (lub nowszym) rysowanie wykresu za pomocą metalu byłoby jeszcze szybsze, co również powinno być łatwe. Jest kilka wskazówek, jak to zrobić: https://www.raywenderlich.com/77488/ios-8-metal-tutorial-swift-getting-started

1

Miałem taką sytuację kilka lat temu (z powrotem w iPhone 4 dni).

że stosuje się CGMutablePathRef do którego dodaje się punkty za pomocą CGPathMoveToPoint na pierwszy punkt, a CGPathAddLineToPoint dla kolejnych punktów.

Aby uzyskać akceptowalną wydajność, zapisałem punkty danych w tablicy C (nie NSArray). Ponadto podczas drukowania punktu, jeśli jego współrzędne wyświetlania były takie same jak ostatnio zaznaczonego punktu, po prostu pominięto wywołanie do CGPathAddLineToPoint. (Będzie to często miało miejsce, gdy masz więcej punktów danych niż pikseli).

Nie pamiętam dokładnego czasu rysowania, ale zadziwiająco szybko.

+0

jeśli nie jesteś w stanie uśrednić zestawu danych, jest to zdecydowanie najlepsza opcja. (bez wchodzenia w pełny Metal) – Hamish

0

Zamiast wykreślać punkty za pomocą UIBezierPath, można ustawić CGBitmapContext, a następnie narysować punkty "ręcznie", np.

color = (0xFF << 24) | (blue << 16) | (green << 8) | (red); // AABBGGRR 
for (loop = 0; loop < count; loop++) 
{ 
    index = indices[loop]; 
    self.pixels[index] = color; 
} 

gdzie self.pixels jest bufor został użyty do stworzenia CGBitmapContext. Następnie w drawRect:

CGContextRef c = UIGraphicsGetCurrentContext(); 

CGImageRef image = CGBitmapContextCreateImage(self.imageContext); 
CGContextDrawImage(c, self.bounds, image); 
CGImageRelease(image); 

myślę, przekonasz się, że jest znacznie szybszy (i mniejsze) niż przy użyciu CGPath lub UIBezierPath.