在帮助下我可以使用协调绘制圆圈:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 5.0);
CGContextSetStrokeColorWithColor(context,[UIColor grayColor].CGColor);
/**** Get values from reponse and fill it in this array. ******/
NSArray *objectCoords = [NSArray arrayWithObjects: @"{{20,80},{5,5}}", @"{{120,60},{5,5}}", @"{{60,84},{5,5}}", @"{{80,88},{5,5}}", @"{{100,93},{5,5}}", @"{{20,20},{5,5}}", @"{{160,70},{5,5}}", @"{{128,68},{5,5}}", @"{{90,60},{5,5}}", @"{{110,80},{5,5}}", nil];
for (NSString* objectCoord in objectCoords) {
CGRect coord = CGRectFromString(objectCoord);
// Draw using your coord
CGContextAddEllipseInRect(context, coord);
}
现在我想要实现的是在点(圆圈)之间绘制线条,如附图中所示。我知道我们可以在2个点之间绘制一条线,但在这种情况下,需要绘制线条在一个到多个点/圆之间。请建议我实现这个结果。
答案 0 :(得分:2)
你可以画多行。首先,提出一个模型来表示您想要绘制线条的点。例如,你可以有一个行数组,其中每一行本身定义为一个索引为两点的数组,即起点和终点。
例如,如果要绘制从第1点到第3点,第4点和第5点以及第3点到第4点和第5点以及第4点和第5点之间的行,您可以执行以下操作:
CGContextSetLineWidth(context, 1.0);
NSArray *lines = @[@[@(1), @(3)],
@[@(1), @(4)],
@[@(1), @(5)],
@[@(3), @(4)],
@[@(3), @(5)],
@[@(4), @(5)]];
for (NSArray *points in lines) {
NSInteger startIndex = [points[0] integerValue];
NSInteger endIndex = [points[1] integerValue];
CGRect startRect = CGRectFromString(objectCoords[startIndex]);
CGRect endRect = CGRectFromString(objectCoords[endIndex]);
CGContextMoveToPoint(context, CGRectGetMidX(startRect), CGRectGetMidY(startRect));
CGContextAddLineToPoint(context, CGRectGetMidX(endRect), CGRectGetMidY(endRect));
}
CGContextDrawPath(context, kCGPathStroke);
有很多不同的方法可以做到这一点,但只是想出一些代表你想要绘制线条的模型,然后遍历该模型来绘制所有单独的线条。
如果您希望每个点都画线到最近的三个点(这不是您的图片所做的,但这是您在后续评论中所要求的),您可以:
在indices
数组中构建索引数组objectCoords
;和
现在遍历objectCoords
中的每个点:
构建新的索引数组sortedIndices
,按照该索引所代表的点距objectCoords
中当前对象的距离排序;以及
画出最近的三条线。
因此:
// build array of indices (0, 1, 2, ...)
NSMutableArray *indices = [NSMutableArray array];
[objectCoords enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[indices addObject:@(idx)];
}];
// now go through all of the points in objectCoords
[objectCoords enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
// build new array of indices sorted by distance from the current point
NSArray *sortedIndices = [indices sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
CGFloat distance1 = [self distanceFromPointAtIndex:idx
toPointAtIndex:[obj1 integerValue]
usingObjectCoords:objectCoords];
CGFloat distance2 = [self distanceFromPointAtIndex:idx
toPointAtIndex:[obj2 integerValue]
usingObjectCoords:objectCoords];
if (distance1 < distance2)
return NSOrderedAscending;
else if (distance1 > distance2)
return NSOrderedDescending;
return NSOrderedSame;
}];
// now draw lines to the three closest indices
// (skipping 0, because that's probably the current point)
for (NSInteger i = 1; i < 4 && i < [sortedIndices count]; i++) {
NSInteger index = [sortedIndices[i] integerValue];
CGRect startRect = CGRectFromString(objectCoords[idx]);
CGRect endRect = CGRectFromString(objectCoords[index]);
CGContextMoveToPoint(context, CGRectGetMidX(startRect), CGRectGetMidY(startRect));
CGContextAddLineToPoint(context, CGRectGetMidX(endRect), CGRectGetMidY(endRect));
}
}];
CGContextSetLineWidth(context, 1);
CGContextDrawPath(context, kCGPathStroke);
这使用以下方法计算两点之间的距离:
- (CGFloat)distanceFromPointAtIndex:(NSInteger)index1 toPointAtIndex:(NSInteger)index2 usingObjectCoords:(NSArray *)objectCoords
{
CGRect rect1 = CGRectFromString(objectCoords[index1]);
CGRect rect2 = CGRectFromString(objectCoords[index2]);
return hypotf(CGRectGetMidX(rect1) - CGRectGetMidX(rect2), CGRectGetMidY(rect1) - CGRectGetMidY(rect2));
}
使用原始示例中的objectCoords
,产生:
答案 1 :(得分:1)
这与你原来的问题有点无关,而不是一串字符串,如下所示:
NSArray *objectCoords = @[@"{{20,80},{5,5}}",
@"{{120,60},{5,5}}",
@"{{60,84},{5,5}}",
@"{{80,88},{5,5}}",
@"{{100,93},{5,5}}",
@"{{20,20},{5,5}}",
@"{{160,70},{5,5}}",
@"{{128,68},{5,5}}",
@"{{90,60},{5,5}}",
@"{{110,80},{5,5}}"];
我可能会建议使用一组NSValue
个对象:
NSArray *objectCoords = @[[NSValue valueWithCGRect:CGRectMake(20,80,5,5)],
[NSValue valueWithCGRect:CGRectMake(120,60,5,5)],
[NSValue valueWithCGRect:CGRectMake(60,84,5,5)],
[NSValue valueWithCGRect:CGRectMake(80,88,5,5)],
[NSValue valueWithCGRect:CGRectMake(100,93,5,5)],
[NSValue valueWithCGRect:CGRectMake(20,20,5,5)],
[NSValue valueWithCGRect:CGRectMake(160,70,5,5)],
[NSValue valueWithCGRect:CGRectMake(128,68,5,5)],
[NSValue valueWithCGRect:CGRectMake(90,60,5,5)],
[NSValue valueWithCGRect:CGRectMake(110,80,5,5)]];
然后,当您提取CGRect
值时,而不是:
CGRect rect = CGRectFromString(objectCoords[index]);
你会这样做:
CGRect rect = [objectCoords[index] CGRectValue];
我知道这看起来更麻烦,但使用NSValue
会更有效率(这在做很多或重复计算距离时很有用)。
更好的是,您可能希望定义自己的模型对象,更直观地定义要绘制图表的点,例如:
@interface ChartPoint : NSObject
@property (nonatomic) CGPoint center;
@property (nonatomic) CGFloat radius;
@end
和
@implementation ChartPoint
+ (instancetype) chartPointWithCenter:(CGPoint)center radius:(CGFloat)radius
{
ChartPoint *chartPoint = [[ChartPoint alloc] init];
chartPoint.center = center;
chartPoint.radius = radius;
return chartPoint;
}
- (CGFloat)distanceToPoint:(ChartPoint *)otherPoint
{
return hypotf(self.center.x - otherPoint.center.x, self.center.y - otherPoint.center.y);
}
@end
然后你可以像这样创建一个数组:
NSArray *objectCoords = @[[ChartPoint chartPointWithCenter:CGPointMake(20,80) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(120,60) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(60,84) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(80,88) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(100,93) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(20,20) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(160,70) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(128,68) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(90,60) radius:5],
[ChartPoint chartPointWithCenter:CGPointMake(110,80) radius:5]];
但是这个
避免效率低CGRectFromString
;
避免需要执行重复CGRectGetMidX
和CGRectGetMidY
次调用以确定CGRect
的中心;最重要的是,
更准确地表示您的对象实际上是什么。
显然,当你想要得出你的分数而不是做:
NSString *string = objectCoords[idx];
CGRect *rect = CGRectFromString(string);
CGContextAddEllipseInRect(context, rect);
你会这样做:
ChartPoint *point = objectCoords[idx];
CGContextAddArc(context, point.center.x, point.center.y, point.radius, 0, M_PI * 2.0, YES);