Domanda

Ho centinaia di migliaia di punti della serie storica che voglio rappresentare per l'utente. La mia attuale soluzione è quella di eseguire il rendering di tali dati in un PNG con una libreria di terze parti, quindi caricare quel PNG in un NSImage e visualizzarlo in una vista di scorrimento. Funziona benissimo, tranne che:

      
  1. Le immagini NSI di larghezza superiore a 32k pixel non vengono visualizzate correttamente   
  2. Voglio essere in grado di ingrandire i dati in modo rapido e semplice   
  3. Leggere e scrivere dal disco è stupido

Il mio attuale tentativo è di disegnare direttamente NSBezierPath s su un NSView. Il rendering della vista è meraviglioso, ma molto, molto lentamente, anche se disegno solo un sottoinsieme limitato di punti alla volta. E ogni volta che scorro devo ridisegnare che è anche lento.

Sono certo, in quanto principiante del Cocoa, che mi manca qualche modo migliore per farlo. Qual è il & Quot; giusto & Quot; modo di farlo?

È stato utile?

Soluzione

  

Il mio attuale tentativo è di disegnare direttamente NSBezierPaths su un NSView. Il rendering della vista è meraviglioso, ma molto, molto lentamente, anche se disegno solo un sottoinsieme limitato di punti alla volta. E ogni volta che scorro devo ridisegnare che è anche lento.

Prima di intraprendere qualsiasi soluzione drastica, prova questi semplici passaggi:

  1. Clip. Usa NSRectClip , passando il rettangolo che prendi come argomento a drawRect:. Questa è una riga.
  2. Esegui semplici test rettangolari prima di riempire i percorsi. Per ogni percorso, ottieni i suoi limiti e usa NSIntersectsRect per verificare se si trova all'interno del rettangolo.
  3. Esegui test del rettangolo leggermente meno semplice prima di tracciare i tracciati. Simile al passaggio precedente, tranne per il fatto che devi aumentare il rettangolo (quello che hai ricevuto come argomento) della larghezza della linea, poiché metà della corsa cadrà al di fuori del percorso. Per ogni percorso, ottieni la larghezza di linea e negala (delta = -[path lineWidth] & # 8212; e sì, devi includere quel segno meno), quindi passa il risultato come entrambi gli argomenti a NSInsetRect. Assicurati di mantenere il rettangolo originale, poiché percorsi diversi possono avere larghezze di riga diverse.

L'idea è, abbastanza semplicemente, di disegnare di meno. L'impostazione del tracciato di ritaglio (usando NSArray) ridurrà la quantità di blitting risultante dalle operazioni di disegno. Escludendo i percorsi che non rientrano completamente nel rettangolo di disegno, risparmierai probabilmente il ritaglio più costoso per tali percorsi.

E, naturalmente, dovresti profilare ad ogni passaggio per assicurarti di non aver rallentato le cose. Potresti voler impostare una sorta di contatore del frame rate.

Un'altra cosa: ottenere i limiti per ciascun percorso può essere costoso. (Ancora una volta, profilo.) In tal caso, potresti voler memorizzare nella cache i limiti per ciascun percorso, magari utilizzando un NSValue parallelo di <=> s o avvolgendo insieme il percorso e i limiti in un oggetto di tua ideazione. Quindi calcoli i limiti solo una volta e semplicemente li recuperi su future tirature.

Altri suggerimenti

I documenti hanno una sezione su NSBezierPath performance .

Se stai disegnando molti percorsi più bezier, OpenGL è probabilmente la strada da percorrere. Apple documentazione sarebbe un buon punto di partenza. Hanno codice di esempio per l'implementazione un contesto di rendering OpenGL di base in una finestra di cacao.

Ciò sposterebbe il carico delle difficili attività di disegno sul processore grafico e lascerebbe la tua app libera di scorrere a piacimento.

Questa pagina ha un codice OpenGL di esempio per disegnare curve di Bezier.

Guarderei CATiledLayer (solo Leopard) per questo. Puoi disegnare una grande quantità di elementi nello strato piastrellato e visualizzarne le aree in base alle esigenze. Nel tuo caso, puoi impostare CATiledLayer come supporto per il tuo NSView, disegnare tutti i tuoi percorsi di Bezier in quel livello, quindi scorrere e persino ingrandire e ridurre. I livelli di animazione di base sono gestiti come trame OpenGL, quindi dovresti ottenere ottime prestazioni da questo. Il disegno vettoriale viene memorizzato nella cache nel layer e non viene ridisegnato mentre scorri, come puoi trovare su un NSView standard.

Ad esempio, Bill Dudney ha pubblicato un codice di esempio su come utilizzare CATiledLayer per visualizzare un enorme file PDF.

Quanto è dinamico il set di dati?

Se è ragionevolmente statico e vuoi " zoom " ;, allora dovresti considerare di consolidare i dati in un sottoinsieme ridimensionato.

Esempio contrastato: se hai 100.000 punti (diciamo che avanzi sull'asse X), quindi, chiaramente, in un'immagine da 1000 pixel, inevitabilmente stai solo tramando 1000 punti di quei 100.000.

Quindi, puoi farlo in avanzato (1000 punti, 10000 punti, dati grezzi di 100000 punti) e selezionare dal set appropriato in base al " zoom " livello che stai visualizzando.

Per quanto riguarda quale valore selezionare quando i punti si sovrappongono, puoi fare min, max, mediana, media, ecc.

Prendi in considerazione l'utilizzo di un framework che gestisca in modo efficiente questo tipo di cose, come CorePlot

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top