// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/omGraphics/EditableOMScalingRaster.java,v $ // $RCSfile: EditableOMScalingRaster.java,v $ // $Revision: 1.13 $ // $Date: 2009/02/25 22:34:03 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.omGraphics; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import javax.swing.JOptionPane; import com.bbn.openmap.Environment; import com.bbn.openmap.omGraphics.editable.GraphicEditState; import com.bbn.openmap.omGraphics.editable.GraphicSelectedState; import com.bbn.openmap.omGraphics.editable.GraphicSetOffsetState; import com.bbn.openmap.omGraphics.editable.ScalingRasterStateMachine; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.proj.coords.LatLonPoint; import com.bbn.openmap.util.Debug; import com.bbn.openmap.util.stateMachine.State; /** * The EditableOMScalingRaster encompasses an OMScalingRaster, providing methods * for modifying or creating it. This class only modifies OMScaling Rasters in * lat/lon space (RENDERTYPE_LATLON). When you grab at the raster, you change * the size of the entire rect. Grabbing the center point moves the raster. If * there is an offset point, moving the center point changes the rect's position * in relation to the offset point. Moving the offset point moves the rect, * keeping the distance to the center point constant. */ public class EditableOMScalingRaster extends EditableOMGraphic { protected GrabPoint gpnw; protected GrabPoint gpne; protected GrabPoint gpsw; protected GrabPoint gpse; protected OffsetGrabPoint gpc; protected OffsetGrabPoint gpo; // offset protected OMScalingRaster raster; public final static String OffsetResetCmd = "OffsetResetCmd"; public final static int CENTER_POINT_INDEX = 0; public final static int NW_POINT_INDEX = 1; public final static int NE_POINT_INDEX = 2; public final static int SW_POINT_INDEX = 3; public final static int SE_POINT_INDEX = 4; public final static int OFFSET_POINT_INDEX = 5; /** * Create the EditableOMRect, setting the state machine to create the rect * off of the gestures. */ public EditableOMScalingRaster() { createGraphic(null); } /** * Create an EditableOMScalingRaster with the rectType and renderType * parameters in the GraphicAttributes object. */ public EditableOMScalingRaster(GraphicAttributes ga) { createGraphic(ga); } /** * Create the EditableOMScalingRaster with an OMScalingRaster already * defined, ready for editing. * * @param omsr OMScalingRaster that should be edited. */ public EditableOMScalingRaster(OMScalingRaster omsr) { setGraphic(omsr); } /** * Create and initialize the state machine that interprets the modifying * gestures/commands, as well as initialize the grab points. Also allocates * the grab point array needed by the EditableOMScalingRaster. */ public void init() { Debug.message("eomg", "EditableOMScalingRaster.init()"); setCanGrabGraphic(false); setStateMachine(new ScalingRasterStateMachine(this)); gPoints = new GrabPoint[6]; } /** * Set the graphic within the state machine. If the graphic is null, then * one shall be created, and located off screen until the gestures driving * the state machine place it on the map. */ public void setGraphic(OMGraphic graphic) { init(); if (graphic instanceof OMScalingRaster) { raster = (OMScalingRaster) graphic; stateMachine.setSelected(); setGrabPoints(raster); } else { createGraphic(null); } } /** * Create and set the graphic within the state machine. The * GraphicAttributes describe the type of rect to create. */ public void createGraphic(GraphicAttributes ga) { init(); stateMachine.setUndefined(); String pathToFile = null; // / This would be an ideal place to bring up a chooser! if (!Environment.isApplet()) { pathToFile = com.bbn.openmap.util.FileUtils.getFilePathToOpenFromUser("Choose Image File for Raster"); } else { JOptionPane.showMessageDialog(null, "Can't search for images in an applet!", "Can't Choose Image", JOptionPane.ERROR_MESSAGE); } if (pathToFile == null) return; try { javax.swing.ImageIcon ii = new javax.swing.ImageIcon(pathToFile); raster = new OMScalingRaster(90f, -180f, 89f, -179f, ii); } catch (IllegalArgumentException iae) { // Not an image file, punch Debug.error("EditableOMScalingRaster: " + pathToFile + " doesn't appear to be an image file"); raster = new OMScalingRaster(90f, -180f, 89f, -179f, new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB)); } if (ga != null) { ga.setTo(raster, true); } assertGrabPoints(); } /** * Get the OMGraphic being created/modified by the EditableOMScalingRaster. */ public OMGraphic getGraphic() { return raster; } /** * Attach to the Moving OffsetGrabPoint so if it moves, it will move this * EditableOMGraphic with it. EditableOMGraphic version doesn't do anything, * each subclass has to decide which of its OffsetGrabPoints should be * attached to it. */ public void attachToMovingGrabPoint(OffsetGrabPoint gp) { gp.addGrabPoint(gpo); } /** * Detach from a Moving OffsetGrabPoint. The EditableOMGraphic version * doesn't do anything, each subclass should remove whatever GrabPoint it * would have attached to an OffsetGrabPoint. */ public void detachFromMovingGrabPoint(OffsetGrabPoint gp) { gp.removeGrabPoint(gpo); } /** * Set the GrabPoint that is in the middle of being modified, as a result of * a mouseDragged event, or other selection process. */ // public void setMovingPoint(GrabPoint gp) { // super.setMovingPoint(gp); // } double diffx; double diffy; // Called from the state machine... public void initRectSize() { diffx = Math.abs(raster.getLRLon() - raster.getULLon()) / 2; diffy = Math.abs(raster.getULLat() - raster.getLRLat()) / 2; // Debug.output("initRectSize(): diffx:" + diffx + ", diffy:" // + diffy); } protected int lastRenderType = -1; /** * Check to make sure the grab points are not null. If they are, allocate * them, and them assign them to the array. */ public void assertGrabPoints() { OMGraphic omg = getGraphic(); if (omg == null) return; int rt = omg.getRenderType(); if (rt != lastRenderType) { clearGrabPoints(); lastRenderType = rt; } if (gpnw == null) { gpnw = new GrabPoint(-1, -1); gPoints[NW_POINT_INDEX] = gpnw; // gpnw.setFillPaint(Color.yellow); } if (gpne == null) { gpne = new GrabPoint(-1, -1); gPoints[NE_POINT_INDEX] = gpne; // gpne.setFillPaint(Color.blue); } if (gpsw == null) { gpsw = new GrabPoint(-1, -1); gPoints[SW_POINT_INDEX] = gpsw; // gpsw.setFillPaint(Color.green); } if (gpse == null) { gpse = new GrabPoint(-1, -1); gPoints[SE_POINT_INDEX] = gpse; // gpse.setFillPaint(Color.orange); } if (gpc == null) { gpc = new OffsetGrabPoint(-1, -1); // gpc.setFillPaint(Color.red); gPoints[CENTER_POINT_INDEX] = gpc; if (getGraphic().getRenderType() != OMGraphic.RENDERTYPE_LATLON) { gpc.addGrabPoint(gpnw); gpc.addGrabPoint(gpne); gpc.addGrabPoint(gpsw); gpc.addGrabPoint(gpse); } } if (gpo == null) { gpo = new OffsetGrabPoint(-1, -1); gPoints[OFFSET_POINT_INDEX] = gpo; gpo.addGrabPoint(gpc); } } protected void clearGrabPoints() { gpc = null; gpnw = null; gpne = null; gpsw = null; gpse = null; gpo = null; gPoints[CENTER_POINT_INDEX] = gpc; gPoints[NW_POINT_INDEX] = gpnw; gPoints[NE_POINT_INDEX] = gpne; gPoints[SW_POINT_INDEX] = gpsw; gPoints[SE_POINT_INDEX] = gpse; gPoints[OFFSET_POINT_INDEX] = gpo; } /** * Set the grab points for the graphic provided, setting them on the extents * of the graphic. Called when you want to set the grab points off the * location of the graphic. */ public void setGrabPoints(OMGraphic graphic) { Debug.message("eomg", "EditableOMScalingRaster.setGrabPoints(graphic)"); if (!(graphic instanceof OMScalingRaster)) { return; } assertGrabPoints(); OMScalingRaster raster = (OMScalingRaster) graphic; if (graphic instanceof OMScalingIcon) { setGrabPointsForOMSI((OMScalingIcon) graphic); return; } boolean ntr = raster.getNeedToRegenerate(); int renderType = raster.getRenderType(); int top = 0; int bottom = 0; int left = 0; int right = 0; LatLonPoint llp; int latoffset = 0; int lonoffset = 0; boolean doStraight = true; if (ntr == false) { if (renderType == OMGraphic.RENDERTYPE_LATLON || renderType == OMGraphic.RENDERTYPE_OFFSET) { if (projection != null) { double wlon = raster.getULLon(); double nlat = raster.getULLat(); double elon = raster.getLRLon(); double slat = raster.getLRLat(); llp = new LatLonPoint.Double(nlat, wlon); Point2D p = projection.forward(llp); if (renderType == OMGraphic.RENDERTYPE_LATLON) { doStraight = false; top = (int) p.getY(); left = (int) p.getX(); gpnw.set((int) p.getX(), (int) p.getY()); p = projection.forward(slat, elon); gpse.set((int) p.getX(), (int) p.getY()); p = projection.forward(nlat, elon); gpne.set((int) p.getX(), (int) p.getY()); p = projection.forward(slat, wlon); gpsw.set((int) p.getX(), (int) p.getY()); p = projection.forward(nlat - (nlat - slat) / 2f, wlon + (elon - wlon) / 2f); gpc.set((int) p.getX(), (int) p.getY()); } else { latoffset = (int) p.getY(); lonoffset = (int) p.getX(); gpo.set(lonoffset, latoffset); } } } if (doStraight) { Debug.message("eomg", "EditableOMScalingRaster: drawing straight line rectangle"); top = raster.getY() + latoffset; bottom = raster.getY() + raster.getHeight() + latoffset; right = raster.getX() + raster.getWidth() + lonoffset; left = raster.getX() + lonoffset; // We have to do some fancy point wrangling to keep // from messing up the next setGrabPoints(). if (movingPoint == gpc || movingPoint == gpo || movingPoint == null) { gpne.set(right, top); gpnw.set(left, top); gpse.set(right, bottom); gpsw.set(left, bottom); } else if (movingPoint == gpnw) { gpne.set(gpse.getX(), gpnw.getY()); gpsw.set(gpnw.getX(), gpse.getY()); } else if (movingPoint == gpse) { gpne.set(gpse.getX(), gpnw.getY()); gpsw.set(gpnw.getX(), gpse.getY()); } else if (movingPoint == gpsw) { gpnw.set(gpsw.getX(), gpne.getY()); gpse.set(gpne.getX(), gpsw.getY()); } else if (movingPoint == gpne) { gpnw.set(gpsw.getX(), gpne.getY()); gpse.set(gpne.getX(), gpsw.getY()); } int middlex = (right - left) / 2; int middley = (bottom - top) / 2; gpc.set(left + middlex, top + middley); gpc.updateOffsets(); // Debug.output("Center setting x: " + gpc.getX() + ", // y:" + gpc.getY()); } if (renderType == OMGraphic.RENDERTYPE_OFFSET) { gpo.updateOffsets(); } } else { Debug.message("eomg", "EditableOMScalingRaster.setGrabPoints: graphic needs to be regenerated"); } } /** * @param icon */ protected void setGrabPointsForOMSI(OMScalingIcon icon) { if (projection != null) { double lon = icon.getLon(); double lat = icon.getLat(); int renderType = icon.getRenderType(); LatLonPoint llp = new LatLonPoint.Double(lat, lon); Point2D p = projection.forward(llp); if (renderType == OMGraphic.RENDERTYPE_LATLON) { gpc.set((int) p.getX(), (int) p.getY()); } } } protected void setGrabPointsForOMSI() { if (projection != null) { // movingPoint == gpc LatLonPoint llp1 = projection.inverse(gpc.getX(), gpc.getY(), new LatLonPoint.Double()); raster.setLat(llp1.getY()); raster.setLon(llp1.getX()); // point.setNeedToRegenerate set } if (projection != null) { regenerate(projection); } } /** * Take the current location of the GrabPoints, and modify the location * parameters of the OMScalingRaster with them. Called when you want the * graphic to change according to the grab points. */ public void setGrabPoints() { int renderType = raster.getRenderType(); LatLonPoint llp1; Debug.message("eomg", "EditableOMScalingRaster.setGrabPoints()"); // Do center point for lat/lon or offset rects if (renderType == OMGraphic.RENDERTYPE_LATLON) { if (projection != null) { if (raster instanceof OMScalingIcon) { setGrabPointsForOMSI(); return; } // Need to figure out which point was moved, and then // set the upper left and lower right points // accordingly. if (movingPoint == gpne) { llp1 = projection.inverse(gpne.getX(), gpne.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setLRLon(llp1.getX()); } else if (movingPoint == gpnw) { llp1 = projection.inverse(gpnw.getX(), gpnw.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); } else if (movingPoint == gpsw) { llp1 = projection.inverse(gpsw.getX(), gpsw.getY(), new LatLonPoint.Double()); raster.setLRLat(llp1.getY()); raster.setULLon(llp1.getX()); } else if (movingPoint == gpse) { llp1 = projection.inverse(gpse.getX(), gpse.getY(), new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpnw.getX(), gpnw.getY(), new LatLonPoint.Double()); raster.setULLat(llp2.getY()); raster.setULLon(llp2.getX()); raster.setLRLat(llp1.getY()); raster.setLRLon(llp1.getX()); } else { // movingPoint == gpc llp1 = projection.inverse(gpc.getX(), gpc.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY() + diffy); raster.setULLon(llp1.getX() - diffx); raster.setLRLat(llp1.getY() - diffy); raster.setLRLon(llp1.getX() + diffx); } raster.setNeedToRegenerate(true); } } boolean settingOffset = getStateMachine().getState() instanceof GraphicSetOffsetState && movingPoint == gpo; // If the center point is moving, the offset distance changes if (renderType == OMGraphic.RENDERTYPE_OFFSET) { llp1 = projection.inverse(gpo.getX(), gpo.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); if (settingOffset || movingPoint == gpc) { int halfheight = (gpse.getY() - gpnw.getY()) / 2; int halfwidth = (gpse.getX() - gpnw.getX()) / 2; // Don't call rect.setLocation because we only want to // setNeedToRegenerate if !settingOffset. llp1 = projection.inverse(gpc.getX() - halfwidth - gpo.getX(), gpc.getY() - halfheight - gpo.getY(), new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpc.getX() + halfwidth - gpo.getX(), gpc.getY() + halfheight - gpo.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); raster.setLRLat(llp2.getY()); raster.setLRLon(llp2.getX()); } if (!settingOffset) { Debug.message("eomg", "EditableOMScalingRaster: updating offset rect"); if (movingPoint == gpnw || movingPoint == gpse) { llp1 = projection.inverse(gpnw.getX() - gpo.getX(), gpnw.getY() - gpo.getY(), new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpse.getX() - gpo.getX(), gpse.getY() - gpo.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); raster.setLRLat(llp2.getY()); raster.setLRLon(llp2.getX()); } else if (movingPoint == gpne || movingPoint == gpsw) { llp1 = projection.inverse(gpsw.getX() - gpo.getX(), gpne.getY() - gpo.getY(), new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpne.getX() - gpo.getX(), gpsw.getY() - gpo.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); raster.setLRLat(llp2.getY()); raster.setLRLon(llp2.getX()); } raster.setNeedToRegenerate(true); } // Set Location has reset the rendertype, but provides // the convenience of setting the max and min values // for us. raster.setRenderType(OMGraphic.RENDERTYPE_OFFSET); } // Do the rect height and width for XY and OFFSET render // types. if (renderType == OMGraphic.RENDERTYPE_XY) { Debug.message("eomg", "EditableOMScalingRaster: updating x/y rect"); if (movingPoint == gpc) { int halfheight = (gpse.getY() - gpnw.getY()) / 2; int halfwidth = (gpse.getX() - gpnw.getX()) / 2; llp1 = projection.inverse(gpc.getX() - halfwidth, gpc.getY() - halfheight, new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpc.getX() + halfwidth, gpc.getY() + halfheight, new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); raster.setLRLat(llp2.getY()); raster.setLRLon(llp2.getX()); } else if (movingPoint == gpnw || movingPoint == gpse) { llp1 = projection.inverse(gpnw.getX(), gpnw.getY(), new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpse.getX(), gpse.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); raster.setLRLat(llp2.getY()); raster.setLRLon(llp2.getX()); } else if (movingPoint == gpne || movingPoint == gpsw) { llp1 = projection.inverse(gpsw.getX(), gpne.getY(), new LatLonPoint.Double()); LatLonPoint llp2 = projection.inverse(gpne.getX(), gpsw.getY(), new LatLonPoint.Double()); raster.setULLat(llp1.getY()); raster.setULLon(llp1.getX()); raster.setLRLat(llp2.getY()); raster.setLRLon(llp2.getX()); } } if (projection != null) { regenerate(projection); } } /** * Called to set the OffsetGrabPoint to the current mouse location, and * update the OffsetGrabPoint with all the other GrabPoint locations, so * everything can shift smoothly. Should also set the OffsetGrabPoint to the * movingPoint. Should be called only once at the beginning of the general * movement, in order to set the movingPoint. After that, redraw(e) should * just be called, and the movingPoint will make the adjustments to the * graphic that are needed. */ public void move(java.awt.event.MouseEvent e) { } /** * Use the current projection to place the graphics on the screen. Has to be * called to at least assure the graphics that they are ready for rendering. * Called when the graphic position changes. * * @param proj com.bbn.openmap.proj.Projection * @return true */ public boolean generate(Projection proj) { Debug.message("eomgdetail", "EditableOMScalingRaster.generate()"); if (raster != null) raster.generate(proj); for (int i = 0; i < gPoints.length; i++) { GrabPoint gp = gPoints[i]; if (gp != null) { gp.generate(proj); } } return true; } /** * Given a new projection, the grab points may need to be repositioned off * the current position of the graphic. Called when the projection changes. */ public void regenerate(Projection proj) { Debug.message("eomg", "EditableOMScalingRaster.regenerate()"); if (raster != null) raster.regenerate(proj); setGrabPoints(raster); generate(proj); } /** * Draw the EditableOMScalingRaster parts into the java.awt.Graphics object. * The grab points are only rendered if the rect machine state is * RectSelectedState.RECT_SELECTED. * * @param graphics java.awt.Graphics. */ public void render(java.awt.Graphics graphics) { Debug.message("eomgdetail", "EditableOMScalingRaster.render()"); State state = getStateMachine().getState(); if (raster == null) { Debug.message("eomg", "EditableOMScalingRaster.render: null rect."); return; } raster.setVisible(true); raster.render(graphics); raster.setVisible(false); int renderType = raster.getRenderType(); if (state instanceof GraphicSelectedState || state instanceof GraphicEditState) { for (int i = 0; i < gPoints.length; i++) { GrabPoint gp = gPoints[i]; if (gp != null) { if ((i == OFFSET_POINT_INDEX && renderType == OMGraphic.RENDERTYPE_OFFSET && movingPoint == gpo) || (state instanceof GraphicSelectedState && ((i != OFFSET_POINT_INDEX && renderType != OMGraphic.RENDERTYPE_OFFSET) || (renderType == OMGraphic.RENDERTYPE_OFFSET)))) { gp.setVisible(true); gp.render(graphics); gp.setVisible(false); } } } } } }