2012-12-22 13 views
6

मैं घंटों के लिए उत्तर खोज रहा हूं लेकिन विषय पर कुछ भी ढूंढने में परेशानी है।UIBezierPath छेड़छाड़

मेरे पास उद्देश्य-सी से संबंधित एक प्रश्न है। मैं एक ऐसा ऐप्लिकेशन बना रहा हूं जिसमें यूआईवीव उपयोगकर्ता से छूने के लिए जांच करता है और यदि उपयोगकर्ता अपनी उंगली को छूता है और ले जाता है, तो UIBezierPath का उपयोग करके एक पथ खींचा जाता है। यदि उपयोगकर्ता खींचता है ताकि पथ स्वयं को छेड़छाड़ कर लेता है तो यह स्क्रीन से गायब हो जाना चाहिए। जब उपयोगकर्ता पैटर्न को चित्रित कर लेता है, तो पथ में अंतिम बिंदु से एक रेखा स्वचालित रूप से पथ में पहले बिंदु से कनेक्ट होनी चाहिए (मैं इस के लिए "क्लोजपैथ" विधि का उपयोग कर रहा हूं), यदि यह रेखा किसी अन्य पंक्ति के साथ छेड़छाड़ करती है "रास्ते में पथ स्क्रीन से भी गायब होना चाहिए।

मैं प्रत्येक टच पॉइंट को एक CGPoint में संग्रहीत करता हूं जिसे मैं लाइन ए के रूप में लाइन ए और पॉइंट बी के रूप में संग्रहीत करता हूं। मैं फिर "लाइन" को "लाइन" नामक एनएसएमयूटेबलएरे में सहेज रहा हूं। प्रत्येक बार जब पथ में एक बिंदु जोड़ा जाता है, तो मैं यह देखने के लिए जांच करता हूं कि उस बिंदु और बिंदु के बीच की रेखा किसी विधि (- (BOOL) चेकलाइन इन्टरटेक्शन: (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 

मुझे आशा है कि किसी को यह जवाब देने में सक्षम हो सकता है। क्षमा करें अगर यह कुछ स्पष्ट है। आपका अग्रिम में ही बहुत धन्यवाद!

उत्तर

8

समस्या checkLineIntersection विधि में है।

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

के साथ आप केवल तभी आंतरिक हिस्सा लाइनों खंडों एक दूसरे को काटना के की जाँच करें। लेकिन अगर प्रारंभ या पहला रेखा खंड के अंतिम बिंदु प्रारंभ या दूसरी पंक्ति खंड के अंतिम बिंदु के बराबर है, ua और ub0.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 में, आप के बाद चौराहे की जांच के बाद नई लाइन जोड़ सकते हैं। अब नई लाइन पहले डाली गई है, जिसका मतलब है कि यह छेड़छाड़ के लिए खुद के खिलाफ जांच की जाती है।

  • आपने 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); 
} 
+0

अद्भुत जवाब! धन्यवाद। – JesperWingardh

+0

@ जेस्पर विंगर्ड: आपका स्वागत है। –

0

मैं करने के लिए एक और वैकल्पिक हल मिल गया है जांचें कि रेखा स्वयं को छेड़छाड़ करती है या नहीं। सीनकेट फ्रेमवर्क के साथ 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) 
    } 
संबंधित मुद्दे