/* * @(#)MapCanvas.java - MapCanvas with MapScroller as inner class * * * This software was developed by the Thermal Modeling and Analysis * Project(TMAP) of the National Oceanographic and Atmospheric * Administration's (NOAA) Pacific Marine Environmental Lab(PMEL), * hereafter referred to as NOAA/PMEL/TMAP. * * Access and use of this software shall impose the following * obligations and understandings on the user. The user is granted the * right, without any fee or cost, to use, copy, modify, alter, enhance * and distribute this software, and any derivative works thereof, and * its supporting documentation for any purpose whatsoever, provided * that this entire notice appears in all copies of the software, * derivative works and supporting documentation. Further, the user * agrees to credit NOAA/PMEL/TMAP in any publications that result from * the use of this software or in any product that includes this * software. The names TMAP, NOAA and/or PMEL, however, may not be used * in any advertising or publicity to endorse or promote any products * or commercial entity unless specific written permission is obtained * from NOAA/PMEL/TMAP. The user also understands that NOAA/PMEL/TMAP * is not obligated to provide the user with any support, consulting, * training or assistance of any kind with regard to the use, operation * and performance of this software nor to provide the user with any * updates, revisions, new versions or "bug fixes". * * THIS SOFTWARE IS PROVIDED BY NOAA/PMEL/TMAP "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL NOAA/PMEL/TMAP BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE. * */ package dods.clients.importwizard.TMAP.map; //1.1 import java.awt.AWTEvent; //Change to jdk1.3 import java.awt.*; import javax.swing.*; //import java.awt.Canvas; //import java.awt.Container; //import java.awt.Color; //import java.awt.Cursor; //import java.awt.Dimension; //import java.awt.Graphics; //import java.awt.Image; //import java.awt.Rectangle; //import java.awt.Frame; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.ImageProducer; import java.awt.image.FilteredImageSource; import java.awt.image.ImageFilter; import java.awt.image.RGBImageFilter; import java.awt.MediaTracker; //import dods.clients.importwizard.TMAP.map.MapConstants; //import dods.clients.importwizard.TMAP.map.MaxZoomException; //import dods.clients.importwizard.TMAP.map.MinZoomException; /** * An extensible Canvas class for obtaining/displaying 2D coordinates. * <p> * This canvas has a base image and uses a tool to get/set coordinates * on the base image. * <p> * This is the second official release (version 2) of the MapCanvas. * It includes zoom/pan/scroll and snap-to-grid capabilities. * * @version 2.2, 17 June 1997 * @author Jonathan Callahan * * Note: Using a tool to select 360 degrees of longitude will result * in <code>user_x[HI] = user_x[LO]+360</code> where user_x[LO] is * correctly interpolated into the domain of the x axis. Thus, * user_x[HI] will be outside the domain of the x axis specified * in MapGrid. */ /** * Modified to a JLabel class * * modified by Sheila (zhifang) Jiang * */ //-------------------------------------------------------------------------- public class MapCanvas extends JLabel //Canvas implements MapConstants, MouseListener, MouseMotionListener { MapScroller scroller; Image base_image, gray_image; ImageIcon image_icon; Dimension offDimension; Image offImage; Graphics offGraphics; int width; int height; int clip_width; int clip_height; double image_scaling = 1.0; Rectangle imageRect = new Rectangle(0, 0, 0, 0); // suspended/resume private boolean scrollSuspended; // scrolling rate in panning() private int slow_delta=1; private int fast_delta=5; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_down = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_down_fast = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_left = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_left_fast = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_right = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_right_fast = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_up = false; /** * Flag to indicate movement of the base image is desired. */ public boolean pan_up_fast = false; /** * Flag determining whether scrolling is controlled by the active MapTool * or externally by the application programmer. */ public boolean tool_driven = true; /** * The zoom factor to be applied when using the methods zoom_in() and zoom_out(). */ public double zoom_factor = 1.4; /** * The maximum image scaling to be allowed. * It doesn't make sense to scale more than 2X the original image */ public double max_img_scaling = 4.0; /** * The minimum image scaling to be allowed. * This will be set automatically when the MapCanvas is created. * The initial min_img_scaling will be such that the map cannot be made * smaller than the MapCanvas area in both the X and Y dimensions. */ public double min_img_scaling = 0.25; public MapTool [] toolArray; public MapRegion [] regionArray; private int selected_tool = 0; /** * The current grid being used by the map. */ public MapGrid grid; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> class GrayFilter extends RGBImageFilter { public GrayFilter() {canFilterIndexColorModel = true;} public int filterRGB(int x, int y, int rgb) { int a = rgb & 0xff000000; int r = (rgb & 0xff0000) >> 16; int g = (rgb & 0x00ff00) >> 8; int b = (rgb & 0x0000ff); // int gray = (int)(.3 * r + .59 * g + .11 * b); int gray = 128 + (int)(.075 * r + .145 * g + .027 * b); return a | (gray << 16) | (gray << 8) | gray; } } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> class MapScroller extends Thread { int sleep_milliseconds=50; public void set_sleep_milliseconds(int milliseconds) { sleep_milliseconds = milliseconds; } public void run() { while (true) { if( panning() ) { repaint(); } yield(); try { sleep(sleep_milliseconds); } catch (InterruptedException e) {} yield(); } } } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> public boolean panning( ) { boolean refresh = false; if ( tool_driven ) { if ( getTool().pan_left) { if ( getTool().pan_left_fast ) scroll_X(fast_delta); else scroll_X(slow_delta); refresh = true; } else if ( getTool().pan_right) { if ( getTool().pan_right_fast) scroll_X(-fast_delta); else scroll_X(-slow_delta); refresh = true; } if ( getTool().pan_down) { if ( getTool().pan_down_fast) scroll_Y(-fast_delta); else scroll_Y(-slow_delta); refresh = true; } else if ( getTool().pan_up) { if ( getTool().pan_up_fast) scroll_Y(fast_delta); else scroll_Y(slow_delta); refresh = true; } } else { if ( pan_left ) { if ( pan_left_fast ) scroll_X(fast_delta); else scroll_X(slow_delta); refresh = true; } else if ( pan_right ) { if ( pan_right_fast ) scroll_X(-fast_delta); else scroll_X(-slow_delta); refresh = true; } if ( pan_down ) { if ( pan_down_fast ) { scroll_Y(-fast_delta); } else scroll_Y(-slow_delta); refresh = true; } else if ( pan_up ) { if ( pan_up_fast ) scroll_Y(fast_delta); else scroll_Y(slow_delta); refresh = true; } getTool().setUser_XY(); } // tool_driven return refresh; } //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /** * Constructs and initializes a MapCanvas with the specified parameters. * @param base_image the image over which the tool will be drawn * @param width the width in pixels of the MapCanvas * @param height the height in pixels of the MapCanvas * @param tool the tool for user interaction * @param grid the grid associated with the underlying basemap. */ public MapCanvas(ImageIcon image_icon, int width, int height, MapTool [] toolArray, MapGrid grid) { super(image_icon); MediaTracker tracker; this.base_image = image_icon.getImage(); this.width = width; this.height = height; this.toolArray = toolArray; this.grid = grid; this.grid.setCanvasWidth(width); ImageFilter f = new GrayFilter(); ImageProducer producer = new FilteredImageSource(base_image.getSource(),f); gray_image = this.createImage(producer); tracker = new MediaTracker(this); tracker.addImage(gray_image, 1); try { tracker.waitForID(1); } catch (InterruptedException e) { System.out.println("MapCanvas: " + e); } if (tracker.isErrorID(1)) { System.out.println("MapCanvas: Error creating gray image."); } // mouse listener addMouseListener( this ); addMouseMotionListener( this ); enableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK); scale_image_to_fit(); scroller = new MapScroller(); scroller.setPriority(Thread.MIN_PRIORITY); scroller.start(); } /** * Constructs and initializes a MapCanvas with the specified parameters. * @param base_image the image over which the tool will be drawn * @param width the width in pixels of the MapCanvas * @param height the height in pixels of the MapCanvas * @param tool the tool for user interaction * @param grid the grid associated with the underlying basemap. */ public MapCanvas(ImageIcon image_icon, int width, int height, MapTool [] toolArray, MapGrid grid, int x, int y, double scaling) { super(image_icon); MediaTracker tracker; this.base_image = image_icon.getImage(); this.width = width; this.height = height; this.toolArray = toolArray; this.grid = grid; this.grid.setCanvasWidth(width); ImageFilter f = new GrayFilter(); ImageProducer producer = new FilteredImageSource(base_image.getSource(),f); gray_image = this.createImage(producer); tracker = new MediaTracker(this); tracker.addImage(gray_image, 1); try { tracker.waitForID(1); } catch (InterruptedException e) { System.out.println("MapCanvas: " + e); } if (tracker.isErrorID(1)) { System.out.println("MapCanvas: Error creating gray image."); } // mouse listener addMouseListener( this ); addMouseMotionListener( this ); enableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK); position_and_scale_image(x, y, scaling); scroller = new MapScroller(); scroller.setPriority(Thread.MIN_PRIORITY); scroller.start(); } /** * Overrides the default method and omits the background fill. * @param g the specified Graphics window */ public synchronized void update(Graphics g) { paintComponent(g); } /** * Paints the canvas with the base image and the current tool. * @param g the specified Graphics window */ public synchronized void paintComponent(Graphics g) { //Rescale offImage = base_image.getScaledInstance(imageRect.width, imageRect.height, base_image.SCALE_DEFAULT); //use a lightweight component to carry out the image ImageIcon temp = new ImageIcon(offImage); //Dimension d = size(); //1.1 We need to create a new graphics context every time /* in java 1.0. if ( (offGraphics == null) || (d.width != offDimension.width) || (d.height != offDimension.height) ) { offDimension = d; offImage = createImage(d.width, d.height); offGraphics = offImage.getGraphics(); }*/ //offGraphics.setColor(Color.gray); //offGraphics.fillRect(0, 0, width, height); //offGraphics.setClip(0, 0, clip_width, clip_height); //offGraphics.clipRect(0, 0, clip_width, clip_height); //offGraphics.drawImage(gray_image, imageRect.x, imageRect.y, // imageRect.width, imageRect.height, this); //offGraphics.drawImage(gray_image, imageRect.x+imageRect.width, // imageRect.y, imageRect.width, imageRect.height, this); // This next section deals with calculating a clipping rectangle // for the valid range of the data. int xlo, xhi, xwidth, ylo, yhi, yheight; double domain = grid.domain_X[HI]-grid.domain_X[LO]; double range = getTool().range_X[HI]-getTool().range_X[LO]; if ( Math.abs(domain) == Math.abs(range) ) { xlo = 0; xhi = clip_width; } else { xlo = grid.userToPixel_X(getTool().range_X[LO]); xhi = grid.userToPixel_X(getTool().range_X[HI]); } // Now for some logic to deal with ranges that span // the domain edges. (e.g. domain=-180:180, range=140E:90W) // (xhi < xlo) means that xhi or xlo is outside of the // MapCanvas viewing area and we need modify xlo or xhi // to match the MapCanvas edge. if ( xhi < xlo ) { if ( xlo > clip_width ) xlo = 0; else xhi = clip_width; } xwidth = xhi - xlo; ylo = grid.userToPixel_Y(getTool().range_Y[HI]); yhi = grid.userToPixel_Y(getTool().range_Y[LO]); yheight = yhi - ylo; // Now we apply a clipping rectangle to match the data range //offGraphics.setClip(xlo, ylo, xwidth, yheight); //offGraphics.clipRect(xlo, ylo, xwidth, yheight); //offGraphics.drawImage(base_image, imageRect.x, imageRect.y, // imageRect.width, imageRect.height, this); //offGraphics.drawImage(base_image, imageRect.x+imageRect.width, // imageRect.y, imageRect.width, imageRect.height, this); //offGraphics.setClip(0, 0, clip_width, clip_height); //offGraphics.clipRect(0, 0, clip_width, clip_height); //g.setClip(xlo, ylo, xwidth, yheight); //g.clipRect(xlo, ylo, xwidth, yheight); temp.paintIcon(this, g, imageRect.x, imageRect.y); temp.paintIcon(this, g, imageRect.x+imageRect.width, imageRect.y); //g.setClip(0, 0, clip_width, clip_height); //g.clipRect(0, 0, clip_width, clip_height); for (int i=0; i<toolArray.length; i++) { toolArray[i].draw(g); //toolArray[i].draw(offGraphics); } for (int i=0; i<regionArray.length; i++) { regionArray[i].draw(g); //regionArray[i].draw(offGraphics); } //g.setClip(0, 0, width, height); //g.clipRect(0, 0, width, height); //g.drawImage(offImage, 0, 0, this); } /** * Causes the map to scroll an amount in the X direction. * @param delta the number of pixels to scroll. */ public synchronized void scroll_X(int delta) { int tool_delta = delta; imageRect.x += delta; /* * The starting coordinates of the base image are always: * * -imageRect.width < imageRect.x <= 0 (for modulo_X) * width - imageRect.width < imageRect.x <= 0 (for non-modulo_X) * height - imageRect.height < imageRect.y <= 0 */ if ( grid.modulo_X ) { if ( imageRect.x <= -imageRect.width ) { imageRect.x = imageRect.x + imageRect.width; } if ( imageRect.x > 0 ) { imageRect.x = imageRect.x - imageRect.width; //??? why } } else { if ( (imageRect.x+imageRect.width) < width ) { imageRect.x = width - imageRect.width; tool_delta = 0; } if ( imageRect.x > 0 ) { imageRect.x = 0; tool_delta = 0; } } /* * If the right edge of the tool is less than 0 or the * left edge of the tool is greater than the width of the canvas */ for (int i=0; i<selected_tool; i++) { if ( grid.modulo_X ) { if ( (toolArray[i].x+tool_delta+toolArray[i].width) < 0 ) tool_delta += imageRect.width; if ( (toolArray[i].x+tool_delta) > width ) tool_delta -= imageRect.width; } toolArray[i].setLocation(toolArray[i].x+tool_delta,toolArray[i].y); } for (int i=selected_tool+1; i<toolArray.length; i++) { if ( grid.modulo_X ) { if ( (toolArray[i].x+tool_delta+toolArray[i].width) < 0 ) tool_delta += imageRect.width; if ( (toolArray[i].x+tool_delta) > width ) tool_delta -= imageRect.width; } toolArray[i].setLocation(toolArray[i].x+tool_delta,toolArray[i].y); } /* * If the right edge of the region is less than 0 or the * left edge of the region is greater than the width of the canvas */ for (int i=0; i<regionArray.length; i++) { if ( grid.modulo_X ) { if ( (regionArray[i].x+tool_delta+regionArray[i].width) < 0 ) tool_delta += imageRect.width; if ( (regionArray[i].x+tool_delta) > width ) tool_delta -= imageRect.width; } regionArray[i].setLocation(regionArray[i].x+tool_delta,regionArray[i].y); } } /** * Causes the map to scroll an amount in the Y direction. * @param delta the number of pixels to scroll. */ public synchronized void scroll_Y(int delta) { int tool_delta = delta; imageRect.y += delta; if ( (imageRect.y+imageRect.height) < height ) { imageRect.y = height - imageRect.height; tool_delta = 0; } if ( imageRect.y > 0 ) { imageRect.y = 0; tool_delta = 0; } for (int i=0; i<selected_tool; i++) toolArray[i].setLocation(toolArray[i].x,toolArray[i].y+tool_delta); for (int i=selected_tool+1; i<toolArray.length; i++) toolArray[i].setLocation(toolArray[i].x,toolArray[i].y+tool_delta); for (int i=0; i<regionArray.length; i++) regionArray[i].setLocation(regionArray[i].x,regionArray[i].y+tool_delta); } /** * Suspends scrolling. * <p> * Scrolling can be resumed with <code>resume_scrolling()</code>. */ public synchronized void suspend_scrolling() { //scroller.suspend(); try { while( scrollSuspended ) wait(); } catch( InterruptedException e) { } } /** * Resumes scrolling. * <p> * Scrolling can be suspended with <code>suspend_scrolling()</code>. */ public synchronized void resume_scrolling() { //scroller.resume(); scrollSuspended = !scrollSuspended; if( !scrollSuspended ) notify(); } /* * We need this in order to get the frame so we can change the cursor. */ private JFrame getFrame() { Container parent = this.getParent(); while ( (parent != null) && !(parent instanceof JFrame)) parent = parent.getParent(); return ((JFrame) parent); } //1.1 ----------------------------------------------------- // implementation of MouseListener, MouseMotionListener public void mouseMoved(MouseEvent evt) { int type = getTool().mouseMove( evt.getX(), evt.getY() ); JFrame frame = this.getFrame(); if( frame != null) frame.setCursor( new Cursor(type) ); } public void mousePressed(MouseEvent evt) { getTool().mouseDown( evt.getX(), evt.getY() ); if ( getTool().is_active() ) { repaint(); } } public void mouseDragged(MouseEvent evt) { getTool().mouseDrag( evt.getX(), evt.getY() ); if ( getTool().is_active() ) { repaint(); } } public void mouseReleased(MouseEvent evt) { getTool().mouseUp( evt.getX(), evt.getY() ); repaint(); } public void mouseEntered(MouseEvent evt) { } public void mouseExited(MouseEvent evt) { } public void mouseClicked(MouseEvent evt) { mousePressed( evt ); } /*----------------------------------------------------- 1.1 /*-------------------------V--------------------------- 1.0 /** * Passes the event to the current tool. * <p> * If we are over the center tool change the cursor to MOVE_CURSOR. * This method returns <code>false</code> so the interface can be updated if desired. * public synchronized boolean mouseMove(Event evt, int mouse_x, int mouse_y) { int type = getTool().mouseMove(mouse_x, mouse_y); this.getFrame().setCursor(type); return false; // The user interface can update a textField at this point } /** * Passes the event to the current tool. * <p> * If the tool is active, the user values are updated. * This method returns <code>false</code> so the interface can be updated if desired. * public synchronized boolean mouseDown(Event evt, int mouse_x, int mouse_y) { getTool().mouseDown(mouse_x, mouse_y); if ( getTool().is_active() ) { repaint(); } return false; // The user interface can update a textField at this point } /** * Passes the event to the current tool. * <p> * If the tool is active, the user values are updated. * This method returns <code>false</code> so the interface can be updated if desired. * public synchronized boolean mouseDrag(Event evt, int mouse_x, int mouse_y) { getTool().mouseDrag(mouse_x, mouse_y); if ( getTool().is_active() ) { repaint(); } return false; // The user interface can update a textField at this point } /** * Passes the event to the current tool. * <p> * If the tool is active, the user values are updated. * This method returns <code>false</code> so the interface can be updated if desired. * public synchronized boolean mouseUp(Event evt, int mouse_x, int mouse_y) { getTool().mouseUp(mouse_x, mouse_y); repaint(); return false; // The user interface can update a textField at this point }*/ /*-------------------------^--------------------------- 1.0 /** * Increases the base image size the internally maintained zoom factor. * * @exception MaxZoomException already at max zoom. * @exception MinZoomException already at min zoom. */ public synchronized void zoom_in() throws MaxZoomException, MinZoomException { this.zoom(zoom_factor); } /** * Decreases the base image size the internally maintained zoom factor. * * @exception MaxZoomException already at max zoom. * @exception MinZoomException already at min zoom. */ public synchronized void zoom_out() throws MaxZoomException, MinZoomException { this.zoom(1.0/zoom_factor); } /** * Increases/decreases the base image size by the specified zoom factor. * * @param zoom_factor. * @exception MaxZoomException already at max zoom. * @exception MinZoomException already at min zoom. */ public synchronized void zoom(double zoom_factor) throws MaxZoomException, MinZoomException { Graphics g = getGraphics(); double initial_scaling = image_scaling; { //1.1 This whole section is unnecessary when using // the setClip() method in java 1.1. /* * We need to create a new off screen graphics context here * because of the rather odd, yet documented behavior of the * clipRect() method of a Graphics object: * * g.clipRect(Rectangle) generates a clipping region which is the * INTERSECTION of the rectangle given and the PREVIOUS * clipping region!!! * * This means there is no way to increase a clipping region * for a particular graphics context. You must instead * create a new graphics context whenever you want the * clipping region increased in size. * Dimension d = getSize(); offDimension = d; offImage = createImage(d.width, d.height); offGraphics = offImage.getGraphics();*/ } if ( (image_scaling * zoom_factor) > max_img_scaling ) { this.zoom(max_img_scaling/image_scaling); throw new MaxZoomException(); } else if ( (image_scaling * zoom_factor) < min_img_scaling - 0.01) { this.zoom(min_img_scaling/image_scaling); throw new MinZoomException(); } else image_scaling = image_scaling * zoom_factor; zoom_factor = image_scaling / initial_scaling; imageRect.width = (int)(base_image.getWidth(this)*image_scaling); imageRect.height = (int)(base_image.getHeight(this)*image_scaling); clip_width = (imageRect.width < width) ? imageRect.width : width; clip_height = (imageRect.height < height) ? imageRect.height : height; for (int i=0; i<toolArray.length; i++) { toolArray[i].applyClipRect(0, 0, clip_width, clip_height); } center_tool(zoom_factor); repaint(); //getRootPane().getContentPane().repaint(); } public void center_tool(double zoom_factor) { double [] regionArrayUser_X = new double[regionArray.length]; double [] regionArrayUser_Y = new double[regionArray.length]; for (int i=0; i<regionArray.length; i++) { regionArrayUser_X[i] = regionArray[i].user_X; regionArrayUser_Y[i] = regionArray[i].user_Y; } double [] toolArrayUser_X = new double[toolArray.length]; double [] toolArrayUser_Y = new double[toolArray.length]; for (int i=0; i<toolArray.length; i++) { toolArrayUser_X[i] = toolArray[i].user_X[LO]; toolArrayUser_Y[i] = toolArray[i].user_Y[HI]; } // Move the image so that the selected tool will be centered // if ( imageRect.width >= width ) { imageRect.x = (int) (width/2 - (getTool().x + getTool().width/2 - imageRect.x)*zoom_factor); imageRect.y = (int) (height/2 - (getTool().y + getTool().height/2 - imageRect.y)*zoom_factor); } else { imageRect.x = (int) (imageRect.width/2 - (getTool().x + getTool().width/2 - imageRect.x)*zoom_factor); imageRect.y = (int) (imageRect.height/2 - (getTool().y + getTool().height/2 - imageRect.y)*zoom_factor); } // Resize the tool // for (int i=0; i<toolArray.length; i++) { toolArray[i].width *= zoom_factor; toolArray[i].height *= zoom_factor; } for (int i=0; i<regionArray.length; i++) { regionArray[i].width *= zoom_factor; regionArray[i].height *= zoom_factor; } /* * Check the image width/height and change image_rect.x/.y if appropriate. */ if ( !grid.modulo_X ) { if ( imageRect.width >= width ) { if ( (imageRect.width + imageRect.x) < width ) imageRect.x = width - imageRect.width; imageRect.x = (imageRect.x > 0) ? 0 : imageRect.x; } else { imageRect.x = 0; } } if ( imageRect.height >= height ) { if ( (imageRect.height + imageRect.y) < height ) imageRect.y = height - imageRect.height; imageRect.y = (imageRect.y > 0) ? 0 : imageRect.y; } else imageRect.y = 0; // This takes care of some checks associated with changing imageRect.x and imageRect.y // this.scroll_X(0); this.scroll_Y(0); clip_width = (imageRect.width < width) ? imageRect.width : width; clip_height = (imageRect.height < height) ? imageRect.height : height; for (int i=0; i<toolArray.length; i++) { toolArray[i].applyClipRect(0, 0, clip_width, clip_height); } for (int i=0; i<toolArray.length; i++) { toolArray[i].setUserLocation(toolArrayUser_X[i],toolArrayUser_Y[i]); } for (int i=0; i<regionArray.length; i++) { regionArray[i].setUserLocation(regionArrayUser_X[i],regionArrayUser_Y[i]); } } public int getSelected() { return selected_tool; } public MapTool getTool() { return toolArray[selected_tool]; } public MapTool getTool(int i) { return toolArray[i]; } public void newToolFromOld(int i, MapTool new_tool, MapTool old_tool) { int alteration=0; new_tool.setGrid(grid); new_tool.setRange_X(old_tool.range_X[LO],old_tool.range_X[HI]); new_tool.setRange_Y(old_tool.range_Y[LO],old_tool.range_Y[HI]); new_tool.setUser_X(old_tool.user_X[LO],old_tool.user_X[HI]); new_tool.setUser_Y(old_tool.user_Y[LO],old_tool.user_Y[HI]); new_tool.setSnapping(old_tool.getSnap_X(),old_tool.getSnap_Y()); new_tool.drawHandles = old_tool.drawHandles; toolArray[i] = new_tool; toolArray[i].applyClipRect(0, 0, clip_width, clip_height); // The check_for_zero_range() function expands the // tool when necessary and may force us to update the // user_X/Y values. alteration = getTool().check_for_zero_range(); if (alteration == 1 || alteration == 3) toolArray[i].setUser_X(); if (alteration == 2 || alteration == 3) toolArray[i].setUser_Y(); toolArray[i].saveHandles(); } public void setTool(int i, MapTool tool) { int alteration=0; toolArray[i] = tool; toolArray[i].setGrid(grid); toolArray[i].applyClipRect(0, 0, clip_width, clip_height); toolArray[i].setUser_XY(); toolArray[i].check_for_zero_range(); toolArray[i].setUser_XY(); if (i == selected_tool) toolArray[i].drawHandles = true; toolArray[i].saveHandles(); } public void setToolArray(MapTool [] toolArray) { this.toolArray = toolArray; selected_tool = 0; toolArray[selected_tool].drawHandles = true; for (int i=0; i<toolArray.length; i++) { toolArray[i].setGrid(grid); toolArray[i].applyClipRect(0, 0, clip_width, clip_height); toolArray[i].setUser_XY(); } } public void selectTool(int id) { for (int i=0; i<id; i++) toolArray[i].drawHandles = false; toolArray[id].drawHandles = true; for (int i=id+1; i<toolArray.length; i++) toolArray[i].drawHandles = false; if ( toolArray[id].getDelta_X() != 0 ) grid.setDelta_X(toolArray[id].getDelta_X()); if ( toolArray[id].getDelta_Y() != 0 ) grid.setDelta_Y(toolArray[id].getDelta_Y()); selected_tool = id; repaint(); } public void setRegionArray(MapRegion [] regionArray) { this.regionArray = regionArray; for (int i=0; i<regionArray.length; i++) { regionArray[i].setGrid(grid); regionArray[i].setUserLocation(); } } public void setGrid(MapGrid grid) { this.grid = grid; this.grid.imageRect = this.imageRect; for (int i=0; i<toolArray.length; i++) { toolArray[i].setGrid(this.grid); } for (int i=0; i<regionArray.length; i++) { regionArray[i].setGrid(grid); } } public MapGrid getGrid() { return grid; } public void setImage(ImageIcon image) { // JC_TODO: throw an exception if image = null if ( image != null ) { this.base_image = image.getImage(); this.setIcon(image); } else System.out.println("null image passed to MapCanvas. Reusing previous image."); scale_image_to_fit(); Graphics g = getGraphics(); repaint(); } public Image get_image() { return base_image; } /** * Returns a string with information for initial positioning and * and sizing of the base map. This information can be used to * initialize a new MapCanvas with the constructor which includes * the x, y and scaling parameters. */ public String get_internals() { StringBuffer sbuf = new StringBuffer(imageRect.x +" " +imageRect.y + " " +image_scaling + " " + min_img_scaling + " " + max_img_scaling); return sbuf.toString(); } /** * This method is necessary for layout managers. */ public Dimension getMinimumSize() { //public Dimension minimumSize() // { return new Dimension(width, height); } /** * This method is necessary for layout managers. */ public Dimension getPreferredSize() { //public Dimension preferredSize() // { return this.getMinimumSize(); //return this.minimumSize(); } /* * Some intelligence to do initial sizing when a new image is received. */ void scale_image_to_fit() { double vert_scaling = 1.0; double hor_scaling = 1.0; vert_scaling = (double)this.height / (double)base_image.getHeight(this); hor_scaling = (double)this.width / (double)base_image.getWidth(this); image_scaling = (vert_scaling < hor_scaling) ? vert_scaling : hor_scaling; if ( image_scaling < 0.1 ) { System.out.println("image scaling = " + image_scaling + ", being reset to 0.1."); image_scaling = 0.1; } min_img_scaling = image_scaling; imageRect.x = 0; imageRect.y = 0; imageRect.width = (int)(base_image.getWidth(this)*image_scaling); imageRect.height = (int)(base_image.getHeight(this)*image_scaling); grid.imageRect = this.imageRect; clip_width = (imageRect.width < width) ? imageRect.width : width; clip_height = (imageRect.height < height) ? imageRect.height : height; } /* * Some intelligence to do image initializing. */ void position_and_scale_image(int x, int y, double scaling) { image_scaling = scaling; imageRect.x = x; imageRect.y = y; imageRect.width = (int)(base_image.getWidth(this)*image_scaling); imageRect.height = (int)(base_image.getHeight(this)*image_scaling); //grid.imageRect = this.imageRect; for (int i=0; i<toolArray.length; i++) { toolArray[i].grid.imageRect = imageRect; } clip_width = (imageRect.width < width) ? imageRect.width : width; clip_height = (imageRect.height < height) ? imageRect.height : height; } } //--------------------------------------------------------------------------