Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 11147)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 11148)
@@ -25,4 +25,5 @@
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -830,77 +831,52 @@
         final int imgHeight = pattern.getHeight();
 
-        double currentWayLength = phase % repeat;
-        if (currentWayLength < 0) {
-            currentWayLength += repeat;
-        }
-
-        int dy1, dy2;
-        switch (align) {
-            case TOP:
-                dy1 = 0;
-                dy2 = imgHeight;
-                break;
-            case CENTER:
-                dy1 = -imgHeight / 2;
-                dy2 = imgHeight + dy1;
-                break;
-            case BOTTOM:
-                dy1 = -imgHeight;
-                dy2 = 0;
-                break;
-            default:
-                throw new AssertionError();
-        }
-
-        MapViewPoint lastP = null;
+        int dy1 = (int) ((align.getAlignmentOffset() - .5) * imgHeight);
+        int dy2 = dy1 + imgHeight;
+
         OffsetIterator it = new OffsetIterator(way.getNodes(), offset);
+        MapViewPath path = new MapViewPath(mapState);
+        if (it.hasNext()) {
+            path.moveTo(it.next());
+        }
         while (it.hasNext()) {
-            MapViewPoint thisP = it.next();
-
-            if (lastP != null) {
-                final double segmentLength = thisP.distanceToInView(lastP);
-
-                final double dx = thisP.getInViewX() - lastP.getInViewX();
-                final double dy = thisP.getInViewY() - lastP.getInViewY();
-
-                // pos is the position from the beginning of the current segment
-                // where an image should be painted
-                double pos = repeat - (currentWayLength % repeat);
-
-                AffineTransform saveTransform = g.getTransform();
-                g.translate(lastP.getInViewX(), lastP.getInViewY());
-                g.rotate(Math.atan2(dy, dx));
-
-                // draw the rest of the image from the last segment in case it
-                // is cut off
-                if (pos > spacing) {
-                    // segment is too short for a complete image
-                    if (pos > segmentLength + spacing) {
-                        g.drawImage(pattern.getImage(disabled), 0, dy1, (int) segmentLength, dy2,
-                                (int) (repeat - pos), 0,
-                                (int) (repeat - pos + segmentLength), imgHeight, null);
-                    } else {
-                        // rest of the image fits fully on the current segment
-                        g.drawImage(pattern.getImage(disabled), 0, dy1, (int) (pos - spacing), dy2,
-                                (int) (repeat - pos), 0, imgWidth, imgHeight, null);
-                    }
-                }
-                // draw remaining images for this segment
-                while (pos < segmentLength) {
-                    // cut off at the end?
-                    if (pos + imgWidth > segmentLength) {
-                        g.drawImage(pattern.getImage(disabled), (int) pos, dy1, (int) segmentLength, dy2,
-                                0, 0, (int) segmentLength - (int) pos, imgHeight, null);
-                    } else {
-                        g.drawImage(pattern.getImage(disabled), (int) pos, dy1, nc);
-                    }
-                    pos += repeat;
-                }
-                g.setTransform(saveTransform);
-
-                currentWayLength += segmentLength;
-            }
-            lastP = thisP;
-        }
+            path.lineTo(it.next());
+        }
+
+        double startOffset = phase % repeat;
+        if (startOffset < 0) {
+            startOffset += repeat;
+        }
+
+        BufferedImage image = pattern.getImage(disabled);
+
+        path.visitClippedLine(startOffset, repeat, (inLineOffset, start, end, startIsOldEnd) -> {
+            final double segmentLength = start.distanceToInView(end);
+            if (segmentLength < 0.1) {
+                // avoid odd patterns when zoomed out.
+                return;
+            }
+            if (segmentLength > repeat * 500) {
+                // simply skip drawing so many images - something must be wrong.
+                return;
+            }
+            AffineTransform saveTransform = g.getTransform();
+            g.translate(start.getInViewX(), start.getInViewY());
+            double dx = end.getInViewX() - start.getInViewX();
+            double dy = end.getInViewY() - start.getInViewY();
+            g.rotate(Math.atan2(dy, dx));
+
+            // The start of the next image
+            double imageStart = -(inLineOffset % repeat);
+
+            while (imageStart < segmentLength) {
+                int x = (int) imageStart;
+                int sx1 = Math.max(0, -x);
+                int sx2 = imgWidth - Math.max(0, x + imgWidth - (int) Math.ceil(segmentLength));
+                g.drawImage(image, x + sx1, dy1, x + sx2, dy2, sx1, 0, sx2, imgHeight, null);
+                imageStart += repeat;
+            }
+
+            g.setTransform(saveTransform);
+        });
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/RepeatImageElement.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/RepeatImageElement.java	(revision 11147)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/RepeatImageElement.java	(revision 11148)
@@ -15,5 +15,26 @@
 public class RepeatImageElement extends StyleElement {
 
-    public enum LineImageAlignment { TOP, CENTER, BOTTOM }
+    /**
+     * The side on which the image should be aligned to the line.
+     */
+    public enum LineImageAlignment {
+        TOP(.5),
+        CENTER(0),
+        BOTTOM(-.5);
+
+        private final double alignmentOffset;
+
+        LineImageAlignment(double alignmentOffset) {
+            this.alignmentOffset = alignmentOffset;
+        }
+
+        /**
+         * Gets the alignment offset.
+         * @return The offset relative to the image height compared to placing the image in the middle of the line.
+         */
+        public double getAlignmentOffset() {
+            return alignmentOffset;
+        }
+    }
 
     public MapImage pattern;
