본문 바로가기
Computer Science

[C++] 볼록 껍질 클래스 구현

by invrtd.h 2022. 8. 7.

임의의 개수의 2차원 점을 input으로 받아, 볼록 껍질 객체를 만들어 주는 클래스이다.

using namespace std;

class Point {
public:
    long long x, y;
    Point(long long _x, long long _y) : x(_x), y(_y) {}
    Point operator-(const Point& rhs) const {
        return Point(x - rhs.x, y - rhs.y);
    }
    bool operator<(const Point& rhs) const {
        // return y / x < rhs.y / rhs.x
        if (y * rhs.x < x * rhs.y) {
            return true;
        } else if (y * rhs.x > x * rhs.y) {
            return false;
        } else {
            return x * x + y * y < rhs.x * rhs.x + rhs.y * rhs.y;
        }
    }
    bool operator==(const Point& rhs) const {
        return x == rhs.x && y == rhs.y;
    }
};

ostream& operator<<(ostream& os, const Point& p) {
    os << '(' << p.x << ' ' << p.y << ')';
    return os;
}

class ConvexHull {
    vector<Point> v;

    long long signed_area(const Point& v1, const Point& v2) const {
        // return det
        return v1.x * v2.y - v2.x * v1.y;
    }
    long long signed_area(const Point& a, const Point& b, const Point& c) const {
        // return det
        Point v1 = b - a, v2 = c - b;
        return v1.x * v2.y - v2.x * v1.y;
    }
    long long inner_product(const Point& v1, const Point& v2) const {
        return v1.x * v2.x + v1.y * v2.y;
    }
public:
    ConvexHull(vector<Point> ipv) {
        // Find the smallest Point (smallest x among the smallest y)
        Point minp = ipv[0];
        int min_idx = 0;
        for (int i = 1; i < ipv.size(); ++i) {
            if (minp.y > ipv[i].y || (minp.y == ipv[i].y && minp.x > ipv[i].x)) {
                minp = ipv[i];
                min_idx = i;
            }
        }

        swap(ipv[0], ipv[min_idx]);

        sort(ipv.begin() + 1, ipv.end(), [minp](const Point& lhs, const Point& rhs) -> bool {
            return lhs - minp < rhs - minp;
        });

        // Convex hull making
        v.push_back(ipv[0]);
        for (int i = 1; i < ipv.size(); ++i) {
            while (v.size() >= 2 && signed_area(v[v.size() - 2], v.back(), ipv[i]) <= 0) {
                v.pop_back();
            }
            v.push_back(ipv[i]);
        }
    }

    void print() const {
        for (int i = 0; i < v.size(); ++i) {
            cout << v[i] << endl;
        }
    }
    
    int size() const {
        return (int) v.size();
    }
};

댓글