0

簡単な描画アプリを作成する必要があります。このアプリは、両端に1つずつ、合計2つのアンカーポイントを持つ線で構成されています。ユーザーは、アンカーポイントをタッチダウンしてドラッグし、線の長さと傾きを操作できる必要があります。また、ユーザーは2つのアンカーポイントを結ぶ線をタッチダウンして移動し、アンカーポイントを画面上で移動できるようにする必要があります。

私はここでちょっと困惑しています。タッチダウン/アップを使用するだけで長さと傾斜の操作を行うことができると思いますが、これは複数の行では機能しないと思いますか?!誰かが私が見ているべき方向に私を向けることができますか?どうもありがとう :)

4

2 に答える 2

1

編集:今回は短いテストを実装して、答えを書き直しました。self.lineDrawView.lines以下のソースコードは次のことを行います。タッチダウン時に、リスト内のすべてのポイントから現在のタッチポイントまでの距離をチェックします。距離が10ピクセル未満の場合、現在のタッチポイントとそのリストインデックスが保存されます。

一致するポイントが見つからない場合、別の関数が内部のペアで構成されるすべてのラインを反復処理し、self.lineDrawView.lines各ラインまでの距離(ここで借用したラインコードまでの距離)を計算します。ここでも、距離が10ピクセル未満の場合、現在のタッチポイントと、現在のラインの開始点と終了点が保存されます。

次に、タッチ移動時に、保存されたポイントが移動されるか、保存されたラインが前のタッチダウンポイントと現在のタッチ位置の間の距離によって再計算されます。

ビューコントローラのヘッダー:

#import <UIKit/UIKit.h>
#import "myView.h"

@interface ViewController : UIViewController
{
    CGPoint dragStartingPoint, lineOriginStart, lineOriginEnd;
    int currentPointIndex, currentLineIndex;
}

@property (retain) myView *lineDrawView;
@property (retain) UITouch *currentTouch;
@end

ビューコントローラのソース:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.lineDrawView = [[myView alloc] initWithFrame:self.view.frame];
    [self.view addSubview:self.lineDrawView];
    self.lineDrawView.lines = [[NSMutableArray alloc] init];
    [self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake( 10,  10)]];
    [self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake(300, 100)]];
    [self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake(200, 400)]];
    [self.lineDrawView.lines addObject:[NSValue valueWithCGPoint:CGPointMake( 50, 300)]];
}

-(float)distanceOfPoint:(CGPoint)p toLineWith:(CGPoint)v0 and:(CGPoint)v1
{
    float vx = v0.x - p.x;
    float vy = v0.y - p.y;
    float ux = v1.x - v0.x;
    float uy = v1.y - v0.y;
    float length = ux * ux + uy * uy;
    float result;

    float det = (-vx * ux) + (-vy * uy);
    // if this is < 0 or > length then it's outside the line segment
    if(det < 0)
        result = (v0.x - p.x) * (v0.x - p.x) + (v0.y - p.y) * (v0.y - p.y);
    else if(det > length)
        result = (v1.x - p.x) * (v1.x - p.x) + (v1.y - p.y) * (v1.y - p.y);
    else
    {
        det = ux * vy - uy * vx;
        result = (det * det) / length;
    }

    return sqrtf(result);
}

-(int)getLineNearToPoint:(CGPoint)p withMaximumDistance:(float)d
{
    CGPoint p1, p2;
    NSValue *v1, *v2;

    for(int i=0; i<self.lineDrawView.lines.count/2; i++)
    {
        v1 = [self.lineDrawView.lines objectAtIndex:i*2+0];
        v2 = [self.lineDrawView.lines objectAtIndex:i*2+1];
        p1 = [v1 CGPointValue];
        p2 = [v2 CGPointValue];
        if([self distanceOfPoint:p toLineWith:p1 and:p2]<=d) return i;
    }

    return -1;
}

