首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >UIBezierPath相交

UIBezierPath相交
EN

Stack Overflow用户
提问于 2012-12-22 01:30:12
回答 2查看 4.9K关注 0票数 8

我已经找了好几个小时的答案了,但很难找到关于这个话题的任何东西。

我有一个关于目标-c的问题。我正在创建一个应用程序,在这个应用程序中,UIView检查用户的触摸,如果用户触摸和移动他/她的手指,则绘制使用UIBezierPath的路径。如果用户绘制的路径与其本身相交,则该路径应从屏幕上消失。当用户完成绘制模式时,路径中最后一点的一条线应该自动与路径中的第一个点连接(我为此使用了"closePath“方法),如果这条线与路径中的另一条”线“相交,那么路径也应该从屏幕上消失。

我将每个触点存储在一个CGPoint中,我将其存储在另一个名为Line的类中,称为A点和B点。然后,我将“行”保存到一个名为"line“的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/"“。

问题

问题是,当我运行应用程序时,它有时会工作,但有时当我绘制时,这样就不会使路径消失。我搞不懂为什么..。当我慢慢地画画时,这种情况似乎更经常发生。

代码:

MyView.h:

代码语言:javascript
运行
复制
#import <UIKit/UIKit.h>
#import "Line.h"
@interface MyView : UIView {

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

@end

MyView.m:

代码语言:javascript
运行
复制
#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:

代码语言:javascript
运行
复制
#import <UIKit/UIKit.h>

@interface Line : UIView 

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

@end

Line.m:

代码语言:javascript
运行
复制
#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

我希望有人能回答这个问题。抱歉,如果是明显的事情。提前谢谢你!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-13 08:01:38

问题在checkLineIntersection方法中。使用

代码语言:javascript
运行
复制
if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0) { return YES; }

您只检查线段的内部部分是否相交。但是,如果第一行段的开始或端点等于第二线段的开始或端点,则uaub将是0.01.0

解决方案是在条件中包括区间的一端:

代码语言:javascript
运行
复制
if (ua > 0.0 && ua <= 1.0 && ub > 0.0 && ub <= 1.0) { return YES; }

在我的测试程序中,这似乎像预期的那样起作用。

一些进一步的评论:

  • 我觉得你应该激活快捷键 如果(分母== 0.0f)返回NO; 再一次避免被零除。
  • touchesMoved中,可以在检查交叉点后将新行添加到数组中。现在,首先插入新行,这意味着它将根据自己的交叉进行检查。
  • 您已经将Line声明为UIView的子类,但这实际上不是一个视图类。您只需声明LineNSObject的子类。

补充说:--以下方法可能会更好地工作,因为它避免了小分母的除法,因此可能会出现溢出问题:

代码语言:javascript
运行
复制
-(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);
}
票数 8
EN

Stack Overflow用户

发布于 2017-11-17 12:14:28

我找到了另一种解决办法,以检查这条线是否与自身相交。使用SceneKit框架,可以从UIBezierPath创建形状。但是,如果路径相交,则节点的边界框将为零。

代码语言:javascript
运行
复制
   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)
   }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13999249

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档