我有一个点数组,其中每个点都是地图上的坐标。我想这样做,以便当我向地图添加一个点时,它会添加到我的数组中最近的两点之间。
此外,我想渲染这些点,以便不同点之间永远不会有任何交叉。新点应添加到生成的多边形的外边缘,并连接到最近的两个。
有这样做的算法吗?
编辑:
为清楚起见,我有以下屏幕截图。我想实现方法B:
编辑2:
这是我为尝试解决问题而编写的一堆代码。假设 MBCoordinates 就是这样,坐标:
//
// Detect which coordinate is the closest to the supplied coordinate
//
- (void) insertCoordinateBetweenClosestNeighbors:(MBCoordinate *)coordinate{
if (![self points] || [[self points] count] < 3) {
[[self points] addObject:coordinate];
return;
}
NSMutableSet *pointSet = [NSMutableSet setWithArray:[self points]];
MBCoordinate *closestCoordinate = [self closestCoordinateToCoordinate:coordinate inSet:pointSet];
[pointSet removeObject:closestCoordinate];
MBCoordinate *nextClosestCoordinate = [self closestCoordinateToCoordinate:coordinate inSet:pointSet];
NSUInteger indexOfClosestCoordinate, indexOfSecondClosestCoordinate, insertionIndex;
for (NSUInteger i=0; i < [[self points] count]; i++) {
if ([[self points][i] isEqual:closestCoordinate]) {
indexOfClosestCoordinate = i;
}
if ([[self points][i] isEqual:nextClosestCoordinate]) {
indexOfSecondClosestCoordinate = i;
}
}
if(indexOfSecondClosestCoordinate == indexOfClosestCoordinate-1){
insertionIndex = indexOfSecondClosestCoordinate+1;
}else{
insertionIndex = indexOfClosestCoordinate+1;
}
[[self points] insertObject:coordinate atIndex:insertionIndex];
/*
Not in use in my program, but an alternate attempt:
[[self points] addObject:coordinate];
[self sortPointsByDistance];
*/
}
- (void) sortPointsByDistance{
//
// Points that need sorting
//
NSMutableSet *unprocessedPoints = [NSMutableSet setWithArray:[self points]];
//
// All of the unsorted points
//
NSMutableSet *unsortedPoints = [NSMutableSet setWithArray:[self points]];
//
// The unsorted points minus the closest one
//
NSMutableSet *unsortedPointsExceptClosest = [NSMutableSet setWithArray:[self points]];
//
// We put the point into here in the correct order
//
NSMutableArray *sortedPoints = [@[] mutableCopy];
//
// Prime the pump
//
MBCoordinate *workingCoordinate = [self points][0];
[sortedPoints addObject:workingCoordinate];
[unprocessedPoints removeObject:workingCoordinate];
while([unprocessedPoints count] > 0){
MBCoordinate *closestCoordinate = [self closestCoordinateToCoordinate:workingCoordinate inSet:unsortedPoints];
MBCoordinate *secondClosestCoordinate = nil;
//
// The closest point might be sorted already!
//
// If it is, then we have to find the closest point.
//
if ([sortedPoints containsObject:closestCoordinate]) {
NSInteger indexOfClosest = [sortedPoints indexOfObject:closestCoordinate];
NSInteger indexOfSecondClosest = indexOfClosest;
NSInteger targetIndex = indexOfClosest+1;
if (!secondClosestCoordinate) {
[unsortedPoints removeObject:closestCoordinate];
secondClosestCoordinate = [self closestCoordinateToCoordinate:workingCoordinate inSet:unsortedPointsExceptClosest];
if ([sortedPoints containsObject:secondClosestCoordinate]) {
//
// Insert between the two points
//
indexOfSecondClosest = [sortedPoints indexOfObject:secondClosestCoordinate];
}
}
if (indexOfSecondClosest < indexOfClosest) {
targetIndex = indexOfSecondClosest + 1;
}
[sortedPoints insertObject:workingCoordinate atIndex:targetIndex];
workingCoordinate = [unprocessedPoints anyObject];
break;
}else{
workingCoordinate = closestCoordinate;
}
[sortedPoints addObject:workingCoordinate];
[unprocessedPoints removeObject:workingCoordinate];
unsortedPointsExceptClosest = [unsortedPoints copy];
secondClosestCoordinate = nil;
}
[self setPoints:sortedPoints];
}
- (MBCoordinate *) closestCoordinateToCoordinate:(MBCoordinate *)coordinate inSet:(NSSet *)aSet{
MBCoordinate *closest = nil;
CGFloat closestDistance;
for (MBCoordinate *coordinateInSet in aSet) {
if ([coordinateInSet isEqual:coordinate]) {
continue;
}
if (!closest) {
closest = coordinateInSet;
closestDistance = [self distanceBetweenCoordinate:coordinate andCoordinate:coordinateInSet];
}
CGFloat distanceBetweenPoints = [self distanceBetweenCoordinate:coordinate andCoordinate:coordinateInSet];
if (distanceBetweenPoints < closestDistance) {
closest = coordinateInSet;
closestDistance = distanceBetweenPoints;
}
}
return closest;
}
//
// Determines the distance between two coordinates
//
- (CGFloat) distanceBetweenCoordinate:(MBCoordinate *)coordinate andCoordinate:(MBCoordinate *)anotherCoordinate{
CGFloat xDistance, yDistance;
xDistance = coordinate.latitude-anotherCoordinate.latitude;
yDistance = coordinate.longitude-anotherCoordinate.longitude;
float distance = xDistance/yDistance;
//
// Absolute value of floats...
//
if (distance < 0) {
distance *= -1;
}
return distance;
}