gpt4 book ai didi

iOS 如何绘制带轮廓的线条

转载 作者:行者123 更新时间:2023-11-28 20:00:23 25 4
gpt4 key购买 nike

我正在寻找此图像中的输出 Expected Result

我需要一个笔画轮廓。我的代码如下

- (void)awakeFromNib {
self.strokeArray = [NSMutableArray array];
self.layerIndex = 0;
self.isSolid = false;
self.path = [[UIBezierPath alloc] init];
self.innerPath = [[UIBezierPath alloc] init];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path moveToPoint:p];
[self.innerPath moveToPoint:p];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path addLineToPoint:p];
[self.innerPath addLineToPoint:p];
[self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path addLineToPoint:p];
[self.innerPath addLineToPoint:p];
[self drawBitmap];
[self setNeedsDisplay];
[self.path removeAllPoints];
[self.innerPath removeAllPoints];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (void)drawRect:(CGRect)rect
{
[self.incrementalImage drawInRect:rect];
[self.brushColor setStroke];
self.path.lineWidth = self.brushWidth;
if(self.isEraser)
[self.path strokeWithBlendMode:kCGBlendModeClear alpha:0.0];
else
[self.path stroke];
self.innerPath.lineWidth = self.brushWidth - 10;
[[UIColor clearColor] setStroke];
[self.innerPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
}
- (void)drawBitmap
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
if (!self.incrementalImage)
{
CGContextClearRect(context, CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height));
}
[self.incrementalImage drawAtPoint:CGPointZero];
[self.brushColor setStroke];
self.path.lineWidth = self.brushWidth;
if(self.isEraser)
[self.path strokeWithBlendMode:kCGBlendModeClear alpha:0.0];
else
[self.path stroke];
self.innerPath.lineWidth = self.brushWidth - 10;
[[UIColor clearColor] setStroke];
[self.innerPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
self.incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

在屏幕上,我得到的是这张图片,Actual Result

我知道“清除”混合模式会产生橡皮擦效果。我想要的是笔划应该在两侧有一个坚实的轮廓并且在中间清晰。它不应该混入它正下方的路径。它下方的路径应该仍然可见。我怎样才能达到这个结果?

最佳答案

看看这个问题:Generate a CGPath from another path's line width outline

我想这就是您所需要的:创建线条的多边形并描边而不是线条。使用 CGPathCreateCopyByStrokingPath获取多边形的路径并对其进行描边。

好的,因为 CGPathCreateCopyByStrokingPath 似乎有点问题,您可以创建自己的实现。类似于下面的算法,它假设您有一个 NSArrayCGPoint 打包在 NSValue 对象中。它工作得很好,直到你开始添加短的重叠线,这在绘图时当然很容易发生。您可以通过仅在 touchesMoved 中添加与之前添加的点具有较大距离(lineWidth/2?)的点来减少这种影响。另一个缺点是线条只是直线(没有 kCGLineJoinRound 或 kCGLineCapRound),但也许您可以调整算法来做到这一点。

+ (UIBezierPath*)polygonForLine:(NSArray *)points withLineWidth:(CGFloat)lineWidth{
UIBezierPath *path = [UIBezierPath bezierPath];

//stores the starting point to close the path
CGPoint startPoint;

//get the points to a c-array for easier access
CGPoint cpoints[points.count];
int numPoints = 0;
for(NSValue *v in points){
cpoints[numPoints++] = [v CGPointValue];
}

//store the last intersection to apply it for the next segement
BOOL hasIntersection = NO;
CGPoint intersectionPoint;

for (int i=0;i<numPoints-1;i++){
//get the current line segment
CGPoint p1 = cpoints[i];
CGPoint p2 = cpoints[i+1];
CGPoint l1p1,l1p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l1p1,&l1p2);

//if there had been an intersection with the previous segement, start here to get a nice outline
if(hasIntersection){
l1p1 = intersectionPoint;
}

//is there a next segment?
if(i+2<numPoints){
//get the next line segment
p1 = cpoints[i+1];
p2 = cpoints[i+2];
CGPoint l2p1,l2p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l2p1,&l2p2);

//calculate the intersection point with the current line segment
hasIntersection = getLineIntersection(l1p1, l1p2, l2p1, l2p2, &intersectionPoint);

//if they intersect, the current linesegment has to end here to get a nice outline
if(hasIntersection){
l1p2 = intersectionPoint;
}
}

//write the current linesegment to the path
if(i==0){
//first point, move to it and store it for closing the path later on
startPoint = l1p1;
[path moveToPoint:startPoint];
}else{
[path addLineToPoint:l1p1];
}
[path addLineToPoint:l1p2];
}

