Jes*_*rdh 7 algorithm drawing objective-c intersect uibezierpath
我一直在寻找一个小时的答案,但很难找到关于这个主题的任何内容.
我有一个与Objective-c相关的问题.我正在制作一个应用程序,其中UIView检查来自用户的触摸,如果用户触摸并移动他/她的手指,则绘制使用UIBezierPath的路径.如果用户绘制以使路径自身相交,则它应从屏幕上消失.当用户完成绘制图案时,路径中最后一个点的一条线应自动连接到路径中的第一个点(我正在使用方法"closePath"),如果此线与另一个"线"相交"在路径中,路径也应该从屏幕上消失.
我将每个触摸点存储在CGPoint中,我将其存储在另一个名为Line的类中作为A点和B点.然后我将"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-切的绳部分-2 /".
问题
问题是,当我运行应用程序时,它有时会起作用,但有时当我绘制时,线条与路径相交并不会消失.我无法弄清楚为什么......当我慢慢画画时,似乎更常见.
代码:
MyView.h:
#import <UIKit/UIKit.h>
#import "Line.h"
@interface MyView : UIView {
NSMutableArray *pathArray;
UIBezierPath *myPath;
NSMutableArray *lines;
Line *line;
}
@end
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
Line.h:
#import <UIKit/UIKit.h>
@interface Line : UIView
@property (nonatomic, assign) CGPoint pointA;
@property (nonatomic, assign) CGPoint pointB;
@end
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
我希望有人能够回答这个问题.对不起,如果这是显而易见的事情.先感谢您!
问题出在checkLineIntersection方法上.同
if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0) { return YES; }
Run Code Online (Sandbox Code Playgroud)
只检查线段的内部部分是否相交.但是,如果第一线段的起点或终点是等于第二线段的起点或终点,ua并且ub将是0.0或1.0.
解决方案是在条件中包括间隔的一端:
if (ua > 0.0 && ua <= 1.0 && ub > 0.0 && ub <= 1.0) { return YES; }
Run Code Online (Sandbox Code Playgroud)
这似乎在我的测试程序中按预期工作.
一些进一步的评论:
我认为你应该激活快捷方式
if (denominator == 0.0f) return NO;
Run Code Online (Sandbox Code Playgroud)
再次避免被零除.
在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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4316 次 |
| 最近记录: |