美文网首页
不规则多边形三角切割法 OC版

不规则多边形三角切割法 OC版

作者: X1aoHey | 来源:发表于2018-06-05 15:57 被阅读211次

    openGL ES 项目中需要绘制不规则的多边形,但openGL ES只支持三角形,三角带,三角扇。但后台给的数据只有顶点坐标没有顶点索引,只能根据顶点坐标把多边形切割成三角形:

    耳切法切割多边形的几个主要方法:

    1.根据顶点坐标计算多边形带方向面积,主要是为了判断顶点时针方向,正时针面积<0,逆时针>0

    + (float)Area:(NSArray<NSValue *> *)contour {
    
        int n = (int)contour.count;
        
        float A = 0.0f;
        
        for(int p = n - 1, q = 0 ; q < n; p = q++) {
            
            CGPoint pPoint = [contour[p] CGPointValue];
            CGPoint qPoint = [contour[q] CGPointValue];
            
            A += (pPoint.x * qPoint.y - qPoint.x * pPoint.y);
        }
        return A * 0.5f;
    }
    

    2.判断一个点是否在一个三角形(三个点)之中

    + (BOOL)InsideTriangle:(float)Ax :(float)Ay :(float)Bx :(float)By :(float)Cx :(float)Cy :(float)Px :(float)Py {
    
        float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
        float cCROSSap, bCROSScp, aCROSSbp;
        
        ax = Cx - Bx;  ay = Cy - By;
        bx = Ax - Cx;  by = Ay - Cy;
        cx = Bx - Ax;  cy = By - Ay;
        apx= Px - Ax;  apy= Py - Ay;
        bpx= Px - Bx;  bpy= Py - By;
        cpx= Px - Cx;  cpy= Py - Cy;
        
        aCROSSbp = ax*bpy - ay*bpx;
        cCROSSap = cx*apy - cy*apx;
        bCROSScp = bx*cpy - by*cpx;
        
        BOOL result = (aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f);
        return result;
    }
    
    1. 是否符合切割条件
    static const float EPSILON = 0.0000000001f;
    + (BOOL)Snip:(NSArray<NSValue *> *)contour :(NSMutableArray *)V :(int)u :(int)v :(int)w :(int)n
    {
        float Ax, Ay, Bx, By, Cx, Cy, Px, Py;
    
        int a = [V[u] intValue];
        CGPoint aPoint = [contour[a] CGPointValue];
        Ax = aPoint.x;
        Ay = aPoint.y;
    
        int b = [V[v] intValue];
        CGPoint bPoint = [contour[b] CGPointValue];
        Bx = bPoint.x;
        By = bPoint.y;
    
        int c = [V[w] intValue];
        CGPoint cPoint = [contour[c] CGPointValue];
        Cx = cPoint.x;
        Cy = cPoint.y;
    
        float temp = ((Bx - Ax) * (Cy - Ay)) - ((By - Ay) * (Cx - Ax));
        
        if ( EPSILON > temp ) 
            return false;
    
        for (int p = 0; p < n ; p++) {
            
            if( (p == u) || (p == v) || (p == w) ) continue;
            
            int z = [V[p] intValue];
            CGPoint pPoint = [contour[z] CGPointValue];
            Px = pPoint.x;
            Py = pPoint.y;
            
            if ([self InsideTriangle:Ax :Ay :Bx :By :Cx :Cy :Px :Py]) 
                return false;
        }
        return true;
    }
    
    1. 流程
    + (NSMutableArray *)Process:(NSArray<NSValue *> *)contour
    {
        NSMutableArray *result = [NSMutableArray array];
        
        NSInteger n = contour.count;
        if ( n < 3 ) return result;
        
        NSMutableArray *V = [NSMutableArray arrayWithCapacity:n];
        
        if ( 0.0f < [self Area:contour] ) {
            for (int v = 0; v < n; v++) {
                NSNumber *num = [NSNumber numberWithInt:v];
                [V insertObject:num atIndex:v];
            }
        } else {
            for(int v = 0; v < n; v++) {
                NSNumber *num = [NSNumber numberWithInt:(int)(n-1)-v];
                [V insertObject:num atIndex:v];
            }
        }
        
        int nv = (int)n;
        
        int count = 2*nv;
        
        for(int v = nv-1; nv > 2; ) {
    
            if (0 >= (count--)) {
                return result;
            }
            
            int u = v; if (nv <= u) u = 0;    // i - 1
            v = u+1; if (nv <= v) v = 0;      // i
            int w = v+1; if (nv <= w) w = 0;  // i + 1
            
            if ( [self Snip:contour :V :u :v :w :nv]) {
                int a,b,c;
                
                a = [V[u] intValue];
                b = [V[v] intValue];
                c = [V[w] intValue];
                
                // 把切下的三角形放入数组
                [result addObject:contour[a]];
                [result addObject:contour[b]];
                [result addObject:contour[c]];
                
                [V removeObjectAtIndex:v];
                nv--;
                
                count = 2*nv;
            }
        }
        return result;
    }
    
    1. 测试
    - (void)test
    {
        CGPoint a = CGPointMake(2, 2);
        NSValue *value1 = [NSValue valueWithCGPoint:a];
        CGPoint b = CGPointMake(2, -1);
        NSValue *value2 = [NSValue valueWithCGPoint:b];
        CGPoint c = CGPointMake(-1, -1);
        NSValue *value3 = [NSValue valueWithCGPoint:c];
        CGPoint d = CGPointMake(-1, 2);
        NSValue *value4 = [NSValue valueWithCGPoint:d];
        CGPoint e = CGPointMake(0, 2);
        NSValue *value5 = [NSValue valueWithCGPoint:e];
        CGPoint f = CGPointMake(0, 1);
        NSValue *value6 = [NSValue valueWithCGPoint:f];
        CGPoint g = CGPointMake(1, 1);
        NSValue *value7 = [NSValue valueWithCGPoint:g];
        CGPoint h = CGPointMake(1, 2);
        NSValue *value8 = [NSValue valueWithCGPoint:h];
    
        NSArray *vs = @[value1, value2, value3, value4, value5, value6, value7, value8];
    
        NSMutableArray *result = [NSMutableArray array];
        
        result = [Triangulate Process:vs];
        
        for (int i = 0; i < result.count/3; i++) {
    
            CGPoint p1 = [result[i*3+0] CGPointValue];
            CGPoint p2 = [result[i*3+1] CGPointValue];
            CGPoint p3 = [result[i*3+2] CGPointValue];
            
            NSLog(@"Triangle %d => (%0.0f, %0.0f) (%0.0f, %0.0f) (%0.0f, %0.0f)\n", i+1, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
        }
    }
    

    6.结果


    测试结果.png

    参考:
    http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml

    相关文章

      网友评论

          本文标题:不规则多边形三角切割法 OC版

          本文链接:https://www.haomeiwen.com/subject/hjtmsftx.html