Changeset 1090 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2008-11-25T00:08:42+01:00 (16 years ago)
Author:
framm
Message:
Location:
trunk/src/org/openstreetmap/josm/actions
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/AlignInCircleAction.java

    r1084 r1090  
    1 // License: GPL. Copyright 2007 by Immanuel Scholz and others
     1//License: GPL. Copyright 2007 by Immanuel Scholz and others
    22package org.openstreetmap.josm.actions;
    33
     
    2424/**
    2525 * Aligns all selected nodes within a circle. (Useful for roundabouts)
    26  *
     26 * 
    2727 * @author Matthew Newton
     28 * @author Petr Dlouhý
    2829 */
    2930public final class AlignInCircleAction extends JosmAction {
    3031
    31         public AlignInCircleAction() {
    32                 super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."),
    33                 Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")), KeyEvent.VK_O, Shortcut.GROUP_EDIT), true);
    34         }
    35 
    36         public void actionPerformed(ActionEvent e) {
    37                 Collection<OsmPrimitive> sel = Main.ds.getSelected();
    38                 Collection<Node> nodes = new LinkedList<Node>();
    39 
    40                 for (OsmPrimitive osm : sel)
    41                         if (osm instanceof Node)
    42                                 nodes.add((Node)osm);
    43 
    44                 // special case if no single nodes are selected and exactly one way is:
    45                 // then use the way's nodes
    46                 if ((nodes.size() == 0) && (sel.size() == 1))
    47                         for (OsmPrimitive osm : sel)
    48                                 if (osm instanceof Way)
    49                                         for (Node n : ((Way)osm).nodes)
    50                                         {
    51                                                 if(!nodes.contains(n))
    52                                                         nodes.add(n);
    53                                         }
    54 
    55                 if (nodes.size() < 4) {
    56                         JOptionPane.showMessageDialog(Main.parent, tr("Please select at least four nodes."));
    57                         return;
    58                 }
    59 
    60                 // Get average position of all nodes
    61                 Node avn = new Node(new LatLon(0,0));
    62                 avn.eastNorth = new EastNorth(0,0);
    63                 for (Node n : nodes) {
    64                         avn.eastNorth = new EastNorth(avn.eastNorth.east()+n.eastNorth.east(), avn.eastNorth.north()+n.eastNorth.north());
    65                 }
    66                 avn.eastNorth = new EastNorth(avn.eastNorth.east()/nodes.size(), avn.eastNorth.north()/nodes.size());
    67                 avn.coor = Main.proj.eastNorth2latlon(avn.eastNorth);
    68                 // Node "avn" now is central to all selected nodes.
    69 
    70                 // Now calculate the average distance to each node from the
    71                 // centre.  This method is ok as long as distances are short
    72                 // relative to the distance from the N or S poles.
    73                 double distances[] = new double[nodes.size()];
    74                 double avdist = 0, latd, lond;
    75                 double lonscale = Math.cos(avn.coor.lat() * Math.PI/180.0);
    76                 lonscale = lonscale * lonscale;
    77                 int i = 0;
    78                 for (Node n : nodes) {
    79                         latd = n.coor.lat() - avn.coor.lat();
    80                         lond = n.coor.lon() - avn.coor.lon();
    81                         distances[i] = Math.sqrt(latd * latd + lonscale * lond * lond);
    82                         avdist += distances[i++];
    83                 }
    84                 avdist = avdist / nodes.size();
    85 
    86                 Collection<Command> cmds = new LinkedList<Command>();
    87                 // Move each node to that distance from the centre.
    88                 i = 0;
    89                 for (Node n : nodes) {
    90                         double dx = n.eastNorth.east() - avn.eastNorth.east();
    91                         double dy = n.eastNorth.north() - avn.eastNorth.north();
    92                         double dist = distances[i++];
    93                         cmds.add(new MoveCommand(n, (dx * (avdist / dist)) - dx, (dy * (avdist / dist)) - dy));
    94                 }
    95 
    96                 Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
    97                 Main.map.repaint();
    98         }
     32    public AlignInCircleAction() {
     33        super(tr("Align Nodes in Circle"), "aligncircle", tr("Move the selected nodes into a circle."),
     34                Shortcut.registerShortcut("tools:aligncircle", tr("Tool: {0}", tr("Align Nodes in Circle")),
     35                        KeyEvent.VK_O, Shortcut.GROUP_EDIT), true);
     36    }
     37
     38    public double determinant(double[][] mat) {
     39        double result = 0;
     40
     41        if (mat.length == 1) {
     42            result = mat[0][0];
     43            return result;
     44        }
     45
     46        if (mat.length == 2) {
     47            result = mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0];
     48            return result;
     49        }
     50
     51        for (int i = 0; i < mat[0].length; i++) {
     52            double temp[][] = new double[mat.length - 1][mat[0].length - 1];
     53            for (int j = 1; j < mat.length; j++) {
     54                for (int k = 0; k < mat[0].length; k++) {
     55                    if (k < i) {
     56                        temp[j - 1][k] = mat[j][k];
     57                    } else if (k > i) {
     58                        temp[j - 1][k - 1] = mat[j][k];
     59                    }
     60                }
     61            }
     62            result += mat[0][i] * Math.pow(-1, (double) i) * determinant(temp);
     63        }
     64        return result;
     65    }
     66
     67    public double distance(EastNorth n, EastNorth m) {
     68        double easd, nord;
     69        easd = n.east() - m.east();
     70        nord = n.north() - m.north();
     71        return Math.sqrt(easd * easd + nord * nord);
     72    }
     73
     74    public EastNorth circumcenter(EastNorth i, EastNorth j, EastNorth k) {
     75        // move to 0,0, to eliminate numeric errors
     76        double ie = i.east() - i.east();
     77        double in = i.north() - i.north();
     78        double je = j.east() - i.east();
     79        double jn = j.north() - i.north();
     80        double ke = k.east() - i.east();
     81        double kn = k.north() - i.north();
     82        double[][] ma = { { ie, in, 1 }, { je, jn, 1 }, { ke, kn, 1 } };
     83        double[][] mbx = { { (ie * ie + in * in), in, 1 }, { (je * je + jn * jn), jn, 1 },
     84                { (ke * ke + kn * kn), kn, 1 } };
     85        double[][] mby = { { ie * ie + in * in, ie, 1 }, { je * je + jn * jn, je, 1 }, { ke * ke + kn * kn, ke, 1 } };
     86        double a = determinant(ma);
     87        double bx = determinant(mbx);
     88        double by = determinant(mby);
     89        EastNorth result = new EastNorth(bx / (2 * a) + i.east(), -by / (2 * a) + i.north());
     90
     91        Node n = new Node(Main.proj.eastNorth2latlon(result));
     92        if (n.coor.isOutSideWorld()) {
     93            JOptionPane.showMessageDialog(Main.parent, tr("Some of the nodes are (almost) in the line"));
     94            return null;
     95        }
     96        return result;
     97    }
     98
     99    public class PolarCoor {
     100        double radius;
     101        double angle;
     102        EastNorth origin = new EastNorth(0, 0);
     103        double azimuth = 0;
     104
     105        PolarCoor(double radius, double angle) {
     106            this(radius, angle, new EastNorth(0, 0), 0);
     107        }
     108
     109        PolarCoor(double radius, double angle, EastNorth origin, double azimuth) {
     110            this.radius = radius;
     111            this.angle = angle;
     112            this.origin = origin;
     113            this.azimuth = azimuth;
     114        }
     115
     116        PolarCoor(EastNorth en) {
     117            this(en, new EastNorth(0, 0), 0);
     118        }
     119
     120        PolarCoor(EastNorth en, EastNorth origin, double azimuth) {
     121            radius = distance(en, origin);
     122            angle = Math.atan2(en.north() - origin.north(), en.east() - origin.east());
     123            this.origin = origin;
     124            this.azimuth = azimuth;
     125        }
     126
     127        public EastNorth toEastNorth() {
     128            return new EastNorth(radius * Math.cos(angle - azimuth) + origin.east(), radius * Math.sin(angle - azimuth)
     129                    + origin.north());
     130        }
     131    }
     132
     133    public void actionPerformed(ActionEvent e) {
     134        Collection<OsmPrimitive> sel = Main.ds.getSelected();
     135        Collection<Node> nodes = new LinkedList<Node>();
     136        Collection<Way> ways = new LinkedList<Way>();
     137        Node center = null;
     138        Node node = null;
     139        double radius = 0;
     140        boolean regular = false;
     141
     142        for (OsmPrimitive osm : sel) {
     143            if (osm instanceof Node)
     144                nodes.add((Node) osm);
     145            else if (osm instanceof Way)
     146                ways.add((Way) osm);
     147        }
     148
     149        // special case if no single nodes are selected and exactly one way is:
     150        // then use the way's nodes
     151        if ((nodes.size() <= 2) && (ways.size() == 1)) {
     152            Way way = (Way) ways.toArray()[0];
     153
     154            // some more special combinations:
     155            // When is selected node that is part of the way, then make a regular polygon, selected
     156            // node doesn't move.
     157            // I haven't got better idea, how to activate that function.
     158            //
     159            // When one way and one node is selected, set center to position of that node.
     160            // When one more node, part of the way, is selected, set the radius equal to the
     161            // distance between two nodes.
     162            if (nodes.size() > 0) {
     163                if (nodes.size() == 1 && way.nodes.contains((Node) nodes.toArray()[0])) {
     164                    node = (Node) nodes.toArray()[0];
     165                    regular = true;
     166                } else {
     167
     168                    center = (Node) nodes.toArray()[way.nodes.contains((Node) nodes.toArray()[0]) ? 1 : 0];
     169                    if (nodes.size() == 2)
     170                        radius = distance(((Node) nodes.toArray()[0]).eastNorth, ((Node) nodes.toArray()[1]).eastNorth);
     171                }
     172                nodes = new LinkedList<Node>();
     173            }
     174
     175            for (Node n : way.nodes) {
     176                if (!nodes.contains(n))
     177                    nodes.add(n);
     178            }
     179        }
     180
     181        if (nodes.size() < 4) {
     182            JOptionPane.showMessageDialog(Main.parent, tr("Please select at least four nodes."));
     183            return;
     184        }
     185
     186        // Get average position of circumcircles of the triangles of all triplets of neighbour nodes
     187        if (center == null) {
     188            center = new Node(new LatLon(0, 0));
     189            Node n0, n1, n2, prvni, druhy;
     190            n0 = (Node) nodes.toArray()[nodes.size() - 1];
     191            n1 = (Node) nodes.toArray()[nodes.size() - 2];
     192            for (Node n : nodes) {
     193                n2 = n1;
     194                n1 = n0;
     195                n0 = n;
     196                EastNorth cc = circumcenter(n0.eastNorth, n1.eastNorth, n2.eastNorth);
     197                if (cc == null)
     198                    return;
     199                center.eastNorth = new EastNorth(center.eastNorth.east() + cc.east(), center.eastNorth.north()
     200                        + cc.north());
     201            }
     202
     203            center.eastNorth = new EastNorth(center.eastNorth.east() / nodes.size(), center.eastNorth.north()
     204                    / nodes.size());
     205            center.coor = Main.proj.eastNorth2latlon(center.eastNorth);
     206        }
     207
     208        // Node "center" now is central to all selected nodes.
     209
     210        // Now calculate the average distance to each node from the
     211        // centre. This method is ok as long as distances are short
     212        // relative to the distance from the N or S poles.
     213        if (radius == 0) {
     214            for (Node n : nodes) {
     215                radius += distance(center.eastNorth, n.eastNorth);
     216            }
     217            radius = radius / nodes.size();
     218        }
     219
     220        Collection<Command> cmds = new LinkedList<Command>();
     221
     222        PolarCoor pc;
     223
     224        if (regular) { // Make a regular polygon
     225            double angle = Math.PI * 2 / nodes.size();
     226            pc = new PolarCoor(((Node) nodes.toArray()[0]).eastNorth, center.eastNorth, 0);
     227
     228            if (pc.angle > (new PolarCoor(((Node) nodes.toArray()[1]).eastNorth, center.eastNorth, 0).angle))
     229                angle *= -1;
     230
     231            pc.radius = radius;
     232            for (Node n : nodes) {
     233                EastNorth no = pc.toEastNorth();
     234                cmds.add(new MoveCommand(n, no.east() - n.eastNorth.east(), no.north() - n.eastNorth.north()));
     235                pc.angle += angle;
     236            }
     237        } else { // Move each node to that distance from the centre.
     238            for (Node n : nodes) {
     239                pc = new PolarCoor(n.eastNorth, center.eastNorth, 0);
     240                pc.radius = radius;
     241                EastNorth no = pc.toEastNorth();
     242                cmds.add(new MoveCommand(n, no.east() - n.eastNorth.east(), no.north() - n.eastNorth.north()));
     243            }
     244        }
     245
     246        Main.main.undoRedo.add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
     247        Main.map.repaint();
     248    }
    99249}
  • trunk/src/org/openstreetmap/josm/actions/OrthogonalizeAction.java

    r1089 r1090  
    116116        boolean use_dirnodes = false;
    117117
    118         if(dirnodes.size() == 2) {
     118        if (dirnodes.size() == 2) {
    119119            // When selection contains two nodes, use the nodes to compute a direction
    120120            // to align all ways to
Note: See TracChangeset for help on using the changeset viewer.