Changeset 3565 in josm


Ignore:
Timestamp:
2010-09-25T16:35:08+02:00 (10 years ago)
Author:
bastiK
Message:

Draw ways as a continuous line and not each segment separately. This improves dashes drawing and joining segments for higher width values. It now always uses Cohen-Sutherland line clipping (not only for OpenJDK).

Location:
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint
Files:
3 edited

Legend:

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

    r2987 r3565  
    77import static java.awt.geom.Rectangle2D.OUT_BOTTOM;
    88import java.awt.Point;
     9import java.awt.Rectangle;
    910
    1011/**
    1112 * Computes the part of a line that is visible in a given rectangle.
    1213 * Using int leads to overflow, so we need long int.
    13  * http://en.wikipedia.org/wiki/Cohen-Sutherland
    1414 */
    1515public class LineClip {
    1616    private Point p1, p2;
     17    private final Rectangle clipBounds;
     18
     19    public LineClip(Point p1, Point p2, Rectangle clipBounds) {
     20        this.p1 = p1;
     21        this.p2 = p2;
     22        this.clipBounds = clipBounds;
     23    }
    1724
    1825    /**
    19      * The outcode of the point.
    20      * We cannot use Rectangle.outcode since it does not work with long ints.
     26     * run the clipping algorithm
     27     * @return true if the some parts of the line lies within the clip bounds
    2128     */
    22     public int computeOutCode (long x, long y, long xmin, long ymin, long xmax, long ymax) {
    23         int code = 0;
    24         if (y > ymax) {
    25             code |= OUT_TOP;
    26         }
    27         else if (y < ymin) {
    28             code |= OUT_BOTTOM;
    29         }
    30         if (x > xmax) {
    31             code |= OUT_RIGHT;
    32         }
    33         else if (x < xmin) {
    34             code |= OUT_LEFT;
    35         }
    36         return code;
     29    public boolean execute() {
     30        return cohenSutherland(p1.x, p1.y, p2.x, p2.y, clipBounds.x , clipBounds.y, clipBounds.x + clipBounds.width, clipBounds.y + clipBounds.height);
    3731    }
    3832
    39     public boolean cohenSutherland( long x1, long y1, long x2, long y2, long xmin, long ymin, long xmax, long ymax)
     33    /**
     34     * @return start point of the clipped line
     35     */
     36    public Point getP1()
     37    {
     38        return p1;
     39    }
     40
     41    /**
     42     * @return end point of the clipped line
     43     */
     44    public Point getP2()
     45    {
     46        return p2;
     47    }
     48
     49    /**
     50     * see http://en.wikipedia.org/wiki/Cohen-Sutherland
     51     */
     52    private boolean cohenSutherland( long x1, long y1, long x2, long y2, long xmin, long ymin, long xmax, long ymax)
    4053    {
    4154        int outcode0, outcode1, outcodeOut;
     
    94107    }
    95108
    96     public Point getP1()
    97     {
    98         return p1;
    99     }
    100 
    101     public Point getP2()
    102     {
    103         return p2;
     109    /**
     110     * The outcode of the point.
     111     * We cannot use Rectangle.outcode since it does not work with long ints.
     112     */
     113    private static int computeOutCode (long x, long y, long xmin, long ymin, long xmax, long ymax) {
     114        int code = 0;
     115        if (y > ymax) {
     116            code |= OUT_TOP;
     117        }
     118        else if (y < ymin) {
     119            code |= OUT_BOTTOM;
     120        }
     121        if (x > xmax) {
     122            code |= OUT_RIGHT;
     123        }
     124        else if (x < xmin) {
     125            code |= OUT_LEFT;
     126        }
     127        return code;
    104128    }
    105129}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java

    r3398 r3565  
    5454    private final Collection<String> regionalNameOrder;
    5555
     56    private static final double PHI = Math.toRadians(20);
     57    private static final double cosPHI = Math.cos(PHI);
     58    private static final double sinPHI = Math.sin(PHI);
     59
    5660    public MapPainter(MapPaintSettings settings, Graphics2D g, boolean inactive, NavigatableComponent nc, boolean virtual, double dist, double circum) {
    5761        this.g = g;
     
    8589
    8690        GeneralPath path = new GeneralPath();
     91        GeneralPath arrows = new GeneralPath();
     92        Rectangle bounds = g.getClipBounds();
     93        bounds.grow(100, 100);                  // avoid arrow heads at the border
    8794
    8895        Point lastPoint = null;
     96        boolean initialMoveToNeeded = true;
    8997        Iterator<Node> it = way.getNodes().iterator();
    9098        while (it.hasNext()) {
     
    92100            Point p = nc.getPoint(n);
    93101            if(lastPoint != null) {
    94                 drawSegment(path, lastPoint, p, showHeadArrowOnly ? !it.hasNext() : showDirection, reversedDirection);
     102                Point p1 = lastPoint;
     103                Point p2 = p;
     104
     105                /**
     106                 * Do custom clipping to work around openjdk bug. It leads to
     107                 * drawing artefacts when zooming in a lot. (#4289, #4424)
     108                 * (Looks like int overflow.)
     109                 */
     110                LineClip clip = new LineClip(p1, p2, bounds);
     111                if (clip.execute()) {
     112                    if (!p1.equals(clip.getP1())) {
     113                        p1 = clip.getP1();
     114                        path.moveTo(p1.x, p1.y);
     115                    } else if (initialMoveToNeeded) {
     116                        initialMoveToNeeded = false;
     117                        path.moveTo(p1.x, p1.y);
     118                    }
     119                    p2 = clip.getP2();
     120                    path.lineTo(p2.x, p2.y);
     121
     122                    /* draw arrow */
     123                    if (showHeadArrowOnly ? !it.hasNext() : showDirection) {
     124                        if (reversedDirection) {
     125                            Point tmp = p1;
     126                            p1 = p2;
     127                            p2 = tmp;
     128                        }
     129                        final double l =  10. / p1.distance(p2);
     130
     131                        final double sx = l * (p1.x - p2.x);
     132                        final double sy = l * (p1.y - p2.y);
     133
     134                        arrows.moveTo(p2.x, p2.y);
     135                        arrows.lineTo (p2.x + (int) Math.round(cosPHI * sx - sinPHI * sy), p2.y + (int) Math.round(sinPHI * sx + cosPHI * sy));
     136                        arrows.moveTo (p2.x + (int) Math.round(cosPHI * sx + sinPHI * sy), p2.y + (int) Math.round(- sinPHI * sx + cosPHI * sy));
     137                        arrows.lineTo(p2.x, p2.y);
     138                    }
     139                }
    95140            }
    96141            lastPoint = p;
    97142        }
    98         displaySegments(path, color, width, dashed, dashedColor);
    99     }
    100 
    101     private void displaySegments(GeneralPath path, Color color, int width, float dashed[], Color dashedColor) {
     143        displaySegments(path, arrows, color, width, dashed, dashedColor);
     144    }
     145
     146    private void displaySegments(GeneralPath path, GeneralPath arrows, Color color, int width, float dashed[], Color dashedColor) {
    102147        g.setColor(inactive ? inactiveColor : color);
    103148        if (useStrokes) {
     
    109154        }
    110155        g.draw(path);
     156        g.draw(arrows);
    111157
    112158        if(!inactive && useStrokes && dashedColor != null) {
     
    122168            }
    123169            g.draw(path);
     170            g.draw(arrows);
    124171        }
    125172
    126173        if(useStrokes) {
    127174            g.setStroke(new BasicStroke());
    128         }
    129     }
    130 
    131     private static final double PHI = Math.toRadians(20);
    132     private static final double cosPHI = Math.cos(PHI);
    133     private static final double sinPHI = Math.sin(PHI);
    134 
    135     private void drawSegment(GeneralPath path, Point p1, Point p2, boolean showDirection, boolean reversedDirection) {
    136         boolean drawIt = false;
    137         if (Main.isOpenjdk) {
    138             /**
    139              * Work around openjdk bug. It leads to drawing artefacts when zooming in a lot. (#4289, #4424)
    140              * (It looks like int overflow when clipping.) We do custom clipping.
    141              */
    142             Rectangle bounds = g.getClipBounds();
    143             bounds.grow(100, 100);                  // avoid arrow heads at the border
    144             LineClip clip = new LineClip();
    145             drawIt = clip.cohenSutherland(p1.x, p1.y, p2.x, p2.y, bounds.x, bounds.y, bounds.x+bounds.width, bounds.y+bounds.height);
    146             p1 = clip.getP1();
    147             p2 = clip.getP2();
    148         } else {
    149             drawIt = isSegmentVisible(p1, p2);
    150         }
    151         if (drawIt) {
    152             /* draw segment line */
    153             path.moveTo(p1.x, p1.y);
    154             path.lineTo(p2.x, p2.y);
    155 
    156             /* draw arrow */
    157             if (showDirection) {
    158                 Point q1 = p1;
    159                 Point q2 = p2;
    160                 if (reversedDirection) {
    161                     q1 = p2;
    162                     q2 = p1;
    163                     path.moveTo(q2.x, q2.y);
    164                 }
    165                 final double l =  10. / q1.distance(q2);
    166 
    167                 final double sx = l * (q1.x - q2.x);
    168                 final double sy = l * (q1.y - q2.y);
    169 
    170                 path.lineTo (q2.x + (int) Math.round(cosPHI * sx - sinPHI * sy), q2.y + (int) Math.round(sinPHI * sx + cosPHI * sy));
    171                 path.moveTo (q2.x + (int) Math.round(cosPHI * sx + sinPHI * sy), q2.y + (int) Math.round(- sinPHI * sx + cosPHI * sy));
    172                 path.lineTo(q2.x, q2.y);
    173             }
    174175        }
    175176    }
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/SimplePaintVisitor.java

    r3398 r3565  
    481481            Rectangle bounds = g.getClipBounds();
    482482            bounds.grow(100, 100);                  // avoid arrow heads at the border
    483             LineClip clip = new LineClip();
    484             drawIt = clip.cohenSutherland(p1.x, p1.y, p2.x, p2.y, bounds.x, bounds.y, bounds.x+bounds.width, bounds.y+bounds.height);
     483            LineClip clip = new LineClip(p1, p2, bounds);
     484            drawIt = clip.execute();
    485485            p1 = clip.getP1();
    486486            p2 = clip.getP2();
Note: See TracChangeset for help on using the changeset viewer.