Сортировка массива точек вершин X и Y? iOS / Цель C
У меня есть сущность Core Data под названием Line. Каждая строка содержит экземпляр VerticePoint, который содержит свойства x и y. Эти вершины x и y образуют простые двумерные многоугольники.
То, что я хочу сделать, это отсортировать массив этих объектов Line в случайном порядке, так чтобы начало формы, нижняя левая точка, всегда было первым элементом в массиве, после чего следовали оставшиеся вершины, намотанные в противоположную сторону. по часовой стрелке от начала координат.
Скажем, точки в моем исходном массиве (ось 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
Большое спасибо
3 ответа
Ты можешь использовать
- (NSArray *)sortedArrayUsingDescriptors:(NSArray *)sortDescriptors
NSArray.
Вы можете использовать более одного дескриптора. Просто инициализируйте два дескриптора, один с x, другой со свойством y.
Вот предложение для точной спецификации:
- Предположим, что первая система координат квадранта (с осью Y, направленной вверх).
- Найти центр оси выровненных ограничивающих рамок всех точек.
- Сортировка точек по углу вектора от центра к точке. Чтобы вычислить угол, рассмотрим вектор, указывающий на юго-запад, на 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);
Вы должны реализовать метод для вашего объекта 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;
}
];