Changeset 5076 in osm for applications/editors/josm


Ignore:
Timestamp:
2007-10-19T00:13:15+02:00 (17 years ago)
Author:
gabriel
Message:

utilsplugin: Port to API 0.5.

Location:
applications/editors/josm/plugins/utilsplugin
Files:
5 added
3 deleted
4 copied

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/utilsplugin/src/UtilsPlugin/MergeNodeWayAction.java

    r5075 r5076  
    44
    55import java.util.ArrayList;
    6 import java.util.Arrays;
    76import java.util.LinkedList;
    87import java.util.Collection;
     8import java.util.Collections;
     9import java.util.List;
     10import java.util.HashMap;
     11import java.util.HashSet;
     12import java.util.Map;
    913
    1014import java.awt.event.ActionEvent;
     
    1216import org.openstreetmap.josm.Main;
    1317import org.openstreetmap.josm.data.osm.Node;
    14 import org.openstreetmap.josm.data.osm.Segment;
     18import org.openstreetmap.josm.data.osm.WaySegment;
    1519import org.openstreetmap.josm.data.osm.Way;
    1620import org.openstreetmap.josm.gui.MapFrame;
    1721import org.openstreetmap.josm.plugins.Plugin;
     22import org.openstreetmap.josm.actions.JosmAction;
    1823import org.openstreetmap.josm.command.Command;
    1924import org.openstreetmap.josm.command.AddCommand;
     
    2530import javax.swing.AbstractAction;
    2631
    27 class MergePointLineAction extends AbstractAction {
    28         public MergePointLineAction() {
    29             super("Join Point and Segment");
     32class MergeNodeWayAction extends JosmAction {
     33        public MergeNodeWayAction() {
     34            super(tr("Join node to way"), "mergenodeway",
     35                        tr("Join a node into the nearest way segments"), 0, 0, true);
    3036        }
     37
    3138        public void actionPerformed(ActionEvent e) {
    3239                Collection<OsmPrimitive> sel = Main.ds.getSelected();
    33                 Node node = null;
    34                 Segment seg = null;
    35                 Way way = null;
     40                if (sel.size() != 1 || !(sel.iterator().next() instanceof Node)) return;
     41                Node node = (Node) sel.iterator().next();
    3642
    37                 boolean error = false;         
    38                 for (OsmPrimitive osm : sel)
    39                 {
    40                         if (osm instanceof Node)
    41                                 if( node == null )
    42                                         node = (Node)osm;
    43                                 else
    44                                         error = true;
    45                         if (osm instanceof Segment)
    46                                 if( seg == null )
    47                                         seg = (Segment)osm;
    48                                 else
    49                                         error = true;
    50                         if (osm instanceof Way)
    51                                 if( way == null )
    52                                         way = (Way)osm;
    53                                 else
    54                                         error = true;
    55                 }
    56                 if( node == null || !(seg == null ^ way == null))
    57                         error = true;
    58                 if( error )
    59                 {
    60                         javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("Must select one node and one segment/way."));
    61                         return;
    62                 }
    63                 if( way != null )
    64                 {
    65                         if( way.isIncomplete() )
    66                         {
    67                                 javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("Selected way must be complete."));
    68                                 return;
     43                List<WaySegment> wss = Main.map.mapView.getNearestWaySegments(
     44                        Main.map.mapView.getPoint(node.eastNorth));
     45                HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
     46                for (WaySegment ws : wss) {
     47                        List<Integer> is;
     48                        if (insertPoints.containsKey(ws.way)) {
     49                                is = insertPoints.get(ws.way);
     50                        } else {
     51                                is = new ArrayList<Integer>();
     52                                insertPoints.put(ws.way, is);
    6953                        }
    70                         double mindist = 0;
    71 //                      System.out.println( node.toString() );
    72                         // If the user has selected a way and a point, we need to determine the segment that is closest to the given point.
    73                         for (Segment s : way.segments )
    74                         {
    75                                 if( s.incomplete )
    76                                         continue;
    77                                        
    78 //                              System.out.println( s.toString() );
    79                                 double dx1 = s.from.coor.lat() - node.coor.lat();
    80                                 double dy1 = s.from.coor.lon() - node.coor.lon();
    81                                 double dx2 = s.to.coor.lat() - node.coor.lat();
    82                                 double dy2 = s.to.coor.lon() - node.coor.lon();
    83                                
    84 //                              System.out.println( dx1+","+dx2+" && "+dy1+","+dy2 );
    85                                 double len1 = Math.sqrt(dx1*dx1+dy1*dy1);
    86                                 double len2 = Math.sqrt(dx2*dx2+dy2*dy2);
    87                                 dx1 /= len1;
    88                                 dy1 /= len1;
    89                                 dx2 /= len2;
    90                                 dy2 /= len2;
    91 //                              System.out.println( dx1+","+dx2+" && "+dy1+","+dy2 );
    92                                
    93                                 double dist = dx1*dx2 + dy1*dy2;
    94 //                              System.out.println( "Dist: "+dist );
    95                                 if( dist < mindist )
    96                                 {
    97                                         mindist = dist;
    98                                         seg = s;
    99                                 }
    100                         }
    101                         if( seg == null )
    102                         {
    103                                 javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("No segment found in range"));
    104                                 return;
     54
     55                        if (ws.way.nodes.get(ws.lowerIndex) != node
     56                                        && ws.way.nodes.get(ws.lowerIndex+1) != node) {
     57                                is.add(ws.lowerIndex);
    10558                        }
    10659                }
    10760
    108                 if( seg.incomplete )
    109                 {
    110                         javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("Both objects must be complete."));
    111                         return;
     61                Collection<Command> cmds = new LinkedList<Command>();
     62                for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
     63                        Way w = insertPoint.getKey();
     64                        Way wnew = new Way(w);
     65                        List<Integer> is = insertPoint.getValue();
     66                        pruneSuccsAndReverse(is);
     67                        for (int i : is) wnew.nodes.add(i+1, node);
     68                        cmds.add(new ChangeCommand(w, wnew));
    11269                }
    113                 if( node == seg.from || node == seg.to )
    114                 {
    115                         javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("Node can't be endpoint of segment"));
    116                         return;
    117                 }
    118                 // Now do the merging
    119                 Collection<Command> cmds = new LinkedList<Command>();
    120                 Segment newseg1 = new Segment(seg);
    121                 newseg1.to = node;
    122                 Segment newseg2 = new Segment(node, seg.to);
    123                 if (seg.keys != null)
    124                         newseg2.keys = new java.util.HashMap<String, String>(seg.keys);
    125                 newseg2.selected = newseg1.selected;
    126                                                
    127                 cmds.add(new ChangeCommand(seg,newseg1));
    128                 cmds.add(new AddCommand(newseg2));
    129                
    130                 // find ways affected and fix them up...
    131                 for (final Way w : Main.ds.ways)
    132                 {
    133                         if( w.deleted )
    134                                 continue;
    135                         int pos = w.segments.indexOf(seg);
    136                         if( pos == -1 )
    137                                 continue;
    138                         Way newway = new Way(w);
    139                         newway.segments.add(pos+1, newseg2);
    140                         cmds.add(new ChangeCommand(w,newway));
    141                 }
    142                 Main.main.editLayer().add(new SequenceCommand(tr("Join Node and Line"), cmds));
     70
     71                Main.main.undoRedo.add(new SequenceCommand(tr("Join Node and Line"), cmds));
    14372                Main.map.repaint();
    14473        }
    145     }
     74
     75        private static void pruneSuccsAndReverse(List<Integer> is) {
     76                //if (is.size() < 2) return;
     77
     78                HashSet<Integer> is2 = new HashSet<Integer>();
     79                for (int i : is) {
     80                        if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
     81                                is2.add(i);
     82                        }
     83                }
     84                is.clear();
     85                is.addAll(is2);
     86                Collections.sort(is);
     87                Collections.reverse(is);
     88        }
     89}
  • applications/editors/josm/plugins/utilsplugin/src/UtilsPlugin/MergeNodesAction.java

    r5075 r5076  
    44
    55import java.util.ArrayList;
    6 import java.util.Arrays;
    76import java.util.LinkedList;
    87import java.util.Collection;
     8import java.util.Collections;
    99
    1010import java.awt.event.ActionEvent;
     
    1313import org.openstreetmap.josm.data.osm.OsmPrimitive;
    1414import org.openstreetmap.josm.data.osm.Node;
    15 import org.openstreetmap.josm.data.osm.Segment;
    1615import org.openstreetmap.josm.data.osm.Way;
     16import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
     17import org.openstreetmap.josm.data.coor.EastNorth;
    1718import org.openstreetmap.josm.gui.MapFrame;
    1819import org.openstreetmap.josm.plugins.Plugin;
     20import org.openstreetmap.josm.actions.JosmAction;
    1921import org.openstreetmap.josm.command.Command;
    2022import org.openstreetmap.josm.command.AddCommand;
     
    2426
    2527import javax.swing.AbstractAction;
     28import javax.swing.JOptionPane;
    2629
    27 class MergePointsAction extends AbstractAction {
    28         public MergePointsAction() {
    29                 super("Merge Points");
     30class MergeNodesAction extends JosmAction {
     31        public MergeNodesAction() {
     32                super(tr("Merge nodes"), "mergenodes",
     33                        tr("Merge nodes"), 0, 0, true);
    3034        }
     35
    3136        public void actionPerformed(ActionEvent e) {
    3237                Collection<OsmPrimitive> sel = Main.ds.getSelected();
    33                 Collection<OsmPrimitive> nodes = new ArrayList<OsmPrimitive>();
    34                 Node target = null;
     38                Collection<Node> nodes = new ArrayList<Node>();
     39
    3540                for (OsmPrimitive osm : sel)
    3641                        if (osm instanceof Node)
    3742                                nodes.add((Node)osm);
    3843                if (nodes.size() < 2) {
    39                         javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("Must select at least two nodes."));
     44                        JOptionPane.showMessageDialog(Main.parent,
     45                                tr("Must select at least two nodes."));
    4046                        return;
    4147                }
    42                 for ( OsmPrimitive o : nodes )
    43                 {
    44                         Node n = (Node)o;
    45                         if( target == null || target.id == 0 )
    46                         {
     48
     49                // Find the node with the lowest ID.
     50                // We're gonna keep our 3-digit node ids.
     51                Node target = null;
     52                for (Node n : nodes) {
     53                        if (target == null || target.id == 0 || n.id < target.id) {
    4754                                target = n;
    48                                 continue;
    4955                        }
    50                         if( n.id == 0 )
    51                                 continue;
    52                         if( n.id < target.id )
    53                                 target = n;
    5456                }
    55 //              System.out.println( "Selected: "+target.toString() );
     57
     58                Collection<Command> cmds = new LinkedList<Command>();
     59
     60                Node newTarget = new Node(target);
     61                cmds.add(new ChangeCommand(target, newTarget));
     62
     63                // Don't place the merged node on one of the former nodes.
     64                // Place it right there in the middle.
     65                double x = 0, y = 0;
     66                for (Node n : nodes) {
     67                        x += n.eastNorth.east();
     68                        y += n.eastNorth.north();
     69                }
     70                newTarget.eastNorth = new EastNorth(
     71                        x / nodes.size(), y / nodes.size());
     72
    5673                nodes.remove(target);
    57                
    58                 // target is what we're merging into
    59                 // nodes is the list of nodes to be removed
    60                 // Since some segment may disappear, we need to track those too
    61                 Collection<OsmPrimitive> seglist = new ArrayList<OsmPrimitive>();
    62                                
    63                 // Now do the merging
    64                 Collection<Command> cmds = new LinkedList<Command>();
    65                 for (final Segment s : Main.ds.segments)
    66                 {
    67                         if( s.deleted || s.incomplete )
    68                                 continue;
    69                         if( !nodes.contains( s.from ) && !nodes.contains( s.to ) )
    70                                 continue;
    71                                
    72                         Segment newseg = new Segment(s);
    73                         if( nodes.contains( s.from ) )
    74                                 newseg.from = target;
    75                         if( nodes.contains( s.to ) )
    76                                 newseg.to = target;
    7774
    78                         // Is this node now a NULL node?
    79                         if( newseg.from == newseg.to )
    80                                 seglist.add(s);
    81                         else
    82                                 cmds.add(new ChangeCommand(s,newseg));
    83                 }
    84                 if( seglist.size() > 0 )  // Some segments to be deleted?
    85                 {
    86                         // We really want to delete this, but we must check if it is part of a way first
    87                         for (final Way w : Main.ds.ways)
    88                         {
    89                                 Way newway = null;
    90                                 if( w.deleted )
    91                                         continue;
    92                                 for (final OsmPrimitive o : seglist )
    93                                 {
    94                                         Segment s = (Segment)o;
    95                                         if( w.segments.contains(s) )
    96                                         {
    97                                                 if( newway == null )
    98                                                         newway = new Way(w);
    99                                                 newway.segments.remove(s);
    100                                         }
    101                                 }
    102                                 if( newway != null )   // Made changes?
    103                                 {
    104                                         // If no segments left, delete the way
    105                                         if( newway.segments.size() == 0 )
    106                                                 cmds.add(makeDeleteCommand(w));
    107                                         else
    108                                                 cmds.add(new ChangeCommand(w,newway));
     75                cmds.add(new DeleteCommand(nodes));
     76
     77                for (Way w : Main.ds.ways) {
     78                        if (w.deleted || w.incomplete) continue;
     79
     80                        boolean affected = false;
     81                        for (Node n : nodes) {
     82                                if (w.nodes.contains(n)) {
     83                                        affected = true;
     84                                        break;
    10985                                }
    11086                        }
    111                         cmds.add(new DeleteCommand(seglist));
     87                        if (!affected) continue;
     88
     89                        // Replace the old nodes with the merged ones
     90                        Way wnew = new Way(w);
     91                        for (int i = 0; i < wnew.nodes.size(); i++) {
     92                                if (nodes.contains(wnew.nodes.get(i))) {
     93                                        wnew.nodes.set(i, newTarget);
     94                                }
     95                        }
     96
     97                        // Remove duplicates
     98                        Node lastN = null;
     99                        for (int i = wnew.nodes.size() - 1; i >= 0; i--) {
     100                                if (lastN == wnew.nodes.get(i)) {
     101                                        wnew.nodes.remove(i);
     102                                        if (i < wnew.nodes.size()) i++;
     103                                }
     104                        }
     105
     106                        if (wnew.nodes.size() < 2) {
     107                                CollectBackReferencesVisitor backRefV =
     108                                        new CollectBackReferencesVisitor(Main.ds, false);
     109                                backRefV.visit(w);
     110                                if (!backRefV.data.isEmpty()) {
     111                                        JOptionPane.showMessageDialog(Main.parent,
     112                                                tr("Cannot merge nodes: " +
     113                                                        "Would have to delete way that is still used."));
     114                                        return;
     115                                }
     116
     117                                cmds.add(new DeleteCommand(Collections.singleton(w)));
     118                        } else {
     119                                cmds.add(new ChangeCommand(w, wnew));
     120                        }
    112121                }
    113122
    114                 cmds.add(new DeleteCommand(nodes));
    115                 Main.main.editLayer().add(new SequenceCommand(tr("Merge Nodes"), cmds));
     123                Main.main.undoRedo.add(new SequenceCommand(tr("Merge Nodes"), cmds));
    116124                Main.map.repaint();
    117125        }
    118         private DeleteCommand makeDeleteCommand(OsmPrimitive obj)
    119         {
    120           return new DeleteCommand(Arrays.asList(new OsmPrimitive[]{obj}));
    121         }
    122126}
    123 
  • applications/editors/josm/plugins/utilsplugin/src/UtilsPlugin/SimplifyWayAction.java

    r5075 r5076  
    55import java.awt.event.ActionEvent;
    66import java.util.ArrayList;
    7 import java.util.Arrays;
    87import java.util.Collection;
    9 import java.util.Comparator;
    10 import java.util.HashMap;
     8import java.util.Collections;
    119import java.util.HashSet;
    1210import java.util.LinkedList;
     
    1816import org.openstreetmap.josm.command.DeleteCommand;
    1917import org.openstreetmap.josm.command.SequenceCommand;
    20 import org.openstreetmap.josm.data.SelectionChangedListener;
    2118import org.openstreetmap.josm.data.coor.LatLon;
    2219import org.openstreetmap.josm.data.osm.Node;
    2320import org.openstreetmap.josm.data.osm.OsmPrimitive;
    24 import org.openstreetmap.josm.data.osm.Segment;
    2521import org.openstreetmap.josm.data.osm.Way;
    26 import org.openstreetmap.josm.data.osm.visitor.Visitor;
     22import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
    2723
    2824import org.openstreetmap.josm.data.osm.DataSet;
    2925import org.openstreetmap.josm.actions.JosmAction;
    3026
    31 /**
    32  * Forgets the selected data, unless it is referenced by something.
    33  *
    34  * "Forgetting", as opposed to "deleting", means that the data is simply removed from JOSM, and
    35  * not tagged as "to be deleted on server".
    36  *
    37  * - selected WAYS can always be forgotten.
    38  * - selected SEGMENTS can be forgotten unless they are referenced by not-forgotten ways.
    39  * - selected NODES can be forgotten unless they are referenced by not-forgotten segments.
    40  */
    41 
    42 public class SimplifyWayAction extends JosmAction implements SelectionChangedListener {
    43 
    44        
    45         private Way selectedWay = null;
    46 
    47         /**
    48          * Create a new SimplifyWayAction.
     27public class SimplifyWayAction extends JosmAction {
     28        public SimplifyWayAction() {
     29                super(tr("Simplify Way"), "simplify",
     30                        tr("Delete unnecessary nodes from a way."), 0, 0, true);
     31        }
     32
     33        public void actionPerformed(ActionEvent e) {
     34                Collection<OsmPrimitive> selection = Main.ds.getSelected();
     35
     36                if (selection.size() == 1 && selection.iterator().next() instanceof Way) {
     37                        simplifyWay((Way) selection.iterator().next());
     38                }
     39        }
     40
     41        public void simplifyWay(Way w) {
     42                double threshold = Double.parseDouble(
     43                        Main.pref.get("simplify-way.max-error", "50"));
     44
     45                Way wnew = new Way(w);
     46
     47                int toI = wnew.nodes.size() - 1;
     48                for (int i = wnew.nodes.size() - 1; i >= 0; i--) {
     49                        CollectBackReferencesVisitor backRefsV =
     50                                new CollectBackReferencesVisitor(Main.ds, false);
     51                        backRefsV.visit(wnew.nodes.get(i));
     52                        boolean used = false;
     53                        if (backRefsV.data.size() == 1) {
     54                                used = Collections.frequency(
     55                                        w.nodes, wnew.nodes.get(i)) > 1;
     56                        } else {
     57                                backRefsV.data.remove(w);
     58                                used = !backRefsV.data.isEmpty();
     59                        }
     60
     61                        if (used) {
     62                                if (toI - i >= 2) {
     63                                        ArrayList<Node> ns = new ArrayList<Node>();
     64                                        simplifyWayRange(wnew, i, toI, ns, threshold);
     65                                        for (int j = toI-1; j > i; j--) wnew.nodes.remove(j);
     66                                        wnew.nodes.addAll(i+1, ns);
     67                                }
     68                                toI = i;
     69                        }
     70                }
     71
     72                HashSet<Node> delNodes = new HashSet<Node>();
     73                delNodes.addAll(w.nodes);
     74                delNodes.removeAll(wnew.nodes);
     75
     76                if (wnew.nodes.size() != w.nodes.size()) {
     77                        Collection<Command> cmds = new LinkedList<Command>();
     78                        cmds.add(new ChangeCommand(w, wnew));
     79                        cmds.add(new DeleteCommand(delNodes));
     80                        Main.main.undoRedo.add(
     81                                new SequenceCommand(tr("Simplify Way (remove {0} nodes)",
     82                                                delNodes.size()),
     83                                        cmds));
     84                        Main.map.repaint();
     85                }
     86        }
     87
     88        /*
     89         * Takes an interval [from,to] and adds nodes from the set (from,to) to
     90         * ns.
    4991         */
    50         public SimplifyWayAction() {
    51                 super(tr("Simplify Way"), "simplify", tr("Delete low-information nodes from a way."), 0, 0, true);
    52                 try { Main.ds.addSelectionChangedListener(this); }
    53                 catch( NoSuchMethodError e )
    54                 {
    55                         try {
    56                         java.lang.reflect.Field f = DataSet.class.getDeclaredField("listeners");
    57                         ((Collection<SelectionChangedListener>)f.get(Main.ds)).add(this);
    58 //                      Main.ds.listeners.add(this);
    59                         } catch (Exception x) { System.out.println( e ); }
    60                 }
    61         }
    62 
    63         /**
    64          * Called when the action is executed.
    65          */
    66         public void actionPerformed(ActionEvent e) {
    67 
    68                 Collection<OsmPrimitive> selection = Main.ds.getSelected();
    69 
    70 
    71                 Visitor selectVisitor = new Visitor(){
    72                         public void visit(Node n) {
    73             }
    74                         public void visit(Segment s) {
    75             }
    76                         public void visit(Way w) {
    77                                 selectedWay = w;
    78             }
    79                 };
    80                
    81                 for (OsmPrimitive p : selection)
    82                         p.visit(selectVisitor);
    83                
    84                 simplifyWay(selectedWay);
    85         }
    86 
    87         private class NodeRecord {
    88                 public boolean keep = false; // whether this node must be kept
    89                 public Node node; // the node
    90                 public NodeRecord previous; // the segment leading to this node
    91                 public double xte; // the cross-track error
    92                 public NodeRecord next;
    93         }
    94        
    95         /**
    96          * Simplifies the given way by potentially removing nodes and segments.
    97          *
    98          * @param way
    99          * @return true if simplification was successful (even if way was not changed)
    100          *         false if simplification was not possible (branching/unordered ways)
    101          */
    102         public boolean simplifyWay(Way way) {
    103                
    104                 // first build some structures that help us working with this way, assuming
    105                 // it might be very long, so we want to be efficient.
    106                
    107                 // a map holding one NodeRecord object for every node in the way, except
    108                 // the first node (which is never "simplified" anyway)
    109                 HashMap<Node,NodeRecord> nodeIndex = new HashMap<Node,NodeRecord>();
    110                
    111                 // a hash set containing all segments in this way, for fast is-in-way checks
    112                 HashSet<Segment> segmentIndex = new HashSet<Segment>();
    113                
    114                 // in addition to all this, we also have each NodeRecord pointing
    115                 // to the next one along the way, making a linked list.
    116                 NodeRecord firstNr = null;
    117                
    118                 // fill structures
    119                 NodeRecord prevNr = null;
    120                 for (Segment s : way.segments) {
    121                         if ((prevNr != null) && (!s.from.equals(prevNr.node))) {
    122                                 // error
    123                                 System.out.println("XXX err");
    124                                 return false;
    125                         }
    126                         segmentIndex.add(s);
    127                         NodeRecord nr = new NodeRecord();
    128                         nr.node = s.to;
    129                         if (prevNr == null) {
    130                                 nr.previous = new NodeRecord();
    131                                 nr.previous.node = s.from;
    132                                 // set "keep" on first node
    133                                 nr.previous.keep = true;
    134                                 firstNr = nr.previous;
    135                                 firstNr.next = nr;
    136                                 nodeIndex.put(s.from, nr.previous);
    137                         } else {
    138                                 nr.previous = prevNr;
    139                                 prevNr.next = nr;
    140                         }
    141                         nr.xte = 0;
    142                         nr.next = null;
    143                         prevNr = nr;
    144                         nodeIndex.put(s.to, nr);
    145                 }
    146                
    147                 // set "keep" on last node
    148                 prevNr.keep = true;
    149                
    150                 // check the current data set, and mark all nodes that are used by a segment
    151                 // not exclusively owned by the current way as "untouchable".
    152                 for (Segment s: Main.ds.segments) {
    153                         if (s.deleted) continue;
    154                         if (segmentIndex.contains(s)) continue; // these don't count
    155                         NodeRecord tmp;
    156                         tmp = nodeIndex.get(s.from); if (tmp != null) tmp.keep = true;
    157                         tmp = nodeIndex.get(s.to); if (tmp != null) tmp.keep = true;
    158                 }
    159                
    160                 for (Way w: Main.ds.ways) {
    161                         if (w.deleted) continue;
    162                         if (w.equals(way)) continue; // these don't count
    163                         for (Segment s: w.segments)
    164                         {
    165                                 NodeRecord tmp;
    166                                 tmp = nodeIndex.get(s.from); if (tmp != null) tmp.keep = true;
    167                                 tmp = nodeIndex.get(s.to); if (tmp != null) tmp.keep = true;
    168                         }
    169                 }
    170                
    171                 // keep all nodes which have tags other than source and created_by
    172                 for (NodeRecord nr : nodeIndex.values()) {
    173                         Collection<String> keyset = nr.node.keySet();
    174                         keyset.remove("source");
    175                         keyset.remove("created_by");
    176                         if (!keyset.isEmpty()) nr.keep = true;
    177                 }
    178                
    179                 // compute cross-track error for all elements. cross-track error is the
    180                 // distance between a node and the nearest point on a line from the
    181                 // previous to the next node - that's the error you would introduce
    182                 // by removing the node.
    183                 for (NodeRecord r = firstNr; r.next != null; r = r.next) {
    184                         computeXte(r);
    185                 }
    186                
    187                 boolean stayInLoop = true;
    188                 double treshold = Double.parseDouble(Main.pref.get("simplify-way.max-error", "0.06"));
    189                 while(stayInLoop) {
    190                         NodeRecord[] sorted = new NodeRecord[nodeIndex.size()];
    191                         nodeIndex.values().toArray(sorted);
    192                         Arrays.sort(sorted, new Comparator<NodeRecord>() {
    193                                 public int compare(NodeRecord a, NodeRecord b) {
    194                                         return (a.xte < b.xte) ? -1 : (a.xte > b.xte) ? 1 : 0;
    195                                 }
    196                         });
    197 
    198                         stayInLoop = false;
    199                         for (NodeRecord nr : sorted) {
    200                                 if (nr.keep) continue;
    201                                 if (nr.xte < treshold) {
    202                                         // delete this node
    203                                         nodeIndex.remove(nr.node);
    204                                         if (nr == firstNr) {
    205                                                 firstNr = nr.next;
    206                                         } else {
    207                                                 nr.previous.next = nr.next;
    208                                         }
    209                                         if (nr.next != null) {
    210                                                 nr.next.previous = nr.previous;
    211                                         }
    212                                         computeXte(nr.next);
    213                                         computeXte(nr.previous);
    214                                         stayInLoop = true;
    215                                 }
    216                                 break;
    217                         }
    218                 }
    219                
    220                 Segment currentOriginalSegment = null;
    221                 Segment currentModifiedSegment = null;
    222                 Way wayCopy = null;
    223                 int delCount = 0;
    224                 Collection<Command> cmds = new LinkedList<Command>();
    225                
    226                 for (Segment s : way.segments) {
    227                         if (currentOriginalSegment == null) {
    228                                 currentOriginalSegment = s;
    229                                 currentModifiedSegment = s;
    230                                 continue;
    231                         }
    232                        
    233                         if (nodeIndex.containsKey(s.from)) {
    234                                 // the current remaining segment's "to" node is not
    235                                 // deleted, so it may stay.
    236                                 if (currentModifiedSegment != currentOriginalSegment) {
    237                                         cmds.add(new ChangeCommand(currentOriginalSegment, currentModifiedSegment));
    238                                 }
    239                                 currentOriginalSegment = s;
    240                                 currentModifiedSegment = s;
    241                         } else {
    242                                 // the "to" node is to be deleted; delete segment and
    243                                 // node
    244                                 cmds.add(new DeleteCommand(Arrays.asList(new OsmPrimitive[]{s, s.from})));
    245                                 delCount ++;
    246                                 if (wayCopy == null) {
    247                                         wayCopy = new Way(way);
    248                                 }
    249                                 wayCopy.segments.remove(s);
    250                                 if (currentModifiedSegment == currentOriginalSegment) {
    251                                         currentModifiedSegment = new Segment(currentOriginalSegment);
    252                                 }
    253                                 currentModifiedSegment.to = s.to;
    254                         }
    255                 }
    256                 if (currentModifiedSegment != currentOriginalSegment) {
    257                         cmds.add(new ChangeCommand(currentOriginalSegment, currentModifiedSegment));
    258                 }
    259                
    260                 if (wayCopy != null) {
    261                         cmds.add(new ChangeCommand(way, wayCopy));
    262                         Main.main.editLayer().add(new SequenceCommand(tr("Simplify Way (remove {0} nodes)", delCount), cmds));
    263                 }
    264                
    265                 return true;
    266                
    267         }
    268         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    269                 setEnabled(!newSelection.isEmpty());
    270         }
    271 
    272         private static void computeXte(NodeRecord r) {
    273                 if ((r.previous == null) || (r.next == null)) {
    274                         r.xte = 0;
    275                         return;
    276                 }
    277                 Node prevNode = r.previous.node;
    278                 Node nextNode = r.next.node;
    279                 r.xte = radtomiles(linedist(prevNode.coor.lat(), prevNode.coor.lon(),
    280                         r.node.coor.lat(), r.node.coor.lon(),
    281                         nextNode.coor.lat(), nextNode.coor.lon()));
    282         }
    283        
     92        public void simplifyWayRange(Way wnew, int from, int to, ArrayList<Node> ns, double thr) {
     93                Node fromN = wnew.nodes.get(from), toN = wnew.nodes.get(to);
     94
     95                int imax = -1;
     96                double xtemax = 0;
     97                for (int i = from+1; i < to; i++) {
     98                        Node n = wnew.nodes.get(i);
     99                        double xte = radtometers(linedist(
     100                                fromN.coor.lat(), fromN.coor.lon(),
     101                                n.coor.lat(), n.coor.lon(),
     102                                toN.coor.lat(), toN.coor.lon()));
     103                        if (xte > xtemax) {
     104                                xtemax = xte;
     105                                imax = i;
     106                        }
     107                }
     108
     109                if (imax != -1 && xtemax >= thr) {
     110                        simplifyWayRange(wnew, from, imax, ns, thr);
     111                        ns.add(wnew.nodes.get(imax));
     112                        simplifyWayRange(wnew, imax, to, ns, thr);
     113                }
     114        }
     115
    284116        /* ----------------------------------------------------------------------
    285117         * Everything below this comment was converted from C to Java by Frederik
  • applications/editors/josm/plugins/utilsplugin/src/UtilsPlugin/UtilsPlugin.java

    r5075 r5076  
    33import static org.openstreetmap.josm.tools.I18n.tr;
    44
    5 import UtilsPlugin.*;
    6 //import UtilsPlugin.JosmLint.JosmLint;
    75import org.openstreetmap.josm.gui.IconToggleButton;
    86
     
    2220
    2321public class UtilsPlugin extends Plugin {
    24 
    25     private JMenu toolsMenu;
    26     private JMenuItem mergePointsMenu = new JMenuItem(new MergePointsAction());
    27     private JMenuItem mergePointLineMenu = new JMenuItem(new MergePointLineAction());
    28     private JMenuItem mergeWaysMenu = new JMenuItem(new MergeWaysAction());
    29     private JMenuItem deduplicateWayMenu =  new JMenuItem(new DeduplicateWayAction());
    30     private JMenuItem simplifyWayMenu =  new JMenuItem(new SimplifyWayAction());
    31        
    32     public UtilsPlugin() {
    33         JMenuBar menu = Main.main.menu;
    34         toolsMenu = menu.getMenu(4);
    35 /*
    36         This code doesn't work, because getName returns null always, so we get two menus
    37        
    38         for (int i = 0; i < menu.getMenuCount(); ++i) {
    39             javax.swing.JOptionPane.showMessageDialog(Main.parent, tr("Menu ["+menu.getMenu(i).getName()+","+tr("Edit")+"]"));
    40             if (menu.getMenu(i) != null && tr("Edit").equals(menu.getMenu(i).getName())) {
    41                 editMenu = menu.getMenu(i);
    42                 break;
    43             }
    44         }
    45 */
    46         if (toolsMenu == null) {
    47             toolsMenu = new JMenu(tr("Tools"));
    48             menu.add(toolsMenu, 5);
    49             toolsMenu.setVisible(false);
    50         }
    51         toolsMenu.add(mergePointsMenu);
    52         toolsMenu.add(mergePointLineMenu);
    53         toolsMenu.add(mergeWaysMenu);
    54         toolsMenu.add(deduplicateWayMenu);
    55         toolsMenu.add(simplifyWayMenu);
    56         mergePointsMenu.setVisible(false);
    57         mergePointLineMenu.setVisible(false);
    58         mergeWaysMenu.setVisible(false);
    59         deduplicateWayMenu.setVisible(false);
    60         simplifyWayMenu.setVisible(false);
    61     }
    6222        @Override
    6323        public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
    64                 if (oldFrame != null && newFrame == null) {
    65                         // disable
    66                         mergePointsMenu.setVisible(false);
    67                         mergePointLineMenu.setVisible(false);
    68                         mergeWaysMenu.setVisible(false);
    69                         deduplicateWayMenu.setVisible(false);
    70                         simplifyWayMenu.setVisible(false);
    71 //                      JosmLint.stopPlugin();
    72                         if (toolsMenu.getMenuComponentCount() == 4)
    73                                 toolsMenu.setVisible(false);
    74                 } else if (oldFrame == null && newFrame != null) {
    75                         // enable
    76                         mergePointsMenu.setVisible(true);
    77                         mergePointLineMenu.setVisible(true);
    78                         mergeWaysMenu.setVisible(true);
    79                         deduplicateWayMenu.setVisible(true);
    80                         simplifyWayMenu.setVisible(true);
    81 
    82 //                      JosmLint.setupPlugin();
    83                        
    84                         if (toolsMenu.getMenuComponentCount() == 4)
    85                                 toolsMenu.setVisible(true);
     24                if (oldFrame == null && newFrame != null) {
     25                        Main.map.toolBarActions.addSeparator();
     26                        Main.map.toolBarActions.add(new MergeNodesAction());
     27                        Main.map.toolBarActions.add(new MergeNodeWayAction());
     28                        Main.map.toolBarActions.add(new SimplifyWayAction());
    8629                }
    8730        }
    88 
    8931}
Note: See TracChangeset for help on using the changeset viewer.