/* eval_kdensity is a modification of eval_bezier */ static double eval_kdensity ( struct curve_points *cp, int first_point, /* where to start in plot->points (to find x-range) */ int num_points, /* to determine end in plot->points */ double x /* x value at which to calculate y */ ) { unsigned int i; struct coordinate GPHUGE *this_points = (cp->points) + first_point; double y, Z, ytmp; double avg, sigma; double bandwidth, default_bandwidth; avg = 0.0; sigma = 0.0; for (i = 0; i < num_points; i++) { avg += this_points[i].x; sigma += this_points[i].x * this_points[i].x; } avg /= (double)num_points; sigma = sqrt( sigma/(double)num_points - avg*avg ); /* Standard Deviation */ /* This is the optimal bandwidth if the point distribution is Gaussian. (Applied Smoothing Techniques for Data Analysis by Adrian W, Bowman & Adelchi Azzalini (1997)) */ /* If the supplied bandwidth is zero of less, the default bandwidth is used. */ default_bandwidth = pow( 4.0/(3.0*num_points), 1.0/5.0 )*sigma; if (cp->smooth_parameter <= 0) { bandwidth = default_bandwidth; cp->smooth_parameter = -default_bandwidth; } else bandwidth = cp->smooth_parameter; y = 0; for (i = 0; i < num_points; i++) { Z = ( x - this_points[i].x )/bandwidth; ytmp = this_points[i].y; y += AXIS_DE_LOG_VALUE(cp->y_axis,ytmp) * exp( -0.5*Z*Z ) / bandwidth; } y /= sqrt(2.0*M_PI); return y; }
static void do_cubic( struct curve_points *plot, /* still containes old plot->points */ spline_coeff *sc, /* generated by cp_tridiag */ int first_point, /* where to start in plot->points */ int num_points, /* to determine end in plot->points */ struct coordinate *dest) /* where to put the interpolated data */ { double xdiff, temp, x, y; double xstart, xend; /* Endpoints of the sampled x range */ int i, l; struct coordinate GPHUGE *this_points; /* min and max in internal (eg logged) co-ordinates. We update * these, then update the external extrema in user co-ordinates * at the end. */ double ixmin, ixmax, iymin, iymax; double sxmin, sxmax, symin, symax; /* starting values of above */ x_axis = plot->x_axis; y_axis = plot->y_axis; ixmin = sxmin = AXIS_LOG_VALUE(x_axis, X_AXIS.min); ixmax = sxmax = AXIS_LOG_VALUE(x_axis, X_AXIS.max); iymin = symin = AXIS_LOG_VALUE(y_axis, Y_AXIS.min); iymax = symax = AXIS_LOG_VALUE(y_axis, Y_AXIS.max); this_points = (plot->points) + first_point; l = 0; /* HBB 20010727: Sample only across the actual x range, not the * full range of input data */ #if SAMPLE_CSPLINES_TO_FULL_RANGE xstart = this_points[0].x; xend = this_points[num_points - 1].x; #else xstart = GPMAX(this_points[0].x, sxmin); xend = GPMIN(this_points[num_points - 1].x, sxmax); if (xstart >= xend) int_error(plot->token, "Cannot smooth: no data within fixed xrange!"); #endif xdiff = (xend - xstart) / (samples_1 - 1); for (i = 0; i < samples_1; i++) { x = xstart + i * xdiff; /* Move forward to the spline interval this point is in */ while ((x >= this_points[l + 1].x) && (l < num_points - 2)) l++; /* KB 981107: With logarithmic x axis the values were * converted back to linear scale before calculating the * coefficients. Use exponential for log x values. */ temp = AXIS_DE_LOG_VALUE(x_axis, x) - AXIS_DE_LOG_VALUE(x_axis, this_points[l].x); /* Evaluate cubic spline polynomial */ y = ((sc[l][3] * temp + sc[l][2]) * temp + sc[l][1]) * temp + sc[l][0]; /* With logarithmic y axis, we need to convert from linear to * log scale now. */ if (Y_AXIS.log) { if (y > 0.) y = AXIS_DO_LOG(y_axis, y); else y = symin - (symax - symin); } dest[i].type = INRANGE; STORE_AND_FIXUP_RANGE(dest[i].x, x, dest[i].type, ixmin, ixmax, X_AXIS.autoscale, NOOP, continue); STORE_AND_FIXUP_RANGE(dest[i].y, y, dest[i].type, iymin, iymax, Y_AXIS.autoscale, NOOP, NOOP); dest[i].xlow = dest[i].xhigh = dest[i].x; dest[i].ylow = dest[i].yhigh = dest[i].y; dest[i].z = -1; } UPDATE_RANGE(ixmax > sxmax, X_AXIS.max, ixmax, x_axis); UPDATE_RANGE(ixmin < sxmin, X_AXIS.min, ixmin, x_axis); UPDATE_RANGE(iymax > symax, Y_AXIS.max, iymax, y_axis); UPDATE_RANGE(iymin < symin, Y_AXIS.min, iymin, y_axis); }
/* * Calculation of cubic splines * * This can be treated as a special case of approximation cubic splines, with * all weights -> infinity. * * Returns matrix of spline coefficients */ static spline_coeff * cp_tridiag(struct curve_points *plot, int first_point, int num_points) { spline_coeff *sc; tri_diag *m; double *r, *x, *h, *xp, *yp; struct coordinate GPHUGE *this_points; int i; x_axis = plot->x_axis; y_axis = plot->y_axis; if (num_points < 3) int_error(plot->token, "Can't calculate splines, need at least 3 points"); this_points = (plot->points) + first_point; sc = gp_alloc((num_points) * sizeof(spline_coeff), "spline matrix"); m = gp_alloc((num_points - 2) * sizeof(tri_diag), "spline help matrix"); r = gp_alloc((num_points - 2) * sizeof(double), "spline right side"); x = gp_alloc((num_points - 2) * sizeof(double), "spline solution vector"); h = gp_alloc((num_points - 1) * sizeof(double), "spline help vector"); xp = gp_alloc((num_points) * sizeof(double), "x pos"); yp = gp_alloc((num_points) * sizeof(double), "y pos"); /* KB 981107: With logarithmic axis first convert back to linear scale */ xp[0] = AXIS_DE_LOG_VALUE(x_axis,this_points[0].x); yp[0] = AXIS_DE_LOG_VALUE(y_axis,this_points[0].y); for (i = 1; i < num_points; i++) { xp[i] = AXIS_DE_LOG_VALUE(x_axis,this_points[i].x); yp[i] = AXIS_DE_LOG_VALUE(y_axis,this_points[i].y); h[i - 1] = xp[i] - xp[i - 1]; } /* set up the matrix and the vector */ for (i = 0; i <= num_points - 3; i++) { r[i] = 3 * ((yp[i + 2] - yp[i + 1]) / h[i + 1] - (yp[i + 1] - yp[i]) / h[i]); if (i < 1) m[i][0] = 0; else m[i][0] = h[i]; m[i][1] = 2 * (h[i] + h[i + 1]); if (i > num_points - 4) m[i][2] = 0; else m[i][2] = h[i + 1]; } /* solve the matrix */ if (!solve_tri_diag(m, r, x, num_points - 2)) { free(h); free(x); free(r); free(m); free(xp); free(yp); int_error(plot->token, "Can't calculate cubic splines"); } sc[0][2] = 0; for (i = 1; i <= num_points - 2; i++) sc[i][2] = x[i - 1]; sc[num_points - 1][2] = 0; for (i = 0; i <= num_points - 1; i++) sc[i][0] = yp[i]; for (i = 0; i <= num_points - 2; i++) { sc[i][1] = (sc[i + 1][0] - sc[i][0]) / h[i] - h[i] / 3 * (sc[i + 1][2] + 2 * sc[i][2]); sc[i][3] = (sc[i + 1][2] - sc[i][2]) / 3 / h[i]; } free(h); free(x); free(r); free(m); free(xp); free(yp); return (sc); }
/* * Calculation of approximation cubic splines * Input: x[i], y[i], weights z[i] * * Returns matrix of spline coefficients */ static spline_coeff * cp_approx_spline( struct curve_points *plot, int first_point, /* where to start in plot->points */ int num_points) /* to determine end in plot->points */ { spline_coeff *sc; five_diag *m; double *r, *x, *h, *xp, *yp; struct coordinate GPHUGE *this_points; int i; x_axis = plot->x_axis; y_axis = plot->y_axis; sc = gp_alloc((num_points) * sizeof(spline_coeff), "spline matrix"); if (num_points < 4) int_error(plot->token, "Can't calculate approximation splines, need at least 4 points"); this_points = (plot->points) + first_point; for (i = 0; i < num_points; i++) if (this_points[i].z <= 0) int_error(plot->token, "Can't calculate approximation splines, all weights have to be > 0"); m = gp_alloc((num_points - 2) * sizeof(five_diag), "spline help matrix"); r = gp_alloc((num_points - 2) * sizeof(double), "spline right side"); x = gp_alloc((num_points - 2) * sizeof(double), "spline solution vector"); h = gp_alloc((num_points - 1) * sizeof(double), "spline help vector"); xp = gp_alloc((num_points) * sizeof(double), "x pos"); yp = gp_alloc((num_points) * sizeof(double), "y pos"); /* KB 981107: With logarithmic axis first convert back to linear scale */ xp[0] = AXIS_DE_LOG_VALUE(x_axis, this_points[0].x); yp[0] = AXIS_DE_LOG_VALUE(y_axis, this_points[0].y); for (i = 1; i < num_points; i++) { xp[i] = AXIS_DE_LOG_VALUE(x_axis, this_points[i].x); yp[i] = AXIS_DE_LOG_VALUE(y_axis, this_points[i].y); h[i - 1] = xp[i] - xp[i - 1]; } /* set up the matrix and the vector */ for (i = 0; i <= num_points - 3; i++) { r[i] = 3 * ((yp[i + 2] - yp[i + 1]) / h[i + 1] - (yp[i + 1] - yp[i]) / h[i]); if (i < 2) m[i][0] = 0; else m[i][0] = 6 / this_points[i].z / h[i - 1] / h[i]; if (i < 1) m[i][1] = 0; else m[i][1] = h[i] - 6 / this_points[i].z / h[i] * (1 / h[i - 1] + 1 / h[i]) - 6 / this_points[i + 1].z / h[i] * (1 / h[i] + 1 / h[i + 1]); m[i][2] = 2 * (h[i] + h[i + 1]) + 6 / this_points[i].z / h[i] / h[i] + 6 / this_points[i + 1].z * (1 / h[i] + 1 / h[i + 1]) * (1 / h[i] + 1 / h[i + 1]) + 6 / this_points[i + 2].z / h[i + 1] / h[i + 1]; if (i > num_points - 4) m[i][3] = 0; else m[i][3] = h[i + 1] - 6 / this_points[i + 1].z / h[i + 1] * (1 / h[i] + 1 / h[i + 1]) - 6 / this_points[i + 2].z / h[i + 1] * (1 / h[i + 1] + 1 / h[i + 2]); if (i > num_points - 5) m[i][4] = 0; else m[i][4] = 6 / this_points[i + 2].z / h[i + 1] / h[i + 2]; } /* solve the matrix */ if (!solve_five_diag(m, r, x, num_points - 2)) { free(h); free(x); free(r); free(m); free(xp); free(yp); int_error(plot->token, "Can't calculate approximation splines"); } sc[0][2] = 0; for (i = 1; i <= num_points - 2; i++) sc[i][2] = x[i - 1]; sc[num_points - 1][2] = 0; sc[0][0] = yp[0] + 2 / this_points[0].z / h[0] * (sc[0][2] - sc[1][2]); for (i = 1; i <= num_points - 2; i++) sc[i][0] = yp[i] - 2 / this_points[i].z * (sc[i - 1][2] / h[i - 1] - sc[i][2] * (1 / h[i - 1] + 1 / h[i]) + sc[i + 1][2] / h[i]); sc[num_points - 1][0] = yp[num_points - 1] - 2 / this_points[num_points - 1].z / h[num_points - 2] * (sc[num_points - 2][2] - sc[num_points - 1][2]); for (i = 0; i <= num_points - 2; i++) { sc[i][1] = (sc[i + 1][0] - sc[i][0]) / h[i] - h[i] / 3 * (sc[i + 1][2] + 2 * sc[i][2]); sc[i][3] = (sc[i + 1][2] - sc[i][2]) / 3 / h[i]; } free(h); free(x); free(r); free(m); free(xp); free(yp); return (sc); }