2011-01-05 16 views
14

Tworzę aplikację do rysowania (tekst) na iPada przy użyciu OpenGL. Już obejrzałem przykład Apple'a GLPaint, a moja aplikacja opiera się teraz na tym kodzie. Moja aplikacja powinna być przeznaczona tylko do rysowania tekstu, a nie do malowania obrazów.Aplikacja do rysowania na iPadzie za pomocą OpenGL

Cóż, moja aplikacja działa, mogę napisać jakiś tekst. Ale pisanie nie jest naprawdę dobre, nie jest fajnie pisać. Ścieżka rysowania nie jest gładka, jest kanciasta, ponieważ rysuję linię od jednego punktu do drugiego. A ścieżka ma wszędzie tę samą szerokość. Mój pomysł jest następujący: kiedy piszesz szybko, linia jest cieńsza niż wtedy, gdy piszesz powoli. Powinno to być takie samo doświadczenie, jak pisanie za pomocą prawdziwego pióra.

Jak sprawić, aby ścieżka wyglądała znacznie płynniej? Jak mogę zmieniać szerokość linii w zależności od szybkości pisania?

Tutaj można zobaczyć, co mam na myśli:

example

Odpowiedz

27

Najlepszym sposobem na wygładzenie rysunku jest użycie krzywej Bezeir. Oto mój kod. Jest to zmodyfikowana wersja, którą znalazłem na stronie Apple'a, ale nie pamiętam oryginalnego linku:

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; 
} 

To będzie losować na podstawie trzech punktów. Kontrola to punkt środkowy, który musisz zwrócić. Nowy punkt środkowy będzie inny niż poprzedni. Ponadto, jeśli przejdziesz powyższy kod, pobierze on tylko połowę linii. Następny skok wypełni go. Jest to wymagane. mój kod do wywoływania tej funkcji (powyższe jest w C, to jest w 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]; 

Ten kod dostanie punktu środkowego na podstawie odwróconych punktów iPad i ustaw „kontrola” jak prąd punkt.

To wygładzi krawędzie. Jeśli chodzi o szerokość linii, wystarczy znaleźć prędkość tego rysunku. Najłatwiej jest znaleźć długość linii. Można to łatwo zrobić za pomocą matematyki komponentów. Nie mam dla niego kodu, ale here jest podkładem dla matematyki komponentowej z witryny fizyki. Lub możesz po prostu podzielić (powyżej) liczbę przez pewną liczbę, aby dowiedzieć się, jak gruby potrzebujesz linii (liczenie wykorzystuje matematykę elementów).

Przechowuję dane punktu w tablicy o nazwie currentStroke, na wypadek, gdyby nie było oczywiste.

To wszystko, czego potrzebujesz.

EDIT:

Aby zapisać punkty, należy użyć touchesBegin i 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]; 
} 

To jest dość dużo cała aplikacja jest rysunek. Jeśli używasz GL_Paint, to już używasz duszków punktowych, na których ten system jest zbudowany.

+0

Dziękuję bardzo, to naprawdę pomaga. Ale nie jestem pewien, gdzie zaimplementować drugą część kodu. W przykładzie GLPaint istnieje funkcja renderLineFromPoint: toPoint :, która jest wywoływana za każdym razem, gdy użytkownik przesuwa palec. Czy muszę włożyć drugą część kodu do tej funkcji? – burki

+0

Czy możesz dodać cały kod? Mam na myśli pełne metody. To byłoby bardzo miłe. – burki

+0

Dodano touchBegin, touchSove i touchEnd. Jest to prawie cała aplikacja do rysowania OpenGL w poście. – Beaker

4

W odniesieniu do drugiej części pytania (jak zmieniać szerokość linii, zależnie od szybkości zapisu), powinno być można to osiągnąć, korzystając z właściwości UITouch o wartości timestamp w metodzie touchesBegan:withEvent: i touchesMoved:withEvent:.

Możesz obliczyć różnicę czasu między dwoma kolejnymi zdarzeniami dotyku, zapisując znacznik czasu ostatniego obiektu UITouch i porównując go z nowym. Podzielenie odległości ruchu przesuwającego o różnicę czasu powinno dać ci pomiar prędkości ruchu.

Teraz wszystko, co musisz zrobić, to wymyślić sposób na konwersję prędkości pisania na szerokość linii, która prawdopodobnie sprowadzi się do wybrania dowolnej wartości i dostosowania jej, aż będziesz zadowolony z wyniku.

+0

Dzięki dotychczasowe. Już myślałem o czymś takim. Byłoby miło, gdybyś wiedział, jak rozwiązać mój pierwszy problem. Mam nadzieję, że jesteś zadowolony z uprowadzenia. – burki

Powiązane problemy