void stp_curve_reverse(stp_curve_t *dest, const stp_curve_t *source) { CHECK_CURVE(dest); CHECK_CURVE(source); curve_dtor(dest); dest->curve_type = source->curve_type; dest->wrap_mode = source->wrap_mode; dest->gamma = source->gamma; if (source->piecewise) { const double *source_data; size_t size; double *new_data; int i; stp_sequence_get_data(source->seq, &size, &source_data); new_data = stp_malloc(sizeof(double) * size); for (i = 0; i < size; i += 2) { int j = size - i - 2; new_data[i] = 1.0 - source_data[j]; new_data[i + 1] = source_data[j + 1]; } dest->seq = stp_sequence_create(); stp_sequence_set_data(dest->seq, size, new_data); stp_free(new_data); } else dest->seq = stp_sequence_create_reverse(source->seq); dest->piecewise = source->piecewise; dest->recompute_interval = 1; }
int stp_curve_set_subrange(stp_curve_t *curve, const stp_curve_t *range, size_t start) { double blo, bhi; double rlo, rhi; const double *data; size_t count; CHECK_CURVE(curve); if (start + stp_curve_count_points(range) > stp_curve_count_points(curve)) return 0; if (curve->piecewise) return 0; stp_sequence_get_bounds(curve->seq, &blo, &bhi); stp_sequence_get_range(curve->seq, &rlo, &rhi); if (rlo < blo || rhi > bhi) return 0; stp_sequence_get_data(range->seq, &count, &data); curve->recompute_interval = 1; curve->gamma = 0.0; invalidate_auxiliary_data(curve); stp_sequence_set_subrange(curve->seq, start, stp_curve_count_points(range), data); return 1; }
static void compute_linear_deltas(stp_curve_t *curve) { int i; size_t delta_count; size_t seq_point_count; const double *data; stp_sequence_get_data(curve->seq, &seq_point_count, &data); if (data == NULL) return; delta_count = get_real_point_count(curve); if (delta_count <= 1) /* No intervals can be computed */ return; delta_count--; /* One less than the real point count. Note size_t is unsigned. */ curve->interval = stp_malloc(sizeof(double) * delta_count); for (i = 0; i < delta_count; i++) { if (curve->piecewise) curve->interval[i] = data[(2 * (i + 1)) + 1] - data[(2 * i) + 1]; else curve->interval[i] = data[i + 1] - data[i]; } }
static const double * stpi_curve_get_data_internal(const stp_curve_t *curve, size_t *count) { const double *ret; CHECK_CURVE(curve); stp_sequence_get_data(curve->seq, count, &ret); *count = get_point_count(curve); if (curve->piecewise) *count *= 2; return ret; }
const stp_curve_point_t * stp_curve_get_data_points(const stp_curve_t *curve, size_t *count) { const double *ret; CHECK_CURVE(curve); if (!curve->piecewise) return NULL; stp_sequence_get_data(curve->seq, count, &ret); *count = get_point_count(curve); return (const stp_curve_point_t *) ret; }
int stp_curve_rescale(stp_curve_t *curve, double scale, stp_curve_compose_t mode, stp_curve_bounds_t bounds_mode) { int i; double nblo; double nbhi; size_t count; CHECK_CURVE(curve); stp_sequence_get_bounds(curve->seq, &nblo, &nbhi); if (bounds_mode == STP_CURVE_BOUNDS_RESCALE) { switch (mode) { case STP_CURVE_COMPOSE_ADD: nblo += scale; nbhi += scale; break; case STP_CURVE_COMPOSE_MULTIPLY: if (scale < 0) { double tmp = nblo * scale; nblo = nbhi * scale; nbhi = tmp; } else { nblo *= scale; nbhi *= scale; } break; case STP_CURVE_COMPOSE_EXPONENTIATE: if (scale == 0.0) return 0; if (nblo < 0) return 0; nblo = pow(nblo, scale); nbhi = pow(nbhi, scale); break; default: return 0; } } if (! isfinite(nbhi) || ! isfinite(nblo)) return 0; count = get_point_count(curve); if (count) { double *tmp; size_t scount; int stride = 1; int offset = 0; const double *data; if (curve->piecewise) { stride = 2; offset = 1; } stp_sequence_get_data(curve->seq, &scount, &data); tmp = stp_malloc(sizeof(double) * scount); memcpy(tmp, data, scount * sizeof(double)); for (i = offset; i < scount; i += stride) { switch (mode) { case STP_CURVE_COMPOSE_ADD: tmp[i] = tmp[i] + scale; break; case STP_CURVE_COMPOSE_MULTIPLY: tmp[i] = tmp[i] * scale; break; case STP_CURVE_COMPOSE_EXPONENTIATE: tmp[i] = pow(tmp[i], scale); break; } if (tmp[i] > nbhi || tmp[i] < nblo) { if (bounds_mode == STP_CURVE_BOUNDS_ERROR) { stp_free(tmp); return(0); } else if (tmp[i] > nbhi) tmp[i] = nbhi; else tmp[i] = nblo; } } stp_sequence_set_bounds(curve->seq, nblo, nbhi); curve->gamma = 0.0; stpi_curve_set_points(curve, count); stp_sequence_set_subrange(curve->seq, 0, scount, tmp); stp_free(tmp); curve->recompute_interval = 1; invalidate_auxiliary_data(curve); } return 1; }
static void compute_spline_deltas_dense(stp_curve_t *curve) { int i; int k; double *u; double *y2; const double *y; size_t point_count; size_t real_point_count; double sig; double p; point_count = get_point_count(curve); stp_sequence_get_data(curve->seq, &real_point_count, &y); u = stp_malloc(sizeof(double) * real_point_count); y2 = stp_malloc(sizeof(double) * real_point_count); if (curve->wrap_mode == STP_CURVE_WRAP_AROUND) { int reps = 3; int count = reps * real_point_count; double *y2a = stp_malloc(sizeof(double) * count); double *ua = stp_malloc(sizeof(double) * count); y2a[0] = 0.0; ua[0] = 0.0; for (i = 1; i < count - 1; i++) { int im1 = (i - 1); int ip1 = (i + 1); int im1a = im1 % point_count; int ia = i % point_count; int ip1a = ip1 % point_count; sig = (i - im1) / (ip1 - im1); p = sig * y2a[im1] + 2.0; y2a[i] = (sig - 1.0) / p; ua[i] = y[ip1a] - 2 * y[ia] + y[im1a]; ua[i] = 3.0 * ua[i] - sig * ua[im1] / p; } y2a[count - 1] = 0.0; for (k = count - 2 ; k >= 0; k--) y2a[k] = y2a[k] * y2a[k + 1] + ua[k]; memcpy(u, ua + ((reps / 2) * point_count), sizeof(double) * real_point_count); memcpy(y2, y2a + ((reps / 2) * point_count), sizeof(double) * real_point_count); stp_free(y2a); stp_free(ua); } else { int count = real_point_count - 1; y2[0] = 0; u[0] = 2 * (y[1] - y[0]); for (i = 1; i < count; i++) { int im1 = (i - 1); int ip1 = (i + 1); sig = (i - im1) / (ip1 - im1); p = sig * y2[im1] + 2.0; y2[i] = (sig - 1.0) / p; u[i] = y[ip1] - 2 * y[i] + y[im1]; u[i] = 3.0 * u[i] - sig * u[im1] / p; } u[count] = 2 * (y[count] - y[count - 1]); y2[count] = 0.0; u[count] = 0.0; for (k = real_point_count - 2; k >= 0; k--) y2[k] = y2[k] * y2[k + 1] + u[k]; } curve->interval = y2; stp_free(u); }
static void compute_spline_deltas_piecewise(stp_curve_t *curve) { int i; int k; double *u; double *y2; const double *data = NULL; const stp_curve_point_t *dp; size_t point_count; size_t real_point_count; double sig; double p; point_count = get_point_count(curve); stp_sequence_get_data(curve->seq, &real_point_count, &data); dp = (const stp_curve_point_t *)data; real_point_count = real_point_count / 2; u = stp_malloc(sizeof(double) * real_point_count); y2 = stp_malloc(sizeof(double) * real_point_count); if (curve->wrap_mode == STP_CURVE_WRAP_AROUND) { int reps = 3; int count = reps * real_point_count; double *y2a = stp_malloc(sizeof(double) * count); double *ua = stp_malloc(sizeof(double) * count); y2a[0] = 0.0; ua[0] = 0.0; for (i = 1; i < count - 1; i++) { int im1 = (i - 1) % point_count; int ia = i % point_count; int ip1 = (i + 1) % point_count; sig = (dp[ia].x - dp[im1].x) / (dp[ip1].x - dp[im1].x); p = sig * y2a[im1] + 2.0; y2a[i] = (sig - 1.0) / p; ua[i] = ((dp[ip1].y - dp[ia].y) / (dp[ip1].x - dp[ia].x)) - ((dp[ia].y - dp[im1].y) / (dp[ia].x - dp[im1].x)); ua[i] = (((6.0 * ua[ia]) / (dp[ip1].x - dp[im1].x)) - (sig * ua[im1])) / p; } y2a[count - 1] = 0.0; for (k = count - 2 ; k >= 0; k--) y2a[k] = y2a[k] * y2a[k + 1] + ua[k]; memcpy(u, ua + ((reps / 2) * point_count), sizeof(double) * real_point_count); memcpy(y2, y2a + ((reps / 2) * point_count), sizeof(double) * real_point_count); stp_free(y2a); stp_free(ua); } else { int count = real_point_count - 1; y2[0] = 0; u[0] = 2 * (dp[1].y - dp[0].y); for (i = 1; i < count; i++) { int im1 = (i - 1); int ip1 = (i + 1); sig = (dp[i].x - dp[im1].x) / (dp[ip1].x - dp[im1].x); p = sig * y2[im1] + 2.0; y2[i] = (sig - 1.0) / p; u[i] = ((dp[ip1].y - dp[i].y) / (dp[ip1].x - dp[i].x)) - ((dp[i].y - dp[im1].y) / (dp[i].x - dp[im1].x)); u[i] = (((6.0 * u[i]) / (dp[ip1].x - dp[im1].x)) - (sig * u[im1])) / p; stp_deprintf(STP_DBG_CURVE, "%d sig %f p %f y2 %f u %f x %f %f %f y %f %f %f\n", i, sig, p, y2[i], u[i], dp[im1].x, dp[i].x, dp[ip1].x, dp[im1].y, dp[i].y, dp[ip1].y); } y2[count] = 0.0; u[count] = 0.0; for (k = real_point_count - 2; k >= 0; k--) y2[k] = y2[k] * y2[k + 1] + u[k]; } curve->interval = y2; stp_free(u); }
stp_curve_t * stp_curve_create_from_xmltree(stp_mxml_node_t *curve) /* The curve node */ { const char *stmp; /* Temporary string */ stp_mxml_node_t *child; /* Child sequence node */ stp_curve_t *ret = NULL; /* Curve to return */ stp_curve_type_t curve_type; /* Type of curve */ stp_curve_wrap_mode_t wrap_mode; /* Curve wrap mode */ double fgamma; /* Gamma value */ stp_sequence_t *seq = NULL; /* Sequence data */ double low, high; /* Sequence bounds */ int piecewise = 0; stp_xml_init(); /* Get curve type */ stmp = stp_mxmlElementGetAttr(curve, "type"); if (stmp) { if (!strcmp(stmp, "linear")) curve_type = STP_CURVE_TYPE_LINEAR; else if (!strcmp(stmp, "spline")) curve_type = STP_CURVE_TYPE_SPLINE; else { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: %s: \"type\" invalid\n", stmp); goto error; } } else { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: \"type\" missing\n"); goto error; } /* Get curve wrap mode */ stmp = stp_mxmlElementGetAttr(curve, "wrap"); if (stmp) { if (!strcmp(stmp, "nowrap")) wrap_mode = STP_CURVE_WRAP_NONE; else if (!strcmp(stmp, "wrap")) { wrap_mode = STP_CURVE_WRAP_AROUND; } else { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: %s: \"wrap\" invalid\n", stmp); goto error; } } else { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: \"wrap\" missing\n"); goto error; } /* Get curve gamma */ stmp = stp_mxmlElementGetAttr(curve, "gamma"); if (stmp) { fgamma = stp_xmlstrtod(stmp); } else { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: \"gamma\" missing\n"); goto error; } /* If gamma is set, wrap_mode must be STP_CURVE_WRAP_NONE */ if (fgamma && wrap_mode != STP_CURVE_WRAP_NONE) { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: " "gamma set and \"wrap\" is not STP_CURVE_WRAP_NONE\n"); goto error; } stmp = stp_mxmlElementGetAttr(curve, "piecewise"); if (stmp && strcmp(stmp, "true") == 0) piecewise = 1; /* Set up the curve */ ret = stp_curve_create(wrap_mode); stp_curve_set_interpolation_type(ret, curve_type); child = stp_mxmlFindElement(curve, curve, "sequence", NULL, NULL, STP_MXML_DESCEND); if (child) seq = stp_sequence_create_from_xmltree(child); if (seq == NULL) { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: sequence read failed\n"); goto error; } /* Set curve bounds */ stp_sequence_get_bounds(seq, &low, &high); stp_curve_set_bounds(ret, low, high); if (fgamma) stp_curve_set_gamma(ret, fgamma); else /* Not a gamma curve, so set points */ { size_t seq_count; const double* data; stp_sequence_get_data(seq, &seq_count, &data); if (piecewise) { if ((seq_count % 2) != 0) { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: invalid data count %ld\n", (long)seq_count); goto error; } if (stp_curve_set_data_points(ret, seq_count / 2, (const stp_curve_point_t *) data) == 0) { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: failed to set curve data points\n"); goto error; } } else { if (stp_curve_set_data(ret, seq_count, data) == 0) { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: failed to set curve data\n"); goto error; } } } if (seq) { stp_sequence_destroy(seq); seq = NULL; } /* Validate curve */ if (stpi_curve_check_parameters(ret, stp_curve_count_points(ret)) == 0) { stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: parameter check failed\n"); goto error; } stp_xml_exit(); return ret; error: stp_deprintf(STP_DBG_CURVE_ERRORS, "stp_curve_create_from_xmltree: error during curve read\n"); if (ret) stp_curve_destroy(ret); stp_xml_exit(); return NULL; }
void stp_array_get_data(const stp_array_t *array, size_t *size, const double **data) { check_array(array); stp_sequence_get_data(array->data, size, data); }