// ********************************************************************** // // <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/EditableOMLine.java,v $ // $RCSfile: EditableOMLine.java,v $ // $Revision: 1.13 $ // $Date: 2009/02/25 22:34:03 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.omGraphics; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import com.bbn.openmap.omGraphics.editable.GraphicEditState; import com.bbn.openmap.omGraphics.editable.GraphicSelectedState; import com.bbn.openmap.omGraphics.editable.LineStateMachine; import com.bbn.openmap.omGraphics.geom.NonRegional; 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 EditableOMLine encompasses an OMLine, providing methods for modifying or * creating it. */ public class EditableOMLine extends EditableOMAbstractLine implements NonRegional { protected GrabPoint gp1; protected GrabPoint gp2; protected OffsetGrabPoint gpo; // offset protected OffsetGrabPoint gpm; // for grabbing the line and moving // it. protected OMLine line; public final static int STARTING_POINT_INDEX = 0; public final static int ENDING_POINT_INDEX = 1; public final static int OFFSET_POINT_INDEX = 2; /** * Create the EditableOMLine, setting the state machine to create the line * off of the gestures. */ public EditableOMLine() { createGraphic(null); } /** * Create an EditableOMLine with the lineType and renderType parameters in * the GraphicAttributes object. */ public EditableOMLine(GraphicAttributes ga) { createGraphic(ga); } /** * Create the EditableOMLine with an OMLine already defined, ready for * editing. * * @param oml OMLine that should be edited. */ public EditableOMLine(OMLine oml) { setGraphic(oml); } /** * 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 EditableOMLine. */ public void init() { Debug.message("eomg", "EditableOMLine.init()"); setStateMachine(new LineStateMachine(this)); gPoints = new GrabPoint[3]; } /** * 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 OMLine) { line = (OMLine) graphic; stateMachine.setSelected(); setGrabPoints(line); } else { createGraphic(null); } } /** * Create and set the graphic within the state machine. The * GraphicAttributes describe the type of line to create. */ public void createGraphic(GraphicAttributes ga) { init(); stateMachine.setUndefined(); int renderType = OMGraphic.RENDERTYPE_UNKNOWN; int lineType = OMGraphic.LINETYPE_GREATCIRCLE; if (ga != null) { renderType = ga.getRenderType(); lineType = ga.getLineType(); } if (Debug.debugging("eoml")) { Debug.output("EditableOMLine.createGraphic(): rendertype = " + renderType); } if (lineType == OMGraphic.LINETYPE_UNKNOWN) { lineType = OMGraphic.LINETYPE_GREATCIRCLE; if (ga != null) ga.setLineType(OMGraphic.LINETYPE_GREATCIRCLE); } switch (renderType) { case (OMGraphic.RENDERTYPE_LATLON): line = new OMLine(90f, -180f, 90f, -180f, lineType); break; case (OMGraphic.RENDERTYPE_OFFSET): line = new OMLine(90d, -180d, 0, 0, 0, 0); break; default: line = new OMLine(-1, -1, -1, -1); } if (ga != null) { ga.setTo(line, true); } } /** * Get the OMGraphic being created/modified by the EditableOMLine. */ public OMGraphic getGraphic() { return line; } /** * 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); gpm = null; } /** * 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); } /** * 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() { if (gp1 == null) { gp1 = new GrabPoint(-1, -1); gPoints[STARTING_POINT_INDEX] = gp1; } if (gp2 == null) { gp2 = new GrabPoint(-1, -1); gPoints[ENDING_POINT_INDEX] = gp2; } if (gpo == null) { gpo = new OffsetGrabPoint(-1, -1); gPoints[OFFSET_POINT_INDEX] = gpo; gpo.addGrabPoint(gp1); gpo.addGrabPoint(gp2); } } /** * 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) { if (!(graphic instanceof OMLine)) { return; } assertGrabPoints(); OMLine line = (OMLine) graphic; boolean ntr = line.getNeedToRegenerate(); int renderType = line.getRenderType(); if (ntr == false) { if (renderType == OMGraphic.RENDERTYPE_LATLON) { Debug.message("eomg", "EditableOMLine: modifying lat/lon line"); // Complicated lines!!!! Need to grab the end points // that are on the map! See, for very large lines // that go around the earth, they are actually drawn // in OpenMap as an array of lines that are clipped as // they go offscreen. Eventually, one of the points // should appear on the map somewhere. If they don't, // then then the end points may not be on the screen. if (projection != null) { double[] ll = line.getLL(); Point2D p = projection.forward(ll[0], ll[1]); gp1.set((int) p.getX(), (int) p.getY()); projection.forward(ll[2], ll[3], p); gp2.set((int) p.getX(), (int) p.getY()); } } else { // Grab the projected endpoints Debug.message("eomg", "EditableOMLine: modifying x/y or offset standard line"); gp1.set(line.xpoints[0][0], line.ypoints[0][0]); int last = line.xpoints[0].length - 1; gp2.set(line.xpoints[0][last], line.ypoints[0][last]); } // Check to see if the line is a offset line, and set the // offset grab point accordingly. if (line.getRenderType() == OMGraphic.RENDERTYPE_OFFSET && projection != null) { double[] ll = line.getLL(); Point2D p = projection.forward(ll[0], ll[1]); gpo.set((int) p.getX(), (int) p.getY()); gpo.updateOffsets(); } } else { Debug.message("eomg", "EditableOMLine.setGrabPoints: graphic needs to be regenerated"); } } /** * Take the current location of the GrabPoints, and modify the location * parameters of the OMLine with them. Called when you want the graphic to * change according to the grab points. */ public void setGrabPoints() { int renderType = line.getRenderType(); if (renderType == OMGraphic.RENDERTYPE_LATLON) { if (projection != null) { double[] coords = new double[4]; LatLonPoint llp = (LatLonPoint) projection.inverse(gp1.getX(), gp1.getY(), new LatLonPoint.Double()); coords[0] = llp.getY(); coords[1] = llp.getX(); projection.inverse(gp2.getX(), gp2.getY(), llp); coords[2] = llp.getY(); coords[3] = llp.getX(); line.setLL(coords); } else { Debug.message("eomg", "EditableOMLine.setGrabPoints: projection is null, can't figure out LATLON points for line."); } } else if (renderType == OMGraphic.RENDERTYPE_OFFSET) { // Do the offset point. if (projection != null) { double[] coords = new double[4]; LatLonPoint llp = (LatLonPoint) projection.inverse(gpo.getX(), gpo.getY(), new LatLonPoint.Double()); coords[0] = llp.getY(); coords[1] = llp.getX(); coords[2] = 0;// not used coords[3] = 0;// not used line.setLL(coords); } else { Debug.message("eomg", "EditableOMLine.setGrabPoints: projection is null, can't figure out LATLON points for line offset."); } } if (renderType == OMGraphic.RENDERTYPE_XY || renderType == OMGraphic.RENDERTYPE_OFFSET) { int[] ints = new int[4]; if (renderType == OMGraphic.RENDERTYPE_OFFSET && gpo != null) { // If offset rendertype, the x-y have to be offset // distances, not screen pixel locations. ints[0] = gp1.getX() - gpo.getX(); ints[1] = gp1.getY() - gpo.getY(); ints[2] = gp2.getX() - gpo.getX(); ints[3] = gp2.getY() - gpo.getY(); } else { ints[0] = gp1.getX(); ints[1] = gp1.getY(); ints[2] = gp2.getX(); ints[3] = gp2.getY(); } line.setPts(ints); } } /** * 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(MouseEvent e) { // Need to check to see if the OffsetGrabPoint is currently // being used. If not, just use it, otherwise, will need to // create a special one for the move. Point2D pnt = getProjectionPoint(e); int x = (int) pnt.getX(); int y = (int) pnt.getY(); if (line.getRenderType() == OMGraphic.RENDERTYPE_OFFSET) { gpm = new OffsetGrabPoint(x, y); gpm.addGrabPoint(gp1); gpm.addGrabPoint(gp2); } else { gpm = gpo; gpm.set(x, y); gpm.updateOffsets(); } movingPoint = gpm; } /** * 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("eomg", "EditableOMLine.generate()"); if (line != null) line.generate(proj); if (gp1 != null) gp1.generate(proj); if (gp2 != null) gp2.generate(proj); if (gpo != null) { gpo.generate(proj); gpo.updateOffsets(); } 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", "EditableOMLine.regenerate()"); if (line != null) line.generate(proj); setGrabPoints(line); if (gp1 != null) gp1.generate(proj); if (gp2 != null) gp2.generate(proj); if (gpo != null) { gpo.generate(proj); gpo.updateOffsets(); } } /** * Draw the EditableOMLine parts into the java.awt.Graphics object. The grab * points are only rendered if the line machine state is * LineSelectedState.LINE_SELECTED. * * @param graphics java.awt.Graphics. */ public void render(java.awt.Graphics graphics) { Debug.message("eomg", "EditableOMLine.render()"); State state = getStateMachine().getState(); if (line != null) { line.setVisible(true); line.render(graphics); line.setVisible(false); } else { Debug.message("eomg", "EditableOMLine.render: null line."); } if (state instanceof GraphicSelectedState) { if (gp1 != null) { gp1.setVisible(true); gp1.render(graphics); gp1.setVisible(false); } if (gp2 != null) { gp2.setVisible(true); gp2.render(graphics); gp2.setVisible(false); } } if (state instanceof GraphicSelectedState || state instanceof GraphicEditState /* * || * state * instanceof * LineSetOffsetState */) { if (gpo != null && line.getRenderType() == OMGraphic.RENDERTYPE_OFFSET) { gpo.setVisible(true); gpo.render(graphics); gpo.setVisible(false); } } } }