// cf. Steven Eker. Faster "Pixel-Perfect" Line Clipping. Graphics Gems V: // 314-322. // - Pixels are not missed at the ends of a clipped segment. // - Visible pixels are the same as if there was no clipping. private boolean clipLine(Rectangle r, final Line sl, Line dl) { int code1 = 0, code2 = 0; dl.x0 = sl.x0; dl.y0 = sl.y0; dl.x1 = sl.x1; dl.y1 = sl.y1; if (sl.x0 < r.xmin) code1 |= CLIP_LEFT; if (sl.x0 > r.xmax) code1 |= CLIP_RIGHT; if (sl.y0 < r.ymin) code1 |= CLIP_BOTTOM; if (sl.y0 > r.ymax) code1 |= CLIP_TOP; if (sl.x1 < r.xmin) code2 |= CLIP_LEFT; if (sl.x1 > r.xmax) code2 |= CLIP_RIGHT; if (sl.y1 < r.ymin) code2 |= CLIP_BOTTOM; if (sl.y1 > r.ymax) code2 |= CLIP_TOP; if ((code1 | code2) == 0) return false; // Trivial accept. if ((code1 & code2) != 0) return true; // Trivial reject. // Clip first end point. if (code1 != 0) if (clipEndPoint(r, sl, dl, code1, false)) return true; // Clip second end point. if (code2 != 0) if (clipEndPoint(r, sl, dl, code2, true)) return true; return false; }
private Line getLine(GC gc, int offset) { Line p = lineCache.get(Integer.valueOf(offset)); if (p == null) { p = new Line(); Point loc = contentAdapter.getLocationAtOffset(control, offset + 1); int h = contentAdapter.getLineHeightAtOffset(control, offset + 1); p.y = loc.y + h - 1; p.x2 = loc.x; p.x1 = p.x2 - gc.stringExtent(contentAdapter.getControlContents(control, offset, 1)).x; lineCache.put(Integer.valueOf(offset), p); } return p; }
private boolean clipEndPoint(Rectangle r, final Line sl, Line dl, int code, boolean swap) { // Rounding mode: 0=round toward 0, 1=round toward +infinity. int x, y, dx, dy, sx = 1, sy = 1, roundX = 0, roundY = 0; if (swap) { x = sl.x1; y = sl.y1; dx = sl.x0 - sl.x1; dy = sl.y0 - sl.y1; } else { x = sl.x0; y = sl.y0; dx = sl.x1 - sl.x0; dy = sl.y1 - sl.y0; } if (dx < 0) { dx = -dx; sx = -1; roundX ^= 1; } if (dy < 0) { dy = -dy; sy = -1; roundY ^= 1; } int dx2 = dx << 1, dy2 = dy << 1, t0 = 0, t1 = 0; int xc = x, yc = y; if ((code & CLIP_LEFT) != 0) { t0 = dy2 * (r.xmin - x); xc = r.xmin; } if ((code & CLIP_RIGHT) != 0) { t0 = dy2 * (x - r.xmax); xc = r.xmax; } if ((code & CLIP_BOTTOM) != 0) { t1 = dx2 * (r.ymin - y); yc = r.ymin; } if ((code & CLIP_TOP) != 0) { t1 = dx2 * (y - r.ymax); yc = r.ymax; } if (CLIP_ZONE_FOR_CODE[code] == CLIP_ZONE_DIAGONALS) { // Find which edge clips the line first and remove a clip flag. if (dx >= dy) code &= ((t0 - t1 + dx - (roundX ^ 1)) < 0) ? ~CLIP_HORIZONTAL : ~CLIP_VERTICAL; else code &= ((t1 - t0 + dy - (roundY ^ 1)) < 0) ? ~CLIP_VERTICAL : ~CLIP_HORIZONTAL; } if ((code & CLIP_HORIZONTAL) != 0) { // Clip to left or right edge. t0 = (dx >= dy) ? (t0 + dx - (roundX ^ 1)) / dx2 : (t0 - dy + dx2 - roundY) / dx2; yc = (sy < 0) ? (y - t0) : (y + t0); if ((yc < r.ymin) || (yc > r.ymax)) return true; } else { // Clip to bottom or top edge. t1 = (dx >= dy) ? (t1 - dx + dy2 - roundX) / dy2 : (t1 + dy - (roundY ^ 1)) / dy2; xc = (sx < 0) ? (x - t1) : (x + t1); if ((xc < r.xmin) || (xc > r.xmax)) return true; } if (swap) { dl.x1 = xc; dl.y1 = yc; } else { dl.x0 = xc; dl.y0 = yc; } return false; }
private void drawLine(int x0, int y0, int x1, int y1, boolean lastPixelFlag) { if (y0 == y1) { drawHLine(x0, x1, y0); return; } if (x0 == x1) { drawVLine(y0, y1, x0); return; } // Clip. Line sl = srcLine, dl = dstLine; // sl.x0=x0-translationX; sl.x1=x1-translationX; sl.y0=y0-translationY; // sl.y1=y1-translationY; sl.x0 = x0 + transX; sl.x1 = x1 + transX; sl.y0 = y0 + transY; sl.y1 = y1 + transY; if (clipLine(clipRectangle, sl, dl)) return; // Draw. { int x = dl.x0, y = dl.y0, w = dl.x1 - dl.x0, h = dl.y1 - dl.y0; int ex = dl.x0 - sl.x0, ey = dl.y0 - sl.y0; int dx = sl.x1 - sl.x0, dy = sl.y1 - sl.y0; int sx = 1, sy = 1; if (dx < 0) { dx = -dx; sx = -sx; ex = -ex; w = -w; } if (dy < 0) { dy = -dy; sy = -sy; ey = -ey; h = -h; } if (dx >= dy) { int decision = (ex + ex + 2) * dy - (ey + ey + 1) * dx; if (sx > 0) decision--; // Modify the decision variable for generating // the same pattern from left to right and right // to left. dx += dx; dy += dy; if (lastPixelFlag) w++; while (w > 0) { drawSpan(x, y, 1); if (decision >= 0) { decision -= dx; y += sy; } decision += dy; x += sx; w--; } } else { int decision = (ey + ey + 2) * dx - (ex + ex + 1) * dy; if (sy > 0) decision--; // Modify the decision variable for generating // the same pattern from bottom to top and top // to bottom. dx += dx; dy += dy; if (lastPixelFlag) h++; while (h > 0) { drawSpan(x, y, 1); if (decision >= 0) { decision -= dy; x += sx; } decision += dx; y += sy; h--; } } } }