Приложение для рисования на iPad с использованием OpenGL - PullRequest
14 голосов
/ 05 января 2011

Я создаю приложение для рисования (текст) для iPad, используя OpenGL.Я уже взглянул на пример Apple GLPaint, и теперь мое приложение основано на этом коде.Мое приложение должно быть только для рисования текста, а не для рисования картинок.

Что ж, мое приложение работает, я могу написать текст.Но написание не очень хорошо, писать не весело.Путь для рисования не является гладким, он угловой, потому что я рисую линию от одной точки к другой.И дорожка имеет везде одинаковую ширину.Моя идея такова: когда вы пишете быстро, строка тоньше, чем когда вы пишете медленно.Это должен быть тот же опыт, что и при написании настоящей ручкой.

Как сделать так, чтобы путь выглядел гораздо более гладким?Как я могу варьировать ширину линии в зависимости от скорости письма?

Здесь вы видите, что я имею в виду:

example

Ответы [ 2 ]

27 голосов
/ 06 января 2011

Лучший способ сгладить рисунок - использовать кривую Безье. Вот мой код Это измененная версия, которую я нашел на сайте разработчика Apple, но я не помню исходную ссылку:

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

Это будет основано на трех точках. Элемент управления - это средняя точка, которую нужно вернуть. Новая средняя точка будет отличаться от предыдущей. Кроме того, если вы пройдете через приведенный выше код, он проведет только половину линии. Следующий штрих заполнит его. Это необходимо. мой код для вызова этой функции (выше в C, это в 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];

Этот код получит среднюю точку на основе инвертированных точек iPad и установит «контроль» в качестве текущей точки.

Это сгладит края. Что касается ширины линии, вам просто нужно найти скорость этого рисунка. Проще всего найти длину вашей линии. Это легко сделать с помощью компонентной математики. У меня нет никакого кода для этого, но здесь является учебником по математике компонентов с сайта физики. Или вы можете просто разделить (выше) счетчик на некоторое число, чтобы узнать, насколько толстой должна быть линия (для подсчета используется математика компонентов).

Я храню точечные данные в массиве currentStroke на случай, если это не очевидно.

Это должно быть все, что вам нужно.

EDIT:

Для хранения очков вы должны использовать touchSegin и TouchEnd:

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

Это почти целое приложение для рисования. Если вы используете GL_Paint, то вы уже используете точечные спрайты, на которых основана эта система.

4 голосов
/ 05 января 2011

Что касается второй части вашего вопроса (как варьировать ширину линии в зависимости от скорости записи), вы сможете достичь этого, используя свойство UITouch timestamp вВаш метод touchesBegan:withEvent: и touchesMoved:withEvent:.

Вы можете рассчитать разницу во времени между двумя последующими событиями касания, сохранив метку времени самого последнего объекта UITouch и сравнив его с новым.Разделив расстояние смахивающего движения на разницу во времени, вы должны будете измерить скорость движения.

Теперь все, что вам нужно сделать, - это найти способ преобразовать скорость записи в ширину линии, котораявероятно, придется выбрать произвольное значение и изменить его, пока вы не будете довольны результатом.

...