我正在尝试计算“addCurveToPoint:”或“addQuadCurveToPoint:”的控制点,但我不知道该怎么做。
我尝试了一些代码示例,但没有... 有人可以帮我吗?
谢谢!
答案 0 :(得分:4)
检查smooth drawing,这是一个很棒的教程,向您展示如何绘制平滑线。一步步。易于理解,易于实施。但它只是告诉你如何绘制平滑线,没有其他功能,如橡皮擦等。
如果您想要绘图应用,请查看Smooth-Line-View,一个简单的绘图应用。
如果您熟悉c ++,则应检查GLPaint,它是Apple提供的绘图示例应用程序,GLPaint
答案 1 :(得分:0)
虽然我知道这个问题都已经很老了,并且b)基本上已经回答了,但我还是决定在这里分享一些代码,以防万一它可以帮助来自Google的人。
可以轻松找到此解决方案的原始绘图代码here。
我最近不得不在Cocoa应用程序中做类似的事情,并实现了一个不需要太多代码的解决方案。该方法在前一个点值和当前点值之间切换,但也会影响移动速度,因此该行与鼠标保持一致。我添加了评论以解释该过程的步骤。
(我知道问题是在iOS上,但是由于它使用Core Graphics,因此在iOS上修改代码并不困难。从Objective-C ++转换为纯Objective-C也不会很困难。)< / p>
// Somewhere in another file...
@interface CIDDrawView : NSView {
NSMutableArray *brushStrokes;
NSMutableArray *strokePoints;
}
@end
// Implementation
#include <QuartzCore/QuartzCore.h>
#include <chrono>
#include <cmath>
#include <algorithm>
float lerp(float a, float b, float f) {
return a + f * (b - a);
}
NSPoint lerpPoint(NSPoint a, NSPoint b, float f) {
return {
lerp(a.x, b.x, f),
lerp(a.y, b.y, f)
};
}
float pointDistance(NSPoint a, NSPoint b) {
return std::sqrt(std::pow(b.x - a.x, 2) + std::pow(b.y - a.y, 2));
}
inline auto msTime() {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
@implementation CIDDrawView
-(id)initWithFrame:(NSRect)frame {
if((self = [super initWithFrame:frame])) {
brushStrokes = [NSMutableArray array];
}
return self;
}
-(NSPoint)mousePointForEvent:(NSEvent *)e {
return [self convertPoint:e.locationInWindow fromView:nil];
}
-(void)mouseDown:(NSEvent *)event {
// Begin new stroke.
strokePoints = [NSMutableArray array];
// Add the new stroke to the strokes array.
[brushStrokes addObject:strokePoints];
// Add the first point to the new stroke.
NSPoint mousePoint = [self mousePointForEvent:event];
[strokePoints addObject:@(mousePoint)];
}
-(void)mouseDragged:(NSEvent *)event {
static auto lastPointTime = msTime();
// The reference speed used to normalise the mouse movement speed.
// Unit is px/s, but that doesn't matter much.
const float refSpeed = 600.f;
// How long it takes for the lerped points to reach the user's mouse location.
// Lower values smooth the line less, but higher values make the line catch up more slowly.
const float lerpAmount = 3.f;
NSPoint mousePoint = [self mousePointForEvent:event];
// Only modify the point value if this is not a new stroke.
if([strokePoints count] > 1) {
NSPoint lastPoint = [[strokePoints lastObject] pointValue];
// Calculate the time since the last point was added.
auto timeNow = msTime();
float secs = float(timeNow - lastPointTime) / 1000.f;
// Normalise the mouse speed.
float movementSpeed = std::min(1.0f, (pointDistance(mousePoint, lastPoint) / secs) / refSpeed);
// Lerp between the last point and the current one by the lerp amount (factoring in the speed).
mousePoint = lerpPoint(lastPoint, mousePoint, movementSpeed / lerpAmount);
lastPointTime = timeNow;
}
// Add the point to the stroke.
[strokePoints addObject:@(mousePoint)];
[self setNeedsDisplay:YES];
}
-(void)mouseUp:(NSEvent *)event {
NSPoint mousePoint = [self mousePointForEvent:event];
[strokePoints addObject:@(mousePoint)];
[self setNeedsDisplay:YES];
}
-(void)drawRect:(NSRect)rect {
const CGColorRef lineColor = [[NSColor blackColor] CGColor];
const float lineWidth = 1.f;
[[NSColor whiteColor] setFill];
NSRectFill(rect);
if(![brushStrokes count]) {
// No strokes to draw.
return;
}
CGContextRef context = [[NSGraphicsContext currentContext] CGContext];
for(NSArray *stroke in brushStrokes) {
CGContextSetLineWidth(context, lineWidth);
CGContextSetStrokeColorWithColor(context, lineColor);
unsigned long strokePointCount = [stroke count];
NSPoint startPoint = [[stroke firstObject] pointValue];
CGContextBeginPath(context);
CGContextMoveToPoint(context, startPoint.x, startPoint.y);
// Add lines to the points, skipping the first mouse point.
for(unsigned long i = 1; i < strokePointCount; ++i) {
NSPoint point = [stroke[i] pointValue];
CGContextAddLineToPoint(context, point.x, point.y);
}
// Stroke the path.
CGContextDrawPath(context, kCGPathStroke);
}
}
@end
我试图使图形保持不变,但是仍然存在一些差异。这部分归因于以下事实:如果不进行平滑处理,绘制起来会有些困难。