3

我有一个点数组,其中每个点都是地图上的坐标。我想这样做,以便当我向地图添加一个点时,它会添加到我的数组中最近的两点之间。

此外,我想渲染这些点,以便不同点之间永远不会有任何交叉。新点应添加到生成的多边形的外边缘,并连接到最近的两个。

有这样做的算法吗?

编辑:

为清楚起见,我有以下屏幕截图。我想实现方法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;

}
4

2 回答 2

5

我认为你所追求的可以通过使用Convex Hull来实现。这将创建一个多边形,其边围绕您的所有点。但是,如果您有一个不在边缘上的点,它将最终在多边形内。

您可以在此页面上查看 Convex Hull 算法的实现。

于 2012-09-24T05:05:36.407 回答
4

好吧,我不知道您的坐标系是如何工作的,但是您要做的是计算新点与数组中其他点之间的欧几里得距离。然后只需将新点插入到新点的欧几里德距离最短的两个点之间。

请记住,地球表面并不平坦。上面链接的欧几里得距离假定二维平面度。因此,您的观点相距越远,该公式的准确性就越低。

于 2012-09-24T05:24:42.520 回答