UIBezierPath相交
我一直在寻找答案几个小时,但找不到有关该主题的任何内容。
我有一个与Objective-
c有关的问题。我正在制作一个应用程序,其中UIView检查用户的触摸,如果用户触摸并移动了他/她的手指,则会绘制使用UIBezierPath的路径。如果用户进行绘制以使路径相交,则路径应从屏幕上消失。当用户绘制完图案后,如果路径中的最后一条线与另一条“线”相交,则路径中最后一点的线应自动与路径中的第一点连接(我正在使用“
closePath”方法)在路径中,路径也应从屏幕上消失。
我将每个触摸点存储在CGPoint中,并将其存储在另一个称为Line的类中,作为Point A和PointB。然后将“ line”保存到名为“
lines”的NSMutableArray中。每次将点添加到路径中时,我都会使用(-(BOOL)checkLineIntersection:(CGPoint)p1方法来检查该点与之前绘制的点之间的线是否与线中的任何“线”相交:(CGPoint)p2:(CGPoint)p3:(CGPoint)p4)我从本教程中获得“
http://www.iossourcecode.com/2012/08/02/how-to-make-a-game-like- cut-the-rope-
part-2 /”。
问题是,当我运行应用程序时,它有时可以工作,但有时在我绘制时,线条与路径相交不会消失。我不知道为什么…当我慢慢画画时,它似乎经常发生。
#import <UIKit/UIKit.h>#import "Line.h"
@interface MyView : UIView {
NSMutableArray *pathArray;
UIBezierPath *myPath;
NSMutableArray *lines;
Line *line;
}
@end
#import "MyView.h"@implementation MyView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
    // Initialization code
    pathArray=[[NSMutableArray alloc]init];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[[UIColor redColor] setStroke];
[[UIColor blueColor] setFill];
for (UIBezierPath *_path in pathArray) {
    //[_path fill];
    [_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
myPath = [[UIBezierPath alloc]init];
lines = [[NSMutableArray alloc]init];
myPath.lineWidth=1;
UITouch *mytouch = [[event allTouches] anyObject];
[myPath moveToPoint:[mytouch locationInView:mytouch.view]];
[pathArray addObject:myPath];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(myPath.isEmpty) {
} else {
    UITouch *mytouch = [[event allTouches] anyObject];
    [myPath addLineToPoint:[mytouch locationInView:mytouch.view]];
    CGPoint pointA = [mytouch previousLocationInView:mytouch.view];
    CGPoint pointB = [mytouch locationInView:mytouch.view];
    line = [[Line alloc]init];
    [line setPointA:pointA];
    [line setPointB:pointB];
    [lines addObject:line];
    for(Line *l in lines) {
        CGPoint pa = l.pointA;
        CGPoint pb = l.pointB;
        //NSLog(@"Point A: %@", NSStringFromCGPoint(pa));
        //NSLog(@"Point B: %@", NSStringFromCGPoint(pb));
        if ([self checkLineIntersection:pointA :pointB :pa :pb])
        {
            [pathArray removeLastObject];
            [myPath removeAllPoints];
            [self setNeedsDisplay];
            NSLog(@"Removed path!");
            return;
        }
    }
}
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if(myPath.isEmpty) {
} else if ([lines count] != 0){
    line = [[Line alloc]init];
    line = [lines lastObject];
    CGPoint pointA = line.pointA;
    line = [[Line alloc]init];
    line = [lines objectAtIndex:0];
    CGPoint pointB = line.pointA;
    [myPath closePath];
    for(Line *l in lines) {
        CGPoint pa = l.pointA;
        CGPoint pb = l.pointB;
        if ([self checkLineIntersection:pointA :pointB :pa :pb])
        {
            [pathArray removeLastObject];
            [myPath removeAllPoints];
            [self setNeedsDisplay];
            NSLog(@"Removed path!");
            return;
        }
    } 
}
[self setNeedsDisplay];
}
-(BOOL)checkLineIntersection:(CGPoint)p1 :(CGPoint)p2 :(CGPoint)p3 :(CGPoint)p4
{
CGFloat denominator = (p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y);
/*
// In this case the lines are parallel so you assume they don't intersect
if (denominator == 0.0f)
    return NO;
*/
CGFloat ua = ((p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x)) / denominator;
CGFloat ub = ((p2.x - p1.x) * (p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x)) / denominator;
if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0)
{
    return YES;
}
return NO;
}
@end
#import <UIKit/UIKit.h>@interface Line : UIView
@property (nonatomic, assign) CGPoint pointA;
@property (nonatomic, assign) CGPoint pointB;
@end
#import "Line.h"@implementation Line
@synthesize pointA;
@synthesize pointB;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
    // Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
@end
我希望有人能够回答这个问题。抱歉,这很明显。先感谢您!
回答:
问题出在checkLineIntersection方法上。用
if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0) { return YES; }您仅检查线段的 内部 是否相交。但是,如果第一线段的起点或终点 是等于 第二线段的起点或终点,ua并且ub将是0.0或1.0。
解决方案是在条件中包括间隔的一端:
if (ua > 0.0 && ua <= 1.0 && ub > 0.0 && ub <= 1.0) { return YES; }这似乎按我的测试程序中的预期工作。
进一步说明:
- 我认为您应该激活快捷方式
if (denominator == 0.0f) return NO; 
再次避免被零除。
在中
touchesMoved,您可以 在 检查交集 后将 新线添加到数组中。现在,首先插入新线,这意味着将针对自身检查交叉点。您已声明
Line为的子类UIView,但这实际上不是视图类。您可以将其声明Line为的子类NSObject。
以下方法可能会更好,因为它避免了除法,因此使用小分母可以避免溢出问题:
-(BOOL)checkLineIntersection:(CGPoint)p1 :(CGPoint)p2 :(CGPoint)p3 :(CGPoint)p4{
    CGFloat denominator = (p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y);
    CGFloat ua = (p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x);
    CGFloat ub = (p2.x - p1.x) * (p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x);
    if (denominator < 0) {
        ua = -ua; ub = -ub; denominator = -denominator;
    }
    return (ua > 0.0 && ua <= denominator && ub > 0.0 && ub <= denominator);
}
以上是 UIBezierPath相交 的全部内容, 来源链接: utcz.com/qa/409883.html

