new IntegerSequence(destMinY, destMaxY);
ySplits.insert(destMinY);
ySplits.insert(destMaxY);
// Overlay the forward-mapped source tile grid
PlanarImage src = getSource(0);
int sMinX = src.getMinX();
int sMinY = src.getMinY();
int sWidth = src.getWidth();
int sHeight = src.getHeight();
int sMaxX = sMinX + sWidth - 1;
int sMaxY = sMinY + sHeight - 1;
int sTileWidth = src.getTileWidth();
int sTileHeight = src.getTileHeight();
int sTileGridXOffset = src.getTileGridXOffset();
int sTileGridYOffset = src.getTileGridYOffset();
int xStart = 0;
int xGap = 0;
int yStart = 0;
int yGap = 0;
// Insert splits from source image.
//
// We can think of the splits as forming an infinite sequence
// xStart + kx*xGap, yStart + ky*yGap, where kx and ky range
// over all integers, negative and positive.
// Forward map the source tile grid origin Note that in cases
// where an axis is "flipped" an adjustment must be made. For
// example, consider flipping an image horizontally.
// If the image has a tile X origin of 0, a tile width
// of 50, and a total width of 100, then forward mapping the
// points (0, 0) and (50, 0) yields the points (99, 0) and
// (49, 0). In the original image, the tile split lines lay
// to the left of the pixel; in the flipped image, they lie
// to the right of the forward mapped pixels. Thus 1 must
// be added to the forward mapped pixel position to get the
// correct split location.
int[] pt = new int[2];
pt[0] = sTileGridXOffset;
pt[1] = sTileGridYOffset;
mapPoint(pt, sMinX, sMinY, sMaxX, sMaxY, type, true);
xStart = pt[0];
yStart = pt[1];
// Forward map the input tile size
switch (type) {
case 0: // FLIP_VERTICAL
++yStart;
xGap = sTileWidth;
yGap = sTileHeight;
break;
case 1: // FLIP_HORIZONTAL
++xStart;
xGap = sTileWidth;
yGap = sTileHeight;
break;
case 2: // FLIP_DIAGONAL
xGap = sTileHeight;
yGap = sTileWidth;
break;
case 3: // FLIP_ANTIDIAGONAL
++xStart;
++yStart;
xGap = sTileHeight;
yGap = sTileWidth;
break;
case 4: // ROTATE_90
++xStart;
xGap = sTileHeight;
yGap = sTileWidth;
break;
case 5: // ROTATE_180
++xStart;
++yStart;
xGap = sTileWidth;
yGap = sTileHeight;
break;
case 6: // ROTATE_270
++yStart;
xGap = sTileHeight;
yGap = sTileWidth;
break;
}
// Now we identify the source splits that intersect
// the destination rectangle and merge them in.
int kx = (int)Math.floor((double)(destMinX - xStart)/xGap);
int xSplit = xStart + kx*xGap;
while (xSplit < destMaxX) {
xSplits.insert(xSplit);
xSplit += xGap;
}
int ky = (int)Math.floor((double)(destMinY - yStart)/yGap);
int ySplit = yStart + ky*yGap;
while (ySplit < destMaxY) {
ySplits.insert(ySplit);
ySplit += yGap;
}
// Allocate memory for source Rasters.
Raster[] sources = new Raster[1];
//
// Divide destRect into sub rectangles based on the source
// splits, and compute each sub rectangle separately.
//
int x1, x2, y1, y2, w, h;
Rectangle subRect = new Rectangle();
ySplits.startEnumeration();
for (y1 = ySplits.nextElement(); ySplits.hasMoreElements(); y1 = y2) {
y2 = ySplits.nextElement();
h = y2 - y1;
xSplits.startEnumeration();
for (x1 = xSplits.nextElement();
xSplits.hasMoreElements(); x1 = x2) {
x2 = xSplits.nextElement();
w = x2 - x1;
// Get sources
// Backwards map the starting destination point
pt[0] = x1;
pt[1] = y1;
mapPoint(pt, sMinX, sMinY, sMaxX, sMaxY, type, false);
// Determine the source tile involved
int tx = src.XToTileX(pt[0]);
int ty = src.YToTileY(pt[1]);
sources[0] = src.getTile(tx, ty);
subRect.x = x1;
subRect.y = y1;
subRect.width = w;
subRect.height = h;