빠르고 정확한 방법이지만 제약 사항들이 있습니다.
1. 주어진 샘플들 중에서 두번째 샘플값이 가장 커야 한다. (위로 볼록한형태임. 반대를 원하면 부호를 뒤집어 인자로 전달하면 되겠죠)
2. 정확한 최대값의 x위치를 찾는게 목적이지 y값을 구하는게 목적이 아니다. (y값을 원한다면 수정하면 됩니다)
3. 2차 방정식을 미분한 형태이기때문에, 4개의 점 이상(3차 이상 방정식)으로 확장은 고려되어 있지 않다.
4. 등 간격 샘플을 가정해 속도를 최적화한 경우이기 때문에, 간격이 다를 경우엔 두번째 샘플의 우측인지 좌측인지만 알 수 있다.
구현은 두 가지 함수로 나누어 두었습니다.
하나는 주어진 샘플(점) 들이 유효한가를 점검하는 함수, 하나는 주어진 두번째 샘플(가장 큰 값)로 부터 실제 최대값이
좌 우측 샘플과 어느정도 거리에 있는지를 (0 ~ -1, 0 ~ 1) 알려주는 함수입니다.
실제 두 번째 인자가 가장 큰 인자라면, 최대값이 두 번째 인자로부터 -0.5 <= offsetX <= + 0.5 범위에 있게 되기
때문에 그 외의 결과값은 유효하지 않은 경우입니다.
하나로 통합해도 간단한 함수이지만, 무진장 빠른 응답을 요구하는 경우를 반영해 나누어둔 형태죠.
enum ErrorCodeParabolic
{
ecpOK,
ecpNotMaxY1,
ecpTooFar
};
ErrorCodeParabolic isErrorParabolicMaxOffsetX(double y0, double y1, double y2)
{
double a = y0 + y2 - y1 * 2;
if (a >= 0) return ecpNotMaxY1;
double c = 0.5 * (y0 - y2) / a;
if (c < -0.5 || c > 0.5) return ecpTooFar;
return ecpOK;
}
//---------------------------------------------------------------------------
double parabolicMaxOffsetX(double y0, double y1, double y2)
{
double d = y0 + y2 - y1 * 2;
if (d >= 0) return 0;
return (0.5 * (y0 - y2) / d);
}
사용은 이런식으로 합니다.
maxX = parabolicMaxOffsetX(y0, y1, y2) + x1;
이는 x0, x1, x2가 각각 1의 간격으로 보았을때 이고, 간격이 1이 아니라면,
maxX = parabolicMaxOffsetX(y0, y1, y2) * (x1 - x0) + x1; 처럼 사용하시면 됩니다.
위에 언급했듯, 인자의 무결성 체크가 필요 없다면,
double parabolicMaxOffsetX(double y0, double y1, double y2)
함수만 작성하시고 사용하시면 됩니다.