Changeset 1295 in josm


Ignore:
Timestamp:
2009-01-18T17:27:32+01:00 (15 years ago)
Author:
ulfl
Message:

turn restriction display in mappaint (very experimental)

will only work with standard restrictions, selection display still strange, ...

but will display icons rotated according to the direction of the from way :-)))

enable this with mappaint.restriction=true (default disabled)

Location:
trunk
Files:
4 edited

Legend:

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

    r1289 r1295  
    99import java.awt.Font;
    1010import java.awt.Graphics2D;
     11import java.awt.Image;
    1112import java.awt.Point;
    1213import java.awt.Polygon;
     
    3738import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
    3839import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
     40import org.openstreetmap.josm.tools.ImageProvider;
    3941
    4042public class MapPaintVisitor extends SimplePaintVisitor {
     
    4345    protected int fillAreas;
    4446    protected boolean drawMultipolygon;
     47    protected boolean drawRestriction;
     48    protected boolean restrictionDebug;
    4549    protected int showNames;
    4650    protected int showIcons;
     
    474478            {
    475479                if (m.member != null && !m.member.incomplete && !m.member.deleted
    476                 && m.member instanceof Node)
     480                && (drawRestriction || m.member instanceof Node))
    477481                {
    478482                    drawSelectedMember(m.member, styles != null ? styles.get(m.member) : null, true, true);
     
    485489        {
    486490            drawMultipolygon(r);
     491            return;
     492        }
     493       
     494        if (drawRestriction && r.keys != null && "restriction".equals(r.keys.get("type")))
     495        {
     496            drawRestriction(r);
    487497            return;
    488498        }
     
    490500        if(r.selected)
    491501            drawSelectedRelation(r);
     502    }
     503
     504   
     505    // this current experimental implementation will only work for standard restrictions:
     506    // from(Way) / via(Node) / to(Way)
     507    public void drawRestriction(Relation r) {
     508        if(restrictionDebug)
     509            System.out.println("Restriction: " + r.keys.get("name") + " restriction " + r.keys.get("restriction"));
     510     
     511        r.clearErrors();
     512
     513        Way fromWay = null;
     514        Way toWay = null;
     515        Node via = null;
     516
     517        // find the "from", "via" and "to" elements
     518        for (RelationMember m : r.members)
     519        {
     520            if(restrictionDebug)
     521                System.out.println("member " + m.member + " selected " + r.selected);
     522           
     523            if(m.member == null)
     524                r.putError(tr("Empty member in relation."), true);
     525            else if(m.member.deleted)
     526                r.putError(tr("Deleted member ''{0}'' in relation.",
     527                m.member.getName()), true);
     528            else if(m.member.incomplete)
     529            {
     530                // TODO: What to do with incomplete members?
     531                //incomplete = true;
     532                r.putError(tr("incomplete member {0}" + " with role {1}", m.member, m.role), true);
     533            }
     534            else
     535            {
     536                if(m.member instanceof Way)
     537                {
     538                    Way w = (Way) m.member;
     539                    ElemStyle style = getPrimitiveStyle(w);
     540                    //if(r.selected) {
     541                    //    drawWay(w, null /*(LineElemStyle)style*/, selectedColor, true);
     542                    //    w.mappaintDrawnCode = paintid;
     543                    //}
     544                    if(w.nodes.size() < 2)
     545                    {
     546                        r.putError(tr("Way ''{0}'' with less than two points.",
     547                        w.getName()), true);
     548                    }
     549                    else if("from".equals(m.role)) {
     550                        if(fromWay != null)
     551                            r.putError(tr("more than one from way found - ignored."), true);
     552                        else {
     553                            fromWay = w;
     554                        }
     555                    } else if("to".equals(m.role)) {
     556                        if(toWay != null)
     557                            r.putError(tr("more than one to way found - ignored."), true);
     558                        else {
     559                            toWay = w;
     560                        }
     561                    }
     562                    else
     563                        r.putError(tr("unknown role {0} - ignored", m.role), true);
     564                }
     565                else if(m.member instanceof Node)
     566                {
     567                    Node n = (Node) m.member;
     568                    if("via".equals(m.role))
     569                        if(via != null)
     570                            System.out.println("more than one via found - ignored");
     571                        else {
     572                            via = n;
     573                        }
     574                    else
     575                        r.putError(tr("unknown role {0} - ignored", m.role), true);
     576                }
     577                else
     578                    r.putError(tr("unknown instanceof member - ignored"), true);
     579            }
     580        }
     581       
     582        if (fromWay == null) {
     583            r.putError(tr("no from way found"), true);
     584            return;
     585        }
     586        if (toWay == null) {
     587            r.putError(tr("no to way found"), true);
     588            return;
     589        }
     590        if (via == null) {
     591            r.putError(tr("no via node found"), true);
     592            return;
     593        }
     594
     595        // check if "from" way starts or ends at via
     596        if(fromWay.nodes.get(0) != via && fromWay.nodes.get(fromWay.nodes.size()-1) != via) {
     597            r.putError(tr("from way doesn't start or end at a via node"), true);
     598            return;
     599        }
     600        // check if "to" way starts or ends at via
     601        /*if(toWay.nodes.get(0) != via && toWay.nodes.get(toWay.nodes.size()-1) != via) {
     602            r.putError(tr("to way doesn't start or end at a via node"), true);
     603            //return;
     604        }*/
     605
     606        // find the "direct" nodes before the via node
     607        Node fromNode = null;       
     608        try
     609        {
     610            if(fromWay.nodes.get(0) == via) {
     611                //System.out.println("From way heading away from via");
     612                fromNode = fromWay.nodes.get(1);
     613            } else {
     614                //System.out.println("From way heading towards via");
     615                fromNode = fromWay.nodes.get(fromWay.nodes.size()-2);
     616            }
     617        } catch (IndexOutOfBoundsException ioobe) {
     618            System.out.println("from must contain at least 2 nodes");
     619        }
     620
     621        // find the "direct" node after the via node
     622        Node toNode = null;
     623        try
     624        {
     625            if(toWay.nodes.get(0) == via) {
     626                if(restrictionDebug)
     627                    System.out.println("To way heading away from via");
     628                toNode = toWay.nodes.get(1);
     629            } else {
     630                if(restrictionDebug)
     631                    System.out.println("To way heading towards via");
     632                toNode = toWay.nodes.get(toWay.nodes.size()-2);
     633            }
     634        } catch (IndexOutOfBoundsException ioobe) {
     635            System.out.println("to must contain at least 2 nodes");
     636        }
     637       
     638        Point pFrom = nc.getPoint(fromNode.eastNorth);
     639        Point pVia = nc.getPoint(via.eastNorth);
     640       
     641        if(restrictionDebug) {
     642            Point pTo = nc.getPoint(toNode.eastNorth);
     643
     644            // debug output of interesting nodes
     645            System.out.println("From: " + fromNode);
     646            drawNode(fromNode, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
     647            System.out.println("Via: " + via);
     648            drawNode(via, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
     649            System.out.println("To: " + toNode);
     650            drawNode(toNode, selectedColor, selectedNodeSize, selectedNodeRadius, fillSelectedNode);
     651            System.out.println("From X: " + pFrom.x + " Y " + pFrom.y);
     652            System.out.println("Via  X: " + pVia.x  + " Y " + pVia.y);
     653            System.out.println("To   X: " + pTo.x   + " Y " + pTo.y);
     654        }
     655
     656        // starting from via, go back the "from" way a few pixels
     657        // (calculate the vector vx/vy with the specified length and the direction away from the "via" node along the first segment of the "from" way)
     658        double distanceFromVia=14;
     659        double dx = (pFrom.x >= pVia.x) ? (pFrom.x - pVia.x) : (pVia.x - pFrom.x);
     660        double dy = (pFrom.y >= pVia.y) ? (pFrom.y - pVia.y) : (pVia.y - pFrom.y);
     661       
     662        if(dx == 0.0) {
     663            System.out.println("dx " + dx);
     664            return;
     665        }
     666        double fromAngle = Math.atan(dy / dx);
     667        double fromAngleDeg = Math.toDegrees(fromAngle);
     668
     669        double vx = distanceFromVia * Math.cos(fromAngle);
     670        double vy = distanceFromVia * Math.sin(fromAngle);
     671       
     672        if(pFrom.x < pVia.x) vx = -vx;
     673        if(pFrom.y < pVia.y) vy = -vy;
     674
     675        if(restrictionDebug)
     676            System.out.println("vx " + vx + " vy " + vy);
     677       
     678        // go a few pixels away from the way (in a right angle)
     679        // (calculate the vx2/vy2 vector with the specified length and the direction 90degrees away from the first segment of the "from" way)
     680        double distanceFromWay=8;
     681        double vx2 = 0;
     682        double vy2 = 0;
     683        double iconAngle = 0;
     684
     685        if(pFrom.x >= pVia.x && pFrom.y >= pVia.y) {
     686            vx2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg - 90));
     687            vy2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg - 90));
     688            iconAngle = 270+fromAngleDeg;
     689        }
     690        if(pFrom.x < pVia.x && pFrom.y >= pVia.y) {
     691            vx2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg));
     692            vy2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg));
     693            iconAngle = 90-fromAngleDeg;
     694        }
     695        if(pFrom.x < pVia.x && pFrom.y < pVia.y) {
     696            vx2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg + 90));
     697            vy2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg + 90));
     698            iconAngle = 90+fromAngleDeg;
     699        }
     700        if(pFrom.x >= pVia.x && pFrom.y < pVia.y) {
     701            vx2 = distanceFromWay * Math.sin(Math.toRadians(fromAngleDeg+180));
     702            vy2 = distanceFromWay * Math.cos(Math.toRadians(fromAngleDeg+180));
     703            iconAngle = 270-fromAngleDeg;
     704        }
     705       
     706        IconElemStyle nodeStyle = (IconElemStyle)getPrimitiveStyle(r);
     707       
     708        if (nodeStyle == null) {
     709            r.putError(tr("Style for restriction {0} not found", r.keys.get("restriction")), true);
     710            return;
     711        }
     712
     713        // rotate icon with direction last node in from to
     714        if(restrictionDebug)
     715            System.out.println("Deg1 " + fromAngleDeg + " Deg2 " + (fromAngleDeg + 180) + " Icon " + iconAngle);
     716        ImageIcon rotatedIcon = ImageProvider.createRotatedImage(null /*icon2*/, nodeStyle.icon, iconAngle);
     717
     718        // scale down icon to 16*16 pixels
     719        ImageIcon smallIcon = new ImageIcon(rotatedIcon.getImage().getScaledInstance(16 , 16, Image.SCALE_SMOOTH));
     720        int w = smallIcon.getIconWidth(), h=smallIcon.getIconHeight();
     721        smallIcon.paintIcon ( Main.map.mapView, g, (int)(pVia.x+vx+vx2)-w/2, (int)(pVia.y+vy+vy2)-h/2 );
     722
     723        if (r.selected)
     724        {
     725            g.setColor (  selectedColor );
     726            g.drawRect ((int)(pVia.x+vx+vx2)-w/2-2,(int)(pVia.y+vy+vy2)-h/2-2, w+4, h+4);
     727        }
    492728    }
    493729
     
    9551191        styles = MapPaintStyles.getStyles().getStyleSet();
    9561192        drawMultipolygon = Main.pref.getBoolean("mappaint.multipolygon",true);
     1193        drawRestriction = Main.pref.getBoolean("mappaint.restriction",false);
     1194        restrictionDebug = Main.pref.getBoolean("mappaint.restriction.debug",false);
    9571195        orderFont = new Font(Main.pref.get("mappaint.font","Helvetica"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
    9581196        String currentLocale = Locale.getDefault().getLanguage();
  • trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java

    r1240 r1295  
    120120        {
    121121            return (osm.keys == null) ? null :
    122             ((osm instanceof Node) ? getNode(osm.keys) : get(osm.keys));
     122            ((osm instanceof Node || osm instanceof Relation) ? getNode(osm.keys) : get(osm.keys));
    123123        }
    124124
  • trunk/src/org/openstreetmap/josm/tools/ImageProvider.java

    r1169 r1295  
    22package org.openstreetmap.josm.tools;
    33
     4import java.awt.Component;
    45import java.awt.Cursor;
    56import java.awt.Graphics;
     7import java.awt.Graphics2D;
    68import java.awt.GraphicsConfiguration;
    79import java.awt.GraphicsEnvironment;
    810import java.awt.Image;
    911import java.awt.Point;
     12import java.awt.RenderingHints;
    1013import java.awt.Toolkit;
    1114import java.awt.Transparency;
     
    224227        }
    225228    }
     229
     230/* from: http://www.jidesoft.com/blog/2008/02/29/rotate-an-icon-in-java/
     231* License: "feel free to use"
     232*/
     233final static double DEGREE_90 = 90.0 * Math.PI / 180.0;
     234
     235    /**
     236     * Creates a rotated version of the input image.
     237     *
     238     * @param c            The component to get properties useful for painting, e.g. the foreground
     239     *                     or background color.
     240     * @param icon         the image to be rotated.
     241     * @param rotatedAngle the rotated angle, in degree, clockwise. It could be any double but we
     242     *                     will mod it with 360 before using it.
     243     *
     244     * @return the image after rotating.
     245     */
     246    public static ImageIcon createRotatedImage(Component c, Icon icon, double rotatedAngle) {
     247        // convert rotatedAngle to a value from 0 to 360
     248        double originalAngle = rotatedAngle % 360;
     249        if (rotatedAngle != 0 && originalAngle == 0) {
     250            originalAngle = 360.0;
     251        }
     252
     253        // convert originalAngle to a value from 0 to 90
     254        double angle = originalAngle % 90;
     255        if (originalAngle != 0.0 && angle == 0.0) {
     256            angle = 90.0;
     257        }
     258
     259        double radian = Math.toRadians(angle);
     260
     261        int iw = icon.getIconWidth();
     262        int ih = icon.getIconHeight();
     263        int w;
     264        int h;
     265
     266        if ((originalAngle >= 0 && originalAngle <= 90) || (originalAngle > 180 && originalAngle <= 270)) {
     267            w = (int) (iw * Math.sin(DEGREE_90 - radian) + ih * Math.sin(radian));
     268            h = (int) (iw * Math.sin(radian) + ih * Math.sin(DEGREE_90 - radian));
     269        }
     270        else {
     271            w = (int) (ih * Math.sin(DEGREE_90 - radian) + iw * Math.sin(radian));
     272            h = (int) (ih * Math.sin(radian) + iw * Math.sin(DEGREE_90 - radian));
     273        }
     274        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
     275        Graphics g = image.getGraphics();
     276        Graphics2D g2d = (Graphics2D) g.create();
     277
     278        // calculate the center of the icon.
     279        int cx = iw / 2;
     280        int cy = ih / 2;
     281
     282        // move the graphics center point to the center of the icon.
     283        g2d.translate(w/2, h/2);
     284
     285        // rotate the graphics about the center point of the icon
     286        g2d.rotate(Math.toRadians(originalAngle));
     287
     288        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
     289        icon.paintIcon(c, g2d, -cx, -cy);
     290
     291        g2d.dispose();
     292        return new ImageIcon(image);
     293    }
    226294}
  • trunk/styles/standard/elemstyles.xml

    r1269 r1295  
    4747<rules name="standard">
    4848
     49        <rule>
     50                <condition k="restriction" v="no_left_turn"/>
     51                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/no_left_turn.png"/>
     52                <scale_min>1</scale_min>
     53                <scale_max>40000</scale_max>
     54        </rule>
     55        <rule>
     56                <condition k="restriction" v="no_right_turn"/>
     57                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/no_right_turn.png"/>
     58                <scale_min>1</scale_min>
     59                <scale_max>40000</scale_max>
     60        </rule>
     61        <rule>
     62                <condition k="restriction" v="no_straight_on"/>
     63                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/no_straight_on.png"/>
     64                <scale_min>1</scale_min>
     65                <scale_max>40000</scale_max>
     66        </rule>
     67        <rule>
     68                <condition k="restriction" v="no_u_turn"/>
     69                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/no_u_turn.png"/>
     70                <scale_min>1</scale_min>
     71                <scale_max>40000</scale_max>
     72        </rule>
     73        <rule>
     74                <condition k="restriction" v="only_left_turn"/>
     75                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/only_left_turn.png"/>
     76                <scale_min>1</scale_min>
     77                <scale_max>40000</scale_max>
     78        </rule>
     79        <rule>
     80                <condition k="restriction" v="only_right_turn"/>
     81                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/only_right_turn.png"/>
     82                <scale_min>1</scale_min>
     83                <scale_max>40000</scale_max>
     84        </rule>
     85        <rule>
     86                <condition k="restriction" v="only_straight_on"/>
     87                <icon annotate="true" src="vehicle/restrictions/turn_restrictions/only_straight_on.png"/>
     88                <scale_min>1</scale_min>
     89                <scale_max>40000</scale_max>
     90        </rule>
     91
     92
    4993        <!-- mark some specials that should be fixed - they are already the default and therefore shouldn't be tagged -->
    5094        <rule>
Note: See TracChangeset for help on using the changeset viewer.