monotone 폴리곤은 한 축 방향으로 꼭짓점의 좌표값이 단조 증가하는 형태를 갖는 단순 폴리곤이다. 단순 폴리곤을 monotone 폴리곤으로 분할하는 방법은 잘 알려져 있고 O(n log n)의 복잡도를 갖는다. monotone 폴리곤은 한 방향에 대해서 이미 정렬이 되어 있기 때문이 그 방향으로 sweep-line 기법을 쓰면 선형 시간 내에 triangulation이 가능하다. 이러한 알고리즘은 이미지 처리에 적용하면 매우 효율적으로 이용이 가능하다. raster 상의 데이터는 scanline 방향으로 항상 정렬이 되어 있기 때문이다.


참고 : http://www.personal.kent.edu/~rmuhamma/Compgeometry/MyCG/PolyPart/polyPartition.htm

Algorithm Monotone_Triangulation
Input: Monotone polygon P (ccw-ness needed!)
Output: Set of triangles
(1) 주어진 폴리곤의 꼭지점을 x-좌표를 기준으로 정렬하여 V에 저장 (O(n) due to monotonicity).
(2) sweep-line 리스트(L)을 초기화 :: V의 처음 두 포인트(이벤트)를 넣음.
(3) while(V is not empty) do
       get next vertex (p) from V ;
       if (p is opposite to points in L) then
            while(size(L)>1) do
                out triangle { first(L), second(L), p }
                remove(first(L))
            end while
            add p to L;
       else 
            while ( size(L)>1 && ccw(last(L), previous(last(L)), p)) do
                 out triangle { last(L), previous(last(L)), p }
                 remove(last(L))
            end while
            add p to L
       end if
     end while/*입력이 ccw이면 ccw-test도 ccw로, cw면 test도 cw로 해야한다.*/ 

/* 구현 코드(C++)의 일부이다.*/
struct endpoint {
    int     vid;                /* polygon vertex id */
    double* x;                  /* X coordinate of the endpoint */
    double* y;                  /* Y coordinate of the endpoint */
} ;
//x-크기순서대로--> y-크기순 서대로; (ascending-order);
static 
int point_compare(double* x1, double* y1, double* x2, double* y2) {
    if (*x1 > *x2) return  1;
    if (*x1 < *x2) return -1;
    if (*y1 > *y2) return  1;
    if (*y1 < *y2) return -1;
    return 0;
}
//qsort에서 사용;
static 
int endpoint_compare(const void* p1, const void* p2) {
    endpoint* e1 = *(endpoint**) p1;
    endpoint* e2 = *(endpoint**) p2;
    return point_compare(e1->x, e1->y, e2->x, e2->y);
}
//
class endpointqueue {
    int n;                      /* total number of endpoints */
    int next;                   /* index of next endpoint on queue */
    endpoint* data;             /* array of all endpoints */
    endpoint** sorted;          /* sorted list of endpoint pointers */
    bool create(int npoly, double polyx[], double polyy[]);
public:
    ~endpointqueue() {
        if(data) delete[] data ;
        if(sorted) delete[] sorted;
    }
    endpointqueue() : data(NULL), sorted(NULL), n(0), next(0) {}
    endpointqueue(int npoly, double polyx[], double polyy[]) {
        create(npoly, polyx, polyy);
    } ;
    endpoint * getnext() { return (next >= n) ? NULL : sorted[next++];}
} ;
bool endpointqueue::create(int n, double polyx[], double polyy[]) {
    data = new endpoint [n] ;
    this->n = n ;
    this->next = 0;
    for (int i = 0; i < n; i++) {
        data[i].x = &polyx[i] ;
        data[i].y = &polyy[i] ;
        data[i].vid = i;
    };
    sorted = new endpoint* [n] ;
    for (i = 0; i < n; i++) {
        sorted[i] = &data[i];
    };
    //non-optimal sorting; use monotonicity of input;
    qsort(sorted, n, sizeof(endpoint*), endpoint_compare);
    return true ;
}
//deque의 행동을 재정의할 필요가 있음.

