我需要創建一個簡單的繪圖應用程序。這個應用程序包括一個兩個錨點,在每一端的一個線。用戶應該能夠觸摸錨點並拖動它來操縱線的長度和斜率。此外,用戶應該能夠觸及連接兩個錨點的線,以將其移動並將屏幕上的錨點移動。iPhone與錨點劃線
我有點難倒在這裏,我知道我可以通過簡單地使用touch down/up來操縱長度和坡度,但我不認爲這將適用於多行?!任何人都可以指出我應該看的方向嗎?非常感謝:)
我需要創建一個簡單的繪圖應用程序。這個應用程序包括一個兩個錨點,在每一端的一個線。用戶應該能夠觸摸錨點並拖動它來操縱線的長度和斜率。此外,用戶應該能夠觸及連接兩個錨點的線,以將其移動並將屏幕上的錨點移動。iPhone與錨點劃線
我有點難倒在這裏,我知道我可以通過簡單地使用touch down/up來操縱長度和坡度,但我不認爲這將適用於多行?!任何人都可以指出我應該看的方向嗎?非常感謝:)
編輯:我重寫了答案,這次通過實施一個簡短的測試。下面的源代碼執行以下操作:觸摸時,它會檢查列表self.lineDrawView.lines
中每個點到當前觸點的距離。如果距離低於10 px,則保存當前觸點及其列表索引。
如果找不到匹配的點,則另一個函數遍歷self.lineDrawView.lines
內部由成對構成的所有線,並計算到每條線的距離(到借用的線路代碼的距離here)。再次,如果距離低於10 px,則保存當前觸點以及當前行的起點和終點。
然後,在觸摸移動時,移動保存的點或者重新計算上一個觸摸點與當前觸摸位置之間的距離。
部首視圖控制器:
#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
我一直在類似的問題,我結束了使用UIWebView的類似於此鏈接
http://mbostock.github.com/protovis/ex/splines.html
,我還可以使用
[myWebview stringByEvaluatingJavaScriptFromString....]
我得到的點列表的東西必須對JS代碼進行一些更改以處理觸摸開始和觸摸結束事件,而不是鼠標向下和鼠標向上,以使其在iPad/iPhone上運行
感謝馬哈茂德,但我希望在不借助Javascript的情況下在Objective C中提供解決方案。我提高了你的答案,因爲我仍然認爲它的解決方案可能與其他方面有關。 – bennythemink
Hey nullp01nter,感謝您的sugg但是這並沒有考慮觸摸是否在不同線上的兩點之間的距離相同(例如,如果一行的末尾重疊/接近另一行的開頭),它也不會告訴我觸摸是否是在一條線上,我需要移動屏幕周圍的線,保持其長度和坡度完好無損。 – bennythemink
我重寫了我的答案,因爲我錯過了線條運動的要點。另一個問題 - 兩條不同線路之間的距離相同 - 取決於你想在這種情況下做什麼。我上面的解決方案只需要第一個匹配點。你也可以搜索最近的點。同樣的近點是不同的,我相信你可以根據我上面的建議來實現你想要的行爲。 – nullp01nter
感謝所有努力nullp01nter。我還沒有機會測試你的代碼,但邏輯看起來很合理。 – bennythemink