2012-12-22 29 views
6

Tôi đã tìm kiếm câu trả lời trong nhiều giờ nhưng gặp sự cố khi tìm bất kỳ nội dung nào về chủ đề.UIBezierPath cắt nhau

Tôi có câu hỏi liên quan đến Mục tiêu-c. Tôi đang tạo một ứng dụng trong đó UIView kiểm tra các chạm từ người dùng và nếu người dùng chạm và di chuyển ngón tay của mình, đường dẫn sử dụng UIBezierPath sẽ được vẽ. Nếu người dùng vẽ để đường dẫn cắt chính nó sẽ biến mất khỏi màn hình. Khi người dùng vẽ xong mẫu, một dòng từ điểm cuối cùng trong đường dẫn sẽ tự động kết nối với điểm đầu tiên trong đường dẫn (tôi đang sử dụng phương thức "closePath" cho điều này), nếu dòng này cắt với một dòng khác "trong đường dẫn con đường cũng sẽ biến mất khỏi màn hình.

Tôi lưu trữ mọi điểm tiếp xúc trong CGPoint mà tôi lưu trữ trong một lớp khác được gọi là Dòng như điểm A và điểm B. Tôi sau đó lưu "dòng" vào NSMutableArray được gọi là "dòng". Mỗi lần một điểm được thêm vào đường dẫn tôi kiểm tra xem đường giữa điểm đó và điểm được vẽ trước khi nó cắt ngang với bất kỳ dòng nào trong dòng bằng cách sử dụng phương thức (- (BOOL) checkLineIntersection: (CGPoint) p1 : (CGPoint) p2: (CGPoint) p3: (CGPoint) p4) Tôi nhận được từ hướng dẫn này "http://www.iossourcecode.com/2012/08/02/how-to-make-a-game-like- cắt-the-rope-part-2/".

Vấn đề

Vấn đề là khi tôi chạy ứng dụng nó hoạt động đôi khi nhưng đôi khi tôi vẽ nên đường giao với đường không biến mất. Tôi không thể hiểu tại sao ... Có vẻ như nó xảy ra thường xuyên hơn khi tôi rút ra từ từ.

Mã:

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 

Tôi hy vọng ai đó có thể có thể trả lời này. Xin lỗi nếu nó là một cái gì đó hiển nhiên. Cảm ơn bạn trước!

Trả lời

8

Sự cố ở phương thức checkLineIntersection. Với

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

bạn kiểm tra chỉ khi phần nội thất của các dòng phân đoạn giao nhau. Nhưng nếu điểm xuất phát hoặc điểm cuối của đoạn đầu tiên bằng điểm xuất phát hoặc điểm cuối của đoạn đường thứ hai, uaub sẽ là 0.0 hoặc 1.0.

Giải pháp là để bao gồm một đầu của khoảng thời gian trong điều kiện:

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

này dường như làm việc như mong đợi trong chương trình thử nghiệm của tôi.

Một số nhận xét thêm:

  • Tôi nghĩ bạn nên kích hoạt các phím tắt

    if (denominator == 0.0f) return NO; 
    

    một lần nữa để tránh phép chia cho không.

  • Trong touchesMoved, bạn có thể thêm dòng mới vào mảng sau khi kiểm tra giao lộ. Bây giờ dòng mới được chèn đầu tiên, có nghĩa là nó được kiểm tra đối với chính nó cho các giao lộ.

  • Bạn đã khai báo Line là lớp con của UIView, nhưng đây không thực sự là lớp xem. Bạn chỉ có thể khai báo Line làm lớp con của NSObject.


thêm: Phương pháp sau đây có thể làm việc tốt hơn, bởi vì nó tránh được sự phân chia và do đó vấn đề tràn có thể với mẫu số nhỏ:

-(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); 
} 
+0

Câu trả lời tuyệt vời! Cảm ơn bạn. – JesperWingardh

+0

@JesperWingardh: Bạn được chào đón. –

0

tôi đã tìm thấy cách giải quyết khác để kiểm tra xem dòng có tự cắt ngang không. Với khung cảnh SceneKit, bạn có thể tạo hình dạng từ UIBezierPath. Nhưng nếu đường cắt giao nhau thì hộp giới hạn của nút sẽ bị xóa.

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) 
    } 
Các vấn đề liên quan