001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.ext.awt.image.renderable;
020:
021: import java.awt.Graphics2D;
022: import java.awt.Rectangle;
023: import java.awt.RenderingHints;
024: import java.awt.Shape;
025: import java.awt.geom.AffineTransform;
026: import java.awt.geom.Point2D;
027: import java.awt.geom.Rectangle2D;
028: import java.awt.image.BufferedImage;
029: import java.awt.image.RenderedImage;
030: import java.awt.image.renderable.RenderContext;
031:
032: import org.apache.batik.ext.awt.RenderingHintsKeyExt;
033: import org.apache.batik.ext.awt.image.GraphicsUtil;
034: import org.apache.batik.ext.awt.image.rendered.AffineRed;
035: import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;
036: import org.apache.batik.ext.awt.image.rendered.CachableRed;
037: import org.apache.batik.ext.awt.image.rendered.TileRed;
038:
039: /**
040: * 8 bit TileRable implementation
041: *
042: * @author <a href="mailto:vhardy@apache.org">Vincent Hardy</a>
043: * @version $Id: TileRable8Bit.java 478276 2006-11-22 18:33:37Z dvholten $
044: */
045: public class TileRable8Bit extends AbstractColorInterpolationRable
046: implements TileRable {
047: /**
048: * Tile region
049: */
050: private Rectangle2D tileRegion;
051:
052: /**
053: * Tiled region
054: */
055: private Rectangle2D tiledRegion;
056:
057: /**
058: * Controls whether the tileRegion clips the source
059: * or not
060: */
061: private boolean overflow;
062:
063: /**
064: * Returns the tile region
065: */
066: public Rectangle2D getTileRegion() {
067: return tileRegion;
068: }
069:
070: /**
071: * Sets the tile region
072: */
073: public void setTileRegion(Rectangle2D tileRegion) {
074: if (tileRegion == null) {
075: throw new IllegalArgumentException();
076: }
077: touch();
078: this .tileRegion = tileRegion;
079: }
080:
081: /**
082: * Returns the tiled region
083: */
084: public Rectangle2D getTiledRegion() {
085: return tiledRegion;
086: }
087:
088: /**
089: * Sets the tiled region
090: */
091: public void setTiledRegion(Rectangle2D tiledRegion) {
092: if (tiledRegion == null) {
093: throw new IllegalArgumentException();
094: }
095: touch();
096: this .tiledRegion = tiledRegion;
097: }
098:
099: /**
100: * Returns the overflow strategy
101: */
102: public boolean isOverflow() {
103: return overflow;
104: }
105:
106: /**
107: * Sets the overflow strategy
108: */
109: public void setOverflow(boolean overflow) {
110: touch();
111: this .overflow = overflow;
112: }
113:
114: /**
115: * Default constructor
116: */
117: public TileRable8Bit(Filter source, Rectangle2D tiledRegion,
118: Rectangle2D tileRegion, boolean overflow) {
119: super (source);
120:
121: setTileRegion(tileRegion);
122: setTiledRegion(tiledRegion);
123: setOverflow(overflow);
124: }
125:
126: /**
127: * Sets the filter source
128: */
129: public void setSource(Filter src) {
130: init(src);
131: }
132:
133: /**
134: * Return's the tile source
135: */
136: public Filter getSource() {
137: return (Filter) srcs.get(0);
138: }
139:
140: /**
141: * Returns this filter's bounds
142: */
143: public Rectangle2D getBounds2D() {
144: return (Rectangle2D) tiledRegion.clone();
145: }
146:
147: public RenderedImage createRendering(RenderContext rc) {
148: // Just copy over the rendering hints.
149: RenderingHints rh = rc.getRenderingHints();
150: if (rh == null)
151: rh = new RenderingHints(null);
152:
153: // update the current affine transform
154: AffineTransform at = rc.getTransform();
155:
156: double sx = at.getScaleX();
157: double sy = at.getScaleY();
158:
159: double shx = at.getShearX();
160: double shy = at.getShearY();
161:
162: double tx = at.getTranslateX();
163: double ty = at.getTranslateY();
164:
165: // The Scale is the "hypotonose" of the matrix vectors.
166: double scaleX = Math.sqrt(sx * sx + shy * shy);
167: double scaleY = Math.sqrt(sy * sy + shx * shx);
168:
169: // System.out.println("AT: " + at);
170: // System.out.println("Scale: " + scaleX + "x" + scaleY);
171:
172: //
173: // Compute the actual tiled area (intersection of AOI
174: // and bounds) and the actual tile (anchored in the
175: // upper left corner of the tiled area
176: //
177:
178: // tiledRect
179: Rectangle2D tiledRect = getBounds2D();
180: Rectangle2D aoiRect;
181: Shape aoiShape = rc.getAreaOfInterest();
182: if (aoiShape == null)
183: aoiRect = tiledRect;
184: else {
185: aoiRect = aoiShape.getBounds2D();
186:
187: if (!tiledRect.intersects(aoiRect))
188: return null;
189: Rectangle2D.intersect(tiledRect, aoiRect, tiledRect);
190: }
191:
192: // tileRect
193: Rectangle2D tileRect = tileRegion;
194:
195: // Adjust the scale so that the tiling happens on pixel
196: // boundaries on both axis.
197: // Desired pixel rect width
198: int dw = (int) (Math.ceil(tileRect.getWidth() * scaleX));
199: int dh = (int) (Math.ceil(tileRect.getHeight() * scaleY));
200:
201: double tileScaleX = dw / tileRect.getWidth();
202: double tileScaleY = dh / tileRect.getHeight();
203:
204: // System.out.println("scaleX/scaleY : " + scaleX + " / " + scaleY);
205: // System.out.println("tileScaleX/tileScaleY : " + tileScaleX + " / " + tileScaleY);
206:
207: // Adjust the translation so that the tile's origin falls on
208: // pixel boundary
209: int dx = (int) Math.floor(tileRect.getX() * tileScaleX);
210: int dy = (int) Math.floor(tileRect.getY() * tileScaleY);
211:
212: double ttx = dx - (tileRect.getX() * tileScaleX);
213: double tty = dy - (tileRect.getY() * tileScaleY);
214:
215: // System.out.println("ttx/tty : " + ttx + " / " + tty);
216:
217: // Get result unsheared or rotated
218: AffineTransform tileAt;
219: // tileAt = AffineTransform.getScaleInstance(tileScaleX, tileScaleY);
220: // tileAt.translate(ttx, tty);
221: // System.out.println("Pt: " + tileAt.transform
222: // (new Point2D.Double(aoiRect.getX(),
223: // aoiRect.getY()), null));
224:
225: tileAt = AffineTransform.getTranslateInstance(ttx, tty);
226: tileAt.scale(tileScaleX, tileScaleY);
227:
228: // System.out.println("Pt: " + tileAt.transform
229: // (new Point2D.Double(aoiRect.getX(),
230: // aoiRect.getY()), null));
231:
232: // System.out.println("tileRect in userSpace : " + tileRect);
233: // System.out.println("tileRect in deviceSpace : " +
234: // tileAt.createTransformedShape(tileRect).
235: // getBounds2D());
236: Filter source = getSource();
237:
238: Rectangle2D srcRect;
239: if (overflow)
240: srcRect = source.getBounds2D();
241: else
242: srcRect = tileRect;
243:
244: // System.out.println("SrcRect: " + srcRect);
245:
246: RenderContext tileRc = new RenderContext(tileAt, srcRect, rh);
247: // RenderedImage tileRed = new DemandRed(source, tileRc);
248: RenderedImage tileRed = source.createRendering(tileRc);
249:
250: // System.out.println("TileRed: " +
251: // GraphicsUtil.wrap(tileRed).getBounds());
252:
253: // RenderedImage tileRed = createTile(tileRc);
254: // System.out.println("tileRed : " + tileRed.getMinX() + "/" + tileRed.getMinY() + "/"
255: // + tileRed.getWidth() + "/" + tileRed.getHeight());
256: if (tileRed == null)
257: return null;
258:
259: // System.out.println("aoiRect: " + aoiRect);
260:
261: Rectangle tiledArea = tileAt.createTransformedShape(aoiRect)
262: .getBounds();
263:
264: // Serious hack alert!!!
265: // In some cases the bounds are set to cover the whole area.
266: // when they get scaled up sometimes the lower bounds go
267: // to Integer.MIN_VALUE, and width/height to Integer.MAX_VALUE,
268: // but this only covers the negative quarter of the canvas!!!
269: // So if width and height are MAX_VALUE then we assume this
270: // clipping has happened and we recenter the range.
271: // Yes this is a serious hack and I appologies for it.
272: // I wouldn't need to do this if PatternPaintContext knew
273: // what it's bounds were going to be....
274: if ((tiledArea.width == Integer.MAX_VALUE)
275: || (tiledArea.height == Integer.MAX_VALUE)) {
276: tiledArea = new Rectangle(Integer.MIN_VALUE / 4,
277: Integer.MIN_VALUE / 4, Integer.MAX_VALUE / 2,
278: Integer.MAX_VALUE / 2);
279: }
280: // System.out.println("tiledArea: " + tiledArea);
281: tileRed = convertSourceCS(tileRed);
282: TileRed tiledRed = new TileRed(tileRed, tiledArea, dw, dh);
283:
284: // org.apache.batik.test.gvt.ImageDisplay.showImage("Tile", tiledRed);
285: // System.out.println("TileR: " + tiledRed.getBounds());
286:
287: // Return sheared/rotated tiled image
288: AffineTransform shearAt = new AffineTransform(sx / scaleX, shy
289: / scaleX, shx / scaleY, sy / scaleY, tx, ty);
290: shearAt.scale(scaleX / tileScaleX, scaleY / tileScaleY);
291:
292: shearAt.translate(-ttx, -tty);
293:
294: CachableRed cr = tiledRed;
295: if (!shearAt.isIdentity())
296: cr = new AffineRed(tiledRed, shearAt, rh);
297:
298: // System.out.println("AffineR: " + cr.getBounds());
299:
300: return cr;
301: }
302:
303: public Rectangle2D getActualTileBounds(Rectangle2D tiledRect) {
304: // Get the tile rectangle in user space
305: Rectangle2D tileRect = (Rectangle2D) tileRegion.clone();
306:
307: // System.out.println("tileRect : " + tileRect);
308: // System.out.println("tiledRect: " + tiledRect);
309:
310: if ((tileRect.getWidth() <= 0) || (tileRect.getHeight() <= 0)
311: || (tiledRect.getWidth() <= 0)
312: || (tiledRect.getHeight() <= 0))
313: return null;
314:
315: double tileWidth = tileRect.getWidth();
316: double tileHeight = tileRect.getHeight();
317:
318: double tiledWidth = tiledRect.getWidth();
319: double tiledHeight = tiledRect.getHeight();
320:
321: double w = Math.min(tileWidth, tiledWidth);
322: double h = Math.min(tileHeight, tiledHeight);
323:
324: Rectangle2D realTileRect = new Rectangle2D.Double(tileRect
325: .getX(), tileRect.getY(), w, h);
326:
327: return realTileRect;
328: }
329:
330: /**
331: * Computes the tile to use for the tiling operation.
332: *
333: * The tile has its origin in the upper left
334: * corner of the tiled region. That tile is separated
335: * into 4 areas: top-left, top-right, bottom-left and
336: * bottom-right. Each of these areas is mapped to
337: * some input area from the source.
338: * If the source is smaller than the tiled area, then
339: * a single rendering is requested from the source.
340: * If the source's width or height is bigger than that
341: * of the tiled area, then separate renderings are
342: * requested from the source.
343: *
344: */
345: public RenderedImage createTile(RenderContext rc) {
346: AffineTransform usr2dev = rc.getTransform();
347:
348: // Hints
349: RenderingHints rcHints = rc.getRenderingHints();
350: RenderingHints hints = new RenderingHints(null);
351: if (rcHints != null) {
352: hints.add(rcHints);
353: }
354:
355: // The region actually tiles is the intersection
356: // of the tiledRegion and the area of interest
357: Rectangle2D tiledRect = getBounds2D();
358: Shape aoiShape = rc.getAreaOfInterest();
359: Rectangle2D aoiRect = aoiShape.getBounds2D();
360: if (!tiledRect.intersects(aoiRect))
361: return null;
362: Rectangle2D.intersect(tiledRect, aoiRect, tiledRect);
363:
364: // Get the tile rectangle in user space
365: Rectangle2D tileRect = (Rectangle2D) tileRegion.clone();
366:
367: // System.out.println("tileRect : " + tileRect);
368: // System.out.println("tiledRect: " + tiledRect);
369:
370: if ((tileRect.getWidth() <= 0) || (tileRect.getHeight() <= 0)
371: || (tiledRect.getWidth() <= 0)
372: || (tiledRect.getHeight() <= 0))
373: return null;
374:
375: //
376: // (tiledX, tiledY)
377: // <------- min(tileWidth, tiledWidth) ----------->
378: // ^ +------+-------------------------------------+
379: // | + A' + B' +
380: // | +------+-------------------------------------+
381: // min(tileHeight, | + + +
382: // tiledHeight) | + + +
383: // | + C' + D' +
384: // | + + +
385: // ^ +------+-------------------------------------+
386: //
387: // Maps to, in the tile:
388: //
389: // (tileX, tileY)
390: //
391: // <----------- tileWidth --------------->
392: // ^ +-----------------------------+------+-------+
393: // | + + + |
394: // tiledHeight | + + + |
395: // | + D + + C |
396: // | + + + |
397: // | +-----------------------------+------+-------|
398: // | + | | |
399: // | + | | |
400: // | +-----------------------------+------+-------+
401: // | | B + + A |
402: // ^ +-----------------------------+------+-------+
403:
404: // w = min(tileWidth, tiledWidth)
405: // h = min(tileHeight, tiledHeight)
406: // dx = tileWidth - (tiledX - tileX)%tileWidth;
407: // dy = tileHeight - (tiledY - tileY)%tileHeight;
408: //
409: // A = (tileX + tileWidth - dx, tileY + tileHeight - dy, dx, dy)
410: // B = (tileX, tileY + tileHeight - dy, w - dx, dy)
411: // C = (tileX + tileWidth - dx, tileY, dx, h - dy)
412: // D = (tileX, tileY, w - dx, h - dy)
413:
414: double tileX = tileRect.getX();
415: double tileY = tileRect.getY();
416: double tileWidth = tileRect.getWidth();
417: double tileHeight = tileRect.getHeight();
418:
419: double tiledX = tiledRect.getX();
420: double tiledY = tiledRect.getY();
421: double tiledWidth = tiledRect.getWidth();
422: double tiledHeight = tiledRect.getHeight();
423:
424: double w = Math.min(tileWidth, tiledWidth);
425: double h = Math.min(tileHeight, tiledHeight);
426: double dx = (tiledX - tileX) % tileWidth;
427: double dy = (tiledY - tileY) % tileHeight;
428:
429: if (dx > 0) {
430: dx = tileWidth - dx;
431: } else {
432: dx *= -1;
433: }
434:
435: if (dy > 0) {
436: dy = tileHeight - dy;
437: } else {
438: dy *= -1;
439: }
440:
441: //
442: // Adjust dx and dy so that they fall on a pixel boundary
443: //
444: double scaleX = usr2dev.getScaleX();
445: double scaleY = usr2dev.getScaleY();
446: double tdx = Math.floor(scaleX * dx);
447: double tdy = Math.floor(scaleY * dy);
448:
449: dx = tdx / scaleX;
450: dy = tdy / scaleY;
451:
452: // System.out.println("dx / dy / w / h : " + dx + " / " + dy + " / " + w + " / " + h);
453:
454: Rectangle2D.Double A = new Rectangle2D.Double(tileX + tileWidth
455: - dx, tileY + tileHeight - dy, dx, dy);
456: Rectangle2D.Double B = new Rectangle2D.Double(tileX, tileY
457: + tileHeight - dy, w - dx, dy);
458: Rectangle2D.Double C = new Rectangle2D.Double(tileX + tileWidth
459: - dx, tileY, dx, h - dy);
460: Rectangle2D.Double D = new Rectangle2D.Double(tileX, tileY, w
461: - dx, h - dy);
462:
463: Rectangle2D realTileRect = new Rectangle2D.Double(tiledRect
464: .getX(), tiledRect.getY(), w, h);
465:
466: // System.out.println("A rect : " + A);
467: // System.out.println("B rect : " + B);
468: // System.out.println("C rect : " + C);
469: // System.out.println("D rect : " + D);
470: // System.out.println("realTileR : " + realTileRect);
471:
472: // A, B, C and D are the four user space are that make the
473: // tile that will be used. We create a rendering for each of
474: // these areas that i s not empty (i.e., with either width or
475: // height equal to zero)
476: RenderedImage ARed = null, BRed = null, CRed = null, DRed = null;
477: Filter source = getSource();
478:
479: if (A.getWidth() > 0 && A.getHeight() > 0) {
480: // System.out.println("Rendering A");
481: Rectangle devA = usr2dev.createTransformedShape(A)
482: .getBounds();
483: if (devA.width > 0 && devA.height > 0) {
484: AffineTransform ATxf = new AffineTransform(usr2dev);
485: ATxf.translate(-A.x + tiledX, -A.y + tiledY);
486:
487: Shape aoi = A;
488: if (overflow) {
489: aoi = new Rectangle2D.Double(A.x, A.y, tiledWidth,
490: tiledHeight);
491: }
492:
493: hints.put(RenderingHintsKeyExt.KEY_AREA_OF_INTEREST,
494: aoi);
495:
496: RenderContext arc = new RenderContext(ATxf, aoi, hints);
497:
498: ARed = source.createRendering(arc);
499:
500: //System.out.println("ARed : " + ARed.getMinX() + " / " +
501: // ARed.getMinY() + " / " +
502: // ARed.getWidth() + " / " +
503: // ARed.getHeight());
504: }
505: }
506:
507: if (B.getWidth() > 0 && B.getHeight() > 0) {
508: // System.out.println("Rendering B");
509: Rectangle devB = usr2dev.createTransformedShape(B)
510: .getBounds();
511: if (devB.width > 0 && devB.height > 0) {
512: AffineTransform BTxf = new AffineTransform(usr2dev);
513: BTxf.translate(-B.x + (tiledX + dx), -B.y + tiledY);
514:
515: Shape aoi = B;
516: if (overflow) {
517: aoi = new Rectangle2D.Double(B.x - tiledWidth + w
518: - dx, B.y, tiledWidth, tiledHeight);
519: }
520:
521: hints.put(RenderingHintsKeyExt.KEY_AREA_OF_INTEREST,
522: aoi);
523:
524: RenderContext brc = new RenderContext(BTxf, aoi, hints);
525:
526: BRed = source.createRendering(brc);
527: // System.out.println("BRed : " + BRed.getMinX() + " / " + BRed.getMinY() + " / " + BRed.getWidth() + " / " + BRed.getHeight());
528: }
529: }
530:
531: if (C.getWidth() > 0 && C.getHeight() > 0) {
532: // System.out.println("Rendering C");
533: Rectangle devC = usr2dev.createTransformedShape(C)
534: .getBounds();
535: if (devC.width > 0 && devC.height > 0) {
536: AffineTransform CTxf = new AffineTransform(usr2dev);
537: CTxf.translate(-C.x + tiledX, -C.y + (tiledY + dy));
538:
539: Shape aoi = C;
540: if (overflow) {
541: aoi = new Rectangle2D.Double(C.x, C.y - tileHeight
542: + h - dy, tiledWidth, tiledHeight);
543: }
544:
545: hints.put(RenderingHintsKeyExt.KEY_AREA_OF_INTEREST,
546: aoi);
547:
548: RenderContext crc = new RenderContext(CTxf, aoi, hints);
549:
550: CRed = source.createRendering(crc);
551: // System.out.println("CRed : " + CRed.getMinX() + " / " + CRed.getMinY() + " / " + CRed.getWidth() + " / " + CRed.getHeight());
552: }
553: }
554:
555: if (D.getWidth() > 0 && D.getHeight() > 0) {
556: // System.out.println("Rendering D");
557: Rectangle devD = usr2dev.createTransformedShape(D)
558: .getBounds();
559: if (devD.width > 0 && devD.height > 0) {
560: AffineTransform DTxf = new AffineTransform(usr2dev);
561: DTxf.translate(-D.x + (tiledX + dx), -D.y
562: + (tiledY + dy));
563:
564: Shape aoi = D;
565: if (overflow) {
566: aoi = new Rectangle2D.Double(D.x - tileWidth + w
567: - dx, D.y - tileHeight + h - dy,
568: tiledWidth, tiledHeight);
569: }
570:
571: hints.put(RenderingHintsKeyExt.KEY_AREA_OF_INTEREST,
572: aoi);
573:
574: RenderContext drc = new RenderContext(DTxf, aoi, hints);
575:
576: DRed = source.createRendering(drc);
577: // System.out.println("DRed : " + DRed.getMinX() + " / " + DRed.getMinY() + " / " + DRed.getWidth() + " / " + DRed.getHeight());
578: }
579: }
580:
581: //
582: // Now, combine ARed, BRed, CRed and DRed into a single
583: // RenderedImage that will be tiled
584: //
585: final Rectangle realTileRectDev = usr2dev
586: .createTransformedShape(realTileRect).getBounds();
587:
588: if (realTileRectDev.width == 0 || realTileRectDev.height == 0) {
589: return null;
590: }
591:
592: BufferedImage realTileBI = new BufferedImage(
593: realTileRectDev.width, realTileRectDev.height,
594: BufferedImage.TYPE_INT_ARGB);
595:
596: Graphics2D g = GraphicsUtil.createGraphics(realTileBI, rc
597: .getRenderingHints());
598: // g.setPaint(new java.awt.Color(0, 255, 0, 64));
599: // g.fillRect(0, 0, realTileBI.getWidth(), realTileBI.getHeight());
600: g.translate(-realTileRectDev.x, -realTileRectDev.y);
601:
602: // System.out.println("realTileRectDev " + realTileRectDev);
603:
604: AffineTransform redTxf = new AffineTransform();
605: Point2D.Double redVec = new Point2D.Double();
606: RenderedImage refRed = null;
607: if (ARed != null) {
608: // System.out.println("Drawing A");
609: g.drawRenderedImage(ARed, redTxf);
610: refRed = ARed;
611: }
612: if (BRed != null) {
613: // System.out.println("Drawing B");
614:
615: if (refRed == null) {
616: refRed = BRed;
617: }
618:
619: // Adjust B's coordinates
620: redVec.x = dx;
621: redVec.y = 0;
622: usr2dev.deltaTransform(redVec, redVec);
623: redVec.x = Math.floor(redVec.x)
624: - (BRed.getMinX() - refRed.getMinX());
625: redVec.y = Math.floor(redVec.y)
626: - (BRed.getMinY() - refRed.getMinY());
627:
628: // System.out.println("BRed adjust : " + redVec);
629:
630: // redTxf.setToTranslation(redVec.x, redVec.y);
631: g.drawRenderedImage(BRed, redTxf);
632: }
633: if (CRed != null) {
634: // System.out.println("Drawing C");
635:
636: if (refRed == null) {
637: refRed = CRed;
638: }
639:
640: // Adjust C's coordinates
641: redVec.x = 0;
642: redVec.y = dy;
643: usr2dev.deltaTransform(redVec, redVec);
644: redVec.x = Math.floor(redVec.x)
645: - (CRed.getMinX() - refRed.getMinX());
646: redVec.y = Math.floor(redVec.y)
647: - (CRed.getMinY() - refRed.getMinY());
648:
649: // System.out.println("CRed adjust : " + redVec);
650:
651: // redTxf.setToTranslation(redVec.x, redVec.y);
652: g.drawRenderedImage(CRed, redTxf);
653: }
654: if (DRed != null) {
655: // System.out.println("Drawing D");
656:
657: if (refRed == null) {
658: refRed = DRed;
659: }
660:
661: // Adjust D's coordinates
662: redVec.x = dx;
663: redVec.y = dy;
664: usr2dev.deltaTransform(redVec, redVec);
665: redVec.x = Math.floor(redVec.x)
666: - (DRed.getMinX() - refRed.getMinX());
667: redVec.y = Math.floor(redVec.y)
668: - (DRed.getMinY() - refRed.getMinY());
669:
670: // System.out.println("DRed adjust : " + redVec);
671:
672: // redTxf.setToTranslation(redVec.x, redVec.y);
673: g.drawRenderedImage(DRed, redTxf);
674: }
675:
676: CachableRed realTile;
677: realTile = new BufferedImageCachableRed(realTileBI,
678: realTileRectDev.x, realTileRectDev.y);
679:
680: return realTile;
681: }
682: }
|