diff --git a/images/mapmode/parallel.png b/images/mapmode/parallel.png
new file mode 100644
index 0000000..a02c6fc
Binary files /dev/null and b/images/mapmode/parallel.png differ
diff --git a/src/org/openstreetmap/josm/actions/MakeParallelWay.java b/src/org/openstreetmap/josm/actions/MakeParallelWay.java
new file mode 100644
index 0000000..739779f
--- /dev/null
+++ b/src/org/openstreetmap/josm/actions/MakeParallelWay.java
@@ -0,0 +1,280 @@
+// License: GPL. Copyright 2007 by Immanuel Scholz and others
+// Author: David Earl
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Cursor;
+import java.awt.Point;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.mapmode.MapMode;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.tools.Geometry;
+import org.openstreetmap.josm.tools.Shortcut;
+
+public final class MakeParallelWay extends MapMode {
+
+    public MakeParallelWay(MapFrame mapFrame) {
+        super(tr("Parallel"), "parallel",
+                tr("Makes a paralell copy of the selected way(s)"),
+                Shortcut.registerShortcut("mapmode:parallel", tr("Mode: {0}", tr("Parallel")),
+                        KeyEvent.VK_P, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT),
+                        mapFrame, Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+        putValue("help", ht("/Action/Parallel"));
+    }
+
+    @Override public String getModeHelpText() {
+        return "Drag a way to make a parallel copy";
+    }
+    @Override public void enterMode() {
+        super.enterMode();
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+    }
+
+    @Override public void exitMode() {
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        Main.map.statusLine.setDist(-1);
+        Main.map.statusLine.repaint();
+        super.exitMode();
+    }
+    @Override public void mousePressed(MouseEvent e) {
+        if(!Main.map.mapView.isActiveLayerVisible())
+            return;
+        if (!(Boolean)this.getValue("active"))
+            return;
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+        Point p = e.getPoint();
+        referenceSegment = Main.map.mapView.getNearestWaySegment(p, Way.isUsablePredicate, true);
+        if(referenceSegment == null)
+            return;
+        Collection<Way> selectedWays = Main.main.getCurrentDataSet().getSelectedWays();
+        if(Main.main.getCurrentDataSet().selectionEmpty()) {
+
+        }
+
+        pways = new ParallelWays(referenceSegment.way);
+        getCurrentDataSet().setSelected(pways.refWay);
+    }
+    @Override public void mouseReleased(MouseEvent e) {
+        // if only a click we should dispose of the created way
+        if (pways != null) {
+            //            pways.commit(Main.main.getCurrentDataSet());
+        }
+        pways = null;
+    }
+    @Override public void mouseDragged(MouseEvent e) {
+        if(pways == null)
+            return;
+        Point p = e.getPoint();
+        EastNorth enp = Main.map.mapView.getEastNorth((int)p.getX(), (int)p.getY());
+        EastNorth enOnRefLine = Geometry.closestPointToLine(referenceSegment.getFirstNode().getEastNorth(),
+                referenceSegment.getSecondNode().getEastNorth(), enp);
+        double d = enp.distance(enOnRefLine);
+        boolean toTheRight = Geometry.isToTheRightSideOfLine(
+                referenceSegment.getFirstNode(), referenceSegment.getFirstNode(), referenceSegment.getSecondNode(), new Node(enp));
+        if (toTheRight) {
+            d = -d;
+        }
+        pways.changeOffset(d);
+        Main.map.statusLine.setDist(Math.abs(d));
+        Main.map.statusLine.repaint();
+        Main.map.mapView.repaint();
+    }
+    private WaySegment referenceSegment;
+    private ParallelWays pways;
+
+    static class ParallelWays {
+        //        public ArrayList<Way> ways;
+        public Way refWay;
+        public Way pWay;
+
+        int nodeCount;
+        EastNorth[] pts;
+        EastNorth[] dts;
+
+        public ParallelWays(Way way) {
+            this.refWay = way;
+            nodeCount = this.refWay.getNodesCount();
+            pts = new EastNorth[nodeCount];
+            dts = new EastNorth[nodeCount-1];
+
+            int i = 0;
+            for(Node n : way.getNodes()) {
+                EastNorth t = n.getEastNorth();
+                pts[i] = t;
+                i++;
+            }
+            for(i = 0; i < nodeCount-1; i++) {
+                double dx = pts[i+1].getX() - pts[i].getX();
+                double dy = pts[i+1].getY() - pts[i].getY();
+                double len = Math.sqrt(dx*dx + dy*dy);
+                dts[i] = new EastNorth(-dy / len, dx / len);
+            }
+
+            pWay = new Way();
+            for(i = 0; i < nodeCount-1; i++) {
+                Node n = new Node(pts[i]);
+                pWay.addNode(n);
+            }
+            if (way.isClosed()) {
+                pWay.addNode(pWay.getNode(0));
+            } else {
+                Node n = new Node(pts[nodeCount-1]);
+                pWay.addNode(n);
+            }
+            commit(getCurrentDataSet());
+        }
+
+        public void changeOffset(double d) {
+            EastNorth[] ppts = new EastNorth[nodeCount];
+
+            EastNorth prevA = add(pts[0], mul(dts[0], d));
+            EastNorth prevB = add(pts[1], mul(dts[0], d));
+            for(int i = 1; i < nodeCount-1; i++) {
+                EastNorth A = add(pts[i], mul(dts[i], d));
+                EastNorth B = add(pts[i+1], mul(dts[i], d));
+                if (Geometry.segmentsParallel(A, B, prevA, prevB)) {
+                    ppts[i] = A;
+                } else {
+                    ppts[i] = Geometry.getLineLineIntersection(A, B, prevA, prevB);
+                }
+                prevA = A;
+                prevB = B;
+            }
+            if(refWay.isClosed()) {
+                EastNorth A = add(pts[0], mul(dts[0], d));
+                EastNorth B = add(pts[1], mul(dts[0], d));
+                if (Geometry.segmentsParallel(A, B, prevA, prevB)) {
+                    ppts[0] = A;
+                } else {
+                    ppts[0] = Geometry.getLineLineIntersection(A, B, prevA, prevB);
+                }
+                ppts[nodeCount-1] = ppts[0];
+            } else {
+                ppts[0] = add(pts[0], mul(dts[0], d));
+                ppts[nodeCount-1] = add(pts[nodeCount-1], mul(dts[nodeCount-2], d));
+            }
+
+            for(int i = 0; i < nodeCount; i++) {
+                pWay.getNode(i).setEastNorth(ppts[i]);
+            }
+        }
+        public static List<Command> makeAddWayAndNodesCommandList(Way w) {
+            ArrayList<Command> commands = new ArrayList<Command>(w.getNodesCount()+1);
+            for(int i = 0; i < w.getNodesCount()-1; i++) {
+                commands.add(new AddCommand(w.getNode(i)));
+            }
+            if(!w.isClosed()){
+                commands.add(new AddCommand(w.getNode(w.getNodesCount()-1)));
+            }
+            commands.add(new AddCommand(w));
+            return commands;
+        }
+        public void commit(DataSet ds) {
+            SequenceCommand undoCommand = new SequenceCommand("Make parallel way", makeAddWayAndNodesCommandList(pWay));
+            Main.main.undoRedo.add(undoCommand);
+        }
+    }
+
+    //    @Override
+    //    public void actionPerformed(ActionEvent e) {
+    //        return;
+    //        //        double d = Double.parseDouble(JOptionPane.showInputDialog("Input offset"));
+    //        //        Collection<OsmPrimitive> selection = getCurrentDataSet().getSelected();
+    //        //        Collection<Way> selectedWays = new ArrayList<Way>();
+    //        //        for(OsmPrimitive prim : selection) {
+    //        //            if (prim instanceof Way) {
+    //        //                selectedWays.add((Way)prim);
+    //        //            }
+    //        //        }
+    //        //        for(Way w : makeParallelWays(selectedWays, d)) {
+    //        //            Main.main.getCurrentDataSet().addPrimitive(w);
+    //        //        }
+    //    }
+
+    //    private Collection<Way> makeParallelWays(Collection<Way> Ways, double d) {
+    //        Collection<Way> parallelWays = new ArrayList<Way>();
+    //        for (Way way : Ways) {
+    //            parallelWays.add(makeParallelWay(way, d));
+    //        }
+    //        return parallelWays;
+    //    }
+
+    //    private Way makeParallelWay(Way way, double d) {
+    //        int nodeCount = way.getNodesCount();
+    //        EastNorth[] pts = new EastNorth[nodeCount];
+    //        EastNorth[] dts = new EastNorth[nodeCount-1];
+    //
+    //        int i = 0;
+    //        for(Node n : way.getNodes()) {
+    //            EastNorth t = n.getEastNorth();
+    //            pts[i] = t;
+    //            i++;
+    //        }
+    //        for(i = 0; i < nodeCount-1; i++) {
+    //            double dx = pts[i+1].getX() - pts[i].getX();
+    //            double dy = pts[i+1].getY() - pts[i].getY();
+    //            double len = Math.sqrt(dx*dx + dy*dy);
+    //            dts[i] = new EastNorth(-dy / len, dx / len);
+    //        }
+    //        EastNorth[] ppts = new EastNorth[nodeCount];
+    //        EastNorth prevA = add(pts[0], mul(dts[0], d));
+    //        EastNorth prevB = add(pts[1], mul(dts[0], d));
+    //        for(i = 1; i < nodeCount-1; i++) {
+    //            EastNorth A = add(pts[i], mul(dts[i], d));
+    //            EastNorth B = add(pts[i+1], mul(dts[i], d));
+    //            if (Geometry.segmentsParallel(A, B, prevA, prevB)) {
+    //                ppts[i] = A;
+    //            } else {
+    //                ppts[i] = Geometry.getLineLineIntersection(A, B, prevA, prevB);
+    //            }
+    //            prevA = A;
+    //            prevB = B;
+    //        }
+    //        if(way.isClosed()) {
+    //            EastNorth A = add(pts[0], mul(dts[0], d));
+    //            EastNorth B = add(pts[1], mul(dts[0], d));
+    //            if (Geometry.segmentsParallel(A, B, prevA, prevB)) {
+    //                ppts[0] = A;
+    //            } else {
+    //                ppts[0] = Geometry.getLineLineIntersection(A, B, prevA, prevB);
+    //            }
+    //            ppts[nodeCount-1] = ppts[0];
+    //        } else {
+    //            ppts[0] = add(pts[0], mul(dts[0], d));
+    //            ppts[nodeCount-1] = add(pts[nodeCount-1], mul(dts[nodeCount-2], d));
+    //        }
+    //        Way pway = new Way();
+    //        for(i = 0; i < nodeCount; i++) {
+    //            Node n = new Node(ppts[i]);
+    //            Main.main.getCurrentDataSet().addPrimitive(n);
+    //            pway.addNode(n);
+    //        }
+    //        return pway;
+    //    }
+
+    static protected EastNorth mul(EastNorth en, double f) {
+        return new EastNorth(en.getX()*f, en.getY()*f);
+    }
+    static protected EastNorth add(EastNorth a, EastNorth b) {
+        return new EastNorth(a.east()+b.east(), a.north()+b.north());
+    }
+}
diff --git a/src/org/openstreetmap/josm/gui/MapFrame.java b/src/org/openstreetmap/josm/gui/MapFrame.java
index 96bddae..aca8e99 100644
--- a/src/org/openstreetmap/josm/gui/MapFrame.java
+++ b/src/org/openstreetmap/josm/gui/MapFrame.java
@@ -36,6 +36,7 @@ import javax.swing.plaf.basic.BasicSplitPaneDivider;
 import javax.swing.plaf.basic.BasicSplitPaneUI;
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.MakeParallelWay;
 import org.openstreetmap.josm.actions.mapmode.DeleteAction;
 import org.openstreetmap.josm.actions.mapmode.DrawAction;
 import org.openstreetmap.josm.actions.mapmode.ExtrudeAction;
@@ -129,6 +130,7 @@ public class MapFrame extends JPanel implements Destroyable, LayerChangeListener
         addMapMode(new IconToggleButton(new SelectAction(this)));
         addMapMode(new IconToggleButton(new DrawAction(this)));
         addMapMode(new IconToggleButton(new ExtrudeAction(this)));
+        addMapMode(new IconToggleButton(new MakeParallelWay(this)));
         addMapMode(new IconToggleButton(new ZoomAction(this)));
         addMapMode(new IconToggleButton(new DeleteAction(this)));
 
diff --git a/src/org/openstreetmap/josm/tools/Geometry.java b/src/org/openstreetmap/josm/tools/Geometry.java
index ade8359..9930fbb 100644
--- a/src/org/openstreetmap/josm/tools/Geometry.java
+++ b/src/org/openstreetmap/josm/tools/Geometry.java
@@ -332,6 +332,19 @@ public class Geometry {
         else
             return new EastNorth(segmentP1.getX() + ldx * offset, segmentP1.getY() + ldy * offset);
     }
+    public static EastNorth closestPointToLine(EastNorth lineP1, EastNorth lineP2, EastNorth point) {
+        double ldx = lineP2.getX() - lineP1.getX();
+        double ldy = lineP2.getY() - lineP1.getY();
+
+        if (ldx == 0 && ldy == 0) //segment zero length
+            return lineP1;
+
+        double pdx = point.getX() - lineP1.getX();
+        double pdy = point.getY() - lineP1.getY();
+
+        double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
+        return new EastNorth(lineP1.getX() + ldx * offset, lineP1.getY() + ldy * offset);
+    }
 
     /**
      * This method tests if secondNode is clockwise to first node.
@@ -457,7 +470,7 @@ public class Geometry {
 
         return inside;
     }
-    
+
     /**
      * returns area of a closed way in square meters
      * (approximate(?), but should be OK for small areas)
@@ -477,7 +490,7 @@ public class Geometry {
         }
         return Math.abs(area/2);
     }
-    
+
     protected static double calcX(Node p1){
         double lat1, lon1, lat2, lon2;
         double dlon, dlat;
@@ -494,7 +507,7 @@ public class Geometry {
         double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
         return 6367000 * c;
     }
-    
+
     protected static double calcY(Node p1){
         double lat1, lon1, lat2, lon2;
         double dlon, dlat;
