如何使用无序CGPoints绘制特定的CGPath

考虑这个ASCII图:

A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |                               |
 |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|
B                                 C

点A,B,C和D是NSMutableArray中已知的CGPoints ,并用于创建一个填充的CGPath 。 现在考虑这张图:

A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D
 |                               |
 |                               |
 |                               |
 |                               |
 |            H _ _ _ I          |
 |             |     |           |
 |             |     |           |
 |      F _ _ _|     |           |
 |       |      G    |           |
 |       |           |_ _ _ K    |
 |       |          J      |     |
 |       |                 |     |
 |_ _ _ _| _ _ _ _ _ _ _ _ |_ _ _|
B         E               L       C

CGPoints E,F,G,H,I,J,K和L是已知的,并已被附加到NSMutableArray的末尾。

问题

如何重新排列数组中的所有点以创建一个如下图所示的CGPath

A _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ D
 |                               |
 |                               |
 |                               |
 |                               |
 |            H _ _ _ I          |
 |             |     |           |
 |             |     |           |
 |      F _ _ _|     |           |
 |       |      G    |           |
 |       |           |_ _ _ K    |
 |       |          J      |     |
 |       |                 |     |
 |_ _ _ _|                 |_ _ _|
B         E               L       C

目前我没有创建CGPath麻烦 - 如果我知道CGpoints的顺序 - 通过遍历它们:

CGPoint firstPoint = [[points objectAtIndex:0] CGPointValue];
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, firstPoint.x, firstPoint.y);
for (int i = 0; i < [points count]; i++)
{
    CGPathAddLineToPoint(path, NULL, [[points objectAtIndex:i] CGPointValue].x, [[points objectAtIndex:i] CGPointValue].y);
}
CGPathCloseSubpath(path);

...但是这假设应该从数组i中的每个点绘制一条线到下面的点i + 1 。 在上图中,线必须从A → BB → EE → F K → LL → CC → D绘制。 如果E不在B之后,C不在数组L之后(它们不会),那么这显然不会正确绘制。

