xcode 使用 OpenGL 在 iPad 上绘制应用程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4606680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Drawing app on iPad using OpenGL
提问by burki
I'm creating a drawing app ( text ) for the iPad using OpenGL. I've already had a look at Apple's example GLPaint, and my app is now based on that code. My app should be just for drawing text, not for painting pictures.
我正在使用 OpenGL 为 iPad 创建一个绘图应用程序(文本)。我已经看过 Apple 的示例 GLPaint,我的应用程序现在基于该代码。我的应用程序应该只用于绘制文本,而不是用于绘制图片。
Well, my App works, I can write some text. But the writing isn't really good, it doesn't make fun to write. The drawing path isn't smooth, it's angularly because I'm drawing a line from one point to another. And the path has everywhere the same width. My idea is: when you're writing fast the line is thinner than when you're writing slow. It should be the same experience like writing with a real pen.
嗯,我的应用程序工作正常,我可以写一些文字。但是文笔不是很好,写起来不好玩。绘图路径不平滑,它是有角度的,因为我正在从一个点到另一个点绘制一条线。并且路径到处都有相同的宽度。我的想法是:当你写得快时,线条比你写得慢时更细。应该和用真笔书写一样的体验。
How can I make the path look much smoother? How can I vary the width of the line depending on the speed of writing?
我怎样才能使路径看起来更平滑?如何根据书写速度改变线条的宽度?
Here you can see what I mean:
在这里你可以明白我的意思:
回答by Beaker
The best way to smooth the drawing is use a bezeir curve. Here is my code. It is a modified version I found on apple's dev site, but I don't remember the original link:
平滑绘图的最佳方法是使用贝塞尔曲线。这是我的代码。这是我在苹果的开发网站上找到的修改版本,但我不记得原始链接:
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;
}
That will draw based on three points. The control is the midpoint, which you need to return. The new midpoint will be different than the previous. Also, if you go through the above code, it will only draw half the line. The next stroke will fill it in. This is required. my code for calling this function (the above is in C, this is in Obj-C):
这将基于三点进行绘制。控件是您需要返回的中点。新的中点将与以前的不同。另外,如果你通过上面的代码,它只会画一半的线。下一个笔划将它填满。这是必需的。我调用这个函数的代码(上面是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];
That code will get the mid point based on inverted iPad points, and set the 'control' as the current point.
该代码将根据倒置的 iPad 点获取中点,并将“控件”设置为当前点。
That will smooth out the edges. Now regarding the line width, you just need to find the speed of that drawing. It is easiest just to find the length of your line. This is easily done using component mathematics. I don't have any code for it, but hereis a primer for component mathmatics from a physics site. Or you can simply divide (above) count by some number to find out how thick you need the line to be (count uses component mathematics).
这将使边缘平滑。现在关于线宽,你只需要找到绘图的速度。最简单的方法是找到线的长度。这可以使用组件数学轻松完成。我没有它的任何代码,但这里有一个来自物理站点的组件数学入门。或者您可以简单地将(以上)计数除以某个数字,以找出您需要的线有多粗(计数使用组件数学)。
I store point data in an array called currentStroke, in case it wasn't obvious.
我将点数据存储在一个名为 currentStroke 的数组中,以防它不明显。
That should be all you need.
这应该就是你所需要的。
EDIT:
编辑:
To store points, you should use touchesBegin and touchesEnd:
要存储点,您应该使用 touchesBegin 和 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];
}
That is pretty much an entire drawing application there. If you are using GL_Paint, then you are already using point sprites, which this system is build on.
这几乎是一个完整的绘图应用程序。如果您正在使用 GL_Paint,那么您已经在使用该系统所基于的点精灵。
回答by Leo Cassarani
With regards to the second part of your question (how to vary the width of the line depending on the speed of writing), you should be able to achieve this by taking advantage of UITouch
's timestamp
property in your touchesBegan:withEvent:
and touchesMoved:withEvent:
method.
关于您问题的第二部分(如何根据写入速度改变线宽),您应该能够通过利用和方法中UITouch
的timestamp
属性来实现这一点。touchesBegan:withEvent:
touchesMoved:withEvent:
You can calculate the time difference between two subsequent touch events by storing the timestamp of the most recent UITouch
object and comparing it to the new one. Dividing the distance of the swiping motion by the time difference should give you some measurement of the movement speed.
您可以通过存储最近UITouch
对象的时间戳并将其与新对象进行比较来计算两个后续触摸事件之间的时间差。将滑动运动的距离除以时间差应该可以测量移动速度。
Now all you need to do is to come up with a way to convert speed of writing into line width, which will probably come down to picking an arbitrary value and adjusting it until you're happy with the result.
现在您需要做的就是想出一种将写入速度转换为线宽的方法,这可能归结为选择一个任意值并对其进行调整,直到您对结果满意为止。