/* GNU General Public License CacheWolf is a software for PocketPC, Win and Linux that enables paperless caching. It supports the sites geocaching.com and opencaching.de Copyright (C) 2006 CacheWolf development team See http://www.cachewolf.de/ for more information. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package CacheWolf.navi; import CacheWolf.database.CoordinatePoint; import ewe.fx.Color; import ewe.fx.Graphics; import ewe.fx.IImage; import ewe.fx.Image; import ewe.fx.Point; import ewe.util.Vector; public class TrackOverlay extends MapImage { public CoordinatePoint topLeft; public CoordinatePoint bottomRight; Graphics draw; Graphics drawMask; int test; MapInfoObject trans; Point pixelShift; public Vector tracks; boolean imageChangesDontShow = false; public Point trackPixels[] = null; public Color trackPixelsColor[] = null; public int numPixels = 0; final static int maxPixelsInCache = 100; final static Color transparentColorForOverlay = Color.White; // only for use when transparent color is used static boolean useTransparentColor; public TrackOverlay(CoordinatePoint topLefti, int widthi, int highti, MapInfoObject transi) { super(); topLeft = new CoordinatePoint(topLefti); trans = transi; pixelShift = trans.calcMapXY(topLeft); bottomRight = trans.calcLatLon(widthi + pixelShift.x, highti + pixelShift.y); if (ewe.sys.Vm.getPlatform().equalsIgnoreCase("java")) { useTransparentColor = true; // java-vm: transparency with a mask is very memory consuming, but transparency with a mask is much faster in ewe-vm and doesn't consume more memory than a transparency color (ewe 1.49) setImage(new Image(widthi, highti), transparentColorForOverlay); } else { useTransparentColor = false; // // momentanously this it not used, but this is only because ewe treats areas as opaque which has a non white color in the image, so that the mask doesn't need to be changed Image maski = new Image(widthi, highti); drawMask = new Graphics(maski); drawMask.setColor(Color.White); drawMask.fillRect(0, 0, maski.getWidth(), maski.getHeight()); setImage(new Image(widthi, highti), maski); // java-vm: transparency with a mask is very memory consuming, but transparency with a mask is much faster in ewe-vm and doesn't consume more memory than a transparency color (ewe 1.49) maski.free(); //setimage produces an inverted copy of the mask maski = null; } //properties = AlwaysOnTop; // arrows are above, so dont set it. draw = new Graphics(image); draw.setDrawOp(Graphics.DRAW_OVER); if (useTransparentColor) draw.setColor(transparentColorForOverlay); else draw.setColor(Color.White); draw.fillRect(0, 0, widthi, highti); //int[] markImage = {0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000}; //int[] markMaskOpaque = {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; //mask.setPixels( markMaskOpaque, 0, 50, 50, 2, 2, 0); //draw.fillRectRGB(50, 50, 52, 52, 0x00ff0000); // fillRectRGB has a Bug - it never returns - use fillRect instead //image.setPixels(markImage, 0, 50, 50, 2, 2, 0); // out of an to me unkwon reason this doesn't work here, but it does in painttracks } public void imageSet() // ================================================================== { IImage i = drawable; if (i == null) i = image; if (i != null) { location.width = i.getWidth(); location.height = i.getHeight(); } if (image != null && image != sourceImage) image.freeze(); // if (mask != null && mask != sourceMask) mask.freeze(); // dont freeze the mask, it could change. Anyway momentanously it doesnt change, because when the image contains non-white in the opaque areas, it will be opaque without changing the mask properties &= ~HasChanged; } public void paintTracks() { // for debugging TrackOverlayPositions // draw.setPen(new Pen(Color.LightBlue,Pen.SOLID,1)); // draw.fillRect(1, 1, image.getWidth()-1, image.getHeight()-1); //draw.setColor(255,0,0); //draw.setPen(new Pen(new Color(255,0,0),Pen.SOLID,3)); //draw.fillRect(50, 50, 4, 4); // fillRectRGB has a Bug - it never returns - use fillRect instead if (tracks == null || tracks.size() == 0) return; int tri, i; Track tr; int numberOfTracks = tracks.size(); int numberOfPoints = ((Track) tracks.get(numberOfTracks - 1)).size(); if (numberOfTracks > 1) { numberOfPoints += (numberOfTracks - 1) * ((Track) tracks.get(0)).size(); } int n = 0; for (tri = 0; tri < numberOfTracks; tri++) { tr = (Track) tracks.get(tri); //draw.setPen(new Pen((Color) tr.trackColor,Pen.SOLID,3)); draw.setColor(tr.trackColor); if (tr.size() > 0) { for (i = 0; i < tr.size(); i++) { n++; if ((numberOfPoints - n > 5 * 60) && ((n & 1) == 0)) continue; if ((numberOfPoints - n > 15 * 60) && ((n & 2) == 0)) continue; if ((numberOfPoints - n > 30 * 60) && ((n & 4) == 0)) continue; paintPoint(tr.trackColor, tr.get(i)); } } } } /** * * @param f * @param lat * @param lon * @return true if point was on this overlay */ public boolean paintPoint(Color f, CoordinatePoint where) { if (where.latDec < bottomRight.latDec || where.latDec > topLeft.latDec || where.lonDec < topLeft.lonDec || where.lonDec > bottomRight.lonDec) return false; Point p = trans.calcMapXY(where); int x = p.x - pixelShift.x; int y = p.y - pixelShift.y; draw.fillRect(x - 1, y - 1, 3, 3); if (imageChangesDontShow) { try { addPixelIfNeccessary(x, y, f); } catch (IndexOutOfBoundsException e) // thrown when there are more than pixels stored than possible { fixate(); } } return true; } /** * this method forces ewe to transfer the drawn points * from _awtImage to bufferedImage, which is drawn to the screen * */ private void fixate() { if (numPixels == 0) return; // draw.drawImage(image,null,Color.DarkBlue,0,0,location.width,location.height); // changing the mask forces graphics to copy from image._awtImage to image.bufferedImage, which is displayed draw.drawImage(image, null, Color.Pink, 0, 0, 1, 1); // width and height is anyway ignored, evtl. testen, imageChangesDontShow = false; removeAllPixels(); } private void removeAllPixels() { numPixels = 0; trackPixels = null; trackPixelsColor = null; } public void addPixel(int x, int y, Color f) throws IndexOutOfBoundsException { if (trackPixels == null) { trackPixels = new Point[maxPixelsInCache]; trackPixelsColor = new Color[maxPixelsInCache]; } trackPixels[numPixels] = new Point(x, y); // IndexOutOfBoundsException is handled in PaintPoint trackPixelsColor[numPixels] = f.getCopy(); numPixels++; } public void addPixelIfNeccessary(int x, int y, Color f) { if (trackPixels != null) { int ll = (numPixels < 30 ? 0 : numPixels - 30); // look in the last 50 added Pixels if the same Pixel is already in the list (for performance reasons dont look in the whole list) for (int i = numPixels - 1; i >= ll; i--) { if (trackPixels[i].x == x && trackPixels[i].y == y && f.equals(trackPixelsColor[i])) { return; } } } addPixel(x, y, f); } public static final int FIXATE_IF_NO_PIXELS_NUM = 60; private int notOnThisOverlaySince = 0; public void paintLastAddedPoint(Track tr) { //draw.setPen(new Pen((Color) tr.trackColor,Pen.SOLID,3)); draw.setColor(tr.trackColor); if (paintPoint(tr.trackColor, tr.get(tr.size() - 1))) notOnThisOverlaySince = 0; else notOnThisOverlaySince++; if (notOnThisOverlaySince > FIXATE_IF_NO_PIXELS_NUM) { // zur Performanceverbesserung: wenn in den letzten 60 Updates keines mehr f�r dieses Overlay dabei war, Overlay Pixels fest schreiben, damit doDraw entlastet wird. fixate(); notOnThisOverlaySince = 0; } } public void doDraw(Graphics g, int options) { // this is automatically called when the image need to be (re-)drawn on the screen super.doDraw(g, options); imageChangesDontShow = true; // g.drawImage (in super) copies _awtImage into bufferedImage, any later changes to _awtImage dont show up until the mask or the image has changed - unfortunately bufferedImage is not accessable from outside // draw trackpoints which were added after image changes don't show up on the screen if (tracks == null || tracks.size() == 0) return; int i; for (i = 0; i < numPixels; i++) { g.setColor(trackPixelsColor[i]); g.fillRect(trackPixels[i].x - 1, trackPixels[i].y - 1, 3, 3); } //g.drawText(Convert.toString(test), 10, 10); //g.drawRect(10 + test, 10, 10, 10); //test++; } } /* draw zeichnet auf _awtImage * image.drawImage erzeugt bufferedImage, wenn es vorher null war * und kopiert den entsprechenden Teil in das �bergebene Surface * Das Problem ist, dass bufferedImage nicht mehr upgedatet wird, wenn * es einmal erzugt wurde. Es wird nur dann upgedatet, wenn das Image ein anderes wird * oder die Maske eine andere. Das Update erfolgt dann �ber doDraw, was doCheckMask aufruft, * das das eigentliche kopieren aus _awtImage vornimmt. * * Problem: das kopieren von _awtImage in BufferedImage ist sehr zeitaufw�ndig, weil * es keine native Routine ist und jedes Pixel einzeln gepr�ft wird. * Deswegen w�re die beste L�sung, wenn ich bufferedImage direkt updaten k�nnte. * Aber bufferedImage ist privat, ich kann auch in abgeleiteten Klassen nicht drauf * zugreifen. * * Zur Not w�re auch denkbar, doDraw zu �berschreiben, um bei jedem Aufruf alle * Trackpoints neu zu zeichnen. * Work-Aorund: draw.drawImage(image,null,Color.Pink,0,0,1,1); bewirkt, dass awtImage ins * bufferedImage kopiert wird. Dabei wird die transparentColor (in mImage) nicht ge�ndert * und beim Aufruf von doDraw wird wieder die urspr�ngliche transparentColor verwendet * */ //was alles nicht funktioniert: //drawmask.setDrawOp(Graphics.DRAW_OVER); //drawmask.drawRect(x-1, y-1, 2, 2, 1); //this.setImage(image, mask); //n�chster Versuch: image.bufferedImage in ewe.fx.Image public definieren !!! //image.rgb //draw._g.surfaceData.bufImg.raster.data[y*this.location.width + x] = -65536; := image._awtImage //((Image)image).eImage(colorOrMask)._awtImage.raster.data[0]=0; //image //((BufferedImage)(image).se.^.bufferedImage.raster.data[y*this.location.width + x]=-65536; //was dort steht wird tats�chlich angezeigt, allerdings kann ich es nicht direkt setzen :-( //int[] markPixels = new int[4]; //for (int i = 0; i<markPixels.length; i++) { markPixels[i] = -65536; } //image.transparent = null; hilft auhc nicht //image.mask = null; //image.bufferedImage = null; //image.setPixels(markPixels, 0 , x-20, y, 2, 2, 0); // dadrin sollte bufferedImage = null gesetzt werden, wird es aber nicht :-( //ewe.fx.mImage mark = new mImage(); //Image mark = new Image(2,2); //new Graphics(mark).drawImage(image, null, transparentColor, x-40, y, 2, 2); //mark.draw(draw, x-50, y, Graphics.DRAW_OVER); // options (Graphics.DRAW_OVER) are ignored anyway //image.bufferedImage = null; // this solves the problem //toCursor(null); //this.draw(draw); //image=(BufferedImage)this.toNativeImage(transparentColor); //(java.awt.Image.b) //image.bufferedImage=null; //draw.flush(); //ewe.ui.PenEvent.refreshTip(draw.surface); //draw.setPixelRGB(x, y, -65536); //this.changed(); hilft auch nicht //this.refresh(); // hilft nicht :-( //lastDrawn.x = lastDrawn.x -10; hilft auch nicht //imageMayChange = true; // hilft auch nicht :-( /* * In der ewe-VM f�r PocketPC-ARM funktioniert die Festlegung einer * transparenten Farbe nicht (Hintergrund wird wei� statt durchsichtig) * deswegen (und weil in ewe-VM effizienter) Umstellung auf Transparenzmaske * statt transparenter Farbe * TODO Dies ist in Java-VM allerdings extrem Speicher fressend -> evtl abfragen static int fixMask(WObject image,WObject col,int isMask): in Maske: 0 an durchsichtiger Stelle, sonst ff in Image: ffffff an durchsichtiger Stelle in java-VM in Maske: ffffffff in image.mask, wenn nicht durchsichtig ff000000 an durchsichtiger Stelle image.doCheckMask erzeugt ein Image mit 0 an den durchsichtigen Stellen, die dadurch definiert sind, dass im image 0xffffff und in (mask & 0xffffff == 0) steht. */ /* * this class is only needed to have a fast access to the list of pixels * which are added but aniimage.draw will not lead to a change on the screen * so that these pixels will be drawn seperately by doDraw * */