4

我有一个名为 Line 的核心数据实体。每行包含一个 VerticePoint 的实例,该实例包含一个 x 和 y 属性。这些 x 和 y 顶点形成简单的 2D 多边形。

我想要做的是对这些 Line 对象的数组进行排序,这些 Line 对象按随机顺序排列,以便形状的原点(左下角)始终是数组中的第一个元素,然后是剩余的顶点缠绕在 counter-从原点顺时针方向。

所以说我的原始数组中的点是(xy 轴以 0,0 为中心):

x = 20, y = 20
x = 20 , y= 10
x = 10, y=10
x = 10, y =20
x = 15, y = 10

我想像这样对它们进行排序:

x = 10, y=10
x = 15, y = 10
x = 20 , y= 10
x = 20, y = 20
x = 10, y =20

非常感谢

4

3 回答 3

13

这是一个精确规范的建议:

  1. 假设有一个第一象限坐标系(y 轴朝上)。
  2. 找到所有点的轴对齐边界框的中心。
  3. 按从中心到点的向量角度对点进行排序。要计算角度,请考虑指向西南的向量为 0°,角度逆时针方向上升。

这是一个解决方案:

NSArray *points = @[
    [NSValue valueWithCGPoint:(CGPoint){20, 20}],
    [NSValue valueWithCGPoint:(CGPoint){20, 10}],
    [NSValue valueWithCGPoint:(CGPoint){10, 10}],
    [NSValue valueWithCGPoint:(CGPoint){10, 20}],
    [NSValue valueWithCGPoint:(CGPoint){15, 10}],
];

CGPoint min = [points[0] CGPointValue];
CGPoint max = min;
for (NSValue *value in points) {
    CGPoint point = [value CGPointValue];
    min.x = fminf(point.x, min.x);
    min.y = fminf(point.y, min.y);
    max.x = fmaxf(point.x, max.x);
    max.y = fmaxf(point.y, max.y);
}

CGPoint center = {
    0.5f * (min.x + max.x),
    0.5f * (min.y + max.y),
};

NSLog(@"center: %@", NSStringFromCGPoint(center));

NSNumber *(^angleFromPoint)(id) = ^(NSValue *value){
    CGPoint point = [value CGPointValue];
    CGFloat theta = atan2f(point.y - center.y, point.x - center.x);
    CGFloat angle = fmodf(M_PI - M_PI_4 + theta, 2 * M_PI);
    return @(angle);
};

NSArray *sortedPoints = [points sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    return [angleFromPoint(a) compare:angleFromPoint(b)];
}];

NSLog(@"sorted points: %@", sortedPoints);
于 2013-12-05T12:01:03.570 回答
1

您可以使用

- (NSArray *)sortedArrayUsingDescriptors:(NSArray *)sortDescriptors

NSArray 的。

您可以使用多个描述符。只需初始化两个描述符,一个使用 x,一个使用 y 属性。

于 2013-12-05T09:13:15.303 回答
0

您应该为进行比较的 VerticePoint 对象实现方法,如下所示:

- (NSComparisonResult)compare:(VerticePoint *)vpoint
{
    if (self.x > vpiont.x)
        return NSOrderedAscending;
    else if (self.x < vpiont.x)
        return NSOrderedDescending;
    else if (self.y > vpiont.y)
        return NSOrderedAscending;
    else if (self.y < vpiont.y)
        return NSOrderedDescending;
    else 
        return NSOrderedSame;
}

之后,如果您的数组带有 VerticePoint 对象,则调用:

NSArray *sortedArray = [yourArray sortedArrayUsingSelector:@selector(compare:)];

希望这有帮助。

//扩展

如果您不想创建 NSManagedObject 的子类,可以使用 NSSortDescriptor:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"ENTITYNAME" inManagedObjectContext:context]];

NSSortDescriptor *sortDescriptorX = [NSSortDescriptor sortDescriptorWithKey:@"yourObjecy.x" ascending:YES];
NSSortDescriptor *sortDescriptorY = [NSSortDescriptor sortDescriptorWithKey:@"yourObjecy.y" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sortDescriptorX, sortDescriptorY, nil]];

NSArray *sortedResults = [context executeFetchRequest:request error:nil];

// 扩展

或者最简单的解决方案是

NSArray *returnedVertices = [verticesPassed sortedArrayUsingComparator:^(id obj1, id obj2) {
    //Cast to your object:
    VerticePoint *p1 = (VerticePoint*)obj1;
    VerticePoint *p2 = (VerticePoint*)obj2;
    if (p1.x > p2.x)
        return NSOrderedAscending;
    else if (p1.x < p2.x)
        return NSOrderedDescending;
    else if (p1.y > p2.y)
        return NSOrderedAscending;
    else if (p1.y < p2.y)
        return NSOrderedDescending;
    else 
        return NSOrderedSame;
}

];

于 2013-12-05T09:13:04.257 回答