【发布时间】:2012-09-24 04:49:45
【问题描述】:
我有一个点数组,其中每个点都是地图上的一个坐标。我想这样当我向地图添加一个点时,它会添加到我的数组中最近的两个点之间。
另外,我想渲染点,这样不同点之间就不会有任何交叉。新点应添加到生成的多边形的外边缘,并连接到最近的两个。
有这样的算法吗?
编辑:
为清楚起见,我有以下屏幕截图。我想实现方法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;
}
【问题讨论】:
-
你假设凸性吗?另外,假设 P 是一个以 C 为中心的正多边形,并在 C 处添加一个点;应该怎么办?
-
@jwpat7 我没有考虑过这些事情。有没有办法“优化”它?比如,根据点假设一种或另一种?
-
如果你假设生成的多边形在添加点时总是凸的,那么在 O(n) 时间内添加第 n 个点很简单。如果您不假设凸性,例如允许星形,则问题可能无法解决。重新凸包,它的复杂度是 Ω(n log n),但如果你假设没有点在包的内部,你可以获得 O(n) 复杂度。
-
好吧,我想考虑星形等,但尽量定位在正确的位置,连接正确。
标签: algorithm geometry mkmapview polygons