Sort points by angle from given axis?

前端 未结 8 2825
無奈伤痛
無奈伤痛 2021-02-19 12:11

How can I sort an array of points/vectors by counter-clockwise increasing angle from a given axis vector?

For example:

8条回答
  •  走了就别回头了
    2021-02-19 12:15

    Yes, you can do it with a custom comparator based on the cross-product. The only problem is that a naive comparator won't have the transitivity property. So an extra step is needed, to prevent angles either side of the reference from being considered close.

    This will be MUCH faster than anything involving trig. There's not even any need to normalize first.

    Here's the comparator:

    class angle_sort
    {
        point m_origin;
        point m_dreference;
    
        // z-coordinate of cross-product, aka determinant
        static double xp(point a, point b) { return a.x * b.y - a.y * b.x; }
    public:
        angle_sort(const point origin, const point reference) : m_origin(origin), m_dreference(reference - origin) {}
        bool operator()(const point a, const point b) const
        {
            const point da = a - m_origin, db = b - m_origin;
            const double detb = xp(m_dreference, db);
    
            // nothing is less than zero degrees
            if (detb == 0 && db.x * m_dreference.x + db.y * m_dreference.y >= 0) return false;
    
            const double deta = xp(m_dreference, da);
    
            // zero degrees is less than anything else
            if (deta == 0 && da.x * m_dreference.x + da.y * m_dreference.y >= 0) return true;
    
            if (deta * detb >= 0) {
                // both on same side of reference, compare to each other
                return xp(da, db) > 0;
            }
    
            // vectors "less than" zero degrees are actually large, near 2 pi
            return deta > 0;
        }
    };
    

    Demo: http://ideone.com/YjmaN

提交回复
热议问题