/** * float_range_function2d: * @val0: * @val1: * @ei: * @func: (scope call): * @flags: * @func_error: * * Returns: (transfer full): **/ GnmValue * float_range_function2d (GnmValue const *val0, GnmValue const *val1, GnmFuncEvalInfo *ei, float_range_function2d_t func, CollectFlags flags, GnmStdError func_error, gpointer data) { gnm_float *vals0, *vals1; int n; GnmValue *res; gnm_float fres; gboolean constp = FALSE; res = collect_float_pairs (val0, val1, ei->pos, flags, &vals0, &vals1, &n, &constp); if (res) return res; if (n <= 0) return value_new_error_std (ei->pos, func_error); if (func (vals0, vals1, n, &fres, data)) res = value_new_error_std (ei->pos, func_error); else res = value_new_float (fres); if (!constp) { g_free (vals0); g_free (vals1); } return res; }
static GnmValue * gnumeric_interpolation (GnmFuncEvalInfo *ei, GnmValue const * const *argv) { gnm_float *vals0, *vals1, *vals2, *fres; int n0, n2; int interp; GnmValue *error = NULL; GnmValue *res; CollectFlags flags; GnmEvalPos const * const ep = ei->pos; GnmValue const * const PtInterpolation = argv[2]; int r, i; GSList *missing2 = NULL, *missing; INTERPPROC interpproc = NULL; gboolean constp = FALSE; /* argv[2] */ int const cols = value_area_get_width (PtInterpolation, ep); int const rows = value_area_get_height (PtInterpolation, ep); if (rows == 0 || cols != 1) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE); return res; } flags = COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS | COLLECT_IGNORE_ERRORS; vals2 = collect_floats_value_with_info (PtInterpolation, ei->pos, flags, &n2, &missing2, &error); if (error) { g_slist_free (missing2); return error; } /* argv[3] */ if (argv[3]) { interp = (int) gnm_floor (value_get_as_float (argv[3])); if (interp < 0 || interp > INTERPOLATION_SPLINE_AVG) { g_slist_free (missing2); g_free (vals2); return value_new_error_VALUE (ei->pos); } } else interp = INTERPOLATION_LINEAR; switch (interp) { case INTERPOLATION_LINEAR: interpproc = linear_interpolation; break; case INTERPOLATION_LINEAR_AVG: interpproc = linear_averaging; n2--; break; case INTERPOLATION_STAIRCASE: interpproc = staircase_interpolation; break; case INTERPOLATION_STAIRCASE_AVG: interpproc = staircase_averaging; n2--; break; case INTERPOLATION_SPLINE: interpproc = spline_interpolation; break; case INTERPOLATION_SPLINE_AVG: interpproc = spline_averaging; n2--; break; } if (n2 <= 0) { g_slist_free (missing2); g_free (vals2); return value_new_error_std (ei->pos, GNM_ERROR_VALUE); } /* argv[0] & argv[1] */ flags = COLLECT_IGNORE_BLANKS | COLLECT_IGNORE_STRINGS | COLLECT_IGNORE_BOOLS; error = collect_float_pairs (argv[0], argv[1], ei->pos, flags, &vals0, &vals1, &n0, &constp); if (error) { g_slist_free (missing2); g_free (vals2); return error; } /* Check whether the abscissae are increasing, if not order them */ if (!gnm_range_increasing (vals0, n0)) { gboolean switched = TRUE; if (constp) { vals0 = g_memdup (vals0, sizeof(gnm_float) * n0); vals1 = g_memdup (vals1, sizeof(gnm_float) * n0); constp = FALSE; } while (switched) { gnm_float *val; switched = FALSE; for (i = 1, val = vals0; i < n0; i++, val++) { if (*val == *(val + 1)) { res = value_new_error_std (ei->pos, GNM_ERROR_VALUE) ; goto done; } if (*val > *(val + 1)) { gnm_float v = *val; *val = *(val + 1); *(val + 1) = v; v = *(vals1 + i); *(vals1 + i) = *(vals1 + i - 1); *(vals1 + i - 1) = v; switched = TRUE; } } } } { int n = n2; if (missing2) gnm_strip_missing (vals2, &n, missing2); res = value_new_array_non_init (1 , n2); i = 0; res->v_array.vals[0] = g_new (GnmValue *, n2); fres = interpproc (vals0, vals1, n0, vals2, n); missing = missing2; if (fres) { i = 0; for (r = 0 ; r < n2; ++r) if (missing && r == GPOINTER_TO_INT (missing->data)) { missing = missing->next; res->v_array.vals[0][r] = value_new_error_std (ei->pos, GNM_ERROR_VALUE); } else res->v_array.vals[0][r] = value_new_float (fres[i++]); g_free (fres); } else { for( r = 0 ; r < n2; ++r) res->v_array.vals[0][r] = value_new_error_std (ei->pos, GNM_ERROR_VALUE); } } done: g_slist_free (missing2); if (!constp) { g_free (vals0); g_free (vals1); } g_free (vals2); return res; }