更多信息

  • 所有的线都是相互垂直的,因此所有的CGPoints应该在它们之前和之后与CGPoint共享一个xy坐标。
  • (#1的延伸)一个点将始终与它之前和之后的点成直角。
  • 无法预测这些点将出现在正方形内的哪个点上,并且当附加到数组末尾时,新的一组点可能会或可能不会按顺序排列。
  • ...
  • 其他可能的布局

    A _ _ _ _ _ _ _ K         P _ _ _ D
     |             |           |     | 
     |             |           |     |
     |             |    N _ _ _|     |
     |             |     |      O    |
     |             |_ _ _|           |
     |            L       M          |
     |                               |
     |            F _ _ _ G          |
     |             |     |           |
     |             |     |_ _ _ I    |
     |             |    H      |     |
     |             |           |     |
     |_ _ _ _ _ _ _|           |_ _ _|
    B               E         J       C
    
    
    A _ _ _ _ _ _ _ _ _ _ M
     |                   |           
     |                   |           
     |                   |_ _ _ _ _ _ O
     |                  N            |
     |            H _ _ _ I          |
     |             |     |           |
     |             |     |           |
     |      F _ _ _|     |           |
     |       |      G    |           |
     |       |           |_ _ _ K    |
     |       |          J      |     |
     |       |                 |     |
     |_ _ _ _|                 |_ _ _|
    B         E               L       C
    

    我认为这可能会做到。 我用几组数字对它进行了测试,它似乎工作。 基本上,我从索引0开始(任何起点应该工作),将其添加到arrangePoints数组,然后查找具有相同y值的最近点 - 该点将添加到排列好的点并从原始随机点中删除阵列。 然后,我在x方向上做同样的事情并重复,直到randomPoints数组中只剩下一个点,并将其添加到arrangePoints的末尾。

    -(void)arrangePoints:(NSMutableArray *) randomPoints {
        NSMutableArray *arrangedPoints = [NSMutableArray array];
        [arrangedPoints addObject:[randomPoints objectAtIndex:0]];
        [randomPoints removeObjectAtIndex:0];
    
        while (randomPoints.count > 1) {
            //Look for the closest point that has the same y value
            int yValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].y;
            int xValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].x;
            NSIndexSet *indSet = [randomPoints indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
                return yValueOfknownPoint == [obj CGPointValue].y;
            }];
            NSLog(@"%d",indSet.count);
    
            if (indSet.count == 1) {
                [arrangedPoints addObject:[randomPoints objectAtIndex:indSet.firstIndex]];
                [randomPoints removeObjectAtIndex:indSet.firstIndex];
            }else{
                __block int min = 10000000;
                __block int foundIndex;
                [indSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
                    int posibleMin = fabs(xValueOfknownPoint - [[randomPoints objectAtIndex:idx]CGPointValue].x);
                    if (posibleMin < min) {
                        min = posibleMin;
                        foundIndex = idx;
                    }
                }];
                [arrangedPoints addObject:[randomPoints objectAtIndex:foundIndex]];
                [randomPoints removeObjectAtIndex:foundIndex];
            }
    
            //Look for the closest point that has the same x value
            xValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].x;
            yValueOfknownPoint = [[arrangedPoints lastObject] CGPointValue].y;
            indSet = [randomPoints indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
                return xValueOfknownPoint == [obj CGPointValue].x;
            }];
    
            if (indSet.count == 1) {
                [arrangedPoints addObject:[randomPoints objectAtIndex:indSet.firstIndex]];
                [randomPoints removeObjectAtIndex:indSet.firstIndex];
            }else{
                __block int min = 10000000;
                __block int foundIndex;
                [indSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
                    int posibleMin = fabs(yValueOfknownPoint - [[randomPoints objectAtIndex:idx]CGPointValue].y);
                    if (posibleMin < min) {
                        min = posibleMin;
                        foundIndex = idx;
                    }
                }];
                [arrangedPoints addObject:[randomPoints objectAtIndex:foundIndex]];
                [randomPoints removeObjectAtIndex:foundIndex];
            }
        }
        [arrangedPoints addObject:randomPoints.lastObject];
        NSLog(@"%@",arrangedPoints);
    
    }
    

    解决已知问题的一些补充点:

    为了处理像N和G这样的等距点,我想我会保持点集合不同 - 而不是把每个东西放到一个数组中,我会保留原始的矩形,并且每个新的点集合都是分开的。 然后,当我构建路径时,我只会在自己的一组点或原始矩形内寻找点,而不是在其他任何点中寻找点。

    为了解决提出的问题,增加双倍回报,我认为你必须确定一组点是否与一个边或一个角相交 - 我认为只有边角点才会出现这个问题。 您可以通过查看2个点落在原始矩形的2条不同线上(而不是在同一条线上)来检查角点。 然后你必须计算出缺少的点(上面最后一个例子中的一个假定点p),并查看原始矩形的哪个点也是相同的,然后从路径中删除该点。 我认为我的算法会正常工作。


    这里有一种方法(伪代码),如果你感兴趣的是填充而不是笔画:

  • 使用CGPathCreateMutable()创建一个空的可变路径。

  • 将原始的矩形图形添加到可变路径作为闭环。

  • 逐个添加每个不规则图形到可变路径,作为一个闭环。

  • 使用函数CGContextEOFillPath()使用偶数填充规则填充被侵蚀的图形。

  • 奇数填充规则在Quartz 2D Programming Guide填充路径一节中介绍。

    您可能也对此感兴趣


    好吧,这可能看起来是一个非常复杂的算法(它远非最佳),但我会这样来处理它。

    1. Find the point(s) with lowest X-value
    
    2. Of those points find point P (using a loop) such that:
        - P has a nabour N with the same X-value
        - There exists no other point that vertically lies between P and its nabour N with the same Y value
        (if no P exists with a nabour, the algorithm has ended, after joining P with its horizontally aligned point)
    
    3. If there exists a point with the same X value as P (horizontally aligned), join that point and P with a line.
    
    4. Now join point P with its nabour N
    
    5. Find all points with the same X-value as N (horizontally aligned)
    
    6. Goto 2
    

    我希望它有效(还没有测试过)。

    链接地址: http://www.djcxy.com/p/61823.html

    上一篇: How to draw a specific CGPath with unordered CGPoints

    下一篇: Transparency Gradient on an Image