-(int)getPointNearToPoint:(CGPoint)p withinRadius:(float)r
{
    float dx, dy;
    CGPoint p2;
    NSValue *v;

    for(int i=0; i<self.lineDrawView.lines.count; i++)
    {
        v = [self.lineDrawView.lines objectAtIndex:i];
        p2 = [v CGPointValue];
        dx = p.x - p2.x;
        dy = p.y - p2.y;
        if(sqrtf(dx*dx + dy*dy)<=r) return i;
    }

    return -1;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    int iPoint, iLine;
    currentLineIndex = -1;
    currentPointIndex = -1;

    for(UITouch *t in touches)
    {
        // check if a starting/ending point is near the current touch
        CGPoint p = [t locationInView:self.view];
        iPoint = [self getPointNearToPoint:p withinRadius:10];
        if(iPoint != -1)
        {
            currentPointIndex = iPoint;
            self.currentTouch = t;
        }

        // check if current touch is near a line
        iLine = [self getLineNearToPoint:p withMaximumDistance:10];
        if((iLine != -1) && (iPoint == -1))
        {
            currentLineIndex = iLine;
            self.currentTouch = t;

            // save current touch position
            dragStartingPoint = p;

            // save original starting/ending point
            NSValue *v1 = [self.lineDrawView.lines objectAtIndex:iLine*2+0];
            NSValue *v2 = [self.lineDrawView.lines objectAtIndex:iLine*2+1];
            lineOriginStart = [v1 CGPointValue];
            lineOriginEnd = [v2 CGPointValue];
        }

        // only use first touch, discard the rest
        break;
    }
    [self.lineDrawView setNeedsDisplay];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    for(UITouch *t in touches)
    {
        // only respond to touch move events of the touch previously assigned
        // to a point or line
        if(t != self.currentTouch) continue;

        CGPoint p = [t locationInView:self.view];

        // Are we moving a starting/ending point?
        if(currentPointIndex != -1)
        {
            NSValue *v = [NSValue valueWithCGPoint:p];
            [self.lineDrawView.lines replaceObjectAtIndex:currentPointIndex withObject:v];
        }

        // Are we moving a line?
        if(currentLineIndex != -1)
        {
            // calculate drag distance
            float dx = p.x - dragStartingPoint.x;
            float dy = p.y - dragStartingPoint.y;

            // calculate new starting/ending points
            CGPoint p1 = CGPointMake(lineOriginStart.x+dx, lineOriginStart.y+dy);
            CGPoint p2 = CGPointMake(lineOriginEnd.x+dx, lineOriginEnd.y+dy);
            NSValue *v1 = [NSValue valueWithCGPoint:p1];
            NSValue *v2 = [NSValue valueWithCGPoint:p2];

            // replace old values
            [self.lineDrawView.lines replaceObjectAtIndex:currentLineIndex*2+0 withObject:v1];
            [self.lineDrawView.lines replaceObjectAtIndex:currentLineIndex*2+1 withObject:v2];
        }

        // only use first touch, discard the rest
        break;
    }
    [self.lineDrawView setNeedsDisplay];
}

- (void)dealloc
{
    self.lineDrawView.lines = nil;
    [super dealloc];
}
@end

描画用のビューのヘッダー:

#import <UIKit/UIKit.h>

@interface myView : UIView

@property (retain) NSMutableArray *lines;
@end

描画のビューのソース:

#import "myView.h"

@implementation myView

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if(self) {
    }
    return self;
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    // fill background
    CGContextSetRGBFillColor(context, 0.5, 0.5, 0.5, 1.0);
    CGContextFillRect(context, self.frame);

    // draw lines
    CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
    CGContextSetLineWidth(context, 2.0);
    for(int i=0; i<self.lines.count/2; i++)
    {
        CGPoint p1 = [[self.lines objectAtIndex:i*2+0] CGPointValue];
        CGPoint p2 = [[self.lines objectAtIndex:i*2+1] CGPointValue];
        CGContextMoveToPoint(context, p1.x, p1.y);
        CGContextAddLineToPoint(context, p2.x, p2.y);
    }
    CGContextStrokePath(context);
}

@end
于 2012-10-15T07:13:17.017 に答える
1

私は同様の問題に取り組んできましたが、このリンクに似たものでUIWebViewを使用することになりました

http://mbostock.github.com/protovis/ex/splines.html

そして、私はポイントのリストを使用して取得することができます

[myWebview stringByEvaluatingJavaScriptFromString....]

iPad / iPhoneで動作させるには、マウスを下に動かしたり上に動かしたりする代わりに、タッチ開始イベントとタッチ終了イベントを処理するためにJSコードにいくつかの変更を加える必要がありました。

于 2012-10-16T07:45:48.697 に答える