How can I determine whether a 2D Point is within a Polygon?

前端 未结 30 2209
醉梦人生
醉梦人生 2020-11-21 05:06

I\'m trying to create a fast 2D point inside polygon algorithm, for use in hit-testing (e.g. Polygon.contains(p:Point)). Suggestions for effective tech

30条回答
  •  春和景丽
    2020-11-21 05:50

    Heres a point in polygon test in C that isn't using ray-casting. And it can work for overlapping areas (self intersections), see the use_holes argument.

    /* math lib (defined below) */
    static float dot_v2v2(const float a[2], const float b[2]);
    static float angle_signed_v2v2(const float v1[2], const float v2[2]);
    static void copy_v2_v2(float r[2], const float a[2]);
    
    /* intersection function */
    bool isect_point_poly_v2(const float pt[2], const float verts[][2], const unsigned int nr,
                             const bool use_holes)
    {
        /* we do the angle rule, define that all added angles should be about zero or (2 * PI) */
        float angletot = 0.0;
        float fp1[2], fp2[2];
        unsigned int i;
        const float *p1, *p2;
    
        p1 = verts[nr - 1];
    
        /* first vector */
        fp1[0] = p1[0] - pt[0];
        fp1[1] = p1[1] - pt[1];
    
        for (i = 0; i < nr; i++) {
            p2 = verts[i];
    
            /* second vector */
            fp2[0] = p2[0] - pt[0];
            fp2[1] = p2[1] - pt[1];
    
            /* dot and angle and cross */
            angletot += angle_signed_v2v2(fp1, fp2);
    
            /* circulate */
            copy_v2_v2(fp1, fp2);
            p1 = p2;
        }
    
        angletot = fabsf(angletot);
        if (use_holes) {
            const float nested = floorf((angletot / (float)(M_PI * 2.0)) + 0.00001f);
            angletot -= nested * (float)(M_PI * 2.0);
            return (angletot > 4.0f) != ((int)nested % 2);
        }
        else {
            return (angletot > 4.0f);
        }
    }
    
    /* math lib */
    
    static float dot_v2v2(const float a[2], const float b[2])
    {
        return a[0] * b[0] + a[1] * b[1];
    }
    
    static float angle_signed_v2v2(const float v1[2], const float v2[2])
    {
        const float perp_dot = (v1[1] * v2[0]) - (v1[0] * v2[1]);
        return atan2f(perp_dot, dot_v2v2(v1, v2));
    }
    
    static void copy_v2_v2(float r[2], const float a[2])
    {
        r[0] = a[0];
        r[1] = a[1];
    }
    

    Note: this is one of the less optimal methods since it includes a lot of calls to atan2f, but it may be of interest to developers reading this thread (in my tests its ~23x slower then using the line intersection method).

提交回复
热议问题