Рисование приложения на iPad с использованием OpenGL

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

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

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

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

example

Ответы

Ответ 1

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

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 и установите "control" в качестве текущей точки.

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

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

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

EDIT:

Чтобы сохранить точки, вы должны использовать touchhesBegin и 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, то вы уже используете точечные спрайты, на которых эта система построена.

Ответ 2

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

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

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