Changeset 25873 in osm for applications/editors


Ignore:
Timestamp:
2011-04-20T09:57:52+02:00 (13 years ago)
Author:
zverik
Message:

align nodes in a way

Location:
applications/editors/josm/plugins/dumbutils
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/dumbutils/README

    r25855 r25873  
    44* Copy tags from previous selected object
    55* Replace geometry for existing way
     6* Remember and paste source tag
     7* Align nodes in a way
     8* Paste relations from objects in the paste buffer
    69
    710As for icons, sorry: this is quick&dirty plugin, and I'm no artist.
  • applications/editors/josm/plugins/dumbutils/src/dumbutils/AlignWayNodesAction.java

    r25870 r25873  
    11package dumbutils;
    22
    3 import org.openstreetmap.josm.data.osm.Way;
    4 import org.openstreetmap.josm.data.osm.Node;
    5 import org.openstreetmap.josm.data.osm.RelationMember;
    6 import org.openstreetmap.josm.data.osm.RelationData;
    7 import org.openstreetmap.josm.data.osm.PrimitiveData;
    8 import org.openstreetmap.josm.data.osm.Relation;
     3import org.openstreetmap.josm.data.osm.*;
    94import org.openstreetmap.josm.Main;
    105import org.openstreetmap.josm.command.*;
    116import java.util.*;
    12 import java.awt.event.KeyEvent;
    13 import org.openstreetmap.josm.tools.Shortcut;
    147import java.awt.event.ActionEvent;
     8import javax.swing.JOptionPane;
    159import org.openstreetmap.josm.actions.JosmAction;
    16 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    17 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    1810import static org.openstreetmap.josm.tools.I18n.tr;
    1911
     
    2517class AlignWayNodesAction extends JosmAction {
    2618    private static final String TITLE = "Align way nodes";
     19    private static final double MOVE_THRESHOLD = 1e-9;
    2720
    2821    public AlignWayNodesAction() {
     
    3326        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
    3427        Set<Node> selectedNodes = filterNodes(selection);
     28        int selectedNodesCount = selectedNodes.size();
    3529        Set<Way> ways = findCommonWays(selectedNodes);
    36         if( ways == null || ways.size() != 1 )
     30        if( ways == null || ways.size() != 1 || selectedNodesCount == 0 )
    3731            return;
    3832        Way way = ways.iterator().next();
     33        if( way.getNodesCount() < (way.isClosed() ? 4 : 3) ) {
     34            JOptionPane.showMessageDialog(Main.parent, tr("The way with selected nodes can not be straightened."), tr(TITLE), JOptionPane.ERROR_MESSAGE);
     35            return;
     36        }
    3937
    4038        // Prepare a list of nodes to align
     39        int firstNodePos = findFirstNode(way, selectedNodes);
     40        int lastNodePos = way.isClosed() ? firstNodePos : way.getNodesCount();
    4141        List<Node> nodes = new ArrayList<Node>();
    42         for( int i = 0; i < way.getNodesCount(); i++ ) {
     42        int i = firstNodePos;
     43        boolean iterated = false;
     44        while( !iterated || i != lastNodePos ) {
    4345            Node node = way.getNode(i);
    4446            if( selectedNodes.contains(node) ) {
    4547                nodes.add(node);
    4648                selectedNodes.remove(node);
    47             }
    48             // todo: 1 node - add adjacent; 2 nodes - add all between them
     49                if( selectedNodesCount == 1 ) {
     50                    nodes.add(0, way.getNode( i > 0 ? i - 1 : way.isClosed() ? way.getNodesCount() - 2 : i + 2 ));
     51                    nodes.add(way.getNode( i + 1 < way.getNodesCount() ? i + 1 : way.isClosed() ? 1 : i - 2 ));
     52                }
     53                if( selectedNodes.isEmpty() )
     54                    break;
     55            } else if( selectedNodesCount == 2 && selectedNodes.size() == 1 )
     56                nodes.add(node);
     57            i++;
     58            if( i >= way.getNodesCount() && way.isClosed() )
     59                i = 0;
     60            iterated = true;
    4961        }
    5062
     63        if( nodes.size() < 3 ) {
     64            JOptionPane.showMessageDialog(Main.parent, "Internal error: number of nodes is " + nodes.size(),
     65                    tr(TITLE), JOptionPane.ERROR_MESSAGE);
     66            return;
     67        }
     68
     69        // Now, we have an ordered list of nodes, of which idx 0 and N-1 serve as guides
     70        // and 1..N-2 should be aligned with them
    5171        List<Command> commands = new ArrayList<Command>();
     72        double ax = nodes.get(0).getEastNorth().east();
     73        double ay = nodes.get(0).getEastNorth().north();
     74        double bx = nodes.get(nodes.size() - 1).getEastNorth().east();
     75        double by = nodes.get(nodes.size() - 1).getEastNorth().north();
     76       
     77        for( i = 1; i + 1 < nodes.size(); i++ ) {
     78            Node n = nodes.get(i);
     79           
     80            // Algorithm is copied from org.openstreetmap.josm.actions.AlignInLineAction
     81            double nx = n.getEastNorth().east();
     82            double ny = n.getEastNorth().north();
     83
     84            if( ax == bx ) {
     85                // Special case if AB is vertical...
     86                nx = ax;
     87            } else if( ay == by ) {
     88                // ...or horizontal
     89                ny = ay;
     90            } else {
     91                // Otherwise calculate position by solving y=mx+c (simplified)
     92                double m1 = (by - ay) / (bx - ax);
     93                double c1 = ay - (ax * m1);
     94                double m2 = (-1) / m1;
     95                double c2 = ny - (nx * m2);
     96
     97                nx = (c2 - c1) / (m1 - m2);
     98                ny = (m1 * nx) + c1;
     99            }
     100
     101            // Add the command to move the node to its new position.
     102            if( Math.abs(nx - n.getEastNorth().east()) > MOVE_THRESHOLD && Math.abs(ny - n.getEastNorth().north()) > MOVE_THRESHOLD )
     103                commands.add(new MoveCommand(n, nx - n.getEastNorth().east(), ny - n.getEastNorth().north()));
     104        }
     105
    52106        if( !commands.isEmpty() )
    53107            Main.main.undoRedo.add(new SequenceCommand(tr(TITLE), commands));
     
    64118    @Override
    65119    protected void updateEnabledState( Collection<? extends OsmPrimitive> selection ) {
    66         Set<Way> ways = findCommonWays(filterNodes(selection));
    67         setEnabled(ways != null && ways.size() == 1);
     120        Set<Node> nodes = filterNodes(selection);
     121        Set<Way> ways = findCommonWays(nodes);
     122        setEnabled(ways != null && ways.size() == 1 && !nodes.isEmpty());
    68123    }
    69124
     
    92147        return result;
    93148    }
     149
     150    /**
     151     * Find the largest empty span between nodes and returns the index of the node right after it.
     152     */
     153    private int findFirstNode( Way way, Set<Node> nodes ) {
     154        int pos = 0;
     155        while( pos < way.getNodesCount() && !nodes.contains(way.getNode(pos)) )
     156            pos++;
     157        if( pos >= way.getNodesCount() )
     158            return 0;
     159        if( !way.isClosed() || nodes.size() <= 1 )
     160            return pos;
     161
     162        // now, way is closed
     163        boolean fullCircle = false;
     164        int maxLength = 0;
     165        int lastPos = 0;
     166        while( !fullCircle ) {
     167            int length = 0;
     168            boolean skippedFirst = false;
     169            while( !(skippedFirst && nodes.contains(way.getNode(pos))) ) {
     170                skippedFirst = true;
     171                length++;
     172                pos++;
     173                if( pos >= way.getNodesCount() ) {
     174                    pos = 0;
     175                    fullCircle = true;
     176                }
     177            }
     178            if( length > maxLength ) {
     179                maxLength = length;
     180                lastPos = pos;
     181            }
     182        }
     183        return lastPos;
     184    }
    94185}
  • applications/editors/josm/plugins/dumbutils/src/dumbutils/DumbUtilsPlugin.java

    r25870 r25873  
    2323        sourceTag = MainMenu.add(Main.main.menu.toolsMenu, new TagSourceAction());
    2424        pasteRelations = MainMenu.add(Main.main.menu.toolsMenu, new PasteRelationsAction());
    25 //        alignWayNodes = MainMenu.add(Main.main.menu.toolsMenu, new AlignWayNodesAction());
     25        alignWayNodes = MainMenu.add(Main.main.menu.toolsMenu, new AlignWayNodesAction());
    2626    }
    2727
     
    3333        sourceTag.setEnabled(enabled);
    3434        pasteRelations.setEnabled(enabled);
    35 //        alignWayNodes.setEnabled(enabled);
     35        alignWayNodes.setEnabled(enabled);
    3636    }
    3737}
Note: See TracChangeset for help on using the changeset viewer.