2016-01-19 37 views
5

Sto cercando un modo per disegnare un grafico a linee con un sacco di punti (fino a 10.000) in modo efficiente su iOS. Il grafico ottiene dati in tempo reale e deve essere aggiornato più volte al secondo. Sto cercando di capire un modo per disegnare il grafico in modo efficiente in modo che non massima la CPU e bloccare il thread principale durante il disegno.Disegno grafico con molti punti in modo efficiente su iOS

Attualmente sto creando un UIBezierPath per il grafico a linee, in un thread in background, aggiungendo tutti i punti e disegnandolo in un CALayer (che ha il disegno asincrono abilitato). Non è molto veloce, supera la CPU e il disegno è così lento che l'interfaccia utente diventa lenta. Sto tracciando dati in tempo reale e, in teoria, potrei riutilizzare lo stesso UIBezierPath ogni volta e aggiungere i nuovi punti, tuttavia i valori più vecchi vengono scartati dopo un po ', il che significa che i punti per i valori eliminati dovrebbero essere rimossi dal percorso di Bezier , che non è possibile.

Non ho trovato nulla sull'ottimizzazione di set di dati di grandi dimensioni su iOS, ma spero che ci siano modi per utilizzare la GPU per aumentare le prestazioni.

+0

devi disegnare tutti i 10 punti? Anche su uno schermo dell'iPad, sembra eccessivamente eccessivo ... (più punti dei pixel orizzontali). Hai preso in considerazione la mediazione dei dati in un set più piccolo? – Hamish

+0

@ originaluser2 Sono totalmente d'accordo. Sto facendo un po 'di lavoro con i clienti e non sono ancora riuscito a discuterli dall'idea di disegnare questi molti punti. – JonasG

+0

beh se sei in grado di convincerli, fare la media è la soluzione migliore! Dubito che sarai in grado di sfruttare gran parte della GPU senza entrare completamente in Metal/Open GL. Sono abbastanza sicuro che 'UIBezierPath' utilizza principalmente la grafica core sotto il cofano e che tutto gira sulla CPU. – Hamish

risposta

0

ho finalmente trovato un'implementazione per disegnare un grafico con OpenGL: https://github.com/syedhali/EZAudio/blob/master/EZAudio/EZAudioPlotGL.m

In realtà è abbastanza facile ei miglioramenti delle prestazioni sono enormi.

Per i dispositivi con chip A7 (o più recenti), sarebbe probabilmente ancora più veloce disegnare il grafico con il metallo, il che dovrebbe anche essere piuttosto semplice. Ci sono alcune guide su come farlo: https://www.raywenderlich.com/77488/ios-8-metal-tutorial-swift-getting-started

1

Ho avuto una situazione come questa alcuni anni fa (di nuovo in iPhone 4 giorni).

Ho utilizzato uno CGMutablePathRef a cui ho aggiunto punti utilizzando CGPathMoveToPoint per il primo punto e CGPathAddLineToPoint per i punti successivi.

Per ottenere prestazioni accettabili, ho memorizzato i punti dati in un array C (non uno NSArray). Inoltre, quando si traccia un punto, se le sue coordinate di visualizzazione erano le stesse dell'ultimo punto tracciato, ho semplicemente saltato la chiamata a CGPathAddLineToPoint. (Questo sarà spesso il caso quando si hanno più punti dati che pixel).

Non ricordo il tempo di disegno esatto, ma era sorprendentemente veloce.

+0

se non riesci a ridurre la media del set di dati, questa è sicuramente la migliore opzione successiva. (senza andare in full metal) – Hamish

0

Invece di tracciare i punti utilizzando UIBezierPath, è possibile impostare uno CGBitmapContext e quindi tracciare i punti "a mano", ad es.

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

dove self.pixels è il buffer utilizzato per creare CGBitmapContext. Poi, in drawRect:

CGContextRef c = UIGraphicsGetCurrentContext(); 

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

Penso che troverete questo per essere significativamente più veloce (e più piccolo) che usare CGPath o UIBezierPath.