Re: RE : [OpenMap Users] Editable OMgraphics weird behavior

From: Don Dietrick <dietrick_at_bbn.com>
Date: Wed, 12 Mar 2008 00:54:03 -0400

Hi Faly,

Thanks for sending in the bug fix - it's a long standing bug that only
affects EditableOMPoly.

Best regards,

Don

On Mar 11, 2008, at 7:04 AM, Le-Faly wrote:

> Hi all,
>
> I reply to myself regarding the issue below. It's actually an
> Openmap bug. If you don't want to see the detail, please just skip
> to the "Mysolution" section below and if you are interested, the
> java file of the solution is enclosed.
>
> The facts are that (I currently make the investigation, only with a
> OMPoly):
> - in the "getGrabPoints()" method of EditableOMPoly, the value of
> the "gPoints" array is updated from the "polyGrabPoints" list, only
> if "gPoints.length != polyGrabPoints.size() + 1"
> - However, when the user unselects a OMPoly (cf. step 3 of the
> previous mail) and reselects it (step 4), polyGrabPoints is cleared
> and new values are affected there (cf. "setGrabPoints(OMGraphic
> graphic)" of EditableOMPoly). After that action, "polyGrabPoints"
> keeps the same size, only internal list values are changed. At this
> stage then, "gPoints" and "polyGrabPoints" still have the same size
> (that is, the above condition always remains true) but do not
> actually have the same values any more.
> - thus, when the user tries to modify the shape (cf. step 5), the
> "_getMovingPoint(MouseEvent e)" method of "EditableOMGraphic"
> modifies the old "gPoints" value while the "setGrabPoint()" method
> called in "redraw(...)" reads the new "polyGrabPoints" values. That
> is the reason the shape drawing is not updated.
>
> ---> My solution: In EditableOMPoly, I introduced a boolean variable
> "arrayCleared" which is true when "polyGrabPoints" is cleared (cf.
> "setGrabPoints(OMGraphic graphic)"). Then, in the "getGrabPoints()"
> method, I updated the above condition with
> "if(gPoints.length != polyGrabPoints.size() + 1 || arrayCleared)"
> {
> arrayCleared = false;
> .... // get new grab points values
> }
>
> So, why is with OMLine fine? just because the implementation of
> "setGrabPoints()" (which is abstract in "EditableOMGraphic") in
> "EditableOMLine" is correct, unlike that in "EditableOMPoly".
>
> I will now go to do the investigation of other OMGraphics like
> OMCurve but it should be easier now, I hope.
>
> That's all folks
>
> Faly
>
> Le-Faly <andri_faly_at_yahoo.fr> a écrit :
> Hi all,
>
> I tried the followings from the editor layer:
> 1- drawing a OMLine (and when the mouse is released, it obviously
> gets selected)
> 2- changing its shape via one of the two grab points
> => the shape is changed accordingly (let's note it (*))
> 3- unselecting it
> 4- selecting it again via the selectmouse mode process
> 5- change its shape via one of the two grab points
> => the shape is changed accordingly (let's note it (**))
>
> Up to here, everything is fine.
>
> But what's wrong is that if I draw a OMPoly or OMCurve instead of a
> OMLine, and follow the same steps, the result (**) is not reached:
> the OMGraphic shape does not want to change any more even if the
> grab points appear after the step 4 (moving of the whole OMGraphic
> is still possible, but not resizing one of its segment).
>
> Am I the only who may have this behavior? If yes, I made some bad
> code modifcations somewhere. If no, is it a bug? why is with OMLine
> fine?
>
> Thanks for any help
>
> Faly
> Envoyé avec Yahoo! Mail.
> Une boite mail plus intelligente.
>
>
> Envoyé avec Yahoo! Mail.
> Une boite mail plus intelligente. //
> **********************************************************************
> //
> // <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/EditableOMPoly.java,v $
> // $RCSfile: EditableOMPoly.java,v $
> // $Revision: 1.9.2.4 $
> // $Date: 2006/01/05 15:20:42 $
> // $Author: dietrick $
> //
> //
> **********************************************************************
>
> package com.bbn.openmap.omGraphics;
>
> import com.bbn.openmap.LatLonPoint;
> import com.bbn.openmap.gui.GridBagToolBar;
> import com.bbn.openmap.layer.util.stateMachine.State;
> import com.bbn.openmap.omGraphics.editable.GraphicEditState;
> import com.bbn.openmap.omGraphics.editable.GraphicSelectedState;
> import com.bbn.openmap.omGraphics.editable.PolyAddNodeState;
> import com.bbn.openmap.omGraphics.editable.PolyDeleteNodeState;
> import com.bbn.openmap.omGraphics.editable.PolyStateMachine;
> import com.bbn.openmap.omGraphics.editable.PolyUndefinedState;
> import com.bbn.openmap.proj.Projection;
> import com.bbn.openmap.util.Debug;
>
> import java.awt.Component;
> import java.awt.Point;
> import java.awt.event.ActionEvent;
> import java.awt.event.ActionListener;
> import java.awt.event.MouseEvent;
>
> import java.net.URL;
>
> import java.util.ArrayList;
> import java.util.Iterator;
>
> import javax.swing.ImageIcon;
> import javax.swing.JButton;
> import javax.swing.JComponent;
> import javax.swing.JLabel;
> import javax.swing.JMenu;
> import javax.swing.JSeparator;
> import javax.swing.JToggleButton;
> import javax.swing.JToolBar;
> import javax.swing.SwingConstants;
>
> /**
> * The EditableOMPoly encompasses an OMPoly, providing methods for
> * modifying or creating it.
> */
> public class EditableOMPoly extends EditableOMAbstractLine
> {
>
> protected ArrayList polyGrabPoints;
> private boolean arrayCleared = false;
> protected OffsetGrabPoint gpo; // offset
> protected OffsetGrabPoint gpm; // for grabbing the poly and
> // moving
> // it.
>
> protected OMPoly poly;
> /**
> * Whether the poly is a polygon, as opposed to a polyline. If the
> * poly color is not clear (OMColor.clear) then it will be a
> * polygon. If it is clear, then it can be set as a polygon - it's
> * otherwise assumed to be a polyline.
> */
> protected boolean manualEnclosed = false;
>
> // We'll have to handle this differently...
> public static int OFFSET_POINT_INDEX = -1;
>
> /**
> * Create the EditableOMPoly, setting the state machine to create
> * the poly off of the gestures.
> */
> public EditableOMPoly() {
> createGraphic(null);
> }
>
> /**
> * Create an EditableOMPoly with the polyType and renderType
> * parameters in the GraphicAttributes object.
> */
> public EditableOMPoly(GraphicAttributes ga) {
> createGraphic(ga);
> }
>
> /**
> * Create the EditableOMPoly with an OMPoly already defined, ready
> * for editing.
> *
> * _at_param omp OMPoly that should be edited.
> */
> public EditableOMPoly(OMPoly omp) {
> setGraphic(omp);
> }
>
> /**
> * Create and initialize the state machine that interprets the
> *
> * modifying gestures/commands, as well as ititialize the grab
> * points. Also allocates the grab point array needed by the
> * EditableOMPoly.
> */
> public void init() {
> Debug.message("eomg", "EditableOMPoly.init()");
> setStateMachine(new PolyStateMachine(this));
> gPoints = new GrabPoint[1];
> }
>
> /**
> * 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 OMPoly) {
> poly = (OMPoly) graphic;
> poly.setDoShapes(true);
> stateMachine.setSelected();
> setGrabPoints(poly);
> } else {
> createGraphic(null);
> }
> }
>
> /**
> * Method checks if the polygon should be enclosed, and then adds
> * an addition point to the end of the polygon, setting the end
> * point on top of the beginning point. The two points are
> * OffsetGrabPoints that are tied to each other's position.
> */
> public boolean evaluateEnclosed() {
> deletePoint();
> boolean enclosed = false;
>
> if (isEnclosed()) {
> enclose(true);
> enclosed = true;
> }
> return enclosed;
> }
>
> /**
> * Method connects the last point to the first point. Make sure
> * they are both OffsetGrabPoints. Return true if the points cover
> * the same pixel and if they were successfully joined.
> */
> protected boolean syncEnclosed() {
> try {
> OffsetGrabPoint gb0 = (OffsetGrabPoint) polyGrabPoints.get(0);
> OffsetGrabPoint ogb = (OffsetGrabPoint)
> polyGrabPoints.get(polyGrabPoints.size() - 1);
>
> // Check to see if they are over the same point.
> if (gb0.getX() == ogb.getX() && gb0.getY() == ogb.getY()) {
>
> // Cross connect them...
> gb0.addGrabPoint(ogb);
> ogb.addGrabPoint(gb0);
> return true;
> }
> } catch (ClassCastException cce) {
> } catch (IndexOutOfBoundsException ioobe) {
> }
> return false;
> }
>
> /**
> * Method disconnects the last point from the first point. Make
> * sure they are both OffsetGrabPoints.
> */
> protected boolean unsyncEnclosed() {
> try {
> OffsetGrabPoint gb0 = (OffsetGrabPoint) polyGrabPoints.get(0);
> OffsetGrabPoint ogb = (OffsetGrabPoint)
> polyGrabPoints.get(polyGrabPoints.size() - 1);
>
> // disconnect them...
> if (gb0.getX() == ogb.getX() && gb0.getY() == ogb.getY()) {
> gb0.removeGrabPoint(ogb);
> ogb.removeGrabPoint(gb0);
> return true;
> }
> } catch (ClassCastException cce) {
> } catch (ArrayIndexOutOfBoundsException aioobe) {
> }
> return false;
> }
>
> public void enclose(boolean e) {
>
> setEnclosed(e);
>
> if (polyGrabPoints == null) {
> return;
> }
>
> OffsetGrabPoint gb0 = (OffsetGrabPoint) polyGrabPoints.get(0);
> OffsetGrabPoint ogb;
>
> if (e) {
> // If they should be enclosed...
> if (!syncEnclosed()) {
> // And they are not already, then add a point, joined
> // to the beginning.
> ogb = new OffsetGrabPoint(gb0.getX(), gb0.getY());
>
> // Add the new point to end of the poly
> addPoint(ogb);
> syncEnclosed();
> repaint();
> } // Else nothing to do...
> } else {
> // They shouldn't be hooked up, so check to see if they
> // are, and disconnect if necessary.
> if (unsyncEnclosed()) {
> deletePoint(); // Delete attached duplicate point
> repaint();
> } // else nothing to do.
> }
> }
>
> /**
> * Set the flag to make the polygon enclosed, which automatically
> * connects the last point with the first point.
> */
> public void setEnclosed(boolean set) {
> manualEnclosed = set;
> }
>
> /**
> * Returns whether the graphic will be a polygon, instead of a
> * polyline.
> */
> public boolean isEnclosed() {
> return manualEnclosed;
> }
>
> /**
> * Create and set the graphic within the state machine. The
> * GraphicAttributes describe the type of poly to create.
> */
> public void createGraphic(GraphicAttributes ga)
> {
> init();
> stateMachine.setUndefined();
> int renderType = OMGraphic.RENDERTYPE_LATLON;
> int lineType = OMGraphic.LINETYPE_GREATCIRCLE;
>
> if (ga != null) {
> renderType = ga.getRenderType();
> lineType = ga.getLineType();
> }
>
> if (Debug.debugging("eomg")) {
> Debug.output("EditableOMPoly.createGraphic(): rendertype = "
> + renderType);
> }
>
> if (lineType == OMGraphic.LINETYPE_UNKNOWN) {
> lineType = OMGraphic.LINETYPE_GREATCIRCLE;
> ga.setLineType(OMGraphic.LINETYPE_GREATCIRCLE);
> }
>
> this.poly = (OMPoly) createGraphic(renderType, lineType);
>
> if (ga != null) {
> ga.setRenderType(poly.getRenderType());
> ga.setTo(poly);
> }
> }
>
> /**
> * Extendable method to create specific subclasses of OMPolys.
> */
> public OMGraphic createGraphic(int renderType, int lineType) {
> OMGraphic g = null;
> switch (renderType) {
> case (OMGraphic.RENDERTYPE_LATLON):
> g = new OMPoly(new float[0], OMGraphic.RADIANS, lineType);
> break;
> case (OMGraphic.RENDERTYPE_OFFSET):
> g = new OMPoly(90f, -180f, new int[0], OMPoly.COORDMODE_ORIGIN);
> break;
> default:
> g = new OMPoly(new int[0]);
> }
> ((OMPoly) g).setDoShapes(true);
> return g;
> }
>
> /**
> * Get the OMGraphic being created/modified by the EditableOMPoly.
> */
> public OMGraphic getGraphic() {
> return poly;
> }
>
> /**
> * 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);
> gpm = null;
> }
>
> /**
> * Given a MouseEvent, find a GrabPoint that it is touching, and
> * set the moving point to that GrabPoint. Called when a
> * MouseEvent happens, and you want to find out if a GrabPoint
> * should be used to make modifications to the graphic or its
> * position.
> *
> * _at_param e MouseEvent
> * _at_return GrabPoint that is touched by the MouseEvent, null if
> * none are.
> */
> public GrabPoint getMovingPoint(MouseEvent e) {
> GrabPoint gb = super.getMovingPoint(e);
>
> // Since there may be an extra point enclosing the polygon, we
> // want to make sure that the start of the polygon is
> // returned, instead of the duplicate ending point.
> int lastPointIndex = polyGrabPoints.size() - 1;
>
> if (gb != null && gb == (GrabPoint)
> polyGrabPoints.get(lastPointIndex)
> && isEnclosed()) {
>
> gb = (GrabPoint) polyGrabPoints.get(0);
> setMovingPoint(gb);
> }
> return gb;
> }
>
> /**
> * 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() {
>
> // This gets called alot. Usually, for EditableOMGraphics
> // that have the same number of GrabPoints, they can just be
> // allocated here. I think we'll have to look at the OMPoly,
> // find out how many points have been defined for it (since
> // it's variable), and make sure everything's OK.
>
> if (polyGrabPoints == null) {
> polyGrabPoints = new ArrayList();
> }
>
> // At least we know about this one.
> if (gpo == null) {
> gpo = new OffsetGrabPoint(-1, -1);
> }
> }
>
> /**
> * An internal method that trys to make sure that the grab point
> * for the first node, and for the last, in case of an enclosed
> * polygon, are OffsetGrabPoints. All of the other points will be
> * regular GrabPoints. Usually called when assigning points to a
> * previously defined poly.
> *
> * _at_param x the horizontal pixel location of the grab point.
> * _at_param y the vertical pixel location of the grab point.
> * _at_param index the index of the grab point.
> * _at_param last the index of the last point.
> */
> protected GrabPoint createGrabPoint(int x, int y, int index, int
> last) {
> if (index == 0 || (index == last && (isEnclosed()))) {
> return new OffsetGrabPoint(x, y);
> } else {
> return new GrabPoint(x, y);
> }
> }
>
> /**
> * 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 points of the graphic.
> */
> public void setGrabPoints(OMGraphic graphic) {
> if (!(graphic instanceof OMPoly)) {
> return;
> }
>
> assertGrabPoints();
> polyGrabPoints.clear();
> gpo.clear();
> arrayCleared = true;
>
> OMPoly poly = (OMPoly) graphic;
> boolean ntr = poly.getNeedToRegenerate();
> int renderType = poly.getRenderType();
> Point p = new Point();
> GrabPoint gb;
> int i;
> int npts;
>
> if (ntr == false) {
> if (renderType == OMGraphic.RENDERTYPE_LATLON) {
> Debug.message("eomg", "EditableOMPoly: modifying lat/lon line");
>
> if (projection != null) {
>
> float[] ll = poly.getLatLonArray();
>
> gb = null; //reset for this loop
>
> for (i = 0; i < ll.length; i += 2) {
> projection.forward(ll[i], ll[i + 1], p, true);
> // Need to add a grab point for this
> // coordinate
> gb = new OffsetGrabPoint((int) p.getX(), (int) p.getY());
> polyGrabPoints.add(gb);
> }
> }
>
> } else if (renderType == OMGraphic.RENDERTYPE_OFFSET) {
> // Grab the projected endpoints
> Debug.message("eomg", "EditableOMPoly: modifying offset poly");
>
> int x;
> int y;
> npts = poly.xs.length;
>
> // Check to see if the poly is a offset poly, and set
> // the
> // offset grab point accordingly.
> if (projection != null) {
> projection.forward(poly.lat, poly.lon, p, true);
>
> gpo.set((int) p.getX(), (int) p.getY());
>
> if (poly.coordMode == OMPoly.COORDMODE_ORIGIN) {
> for (i = 0; i < npts; i++) {
> x = poly.xs[i] + p.x;
> y = poly.ys[i] + p.y;
> gb = new OffsetGrabPoint(x, y);
> polyGrabPoints.add(gb);
> }
> } else { // CMode Previous offset deltas
> int lastX = p.x;
> int lastY = p.y;
>
> for (i = 0; i < npts; i++) {
> x = poly.xs[i] + lastX;
> y = poly.ys[i] + lastY;
>
> gb = new OffsetGrabPoint(x, y);
> polyGrabPoints.add(gb);
>
> lastX += x;
> lastY += y;
> }
> }
> }
>
> } else {
> npts = poly.xs.length;
>
> Debug.message("eomg", "EditableOMPoly: modifying x/y poly");
> for (i = 0; i < npts; i++) {
> gb = new OffsetGrabPoint(poly.xs[i], poly.ys[i]);
> polyGrabPoints.add(gb);
> }
> }
>
> // Add the || to maintain manualEnclosed if it was
> // externally set before the OMPoly is actually defined,
> // indicating that the user wants to draw a polygon.
> setEnclosed(syncEnclosed() || isEnclosed());
> addPolyGrabPointsToOGP(gpo);
>
> } else {
> Debug.message("eomg",
> "EditableOMPoly.setGrabPoints: graphic needs to
> be regenerated ");
> }
> }
>
> /**
> * Take the current location of the GrabPoints, and modify the
> * location parameters of the OMPoly with them. Called when you
> * want the graphic to change according to the grab points.
> */
> public void setGrabPoints() {
> int i;
> GrabPoint gb; // just to use a temp marker
> LatLonPoint llp = new LatLonPoint();
> int renderType = poly.getRenderType();
> if (renderType == OMGraphic.RENDERTYPE_LATLON) {
> if (projection != null) {
> float[] floats = new float[polyGrabPoints.size() * 2];
> for (i = 0; i < polyGrabPoints.size(); i++) {
> gb = (GrabPoint) polyGrabPoints.get(i);
> projection.inverse(gb.getX(), gb.getY(), llp);
>
> floats[2 * i] = llp.radlat_;
> floats[2 * i + 1] = llp.radlon_;
> }
>
> poly.setLocation((float[]) floats, OMGraphic.RADIANS);
> } else {
> Debug.message("eomg",
> "EditableOMPoly.setGrabPoints: projection is null, can't
> figure out LATLON points for poly.");
> }
> } else if (renderType == OMGraphic.RENDERTYPE_OFFSET) {
> // Do the offset point.
> if (projection != null) {
>
> projection.inverse(gpo.getX(), gpo.getY(), llp);
>
> } else {
> Debug.message("eomg",
> "EditableOMPoly.setGrabPoints: projection is null, can't
> figure out LATLON points for poly offset.");
> }
> }
>
> if (renderType == OMGraphic.RENDERTYPE_XY
> || renderType == OMGraphic.RENDERTYPE_OFFSET) {
>
> int[] ints = new int[polyGrabPoints.size() * 2];
> if (renderType == OMGraphic.RENDERTYPE_OFFSET && gpo != null) {
> // If offset rendertype, the x-y have to be offset
> // distances, not screen pixel locations. For the
> // polygon, you also need to take into account that
> // the ints can represent 2 different things: distance
> // from the origin (Offset) or distance from the
> // previous point. Need to check with the poly to
> // find out which to do.
> GrabPoint previous = gpo;
>
> for (i = 0; i < polyGrabPoints.size(); i++) {
> gb = (GrabPoint) polyGrabPoints.get(i);
>
> if (poly.coordMode == OMPoly.COORDMODE_PREVIOUS) {
>
> ints[2 * i] = gb.getX() - previous.getX();
> ints[2 * i + 1] = gb.getY() - previous.getY();
>
> previous = gb;
>
> } else {
> ints[2 * i] = gb.getX() - gpo.getX();
> ints[2 * i + 1] = gb.getY() - gpo.getY();
> }
> }
>
> poly.setLocation(llp.radlat_,
> llp.radlon_,
> OMGraphic.RADIANS,
> ints);
>
> } else {
>
> for (i = 0; i < polyGrabPoints.size(); i++) {
> gb = (GrabPoint) polyGrabPoints.get(i);
>
> ints[2 * i] = gb.getX();
> ints[2 * i + 1] = gb.getY();
> }
>
> poly.setLocation(ints);
> }
> }
>
> }
>
> /**
> * Add a point to the end of the polyline/polygon and then make it
> * the moving one.
> *
> * _at_return the index for the point in the polygon, starting with
> * 0.
> */
> public int addMovingPoint(int x, int y) {
> int position = addPoint(x, y);
> setMovingPoint((GrabPoint) polyGrabPoints.get(position));
> return position;
> }
>
> /**
> * Add a point to the end of the polyline/polygon.
> *
> * _at_return the index for the point in the polygon, starting with
> * 0.
> */
> public int addPoint(int x, int y) {
> return addPoint(x, y, Integer.MAX_VALUE);
> }
>
> /**
> * Add a point at a certain point in the polygon coordinate list.
> * If the position is less than zero, the point will be the
> * starting point. If the position is greater than the list of
> * current points, the point will be added to the end of the poly.
> *
> * _at_return the index for the point in the polygon, starting with
> * 0.
> */
> public int addPoint(int x, int y, int position) {
> return addPoint(new OffsetGrabPoint(x, y), position);
> }
>
> /**
> * Add a point at a certain point in the polygon coordinate list.
> * If the position is less than zero, the point will be the
> * starting point. If the position is greater than the list of
> * current points, the point will be added to the end of the poly.
> * This method is convenient because it lets you define the
> * GrabPoint object to use for the node, in case you need a
> * special type of GrabPoint.
> *
> * _at_param gp the GrabPoint set to the screen coordinates of the
> * point to be added.
> * _at_return the index for the point in the polygon, starting with
> * 0.
> */
> public int addPoint(GrabPoint gp) {
> return addPoint(gp, Integer.MAX_VALUE);
> }
>
> /**
> * Add a point at a certain point in the polygon coordinate list.
> * If the position is less than zero, the point will be the
> * starting point. If the position is greater than the list of
> * current points, the point will be added to the end of the poly.
> * This method is convenient because it lets you define the
> * GrabPoint object to use for the node, in case you need a
> * special type of GrabPoint.
> *
> * _at_return the index for the point in the polygon, starting with
> * 0.
> */
> public int addPoint(GrabPoint gp, int position) {
>
> if (gp == null) {
> return -1;
> }
>
> int x = gp.getX();
> int y = gp.getY();
>
> int renderType = poly.getRenderType();
>
> if (renderType == OMGraphic.RENDERTYPE_LATLON) {
> Debug.message("eomg",
> "EditableOMPoly: adding point to lat/lon poly");
>
> if (projection != null) {
>
> float[] ll = poly.getLatLonArray();
> int actualPosition = (position == Integer.MAX_VALUE ? ll.length
> : position * 2);
>
> LatLonPoint llpnt = projection.inverse(x, y);
>
> if (Debug.debugging("eomp")) {
> Debug.output("EditableOMPoly: adding point to lat/lon poly at "
> + x + ", " + y + ": " + llpnt + ", at the end of ");
>
> for (int j = 0; j < ll.length; j += 2) {
> Debug.output(ll[j] + ", " + ll[j + 1]);
> }
> }
>
> float[] newll = new float[ll.length + 2];
>
> if (actualPosition >= ll.length) {
> // Put the new points at the end
> if (ll.length != 0) {
> System.arraycopy(ll, 0, newll, 0, ll.length);
> }
> newll[ll.length] = llpnt.radlat_;
> newll[ll.length + 1] = llpnt.radlon_;
>
> position = ll.length / 2;
>
> } else if (actualPosition <= 0) {
> // Put the new point at the beginning
> System.arraycopy(ll, 0, newll, 2, ll.length);
> newll[0] = llpnt.radlat_;
> newll[1] = llpnt.radlon_;
> position = 0;
> } else {
> // actualPosition because there are 2 floats for
> // every
> // position.
> newll[actualPosition] = llpnt.radlat_;
> newll[actualPosition + 1] = llpnt.radlon_;
> System.arraycopy(ll, 0, newll, 0, actualPosition);
> System.arraycopy(ll,
> actualPosition,
> newll,
> actualPosition + 2,
> ll.length - actualPosition);
> }
> poly.setLocation((float[]) newll, OMGraphic.RADIANS);
> }
> } else if (renderType == OMGraphic.RENDERTYPE_XY) {
> // Grab the projected endpoints
> Debug.message("eomg", "EditableOMPoly: adding point to x/y
> poly");
> int currentLength = poly.xs.length;
> int[] newxs = new int[currentLength + 1];
> int[] newys = new int[currentLength + 1];
>
> if (position >= currentLength) {
> // Put the new points at the end
> System.arraycopy(poly.xs, 0, newxs, 0, currentLength);
> System.arraycopy(poly.ys, 0, newys, 0, currentLength);
> newxs[currentLength] = x;
> newys[currentLength] = y;
>
> position = currentLength;
>
> } else if (position <= 0) {
> // Put the new points at the beginning
> System.arraycopy(poly.xs, 0, newxs, 1, currentLength);
> System.arraycopy(poly.ys, 0, newys, 1, currentLength);
> newxs[0] = x;
> newys[0] = y;
>
> position = 0;
>
> } else {
> newxs[position] = x;
> newys[position] = y;
>
> System.arraycopy(poly.xs, 0, newxs, 0, position);
> System.arraycopy(poly.xs,
> position,
> newxs,
> position + 1,
> currentLength - position);
>
> System.arraycopy(poly.ys, 0, newys, 0, position);
> System.arraycopy(poly.ys,
> position,
> newys,
> position + 1,
> currentLength - position);
> }
>
> poly.setLocation(newxs, newys);
>
> } else {
> // Rendertype is offset...
> // Grab the projected endpoints
> Debug.message("eomg", "EditableOMPoly: adding point to offset
> poly");
> int currentLength = poly.xs.length;
> int[] newxs = new int[currentLength + 1];
> int[] newys = new int[currentLength + 1];
>
> if (position >= currentLength) {
> // Put the new points at the end
> position = currentLength;
>
> System.arraycopy(poly.xs, 0, newxs, 0, currentLength);
> System.arraycopy(poly.ys, 0, newys, 0, currentLength);
>
> } else if (position <= 0) {
> // Put the new points at the beginning
> position = 0;
>
> System.arraycopy(poly.xs, 0, newxs, 1, currentLength);
> System.arraycopy(poly.ys, 0, newys, 1, currentLength);
>
> } else {
>
> System.arraycopy(poly.xs, 0, newxs, 0, position);
> System.arraycopy(poly.xs,
> position,
> newxs,
> position + 1,
> currentLength - position);
>
> System.arraycopy(poly.ys, 0, newys, 0, position);
> System.arraycopy(poly.ys,
> position,
> newys,
> position + 1,
> currentLength - position);
> }
>
> int offsetX;
> int offsetY;
>
> if (gpo.getX() == -1 && gpo.getY() == -1) {
> offsetX = projection.getWidth() / 2;
> offsetY = projection.getHeight() / 2;
> } else {
> offsetX = gpo.getX();
> offsetY = gpo.getY();
> }
>
> if (poly.coordMode == OMPoly.COORDMODE_ORIGIN || position == 0)
> { // cover
> // the
> // first
> // point
>
> newxs[position] = x - offsetX;
> newys[position] = y - offsetY;
> } else { // CMode Previous offset deltas
> newxs[position] = x - offsetX - newxs[position - 1];
> newys[position] = y - offsetY - newys[position - 1];
> }
>
> if (position == 0) {
> // Could call projection.getCenter() but that might
> // break if/when we make other projection
> // libraries/paradigms active.
> LatLonPoint llpnt = projection.inverse(offsetX, offsetY);
> poly.lat = llpnt.radlat_;
> poly.lon = llpnt.radlon_;
> }
>
> poly.setLocation(poly.lat,
> poly.lon,
> OMGraphic.RADIANS,
> newxs,
> newys);
> }
>
> // Need to reset the arrowhead when an end point is added,
> // removing it from the shape when the point gets added.
> // Otherwise, you end up with a arrowhead at each junction of
> // the polygon.
> OMArrowHead omah = poly.getArrowHead();
> poly.setArrowHead(null);
> // This is the standard call that needs to be made here, the
> // arrowhead changes are around this.
> poly.regenerate(projection);
> // Reset the arrowhead so it will get drawn on the new
> // segment.
> poly.setArrowHead(omah);
> polyGrabPoints.add(position, gp);
>
> if (gpo != null) {
> gpo.addGrabPoint(gp);
> }
>
> return position;
> }
>
> /**
> * Delete a point off the end of the polyline/polygon.
> */
> public void deletePoint() {
> deletePoint(Integer.MAX_VALUE);
> }
>
> /**
> * Delete a point at a certain point in the polygon coordinate
> * list. If the position is less than zero, the deleted point will
> * be the starting point. If the position is greater than the list
> * of current points, the point will be deleted from the end of
> * the poly.
> */
> public void deletePoint(int position) {
>
> int renderType = poly.getRenderType();
>
> boolean needToHookUp = false;
> if (position <= 0 && isEnclosed()) {
> // if the position is 0 and the polygon is enclosed, we
> // need to disengage the two points, then reattach.
> enclose(false);
> needToHookUp = true;
> }
>
> if (renderType == OMGraphic.RENDERTYPE_LATLON) {
> Debug.message("eomg",
> "EditableOMPoly: adding point to lat/lon poly");
>
> if (projection != null) {
>
> float[] ll = poly.getLatLonArray();
> float[] newll = new float[ll.length - 2];
>
> int actualPosition = (position == Integer.MAX_VALUE ? ll.length
> : position * 2);
>
> if (actualPosition >= ll.length) {
> // Pull the new points off the end
> System.arraycopy(ll, 0, newll, 0, ll.length - 2);
> position = (ll.length - 2) / 2;
> } else if (actualPosition <= 0) {
> // Pull the new points off the beginning
> System.arraycopy(ll, 2, newll, 0, ll.length - 2);
> position = 0;
> } else {
> // actualPosition because there are 2 floats for
> // every
> // position.
> System.arraycopy(ll, 0, newll, 0, actualPosition);
> System.arraycopy(ll,
> actualPosition + 2,
> newll,
> actualPosition,
> ll.length - actualPosition - 2);
> }
> poly.setLocation((float[]) newll, OMGraphic.RADIANS);
> }
> } else {
> // Grab the projected endpoints
> Debug.message("eomg",
> "EditableOMPoly: adding point to x/y or offset
> poly");
> int currentLength = poly.xs.length;
> int[] newxs = new int[currentLength - 1];
> int[] newys = new int[currentLength - 1];
>
> if (position >= currentLength) {
> // Pull the points from the end...
> System.arraycopy(poly.xs, 0, newxs, 0, currentLength - 1);
> System.arraycopy(poly.ys, 0, newys, 0, currentLength - 1);
> position = currentLength - 1;
> } else if (position <= 0) {
> // Pull the points from the beginning...
> System.arraycopy(poly.xs, 1, newxs, 0, currentLength - 1);
> System.arraycopy(poly.ys, 1, newys, 0, currentLength - 1);
> position = 0;
> } else {
>
> System.arraycopy(poly.xs, 0, newxs, 0, position);
> System.arraycopy(poly.xs,
> position + 1,
> newxs,
> position,
> currentLength - position - 1);
>
> System.arraycopy(poly.ys, 0, newys, 0, position);
> System.arraycopy(poly.ys,
> position + 1,
> newys,
> position,
> currentLength - position - 1);
>
> }
>
> if (poly.getRenderType() == OMGraphic.RENDERTYPE_OFFSET) {
> poly.setLocation(poly.lat,
> poly.lon,
> OMGraphic.RADIANS,
> newxs,
> newys);
> } else {
> poly.setLocation(newxs, newys);
> }
> }
>
> if (projection != null) {
> poly.regenerate(projection);
> }
>
> // Remove the GrabPoint for the deleted spot.
> GrabPoint gp = (GrabPoint) polyGrabPoints.remove(position);
> if (gpo != null && gp != null) {
> gpo.removeGrabPoint(gp);
> }
>
> if (needToHookUp) {
> enclose(true);
> }
> }
>
> /**
> * 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.
> if (poly.getRenderType() == OMGraphic.RENDERTYPE_OFFSET) {
> gpm = new OffsetGrabPoint(e.getX(), e.getY());
> gpm.clear();
> } else {
> gpm = gpo;
> gpm.clear();
> gpm.set(e.getX(), e.getY());
> }
>
> // Move all the other points along with the offset point...
> addPolyGrabPointsToOGP(gpm);
>
> movingPoint = gpm;
> }
>
> /**
> * This method adds all the GrabPoints associated with the polygon
> * nodes and adds them to the offset GrabPoint representing the
> * lat/lon anchor point.
> */
> protected void addPolyGrabPointsToOGP(OffsetGrabPoint ogp) {
>
> if (ogp == null)
> return;
>
> // Reset the points to the offset point.
> int count = 0;
> Iterator gps = polyGrabPoints.iterator();
> while (gps.hasNext()) {
> GrabPoint gb = (GrabPoint) gps.next();
> ogp.addGrabPoint(gb);
> count++;
> }
>
> ogp.updateOffsets();
> }
>
> /**
> * 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.
> *
> * _at_param proj com.bbn.openmap.proj.Projection
> * _at_return true
> */
> public boolean generate(Projection proj) {
> Debug.message("eomg", "EditableOMPoly.generate()");
> if (poly != null) {
> poly.generate(proj);
> }
>
> // Generate all the grab points
> Iterator gps = polyGrabPoints.iterator();
> while (gps.hasNext()) {
> GrabPoint gb = (GrabPoint) gps.next();
> if (gb != null)
> gb.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", "EditableOMPoly.regenerate()");
> if (poly != null) {
> poly.generate(proj);
> setGrabPoints(poly);
> }
>
> //Generate all the grab points
> Iterator gps = polyGrabPoints.iterator();
> while (gps.hasNext()) {
> GrabPoint gb = (GrabPoint) gps.next();
> if (gb != null) {
> gb.generate(proj);
> }
> }
>
> if (gpo != null) {
> gpo.generate(proj);
> gpo.updateOffsets();
> }
> }
>
> /**
> * Draw the EditableOMPoly parts into the java.awt.Graphics
> * object. The grab points are only rendered if the poly machine
> * state is PolySelectedState.POLY_SELECTED.
> *
> * _at_param graphics java.awt.Graphics.
> */
> public void render(java.awt.Graphics graphics) {
> Debug.message("eomg", "EditableOMPoly.render()");
>
> State state = getStateMachine().getState();
>
> if (poly != null && !(state instanceof PolyUndefinedState)) {
> poly.setVisible(true);
> poly.render(graphics);
> poly.setVisible(false);
> } else {
> Debug.message("eomg",
> "EditableOMPoly.render: null or undefined poly.");
> return;
> }
>
> // Render the points actually on the polygon
> if (state instanceof GraphicSelectedState
> || state instanceof PolyAddNodeState
> || state instanceof PolyDeleteNodeState) {
>
> Iterator gps = polyGrabPoints.iterator();
> while (gps.hasNext()) {
> GrabPoint gb = (GrabPoint) gps.next();
> if (gb != null) {
> gb.setVisible(true);
> poly.render(graphics);
> gb.render(graphics);
> gb.setVisible(false);
> }
> }
> }
>
> // In certain condiditions, render the offset grab point.
>
> if (state instanceof GraphicSelectedState
> || state instanceof GraphicEditState /*
> * || state
> * instanceof
> * PolySetOffsetState
> */) {
> if (gpo != null
> && poly.getRenderType() == OMGraphic.RENDERTYPE_OFFSET) {
> gpo.setVisible(true);
> gpo.render(graphics);
> gpo.setVisible(false);
> }
> }
> }
>
> /////////////// Special Grab Point functions
> // /////////////////////
> // Since the GrabPoints only refer to the points actually on the
> // polygon, we have to make sure that the generic
> // EditableOMGraphic grab point methods handle that. The
> // OffsetGrabPointIndex is -1, so we have to look out for that and
> // use the gpo when appropriate.
> ///////////////////////////////////////////////////////////////////
>
> /**
> * Set the grab point objects within the EditableOMGraphic array.
> * For the EditableOMPoly, with its variable number of GrabPoints,
> * this just sets up a new list of all the grab points to look at.
> * It's different than the polyGrabPoints, which are the grab
> * points just on the polygon. This list includes the offset grab
> * point. This method should be called when a new point gets added
> * to the polygon, and should take an array of all the GrabPoints
> * created. It will add the offsetGrabPoint to the end of the
> * array.
> *
> * _at_param points a GrabPoint[] for the points on the polygon.
> * _at_return true if the grab point array was exactly what the
> * EditableOMGraphic was expecting, in terms of length of
> * the GrabPoint array length. The method copies the array
> * values that fit into the resident array.
> */
> public boolean setGrabPoints(GrabPoint[] points) {
> gPoints = new GrabPoint[points.length + 1];
> System.arraycopy(gPoints, 0, points, 0, points.length);
> gPoints[points.length] = gpo;
>
> return true;
> }
>
> /**
> * Get the array of grab points used for the EditableOMGraphic.
> * Creates the array by copying all the grab points out of the
> * ArrayList, and tacking the offset grab point to the end.
> */
> public GrabPoint[] getGrabPoints() {
> int size = polyGrabPoints.size();
>
> if (gPoints.length != size + 1 || arrayCleared) {
> Debug.message("eomg",
> "EditableOMPoly.getGrabPoints(): recreating grab
> points");
> arrayCleared = false;
> gPoints = new GrabPoint[size + 1];
> int counter = 0;
> Iterator obj = polyGrabPoints.iterator();
> while (obj.hasNext()) {
> gPoints[counter++] = (GrabPoint) obj.next();
> }
> gPoints[counter] = gpo;
> }
>
> return gPoints;
> }
>
> /**
> * Set the GrabPoint at a particule index of the array. This can
> * be used to tie two different grab points together. This used to
> * work with the gPoints array declared in EditableOMGraphic - no
> * longer. If the index is -1, the offset grab point is set, and
> * any other index refers to the concurrent polygon point.
> *
> * _at_param gb GrabPoint to assign within array.
> * _at_param index the index of the array to put the GrabPoint. This
> * index should be -1 for the offset grab point, or the
> * index of the corner of the poly, in order starting from
> * 0.
> * _at_return If the grab point or array is null, or if the index is
> * outside the range of the array, false is returned. If
> * everything goes OK, then true is returned.
> */
> public boolean setGrabPoint(GrabPoint gb, int index) {
> // We might have to take care of the offset grab point
> // connections here...
>
> if (index == OFFSET_POINT_INDEX) {
> gpo = (OffsetGrabPoint) gb;
> return true;
> } else {
> return super.setGrabPoint(gb, index);
> }
> }
>
> /**
> * Given a grab point, return its index into the polygon array. If
> * its not in the array, the next available index is returned.
> */
> public int whichGrabPoint(GrabPoint gp) {
> GrabPoint[] points = getGrabPoints();
> for (int i = 0; i < points.length; i++) {
> if (gp == points[i]) {
> if (gp == gpo) {
> return OFFSET_POINT_INDEX;
> } else {
> return i;
> }
> }
> }
> return points.length;
> }
>
> /**
> * Return a particular GrabPoint at a particular point in the
> * array. The EditableOMGraphic should describe which indexes
> * refer to which grab points in the EOMG GrabPoint array. If the
> * index is OFFSET_POINT_INDEX, the offset point is returned. If
> * the index is otherwise outside the range of the array, null is
> * returned.
> */
> public GrabPoint getGrabPoint(int index) {
> if (index == OFFSET_POINT_INDEX) {
> return gpo;
> } else {
> return super.getGrabPoint(index);
> }
> }
>
> /**
> * Adds widgets to modify polygon.
> *
> * _at_param graphicAttributes the GraphicAttributes to use to get
> * the GUI widget from to control those parameters for this
> * EOMG.
> * _at_return Component to use to control parameters for this EOMG.
> */
> public Component getGUI(GraphicAttributes graphicAttributes) {
> Debug.message("eomg", "EditableOMPoly.getGUI");
> if (graphicAttributes != null) {
> JMenu ahm = getArrowHeadMenu();
> graphicAttributes.setLineMenuAdditions(new JMenu[] { ahm });
> Component gaGUI = graphicAttributes.getGUI();
> ((JComponent) gaGUI).add(getPolyGUI());
> return gaGUI;
> } else {
> return getPolyGUI();
> }
> }
>
> protected JToggleButton polygonButton = null;
> protected JButton addButton = null;
> protected JButton deleteButton = null;
>
> public void enablePolygonButton(boolean enable) {
> if (polygonButton != null) {
> polygonButton.setEnabled(enable);
> }
> }
>
> public void enablePolygonEditButtons(boolean enable) {
> if (addButton != null) {
> addButton.setEnabled(enable);
> }
> if (deleteButton != null) {
> deleteButton.setEnabled(enable);
> }
> }
>
> public java.awt.Component getPolyGUI(boolean includeEnclose,
> boolean includeAdd,
> boolean includeDelete)
> {
> javax.swing.Box attributeBox =
> javax.swing.Box.createHorizontalBox();
>
> URL url;
> ImageIcon imageIcon;
> java.awt.Insets insets;
> int reduc_factor = 5;
>
> if (polygonButton == null) {
> url = getImageURL("enclosepoly.gif");
> imageIcon = new ImageIcon(url);
> polygonButton = new JToggleButton(imageIcon);
> polygonButton.setToolTipText(i18n.get(EditableOMPoly.class,
> "polygonButton.tooltip"
> , "Automatically link first and last nodes"));
> // Too wide margins for 1 letter look unnatural
> insets = polygonButton.getInsets();
> insets.left = 2;
> insets.right = 2;
> insets.top = insets.top / reduc_factor;
> insets.bottom = insets.bottom / reduc_factor;
> polygonButton.setMargin(insets);
>
> }
>
> polygonButton.setSelected(isEnclosed());
> polygonButton.addActionListener(new ActionListener() {
> public void actionPerformed(ActionEvent e) {
> if (getStateMachine().getState() instanceof GraphicSelectedState) {
> enclose(((JToggleButton) e.getSource()).isSelected());
> } else {
> setEnclosed(((JToggleButton) e.getSource()).isSelected());
> }
> }
> });
> if (includeEnclose) {
> attributeBox.add(polygonButton);
> }
>
> if (addButton == null)
> {
> url = getImageURL("addpoint.gif");
> imageIcon = new ImageIcon(url);
> addButton = new JButton(imageIcon);
> addButton.setToolTipText(i18n.get(EditableOMPoly.class,
> "addButton.tooltip", "Add a node to the polygon"));
> // Too wide margins for 1 letter look unnatural
> insets = addButton.getInsets();
> insets.left = 2;
> insets.right = 2;
> insets.top = insets.top / reduc_factor;
> insets.bottom = insets.bottom / reduc_factor;
> addButton.setMargin(insets);
> }
> addButton.addActionListener(new ActionListener() {
> public void actionPerformed(ActionEvent e) {
> ((PolyStateMachine) stateMachine).setAddNode();
> enablePolygonEditButtons(false);
> }
> });
> addButton.setEnabled(false);
> if (includeAdd) {
> attributeBox.add(addButton);
> }
>
> if (deleteButton == null) {
> url = getImageURL("deletepoint.gif");
> imageIcon = new ImageIcon(url);
> deleteButton = new JButton(imageIcon);
> deleteButton.setToolTipText(i18n.get(EditableOMPoly.class,
> "deleteButton.tooltip", "Delete a node from the polygon"));
> // Too wide margins for 1 letter look unnatural
> insets = deleteButton.getInsets();
> insets.left = 2;
> insets.right = 2;
> insets.top = insets.top / reduc_factor;
> insets.bottom = insets.bottom / reduc_factor;
> deleteButton.setMargin(insets);
> }
> deleteButton.addActionListener(new ActionListener() {
> public void actionPerformed(ActionEvent e) {
> ((PolyStateMachine) stateMachine).setDeleteNode();
> enablePolygonEditButtons(false);
> }
> });
> deleteButton.setEnabled(false);
> if (includeDelete) {
> attributeBox.add(deleteButton);
> }
>
> attributeBox.add(new JLabel(" "));
> attributeBox.add(new JSeparator(SwingConstants.VERTICAL));
> return attributeBox;
> }
>
> public java.awt.Component getPolyGUI()
> {return getPolyGUI(false, true, true);}
>
> public java.net.URL getImageURL(String imageName) {
> return EditableOMPoly.class.getResource(imageName);
> }
> }

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Don Dietrick, dietrick_at_bbn.com
BBN Technologies, Cambridge MA
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=



--
[To unsubscribe to this list send an email to "majdart_at_bbn.com"
with the following text in the BODY of the message "unsubscribe openmap-users"]
Received on Wed Mar 12 2008 - 00:55:59 EDT

This archive was generated by hypermail 2.3.0 : Tue Mar 28 2017 - 23:25:09 EDT