struct sweepline {
    int     n;                      /* number of vertices in polygon */
    endpoint* deque;
    int bot, top;
    sweepline() : n(0), deque(NULL) {}
    sweepline(int n_) {
        n = n_; bot = -1; top = -1; 
        deque = new endpoint [n] ;
    }
    ~sweepline(){ if(deque) delete [] deque;}
    endpoint* add(endpoint* e) ;
    void removefirst() { if (bot < top) bot++;} //safe::size()>1
    void removelast() { if (top > bot) top--;}  //safe::size()>1;
    int size() { if (top >= 0 && bot >= 0 && top >= bot) return top - bot + 1; else return 0;}
    endpoint* getlast()     { ASSERT(size() > 0); return &deque[top];}
    endpoint* getprelast()  { ASSERT(size() > 1); return &deque[top - 1];}
    endpoint* getfirst()    { ASSERT(size() > 0); return &deque[bot  ];}
    endpoint* getsecond()   { ASSERT(size() > 1); return &deque[bot + 1];}
    bool opposite(endpoint* e) ;
    void draw(CDC *pDC, DWORD color = RGB(0xFF, 0, 0)) ;
};
endpoint* sweepline::add(endpoint* e) {
    if (bot == -1 && top == -1) //first adding;
        bot = 0;
    top++;
    deque[top].x = e->x ;
    deque[top].y = e->y ;
    deque[top].vid = e->vid ;
    return &deque[top];
}
bool sweepline::opposite(endpoint* e) {
    if (e->vid == ((deque[top].vid + 1) % this->n))
        return false;
    else
        return true ;
}
void monotone_triangulate(CPoint P[], int n, 
                          void (*print_triangle)(int a, int b, int c)) {
    double *polyx = new double [n] ;
    double *polyy = new double [n] ;
    for (int i = 0; i < n; i++) {
        polyx[i] = P[i].x;
        polyy[i] = P[i].y;
    };
    //
    endpointqueue eq(n, polyx, polyy);
    sweepline sl(n);
    endpoint *e ;
    sl.add(eq.getnext());
    sl.add(eq.getnext());
    while ((e = eq.getnext())) {
        TRACE("event=%d(x=%5.0f, y=%5.0f)\n", e->vid, *e->x, *e->y);
        if (sl.opposite(e)) {
            while (sl.size() > 1) {
                //(first, second, p);
                print_triangle(sl.getfirst()->vid, sl.getsecond()->vid, e->vid);
                sl.removefirst();
            }
            sl.add(e);
        } else {
            while (sl.size() > 1 && isccw(sl.getlast(), sl.getprelast(), e)) {
                //triangle(last, previous(last), p);
                print_triangle(sl.getlast()->vid, sl.getprelast()->vid, e->vid);
                sl.removelast();
            }
            sl.add(e);
        }
    }
    //
    delete [] polyx;
    delete [] polyy;
};

/*
**  http://blog.naver.com/helloktk/80051120809 에서 옮김.
*/

728x90

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

Polygon Fill  (0) 2008.05.22
Fortune's Sweep Algorithm  (0) 2008.05.22
Trapezoidalization  (0) 2008.05.22
Optimizing Polygon Triangulation  (0) 2008.05.22
Sweep Line Algorithm  (0) 2008.05.22
Posted by helloktk
,

단순 폴리곤을 사다리꼴로 분해하는 알고리즘이다(삼각형은 평행한 변 중에 하나의 길이가 0인 것으로 취급한다). 이 알고리즘은 복잡한 폴리곤을 한 방향으로 정렬된 보다 단순한 형태로 바꾸어, 효율적인 알고리즘의 디자인과 적용이 가능하게 한다. 이 역시 sweep-line 알고리즘을 이용한다.

(1) 폴리곤의 꼭짓점들을 y-값(or x) 값으로 크기순 서로 정렬한다.

(2) sweep-line L이 정렬된 각각의 꼭짓점을 스캔한다.

(3) 각각의 꼭짓점에서 폴리곤 내부에 들어가는 최대의 평행 세그먼트를 계산한다.
    (녹색과 붉은색(붉은색은 꼭짓점이 세그먼트 중간에 있는 것을 표시함))

** 알고리즘 복잡도 : O(n log n)

사용자 삽입 이미지

붉은색 세그먼트에 포함된 꼭지점에서 위/아래의 세그먼트의 꼭짓점으로 대각선을 그을 수가 있는데, 이 대각선을 이용하면 폴리곤을 monotonic(y방향)한 분리가 가능하다.
**관련 자료: www.cs.jhu.edu/~misha/Spring16/04.pdf
/**
** http://blog.naver.com/helloktk/80051167220 에서 옮김.
*/

