// License: GPL. Copyright 2007 by Immanuel Scholz and others package org.openstreetmap.josm.data.osm.visitor.paint; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.osm.BBox; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.osm.WaySegment; import org.openstreetmap.josm.gui.NavigatableComponent; import org.openstreetmap.josm.gui.mappaint.AreaElemStyle; import org.openstreetmap.josm.gui.mappaint.ElemStyle; import org.openstreetmap.josm.gui.mappaint.ElemStyles; import org.openstreetmap.josm.gui.mappaint.MapPaintStyles; import org.openstreetmap.josm.gui.mappaint.NodeElemStyle; import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList; /** *

A map renderer which renders a map according to style rules in a set of style sheets.

* */ public class StyledMapRenderer extends AbstractMapRenderer{ private ElemStyles styles; private double circum; private MapPainter painter; private MapPaintSettings paintSettings; private static int FLAG_NORMAL = 0; private static int FLAG_DISABLED = 1; private static int FLAG_MEMBER_OF_SELECTED = 2; private static int FLAG_SELECTED = 4; private static class StyleRecord implements Comparable { final ElemStyle style; final OsmPrimitive osm; final int flags; public StyleRecord(ElemStyle style, OsmPrimitive osm, int flags) { this.style = style; this.osm = osm; this.flags = flags; } @Override public int compareTo(StyleRecord other) { if ((this.flags & FLAG_DISABLED) != 0 && (other.flags & FLAG_DISABLED) == 0) return -1; if ((this.flags & FLAG_DISABLED) == 0 && (other.flags & FLAG_DISABLED) != 0) return 1; int d0 = Float.compare(this.style.major_z_index, other.style.major_z_index); if (d0 != 0) return d0; // selected on top of member of selected on top of unselected // FLAG_DISABLED bit is the same at this point if (this.flags > other.flags) return 1; if (this.flags < other.flags) return -1; int dz = Float.compare(this.style.z_index, other.style.z_index); if (dz != 0) return dz; // simple node on top of icons and shapes if (this.style == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && other.style != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE) return 1; if (this.style != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && other.style == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE) return -1; // newer primitives to the front long id = this.osm.getUniqueId() - other.osm.getUniqueId(); if (id > 0) return 1; if (id < 0) return -1; return Float.compare(this.style.object_z_index, other.style.object_z_index); } } private class StyleCollector { private final boolean drawArea; private final boolean drawMultipolygon; private final boolean drawRestriction; private final List styleElems; public StyleCollector(boolean drawArea, boolean drawMultipolygon, boolean drawRestriction) { this.drawArea = drawArea; this.drawMultipolygon = drawMultipolygon; this.drawRestriction = drawRestriction; styleElems = new ArrayList(); } public void add(Node osm, int flags) { StyleList sl = styles.get(osm, circum, nc); for (ElemStyle s : sl) { styleElems.add(new StyleRecord(s, osm, flags)); } } public void add(Way osm, int flags) { StyleList sl = styles.get(osm, circum, nc); for (ElemStyle s : sl) { if (!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElemStyle) { continue; } styleElems.add(new StyleRecord(s, osm, flags)); } } public void add(Relation osm, int flags) { StyleList sl = styles.get(osm, circum, nc); for (ElemStyle s : sl) { if (drawMultipolygon && drawArea && s instanceof AreaElemStyle && (flags & FLAG_DISABLED) == 0) { styleElems.add(new StyleRecord(s, osm, flags)); } else if (drawRestriction && s instanceof NodeElemStyle) { styleElems.add(new StyleRecord(s, osm, flags)); } } } public void drawAll() { Collections.sort(styleElems); for (StyleRecord r : styleElems) { r.style.paintPrimitive( r.osm, paintSettings, painter, (r.flags & FLAG_SELECTED) != 0, (r.flags & FLAG_MEMBER_OF_SELECTED) != 0 ); } } } /** * {@inheritDoc} */ public StyledMapRenderer(Graphics2D g, NavigatableComponent nc, boolean isInactiveMode) { super(g, nc, isInactiveMode); } private void collectNodeStyles(DataSet data, StyleCollector sc, BBox bbox) { for (final Node n: data.searchNodes(bbox)) { if (n.isDrawable()) { if (n.isDisabled()) { sc.add(n, FLAG_DISABLED); } else if (data.isSelected(n)) { sc.add(n, FLAG_SELECTED); } else if (n.isMemberOfSelected()) { sc.add(n, FLAG_MEMBER_OF_SELECTED); } else { sc.add(n, FLAG_NORMAL); } } } } private void collectWayStyles(DataSet data, StyleCollector sc, BBox bbox) { for (final Way w : data.searchWays(bbox)) { if (w.isDrawable()) { if (w.isDisabled()) { sc.add(w, FLAG_DISABLED); } else if (data.isSelected(w)) { sc.add(w, FLAG_SELECTED); } else if (w.isMemberOfSelected()) { sc.add(w, FLAG_MEMBER_OF_SELECTED); } else { sc.add(w, FLAG_NORMAL); } } } } private void collectRelationStyles(DataSet data, StyleCollector sc, BBox bbox) { for (Relation r: data.searchRelations(bbox)) { if (r.isDrawable()) { if (r.isDisabled()) { sc.add(r, FLAG_DISABLED); } else if (data.isSelected(r)) { sc.add(r, FLAG_SELECTED); } else { sc.add(r, FLAG_NORMAL); } } } } @Override public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) { //long start = System.currentTimeMillis(); BBox bbox = new BBox(bounds); styles = MapPaintStyles.getStyles(); this.paintSettings = MapPaintSettings.INSTANCE; circum = nc.getDist100Pixel(); boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000); boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true); styles.setDrawMultipolygon(drawMultipolygon); boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true); boolean leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, Main.pref.getBoolean("mappaint.use-antialiasing", true) ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); Collection hws = data.getHighlightedWaySegments(); this.painter = new MapPainter(paintSettings, g, isInactiveMode, nc, renderVirtualNodes, circum, leftHandTraffic, hws); StyleCollector sc = new StyleCollector(drawArea, drawMultipolygon, drawRestriction); collectNodeStyles(data, sc, bbox); collectWayStyles(data, sc, bbox); collectRelationStyles(data, sc, bbox); //long phase1 = System.currentTimeMillis(); sc.drawAll(); sc = null; painter.drawVirtualNodes(data.searchWays(bbox), data.getHighlightedVirtualNodes()); //long now = System.currentTimeMillis(); //System.err.println(String.format("PAINTING TOOK %d [PHASE1 took %d] (at scale %s)", now - start, phase1 - start, circum)); } }