UIBezierPath相交(UIBezierPath intersect)

2019-07-17 12:25发布

我一直在寻找了几个小时一个答案,但很难找到的话题什么。

我有关于Objective-C的一个问题。 我在做一个应用程序,其中一个UIView检查来自用户触摸并且如果用户触摸和移动他/她的手指,用UIBezierPath路径绘制。 如果用户绘制,使路径贯穿本身应该从屏幕上消失。 当用户完成绘制的图案,从路径中的最后一个点的直线应与自动路径中的第一点连接(我用这个方法“closePath”),如果该行与其他“线相交“在路径的路径也应该从屏幕上消失。

我保存在我存储在另一个类中调用线为点A和点B.然后我节省了“线”,以一个NSMutableArray所谓的“线”,一个CGPoint每一个接触点。 每一个时间点被添加到路径I检查,看看是否收到得出点与点之间的线路通过使用一种方法(与任何在线“行”的相交 - (BOOL)checkLineIntersection:(CGPoint)p1所:(CGPoint)P2:(CGPoint)P3:(CGPoint)P4)我从本教程“得到http://www.iossourcecode.com/2012/08/02/how-to-make-a-game-like-切的绳部分-2 /”。

问题

问题是,当我运行该应用程序它的工作原理,但有时有时当我画等都以线条相交的路径不会消失。 我想不通为什么...这似乎为它,当我画慢慢发生更频繁。

代码:

MyView.h:

#import <UIKit/UIKit.h>
#import "Line.h"
@interface MyView : UIView {

NSMutableArray *pathArray;
UIBezierPath *myPath;
NSMutableArray *lines;
Line *line;
} 

@end

MyView.m:

#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

Line.h:

#import <UIKit/UIKit.h>

@interface Line : UIView 

@property (nonatomic, assign) CGPoint pointA;
@property (nonatomic, assign) CGPoint pointB;

@end

Line.m:

#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

我希望有人也许能够回答这个问题。 很抱歉,如果这件事情很明显。 先感谢您!

Answer 1:

问题是在checkLineIntersection方法。 同

if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0) { return YES; }

你只检查是否线路段的内饰部分相交。 但是,如果第一线段的起点或终点是等于开始或第二线段的端点, uaub将是0.01.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);
}


Answer 2:

我发现另一个解决方法,以检查线路相交它的自我。 随着SceneKit框架有可能从UIBezierPath打造成型。 但是,如果路径贯穿然后边界节点的框将被清零。

   let path = UIBezierPath()

    //...

    let testGeometry = SCNShape(path:path, extrusionDepth: 0.5)
    let testNode = SCNNode(geometry: testGeometry)

    if (testNode.boundingBox.max - testNode.boundingBox.min).length() > 0 {
    // No intersection (or empty)
   }


文章来源: UIBezierPath intersect