/* write <n> last entries of the history to the file <filename> * Input parameters: * n > 0 ... write only <n> last entries; otherwise all entries * filename == NULL ... write to stdout; otherwise to the filename * filename == "" ... write to stdout, but without entry numbers * mode ... should be "w" or "a" to select write or append for file, * ignored if history is written to a pipe */ void write_history_n(const int n, const char *filename, const char *mode) { struct hist *entry = history, *start = NULL; FILE *out = stdout; #ifdef PIPES int is_pipe = 0; /* not filename but pipe to an external program */ #endif int hist_entries = 0; int hist_index = 1; if (entry == NULL) return; /* no history yet */ /* find the beginning of the history and count nb of entries */ while (entry->prev != NULL) { entry = entry->prev; hist_entries++; if (n <= 0 || hist_entries <= n) start = entry; /* listing will start from this entry */ } entry = start; hist_index = (n > 0) ? GPMAX(hist_entries - n, 0) + 1 : 1; /* now write the history */ if (filename != NULL && filename[0]) { #ifdef PIPES if (filename[0]=='|') { out = popen(filename+1, "w"); is_pipe = 1; } else #endif out = fopen(filename, mode); } if (!out) { /* cannot use int_error() because we are just exiting gnuplot: int_error(NO_CARET, "cannot open file for saving the history"); */ fprintf(stderr, "Warning: cannot open file %s for saving the history.", filename); } else { while (entry != NULL) { /* don't add line numbers when writing to file * to make file loadable */ if (filename) { if (filename[0]==0) fputs(" ", out); fprintf(out, "%s\n", entry->line); } else fprintf(out, "%5i %s\n", hist_index++, entry->line); entry = entry->next; } if (filename != NULL && filename[0]) { #ifdef PIPES if (is_pipe) pclose(out); else #endif fclose(out); } } }
/* sb_max_line_length: * determine maximum length of a single text line */ uint sb_max_line_length(LPSB sb) { uint idx; uint len; uint count; len = 0; count = sb_internal_length(sb); for(idx = 0; idx < count; idx++) len = GPMAX(lb_length(sb_internal_get(sb, idx)), len); if ((sb->wrap_at != 0) && (len > sb->wrap_at)) len = sb->wrap_at; return len; }
/* lb_insert_str: * (actually this is a misnomer as it overwrites any previous text) * insert a string <s> at position <pos> into the line buffer, * increase the size of the line buffer if necessary, * fill gaps with spaces */ void lb_insert_str(LPLB lb, uint pos, char *s, uint count) { assert(lb != NULL); /* enlarge string buffer if necessary */ if (lb->size <= pos + count) { uint newsize = ((pos + count + 8) / 8) * 8 + 32; lb->str = realloc(lb->str, newsize); lb->size = newsize; } /* fill up with spaces */ if (pos > lb->len) memset(lb->str + lb->len, ' ', pos - lb->len); /* copy characters */ memcpy(lb->str + pos, s, count); lb->len = GPMAX(pos + count, lb->len); lb->str[lb->len] = '\0'; }
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); }
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 }
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 (>= 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 }
/* 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); }