기하 알고리즘을 특히 폴리곤 관련 알고리즘을 테스트하기 위해서는 폴리곤 데이터를 만들어야 한다. 여기서 2차원의 점들을 이용하여 간단히 simple polygon을 만드는 방법을 소개한다.

 

Simple polygon을 만들기 위해서는 점들을 정렬을 해야 한다. 각 점들을 $x$ 축으로 정사영하면 $x$축 방향에 대해 정렬이 된다(같은 $x$ 값인 경우에는 $y$의 크기대로 정렬). 따라서 x 값으로 정렬된 점들을 순차적으로 연결하면 하나의 polyline을 만들 수 있다. polyline의 끝을 잇는다고 해서 simple polygon이 항상 만들어지지는 않는다. 이를 해결하기 위해서는 점들을  한 직선을 기준으로 위-아래로 분리하고, 직선의 윗부분은 $x$ 값이 큰 순서대로 정렬을 하고, 아래 부분은 $x$ 값이 작은 순서대로 정열을 하면 폴리 라인이 아닌 simple polygon을 얻을 수 있다. 직선은 어떻게 잡을까? 이것은 가장 작은 $x$ 값을 갖는 점과 가장 큰 $x$ 값을 같은 점을 잇는 직선을 생각하면 편리하다.

// cross(CB, AB)
// A->B-C: 반시계(C가 AB 왼편: > 0), 시계(C가 AB오른편: < 0), 일직선(0);
int CCW(const CPoint& A, const CPoint& B, const CPoint& C) {
    const CPoint CB = C - B, AB = A - B;
    return CB.x * AB.y - CB.y * AB.x;
}
// x가 커지는(같으면 y가 커지는) 순서로 정렬;
bool compare(const CPoint &a, const CPoint& b) {
    if (a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}
std::vector<CPoint> makeSimplePolygon(const std::vector<CPoint>& pts) {
    if (pts.size() < 1) return std::vector<CPoint> (); //null_vector;
    int rightId = 0, leftId = 0;
    for (int i = pts.size(); i-->1;) {
        if (pts[i].x > pts[rightId].x) rightId = i;
        if (pts[i].x < pts[leftId].x) leftId = i;
    }
    std::vector<CPoint> LP, RP;
    for (int i = 0; i < pts.size(); i++) {
        if (i == rightId || i == leftId) continue;
        // 기준선의 왼편(LP)/오른편(RP)에 놓인 점 분리;
        if (CCW(pts[leftId], pts[rightId], pts[i]) >= 0) LP.push_back(pts[i]); 
        else RP.push_back(pts[i]);
    }
    if (LP.size() > 0) std::sort(LP.begin(), LP.end(), compare);
    if (RP.size() > 0) std::sort(RP.begin(), RP.end(), compare);
	
    std::vector<CPoint> sploy;
    spoly.reserve(LP.size()+RP.size()+2);
    spoly.push_back(pts[leftId]);
    for (int i = 0; i < LP.size(); i++) spoly.push_back(LP[i]);
    spoly.push_back(pts[rightId]);
    for (int i = RP.size(); i-->0;) spoly.push_back(RP[i]);
    // spoly = clockwise simple polygon;
    return spoly;
};

다른 방법으로는 위와 같은 직선을 만들고, 아랫부분의 점들의 convex hull을 구성하고, 나머지 점들을 마찬가지의 방법으로 정렬을 하여 폴리곤을 만들거나, 아니면 한 점을 잡아서(맨 아래 오른쪽) 그 점을 기준으로 해서 나머지 점들을 각도에 대해서 정렬을 한 다음 그 정렬된 순서대로 폴리곤을 구성하면 된다.

기준점에 대한 각도를 정렬하여서 만든 예(동일한 각도가 생기는 경우에는 기준점에서의 거리로 비교)

**네이버 블로그에서 이전;

728x90

'Computational Geometry' 카테고리의 다른 글

Minimum Bounding Rectangle  (3) 2021.03.15
Minimum Enclosing Circle  (0) 2021.03.01
단순 다각형의 Convex Hull  (0) 2021.01.24
단순 다각형의 무게중심  (0) 2021.01.24
단순 다각형의 면적(2D)  (0) 2021.01.23
Posted by helloktk
,