Changeset 4 in josm


Ignore:
Timestamp:
2005-09-30T01:34:07+02:00 (16 years ago)
Author:
imi
Message:

improved selection

Location:
src/org/openstreetmap/josm
Files:
2 added
3 edited
5 moved

Legend:

Unmodified
Added
Removed
  • src/org/openstreetmap/josm/actions/mapmode/DebugAction.java

    r2 r4  
    1 package org.openstreetmap.josm.actions;
     1package org.openstreetmap.josm.actions.mapmode;
    22
    33import java.awt.BorderLayout;
    44import java.awt.Color;
    55import java.awt.Graphics;
     6import java.awt.Point;
     7import java.awt.Rectangle;
    68import java.awt.event.KeyEvent;
    79import java.awt.event.MouseEvent;
     
    1113import javax.swing.JLabel;
    1214
    13 import org.openstreetmap.josm.data.GeoPoint;
     15import org.openstreetmap.josm.data.osm.LineSegment;
     16import org.openstreetmap.josm.data.osm.Track;
    1417import org.openstreetmap.josm.gui.MapFrame;
    1518import org.openstreetmap.josm.gui.MapView;
     
    2528
    2629        public DebugAction(MapFrame mapFrame) {
    27                 super("Debug Zones", "debug", KeyEvent.VK_D, mapFrame);
     30                super("Debug Zones", "debug", "Debug only. Just ignore.", KeyEvent.VK_D, mapFrame);
    2831        }
    2932       
     
    4447
    4548        public void mouseMoved(MouseEvent e) {
    46                 double lon = ((double)e.getX()/mapFrame.mapView.getWidth()*360) - 180;
    47                 double lat = 90 - (double)e.getY()/mapFrame.mapView.getHeight() * 180;
    48                 GeoPoint p = new GeoPoint(lat, lon);
    49                 mapFrame.mapView.getProjection().latlon2xy(p);
    50                 label.setText("x="+e.getX()+" y="+e.getY()+" lat="+p.lat+" lon="+p.lon+" N="+p.y+" E="+p.x);
    51                
    52                 GeoPoint mousePoint = mapFrame.mapView.getPoint(e.getX(), e.getY(), false);
    53                 GeoPoint center = mapFrame.mapView.getCenter();
    54                 double scale = mapFrame.mapView.getScale();
    55                 int xscr = (int)Math.round((mousePoint.x-center.x) / scale + mapFrame.mapView.getWidth()/2);
    56                 int yscr = (int)Math.round((center.y-mousePoint.y) / scale + mapFrame.mapView.getHeight()/2);
    57                 Graphics g = mapFrame.mapView.getGraphics();
    58                 g.setColor(Color.CYAN);
    59                 g.drawArc(xscr, yscr, 4,4,0,360);
    6049        }
    6150
    6251        public void mouseClicked(MouseEvent e) {
     52                Graphics g = mapFrame.mapView.getGraphics();
     53                g.setColor(Color.WHITE);
     54                for (Track t :mapFrame.mapView.dataSet.tracks)
     55                        for (LineSegment ls : t.segments) {
     56                                Point A = mapFrame.mapView.getScreenPoint(ls.start.coor);
     57                                Point B = mapFrame.mapView.getScreenPoint(ls.end.coor);
     58                                Point C = e.getPoint();
     59                                Rectangle r = new Rectangle(A.x, A.y, B.x-A.x, B.y-A.y);
     60                                double dist = perpendicularDistSq(B.distanceSq(C), A.distanceSq(C), A.distanceSq(B));
     61                                g.drawString(""+dist, (int)r.getCenterX(), (int)r.getCenterY());
     62                        }
     63        }
     64
     65        private double perpendicularDistSq(double a, double b, double c) {
     66                // I did this on paper by myself, so I am surprised too, that it is that
     67                // performant ;-)
     68                return a-(a-b+c)*(a-b+c)/4/c;
    6369        }
    6470
  • src/org/openstreetmap/josm/actions/mapmode/MapMode.java

    r2 r4  
    1 package org.openstreetmap.josm.actions;
     1package org.openstreetmap.josm.actions.mapmode;
    22
    33import java.awt.event.ActionEvent;
     
    3030         * @param mapFrame The parent MapFrame, this MapMode belongs to.
    3131         */
    32         public MapMode(String name, String iconName, int mnemonic, MapFrame mapFrame) {
     32        public MapMode(String name, String iconName, String tooltip, int mnemonic, MapFrame mapFrame) {
    3333                super(name, new ImageIcon("images/"+iconName+".png"));
    3434                putValue(MNEMONIC_KEY, mnemonic);
     35                putValue(LONG_DESCRIPTION, tooltip);
    3536                this.mapFrame = mapFrame;
    3637        }
  • src/org/openstreetmap/josm/actions/mapmode/SelectionAction.java

    r3 r4  
    1 package org.openstreetmap.josm.actions;
     1package org.openstreetmap.josm.actions.mapmode;
    22
    33import java.awt.Point;
     
    55import java.awt.event.KeyEvent;
    66import java.awt.event.MouseEvent;
     7import java.awt.geom.Point2D;
    78
    8 import org.openstreetmap.josm.actions.SelectionManager.SelectionEnded;
    99import org.openstreetmap.josm.data.osm.LineSegment;
    1010import org.openstreetmap.josm.data.osm.Node;
     11import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1112import org.openstreetmap.josm.data.osm.Track;
    1213import org.openstreetmap.josm.gui.MapFrame;
    1314import org.openstreetmap.josm.gui.MapView;
     15import org.openstreetmap.josm.gui.SelectionManager;
     16import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
    1417
    1518/**
     
    4245 * If both are pressed, nothing happens when releasing the mouse button.
    4346 *
     47 * The user can also only click on the map. All total movements of 2 or less
     48 * pixel are considered "only click". If that happens, the nearest Node will
     49 * be selected if there is any within 10 pixel range. If there is no Node within
     50 * 10 pixel, the nearest LineSegment (or Street, if user hold down the Alt-Key)
     51 * within 10 pixel range is selected. If there is no LineSegment within 10 pixel
     52 * and the user clicked in or 10 pixel away from an area, this area is selected.
     53 * If there is even no area, nothing is selected. Shift and Ctrl key applies to
     54 * this as usual.
     55 *
    4456 * @author imi
    4557 */
     
    6072         */
    6173        public SelectionAction(MapFrame mapFrame) {
    62                 super("Selection", "selection", KeyEvent.VK_S, mapFrame);
     74                super("Selection", "selection", "Select objects by dragging or clicking", KeyEvent.VK_S, mapFrame);
    6375                this.mv = mapFrame.mapView;
    6476                this.selectionManager = new SelectionManager(this, false, mv);
     
    94106                boolean selection = !ctrl;
    95107
    96                 // nodes
    97                 for (Node n : mv.dataSet.allNodes) {
    98                         Point sp = mv.getScreenPoint(n.coor);
    99                         if (r.contains(sp))
    100                                 n.selected = selection;
     108                // whether user only clicked, not dragged.
     109                boolean clicked = r.width <= 2 && r.height <= 2;
     110                Point2D.Double center = new Point2D.Double(r.getCenterX(), r.getCenterY());
     111
     112                try {
     113                        // nodes
     114                        double minDistanceSq = Double.MAX_VALUE;
     115                        OsmPrimitive minPrimitive = null;
     116                        for (Node n : mv.dataSet.allNodes) {
     117                                Point sp = mv.getScreenPoint(n.coor);
     118                                double dist = center.distanceSq(sp);
     119                                if (clicked && minDistanceSq > dist && dist < 100) {
     120                                        minDistanceSq = center.distanceSq(sp);
     121                                        minPrimitive = n;
     122                                } else if (r.contains(sp))
     123                                        n.selected = selection;
     124                        }
     125                        if (minPrimitive != null) {
     126                                minPrimitive.selected = selection;
     127                                return;
     128                        }
     129
     130                        // tracks
     131                        minDistanceSq = Double.MAX_VALUE;
     132                        for (Track t : mv.dataSet.tracks) {
     133                                boolean wholeTrackSelected = t.segments.size() > 0;
     134                                for (LineSegment ls : t.segments) {
     135                                        if (clicked) {
     136                                                Point A = mv.getScreenPoint(ls.start.coor);
     137                                                Point B = mv.getScreenPoint(ls.end.coor);
     138                                                double c = A.distanceSq(B);
     139                                                double a = center.distanceSq(B);
     140                                                double b = center.distanceSq(A);
     141                                                double perDist = perpendicularDistSq(a,b,c);
     142                                                if (perDist < 100 && minDistanceSq > perDist && a < c+100 && b < c+100) {
     143                                                        minDistanceSq = perDist;
     144                                                        if (alt)
     145                                                                minPrimitive = t;
     146                                                        else
     147                                                                minPrimitive = ls;
     148                                                }
     149                                        } else {
     150                                                if (alt) {
     151                                                        Point p1 = mv.getScreenPoint(ls.start.coor);
     152                                                        Point p2 = mv.getScreenPoint(ls.end.coor);
     153                                                        if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))
     154                                                                ls.selected = selection;
     155                                                        else
     156                                                                wholeTrackSelected = false;
     157                                                } else {
     158                                                        if (r.contains(mv.getScreenPoint(ls.start.coor))
     159                                                                        && r.contains(mv.getScreenPoint(ls.end.coor)))
     160                                                                ls.selected = selection;
     161                                                        else
     162                                                                wholeTrackSelected = false;
     163                                                }
     164                                        }
     165                                }
     166                                if (wholeTrackSelected && !clicked)
     167                                        t.selected = true;
     168                        }
     169                        if (minPrimitive != null) {
     170                                minPrimitive.selected = selection;
     171                                return;
     172                        }
     173                       
     174                        // TODO arrays
     175                } finally {
     176                        mv.repaint();
    101177                }
    102                
    103                 // tracks
    104                 for (Track t : mv.dataSet.tracks) {
    105                         boolean wholeTrackSelected = t.segments.size() > 0;
    106                         for (LineSegment ls : t.segments) {
    107                                 if (alt) {
    108                                         Point p1 = mv.getScreenPoint(ls.start.coor);
    109                                         Point p2 = mv.getScreenPoint(ls.end.coor);
    110                                         if (r.intersectsLine(p1.x, p1.y, p2.x, p2.y))
    111                                                 ls.selected = selection;
    112                                         else
    113                                                 wholeTrackSelected = false;
    114                                 } else {
    115                                         if (r.contains(mv.getScreenPoint(ls.start.coor)) &&
    116                                                         r.contains(mv.getScreenPoint(ls.end.coor)))
    117                                                 ls.selected = selection;
    118                                         else
    119                                                 wholeTrackSelected = false;
    120                                 }
    121                         }
    122                         if (wholeTrackSelected)
    123                                 t.selected = true;
    124                 }
    125                 mv.repaint();
     178        }
     179
     180        /**
     181         * Calculates the squared perpendicular distance named "h" from a point C to the
     182         * straight line going to the points A and B, where the distance to B is
     183         * sqrt(a) and the distance to A is sqrt(b).
     184         *
     185         * Think of a, b and c as the squared line lengths of any ordinary triangle
     186         * A,B,C. a = BC, b = AC and c = AB. The straight line goes through A and B
     187         * and the desired return value is the perpendicular distance from C to c.
     188         *
     189         * @param a Squared distance from B to C.
     190         * @param b Squared distance from A to C.
     191         * @param c Squared distance from A to B.
     192         * @return The perpendicular distance from C to c.
     193         */
     194        private double perpendicularDistSq(double a, double b, double c) {
     195                // I did this on paper by myself, so I am surprised too, that it is that
     196                // performant ;-)
     197                return a-(a-b+c)*(a-b+c)/4/c;
    126198        }
    127199}
  • src/org/openstreetmap/josm/actions/mapmode/ZoomAction.java

    r2 r4  
    1 package org.openstreetmap.josm.actions;
     1package org.openstreetmap.josm.actions.mapmode;
    22
    33import java.awt.Rectangle;
    44import java.awt.event.KeyEvent;
    55
    6 import org.openstreetmap.josm.actions.SelectionManager.SelectionEnded;
    76import org.openstreetmap.josm.data.GeoPoint;
    87import org.openstreetmap.josm.gui.MapFrame;
    98import org.openstreetmap.josm.gui.MapView;
     9import org.openstreetmap.josm.gui.SelectionManager;
     10import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
    1011
    1112/**
     
    3738         */
    3839        public ZoomAction(MapFrame mapFrame) {
    39                 super("Zoom", "zoom", KeyEvent.VK_Z, mapFrame);
     40                super("Zoom", "zoom", "Zoom in by dragging", KeyEvent.VK_Z, mapFrame);
    4041                mv = mapFrame.mapView;
    4142                selectionManager = new SelectionManager(this, true, mv);
  • src/org/openstreetmap/josm/gui/IconToggleButton.java

    r1 r4  
    22
    33import javax.swing.Action;
     4import javax.swing.JComponent;
    45import javax.swing.JToggleButton;
    56
     
    1516         * Construct the toggle button with the given action.
    1617         */
    17         public IconToggleButton(Action action) {
     18        public IconToggleButton(JComponent acceleratorReceiver, Action action) {
    1819                super(action);
    1920                setText(null);
     21                Object o = action.getValue(Action.LONG_DESCRIPTION);
     22                if (o != null)
     23                        setToolTipText(o.toString());
    2024        }
    2125}
  • src/org/openstreetmap/josm/gui/MapFrame.java

    r2 r4  
    2525import javax.swing.event.ChangeListener;
    2626
    27 import org.openstreetmap.josm.actions.DebugAction;
    28 import org.openstreetmap.josm.actions.MapMode;
    29 import org.openstreetmap.josm.actions.SelectionAction;
    30 import org.openstreetmap.josm.actions.ZoomAction;
     27import org.openstreetmap.josm.actions.mapmode.DebugAction;
     28import org.openstreetmap.josm.actions.mapmode.MapMode;
     29import org.openstreetmap.josm.actions.mapmode.SelectionAction;
     30import org.openstreetmap.josm.actions.mapmode.ZoomAction;
    3131import org.openstreetmap.josm.data.Preferences;
    3232import org.openstreetmap.josm.data.osm.DataSet;
     
    125125               
    126126                toolBarActions.setFloatable(false);
    127                 toolBarActions.add(new IconToggleButton(new ZoomAction(this)));
    128                 toolBarActions.add(new IconToggleButton(new SelectionAction(this)));
    129                 toolBarActions.add(new IconToggleButton(new DebugAction(this)));
     127                toolBarActions.add(new IconToggleButton(this, new ZoomAction(this)));
     128                toolBarActions.add(new IconToggleButton(this, new SelectionAction(this)));
     129                toolBarActions.add(new IconToggleButton(this, new DebugAction(this)));
    130130
    131131                // all map modes in one button group
     
    138138                // autoScale
    139139                toolBarActions.addSeparator();
    140                 final JToggleButton autoScaleButton = new IconToggleButton(mapView.new AutoScaleAction());
     140                final JToggleButton autoScaleButton = new IconToggleButton(this, mapView.new AutoScaleAction());
    141141                toolBarActions.add(autoScaleButton);
    142142                autoScaleButton.setText(null);
     
    149149
    150150                // properties
    151                 toolBarActions.add(new IconToggleButton(new PropertiesAction()));
     151                toolBarActions.add(new IconToggleButton(this, new PropertiesAction()));
    152152        }
    153153
  • src/org/openstreetmap/josm/gui/MapView.java

    r2 r4  
    22
    33import java.awt.Color;
    4 import java.awt.Component;
    54import java.awt.Graphics;
    65import java.awt.Point;
     
    1413import javax.swing.AbstractAction;
    1514import javax.swing.ImageIcon;
     15import javax.swing.JComponent;
    1616import javax.swing.event.ChangeEvent;
    1717import javax.swing.event.ChangeListener;
     
    3737 * @author imi
    3838 */
    39 public class MapView extends Component implements ComponentListener, ChangeListener {
     39public class MapView extends JComponent implements ComponentListener, ChangeListener {
    4040
    4141        /**
     
    251251                        for (Track track : dataSet.tracks)
    252252                                for (LineSegment ls : track.segments) {
    253                                         g.setColor(ls.selected ? Color.WHITE : Color.GRAY);
     253                                        g.setColor(ls.selected || track.selected ? Color.WHITE : Color.GRAY);
    254254                                        g.drawLine(toScreenX(ls.start.coor.x), toScreenY(ls.start.coor.y),
    255255                                                        toScreenX(ls.end.coor.x), toScreenY(ls.end.coor.y));
  • src/org/openstreetmap/josm/gui/SelectionManager.java

    r3 r4  
    1 package org.openstreetmap.josm.actions;
     1package org.openstreetmap.josm.gui;
    22
    33import java.awt.Color;
Note: See TracChangeset for help on using the changeset viewer.