/** getIndexNearXY: return index of point within (or closest too) x +- dx which is closest to y **/ int Curve::getIndexNearXY(double x, double dx_per_pix, double y) const { VectorPtr xv = *_inputVectors.find(XVECTOR); VectorPtr yv = *_inputVectors.find(YVECTOR); if (!xv || !yv) { return 0; // anything better we can do? } double xi, yi, dx, dxi, dy, dyi; bool first = true; int i,i0, iN, index; int sc = sampleCount(); if (xv->isRising()) { iN = i0 = indexNearX(x, xv, NS); xi = xv->interpolate(i0, NS); while (i0 > 0 && x-dx_per_pix < xi) { xi = xv->interpolate(--i0, NS); } xi = xv->interpolate(iN, NS); while (iN < sc-1 && x+dx_per_pix > xi) { xi = xv->interpolate(++iN, NS); } } else { i0 = 0; iN = sampleCount()-1; } index = i0; xi = xv->interpolate(index, NS); yi = yv->interpolate(index, NS); dx = fabs(x - xi); dy = fabs(y - yi); for (i = i0 + 1; i <= iN; i++) { xi = xv->interpolate(i, NS); dxi = fabs(x - xi); if (dxi < dx_per_pix) { dx = dxi; yi = yv->interpolate(i, NS); dyi = fabs(y - yi); if (first || dyi < dy) { first = false; index = i; dy = dyi; } } else if (dxi < dx) { dx = dxi; index = i; } } return index; }
inline int indexNearX(double x, VectorPtr& xv, int NS) { // monotonically rising: we can do a binary search // should be reasonably fast if (xv->isRising()) { int i_top = NS - 1; int i_bot = 0; // don't pre-check for x outside of the curve since this is not // the common case. It will be correct - just slightly slower... while (i_bot + 1 < i_top) { int i0 = (i_top + i_bot)/2; double rX = xv->interpolate(i0, NS); if (x < rX) { i_top = i0; } else { i_bot = i0; } } double xt = xv->interpolate(i_top, NS); double xb = xv->interpolate(i_bot, NS); if (xt - x < x - xb) { return i_top; } else { return i_bot; } } else { // Oh Oh... not monotonically rising - we have to search the entire curve! // May be unbearably slow for large vectors double rX = xv->interpolate(0, NS); double dx0 = fabs(x - rX); int i0 = 0; for (int i = 1; i < NS; ++i) { rX = xv->interpolate(i, NS); double dx = fabs(x - rX); if (dx < dx0) { dx0 = dx; i0 = i; } } return i0; } }