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); }
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 = X_AXIS.min; ixmax = sxmax = X_AXIS.max; iymin = symin = Y_AXIS.min; iymax = symax = 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) { /* This entire segment lies outside the current x range. */ for (i = 0; i < samples_1; i++) dest[i].type = OUTRANGE; return; } #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++; temp = x - 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 && y <= 0) y = symin - (symax - symin); dest[i].type = INRANGE; STORE_AND_FIXUP_RANGE(dest[i].x, x, dest[i].type, ixmin, ixmax, X_AXIS.autoscale); STORE_AND_FIXUP_RANGE(dest[i].y, y, dest[i].type, iymin, iymax, Y_AXIS.autoscale); 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); UPDATE_RANGE(ixmin < sxmin, X_AXIS.min, ixmin); UPDATE_RANGE(iymax > symax, Y_AXIS.max, iymax); UPDATE_RANGE(iymin < symin, Y_AXIS.min, iymin); }
void mcs_interp(struct curve_points *plot) { /* These track the original (pre-sorted) data points */ int N = plot->p_count; struct coordinate *p = gp_realloc(plot->points, (N+1) * sizeof(coordinate), "mcs"); int i; /* These will track the resulting smoothed curve */ struct coordinate *new_points = gp_alloc((samples_1+1) * sizeof(coordinate), "mcs"); double sxmin = AXIS_LOG_VALUE(plot->x_axis, X_AXIS.min); double sxmax = AXIS_LOG_VALUE(plot->x_axis, X_AXIS.max); double xstart, xend, xstep; xstart = GPMAX(p[0].x, sxmin); xend = GPMIN(p[N-1].x, sxmax); xstep = (xend - xstart) / (samples_1 - 1); /* Calculate spline coefficients */ #define DX xlow #define SLOPE xhigh #define C1 ylow #define C2 yhigh #define C3 z for (i = 0; i < N-1; i++) { p[i].DX = p[i+1].x - p[i].x; p[i].SLOPE = (p[i+1].y - p[i].y) / p[i].DX; } p[N-1].SLOPE = 0; p[0].C1 = p[0].SLOPE; for (i = 0; i < N-1; i++) { if (p[i].SLOPE * p[i+1].SLOPE <= 0) { p[i+1].C1 = 0; } else { double sum = p[i].DX + p[i+1].DX; p[i+1].C1 = (3. * sum) / ((sum + p[i+1].DX) / p[i].SLOPE + (sum + p[i].DX) / p[i+1].SLOPE); } } p[N].C1 = p[N-1].SLOPE; for (i = 0; i < N; i++) { double temp = p[i].C1 + p[i+1].C1 - 2*p[i].SLOPE; p[i].C2 = (p[i].SLOPE - p[i].C1 -temp) / p[i].DX; p[i].C3 = temp / (p[i].DX * p[i].DX); } /* Use the coefficients C1, C2, C3 to interpolate over the requested range */ for (i = 0; i < samples_1; i++) { double x = xstart + i * xstep; double y; TBOOLEAN exact = FALSE; if (x == p[N-1].x) { /* Exact value for right-most point of original data */ y = p[N-1].y; exact = TRUE; } else { int low = 0; int mid; int high = N-1; while (low <= high) { mid = floor((low + high) / 2); if (p[mid].x < x) low = mid + 1; else if (p[mid].x > x) high = mid - 1; else { /* Exact value for some point in original data */ y = p[mid].y; exact = TRUE; break; } } if (!exact) { int j = GPMAX(0, high); double diff = x - p[j].x; y = p[j].y + p[j].C1 * diff + p[j].C2 * diff * diff + p[j].C3 * diff * diff * diff; } } /* FIXME: Log x? autoscale x? */ new_points[i].x = x; new_points[i].type = INRANGE; STORE_WITH_LOG_AND_UPDATE_RANGE(new_points[i].y, y, new_points[i].type, plot->y_axis, plot->noautoscale, NOOP, NOOP); } /* Replace original data with the interpolated curve */ free(p); plot->points = new_points; plot->p_count = samples_1; plot->p_max = samples_1 + 1; #undef DX #undef SLOPE #undef C1 #undef C2 #undef C3 }
void mcs_interp(struct curve_points *plot) { /* These track the original (pre-sorted) data points */ int N = plot->p_count; struct coordinate *p = gp_realloc(plot->points, (N+1) * sizeof(coordinate), "mcs"); int i; /* These will track the resulting smoothed curve (>= 3X original count) */ /* Larger number of samples gives smoother curve (no surprise!) */ int Nsamp = (samples_1 > 2*N) ? samples_1 : 2*N; int Ntot = N + Nsamp; struct coordinate *new_points = gp_alloc((Ntot) * sizeof(coordinate), "mcs"); double xstart = GPMAX(p[0].x, X_AXIS.min); double xend = GPMIN(p[N-1].x, X_AXIS.max); double xstep = (xend - xstart) / (Nsamp - 1); /* Load output x coords for sampling */ for (i=0; i<N; i++) new_points[i].x = p[i].x; for ( ; i<Ntot; i++) new_points[i].x = xstart + (i-N)*xstep; /* Sort output x coords */ qsort(new_points, Ntot, sizeof(struct coordinate), compare_points); /* Displace any collisions */ for (i=1; i<Ntot-1; i++) { double delta = new_points[i].x - new_points[i-1].x; if (new_points[i+1].x - new_points[i].x < delta/1000.) new_points[i].x -= delta/2.; } /* Calculate spline coefficients */ #define DX xlow #define SLOPE xhigh #define C1 ylow #define C2 yhigh #define C3 z for (i = 0; i < N-1; i++) { p[i].DX = p[i+1].x - p[i].x; p[i].SLOPE = (p[i+1].y - p[i].y) / p[i].DX; } p[N-1].SLOPE = 0; p[0].C1 = p[0].SLOPE; for (i = 0; i < N-1; i++) { if (p[i].SLOPE * p[i+1].SLOPE <= 0) { p[i+1].C1 = 0; } else { double sum = p[i].DX + p[i+1].DX; p[i+1].C1 = (3. * sum) / ((sum + p[i+1].DX) / p[i].SLOPE + (sum + p[i].DX) / p[i+1].SLOPE); } } p[N].C1 = p[N-1].SLOPE; for (i = 0; i < N; i++) { double temp = p[i].C1 + p[i+1].C1 - 2*p[i].SLOPE; p[i].C2 = (p[i].SLOPE - p[i].C1 -temp) / p[i].DX; p[i].C3 = temp / (p[i].DX * p[i].DX); } /* Use the coefficients C1, C2, C3 to interpolate over the requested range */ for (i = 0; i < Ntot; i++) { double x = new_points[i].x; double y; TBOOLEAN exact = FALSE; if (x == p[N-1].x) { /* Exact value for right-most point of original data */ y = p[N-1].y; exact = TRUE; } else { int low = 0; int mid; int high = N-1; while (low <= high) { mid = floor((low + high) / 2); if (p[mid].x < x) low = mid + 1; else if (p[mid].x > x) high = mid - 1; else { /* Exact value for some point in original data */ y = p[mid].y; exact = TRUE; break; } } if (!exact) { int j = GPMAX(0, high); double diff = x - p[j].x; y = p[j].y + p[j].C1 * diff + p[j].C2 * diff * diff + p[j].C3 * diff * diff * diff; } } xstart = X_AXIS.min; xend = X_AXIS.max; if (inrange(x, xstart, xend)) new_points[i].type = INRANGE; else new_points[i].type = OUTRANGE; /* FIXME: simpler test for outrange would be sufficient */ STORE_AND_UPDATE_RANGE(new_points[i].y, y, new_points[i].type, plot->y_axis, plot->noautoscale, NOOP); } /* Replace original data with the interpolated curve */ free(p); plot->points = new_points; plot->p_count = Ntot; plot->p_max = Ntot + 1; #undef DX #undef SLOPE #undef C1 #undef C2 #undef C3 }
/* plot a colour smooth box bounded by the terminal's integer coordinates [x_from,y_from] to [x_to,y_to]. This routine is for non-postscript files, as it does an explicit loop over all thin rectangles */ static void draw_inside_color_smooth_box_bitmap(FILE * out) { int steps = 128; /* I think that nobody can distinguish more colours drawn in the palette */ int i, j, xy, xy2, xy_from, xy_to; int jmin = 0; double xy_step, gray, range; gpiPoint corners[4]; (void) out; /* to avoid "unused parameter" warning */ if (color_box.rotation == 'v') { corners[0].x = corners[3].x = color_box.bounds.xleft; corners[1].x = corners[2].x = color_box.bounds.xright; xy_from = color_box.bounds.ybot; xy_to = color_box.bounds.ytop; xy_step = (color_box.bounds.ytop - color_box.bounds.ybot) / (double)steps; } else { corners[0].y = corners[1].y = color_box.bounds.ybot; corners[2].y = corners[3].y = color_box.bounds.ytop; xy_from = color_box.bounds.xleft; xy_to = color_box.bounds.xright; xy_step = (color_box.bounds.xright - color_box.bounds.xleft) / (double)steps; } range = (xy_to - xy_from); for (i = 0, xy2 = xy_from; i < steps; i++) { /* Start from one pixel beyond the previous box */ xy = xy2; xy2 = xy_from + (int) (xy_step * (i + 1)); /* Set the colour for the next range increment */ /* FIXME - The "1 +" seems wrong, yet it improves the placement in gd */ gray = (double)(1 + xy - xy_from) / range; if (sm_palette.positive == SMPAL_NEGATIVE) gray = 1 - gray; set_color(gray); /* If this is a defined palette, make sure that the range increment */ /* does not straddle a palette segment boundary. If it does, split */ /* it into two parts. */ if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRADIENT) for (j=jmin; j<sm_palette.gradient_num; j++) { int boundary = xy_from + (int)(sm_palette.gradient[j].pos * range); if (xy >= boundary) { jmin = j; } else { if (xy2 > boundary) { xy2 = boundary; i--; break; } } if (xy2 < boundary) break; } if (color_box.rotation == 'v') { corners[0].y = corners[1].y = xy; corners[2].y = corners[3].y = GPMIN(xy_to,xy2+1); } else { corners[0].x = corners[3].x = xy; corners[1].x = corners[2].x = GPMIN(xy_to,xy2+1); } #ifdef EXTENDED_COLOR_SPECS if (supply_extended_color_specs) corners[0].spec.gray = -1; /* force solid color */ #endif /* print the rectangle with the given colour */ if (default_fillstyle.fillstyle == FS_EMPTY) corners->style = FS_OPAQUE; else corners->style = style_from_fill(&default_fillstyle); term->filled_polygon(4, corners); } }
/* sb_get: * retrieve (wrapped) line buffer */ LPLB sb_get(LPSB sb, uint index) { LPLB line = NULL; assert(sb != NULL); assert((index < sb->size) || (sb->wrap_at > 0)); assert(sb->lb != NULL); if (sb->wrap_at == 0) { if (index < sb_internal_length(sb)) line = &(sb->lb[(sb->head + index) % sb->size]); } else { /* count number of wrapped lines */ uint line_count; uint idx; uint internal_length = sb_internal_length(sb); if (sb->last_line <= index) { /* use cached values */ line_count = sb->last_line; idx = sb->last_line_index; } else { line_count = 0; idx = 0; } for ( ; (idx < internal_length); idx++) { line_count += sb_lines(sb, sb_internal_get(sb, idx)); if (line_count > index) break; } if (idx < internal_length) { uint wrapped_lines; uint len; LPLB lb; uint start, count; /* get last line buffer */ lb = sb_internal_get(sb, idx); len = lb_length(lb); wrapped_lines = sb_lines(sb, lb); line_count -= wrapped_lines; /* cache current index */ sb->last_line_index = idx; sb->last_line = line_count; /* index into current line buffer */ start = (index - line_count) * sb->wrap_at; count = GPMIN(len - start, sb->wrap_at); /* copy substring from current line buffer */ lb_init(sb->current_line); if (lb->str) { sb->current_line->len = count; sb->current_line->str = lb->str + start; //lb_insert_str(sb->current_line, 0, lb->str + start, count); } /* return temporary buffer */ line = sb->current_line; } } return line; }
/* Given two points, both outside the plot, return * the points where an edge of the plot intersects the line segment defined * by the two points. There may be zero, one, two, or an infinite number * of intersection points. (One means an intersection at a corner, infinite * means overlaying the edge itself). We return FALSE when there is nothing * to draw (zero intersections), and TRUE when there is something to * draw (the one-point case is a degenerate of the two-point case and we do * not distinguish it - we draw it anyway). */ TBOOLEAN /* any intersection? */ two_edge3d_intersect( struct coordinate GPHUGE *points, /* the points array */ int i, /* line segment from point i-1 to point i */ double *lx, double *ly, double *lz) /* lx[2], ly[2], lz[2]: points where it crosses edges */ { int count; /* global axis_array[FIRST_{X,Y,Z}_AXIS].{min,max} */ double ix = points[i - 1].x; double iy = points[i - 1].y; double iz = points[i - 1].z; double ox = points[i].x; double oy = points[i].y; double oz = points[i].z; double t[6]; double swap; double x, y, z; /* possible intersection point */ double t_min, t_max; /* nasty degenerate cases, effectively drawing to an infinity point (?) cope with them here, so don't process them as a "real" OUTRANGE point If more than one coord is -VERYLARGE, then can't ratio the "infinities" so drop out by returning FALSE */ count = 0; if (ix == -VERYLARGE) count++; if (ox == -VERYLARGE) count++; if (iy == -VERYLARGE) count++; if (oy == -VERYLARGE) count++; if (iz == -VERYLARGE) count++; if (oz == -VERYLARGE) count++; /* either doesn't pass through 3D volume *or* can't ratio infinities to get a direction to draw line, so simply return(FALSE) */ if (count > 1) { return (FALSE); } if (ox == -VERYLARGE || ix == -VERYLARGE) { if (ix == -VERYLARGE) { /* swap points so ix/iy/iz don't have a -VERYLARGE component */ x = ix; ix = ox; ox = x; y = iy; iy = oy; oy = y; z = iz; iz = oz; oz = z; } /* check actually passes through the 3D graph volume */ if (ix > axis_array[FIRST_X_AXIS].max && IN_AXIS_RANGE(iy, FIRST_Y_AXIS) && IN_AXIS_RANGE(iz, FIRST_Z_AXIS)) { lx[0] = axis_array[FIRST_X_AXIS].min; ly[0] = iy; lz[0] = iz; lx[1] = axis_array[FIRST_X_AXIS].max; ly[1] = iy; lz[1] = iz; return (TRUE); } else { return (FALSE); } } if (oy == -VERYLARGE || iy == -VERYLARGE) { if (iy == -VERYLARGE) { /* swap points so ix/iy/iz don't have a -VERYLARGE component */ x = ix; ix = ox; ox = x; y = iy; iy = oy; oy = y; z = iz; iz = oz; oz = z; } /* check actually passes through the 3D graph volume */ if (iy > axis_array[FIRST_Y_AXIS].max && IN_AXIS_RANGE(ix, FIRST_X_AXIS) && IN_AXIS_RANGE(iz, FIRST_Z_AXIS)) { lx[0] = ix; ly[0] = axis_array[FIRST_Y_AXIS].min; lz[0] = iz; lx[1] = ix; ly[1] = axis_array[FIRST_Y_AXIS].max; lz[1] = iz; return (TRUE); } else { return (FALSE); } } if (oz == -VERYLARGE || iz == -VERYLARGE) { if (iz == -VERYLARGE) { /* swap points so ix/iy/iz don't have a -VERYLARGE component */ x = ix; ix = ox; ox = x; y = iy; iy = oy; oy = y; z = iz; iz = oz; oz = z; } /* check actually passes through the 3D graph volume */ if (iz > axis_array[FIRST_Z_AXIS].max && IN_AXIS_RANGE(ix, FIRST_X_AXIS) && IN_AXIS_RANGE(iy, FIRST_Y_AXIS)) { lx[0] = ix; ly[0] = iy; lz[0] = axis_array[FIRST_Z_AXIS].min; lx[1] = ix; ly[1] = iy; lz[1] = axis_array[FIRST_Z_AXIS].max; return (TRUE); } else { return (FALSE); } } /* * Quick outcode tests on the 3d graph volume */ /* test z coord first --- most surface OUTRANGE points generated * between axis_array[FIRST_Z_AXIS].min and baseplane (i.e. when * ticslevel is non-zero) */ if (GPMAX(iz, oz) < axis_array[FIRST_Z_AXIS].min || GPMIN(iz, oz) > axis_array[FIRST_Z_AXIS].max) return (FALSE); if (GPMAX(ix, ox) < axis_array[FIRST_X_AXIS].min || GPMIN(ix, ox) > axis_array[FIRST_X_AXIS].max) return (FALSE); if (GPMAX(iy, oy) < axis_array[FIRST_Y_AXIS].min || GPMIN(iy, oy) > axis_array[FIRST_Y_AXIS].max) return (FALSE); /* Special horizontal/vertical, etc. cases are checked and * remaining slant lines are checked separately. * * The slant line intersections are solved using the parametric * form of the equation for a line, since if we test x/y/z min/max * planes explicitly then e.g. a line passing through a corner * point (x_min,y_min,z_min) actually intersects all 3 planes and * hence further tests would be required to anticipate this and * similar situations. */ /* Can have case (ix == ox && iy == oy && iz == oz) as both points * OUTRANGE */ if (ix == ox && iy == oy && iz == oz) { /* but as only define single outrange point, can't intersect * 3D graph volume */ return (FALSE); } if (ix == ox) { if (iy == oy) { /* line parallel to z axis */ /* x and y coords must be in range, and line must span * both FIRST_Z_AXIS->min and ->max. * * note that spanning FIRST_Z_AXIS->min implies spanning * ->max as both points OUTRANGE */ if (!IN_AXIS_RANGE(ix, FIRST_X_AXIS) || !IN_AXIS_RANGE(iy, FIRST_Y_AXIS)) { return (FALSE); } if (inrange(axis_array[FIRST_Z_AXIS].min, iz, oz)) { lx[0] = ix; ly[0] = iy; lz[0] = axis_array[FIRST_Z_AXIS].min; lx[1] = ix; ly[1] = iy; lz[1] = axis_array[FIRST_Z_AXIS].max; return (TRUE); } else return (FALSE); } if (iz == oz) { /* line parallel to y axis */ if (!IN_AXIS_RANGE(ix, FIRST_X_AXIS) || !IN_AXIS_RANGE(iz, FIRST_Z_AXIS)) { return (FALSE); } if (inrange(axis_array[FIRST_Y_AXIS].min, iy, oy)) { lx[0] = ix; ly[0] = axis_array[FIRST_Y_AXIS].min; lz[0] = iz; lx[1] = ix; ly[1] = axis_array[FIRST_Y_AXIS].max; lz[1] = iz; return (TRUE); } else return (FALSE); } /* nasty 2D slanted line in a yz plane */ if (!IN_AXIS_RANGE(ox, FIRST_X_AXIS)) return (FALSE); t[0] = (axis_array[FIRST_Y_AXIS].min - iy) / (oy - iy); t[1] = (axis_array[FIRST_Y_AXIS].max - iy) / (oy - iy); if (t[0] > t[1]) { swap = t[0]; t[0] = t[1]; t[1] = swap; } t[2] = (axis_array[FIRST_Z_AXIS].min - iz) / (oz - iz); t[3] = (axis_array[FIRST_Z_AXIS].max - iz) / (oz - iz); if (t[2] > t[3]) { swap = t[2]; t[2] = t[3]; t[3] = swap; } t_min = GPMAX(GPMAX(t[0], t[2]), 0.0); t_max = GPMIN(GPMIN(t[1], t[3]), 1.0); if (t_min > t_max) return (FALSE); lx[0] = ix; ly[0] = iy + t_min * (oy - iy); lz[0] = iz + t_min * (oz - iz); lx[1] = ix; ly[1] = iy + t_max * (oy - iy); lz[1] = iz + t_max * (oz - iz); /* Can only have 0 or 2 intersection points -- only need test * one coord */ if (IN_AXIS_RANGE(ly[0], FIRST_Y_AXIS) && IN_AXIS_RANGE(lz[0], FIRST_Z_AXIS)) { return (TRUE); } return (FALSE); } if (iy == oy) { /* already checked case (ix == ox && iy == oy) */ if (oz == iz) { /* line parallel to x axis */ if (!IN_AXIS_RANGE(iy, FIRST_Y_AXIS) || !IN_AXIS_RANGE(iz, FIRST_Z_AXIS)) { return (FALSE); } if (inrange(axis_array[FIRST_X_AXIS].min, ix, ox)) { lx[0] = axis_array[FIRST_X_AXIS].min; ly[0] = iy; lz[0] = iz; lx[1] = axis_array[FIRST_X_AXIS].max; ly[1] = iy; lz[1] = iz; return (TRUE); } else return (FALSE); } /* nasty 2D slanted line in an xz plane */ if (!IN_AXIS_RANGE(oy, FIRST_Y_AXIS)) return (FALSE); t[0] = (axis_array[FIRST_X_AXIS].min - ix) / (ox - ix); t[1] = (axis_array[FIRST_X_AXIS].max - ix) / (ox - ix); if (t[0] > t[1]) { swap = t[0]; t[0] = t[1]; t[1] = swap; } t[2] = (axis_array[FIRST_Z_AXIS].min - iz) / (oz - iz); t[3] = (axis_array[FIRST_Z_AXIS].max - iz) / (oz - iz); if (t[2] > t[3]) { swap = t[2]; t[2] = t[3]; t[3] = swap; } t_min = GPMAX(GPMAX(t[0], t[2]), 0.0); t_max = GPMIN(GPMIN(t[1], t[3]), 1.0); if (t_min > t_max) return (FALSE); lx[0] = ix + t_min * (ox - ix); ly[0] = iy; lz[0] = iz + t_min * (oz - iz); lx[1] = ix + t_max * (ox - ix); ly[1] = iy; lz[1] = iz + t_max * (oz - iz); /* * Can only have 0 or 2 intersection points -- only need test one coord */ if (IN_AXIS_RANGE(lx[0], FIRST_X_AXIS) && IN_AXIS_RANGE(lz[0], FIRST_Z_AXIS)) { return (TRUE); } return (FALSE); } if (iz == oz) { /* already checked cases (ix == ox && iz == oz) and (iy == oy && iz == oz) */ /* nasty 2D slanted line in an xy plane */ if (!IN_AXIS_RANGE(oz, FIRST_Z_AXIS)) return (FALSE); t[0] = (axis_array[FIRST_X_AXIS].min - ix) / (ox - ix); t[1] = (axis_array[FIRST_X_AXIS].max - ix) / (ox - ix); if (t[0] > t[1]) { swap = t[0]; t[0] = t[1]; t[1] = swap; } t[2] = (axis_array[FIRST_Y_AXIS].min - iy) / (oy - iy); t[3] = (axis_array[FIRST_Y_AXIS].max - iy) / (oy - iy); if (t[2] > t[3]) { swap = t[2]; t[2] = t[3]; t[3] = swap; } t_min = GPMAX(GPMAX(t[0], t[2]), 0.0); t_max = GPMIN(GPMIN(t[1], t[3]), 1.0); if (t_min > t_max) return (FALSE); lx[0] = ix + t_min * (ox - ix); ly[0] = iy + t_min * (oy - iy); lz[0] = iz; lx[1] = ix + t_max * (ox - ix); ly[1] = iy + t_max * (oy - iy); lz[1] = iz; /* * Can only have 0 or 2 intersection points -- only need test one coord */ if (IN_AXIS_RANGE(lx[0], FIRST_X_AXIS) && IN_AXIS_RANGE(ly[0], FIRST_Y_AXIS)) { return (TRUE); } return (FALSE); } /* really nasty general slanted 3D case */ /* Solve parametric equation (ix, iy, iz) + t (diff_x, diff_y, diff_z) where 0.0 <= t <= 1.0 and diff_x = (ox - ix); diff_y = (oy - iy); diff_z = (oz - iz); */ t[0] = (axis_array[FIRST_X_AXIS].min - ix) / (ox - ix); t[1] = (axis_array[FIRST_X_AXIS].max - ix) / (ox - ix); if (t[0] > t[1]) { swap = t[0]; t[0] = t[1]; t[1] = swap; } t[2] = (axis_array[FIRST_Y_AXIS].min - iy) / (oy - iy); t[3] = (axis_array[FIRST_Y_AXIS].max - iy) / (oy - iy); if (t[2] > t[3]) { swap = t[2]; t[2] = t[3]; t[3] = swap; } t[4] = (iz == oz) ? 0.0 : (axis_array[FIRST_Z_AXIS].min - iz) / (oz - iz); t[5] = (iz == oz) ? 1.0 : (axis_array[FIRST_Z_AXIS].max - iz) / (oz - iz); if (t[4] > t[5]) { swap = t[4]; t[4] = t[5]; t[5] = swap; } t_min = GPMAX(GPMAX(t[0], t[2]), GPMAX(t[4], 0.0)); t_max = GPMIN(GPMIN(t[1], t[3]), GPMIN(t[5], 1.0)); if (t_min > t_max) return (FALSE); lx[0] = ix + t_min * (ox - ix); ly[0] = iy + t_min * (oy - iy); lz[0] = iz + t_min * (oz - iz); lx[1] = ix + t_max * (ox - ix); ly[1] = iy + t_max * (oy - iy); lz[1] = iz + t_max * (oz - iz); /* * Can only have 0 or 2 intersection points -- only need test one coord */ if (IN_AXIS_RANGE(lx[0], FIRST_X_AXIS) && IN_AXIS_RANGE(ly[0], FIRST_Y_AXIS) && IN_AXIS_RANGE(lz[0], FIRST_Z_AXIS)) { return (TRUE); } return (FALSE); }
int main(int argc_orig, char **argv) #endif { int i; /* We want the current value of argc to persist across a LONGJMP from int_error(). * Without this the compiler may put it on the stack, which LONGJMP clobbers. * Here we try make it a volatile variable that optimization will not affect. * Why do we not have to do the same for argv? I don't know. * But the test cases that broke with generic argc seem fine with generic argv. */ static volatile int argc; argc = argc_orig; #ifdef LINUXVGA LINUX_setup(); /* setup VGA before dropping privilege DBT 4/5/99 */ drop_privilege(); #endif /* make sure that we really have revoked root access, this might happen if gnuplot is compiled without vga support but is installed suid by mistake */ #ifdef __linux__ if (setuid(getuid()) != 0) { fprintf(stderr,"gnuplot: refusing to run at elevated privilege\n"); exit(EXIT_FAILURE); } #endif /* HBB: Seems this isn't needed any more for DJGPP V2? */ /* HBB: disable all floating point exceptions, just keep running... */ #if defined(DJGPP) && (DJGPP!=2) _control87(MCW_EM, MCW_EM); #endif #if defined(OS2) { int rc; #ifdef OS2_IPC char semInputReadyName[40]; sprintf(semInputReadyName, "\\SEM32\\GP%i_Input_Ready", getpid()); rc = DosCreateEventSem(semInputReadyName, &semInputReady, 0, 0); if (rc != 0) fputs("DosCreateEventSem error\n", stderr); #endif rc = RexxRegisterSubcomExe("GNUPLOT", (PFN) RexxInterface, NULL); } #endif /* malloc large blocks, otherwise problems with fragmented mem */ #ifdef MALLOCDEBUG malloc_debug(7); #endif /* init progpath and get helpfile from executable directory */ #if defined(MSDOS) || defined(OS2) { char *s; #ifdef __EMX__ _execname(progpath, sizeof(progpath)); #else safe_strncpy(progpath, argv[0], sizeof(progpath)); #endif /* convert '/' to '\\' */ for (s = progpath; *s != NUL; s++) if (*s == DIRSEP2) *s = DIRSEP1; /* cut program name */ s = strrchr(progpath, DIRSEP1); if (s != NULL) s++; else s = progpath; *s = NUL; /* init HelpFile */ strcpy(HelpFile, progpath); strcat(HelpFile, "gnuplot.gih"); /* remove trailing "bin/" from progpath */ if ((s != NULL) && (s - progpath >= 4)) { s -= 4; if (strncasecmp(s, "bin", 3) == 0) *s = NUL; } } #endif /* DJGPP */ #if (defined(PIPE_IPC) || defined(_WIN32)) && (defined(HAVE_LIBREADLINE) || (defined(HAVE_LIBEDITLINE) && defined(X11))) /* Editline needs this to be set before the very first call to readline(). */ /* Support for rl_getc_function is broken for utf-8 in editline. Since it is only really required for X11, disable this section when building without X11. */ rl_getc_function = getc_wrapper; #endif #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE) /* T.Walter 1999-06-24: 'rl_readline_name' must be this fix name. * It is used to parse a 'gnuplot' specific section in '~/.inputrc' * or gnuplot specific commands in '.editrc' (when using editline * instead of readline) */ rl_readline_name = "Gnuplot"; rl_terminal_name = getenv("TERM"); #if defined(HAVE_LIBREADLINE) using_history(); #else history_init(); #endif #endif #if defined(HAVE_LIBREADLINE) && !defined(MISSING_RL_TILDE_EXPANSION) rl_complete_with_tilde_expansion = 1; #endif for (i = 1; i < argc; i++) { if (!argv[i]) continue; if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) { printf("gnuplot %s patchlevel %s\n", gnuplot_version, gnuplot_patchlevel); return 0; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { printf( "Usage: gnuplot [OPTION] ... [FILE]\n" #ifdef X11 "for X11 options see 'help X11->command-line-options'\n" #endif " -V, --version\n" " -h, --help\n" " -p --persist\n" " -s --slow\n" " -d --default-settings\n" " -c scriptfile ARG1 ARG2 ... \n" " -e \"command1; command2; ...\"\n" "gnuplot %s patchlevel %s\n", gnuplot_version, gnuplot_patchlevel); #ifdef DEVELOPMENT_VERSION printf( #ifdef DIST_CONTACT "Report bugs to "DIST_CONTACT"\n" " or %s\n", #else "Report bugs to %s\n", #endif bug_email); #endif return 0; } else if (!strncmp(argv[i], "-persist", 2) || !strcmp(argv[i], "--persist") #ifdef _WIN32 || !stricmp(argv[i], "-noend") || !stricmp(argv[i], "/noend") #endif ) { persist_cl = TRUE; } else if (!strncmp(argv[i], "-slow", 2) || !strcmp(argv[i], "--slow")) { slow_font_startup = TRUE; } else if (!strncmp(argv[i], "-d", 2) || !strcmp(argv[i], "--default-settings")) { /* Skip local customization read from ~/.gnuplot */ skip_gnuplotrc = TRUE; } } #ifdef X11 /* the X11 terminal removes tokens that it recognizes from argv. */ { int n = X11_args(argc, argv); argv += n; argc -= n; } #endif setbuf(stderr, (char *) NULL); #ifdef HAVE_SETVBUF /* This was once setlinebuf(). Docs say this is * identical to setvbuf(,NULL,_IOLBF,0), but MS C * faults this (size out of range), so we try with * size of 1024 instead. [SAS/C does that, too. -lh] */ if (setvbuf(stdout, (char *) NULL, _IOLBF, (size_t) 1024) != 0) (void) fputs("Could not linebuffer stdout\n", stderr); /* Switching to unbuffered mode causes all characters in the input * buffer to be lost. So the only safe time to do it is on program entry. * Do any non-X platforms suffer from this problem? * EAM - Jan 2013 YES. */ setvbuf(stdin, (char *) NULL, _IONBF, 0); #endif gpoutfile = stdout; /* Initialize pre-loaded user variables */ /* "pi" is hard-wired as the first variable */ (void) add_udv_by_name("GNUTERM"); (void) add_udv_by_name("NaN"); init_constants(); udv_user_head = &(udv_NaN->next_udv); init_memory(); interactive = FALSE; /* April 2017: We used to call init_terminal() here, but now */ /* We defer initialization until error handling has been set up. */ # if defined(_WIN32) && !defined(WGP_CONSOLE) interactive = TRUE; # else interactive = isatty(fileno(stdin)); # endif /* Note: we want to know whether this is an interactive session so that we can * decide whether or not to write status information to stderr. The old test * for this was to see if (argc > 1) but the addition of optional command line * switches broke this. What we really wanted to know was whether any of the * command line arguments are file names or an explicit in-line "-e command". */ for (i = 1; i < argc; i++) { # ifdef _WIN32 if (!stricmp(argv[i], "/noend")) continue; # endif if ((argv[i][0] != '-') || (argv[i][1] == 'e') || (argv[i][1] == 'c') ) { interactive = FALSE; break; } } /* Need this before show_version is called for the first time */ if (interactive) show_version(stderr); else show_version(NULL); /* Only load GPVAL_COMPILE_OPTIONS */ update_gpval_variables(3); /* update GPVAL_ variables available to user */ #ifdef VMS /* initialise screen management routines for command recall */ { unsigned int ierror; if (ierror = smg$create_virtual_keyboard(&vms_vkid) != SS$_NORMAL) done(ierror); if (ierror = smg$create_key_table(&vms_ktid) != SS$_NORMAL) done(ierror); } #endif /* VMS */ if (!SETJMP(command_line_env, 1)) { /* first time */ interrupt_setup(); get_user_env(); init_loadpath(); init_locale(); memset(&sm_palette, 0, sizeof(sm_palette)); init_fit(); /* Initialization of fitting module */ #ifdef READLINE /* When using the built-in readline, we set the initial encoding according to the locale as this is required to properly handle keyboard input. */ init_encoding(); #endif init_gadgets(); /* April 2017: Now that error handling is in place, it is safe parse * GNUTERM during terminal initialization. * atexit processing is done in reverse order. We want * the generic terminal shutdown in term_reset to be executed before * any terminal specific cleanup requested by individual terminals. */ init_terminal(); push_terminal(0); /* remember the initial terminal */ gp_atexit(term_reset); /* Execute commands in ~/.gnuplot */ init_session(); if (interactive && term != 0) { /* not unknown */ #ifdef GNUPLOT_HISTORY #if (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)) && !defined(_WIN32) expanded_history_filename = tilde_expand(GNUPLOT_HISTORY_FILE); #else expanded_history_filename = gp_strdup(GNUPLOT_HISTORY_FILE); gp_expand_tilde(&expanded_history_filename); #endif read_history(expanded_history_filename); /* * It is safe to ignore the return values of 'atexit()' and * 'on_exit()'. In the worst case, there is no history of your * currrent session and you have to type all again in your next * session. */ gp_atexit(wrapper_for_write_history); #endif /* GNUPLOT_HISTORY */ #if defined(READLINE) && defined(WGP_CONSOLE) fprintf(stderr, "Encoding set to '%s'.\n", encoding_names[encoding]); #endif } /* if (interactive && term != 0) */ } else { /* come back here from int_error() */ if (!successful_initialization) { /* Only print the warning once */ successful_initialization = TRUE; fprintf(stderr,"WARNING: Error during initialization\n\n"); } if (interactive == FALSE) exit_status = EXIT_FAILURE; #ifdef HAVE_READLINE_RESET else { /* reset properly readline after a SIGINT+longjmp */ rl_reset_after_signal (); } #endif load_file_error(); /* if we were in load_file(), cleanup */ SET_CURSOR_ARROW; #ifdef VMS /* after catching interrupt */ /* VAX stuffs up stdout on SIGINT while writing to stdout, so reopen stdout. */ if (gpoutfile == stdout) { if ((stdout = freopen("SYS$OUTPUT", "w", stdout)) == NULL) { /* couldn't reopen it so try opening it instead */ if ((stdout = fopen("SYS$OUTPUT", "w")) == NULL) { /* don't use int_error here - causes infinite loop! */ fputs("Error opening SYS$OUTPUT as stdout\n", stderr); } } gpoutfile = stdout; } #endif /* VMS */ /* Why a goto? Because we exited the loop below via int_error */ /* using LONGJMP. The compiler was not expecting this, and */ /* "optimized" the handling of argc and argv such that simply */ /* entering the loop again from the top finds them messed up. */ /* If we reenter the loop via a goto then there is some hope */ /* that code reordering does not hurt us. */ if (reading_from_dash && interactive) goto RECOVER_FROM_ERROR_IN_DASH; reading_from_dash = FALSE; if (!interactive && !noinputfiles) { term_reset(); gp_exit(EXIT_FAILURE); /* exit on non-interactive error */ } } /* load filenames given as arguments */ while (--argc > 0) { ++argv; c_token = 0; if (!strncmp(*argv, "-persist", 2) || !strcmp(*argv, "--persist") #ifdef _WIN32 || !stricmp(*argv, "-noend") || !stricmp(*argv, "/noend") #endif ) { FPRINTF((stderr,"'persist' command line option recognized\n")); } else if (strcmp(*argv, "-") == 0) { #if defined(_WIN32) && !defined(WGP_CONSOLE) TextShow(&textwin); interactive = TRUE; #else interactive = isatty(fileno(stdin)); #endif RECOVER_FROM_ERROR_IN_DASH: reading_from_dash = TRUE; while (!com_line()); reading_from_dash = FALSE; interactive = FALSE; noinputfiles = FALSE; } else if (strcmp(*argv, "-e") == 0) { int save_state = interactive; --argc; ++argv; if (argc <= 0) { fprintf(stderr, "syntax: gnuplot -e \"commands\"\n"); return 0; } interactive = FALSE; noinputfiles = FALSE; do_string(*argv); interactive = save_state; } else if (!strncmp(*argv, "-slow", 2) || !strcmp(*argv, "--slow")) { slow_font_startup = TRUE; } else if (!strncmp(*argv, "-d", 2) || !strcmp(*argv, "--default-settings")) { /* Ignore this; it already had its effect */ FPRINTF((stderr, "ignoring -d\n")); } else if (strcmp(*argv, "-c") == 0) { /* Pass command line arguments to the gnuplot script in the next * argument. This consumes the remainder of the command line */ interactive = FALSE; noinputfiles = FALSE; --argc; ++argv; if (argc <= 0) { fprintf(stderr, "syntax: gnuplot -c scriptname args\n"); gp_exit(EXIT_FAILURE); } call_argc = GPMIN(9, argc - 1); for (i=0; i<=call_argc; i++) { /* Need to stash argv[i] somewhere visible to load_file() */ call_args[i] = gp_strdup(argv[i+1]); } load_file(loadpath_fopen(*argv, "r"), gp_strdup(*argv), 5); gp_exit(EXIT_SUCCESS); } else if (*argv[0] == '-') { fprintf(stderr, "unrecognized option %s\n", *argv); } else { interactive = FALSE; noinputfiles = FALSE; load_file(loadpath_fopen(*argv, "r"), gp_strdup(*argv), 4); } } /* take commands from stdin */ if (noinputfiles) { while (!com_line()) ctrlc_flag = FALSE; /* reset asynchronous Ctrl-C flag */ } #ifdef _WIN32 /* On Windows, handle 'persist' by keeping the main input loop running (windows/wxt), */ /* but only if there are any windows open. Note that qt handles this properly. */ if (persist_cl) { if (WinAnyWindowOpen()) { #ifdef WGP_CONSOLE if (!interactive) { /* no further input from pipe */ while (WinAnyWindowOpen()) win_sleep(100); } else #endif { interactive = TRUE; while (!com_line()) ctrlc_flag = FALSE; /* reset asynchronous Ctrl-C flag */ interactive = FALSE; } } } #endif #if (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)) && defined(GNUPLOT_HISTORY) #if !defined(HAVE_ATEXIT) && !defined(HAVE_ON_EXIT) /* You should be here if you neither have 'atexit()' nor 'on_exit()' */ wrapper_for_write_history(); #endif /* !HAVE_ATEXIT && !HAVE_ON_EXIT */ #endif /* (HAVE_LIBREADLINE || HAVE_LIBEDITLINE) && GNUPLOT_HISTORY */ #ifdef OS2 RexxDeregisterSubcom("GNUPLOT", NULL); #endif /* HBB 20040223: Not all compilers like exit() to end main() */ /* exit(exit_status); */ #if ! defined(_WIN32) /* Windows does the cleanup later */ gp_exit_cleanup(); #endif return exit_status; }