8

私は何時間も答えを探してきましたが、そのトピックについて何かを見つけるのに苦労しています。

Objective-cに関連する質問があります。UIViewがユーザーからのタッチをチェックし、ユーザーが指をタッチして動かすと、UIBezierPathを使用したパスが描画されるアプリケーションを作成しています。パスがそれ自体と交差するようにユーザーが描画すると、画面から消えるはずです。ユーザーがパターンの描画を完了すると、この線が別の「線」と交差する場合、パスの最後の点からの線がパスの最初の点に自動的に接続する必要があります(これには「closePath」メソッドを使用しています)。 "パス内のパスも画面から消えるはずです。

すべてのタッチポイントを、Lineと呼ばれる別のクラスにポイントAおよびポイントBとして格納するCGPointに格納します。次に、「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

誰かがこれに答えられるかもしれないといいのですが。明らかなことならごめんなさい。前もって感謝します!

4

2 に答える 2

8

問題はcheckLineIntersection方法にあります。と

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

線分セグメントの内側部分が交差するかどうかのみをチェックします。ただし、最初の線分の始点または終点が 2 番目の線分の始点または終点と等しい場合は、またはuaubなります。0.01.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たが、これは実際にはビュー クラスではありません。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);
}
于 2013-01-13T08:01:38.573 に答える