Ignore:
Timestamp:
2011-02-10T00:05:18+01:00 (13 years ago)
Author:
bastiK
Message:

mapcss: text along line

File:
1 edited

Legend:

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

    r3879 r3880  
    1414import java.awt.TexturePaint;
    1515import java.awt.font.FontRenderContext;
     16import java.awt.font.GlyphVector;
    1617import java.awt.font.LineMetrics;
     18import java.awt.geom.AffineTransform;
    1719import java.awt.geom.GeneralPath;
    1820import java.awt.geom.Rectangle2D;
     
    3739import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.HorizontalTextAlignment;
    3840import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
    39 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.TextElement;
     41import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement;
    4042import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.VerticalTextAlignment;
     43import org.openstreetmap.josm.gui.mappaint.TextElement;
    4144import org.openstreetmap.josm.tools.ImageProvider;
    4245import org.openstreetmap.josm.tools.LanguageInfo;
    43 import org.openstreetmap.josm.tools.Utils;
    4446
    4547public class MapPainter {
     
    106108    }
    107109
    108     public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, boolean showDirection,
     110    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, TextElement text, boolean showDirection,
    109111            boolean reversedDirection, boolean showHeadArrowOnly) {
    110112
     
    163165        }
    164166        displaySegments(path, arrows, color, line, dashes, dashedColor);
     167        drawTextOnPath(way, text);
    165168    }
    166169
     
    193196    }
    194197
    195     public void drawNodeIcon(Node n, ImageIcon icon, float iconAlpha, boolean selected, boolean member, TextElement text) {
     198    private void drawTextOnPath(Way way, TextElement text) {
     199        if (text == null)
     200            return;
     201        String name = getAreaName(way);
     202        if (name == null || name.equals(""))
     203            return;
     204
     205        Polygon poly = new Polygon();
     206        Point lastPoint = null;
     207        Iterator<Node> it = way.getNodes().iterator();
     208        double pathLength = 0;
     209        int dx, dy;
     210        while (it.hasNext()) {
     211            Node n = it.next();
     212            Point p = nc.getPoint(n);
     213            poly.addPoint(p.x, p.y);
     214
     215            if(lastPoint != null) {
     216                dx = p.x - lastPoint.x;
     217                dy = p.y - lastPoint.y;
     218                pathLength += Math.sqrt(dx*dx + dy*dy);
     219            }
     220            lastPoint = p;
     221        }
     222
     223        FontMetrics fontMetrics = g.getFontMetrics(text.font); // if slow, use cache
     224        Rectangle2D rec = fontMetrics.getStringBounds(name, g); // if slow, approximate by strlen()*maxcharbounds(font)
     225
     226        if (rec.getWidth() > pathLength)
     227            return;
     228
     229        double t1 = (pathLength/2 - rec.getWidth()/2) / pathLength;
     230        double t2 = (pathLength/2 + rec.getWidth()/2) / pathLength;
     231
     232        double[] p1 = pointAt(t1, poly, pathLength);
     233        double[] p2 = pointAt(t2, poly, pathLength);
     234
     235        double angleOffset;
     236        double offsetSign;
     237        double tStart;
     238
     239        if (p1[0] < p2[0] &&
     240            p1[2] < Math.PI/2 &&
     241            p1[2] > -Math.PI/2) {
     242            angleOffset = 0;
     243            offsetSign = 1;
     244            tStart = t1;
     245        } else {
     246            angleOffset = Math.PI;
     247            offsetSign = -1;
     248            tStart = t2;
     249        }
     250
     251        FontRenderContext frc = g.getFontRenderContext();
     252        GlyphVector gv = text.font.createGlyphVector(frc, name);
     253
     254        for (int i=0; i<gv.getNumGlyphs(); ++i) {
     255            Rectangle2D rect = gv.getGlyphLogicalBounds(i).getBounds2D();
     256            double t = tStart + offsetSign * (rect.getX() + rect.getWidth()/2) / pathLength;
     257            double[] p = pointAt(t, poly, pathLength);
     258            AffineTransform trfm = AffineTransform.getTranslateInstance(p[0] - rect.getX(), p[1]);
     259            trfm.rotate(p[2]+angleOffset);
     260            double off = -rect.getY() - rect.getHeight()/2 + text.yOffset;
     261            trfm.translate(-rect.getWidth()/2, off);
     262            gv.setGlyphTransform(i, trfm);
     263        }
     264        g.setColor(text.color);
     265        g.drawGlyphVector(gv, 0, 0);
     266
     267    }
     268
     269    private double[] pointAt(double t, Polygon poly, double pathLength) {
     270        double totalLen = t * pathLength;
     271        double curLen = 0;
     272        int dx, dy;
     273        double segLen;
     274
     275        // Yes, it is ineffecient to iterate from the beginning for each glyph.
     276        // Can be optimized if it turns out to be slow.
     277        for (int i = 1; i < poly.npoints; ++i) {
     278            dx = poly.xpoints[i] - poly.xpoints[i-1];
     279            dy = poly.ypoints[i] - poly.ypoints[i-1];
     280            segLen = Math.sqrt(dx*dx + dy*dy);
     281            if (totalLen > curLen + segLen) {
     282                curLen += segLen;
     283                continue;
     284            }
     285            return new double[] {poly.xpoints[i-1]+(totalLen - curLen)/segLen*dx,
     286                                 poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy,
     287                                 Math.atan2(dy, dx)};
     288        }
     289        return null;
     290    }
     291
     292    public void drawNodeIcon(Node n, ImageIcon icon, float iconAlpha, boolean selected, boolean member, NodeTextElement text) {
    196293        Point p = nc.getPoint(n);
    197294        if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
     
    211308    }
    212309
    213     public void drawNodeSymbol(Node n, Symbol s, Color fillColor, Color strokeColor, TextElement text) {
     310    public void drawNodeSymbol(Node n, Symbol s, Color fillColor, Color strokeColor, NodeTextElement text) {
    214311        Point p = nc.getPoint(n);
    215312        if ((p.x < 0) || (p.y < 0) || (p.x > nc.getWidth()) || (p.y > nc.getHeight())) return;
     
    253350     * @param color The color of the node.
    254351     */
    255     public void drawNode(Node n, Color color, int size, boolean fill, TextElement text) {
     352    public void drawNode(Node n, Color color, int size, boolean fill, NodeTextElement text) {
    256353        if (size > 1) {
    257354            Point p = nc.getPoint(n);
     
    274371    }
    275372
    276     private void drawNodeText(Node n, TextElement text, Point p, int w_half, int h_half) {
     373    private void drawNodeText(Node n, NodeTextElement text, Point p, int w_half, int h_half) {
    277374        if (!isShowNames() || text == null)
    278375            return;
     
    345442    }
    346443
    347     public void drawArea(Way w, Color color, BufferedImage fillImage, float fillImageAlpha, String name) {
     444    public void drawArea(Way w, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
    348445        Polygon polygon = getPolygon(w);
    349         drawArea(polygon, color, fillImage, fillImageAlpha, name);
    350     }
    351 
    352     protected void drawArea(Polygon polygon, Color color, BufferedImage fillImage, float fillImageAlpha, String name) {
     446        drawArea(w, polygon, color, fillImage, fillImageAlpha, text);
     447    }
     448
     449    protected void drawArea(OsmPrimitive osm, Polygon polygon, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
    353450
    354451        if (fillImage == null) {
     
    366463        }
    367464
    368         if (name != null) {
     465        if (text != null && isShowNames()) {
     466            String name = text.textKey == null ? getAreaName(osm) : osm.get(text.textKey);
     467            if (name == null)
     468                return;
     469
    369470            Rectangle pb = polygon.getBounds();
    370471            FontMetrics fontMetrics = g.getFontMetrics(orderFont); // if slow, use cache
     
    403504    }
    404505
    405     public void drawArea(Relation r, Color color, BufferedImage fillImage, float fillImageAlpha, String name) {
     506    public void drawArea(Relation r, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
    406507        Multipolygon multipolygon = new Multipolygon(nc);
    407508        multipolygon.load(r);
     
    412513                    continue;
    413514                }
    414                 drawArea(p, color, fillImage, fillImageAlpha, getAreaName(r));
     515                drawArea(r, p, color, fillImage, fillImageAlpha, text);
    415516            }
    416517        }
Note: See TracChangeset for help on using the changeset viewer.