예제 #1
0
void
Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
	double rx, lx, hx, max_x, min_x;
	int32_t i;
	int32_t original_veclen;
	int32_t npoints;

	if (veclen == 0) {
		return;
	}

	if ((npoints = _list.events().size()) == 0) {
		/* no events in list, so just fill the entire array with the default value */
		for (int32_t i = 0; i < veclen; ++i) {
			vec[i] = _list.default_value();
		}
		return;
	}

	if (npoints == 1) {
		for (int32_t i = 0; i < veclen; ++i) {
			vec[i] = _list.events().front()->value;
		}
		return;
	}

	/* events is now known not to be empty */

	max_x = _list.events().back()->when;
	min_x = _list.events().front()->when;

	if (x0 > max_x) {
		/* totally past the end - just fill the entire array with the final value */
		for (int32_t i = 0; i < veclen; ++i) {
			vec[i] = _list.events().back()->value;
		}
		return;
	}

	if (x1 < min_x) {
		/* totally before the first event - fill the entire array with
		 * the initial value.
		 */
		for (int32_t i = 0; i < veclen; ++i) {
			vec[i] = _list.events().front()->value;
		}
		return;
	}

	original_veclen = veclen;

	if (x0 < min_x) {

		/* fill some beginning section of the array with the
		   initial (used to be default) value
		*/

		double frac = (min_x - x0) / (x1 - x0);
		int64_t fill_len = (int64_t) floor (veclen * frac);

		fill_len = min (fill_len, (int64_t)veclen);

		for (i = 0; i < fill_len; ++i) {
			vec[i] = _list.events().front()->value;
		}

		veclen -= fill_len;
		vec += fill_len;
	}

	if (veclen && x1 > max_x) {

		/* fill some end section of the array with the default or final value */

		double frac = (x1 - max_x) / (x1 - x0);
		int64_t fill_len = (int64_t) floor (original_veclen * frac);
		float val;

		fill_len = min (fill_len, (int64_t)veclen);
		val = _list.events().back()->value;

		for (i = veclen - fill_len; i < veclen; ++i) {
			vec[i] = val;
		}

		veclen -= fill_len;
	}

	lx = max (min_x, x0);
	hx = min (max_x, x1);

	if (npoints == 2) {

		/* linear interpolation between 2 points */

		/* XXX: this numerator / denominator stuff is pretty grim, but it's the only
		   way I could get the maths to be accurate; doing everything with pure doubles
		   gives ~1e-17 errors in the vec[i] computation.
		*/

		/* gradient of the line */
		double const m_num = _list.events().back()->value - _list.events().front()->value;
		double const m_den = _list.events().back()->when - _list.events().front()->when;

		/* y intercept of the line */
		double const c = double (_list.events().back()->value) - (m_num * _list.events().back()->when / m_den);

		/* dx that we are using */
		double dx_num = 0;
		double dx_den = 1;
		if (veclen > 1) {
			dx_num = hx - lx;
			dx_den = veclen - 1;
			for (int i = 0; i < veclen; ++i) {
				vec[i] = (lx * (m_num / m_den) + m_num * i * dx_num / (m_den * dx_den)) + c;
			}
		} else {
			vec[0] = lx * (m_num / m_den) + c;
		}

		return;
	}

	if (_dirty) {
		solve ();
	}

	rx = lx;

	double dx = 0;
	if (veclen > 1) {
		dx = (hx - lx) / (veclen - 1);
	}

	for (i = 0; i < veclen; ++i, rx += dx) {
		vec[i] = multipoint_eval (rx);
	}
}
예제 #2
0
void
Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
	double rx, dx, lx, hx, max_x, min_x;
	int32_t i;
	int32_t original_veclen;
	int32_t npoints;

	if ((npoints = _list.events().size()) == 0) {
		for (i = 0; i < veclen; ++i) {
			vec[i] = _list.default_value();
		}
		return;
	}

	/* events is now known not to be empty */

	max_x = _list.events().back()->when;
	min_x = _list.events().front()->when;

	lx = max (min_x, x0);

	if (x1 < 0) {
		x1 = _list.events().back()->when;
	}

	hx = min (max_x, x1);

	original_veclen = veclen;

	if (x0 < min_x) {

		/* fill some beginning section of the array with the
		   initial (used to be default) value
		*/

		double frac = (min_x - x0) / (x1 - x0);
		int32_t subveclen = (int32_t) floor (veclen * frac);

		subveclen = min (subveclen, veclen);

		for (i = 0; i < subveclen; ++i) {
			vec[i] = _list.events().front()->value;
		}

		veclen -= subveclen;
		vec += subveclen;
	}

	if (veclen && x1 > max_x) {

		/* fill some end section of the array with the default or final value */

		double frac = (x1 - max_x) / (x1 - x0);

		int32_t subveclen = (int32_t) floor (original_veclen * frac);

		float val;

		subveclen = min (subveclen, veclen);

		val = _list.events().back()->value;

		i = veclen - subveclen;

		for (i = veclen - subveclen; i < veclen; ++i) {
			vec[i] = val;
		}

		veclen -= subveclen;
	}

	if (veclen == 0) {
		return;
	}

	if (npoints == 1) {

		for (i = 0; i < veclen; ++i) {
			vec[i] = _list.events().front()->value;
		}
		return;
	}


	if (npoints == 2) {

		/* linear interpolation between 2 points */

		/* XXX I'm not sure that this is the right thing to
		   do here. but its not a common case for the envisaged
		   uses.
		*/

		if (veclen > 1) {
			dx = (hx - lx) / (veclen - 1) ;
		} else {
			dx = 0; // not used
		}

		double slope = (_list.events().back()->value - _list.events().front()->value)/
			(_list.events().back()->when - _list.events().front()->when);
		double yfrac = dx*slope;

		vec[0] = _list.events().front()->value + slope * (lx - _list.events().front()->when);

		for (i = 1; i < veclen; ++i) {
			vec[i] = vec[i-1] + yfrac;
		}

		return;
	}

	if (_dirty) {
		solve ();
	}

	rx = lx;

	if (veclen > 1) {
		dx = (hx - lx) / (veclen - 1);
	} else {
		dx = 0;
	}

	for (i = 0; i < veclen; ++i, rx += dx) {
		vec[i] = multipoint_eval (rx);
	}
}