我一直在寻找答案几个小时,但找不到有关该主题的任何内容。
我有一个与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 /”。
问题
问题是,当我运行应用程序时,它有时可以工作,但有时在我绘制时,线条与路径相交不会消失。我不知道为什么…当我慢慢画画时,它似乎经常发生。
代码:
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
我希望有人能够回答这个问题。抱歉,这很明显。先感谢您!
问题出在checkLineIntersection方法上。用
checkLineIntersection
if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0) { return YES; }
您仅检查线段的 内部 是否相交。但是,如果第一线段的起点或终点 是等于 第二线段的起点或终点,ua并且ub将是0.0或1.0。
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,您可以 在 检查交集 后将 新线添加到数组中。现在,首先插入新线,这意味着将针对自身检查交叉点。
touchesMoved
您已声明Line为的子类UIView,但这实际上不是视图类。您可以将其声明Line为的子类NSObject。
Line
UIView
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); }