Spline은 일정한 매개변수 구간
Catmull-Rom spline은 3차 다항식으로 써지는 uniform spline으로 각 knot 위치에서 주어진 값을 통과하므로 interpolation 함수이기도 한다. 그리고 1차 도함수가 연속성을 가지고 있고, knot의 위치 변화나 knot에서 주어진 값의 변화에 곡선이 민감하게 변하지 않는다. 그러나 2차원 이상에는 Catmull-Rom spline이 꼬이는 현상이 발생할 수 있고, 극단적으로는 cusp가 생기는 단점도 가지고 있다.
2차원 이상에서는 Catmull-Rom spline으로 주어진 점(벡터)들을 보간하는 곡선을 찾을 때 uniform이 아니면 knot을 정하는데 모호함이 존재한다. 보통은 순차적으로 주어진 입력점의 직선거리를 이용해서 knot을 정할 수 있는데 이 경우를 chordal Catmull-Rom spline이라고 한다.

주어진 입력점이
더 일반적으로
로 잡을 수 있는데 이 경우를 centripetal Catmull-Rom spline이라 하며 cusp를 피할 수 있다. 단, 입력점의 중복이 없도록 미리 제거되어야 한다. Spline
- 3차 함수로 쓰여져야 하고,
- 입력점 통과:
,S(t1)=P1 ,S(t2)=P2 - 기울기:
,S′(t1)=1t2−t0(P2−P0) S′(t2)=1t3−t1(P3−P1)
인 조건을 사용하면
ref: http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
Catmull-Rom Spline
두 개의 점이 주어지는 경우 이들을 잇는 가장 단순한 곡선은 직선이다. 또 직선은 두 점을 잇는 가장 짧은 거리를 갖는 곡선이기도 하다. 그러면
kipl.tistory.com

double GetParam(double t, double alpha, const CfPt& p0, const CfPt& p1 ) {
CfPt p = p1 - p0;
double dsq = p.x * p.x + p.y * p.y;
if (dsq == 0) return t;
return pow(a, alpha / 2) + t;
}
//centripetal catmull-rom spline;
CfPt CRSplineA(double t /*[0:1]*/,
const CfPt& p0,
const CfPt& p1,
const CfPt& p2,
const CfPt& p3, double alpha=.5 /*[0:1]*/)
{
double t0 = 0;
double t1 = GetParam( t0, alpha, p0, p1 );
double t2 = GetParam( t1, alpha, p1, p2 );
double t3 = GetParam( t2, alpha, p2, p3 );
t = t1 * (1 - t) + t2 * t;
CfPt A1 = t1==t0 ? p0: p0*(t1-t)/(t1-t0) + p1*(t-t0)/(t1-t0);
CfPt A2 = t2==t1 ? p1: p1*(t2-t)/(t2-t1) + p2*(t-t1)/(t2-t1);
CfPt A3 = t3==t2 ? p2: p2*(t3-t)/(t3-t2) + p3*(t-t2)/(t3-t2);
CfPt B1 = A1 * (t2-t)/(t2-t0) + A2 * (t-t0)/(t2-t0);
CfPt B2 = A2 * (t3-t)/(t3-t1) + A3 * (t-t1)/(t3-t1);
return B1 * (t2-t)/(t2-t1) + B2 * (t-t1)/(t2-t1);
}
void DrawCatmullRom(std::vector<CfPt>& Q, CDC *pDC) {
#define STEPS (20)
if (Q.size() < 4) return ;
CPen red(PS_SOLID, 2, RGB(255, 0, 0));
CPen *pOld = pDC->SelectObject(&red);
const int n = Q.size();
// centripetal Catmull-Rom spline;
for (int i = 0; i < n - 1; i++) {
pDC->MoveTo(Q[i]);
// i = 0 인 경우에는 처음 점을 반복, i = n - 2인 경우에는 마지막 점을 반복..
int ip = max(i - 1, 0);
int inn = min(i + 2, n - 1);
for (int it = 1; it <= STEPS; it++)
pDC->LineTo(CRSplineA(double(it)/STEPS, Q[ip], Q[i], Q[i + 1], Q[inn]));
};
pDC->SelectObject(pOld);
CPen blue(PS_SOLID, 2, RGB(0, 0, 255));
pOld = pDC->SelectObject(&blue);
// uniform Catmull-Rom spline;
for (int i = 0; i < n - 1; i++) {
pDC->MoveTo(Q[i]);
// i = 0 인 경우에는 처음 점을 반복, i = n - 2인 경우에는 마지막 점을 반복..
int ip = max(i - 1, 0);
int inn = min(i + 2, n - 1);
for (int it = 1; it <= STEPS; it++)
pDC->LineTo(CRSpline(double(it)/STEPS, Q[ip], Q[i], Q[i + 1], Q[inn]));
};
pDC->SelectObject(pOld);
}
'Computational Geometry' 카테고리의 다른 글
Natural Cubic Spline: revisited (0) | 2024.06.14 |
---|---|
Polygon Decimation (0) | 2024.06.08 |
Bezier curves (1) | 2024.04.19 |
Subdividing a Bezier Curve (0) | 2024.04.18 |
Derivatives of Bezier Curves (1) | 2024.04.12 |