Changeset 11148 in josm


Ignore:
Timestamp:
2016-10-19T17:30:15+02:00 (8 years ago)
Author:
michael2402
Message:

Fix #13636: Use clipping for images on a line (RepeatImageElement).

Location:
trunk/src/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    r11147 r11148  
    2525import java.awt.geom.Rectangle2D;
    2626import java.awt.geom.RoundRectangle2D;
     27import java.awt.image.BufferedImage;
    2728import java.util.ArrayList;
    2829import java.util.Collection;
     
    830831        final int imgHeight = pattern.getHeight();
    831832
    832         double currentWayLength = phase % repeat;
    833         if (currentWayLength < 0) {
    834             currentWayLength += repeat;
    835         }
    836 
    837         int dy1, dy2;
    838         switch (align) {
    839             case TOP:
    840                 dy1 = 0;
    841                 dy2 = imgHeight;
    842                 break;
    843             case CENTER:
    844                 dy1 = -imgHeight / 2;
    845                 dy2 = imgHeight + dy1;
    846                 break;
    847             case BOTTOM:
    848                 dy1 = -imgHeight;
    849                 dy2 = 0;
    850                 break;
    851             default:
    852                 throw new AssertionError();
    853         }
    854 
    855         MapViewPoint lastP = null;
     833        int dy1 = (int) ((align.getAlignmentOffset() - .5) * imgHeight);
     834        int dy2 = dy1 + imgHeight;
     835
    856836        OffsetIterator it = new OffsetIterator(way.getNodes(), offset);
     837        MapViewPath path = new MapViewPath(mapState);
     838        if (it.hasNext()) {
     839            path.moveTo(it.next());
     840        }
    857841        while (it.hasNext()) {
    858             MapViewPoint thisP = it.next();
    859 
    860             if (lastP != null) {
    861                 final double segmentLength = thisP.distanceToInView(lastP);
    862 
    863                 final double dx = thisP.getInViewX() - lastP.getInViewX();
    864                 final double dy = thisP.getInViewY() - lastP.getInViewY();
    865 
    866                 // pos is the position from the beginning of the current segment
    867                 // where an image should be painted
    868                 double pos = repeat - (currentWayLength % repeat);
    869 
    870                 AffineTransform saveTransform = g.getTransform();
    871                 g.translate(lastP.getInViewX(), lastP.getInViewY());
    872                 g.rotate(Math.atan2(dy, dx));
    873 
    874                 // draw the rest of the image from the last segment in case it
    875                 // is cut off
    876                 if (pos > spacing) {
    877                     // segment is too short for a complete image
    878                     if (pos > segmentLength + spacing) {
    879                         g.drawImage(pattern.getImage(disabled), 0, dy1, (int) segmentLength, dy2,
    880                                 (int) (repeat - pos), 0,
    881                                 (int) (repeat - pos + segmentLength), imgHeight, null);
    882                     } else {
    883                         // rest of the image fits fully on the current segment
    884                         g.drawImage(pattern.getImage(disabled), 0, dy1, (int) (pos - spacing), dy2,
    885                                 (int) (repeat - pos), 0, imgWidth, imgHeight, null);
    886                     }
    887                 }
    888                 // draw remaining images for this segment
    889                 while (pos < segmentLength) {
    890                     // cut off at the end?
    891                     if (pos + imgWidth > segmentLength) {
    892                         g.drawImage(pattern.getImage(disabled), (int) pos, dy1, (int) segmentLength, dy2,
    893                                 0, 0, (int) segmentLength - (int) pos, imgHeight, null);
    894                     } else {
    895                         g.drawImage(pattern.getImage(disabled), (int) pos, dy1, nc);
    896                     }
    897                     pos += repeat;
    898                 }
    899                 g.setTransform(saveTransform);
    900 
    901                 currentWayLength += segmentLength;
    902             }
    903             lastP = thisP;
    904         }
     842            path.lineTo(it.next());
     843        }
     844
     845        double startOffset = phase % repeat;
     846        if (startOffset < 0) {
     847            startOffset += repeat;
     848        }
     849
     850        BufferedImage image = pattern.getImage(disabled);
     851
     852        path.visitClippedLine(startOffset, repeat, (inLineOffset, start, end, startIsOldEnd) -> {
     853            final double segmentLength = start.distanceToInView(end);
     854            if (segmentLength < 0.1) {
     855                // avoid odd patterns when zoomed out.
     856                return;
     857            }
     858            if (segmentLength > repeat * 500) {
     859                // simply skip drawing so many images - something must be wrong.
     860                return;
     861            }
     862            AffineTransform saveTransform = g.getTransform();
     863            g.translate(start.getInViewX(), start.getInViewY());
     864            double dx = end.getInViewX() - start.getInViewX();
     865            double dy = end.getInViewY() - start.getInViewY();
     866            g.rotate(Math.atan2(dy, dx));
     867
     868            // The start of the next image
     869            double imageStart = -(inLineOffset % repeat);
     870
     871            while (imageStart < segmentLength) {
     872                int x = (int) imageStart;
     873                int sx1 = Math.max(0, -x);
     874                int sx2 = imgWidth - Math.max(0, x + imgWidth - (int) Math.ceil(segmentLength));
     875                g.drawImage(image, x + sx1, dy1, x + sx2, dy2, sx1, 0, sx2, imgHeight, null);
     876                imageStart += repeat;
     877            }
     878
     879            g.setTransform(saveTransform);
     880        });
    905881    }
    906882
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/RepeatImageElement.java

    r10238 r11148  
    1515public class RepeatImageElement extends StyleElement {
    1616
    17     public enum LineImageAlignment { TOP, CENTER, BOTTOM }
     17    /**
     18     * The side on which the image should be aligned to the line.
     19     */
     20    public enum LineImageAlignment {
     21        TOP(.5),
     22        CENTER(0),
     23        BOTTOM(-.5);
     24
     25        private final double alignmentOffset;
     26
     27        LineImageAlignment(double alignmentOffset) {
     28            this.alignmentOffset = alignmentOffset;
     29        }
     30
     31        /**
     32         * Gets the alignment offset.
     33         * @return The offset relative to the image height compared to placing the image in the middle of the line.
     34         */
     35        public double getAlignmentOffset() {
     36            return alignmentOffset;
     37        }
     38    }
    1839
    1940    public MapImage pattern;
Note: See TracChangeset for help on using the changeset viewer.