728x90

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

Polygon Fill  (0) 2008.05.22
Fortune's Sweep Algorithm  (0) 2008.05.22
Triangulating Monotone Polygon  (0) 2008.05.22
Optimizing Polygon Triangulation  (0) 2008.05.22
Sweep Line Algorithm  (0) 2008.05.22
Posted by helloktk
,

다각형을 삼각 분할하다 보면 일부 삼각형 중에는 한 변의 길이가 나머지 변의 길이에 비해서 매우 작거나 또는 매우 큰 경우가 많이 나타난다. (이런 경우에 외접원의 반지름이 매우 커진다). 삼각 분할에서 만들어진 삼각형을 이용하여 mesh을 형성할 경우에 분할된 삼각형이 보다 균일한  경우가 더 좋을 것이다.

균일한 삼각 분할을 만들기 위해서 이미 완성된 분할 결과를 가지고 다시 수정 작업을 거쳐야 한다. 삼각 분할 결과로 나타난 각 내부 edge(AC, diagonal)에 대해서 그 edge가 대각선이 되는 사각형(ABCD)을 찾고, 이 사각형이 convex인 경우에 한하여 아래의 과정을 적용한다.

  1. 사각형 ABCD를 분할하는 두 개의 삼각형 ABC, ACD의 외접원의 반지름의 최솟값을 찾는다.
    min(radius(ABC), radius(ACD))
  2. 사각형 ABCD에서 원래 대각선(AC)과 교차하는 대각선(BD)이 나누는 두 개의 삼각형 BCD, BDA의 외접원의 반지름의 최솟값을 찾는다. 
    min(radius(BCD) and radius(BDA))
  3. 원래 대각선(AC)이 나누는 삼각형 외접원의 최소 반지름이 교차 대각선(BD)이 나누는 삼각형의 최소 반지름보다 더 작은 경우 이 대각선을 기존의 edge(AC)와 바꾼다. (바꾼 edge는 더 이상 바꾸지 않는다)
  4. 다른 내부 edge에 대해서 동일한 과정을 반복한다.

** 내부 edge의  FLIP;

사용자 삽입 이미지

 

** 원래의 삼각화(Ear Clipping)

사용자 삽입 이미지

**최적화 후

사용자 삽입 이미지

 


/**
** http://blog.naver.com/helloktk/80051332733 에서 옮김.
*/

728x90

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

Polygon Fill  (0) 2008.05.22
Fortune's Sweep Algorithm  (0) 2008.05.22
Triangulating Monotone Polygon  (0) 2008.05.22
Trapezoidalization  (0) 2008.05.22
Sweep Line Algorithm  (0) 2008.05.22
Posted by helloktk
,

(1) closest pair in the planar point set
     * brute force : O(n^2) --> O(n log n), see also divide and conquer algorithm.
     * ref : http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html 

사용자 삽입 이미지

(2) simplicity of polygon :

Shamos-Hoey Algorithm

 

 

 

사용자 삽입 이미지

(3) voronoi diagram :Fortune algorithm


 

 

사용자 삽입 이미지

(4) segment intersection : Bentley-Ottmann Algorithm

      * 파란색 점 : sweep-line과 교차하는 세그먼트들 간의(붉은색으로 표시)의 교차점으로(before sweep-line)로 point 이벤트 큐에 들어간다.
      * 청록색 점 : sweep-line이 지나간 후의 교차점.

사용자 삽입 이미지

sweep-line알고리즘을 구현하는데서 스텝별로 쪼개서 구현하려고 하니 조금 귀찮은 작업들이 많아진다 (DC에 그려지는 것을 자동으로 저장하는 부분을 만들어서 매 스텝마다 캡처하는 작업은 줄였다). 그러나 근본적인 문제는 입력되는 데이터에 degeneracy가 있는 경우다. 이것 때문에 가장 기본적인 세그먼트 intersection 부분부터 다시 살펴보아야 했다.

/**
** http://blog.naver.com/helloktk/80051980882 에서 옮긴 글.
*/

 

728x90

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

Polygon Fill  (0) 2008.05.22
Fortune's Sweep Algorithm  (0) 2008.05.22
Triangulating Monotone Polygon  (0) 2008.05.22
Trapezoidalization  (0) 2008.05.22
Optimizing Polygon Triangulation  (0) 2008.05.22
Posted by helloktk
,