package net.osmand.plus.render; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import net.osmand.LogUtil; import net.osmand.plus.render.OsmandRenderer.RenderingContext; import net.osmand.plus.render.OsmandRenderer.RenderingPaintProperties; import net.osmand.render.OsmandRenderingRulesParser; import net.osmand.render.OsmandRenderingRulesParser.EffectAttributes; import net.osmand.render.OsmandRenderingRulesParser.FilterState; import net.osmand.render.OsmandRenderingRulesParser.RenderingRuleVisitor; import org.apache.commons.logging.Log; import org.xml.sax.SAXException; import android.graphics.Color; import android.graphics.Paint.Cap; public class BaseOsmandRender implements RenderingRuleVisitor { public String name = "default"; //$NON-NLS-1$ public List<String> depends = new ArrayList<String>(); public List<BaseOsmandRender> dependRenderers = new ArrayList<BaseOsmandRender>(); private static final Log log = LogUtil.getLog(BaseOsmandRender.class); @SuppressWarnings("unchecked") private Map<String, Map<String, List<FilterState>>>[] rules = new LinkedHashMap[6]; private int defaultColor; public void init(InputStream is) throws IOException, SAXException{ long time = System.currentTimeMillis(); OsmandRenderingRulesParser parser = new OsmandRenderingRulesParser(); parser.parseRenderingRules(is, this); log.info("Init render " + name + " for " + (System.currentTimeMillis() - time) + " ms"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ } public BaseOsmandRender() { } public boolean isDayRender() { return !name.endsWith(RendererRegistry.NIGHT_SUFFIX); } @Override public void rendering(String name, String depends, int defaultColor) { this.name = name; this.defaultColor = defaultColor; if(depends != null && depends.length() > 0){ for(String s : depends.split(",")) { //$NON-NLS-1$ if(s.trim().length() > 0){ this.depends.add(s.trim()); } } } } public int getDefaultColor() { int r = defaultColor; if (r == 0) { for (BaseOsmandRender d : dependRenderers) { r = d.getDefaultColor(); if (r != 0) { break; } } } return r; } @Override public void visitRule(int state, FilterState filter) { boolean accept = filter.minzoom != -1 || state == OsmandRenderingRulesParser.ORDER_STATE; if(state == OsmandRenderingRulesParser.POINT_STATE){ accept &= RenderingIcons.getIcons().containsKey(filter.icon); } if(state == OsmandRenderingRulesParser.ORDER_STATE){ accept &= filter.order != 0 && filter.orderType != 0; } if (accept) { if (rules[state] == null) { rules[state] = new LinkedHashMap<String, Map<String, List<FilterState>>>(); } if (rules[state].get(filter.tag) == null) { rules[state].put(filter.tag, new LinkedHashMap<String, List<FilterState>>()); } if (rules[state].get(filter.tag).get(filter.val) == null) { rules[state].get(filter.tag).put(filter.val, new ArrayList<FilterState>(3)); } rules[state].get(filter.tag).get(filter.val).add(filter); } } public Integer getPointIcon(String tag, String val, int zoom) { Integer i = getPointIconImpl(tag, val, zoom); if (i == null) { i = getPointIconImpl(tag, null, zoom); } if (i == null) { for (BaseOsmandRender d : dependRenderers) { i = d.getPointIcon(tag, val, zoom); if (i != null) { break; } } } return i; } // type public float getObjectOrder(String tag, String val, int type, int layer) { if(type == 0){ // replace multipolygon with polygon type = 3; } float f = getObjectOrderImpl(tag, val, type, layer); if (f == 0) { f = getObjectOrderImpl(tag, null, type, layer); } if (f == 0) { f = getObjectOrderImpl("", null, type, layer); //$NON-NLS-1$ } if(f == 0){ for(BaseOsmandRender d : dependRenderers){ f = d.getObjectOrder(tag, val, type, layer); if (f != 0) { break; } } } if (f == 0) { if (type == 0 || type == 3) { return 1f; } else if (type == 1) { return 128f; } else { return 35f; } } return f; } public boolean renderPolyline(String tag, String val, int zoom, RenderingContext rc, OsmandRenderer o, int layer){ boolean r = renderPolylineImpl(tag,val, zoom, rc, o, layer); if(!r){ r = renderPolylineImpl(tag, null, zoom, rc, o, layer); } if(!r){ for(BaseOsmandRender d : dependRenderers){ r = d.renderPolyline(tag, val, zoom, rc, o, layer); if (r) { break; } } } return r; } public boolean renderPolygon(String tag, String val, int zoom, RenderingContext rc, OsmandRenderer o){ boolean r = renderPolygonImpl(tag,val, zoom, rc, o); if(!r){ r = renderPolygonImpl(tag, null, zoom, rc, o); } if(!r){ for(BaseOsmandRender d : dependRenderers){ r = d.renderPolygon(tag, val, zoom, rc, o); if (r) { break; } } } return r; } public String renderObjectText(String name, String tag, String val, RenderingContext rc, boolean ref) { if(name == null || name.length() == 0){ return null; } String ret = renderObjectTextImpl(name, tag, val, rc, ref); if(ret == null){ ret = renderObjectTextImpl(name, tag, null, rc, ref); } if(ret == null){ for(BaseOsmandRender d : dependRenderers){ ret = d.renderObjectText(name, tag, val, rc, ref); if (ret != null) { break; } } } return ret; } public boolean isObjectVisible(String tag, String val, int zoom, int type) { if (type == 0) { // replace multipolygon with polygon type = 3; } if (isObjectVisibleImpl(tag, val, zoom, type)) { return true; } if (isObjectVisibleImpl(tag, null, zoom, type)) { return true; } for (BaseOsmandRender d : dependRenderers) { if (d.isObjectVisibleImpl(tag, val, zoom, type)) { return true; } } return false; } private boolean isObjectVisibleImpl(String tag, String val, int zoom, int type) { if (rules[type] != null) { Map<String, List<FilterState>> map = rules[type].get(tag); if (map != null) { List<FilterState> list = map.get(val); if (list != null) { for (FilterState f : list) { if (f.minzoom <= zoom && (zoom <= f.maxzoom || f.maxzoom == -1)) { return true; } } } } } return false; } private float getObjectOrderImpl(String tag, String val, int type, int layer) { if (rules[OsmandRenderingRulesParser.ORDER_STATE] != null) { Map<String, List<FilterState>> map = rules[OsmandRenderingRulesParser.ORDER_STATE].get(tag); if (map != null) { List<FilterState> list = map.get(val); if (list != null) { for (FilterState f : list) { if (f.orderType == type && f.layer == layer) { return f.order; } } } } } return 0; } private Integer getPointIconImpl(String tag, String val, int zoom) { if (rules[OsmandRenderingRulesParser.POINT_STATE] != null) { Map<String, List<FilterState>> map = rules[OsmandRenderingRulesParser.POINT_STATE].get(tag); if (map != null) { List<FilterState> list = map.get(val); if (list != null) { for (FilterState f : list) { if (f.minzoom <= zoom && (zoom <= f.maxzoom || f.maxzoom == -1)) { Integer i = RenderingIcons.getIcons().get(f.icon); return i == null ? 0 : i; } } } } } return null; } private boolean renderPolylineImpl(String tag, String val, int zoom, RenderingContext rc, OsmandRenderer o, int layer) { if(rules[OsmandRenderingRulesParser.LINE_STATE] == null){ return false; } Map<String, List<FilterState>> map = rules[OsmandRenderingRulesParser.LINE_STATE].get(tag); if (map != null) { List<FilterState> list = map.get(val); if (list != null) { FilterState found = null; for (FilterState f : list) { if (f.minzoom <= zoom && (zoom <= f.maxzoom || f.maxzoom == -1) && f.layer == layer) { found = f; break; } } if (found == null) { for (FilterState f : list) { if (f.minzoom <= zoom && (zoom <= f.maxzoom || f.maxzoom == -1) && f.layer == 0) { found = f; break; } } } if (found != null) { // to not make transparent rc.main.color = Color.BLACK; if (found.shader != null) { Integer i = RenderingIcons.getIcons().get(found.shader); if (i != null) { rc.main.shader = o.getShader(i); } } rc.main.fillArea = false; applyEffectAttributes(found.main, rc.main, o); if (found.effectAttributes.size() > 0) { applyEffectAttributes(found.effectAttributes.get(0), rc.second, o); if (found.effectAttributes.size() > 1) { applyEffectAttributes(found.effectAttributes.get(1), rc.third, o); } } return true; } } } return false; } private boolean renderPolygonImpl(String tag, String val, int zoom, RenderingContext rc, OsmandRenderer o) { if(rules[OsmandRenderingRulesParser.POLYGON_STATE] == null){ return false; } Map<String, List<FilterState>> map = rules[OsmandRenderingRulesParser.POLYGON_STATE].get(tag); if (map != null) { List<FilterState> list = map.get(val); if (list != null) { for (FilterState f : list) { if (f.minzoom <= zoom && (zoom <= f.maxzoom || f.maxzoom == -1)) { if(f.shader != null){ Integer i = RenderingIcons.getIcons().get(f.shader); if(i != null){ // to not make transparent rc.main.color = Color.BLACK; rc.main.shader = o.getShader(i); } } rc.main.fillArea = true; applyEffectAttributes(f.main, rc.main, o); if(f.effectAttributes.size() > 0){ applyEffectAttributes(f.effectAttributes.get(0), rc.second, o); if(f.effectAttributes.size() > 1){ applyEffectAttributes(f.effectAttributes.get(1), rc.third, o); } } return true; } } } } return false; } private void applyEffectAttributes(EffectAttributes ef, RenderingPaintProperties props, OsmandRenderer o){ if(ef.cap != null){ props.cap = Cap.valueOf(ef.cap.toUpperCase()); } if(ef.color != 0){ // do not set transparent color props.color = ef.color; } if(ef.pathEffect != null){ props.pathEffect = o.getDashEffect(ef.pathEffect); } if(ef.strokeWidth > 0){ props.strokeWidth = ef.strokeWidth; } if(ef.shadowColor != 0 && ef.shadowRadius > 0){ props.shadowColor = ef.shadowColor; props.shadowLayer = (int) ef.shadowRadius; } } private boolean checkRefTextRule(FilterState f, boolean ref){ if(ref){ return f.text != null && f.text.ref != null; } else { return f.text == null || f.text.ref == null || "true".equals(f.text.ref); //$NON-NLS-1$ } } private String renderObjectTextImpl(String name, String tag, String val, RenderingContext rc, boolean ref) { if(rules[OsmandRenderingRulesParser.TEXT_STATE] == null){ return null; } Map<String, List<FilterState>> map = rules[OsmandRenderingRulesParser.TEXT_STATE].get(tag); if (map != null) { List<FilterState> list = map.get(val); if (list != null) { // first find rule with same text length for (FilterState f : list) { if (f.minzoom <= rc.zoom && (rc.zoom <= f.maxzoom || f.maxzoom == -1) && checkRefTextRule(f, ref)) { if(f.textLength == name.length()){ fillTextProperties(f, rc); return name; } } } for (FilterState f : list) { if (f.minzoom <= rc.zoom && (rc.zoom <= f.maxzoom || f.maxzoom == -1) && checkRefTextRule(f, ref)) { if(f.textLength == 0){ fillTextProperties(f, rc); return name; } } } } } return null; } private void fillTextProperties(FilterState f, RenderingContext rc) { rc.textSize = f.text.textSize; rc.textColor = f.text.textColor == 0 ? Color.BLACK : f.text.textColor; rc.textSize = f.text.textSize; rc.textMinDistance = f.text.textMinDistance; rc.showTextOnPath = f.text.textOnPath; Integer i = RenderingIcons.getIcons().get(f.text.textShield); rc.textShield = i== null ? 0 : i.intValue(); rc.textWrapWidth = f.text.textWrapWidth; rc.textHaloRadius = f.text.textHaloRadius; rc.textBold = f.text.textBold; rc.textDy = f.text.textDy; } public List<String> getDepends() { return depends; } public void setDependRenderers(List<BaseOsmandRender> dependRenderers) { this.dependRenderers = dependRenderers; } }