void cohen_sutherland (double x1, double y1, double x2, double y2, double xmin, double ymin, double xmax, double ymax) { int accept; int done; outcode outcode1, outcode2; accept = FALSE; done = FALSE; outcode1 = compute_outcode (x1, y1, xmin, ymin, xmax, ymax); outcode2 = compute_outcode (x2, y2, xmin, ymin, xmax, ymax); do { if (outcode1 == 0 && outcode2 == 0) { accept = TRUE; done = TRUE; } else if (outcode1 & outcode2) done = TRUE; else { double x, y; int outcode_ex = outcode1 ? outcode1 : outcode2; if (outcode_ex & top) { x = x1 + (x2 - x1) * (ymax - y1) / (y2 - y1); y = ymax; } else if (outcode_ex & bottom) { x = x1 + (x2 - x1) * (ymin - y1) / (y2 - y1); y = ymin; } else if (outcode_ex & right) { y = y1 + (y2 - y1) * (xmax - x1) / (x2 - x1); x = xmax; } else { y = y1 + (y2 - y1) * (xmin - x1) / (x2 - x1); x = xmin; } if (outcode_ex == outcode1) { x1 = x; y1 = y; outcode1 = compute_outcode (x1, y1, xmin, ymin, xmax, ymax); } else { x2 = x; y2 = y; outcode2 = compute_outcode (x2, y2, xmin, ymin, xmax, ymax); } } } while (done == FALSE); if (accept == TRUE) line (x1, y1, x2, y2); }
/* * Calculate the intersection of a rectangle and line segment. * return TRUE if there is an intersection, FALSE otherwise. */ bool_t rect_intersect_with_line(const struct rect_t * r, s32_t * x1, s32_t * y1, s32_t * x2, s32_t * y2) { s32_t x = 0; s32_t y = 0; s32_t _x1, _y1; s32_t _x2, _y2; s32_t rectx1; s32_t recty1; s32_t rectx2; s32_t recty2; int outcode1, outcode2; if (!r || !x1 || !y1 || !x2 || !y2) { return FALSE; } _x1 = *x1; _y1 = *y1; _x2 = *x2; _y2 = *y2; rectx1 = r->x; recty1 = r->y; rectx2 = r->x + r->w - 1; recty2 = r->y + r->h - 1; /* Check to see if entire line is inside rect */ if (_x1 >= rectx1 && _x1 <= rectx2 && _x2 >= rectx1 && _x2 <= rectx2 && _y1 >= recty1 && _y1 <= recty2 && _y2 >= recty1 && _y2 <= recty2) { return TRUE; } /* Check to see if entire line is to one side of rect */ if ((_x1 < rectx1 && _x2 < rectx1) || (_x1 > rectx2 && _x2 > rectx2) || (_y1 < recty1 && _y2 < recty1) || (_y1 > recty2 && _y2 > recty2)) { return FALSE; } if (_y1 == _y2) { /* Horizontal line, easy to clip */ if (_x1 < rectx1) { *x1 = rectx1; } else if (_x1 > rectx2) { *x1 = rectx2; } if (_x2 < rectx1) { *x2 = rectx1; } else if (_x2 > rectx2) { *x2 = rectx2; } return TRUE; } if (_x1 == _x2) { /* Vertical line, easy to clip */ if (_y1 < recty1) { *y1 = recty1; } else if (_y1 > recty2) { *y1 = recty2; } if (_y2 < recty1) { *y2 = recty1; } else if (_y2 > recty2) { *y2 = recty2; } return TRUE; } /* More complicated Cohen-Sutherland algorithm */ outcode1 = compute_outcode(r, _x1, _y1); outcode2 = compute_outcode(r, _x2, _y2); while (outcode1 || outcode2) { if (outcode1 & outcode2) { return FALSE; } if (outcode1) { if (outcode1 & CODE_TOP) { y = recty1; x = _x1 + ((_x2 - _x1) * (y - _y1)) / (_y2 - _y1); } else if (outcode1 & CODE_BOTTOM) { y = recty2; x = _x1 + ((_x2 - _x1) * (y - _y1)) / (_y2 - _y1); } else if (outcode1 & CODE_LEFT) { x = rectx1; y = _y1 + ((_y2 - _y1) * (x - _x1)) / (_x2 - _x1); } else if (outcode1 & CODE_RIGHT) { x = rectx2; y = _y1 + ((_y2 - _y1) * (x - _x1)) / (_x2 - _x1); } _x1 = x; _y1 = y; outcode1 = compute_outcode(r, x, y); } else { if (outcode2 & CODE_TOP) { y = recty1; x = _x1 + ((_x2 - _x1) * (y - _y1)) / (_y2 - _y1); } else if (outcode2 & CODE_BOTTOM) { y = recty2; x = _x1 + ((_x2 - _x1) * (y - _y1)) / (_y2 - _y1); } else if (outcode2 & CODE_LEFT) { x = rectx1; y = _y1 + ((_y2 - _y1) * (x - _x1)) / (_x2 - _x1); } else if (outcode2 & CODE_RIGHT) { x = rectx2; y = _y1 + ((_y2 - _y1) * (x - _x1)) / (_x2 - _x1); } _x2 = x; _y2 = y; outcode2 = compute_outcode(r, x, y); } } *x1 = _x1; *y1 = _y1; *x2 = _x2; *y2 = _y2; return TRUE; }
static int clip_line (double *x0_p, double *y0_p, double *x1_p, double *y1_p, double x_min_clip, double x_max_clip, double y_min_clip, double y_max_clip, bool spec_min_x, bool spec_min_y, bool spec_max_x, bool spec_max_y) { double x0 = *x0_p; double y0 = *y0_p; double x1 = *x1_p; double y1 = *y1_p; int outcode0, outcode1; bool accepted; int clipval = 0; outcode0 = compute_outcode (x0, y0, x_min_clip, x_max_clip, y_min_clip, y_max_clip, spec_min_x, spec_min_y, spec_max_x, spec_max_y); outcode1 = compute_outcode (x1, y1, x_min_clip, x_max_clip, y_min_clip, y_max_clip, spec_min_x, spec_min_y, spec_max_x, spec_max_y); for ( ; ; ) { if (!(outcode0 | outcode1)) /* accept */ { accepted = true; break; } else if (outcode0 & outcode1) /* reject */ { accepted = false; break; } else { /* at least one endpoint is outside; choose one that is */ int outcode_out = (outcode0 ? outcode0 : outcode1); double x, y; /* intersection with clip edge */ if (outcode_out & RIGHT) { x = x_max_clip; y = y0 + (y1 - y0) * (x_max_clip - x0) / (x1 - x0); } else if (outcode_out & LEFT) { x = x_min_clip; y = y0 + (y1 - y0) * (x_min_clip - x0) / (x1 - x0); } else if (outcode_out & TOP) { x = x0 + (x1 - x0) * (y_max_clip - y0) / (y1 - y0); y = y_max_clip; } else /* BOTTOM bit must be set */ { x = x0 + (x1 - x0) * (y_min_clip - y0) / (y1 - y0); y = y_min_clip; } if (outcode_out == outcode0) { x0 = x; y0 = y; outcode0 = compute_outcode (x0, y0, x_min_clip, x_max_clip, y_min_clip, y_max_clip, spec_min_x, spec_min_y, spec_max_x, spec_max_y); } else { x1 = x; y1 = y; outcode1 = compute_outcode (x1, y1, x_min_clip, x_max_clip, y_min_clip, y_max_clip, spec_min_x, spec_min_y, spec_max_x, spec_max_y); } } } if (accepted) { clipval |= ACCEPTED; if ((x0 != *x0_p) || (y0 != *y0_p)) clipval |= CLIPPED_FIRST; if ((x1 != *x1_p) || (y1 != *y1_p)) clipval |= CLIPPED_SECOND; *x0_p = x0; *y0_p = y0; *x1_p = x1; *y1_p = y1; } return clipval; }