//now do the same for the other side of the future polygon
hasIntersection = NO;//reset intersections
for (int i=numPoints-1;i>0;i--){
//get the current line segment
CGPoint p1 = cpoints[i];
CGPoint p2 = cpoints[i-1];
CGPoint l1p1,l1p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l1p1,&l1p2);

//if there had been an intersection with the previous segement, start here to get a nice outline
if(hasIntersection){
l1p1 = intersectionPoint;
}

//is there a next segment?
if(i-2>=0){
//get the next line segment
p1 = cpoints[i-1];
p2 = cpoints[i-2];
CGPoint l2p1,l2p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l2p1,&l2p2);

//calculate the intersection point with the current line segment
hasIntersection = getLineIntersection(l1p1, l1p2, l2p1, l2p2, &intersectionPoint);
//if they intersect, the current linesegment has to end here to get a nice outline
if(hasIntersection){
l1p2 = intersectionPoint;
}
}

//write the current linesegment to the path
[path addLineToPoint:l1p1];
[path addLineToPoint:l1p2];
}

//close the path
[path addLineToPoint:startPoint];

//we're done
return path;
}

void getOffsetLineSegmentForPoints(CGPoint p1, CGPoint p2, CGFloat lineWidth, CGPoint *linep1, CGPoint *linep2){
CGPoint offset = CGPointSub(p2, p1);
offset = CGPointNorm(offset);
offset = CGPointOrthogonal(offset);
offset = CGPointMultiply(offset, lineWidth/2);

(*linep1) = CGPointAdd(p1, offset);
(*linep2) = CGPointAdd(p2, offset);
}

CGPoint CGPointSub(CGPoint p1, CGPoint p2){
return CGPointMake(p1.x-p2.x, p1.y-p2.y);
}

CGPoint CGPointAdd(CGPoint p1, CGPoint p2){
return CGPointMake(p1.x+p2.x, p1.y+p2.y);
}

CGFloat CGPointLength(CGPoint p){
return sqrtf(powf(p.x,2)+powf(p.y,2));
}

CGPoint CGPointNorm(CGPoint p){
CGFloat length = CGPointLength(p);
if(length==0)
return CGPointZero;
return CGPointMultiply(p, 1/length);
}

CGPoint CGPointMultiply(CGPoint p, CGFloat f){
return CGPointMake(p.x*f, p.y*f);
}

CGPoint CGPointOrthogonal(CGPoint p){
return CGPointMake(p.y, -p.x);
}

BOOL getLineIntersection(CGPoint l1p1, CGPoint l1p2, CGPoint l2p1,
CGPoint l2p2, CGPoint *intersection)
{
CGPoint s1 = CGPointSub(l1p2, l1p1);
CGPoint s2 = CGPointSub(l2p2, l2p1);
float determinant = (-s2.x * s1.y + s1.x * s2.y);
if(determinant==0)
return NO;
CGPoint l2p1l1p1 = CGPointSub(l1p1, l2p1);
float s, t;
s = (-s1.y * l2p1l1p1.x + s1.x * l2p1l1p1.y) / determinant;
t = ( s2.x * l2p1l1p1.y - s2.y * l2p1l1p1.x) / determinant;

if (s >= 0 && s <= 1 && t >= 0 && t <= 1){
if (intersection != NULL){
(*intersection).x = l1p1.x + (t * s1.x);
(*intersection).y = l1p1.y + (t * s1.y);
}

return YES;
}

return NO;
}

关于iOS 如何绘制带轮廓的线条,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24463832/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com