2011-01-05 11 views
14

Sto creando un'app di disegno (testo) per iPad utilizzando OpenGL. Ho già dato un'occhiata all'esempio di Apple GLPaint e la mia app ora si basa su quel codice. La mia app dovrebbe essere solo per disegnare il testo, non per dipingere le immagini.Applicazione di disegno su iPad con OpenGL

Bene, la mia app funziona, posso scrivere del testo. Ma la scrittura non è molto buona, non è divertente scrivere. Il percorso del disegno non è scorrevole, è angolare perché sto disegnando una linea da un punto a un altro. E il percorso ha ovunque la stessa larghezza. La mia idea è: quando scrivi velocemente la linea è più sottile di quando scrivi lentamente. Dovrebbe essere la stessa esperienza come scrivere con una penna reale.

Come posso rendere il percorso più agevole? Come posso variare la larghezza della linea a seconda della velocità di scrittura?

Qui si può vedere quello che voglio dire:

example

risposta

27

Il modo migliore per arrotondare il disegno è utilizzare una curva bezeir. Ecco il mio codice. Si tratta di una versione modificata che ho trovato sul sito dev di Apple, ma non mi ricordo il link originale:

CGPoint drawBezier(CGPoint origin, CGPoint control, CGPoint destination, int segments) 
{ 
CGPoint vertices[segments/2]; 
CGPoint midPoint; 
glDisable(GL_TEXTURE_2D); 
float x, y; 

float t = 0.0; 
for(int i = 0; i < (segments/2); i++) 
{ 
    x = pow(1 - t, 2) * origin.x + 2.0 * (1 - t) * t * control.x + t * t * destination.x; 
    y = pow(1 - t, 2) * origin.y + 2.0 * (1 - t) * t * control.y + t * t * destination.y; 
    vertices[i] = CGPointMake(x, y); 
    t += 1.0/(segments); 

} 
//windowHeight is the height of you drawing canvas. 
midPoint = CGPointMake(x, windowHeight - y); 
glVertexPointer(2, GL_FLOAT, 0, vertices); 
glDrawArrays(GL_POINTS, 0, segments/2); 
return midPoint; 
} 

che disegnerà sulla base di tre punti. Il controllo è il punto medio, che è necessario restituire. Il nuovo punto medio sarà diverso rispetto al precedente. Inoltre, se si passa attraverso il codice di cui sopra, si disegna solo metà della linea. Il colpo successivo lo riempirà. Questo è richiesto. il mio codice per chiamare questa funzione (di cui sopra è in C, questo è in Obj-C):

//Invert the Y axis to conform the iPhone top-down approach 
    invertedYBegCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i] CGPointValue].y; 
    invertedYEndCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i+1] CGPointValue].y; 
    invertedYThirdCoord = self.bounds.size.height - [[currentStroke objectAtIndex:i+2] CGPointValue].y; 
    //Figure our how many dots you need 
    count = MAX(ceilf(sqrtf(([[currentStroke objectAtIndex:i+2] CGPointValue].x - [[currentStroke objectAtIndex:i] CGPointValue].x) 
     * ([[currentStroke objectAtIndex:i+2] CGPointValue].x - [[currentStroke objectAtIndex:i] CGPointValue].x) 
     + ((invertedYThirdCoord - invertedYBegCoord) * (invertedYThirdCoord - invertedYBegCoord)))/pointCount), 1); 

    newMidPoint = drawBezier(CGPointMake([[currentStroke objectAtIndex:i] CGPointValue].x, invertedYBegCoord), CGPointMake([[currentStroke objectAtIndex:i+1] CGPointValue].x, invertedYEndCoord), CGPointMake([[currentStroke objectAtIndex:i+2] CGPointValue].x, invertedYThirdCoord), count); 

    int loc = [currentStroke count]-1; 
    [currentStroke insertObject:[NSValue valueWithCGPoint:newMidPoint] atIndex:loc]; 
    [currentStroke removeObjectAtIndex:loc-1]; 

Quel codice otterrà il punto centrale sulla base di punti iPad invertite, e impostare il 'controllo' come l'attuale punto.

Questo attenuerà i bordi. Ora riguardo alla larghezza della linea, devi solo trovare la velocità di quel disegno. È più facile trovare la lunghezza della linea. Questo è fatto facilmente usando la matematica dei componenti. Non ho alcun codice per questo, ma here è un primer per i componenti di matematica da un sito di fisica. Oppure puoi semplicemente dividere (sopra) contare per un certo numero per scoprire quanto spesso hai bisogno che la linea sia (il conteggio usa la matematica dei componenti).

Memorizzo i dati dei punti in un array chiamato currentStroke, nel caso in cui non fosse ovvio.

Questo dovrebbe essere tutto ciò che serve.

EDIT:

Per memorizzare i punti, si dovrebbe usare touchesBegin e touchesEnd:

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    self.currentStroke = [NSMutableArray array]; 
    CGPoint point = [ [touches anyObject] locationInView:self]; 
    [currentStroke addObject:[NSValue valueWithCGPoint:point]]; 
    [self draw]; 

} 

- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event 
{ 
    CGPoint point = [ [touches anyObject] locationInView:self]; 
    [currentStroke addObject:[NSValue valueWithCGPoint:point]]; 
    [self draw]; 
} 


- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    CGPoint point = [ [touches anyObject] locationInView:self]; 
    [currentStroke addObject:[NSValue valueWithCGPoint:point]]; 
    [self draw]; 
} 

Questo è praticamente un'intera applicazione di disegno lì. Se si utilizza GL_Paint, si utilizzano già gli sprite di punti, su cui è basato questo sistema.

+0

Grazie mille, questo aiuta davvero. Ma non sono sicuro di dove implementare la seconda parte del codice. Nell'esempio GLPaint c'è una funzione renderLineFromPoint: toPoint :, che viene chiamata ogni volta che l'utente muove il dito. Devo inserire la seconda parte del tuo codice in quella funzione? – burki

+0

Oppure potresti aggiungere l'intero codice? Intendo i metodi completi. Sarebbe molto gentile. – burki

+0

Tocchi aggiuntiBinale, ToccaVengono spostati e tocca Fine. È praticamente un'intera applicazione di disegno openGL nel post. – Beaker

4

Per quanto riguarda la seconda parte della tua domanda (come variare la larghezza della linea a seconda della velocità di scrittura), si dovrebbe essere in grado di ottenere questo sfruttando la proprietà timestamp di UITouch nel proprio metodo touchesBegan:withEvent: e touchesMoved:withEvent:.

è possibile calcolare la differenza di tempo tra due eventi successivi tocco memorizzando il timestamp della più recente oggetto UITouch e confrontandola con quella nuova. Dividere la distanza del movimento a scorrimento per la differenza di tempo dovrebbe darvi una misura della velocità di movimento.

Ora tutto quello che devi fare è trovare un modo per convertire la velocità di scrittura in larghezza della linea, che probabilmente arriverà a scegliere un valore arbitrario e aggiustandolo finché non sarai soddisfatto del risultato.

+0

Grazie mille. Ho già pensato a qualcosa di simile. Sarebbe bello se tu sapessi come risolvere il mio primo problema. Spero che tu sia abbastanza felice con upvote. – burki

Problemi correlati