diff --git a/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java b/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java index 3bc10c8f22..65600bee69 100644 --- a/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java +++ b/DataExtractionOSM/src/net/osmand/osm/MapRenderingTypes.java @@ -36,7 +36,6 @@ public class MapRenderingTypes { private static final Log log = LogUtil.getLog(MapRenderingTypes.class); - // TODO Internet access bits for point, polygon /** standard schema : polygon : ll aaaaa ttttt 11 : 14 bits multi : ll aaaaa ttttt 00 : 14 bits @@ -47,6 +46,7 @@ public class MapRenderingTypes { t - object type, s - subtype */ + // keep sync ! not change values public final static int MULTY_POLYGON_TYPE = 0; public final static int POLYGON_TYPE = 3; public final static int POLYLINE_TYPE = 2; diff --git a/DataExtractionOSM/src/net/osmand/render/OsmandRenderingRulesParser.java b/DataExtractionOSM/src/net/osmand/render/OsmandRenderingRulesParser.java deleted file mode 100644 index b2f7115f89..0000000000 --- a/DataExtractionOSM/src/net/osmand/render/OsmandRenderingRulesParser.java +++ /dev/null @@ -1,561 +0,0 @@ -package net.osmand.render; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Stack; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import net.osmand.osm.MapRenderingTypes; -import net.osmand.LogUtil; - -import org.apache.commons.logging.Log; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -public class OsmandRenderingRulesParser { - - - private final static Log log = LogUtil.getLog(OsmandRenderingRulesParser.class); - - public static class EffectAttributes { - public int color = 0; - public float strokeWidth = 0; - public String pathEffect = null; - public int shadowColor = 0; - public float shadowRadius = 0; - public String cap = null; - - } - - public static class TextAttributes { - public int textColor = 0; - public int textOrder = 0; - public float textSize = 0; - public boolean textBold = false; - public String textShield = null; - public int textMinDistance = 0; - public boolean textOnPath = false; - public int textWrapWidth = 0; - public float textHaloRadius = 0; - public int textDy = 0; - public String ref = null; - } - - protected static class SwitchState { - List filters = new ArrayList(); - } - - public static class FilterState { - public int minzoom = -1; - public int maxzoom = -1; - public String tag = null; - public String val = null; - public int layer = 0; - public int textLength = 0; - public float order = 0; - public int orderType = -1; - public Boolean nightMode = null; - - public String shader = null; - - // point - public String icon = null; - - public EffectAttributes main = new EffectAttributes(); - public TextAttributes text = null; - public List effectAttributes = new ArrayList(3); - - protected EffectAttributes getEffectAttributes(int i) { - i -= 2; - while (i >= effectAttributes.size()) { - effectAttributes.add(new EffectAttributes()); - } - return effectAttributes.get(i); - } - - - } - - public interface RenderingRuleVisitor { - - /** - * @param state - one of the point, polygon, line, text state - * @param filter - */ - public void visitRule(int state, FilterState filter); - - public void rendering(String name, String depends, int defaultColor, int defaultNightColor); - } - - - public final static int POINT_STATE = MapRenderingTypes.POINT_TYPE; - public final static int LINE_STATE = MapRenderingTypes.POLYLINE_TYPE; - public final static int POLYGON_STATE = MapRenderingTypes.POLYGON_TYPE; - public final static int TEXT_STATE = 4; - public final static int ORDER_STATE = 5; - - public void parseRenderingRules(InputStream is, RenderingRuleVisitor visitor) throws IOException, SAXException { - try { - final SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); - saxParser.parse(is, new RenderingRulesHandler(saxParser, visitor)); - } catch (ParserConfigurationException e) { - throw new SAXException(e); - } - } - - private class RenderingRulesHandler extends DefaultHandler { - private final SAXParser parser; - private final RenderingRuleVisitor visitor; - private int state; - - Stack stack = new Stack(); - - - public RenderingRulesHandler(SAXParser parser, RenderingRuleVisitor visitor){ - this.parser = parser; - this.visitor = visitor; - } - - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - name = parser.isNamespaceAware() ? localName : name; - if("filter".equals(name)){ //$NON-NLS-1$ - FilterState st = parseFilterAttributes(attributes); - stack.push(st); - } else if("order".equals(name)){ //$NON-NLS-1$ - state = ORDER_STATE; - } else if("text".equals(name)){ //$NON-NLS-1$ - state = TEXT_STATE; - } else if("point".equals(name)){ //$NON-NLS-1$ - state = POINT_STATE; - } else if("line".equals(name)){ //$NON-NLS-1$ - state = LINE_STATE; - } else if("polygon".equals(name)){ //$NON-NLS-1$ - state = POLYGON_STATE; - } else if("switch".equals(name)){ //$NON-NLS-1$ - SwitchState st = new SwitchState(); - stack.push(st); - } else if("case".equals(name)){ //$NON-NLS-1$ - FilterState st = parseFilterAttributes(attributes); - ((SwitchState)stack.peek()).filters.add(st); - } else if("renderer".equals(name)){ //$NON-NLS-1$ - String dc = attributes.getValue("defaultColor"); - int defaultColor = 0; - if(dc != null && dc.length() > 0){ - defaultColor = parseColor(dc); - } - String dnc = attributes.getValue("defaultNightColor"); - int defautNightColor = defaultColor; - if(dnc != null && dnc.length() > 0){ - defautNightColor = parseColor(dnc); - } - visitor.rendering(attributes.getValue("name"), attributes.getValue("depends"), defaultColor, defautNightColor); //$NON-NLS-1$ //$NON-NLS-2$ - } else { - log.warn("Unknown tag" + name); //$NON-NLS-1$ - } - } - - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - name = parser.isNamespaceAware() ? localName : name; - if ("filter".equals(name)) { //$NON-NLS-1$ - List list = popAndAggregateState(); - for (FilterState pop : list) { - if (pop.tag != null && (pop.minzoom != -1 || state == ORDER_STATE)) { - visitor.visitRule(state, pop); - } - } - } else if("switch".equals(name)){ //$NON-NLS-1$ - stack.pop(); - } - } - - - - public List popAndAggregateState() { - FilterState pop = (FilterState) stack.pop(); - List res = null; - for (int i = stack.size() - 1; i >= 0; i--) { - Object o = stack.get(i); - if(o instanceof FilterState){ - if(res == null){ - mergeStateInto((FilterState) o, pop); - } else { - for(FilterState f : res){ - mergeStateInto((FilterState) o, f); - } - } - } else { - List filters = ((SwitchState)o).filters; - if (res == null) { - res = new ArrayList(); - res.add(pop); - } - int l = res.size(); - for (int t = 0; t < filters.size() - 1; t++) { - for (int j = 0; j < l; j++) { - FilterState n = new FilterState(); - mergeStateInto(res.get(j), n); - res.add(n); - } - } - for (int j = 0; j < res.size(); j++) { - mergeStateInto(filters.get(j / l), res.get(j)); - } - } - - } - if(res == null){ - return Collections.singletonList(pop); - } else { - return res; - } - } - - public void mergeStateInto(FilterState toMerge, FilterState mergeInto){ - if(toMerge.maxzoom != -1 && mergeInto.maxzoom == -1){ - mergeInto.maxzoom = toMerge.maxzoom; - } - - if(toMerge.minzoom != -1 && mergeInto.minzoom == -1){ - mergeInto.minzoom = toMerge.minzoom; - } - if(toMerge.nightMode != null && mergeInto.nightMode == null){ - mergeInto.nightMode = toMerge.nightMode; - } - if(toMerge.icon != null && mergeInto.icon == null){ - mergeInto.icon = toMerge.icon; - } - if(toMerge.tag != null && mergeInto.tag == null){ - mergeInto.tag = toMerge.tag; - } - if(toMerge.orderType != -1 && mergeInto.orderType == -1){ - mergeInto.orderType = toMerge.orderType; - } - if(toMerge.layer != 0 && mergeInto.layer == 0){ - mergeInto.layer = toMerge.layer; - } - if(toMerge.order != 0 && mergeInto.order == 0){ - mergeInto.order = toMerge.order; - } - if(toMerge.textLength != 0 && mergeInto.textLength == 0){ - mergeInto.textLength = toMerge.textLength; - } - if(toMerge.val != null && mergeInto.val == null){ - mergeInto.val = toMerge.val; - } - if(toMerge.text != null){ - if(mergeInto.text == null){ - mergeInto.text = new TextAttributes(); - } - if(toMerge.text.textColor != 0 && mergeInto.text.textColor == 0){ - mergeInto.text.textColor = toMerge.text.textColor; - } - if(toMerge.text.textSize != 0 && mergeInto.text.textSize == 0){ - mergeInto.text.textSize = toMerge.text.textSize; - } - if(toMerge.text.textOrder != 0 && mergeInto.text.textOrder == 0){ - mergeInto.text.textOrder = toMerge.text.textOrder; - } - if(toMerge.text.textBold && !mergeInto.text.textBold){ - mergeInto.text.textBold = toMerge.text.textBold; - } - if(toMerge.text.textShield != null && mergeInto.text.textShield == null){ - mergeInto.text.textShield = toMerge.text.textShield; - } - - if(toMerge.text.ref != null && mergeInto.text.ref == null){ - mergeInto.text.ref = toMerge.text.ref; - } - - if(toMerge.text.textMinDistance != 0 && mergeInto.text.textMinDistance == 0){ - mergeInto.text.textMinDistance = toMerge.text.textMinDistance; - } - if(toMerge.text.textDy != 0 && mergeInto.text.textDy == 0){ - mergeInto.text.textDy = toMerge.text.textDy; - } - if(toMerge.text.textHaloRadius != 0 && mergeInto.text.textHaloRadius == 0){ - mergeInto.text.textHaloRadius = toMerge.text.textHaloRadius; - } - if(toMerge.text.textWrapWidth != 0 && mergeInto.text.textWrapWidth == 0){ - mergeInto.text.textWrapWidth = toMerge.text.textWrapWidth; - } - if(toMerge.text.textOnPath && !mergeInto.text.textOnPath){ - mergeInto.text.textOnPath = toMerge.text.textOnPath; - } - } - - mergeStateInto(toMerge.main, mergeInto.main); - while(mergeInto.effectAttributes.size() < toMerge.effectAttributes.size()){ - mergeInto.effectAttributes.add(new EffectAttributes()); - } - for(int i=0; i getIfChildren() { + return ifChildren != null ? ifChildren : Collections.EMPTY_LIST ; + } + + @SuppressWarnings("unchecked") + public List getIfElseChildren() { + return ifElseChildren != null ? ifElseChildren : Collections.EMPTY_LIST ; + } + + public void addIfChildren(RenderingRule rr){ + if(ifChildren == null){ + ifChildren = new ArrayList(); + } + ifChildren.add(rr); + } + + public void addIfElseChildren(RenderingRule rr){ + if(ifElseChildren == null){ + ifElseChildren = new ArrayList(); + } + ifElseChildren.add(rr); + } + +} diff --git a/DataExtractionOSM/src/net/osmand/render/RenderingRuleProperty.java b/DataExtractionOSM/src/net/osmand/render/RenderingRuleProperty.java new file mode 100644 index 0000000000..638349c65f --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/render/RenderingRuleProperty.java @@ -0,0 +1,264 @@ +package net.osmand.render; + + +import net.osmand.LogUtil; + +import org.apache.commons.logging.Log; + + +public class RenderingRuleProperty { + private final static Log log = LogUtil.getLog(RenderingRuleProperty.class); + + private final static int INT_TYPE = 1; + private final static int FLOAT_TYPE = 2; + private final static int STRING_TYPE = 3; + private final static int COLOR_TYPE = 4; + private final static int BOOLEAN_TYPE = 5; + + public static final int TRUE_VALUE = 1; + public static final int FALSE_VALUE = 0; + + protected final int type; + protected final boolean input; + protected final String attrName; + + protected int id = -1; + + // use for custom rendering rule properties + protected String name; + protected String description; + protected String[] possibleValues; + + private RenderingRuleProperty(String attrName, int type, boolean input){ + this.attrName = attrName; + this.type = type; + this.input = input; + } + + public boolean isInputProperty() { + return input; + } + + public boolean isOutputProperty() { + return !input; + } + + public void setId(int id) { + if (this.id != -1) { + throw new IllegalArgumentException(); + } + this.id = id; + } + + public int getId() { + return id; + } + + public String getAttrName() { + return attrName; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + protected void setName(String name) { + this.name = name; + } + + protected void setDescription(String description) { + this.description = description; + } + + protected void setPossibleValues(String[] possibleValues) { + this.possibleValues = possibleValues; + } + + public String[] getPossibleValues() { + if (isBoolean()) { + return new String[] { "true", "false" }; + } + return possibleValues; + } + + public boolean isBoolean() { + return type == BOOLEAN_TYPE; + } + + public boolean isFloat() { + return type == FLOAT_TYPE; + } + + public boolean isInt() { + return type == INT_TYPE; + } + + public boolean isColor() { + return type == COLOR_TYPE; + } + + public boolean isString() { + return type == STRING_TYPE; + } + + public boolean isIntParse(){ + return type == INT_TYPE || type == STRING_TYPE || type == COLOR_TYPE || type == BOOLEAN_TYPE; + } + + public boolean accept(int ruleValue, int renderingProperty){ + if(!isIntParse() || !input){ + return false; + } + return ruleValue == renderingProperty; + } + + public boolean accept(float ruleValue, float renderingProperty){ + if(type != FLOAT_TYPE || !input){ + return false; + } + return ruleValue == renderingProperty; + } + + @Override + public String toString() { + return "#RenderingRuleProperty " + getAttrName(); + } + + + public int parseIntValue(String value){ + if(type == INT_TYPE){ + try { + return Integer.parseInt(value); + } catch (NumberFormatException e) { + log.error("Rendering parse " + value); + } + return -1; + } else if(type == BOOLEAN_TYPE){ + return Boolean.parseBoolean(value) ? TRUE_VALUE : FALSE_VALUE; + } else if(type == STRING_TYPE){ + // requires dictionary to parse + return -1; + } else if(type == COLOR_TYPE){ + try { + return parseColor(value); + } catch (RuntimeException e) { + log.error("Rendering parse " + e.getMessage()); + } + return -1; + } else { + return -1; + } + } + + public float parseFloatValue(String value){ + if(type == FLOAT_TYPE){ + try { + return Float.parseFloat(value); + } catch (NumberFormatException e) { + log.error("Rendering parse " + value); + } + return -1; + } else { + return -1; + } + } + + + + public static RenderingRuleProperty createOutputIntProperty(String name){ + return new RenderingRuleProperty(name, INT_TYPE, false); + } + + public static RenderingRuleProperty createOutputBooleanProperty(String name){ + return new RenderingRuleProperty(name, BOOLEAN_TYPE, false); + } + + public static RenderingRuleProperty createInputBooleanProperty(String name){ + return new RenderingRuleProperty(name, BOOLEAN_TYPE, true); + } + + public static RenderingRuleProperty createOutputFloatProperty(String name){ + return new RenderingRuleProperty(name, FLOAT_TYPE, false); + } + + public static RenderingRuleProperty createOutputStringProperty(String name){ + return new RenderingRuleProperty(name, STRING_TYPE, false); + } + + public static RenderingRuleProperty createInputIntProperty(String name){ + return new RenderingRuleProperty(name, INT_TYPE, true); + } + + public static RenderingRuleProperty createInputColorProperty(String name){ + return new RenderingRuleProperty(name, COLOR_TYPE, true); + } + + public static RenderingRuleProperty createOutputColorProperty(String name){ + return new RenderingRuleProperty(name, COLOR_TYPE, false); + } + + public static RenderingRuleProperty createInputStringProperty(String name){ + return new RenderingRuleProperty(name, STRING_TYPE, true); + } + + public static RenderingRuleProperty createInputLessIntProperty(String name){ + return new RenderingRuleProperty(name, INT_TYPE, true) { + @Override + public boolean accept(int ruleValue, int renderingProperty) { + if(!isIntParse() || !input){ + return false; + } + return ruleValue >= renderingProperty; + } + }; + } + + public static RenderingRuleProperty createInputGreaterIntProperty(String name){ + return new RenderingRuleProperty(name, INT_TYPE, true) { + @Override + public boolean accept(int ruleValue, int renderingProperty) { + if(!isIntParse() || !input){ + return false; + } + return ruleValue <= renderingProperty; + } + }; + } + + /** + * Parse the color string, and return the corresponding color-int. + * If the string cannot be parsed, throws an IllegalArgumentException + * exception. Supported formats are: + * #RRGGBB + * #AARRGGBB + * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta', + * 'yellow', 'lightgray', 'darkgray' + */ + public static int parseColor(String colorString) { + if (colorString.charAt(0) == '#') { + // Use a long to avoid rollovers on #ffXXXXXX + long color = Long.parseLong(colorString.substring(1), 16); + if (colorString.length() == 7) { + // Set the alpha value + color |= 0x00000000ff000000; + } else if (colorString.length() != 9) { + throw new IllegalArgumentException("Unknown color" + colorString); //$NON-NLS-1$ + } + return (int)color; + } + throw new IllegalArgumentException("Unknown color" + colorString); //$NON-NLS-1$ + } + + public static String colorToString(int color) { + if ((0xFF000000 & color) == 0xFF000000) { + return "#" + Integer.toHexString(color & 0x00FFFFFF); //$NON-NLS-1$ + } else { + return "#" + Integer.toHexString(color); //$NON-NLS-1$ + } + } + +} diff --git a/DataExtractionOSM/src/net/osmand/render/RenderingRuleSearchRequest.java b/DataExtractionOSM/src/net/osmand/render/RenderingRuleSearchRequest.java new file mode 100644 index 0000000000..c3c089eb1b --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/render/RenderingRuleSearchRequest.java @@ -0,0 +1,210 @@ +package net.osmand.render; + + +public class RenderingRuleSearchRequest { + + private final RenderingRulesStorage storage; + private final RenderingRuleSearchRequest dependsRequest; + RenderingRuleProperty[] props; + int[] values; + float[] fvalues; + + int[] savedValues; + float[] savedFvalues; + + boolean searchResult = false; + + + public final RenderingRuleStorageProperties ALL; + + public RenderingRuleSearchRequest(RenderingRulesStorage storage) { + this.storage = storage; + this.ALL = storage.PROPS; + if(storage.getDependsStorage() != null){ + dependsRequest = new RenderingRuleSearchRequest(storage.getDependsStorage()); + } else { + dependsRequest = null; + } + props = storage.PROPS.getPoperties(); + values = new int[props.length]; + for (int i = 0; i < props.length; i++) { + if (!props[i].isColor()) { + values[i] = -1; + } + } + fvalues = new float[props.length]; + saveState(); + } + + public void setStringFilter(RenderingRuleProperty p, String filter) { + assert p.isInputProperty(); + values[p.getId()] = storage.getDictionaryValue(filter); + } + + public void setIntFilter(RenderingRuleProperty p, int filter) { + assert p.isInputProperty(); + values[p.getId()] = filter; + } + + public void setBooleanFilter(RenderingRuleProperty p, boolean filter) { + assert p.isInputProperty(); + values[p.getId()] = filter ? RenderingRuleProperty.TRUE_VALUE : RenderingRuleProperty.FALSE_VALUE; + } + + public void saveState() { + savedValues = new int[values.length]; + savedFvalues = new float[fvalues.length]; + System.arraycopy(values, 0, savedValues, 0, values.length); + System.arraycopy(fvalues, 0, savedFvalues, 0, fvalues.length); + } + + public void clearState() { + System.arraycopy(savedValues, 0, values, 0, values.length); + System.arraycopy(savedFvalues, 0, fvalues, 0, fvalues.length); + } + + public void setInitialTagValueZoom(String tag, String val, int zoom){ + clearState(); + setIntFilter(ALL.R_MINZOOM, zoom); + setIntFilter(ALL.R_MAXZOOM, zoom); + setStringFilter(ALL.R_TAG, tag); + setStringFilter(ALL.R_VALUE, val); + } + + public boolean isFound() { + return searchResult; + } + + public boolean search(int state) { + return search(state, true); + } + + public boolean search(int state, boolean loadOutput) { + searchResult = false; + int tagKey = values[storage.PROPS.R_TAG.getId()]; + int valueKey = values[storage.PROPS.R_VALUE.getId()]; + boolean result = searchInternal(state, tagKey, valueKey, loadOutput); + if (result) { + searchResult = true; + return true; + } + result = searchInternal(state, tagKey, 0, loadOutput); + if (result) { + searchResult = true; + return true; + } + result = searchInternal(state, 0, 0, loadOutput); + if (result) { + searchResult = true; + return true; + } + + if(dependsRequest != null){ + // TODO search depends ? + // and copy results to local array + dependsRequest.search(state); + } + return false; + } + + + private boolean searchInternal(int state, int tagKey, int valueKey, boolean loadOutput) { + values[storage.PROPS.R_TAG.getId()] = tagKey; + values[storage.PROPS.R_VALUE.getId()] = valueKey; + RenderingRule accept = storage.getRule(state, tagKey, valueKey); + if (accept == null) { + return false; + } + boolean match = visitRule(accept, loadOutput); + return match; + } + + private boolean visitRule(RenderingRule rule, boolean loadOutput) { + RenderingRuleProperty[] properties = rule.getProperties(); + for (int i = 0; i < properties.length; i++) { + RenderingRuleProperty rp = properties[i]; + if (rp.isInputProperty()) { + boolean match; + if (rp.isFloat()) { + match = rp.accept(rule.getFloatProp(i), fvalues[rp.getId()]); + } else { + match = rp.accept(rule.getIntProp(i), values[rp.getId()]); + } + if (!match) { + return false; + } + } + } + if (!loadOutput) { + return true; + } + // accept it + for (int i = 0; i < properties.length; i++) { + RenderingRuleProperty rp = properties[i]; + if (rp.isOutputProperty()) { + searchResult = true; + if (rp.isFloat()) { + fvalues[rp.getId()] = rule.getFloatProp(i); + } else { + values[rp.getId()] = rule.getIntProp(i); + } + } + } + + for (RenderingRule rr : rule.getIfElseChildren()) { + boolean match = visitRule(rr, loadOutput); + if (match) { + break; + } + } + + for(RenderingRule rr : rule.getIfChildren()){ + visitRule(rr, loadOutput); + } + return true; + + } + + public boolean isSpecified(RenderingRuleProperty property){ + if(property.isFloat()){ + return fvalues[property.getId()] != 0; + } else { + int val = values[property.getId()]; + if(property.isColor()){ + return val != 0; + } else { + return val != -1; + } + } + } + + public RenderingRuleProperty[] getProperties() { + return props; + } + + public String getStringPropertyValue(RenderingRuleProperty property) { + int val = values[property.getId()]; + if(val < 0){ + return null; + } + return storage.getStringValue(val); + } + + public float getFloatPropertyValue(RenderingRuleProperty property) { + return fvalues[property.getId()]; + } + + public String getColorStringPropertyValue(RenderingRuleProperty property) { + return RenderingRuleProperty.colorToString(values[property.getId()]); + } + + public int getIntPropertyValue(RenderingRuleProperty property) { + return values[property.getId()]; + } + + public int getIntPropertyValue(RenderingRuleProperty property, int defValue) { + int val = values[property.getId()]; + return val == -1 ? defValue : val; + } + +} \ No newline at end of file diff --git a/DataExtractionOSM/src/net/osmand/render/RenderingRuleStorageProperties.java b/DataExtractionOSM/src/net/osmand/render/RenderingRuleStorageProperties.java new file mode 100644 index 0000000000..fc20725f0b --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/render/RenderingRuleStorageProperties.java @@ -0,0 +1,168 @@ +package net.osmand.render; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class RenderingRuleStorageProperties { + + public static final String TEXT_LENGTH = "textLength"; + public static final String REF = "ref"; + public static final String TEXT_SHIELD = "textShield"; + public static final String SHADOW_RADIUS = "shadowRadius"; + public static final String SHADOW_COLOR = "shadowColor"; + public static final String SHADER = "shader"; + public static final String CAP_3 = "cap_3"; + public static final String CAP_2 = "cap_2"; + public static final String CAP = "cap"; + public static final String PATH_EFFECT_3 = "pathEffect_3"; + public static final String PATH_EFFECT_2 = "pathEffect_2"; + public static final String PATH_EFFECT = "pathEffect"; + public static final String STROKE_WIDTH_3 = "strokeWidth_3"; + public static final String STROKE_WIDTH_2 = "strokeWidth_2"; + public static final String STROKE_WIDTH = "strokeWidth"; + public static final String COLOR_3 = "color_3"; + public static final String COLOR = "color"; + public static final String COLOR_2 = "color_2"; + public static final String TEXT_BOLD = "textBold"; + public static final String TEXT_ORDER = "textOrder"; + public static final String TEXT_MIN_DISTANCE = "textMinDistance"; + public static final String TEXT_ON_PATH = "textOnPath"; + public static final String ICON = "icon"; + public static final String LAYER = "layer"; + public static final String ORDER = "order"; + public static final String ORDER_TYPE = "orderType"; + public static final String TAG = "tag"; + public static final String VALUE = "value"; + public static final String MINZOOM = "minzoom"; + public static final String MAXZOOM = "maxzoom"; + public static final String NIGHT_MODE = "nightMode"; + public static final String TEXT_DY = "textDy"; + public static final String TEXT_SIZE = "textSize"; + public static final String TEXT_COLOR = "textColor"; + public static final String TEXT_HALO_RADIUS = "textHaloRadius"; + public static final String TEXT_WRAP_WIDTH = "textWrapWidth"; + + public RenderingRuleProperty R_TEXT_LENGTH; + public RenderingRuleProperty R_REF; + public RenderingRuleProperty R_TEXT_SHIELD; + public RenderingRuleProperty R_SHADOW_RADIUS; + public RenderingRuleProperty R_SHADOW_COLOR; + public RenderingRuleProperty R_SHADER; + public RenderingRuleProperty R_CAP_3; + public RenderingRuleProperty R_CAP_2; + public RenderingRuleProperty R_CAP; + public RenderingRuleProperty R_PATH_EFFECT_3; + public RenderingRuleProperty R_PATH_EFFECT_2; + public RenderingRuleProperty R_PATH_EFFECT; + public RenderingRuleProperty R_STROKE_WIDTH_3; + public RenderingRuleProperty R_STROKE_WIDTH_2; + public RenderingRuleProperty R_STROKE_WIDTH; + public RenderingRuleProperty R_COLOR_3; + public RenderingRuleProperty R_COLOR; + public RenderingRuleProperty R_COLOR_2; + public RenderingRuleProperty R_TEXT_BOLD; + public RenderingRuleProperty R_TEXT_ORDER; + public RenderingRuleProperty R_TEXT_MIN_DISTANCE; + public RenderingRuleProperty R_TEXT_ON_PATH; + public RenderingRuleProperty R_ICON; + public RenderingRuleProperty R_LAYER; + public RenderingRuleProperty R_ORDER; + public RenderingRuleProperty R_ORDER_TYPE; + public RenderingRuleProperty R_TAG; + public RenderingRuleProperty R_VALUE; + public RenderingRuleProperty R_MINZOOM; + public RenderingRuleProperty R_MAXZOOM; + public RenderingRuleProperty R_NIGHT_MODE; + public RenderingRuleProperty R_TEXT_DY; + public RenderingRuleProperty R_TEXT_SIZE; + public RenderingRuleProperty R_TEXT_COLOR; + public RenderingRuleProperty R_TEXT_HALO_RADIUS; + public RenderingRuleProperty R_TEXT_WRAP_WIDTH; + + final Map properties = new LinkedHashMap(); + final List rules = new ArrayList(); + final List customRules = new ArrayList(); + + public RenderingRuleStorageProperties() { + createDefaultRenderingRuleProperties(); + } + + public void createDefaultRenderingRuleProperties() { + R_TAG = registerRuleInternal(RenderingRuleProperty.createInputStringProperty(TAG)); + R_VALUE = registerRuleInternal(RenderingRuleProperty.createInputStringProperty(VALUE)); + R_MINZOOM = registerRuleInternal(RenderingRuleProperty.createInputGreaterIntProperty(MINZOOM)); + R_MAXZOOM = registerRuleInternal(RenderingRuleProperty.createInputLessIntProperty(MAXZOOM)); + R_NIGHT_MODE = registerRuleInternal(RenderingRuleProperty.createInputBooleanProperty(NIGHT_MODE)); + R_LAYER = registerRuleInternal(RenderingRuleProperty.createInputIntProperty(LAYER)); + R_ORDER_TYPE = registerRuleInternal(RenderingRuleProperty.createInputIntProperty(ORDER_TYPE)); + R_TEXT_LENGTH = registerRuleInternal(RenderingRuleProperty.createInputIntProperty(TEXT_LENGTH)); + R_REF = registerRuleInternal(RenderingRuleProperty.createInputBooleanProperty(REF)); + + // order - no sense to make it float + R_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(ORDER)); + + // text properties + R_TEXT_WRAP_WIDTH = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_WRAP_WIDTH)); + R_TEXT_DY = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_DY)); + R_TEXT_HALO_RADIUS = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_HALO_RADIUS)); + R_TEXT_SIZE = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_SIZE)); + R_TEXT_ORDER = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_ORDER)); + R_TEXT_MIN_DISTANCE = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(TEXT_MIN_DISTANCE)); + R_TEXT_SHIELD = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(TEXT_SHIELD)); + + + R_TEXT_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(TEXT_COLOR)); + + R_TEXT_BOLD = registerRuleInternal(RenderingRuleProperty.createOutputBooleanProperty(TEXT_BOLD)); + R_TEXT_ON_PATH = registerRuleInternal(RenderingRuleProperty.createOutputBooleanProperty(TEXT_ON_PATH)); + + // point + R_ICON = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(ICON)); + + // polygon/way + R_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(COLOR)); + R_COLOR_2 = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(COLOR_2)); + R_COLOR_3 = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(COLOR_3)); + R_STROKE_WIDTH = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(STROKE_WIDTH)); + R_STROKE_WIDTH_2 = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(STROKE_WIDTH_2)); + R_STROKE_WIDTH_3 = registerRuleInternal(RenderingRuleProperty.createOutputFloatProperty(STROKE_WIDTH_3)); + + R_PATH_EFFECT = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(PATH_EFFECT)); + R_PATH_EFFECT_2 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(PATH_EFFECT_2)); + R_PATH_EFFECT_3 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(PATH_EFFECT_3)); + R_CAP = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(CAP)); + R_CAP_2 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(CAP_2)); + R_CAP_3 = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(CAP_3)); + R_SHADER = registerRuleInternal(RenderingRuleProperty.createOutputStringProperty(SHADER)); + + R_SHADOW_COLOR = registerRuleInternal(RenderingRuleProperty.createOutputColorProperty(SHADOW_COLOR)); + R_SHADOW_RADIUS = registerRuleInternal(RenderingRuleProperty.createOutputIntProperty(SHADOW_RADIUS)); + } + + public RenderingRuleProperty get(String name) { + return properties.get(name); + } + + public RenderingRuleProperty[] getPoperties() { + return rules.toArray(new RenderingRuleProperty[rules.size()]); + } + + public List getCustomRules() { + return customRules; + } + + private RenderingRuleProperty registerRuleInternal(RenderingRuleProperty p) { + properties.put(p.getAttrName(), p); + p.setId(rules.size()); + rules.add(p); + return p; + } + + public RenderingRuleProperty registerRule(RenderingRuleProperty p) { + registerRuleInternal(p); + customRules.add(p); + return p; + } +} diff --git a/DataExtractionOSM/src/net/osmand/render/RenderingRulesStorage.java b/DataExtractionOSM/src/net/osmand/render/RenderingRulesStorage.java new file mode 100644 index 0000000000..bdb98edc6d --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/render/RenderingRulesStorage.java @@ -0,0 +1,417 @@ +package net.osmand.render; + +import gnu.trove.map.hash.TIntObjectHashMap; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import net.osmand.LogUtil; +import net.osmand.osm.MapRenderingTypes; + +import org.apache.commons.logging.Log; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +public class RenderingRulesStorage { + + private final static Log log = LogUtil.getLog(RenderingRulesStorage.class); + + // keep sync ! + public final static int POINT_RULES = MapRenderingTypes.POINT_TYPE; + public final static int LINE_RULES = MapRenderingTypes.POLYLINE_TYPE; + public final static int POLYGON_RULES = MapRenderingTypes.POLYGON_TYPE; + public final static int TEXT_RULES = 4; + public final static int ORDER_RULES = 5; + private final static int LENGTH_RULES = 6; + + private final static int SHIFT_TAG_VAL = 16; + + List dictionary = new ArrayList(); + Map dictionaryMap = new LinkedHashMap(); + + public final RenderingRuleStorageProperties PROPS = new RenderingRuleStorageProperties(); + + @SuppressWarnings("unchecked") + protected TIntObjectHashMap[] tagValueGlobalRules = new TIntObjectHashMap[LENGTH_RULES]; + + private int bgColor = 0; + private int bgNightColor = 0; + private String renderingName; + private String depends; + private RenderingRulesStorage dependsStorage; + + + public RenderingRulesStorage(){ + // register empty string as 0 + getDictionaryValue(""); + } + + public int getDictionaryValue(String val) { + if(dictionaryMap.containsKey(val)){ + return dictionaryMap.get(val); + } + int nextInd = dictionaryMap.size(); + dictionaryMap.put(val, nextInd); + dictionary.add(val); + return nextInd; + + } + + public String getStringValue(int i){ + return dictionary.get(i); + } + + + public String getName() { + return renderingName; + } + + public int getBgColor() { + return bgColor; + } + + public int getBgNightColor() { + return bgNightColor; + } + + public int getBgColor(boolean nightMode){ + return nightMode ? bgNightColor : bgColor; + } + + public String getDepends() { + return depends; + } + + public RenderingRulesStorage getDependsStorage() { + return dependsStorage; + } + + public void setDependsStorage(RenderingRulesStorage dependsStorage) { + this.dependsStorage = dependsStorage; + } + + + public void parseRulesFromXmlInputStream(InputStream is) throws SAXException, IOException { + try { + final SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); + saxParser.parse(is, new RenderingRulesHandler(saxParser)); + } catch (ParserConfigurationException e) { + throw new SAXException(e); + } + } + + public static String colorToString(int color) { + if ((0xFF000000 & color) == 0xFF000000) { + return "#" + Integer.toHexString(color & 0x00FFFFFF); //$NON-NLS-1$ + } else { + return "#" + Integer.toHexString(color); //$NON-NLS-1$ + } + } + + @SuppressWarnings("unchecked") + private void registerGlobalRule(RenderingRule rr, int state, Map attrsMap) throws SAXException { + int tag = rr.getIntPropertyValue(RenderingRuleStorageProperties.TAG); + if(tag == -1){ + throw new SAXException("Attribute tag should be specified for root filter " + attrsMap.toString()); + } + int value = rr.getIntPropertyValue(RenderingRuleStorageProperties.VALUE); + if(value == -1){ + throw new SAXException("Attribute tag should be specified for root filter " + attrsMap.toString()); + } + int key = (tag << SHIFT_TAG_VAL) + value; + RenderingRule toInsert = rr; + RenderingRule previous = tagValueGlobalRules[state].get(key); + if(previous != null){ + if(previous.getProperties().length != 0){ + toInsert = new RenderingRule(Collections.EMPTY_MAP, RenderingRulesStorage.this); + toInsert.addIfElseChildren(previous); + } else { + toInsert = previous; + } + toInsert.addIfElseChildren(rr); + } + tagValueGlobalRules[state].put(key, toInsert); + } + + private class GroupRules { + Map groupAttributes = new LinkedHashMap(); + List children = new ArrayList(); + List childrenGroups = new ArrayList(); + + private void addGroupFilter(RenderingRule rr) { + for (RenderingRule ch : children) { + ch.addIfChildren(rr); + } + for(GroupRules gch : childrenGroups){ + gch.addGroupFilter(rr); + } + } + + public void registerGlobalRules(int state) throws SAXException { + for (RenderingRule ch : children) { + registerGlobalRule(ch, state, groupAttributes); + } + for(GroupRules gch : childrenGroups){ + gch.registerGlobalRules(state); + } + + } + } + + private class RenderingRulesHandler extends DefaultHandler { + private final SAXParser parser; + private int state; + + Stack stack = new Stack(); + + Map attrsMap = new LinkedHashMap(); + + + public RenderingRulesHandler(SAXParser parser){ + this.parser = parser; + } + + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { + name = parser.isNamespaceAware() ? localName : name; + boolean stateChanged = false; + if("filter".equals(name)){ //$NON-NLS-1$ + attrsMap.clear(); + if (stack.size() > 0 && stack.peek() instanceof GroupRules) { + GroupRules parent = ((GroupRules) stack.peek()); + attrsMap.putAll(parent.groupAttributes); + } + parseAttributes(attributes, attrsMap); + RenderingRule renderingRule = new RenderingRule(attrsMap, RenderingRulesStorage.this); + + if (stack.size() > 0 && stack.peek() instanceof GroupRules) { + GroupRules parent = ((GroupRules) stack.peek()); + parent.children.add(renderingRule); + } else if (stack.size() > 0 && stack.peek() instanceof RenderingRule) { + RenderingRule parent = ((RenderingRule) stack.peek()); + parent.addIfElseChildren(renderingRule); + } else { + registerGlobalRule(renderingRule, state, attrsMap); + } + stack.push(renderingRule); + } else if("groupFilter".equals(name)){ //$NON-NLS-1$ + attrsMap.clear(); + parseAttributes(attributes, attrsMap); + RenderingRule renderingRule = new RenderingRule(attrsMap, RenderingRulesStorage.this); + if (stack.size() > 0 && stack.peek() instanceof GroupRules) { + GroupRules parent = ((GroupRules) stack.peek()); + parent.addGroupFilter(renderingRule); + } else if (stack.size() > 0 && stack.peek() instanceof RenderingRule) { + ((RenderingRule) stack.peek()).addIfChildren(renderingRule); + } else { + throw new SAXException("Group filter without parent"); + } + stack.push(renderingRule); + } else if("group".equals(name)){ //$NON-NLS-1$ + GroupRules groupRules = new GroupRules(); + if (stack.size() > 0 && stack.peek() instanceof GroupRules) { + GroupRules parent = ((GroupRules) stack.peek()); + groupRules.groupAttributes.putAll(parent.groupAttributes); + parent.childrenGroups.add(groupRules); + } + parseAttributes(attributes, groupRules.groupAttributes); + stack.push(groupRules); + } else if("order".equals(name)){ //$NON-NLS-1$ + state = ORDER_RULES; + stateChanged = true; + } else if("text".equals(name)){ //$NON-NLS-1$ + state = TEXT_RULES; + stateChanged = true; + } else if("point".equals(name)){ //$NON-NLS-1$ + state = POINT_RULES; + stateChanged = true; + } else if("line".equals(name)){ //$NON-NLS-1$ + state = LINE_RULES; + stateChanged = true; + } else if("polygon".equals(name)){ //$NON-NLS-1$ + state = POLYGON_RULES; + stateChanged = true; + } else if("renderingProperty".equals(name)){ //$NON-NLS-1$ + String attr = attributes.getValue("attr"); + RenderingRuleProperty prop; + String type = attributes.getValue("type"); + if("boolean".equalsIgnoreCase(type)){ + prop = RenderingRuleProperty.createInputBooleanProperty(attr); + } else if("string".equalsIgnoreCase(type)){ + prop = RenderingRuleProperty.createInputStringProperty(attr); + } else { + prop = RenderingRuleProperty.createInputIntProperty(attr); + } + prop.setDescription(attributes.getValue("description")); + prop.setName(attributes.getValue("name")); + if(attributes.getValue("possibleValues") != null){ + prop.setPossibleValues(attributes.getValue("possibleValues").split(",")); + } + PROPS.registerRule(prop); + } else if("renderingStyle".equals(name)){ //$NON-NLS-1$ + String dc = attributes.getValue("defaultColor"); + int defaultColor = 0; + if(dc != null && dc.length() > 0){ + bgColor = RenderingRuleProperty.parseColor(dc); + } + String dnc = attributes.getValue("defaultNightColor"); + bgNightColor = defaultColor; + if(dnc != null && dnc.length() > 0){ + bgNightColor = RenderingRuleProperty.parseColor(dnc); + } + renderingName = attributes.getValue("name"); + depends = attributes.getValue("depends"); + } else if("renderer".equals(name)){ //$NON-NLS-1$ + throw new SAXException("Rendering style is deprecated and no longer supported."); + } else { + log.warn("Unknown tag : " + name); //$NON-NLS-1$ + } + + if(stateChanged){ + tagValueGlobalRules[state] = new TIntObjectHashMap(); + } + + } + + private Map parseAttributes(Attributes attributes, Map m) { + for (int i = 0; i < attributes.getLength(); i++) { + String name = parser.isNamespaceAware() ? attributes.getLocalName(i) : attributes.getQName(i); + m.put(name, attributes.getValue(i)); + } + return m; + } + + + @Override + public void endElement(String uri, String localName, String name) throws SAXException { + name = parser.isNamespaceAware() ? localName : name; + if ("filter".equals(name)) { //$NON-NLS-1$ + stack.pop(); + } else if("group".equals(name)){ //$NON-NLS-1$ + GroupRules group = (GroupRules) stack.pop(); + if (stack.size() == 0) { + group.registerGlobalRules(state); + } + } else if("groupFilter".equals(name)){ //$NON-NLS-1$ + stack.pop(); + } + } + + } + + public int getTagValueKey(String tag, String value){ + int itag = getDictionaryValue(tag); + int ivalue = getDictionaryValue(value); + return (itag << SHIFT_TAG_VAL) | ivalue; + } + + public String getValueString(int tagValueKey){ + return getStringValue(tagValueKey & ((1 << SHIFT_TAG_VAL) - 1)); + } + + public String getTagString(int tagValueKey){ + return getStringValue(tagValueKey >> SHIFT_TAG_VAL); + } + + protected RenderingRule getRule(int state, int itag, int ivalue){ + if(tagValueGlobalRules[state] != null){ + return tagValueGlobalRules[state].get((itag << SHIFT_TAG_VAL) | ivalue); + } + return null; + } + + + public void printDebug(int state, PrintStream out){ + for(int key : tagValueGlobalRules[state].keys()) { + RenderingRule rr = tagValueGlobalRules[state].get(key); + out.print("\n\n"+getTagString(key) + " : " + getValueString(key)); + printRenderingRule("", rr, out); + } + } + + private static void printRenderingRule(String indent, RenderingRule rr, PrintStream out){ + indent += " "; + out.print("\n"+indent); + for(RenderingRuleProperty p : rr.getProperties()){ + out.print(" " + p.getAttrName() + "= "); + if(p.isString()){ + out.print("\"" + rr.getStringPropertyValue(p.getAttrName()) + "\""); + } else if(p.isFloat()){ + out.print(rr.getFloatPropertyValue(p.getAttrName())); + } else if(p.isColor()){ + out.print(rr.getColorPropertyValue(p.getAttrName())); + } else if(p.isIntParse()){ + out.print(rr.getIntPropertyValue(p.getAttrName())); + } + } + for(RenderingRule rc : rr.getIfElseChildren()){ + printRenderingRule(indent, rc, out); + } + + } + + + public static void main(String[] args) throws SAXException, IOException { + RenderingRulesStorage storage = new RenderingRulesStorage(); + storage.parseRulesFromXmlInputStream(RenderingRulesStorage.class.getResourceAsStream("new_default.render.xml")); +// storage.printDebug(LINE_RULES, System.out); + long tm = System.nanoTime(); + int count = 100000; + for (int i = 0; i < count; i++) { + RenderingRuleSearchRequest searchRequest = new RenderingRuleSearchRequest(storage); + searchRequest.setStringFilter(storage.PROPS.R_TAG, "highway"); + searchRequest.setStringFilter(storage.PROPS.R_VALUE, "motorway"); + // searchRequest.setIntFilter(storage.PROPS.R_LAYER, 1); + searchRequest.setIntFilter(storage.PROPS.R_MINZOOM, 14); + searchRequest.setIntFilter(storage.PROPS.R_MAXZOOM, 14); + // searchRequest.setStringFilter(storage.PROPS.R_ORDER_TYPE, "line"); + // searchRequest.setBooleanFilter(storage.PROPS.R_NIGHT_MODE, true); + // searchRequest.setBooleanFilter(storage.PROPS.get("hmRendered"), true); + + searchRequest.search(ORDER_RULES); + printResult(searchRequest, new PrintStream(new OutputStream() { + @Override + public void write(int b) throws IOException { + + } + })); + } + System.out.println((System.nanoTime()- tm)/ (1e6f * count) ); + } + + private static void printResult(RenderingRuleSearchRequest searchRequest, PrintStream out) { + if(searchRequest.isFound()){ + out.print(" Found : "); + for (RenderingRuleProperty rp : searchRequest.getProperties()) { + if(rp.isOutputProperty() && searchRequest.isSpecified(rp)){ + out.print(" " + rp.getAttrName() + "= "); + if(rp.isString()){ + out.print("\"" + searchRequest.getStringPropertyValue(rp) + "\""); + } else if(rp.isFloat()){ + out.print(searchRequest.getFloatPropertyValue(rp)); + } else if(rp.isColor()){ + out.print(searchRequest.getColorStringPropertyValue(rp)); + } else if(rp.isIntParse()){ + out.print(searchRequest.getIntPropertyValue(rp)); + } + } + } + } else { + out.println("Not found"); + } + + } +} diff --git a/DataExtractionOSM/src/net/osmand/render/new_default.render.xml b/DataExtractionOSM/src/net/osmand/render/new_default.render.xml new file mode 100644 index 0000000000..3ebbbe2f0f --- /dev/null +++ b/DataExtractionOSM/src/net/osmand/render/new_default.render.xml @@ -0,0 +1,1362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 02609f20ee..7a44786ff8 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -1,5 +1,9 @@ + Vector rendering + Overlay/underlay + Raster map + Vector map About to delete Are you sure about deleting %1$s? Suburb diff --git a/OsmAnd/res/xml/settings_pref.xml b/OsmAnd/res/xml/settings_pref.xml index 1cc5d36692..c1b0cee004 100644 --- a/OsmAnd/res/xml/settings_pref.xml +++ b/OsmAnd/res/xml/settings_pref.xml @@ -5,27 +5,31 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -69,17 +73,17 @@ - - + + + - + - diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index ee79a8cfcb..01ff3d924b 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -15,9 +15,9 @@ import net.osmand.osm.LatLon; import net.osmand.plus.activities.ApplicationMode; import net.osmand.plus.activities.OsmandApplication; import net.osmand.plus.activities.search.SearchHistoryHelper; -import net.osmand.plus.render.BaseOsmandRender; import net.osmand.plus.render.RendererRegistry; import net.osmand.plus.routing.RouteProvider.RouteService; +import net.osmand.render.RenderingRulesStorage; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -143,7 +143,7 @@ public class OsmandSettings { } // update vector renderer RendererRegistry registry = ctx.getRendererRegistry(); - BaseOsmandRender newRenderer = registry.getRenderer(RENDERER.get()); + RenderingRulesStorage newRenderer = registry.getRenderer(RENDERER.get()); if (newRenderer == null) { newRenderer = registry.defaultRender(); } @@ -564,18 +564,6 @@ public class OsmandSettings { return USE_ENGLISH_NAMES.get(); } - // this value string is synchronized with settings_pref.xml preference name - public final OsmandPreference SHOW_MORE_MAP_DETAIL = new BooleanPreference("show_more_map_detail", false, true); - - // this value string is synchronized with settings_pref.xml preference name - public final CommonPreference USE_STEP_BY_STEP_RENDERING = new BooleanPreference("use_step_by_step_rendering", - true, false); - { - USE_STEP_BY_STEP_RENDERING.setModeDefaultValue(ApplicationMode.CAR, true); - USE_STEP_BY_STEP_RENDERING.setModeDefaultValue(ApplicationMode.BICYCLE, true); - USE_STEP_BY_STEP_RENDERING.setModeDefaultValue(ApplicationMode.PEDESTRIAN, true); - } - // this value string is synchronized with settings_pref.xml preference name public final CommonPreference MAP_VECTOR_DATA = new BooleanPreference("map_vector_data", false, true); @@ -1001,7 +989,7 @@ public class OsmandSettings { if(val == null){ val = RendererRegistry.DEFAULT_RENDER; } - BaseOsmandRender loaded = ctx.getRendererRegistry().getRenderer(val); + RenderingRulesStorage loaded = ctx.getRendererRegistry().getRenderer(val); if (loaded != null) { ctx.getRendererRegistry().setCurrentSelectedRender(loaded); super.setValue(prefs, val); @@ -1011,12 +999,20 @@ public class OsmandSettings { return false; }; }; - { - RENDERER.setModeDefaultValue(ApplicationMode.CAR, RendererRegistry.CAR_RENDER); - RENDERER.setModeDefaultValue(ApplicationMode.PEDESTRIAN, RendererRegistry.PEDESTRIAN_RENDER); - RENDERER.setModeDefaultValue(ApplicationMode.BICYCLE, RendererRegistry.BICYCLE_RENDER); - } + Map> customRendersProps = new LinkedHashMap>(); + public CommonPreference getCustomRenderProperty(String attrName){ + if(!customRendersProps.containsKey(attrName)){ + customRendersProps.put(attrName, new StringPreference("renderer_"+attrName, "", false)); + } + return customRendersProps.get(attrName); + } + { + CommonPreference pref = getCustomRenderProperty("appMode"); + pref.setModeDefaultValue(ApplicationMode.CAR, "car"); + pref.setModeDefaultValue(ApplicationMode.PEDESTRIAN, "pedestrian"); + pref.setModeDefaultValue(ApplicationMode.BICYCLE, "bicycle"); + } public final OsmandPreference VOICE_MUTE = new BooleanPreference("voice_mute", false, true); diff --git a/OsmAnd/src/net/osmand/plus/ResourceManager.java b/OsmAnd/src/net/osmand/plus/ResourceManager.java index 9865f295d7..63ac92edd2 100644 --- a/OsmAnd/src/net/osmand/plus/ResourceManager.java +++ b/OsmAnd/src/net/osmand/plus/ResourceManager.java @@ -36,8 +36,8 @@ import net.osmand.plus.AsyncLoadingThread.MapLoadRequest; import net.osmand.plus.AsyncLoadingThread.TileLoadDownloadRequest; import net.osmand.plus.AsyncLoadingThread.TransportLoadRequest; import net.osmand.plus.activities.OsmandApplication; -import net.osmand.plus.render.BaseOsmandRender; import net.osmand.plus.render.MapRenderRepositories; +import net.osmand.render.RenderingRulesStorage; import org.apache.commons.logging.Log; import org.xmlpull.v1.XmlPullParser; @@ -435,7 +435,7 @@ public class ResourceManager { context.getRendererRegistry().setExternalRenderers(externalRenderers); String r = context.getSettings().RENDERER.get(); if(r != null){ - BaseOsmandRender obj = context.getRendererRegistry().getRenderer(r); + RenderingRulesStorage obj = context.getRendererRegistry().getRenderer(r); if(obj != null){ context.getRendererRegistry().setCurrentSelectedRender(obj); } diff --git a/OsmAnd/src/net/osmand/plus/activities/SettingsActivity.java b/OsmAnd/src/net/osmand/plus/activities/SettingsActivity.java index f201c1b924..ab25f7e341 100644 --- a/OsmAnd/src/net/osmand/plus/activities/SettingsActivity.java +++ b/OsmAnd/src/net/osmand/plus/activities/SettingsActivity.java @@ -15,6 +15,7 @@ import net.osmand.map.TileSourceManager; import net.osmand.map.TileSourceManager.TileSourceTemplate; import net.osmand.plus.NavigationService; import net.osmand.plus.OsmandSettings; +import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.OsmandSettings.DayNightMode; import net.osmand.plus.OsmandSettings.MetricsConstants; import net.osmand.plus.OsmandSettings.OsmandPreference; @@ -22,8 +23,11 @@ import net.osmand.plus.ProgressDialogImplementation; import net.osmand.plus.R; import net.osmand.plus.ResourceManager; import net.osmand.plus.render.MapRenderRepositories; +import net.osmand.plus.render.RendererRegistry; import net.osmand.plus.routing.RouteProvider.RouteService; import net.osmand.plus.views.SeekBarPreference; +import net.osmand.render.RenderingRuleProperty; +import net.osmand.render.RenderingRulesStorage; import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -43,6 +47,7 @@ import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceCategory; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceActivity; @@ -160,12 +165,10 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference registerBooleanPreference(osmandSettings.USE_TRACKBALL_FOR_MOVEMENTS,screen); registerBooleanPreference(osmandSettings.USE_HIGH_RES_MAPS,screen); registerBooleanPreference(osmandSettings.USE_ENGLISH_NAMES,screen); - registerBooleanPreference(osmandSettings.SHOW_MORE_MAP_DETAIL,screen); registerBooleanPreference(osmandSettings.AUTO_ZOOM_MAP,screen); registerBooleanPreference(osmandSettings.AUTO_FOLLOW_ROUTE_NAV,screen); registerBooleanPreference(osmandSettings.SAVE_TRACK_TO_GPX,screen); registerBooleanPreference(osmandSettings.DEBUG_RENDERING_INFO,screen); - registerBooleanPreference(osmandSettings.USE_STEP_BY_STEP_RENDERING,screen); registerBooleanPreference(osmandSettings.FAST_ROUTE_MODE,screen); registerBooleanPreference(osmandSettings.USE_OSMAND_ROUTING_SERVICE_ALWAYS,screen); registerBooleanPreference(osmandSettings.USE_INTERNET_TO_DOWNLOAD_TILES,screen); @@ -284,6 +287,8 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference entries = (String[]) rendererNames.toArray(new String[rendererNames.size()]); registerListPreference(osmandSettings.RENDERER, screen, entries, entries); + createCustomRenderingProperties(); + tileSourcePreference = (ListPreference) screen.findPreference(osmandSettings.MAP_TILE_SOURCES.getId()); tileSourcePreference.setOnPreferenceChangeListener(this); overlayPreference = (ListPreference) screen.findPreference(osmandSettings.MAP_OVERLAY.getId()); @@ -304,6 +309,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference applicationDir.setOnPreferenceChangeListener(this); + broadcastReceiver = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { @@ -334,6 +340,35 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference } } + private void createCustomRenderingProperties() { + RenderingRulesStorage renderer = getMyApplication().getRendererRegistry().getCurrentSelectedRenderer(); + PreferenceCategory cat = (PreferenceCategory) findPreference("custom_vector_rendering"); + cat.removeAll(); + if(renderer != null){ + for(RenderingRuleProperty p : renderer.PROPS.getCustomRules()){ + CommonPreference custom = getMyApplication().getSettings().getCustomRenderProperty(p.getAttrName()); + ListPreference lp = new ListPreference(this); + lp.setOnPreferenceChangeListener(this); + lp.setKey(custom.getId()); + lp.setTitle(p.getName()); + lp.setSummary(p.getDescription()); + cat.addPreference(lp); + + + LinkedHashMap vals = new LinkedHashMap(); + screenPreferences.put(custom.getId(), lp); + listPreferences.put(custom.getId(), custom); + listPrefValues.put(custom.getId(), vals); + String[] names = p.getPossibleValues(); + for(int i=0; i depends = new ArrayList(); - public List dependRenderers = new ArrayList(); - private static final Log log = LogUtil.getLog(BaseOsmandRender.class); - - @SuppressWarnings("unchecked") - private Map>>[] rules = new LinkedHashMap[6]; - - - private int defaultColor; - private int defaultNightColor; - - - 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() { - } - - @Override - public void rendering(String name, String depends, int defaultColor, int defaultNightColor) { - this.name = name; - this.defaultColor = defaultColor; - this.defaultNightColor = defaultNightColor; - 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(boolean nightMode) { - int r = nightMode ? defaultNightColor : defaultColor ; - if (r == 0) { - for (BaseOsmandRender d : dependRenderers) { - r = d.getDefaultColor(nightMode); - 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>>(); - } - if (rules[state].get(filter.tag) == null) { - rules[state].put(filter.tag, new LinkedHashMap>()); - } - if (rules[state].get(filter.tag).get(filter.val) == null) { - rules[state].get(filter.tag).put(filter.val, new ArrayList(3)); - } - rules[state].get(filter.tag).get(filter.val).add(filter); - } - } - - public Integer getPointIcon(String tag, String val, int zoom, boolean nightMode) { - Integer i = getPointIconImpl(tag, val, zoom, nightMode); - if (i == null) { - i = getPointIconImpl(tag, null, zoom, nightMode); - } - if (i == null) { - for (BaseOsmandRender d : dependRenderers) { - i = d.getPointIcon(tag, val, zoom, nightMode); - 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 nightMode){ - boolean r = renderPolylineImpl(tag, val, zoom, rc, o, layer, nightMode); - if(!r){ - r = renderPolylineImpl(tag, null, zoom, rc, o, layer, nightMode); - } - if(!r){ - for(BaseOsmandRender d : dependRenderers){ - r = d.renderPolyline(tag, val, zoom, rc, o, layer, nightMode); - if (r) { - break; - } - } - } - return r; - } - public boolean renderPolygon(String tag, String val, int zoom, RenderingContext rc, OsmandRenderer o, boolean nightMode){ - boolean r = renderPolygonImpl(tag,val, zoom, rc, o, nightMode); - if(!r){ - r = renderPolygonImpl(tag, null, zoom, rc, o, nightMode); - } - if(!r){ - for(BaseOsmandRender d : dependRenderers){ - r = d.renderPolygon(tag, val, zoom, rc, o, nightMode); - if (r) { - break; - } - } - } - return r; - } - - public String renderObjectText(String name, String tag, String val, RenderingContext rc, boolean ref, boolean nightMode) { - if(name == null || name.length() == 0){ - return null; - } - String ret = renderObjectTextImpl(name, tag, val, rc, ref, nightMode); - if(ret == null){ - ret = renderObjectTextImpl(name, tag, null, rc, ref, nightMode); - } - if(ret == null){ - for(BaseOsmandRender d : dependRenderers){ - ret = d.renderObjectText(name, tag, val, rc, ref, nightMode); - if (ret != null) { - break; - } - } - } - - return ret; - } - - public boolean isObjectVisible(String tag, String val, int zoom, int type, boolean nightMode) { - if (type == 0) { - // replace multipolygon with polygon - type = 3; - } - if (isObjectVisibleImpl(tag, val, zoom, type, nightMode)) { - return true; - } - if (isObjectVisibleImpl(tag, null, zoom, type, nightMode)) { - return true; - } - for (BaseOsmandRender d : dependRenderers) { - if (d.isObjectVisible(tag, val, zoom, type, nightMode)) { - return true; - } - } - return false; - } - - - private boolean isObjectVisibleImpl(String tag, String val, int zoom, int type, boolean nightMode) { - FilterState fs = findBestFilterState(tag, val, zoom, nightMode, 0, null, 0, rules[type]); - return fs != null; - } - - private float getObjectOrderImpl(String tag, String val, int type, int layer) { - if (rules[OsmandRenderingRulesParser.ORDER_STATE] != null) { - Map> map = rules[OsmandRenderingRulesParser.ORDER_STATE].get(tag); - if (map != null) { - List list = map.get(val); - if (list != null) { - int sz = list.size(); - for (int i = 0; i < sz; i++) { - FilterState f = list.get(i); - if (f.orderType == type && f.layer == layer) { - return f.order; - } - } - } - } - } - return 0; - } - - - private Integer getPointIconImpl(String tag, String val, int zoom, boolean nightMode) { - FilterState fs = findBestFilterState(tag, val, zoom, nightMode, 0, null, 0, rules[OsmandRenderingRulesParser.POINT_STATE]); - if (fs != null) { - Integer i = RenderingIcons.getIcons().get(fs.icon); - return i == null ? 0 : i; - } - return null; - } - - private FilterState findBestFilterState(String tag, String val, int zoom, boolean nightMode, int layer, Boolean ref, - int nameLength, Map>> mapTag) { - if (mapTag != null) { - Map> map = mapTag.get(tag); - if (map != null) { - List list = map.get(val); - if (list != null) { - FilterState bestResult = null; - boolean prevDayNightMatches = false; - boolean prevLayerMatches = false; - int sz = list.size(); - for (int i = 0; i < sz; i++) { - FilterState f = list.get(i); - if (f.minzoom <= zoom && (zoom <= f.maxzoom || f.maxzoom == -1)) { - if(ref != null && !checkRefTextRule(f, ref.booleanValue())){ - continue; - } - if(f.textLength != nameLength){ - continue; - } - boolean dayNightMatches = (f.nightMode != null && f.nightMode.booleanValue() == nightMode) || - (!nightMode && f.nightMode == null); - boolean layerMatches = f.layer == layer; - boolean defLayerMatches = f.layer == 0; - if (dayNightMatches || !prevDayNightMatches){ - if(dayNightMatches && !prevDayNightMatches){ - if(layerMatches || defLayerMatches){ - prevDayNightMatches = true; - prevLayerMatches = false; - } - } - if(layerMatches){ - prevLayerMatches = true; - bestResult = f; - } else if(defLayerMatches && !prevLayerMatches){ - bestResult = f; - } - } - } - } - return bestResult; - } - } - } - return null; - } - - private boolean renderPolylineImpl(String tag, String val, int zoom, RenderingContext rc, OsmandRenderer o, int layer, boolean nightMode) { - FilterState found = findBestFilterState(tag, val, zoom, nightMode, layer, null, 0, rules[OsmandRenderingRulesParser.LINE_STATE]); - 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, boolean nightMode) { - FilterState f = findBestFilterState(tag, val, zoom, nightMode, 0, null, 0, rules[OsmandRenderingRulesParser.POLYGON_STATE]); - if (f != null) { - 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, boolean nightMode) { - FilterState fs = findBestFilterState(tag, val, rc.zoom, nightMode, 0, ref, name.length(), rules[OsmandRenderingRulesParser.TEXT_STATE]); - if(fs == null){ - fs = findBestFilterState(tag, val, rc.zoom, nightMode, 0, ref, 0, rules[OsmandRenderingRulesParser.TEXT_STATE]); - } - if(fs != null){ - fillTextProperties(fs, 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.textOrder = f.text.textOrder; - 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 getDepends() { - return depends; - } - - public void setDependRenderers(List dependRenderers) { - this.dependRenderers = dependRenderers; - } -} diff --git a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java index 7edba9a3cd..6697d7aab3 100644 --- a/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java +++ b/OsmAnd/src/net/osmand/plus/render/MapRenderRepositories.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import net.osmand.Algoritms; import net.osmand.IProgress; import net.osmand.LogUtil; import net.osmand.binary.BinaryMapDataObject; @@ -31,11 +32,14 @@ import net.osmand.osm.MapRenderingTypes; import net.osmand.osm.MapUtils; import net.osmand.osm.MultyPolygon; import net.osmand.plus.OsmandSettings; +import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.R; import net.osmand.plus.RotatedTileBox; import net.osmand.plus.activities.OsmandApplication; import net.osmand.plus.render.OsmandRenderer.RenderingContext; -import net.osmand.render.OsmandRenderingRulesParser; +import net.osmand.render.RenderingRuleProperty; +import net.osmand.render.RenderingRuleSearchRequest; +import net.osmand.render.RenderingRulesStorage; import org.apache.commons.logging.Log; @@ -48,7 +52,7 @@ import android.os.Looper; import android.widget.Toast; public class MapRenderRepositories { - + private final static Log log = LogUtil.getLog(MapRenderRepositories.class); private final Context context; private Handler handler; @@ -56,46 +60,45 @@ public class MapRenderRepositories { private OsmandRenderer renderer; private static String BASEMAP_NAME = "basemap"; - - - // lat/lon box of requested vector data + + // lat/lon box of requested vector data private RectF cObjectsBox = new RectF(); // cached objects in order to render rotation without reloading data from db private List cObjects = new LinkedList(); - + // currently rendered box (not the same as already rendered) - // this box is checked for interrupted process or + // this box is checked for interrupted process or private RotatedTileBox requestedBox = null; // location of rendered bitmap private RotatedTileBox prevBmpLocation = null; - // already rendered bitmap + // already rendered bitmap private Bitmap prevBmp; - + // location of rendered bitmap private RotatedTileBox bmpLocation = null; - // already rendered bitmap + // already rendered bitmap private Bitmap bmp; - + private boolean interrupted = false; private RenderingContext currentRenderingContext; private SearchRequest searchRequest; private OsmandSettings prefs; - public MapRenderRepositories(Context context){ + + public MapRenderRepositories(Context context) { this.context = context; this.renderer = new OsmandRenderer(context); handler = new Handler(Looper.getMainLooper()); prefs = OsmandSettings.getOsmandSettings(context); } - + public Context getContext() { return context; } - - + public BinaryMapIndexReader initializeNewResource(final IProgress progress, File file) { long start = System.currentTimeMillis(); - if(files.containsKey(file.getAbsolutePath())){ + if (files.containsKey(file.getAbsolutePath())) { closeConnection(files.get(file.getAbsolutePath()), file.getAbsolutePath()); } RandomAccessFile raf = null; @@ -103,14 +106,14 @@ public class MapRenderRepositories { try { raf = new RandomAccessFile(file, "r"); //$NON-NLS-1$ reader = new BinaryMapIndexReader(raf); - if(reader.getVersion() != IndexConstants.BINARY_MAP_VERSION){ + if (reader.getVersion() != IndexConstants.BINARY_MAP_VERSION) { return null; } files.put(file.getAbsolutePath(), reader); - + } catch (IOException e) { log.error("No connection or unsupported version", e); //$NON-NLS-1$ - if(raf != null){ + if (raf != null) { try { raf.close(); } catch (IOException e1) { @@ -118,7 +121,7 @@ public class MapRenderRepositories { } return null; } catch (OutOfMemoryError oome) { - if(raf != null){ + if (raf != null) { try { raf.close(); } catch (IOException e1) { @@ -131,16 +134,16 @@ public class MapRenderRepositories { } return reader; } - + public RotatedTileBox getBitmapLocation() { return bmpLocation; } - + public RotatedTileBox getPrevBmpLocation() { return prevBmpLocation; } - - protected void closeConnection(BinaryMapIndexReader c, String file){ + + protected void closeConnection(BinaryMapIndexReader c, String file) { files.remove(file); try { c.close(); @@ -148,7 +151,7 @@ public class MapRenderRepositories { e.printStackTrace(); } } - + public boolean containsLatLonMapData(double lat, double lon, int zoom) { int x = MapUtils.get31TileNumberX(lon); int y = MapUtils.get31TileNumberY(lat); @@ -159,61 +162,60 @@ public class MapRenderRepositories { } return false; } - - public void clearAllResources(){ + + public void clearAllResources() { clearCache(); - for(String f : new ArrayList(files.keySet())){ + for (String f : new ArrayList(files.keySet())) { closeConnection(files.get(f), f); } } - - public boolean updateMapIsNeeded(RotatedTileBox box){ + public boolean updateMapIsNeeded(RotatedTileBox box) { if (files.isEmpty() || box == null) { return false; } - if(requestedBox == null){ + if (requestedBox == null) { return true; } - if(requestedBox.getZoom() != box.getZoom()){ + if (requestedBox.getZoom() != box.getZoom()) { return true; } - + float deltaRotate = requestedBox.getRotate() - box.getRotate(); - if(deltaRotate > 180){ + if (deltaRotate > 180) { deltaRotate -= 360; - } else if(deltaRotate < -180){ + } else if (deltaRotate < -180) { deltaRotate += 360; } - if(Math.abs(deltaRotate) > 25){ + if (Math.abs(deltaRotate) > 25) { return true; } return !requestedBox.containsTileBox(box); } - public boolean isEmpty(){ + public boolean isEmpty() { return files.isEmpty(); } - - public void interruptLoadingMap(){ + + public void interruptLoadingMap() { interrupted = true; - if(currentRenderingContext != null){ + if (currentRenderingContext != null) { currentRenderingContext.interrupted = true; } - if(searchRequest != null){ + if (searchRequest != null) { searchRequest.setInterrupted(true); } } - - private boolean checkWhetherInterrupted(){ - if(interrupted || (currentRenderingContext != null && currentRenderingContext.interrupted)){ + + private boolean checkWhetherInterrupted() { + if (interrupted || (currentRenderingContext != null && currentRenderingContext.interrupted)) { requestedBox = bmpLocation; return true; } return false; } - - public boolean basemapExists(){ + + public boolean basemapExists() { for (String f : files.keySet()) { if (f.toLowerCase().contains(BASEMAP_NAME)) { return true; @@ -221,15 +223,15 @@ public class MapRenderRepositories { } return false; } - - private boolean loadVectorData(RectF dataBox, final int zoom, final BaseOsmandRender renderingType, final boolean nightMode){ + + private boolean loadVectorData(RectF dataBox, final int zoom, final RenderingRuleSearchRequest renderingReq, final boolean nightMode) { double cBottomLatitude = dataBox.bottom; double cTopLatitude = dataBox.top; double cLeftLongitude = dataBox.left; double cRightLongitude = dataBox.right; log.info(String.format("BLat=%s, TLat=%s, LLong=%s, RLong=%s, zoom=%s", //$NON-NLS-1$ - cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom)); + cBottomLatitude, cTopLatitude, cLeftLongitude, cRightLongitude, zoom)); long now = System.currentTimeMillis(); @@ -256,12 +258,21 @@ public class MapRenderRepositories { int type = types.get(j); int mask = type & 3; TagValuePair pair = root.decodeType(type); - if (pair != null && renderingType.isObjectVisible(pair.tag, pair.value, zoom, mask, nightMode)) { - return true; - } - if(pair != null && mask == OsmandRenderingRulesParser.POINT_STATE && - renderingType.isObjectVisible(pair.tag, pair.value, zoom, OsmandRenderingRulesParser.TEXT_STATE, nightMode)){ - return true; + if (pair != null) { + if(mask == MapRenderingTypes.MULTY_POLYGON_TYPE){ + mask = RenderingRulesStorage.POLYGON_RULES; + } + renderingReq.setInitialTagValueZoom(pair.tag, pair.value, zoom); + if (renderingReq.search(mask, false)) { + return true; + } + if (mask == RenderingRulesStorage.POINT_RULES) { + renderingReq.setInitialTagValueZoom(pair.tag, pair.value, zoom); + if (renderingReq.search(RenderingRulesStorage.TEXT_RULES, false)) { + return true; + } + + } } } return false; @@ -281,12 +292,12 @@ public class MapRenderRepositories { } } } - + for (String mapName : files.keySet()) { - if(basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)){ + if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) { continue; } - BinaryMapIndexReader c = files.get(mapName); + BinaryMapIndexReader c = files.get(mapName); searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter); List res = c.searchMapIndex(searchRequest); for (BinaryMapDataObject r : res) { @@ -298,13 +309,13 @@ public class MapRenderRepositories { ids.add(r.getId()); } count++; - - for(int i=0; i < r.getTypes().length; i++){ + + for (int i = 0; i < r.getTypes().length; i++) { if ((r.getTypes()[i] & 0x3) == MapRenderingTypes.MULTY_POLYGON_TYPE) { // multy polygon r.getId() >> 3 TagValuePair pair = r.getMapIndex().decodeType(MapRenderingTypes.getMainObjectType(r.getTypes()[i]), MapRenderingTypes.getObjectSubType(r.getTypes()[i])); - if(pair != null){ + if (pair != null) { pair = new TagValuePair(pair.tag, pair.value, r.getTypes()[i]); if (!multiPolygons.containsKey(pair)) { multiPolygons.put(pair, new ArrayList()); @@ -319,57 +330,76 @@ public class MapRenderRepositories { tempList.add(r); } } - + List pMulti = proccessMultiPolygons(multiPolygons, leftX, rightX, bottomY, topY, zoom); tempList.addAll(pMulti); log.info(String.format("Search done in %s ms. %s results were found.", System.currentTimeMillis() - now, count)); //$NON-NLS-1$ - + cObjects = tempList; cObjectsBox = dataBox; } catch (IOException e) { log.debug("Search failed", e); //$NON-NLS-1$ return false; } - + return true; } - - - private void validateLatLonBox(RectF box){ - if(box.top > 90){ + + private void validateLatLonBox(RectF box) { + if (box.top > 90) { box.top = 85.5f; } - if(box.bottom < -90){ + if (box.bottom < -90) { box.bottom = -85.5f; } - if(box.left <= -180){ + if (box.left <= -180) { box.left = -179.5f; } - if(box.right > 180){ + if (box.right > 180) { box.right = 180.0f; } } - + public synchronized void loadMap(RotatedTileBox tileRect, List notifyList) { interrupted = false; - if(currentRenderingContext != null){ + if (currentRenderingContext != null) { currentRenderingContext = null; } try { // find selected rendering type - OsmandApplication app = ((OsmandApplication)context.getApplicationContext()); + OsmandApplication app = ((OsmandApplication) context.getApplicationContext()); Boolean renderDay = app.getDaynightHelper().getDayNightRenderer(); boolean nightMode = renderDay != null && !renderDay.booleanValue(); // boolean moreDetail = prefs.SHOW_MORE_MAP_DETAIL.get(); - BaseOsmandRender renderingType = app.getRendererRegistry().getCurrentSelectedRenderer(); - + RenderingRulesStorage storage = app.getRendererRegistry().getCurrentSelectedRenderer(); + RenderingRuleSearchRequest renderingReq = new RenderingRuleSearchRequest(storage); + renderingReq.setBooleanFilter(renderingReq.ALL.R_NIGHT_MODE, nightMode); + for (RenderingRuleProperty customProp : storage.PROPS.getCustomRules()) { + CommonPreference settings = app.getSettings().getCustomRenderProperty(customProp.getAttrName()); + String res = settings.get(); + if (!Algoritms.isEmpty(res)) { + if (customProp.isString()) { + renderingReq.setStringFilter(customProp, res); + } else if (customProp.isBoolean()) { + renderingReq.setBooleanFilter(customProp, "true".equalsIgnoreCase(res)); + } else { + try { + renderingReq.setIntFilter(customProp, Integer.parseInt(res)); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + } + } + renderingReq.saveState(); + // prevent editing requestedBox = new RotatedTileBox(tileRect); // calculate data box RectF dataBox = requestedBox.calculateLatLonBox(new RectF()); long now = System.currentTimeMillis(); - + if (cObjectsBox.left > dataBox.left || cObjectsBox.top > dataBox.top || cObjectsBox.right < dataBox.right || cObjectsBox.bottom < dataBox.bottom) { // increase data box in order for rotate @@ -383,7 +413,7 @@ public class MapRenderRepositories { dataBox.bottom -= hi; } validateLatLonBox(dataBox); - boolean loaded = loadVectorData(dataBox, requestedBox.getZoom(), renderingType, nightMode); + boolean loaded = loadVectorData(dataBox, requestedBox.getZoom(), renderingReq, nightMode); if (!loaded || checkWhetherInterrupted()) { return; } @@ -405,45 +435,34 @@ public class MapRenderRepositories { } now = System.currentTimeMillis(); - - + Bitmap bmp = Bitmap.createBitmap(currentRenderingContext.width, currentRenderingContext.height, Config.RGB_565); - - boolean stepByStep = prefs.USE_STEP_BY_STEP_RENDERING.get(); + // 1. generate image step by step - if (stepByStep) { - this.prevBmp = this.bmp; - this.prevBmpLocation = this.bmpLocation; - this.bmp = bmp; - this.bmpLocation = tileRect; - } - - - - renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, - prefs.USE_ENGLISH_NAMES.get(), renderingType, stepByStep ? notifyList : null); + this.prevBmp = this.bmp; + this.prevBmpLocation = this.bmpLocation; + this.bmp = bmp; + this.bmpLocation = tileRect; + + renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq, + notifyList, storage.getBgColor(nightMode)); String renderingDebugInfo = currentRenderingContext.renderingDebugInfo; if (checkWhetherInterrupted()) { currentRenderingContext = null; return; } currentRenderingContext = null; - + // 2. replace whole image - if (!stepByStep) { - this.bmp = bmp; - this.bmpLocation = tileRect; - } else { - this.prevBmp = null; - this.prevBmpLocation = null; - } - if(prefs.DEBUG_RENDERING_INFO.get()){ - String timeInfo = "Search done in "+ searchTime+" ms"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - if(renderingDebugInfo != null){ - timeInfo += "\n"+renderingDebugInfo; + this.prevBmp = null; + this.prevBmpLocation = null; + if (prefs.DEBUG_RENDERING_INFO.get()) { + String timeInfo = "Search done in " + searchTime + " ms"; //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + if (renderingDebugInfo != null) { + timeInfo += "\n" + renderingDebugInfo; } final String msg = timeInfo; - handler.post(new Runnable(){ + handler.post(new Runnable() { @Override public void run() { Toast.makeText(context, msg, Toast.LENGTH_LONG).show(); @@ -452,7 +471,7 @@ public class MapRenderRepositories { } } catch (RuntimeException e) { log.error("Runtime memory exception", e); //$NON-NLS-1$ - handler.post(new Runnable(){ + handler.post(new Runnable() { @Override public void run() { Toast.makeText(context, R.string.rendering_exception, Toast.LENGTH_SHORT).show(); @@ -462,37 +481,36 @@ public class MapRenderRepositories { log.error("Out of memory error", e); //$NON-NLS-1$ cObjects = new ArrayList(); cObjectsBox = new RectF(); - handler.post(new Runnable(){ + handler.post(new Runnable() { @Override public void run() { Toast.makeText(context, R.string.rendering_out_of_memory, Toast.LENGTH_SHORT).show(); } }); - + } - + } - + public Bitmap getBitmap() { return bmp; } - + public Bitmap getPrevBitmap() { return prevBmp; } - - + public synchronized void clearCache() { cObjects = new ArrayList(); cObjectsBox = new RectF(); - prevBmp = bmp = null; + prevBmp = bmp = null; requestedBox = prevBmpLocation = bmpLocation = null; } - - /// Manipulating with multipolygons - - public List proccessMultiPolygons(Map> multyPolygons, int leftX, int rightX, int bottomY, int topY, int zoom){ + // / Manipulating with multipolygons + + public List proccessMultiPolygons(Map> multyPolygons, int leftX, int rightX, + int bottomY, int topY, int zoom) { List listPolygons = new ArrayList(multyPolygons.size()); List completedRings = new ArrayList(); List incompletedRings = new ArrayList(); @@ -501,7 +519,7 @@ public class MapRenderRepositories { for (TagValuePair type : multyPolygons.keySet()) { List directList; List inverselist; - if(((type.additionalAttribute >> 15) & 1) == 1){ + if (((type.additionalAttribute >> 15) & 1) == 1) { TagValuePair directType = new TagValuePair(type.tag, type.value, type.additionalAttribute & ((1 << 15) - 1)); if (!multyPolygons.containsKey(directType)) { inverselist = multyPolygons.get(type); @@ -522,11 +540,11 @@ public class MapRenderRepositories { incompletedRings.clear(); completedRingNames.clear(); incompletedRingNames.clear(); - log.debug("Process multypolygon " + type.tag + " " + type.value + //$NON-NLS-1$ //$NON-NLS-2$ - " direct list : " +directList + " rev : " + inverselist); //$NON-NLS-1$ //$NON-NLS-2$ - MultyPolygon pl = processMultiPolygon(leftX, rightX, bottomY, topY, listPolygons, completedRings, incompletedRings, - completedRingNames, incompletedRingNames, type, directList, inverselist, zoom); - if(pl != null){ + log.debug("Process multypolygon " + type.tag + " " + type.value + //$NON-NLS-1$ //$NON-NLS-2$ + " direct list : " + directList + " rev : " + inverselist); //$NON-NLS-1$ //$NON-NLS-2$ + MultyPolygon pl = processMultiPolygon(leftX, rightX, bottomY, topY, listPolygons, completedRings, incompletedRings, + completedRingNames, incompletedRingNames, type, directList, inverselist, zoom); + if (pl != null) { listPolygons.add(pl); } } @@ -534,8 +552,9 @@ public class MapRenderRepositories { } private MultyPolygon processMultiPolygon(int leftX, int rightX, int bottomY, int topY, List listPolygons, - List completedRings, List incompletedRings, List completedRingNames, List incompletedRingNames, - TagValuePair type, List directList, List inverselist, int zoom) { + List completedRings, List incompletedRings, List completedRingNames, + List incompletedRingNames, TagValuePair type, List directList, + List inverselist, int zoom) { MultyPolygon pl = new MultyPolygon(); // delete direction last bit (to not show point) pl.setTag(type.tag); @@ -551,7 +570,7 @@ public class MapRenderRepositories { } dbId = o.getId() >> 1; TLongList coordinates = new TLongArrayList(o.getPointsLength() / 2); - int px = o.getPoint31XTile(km == 0 ? 0 : len - 1); + int px = o.getPoint31XTile(km == 0 ? 0 : len - 1); int py = o.getPoint31YTile(km == 0 ? 0 : len - 1); int x = px; int y = py; @@ -564,9 +583,9 @@ public class MapRenderRepositories { y = o.getPoint31YTile(km == 0 ? i : len - i - 1); boolean inside = leftX <= x && x <= rightX && y >= topY && y <= bottomY; boolean lineEnded = calculateLineCoordinates(inside, x, y, pinside, px, py, leftX, rightX, bottomY, topY, coordinates); - if(lineEnded){ - processMultipolygonLine(completedRings, incompletedRings, completedRingNames, incompletedRingNames, - coordinates, o.getName()); + if (lineEnded) { + processMultipolygonLine(completedRings, incompletedRings, completedRingNames, incompletedRingNames, coordinates, + o.getName()); // create new line if it goes outside coordinates = new TLongArrayList(); } @@ -574,19 +593,19 @@ public class MapRenderRepositories { py = y; pinside = inside; } - processMultipolygonLine(completedRings, incompletedRings, completedRingNames, incompletedRingNames, - coordinates, o.getName()); + processMultipolygonLine(completedRings, incompletedRings, completedRingNames, incompletedRingNames, coordinates, + o.getName()); } } - if(completedRings.size() == 0 && incompletedRings.size() == 0){ + if (completedRings.size() == 0 && incompletedRings.size() == 0) { return null; } if (incompletedRings.size() > 0) { - unifyIncompletedRings(incompletedRings, completedRings, completedRingNames, incompletedRingNames, leftX, rightX, bottomY, topY, dbId, zoom); + unifyIncompletedRings(incompletedRings, completedRings, completedRingNames, incompletedRingNames, leftX, rightX, bottomY, topY, + dbId, zoom); } else { // due to self intersection small objects (for low zooms check only coastline) - if (zoom >= 13 - || ("natural".equals(type.tag) && "coastline".equals(type.value))) { //$NON-NLS-1$//$NON-NLS-2$ + if (zoom >= 13 || ("natural".equals(type.tag) && "coastline".equals(type.value))) { //$NON-NLS-1$//$NON-NLS-2$ boolean clockwiseFound = false; for (TLongList c : completedRings) { if (isClockwiseWay(c)) { @@ -607,7 +626,7 @@ public class MapRenderRepositories { } } - + long[][] lns = new long[completedRings.size()][]; for (int i = 0; i < completedRings.size(); i++) { TLongList ring = completedRings.get(i); @@ -620,30 +639,30 @@ public class MapRenderRepositories { pl.setLines(lns); return pl; } - + // Copied from MapAlgorithms - private boolean isClockwiseWay(TLongList c){ - if(c.size() == 0){ + private boolean isClockwiseWay(TLongList c) { + if (c.size() == 0) { return true; } // calculate middle Y int mask = 0xffffffff; long middleY = 0; - for(int i=0; i< c.size(); i++) { - middleY += (c.get(i) & mask); + for (int i = 0; i < c.size(); i++) { + middleY += (c.get(i) & mask); } middleY /= (long) c.size(); - + double clockwiseSum = 0; boolean firstDirectionUp = false; int previousX = Integer.MIN_VALUE; int firstX = Integer.MIN_VALUE; - + int prevX = (int) (c.get(0) >> 32); int prevY = (int) (c.get(0) & mask); - + for (int i = 1; i < c.size(); i++) { int x = (int) (c.get(i) >> 32); int y = (int) (c.get(i) & mask); @@ -670,24 +689,24 @@ public class MapRenderRepositories { prevY = y; } } - - if(firstX != -360){ + + if (firstX != -360) { boolean clockwise = (!firstDirectionUp) == (previousX < firstX); - if(clockwise){ + if (clockwise) { clockwiseSum += Math.abs(previousX - firstX); } else { clockwiseSum -= Math.abs(previousX - firstX); } } - + return clockwiseSum >= 0; } - + // Copied from MapAlgorithms private int ray_intersect_x(int prevX, int prevY, int x, int y, int middleY) { // prev node above line // x,y node below line - if(prevY > y){ + if (prevY > y) { int tx = prevX; int ty = prevY; x = prevX; @@ -712,7 +731,7 @@ public class MapRenderRepositories { } // NOT WORKING GOOD ! - private boolean isClockwiseWayOld(TLongList c){ + private boolean isClockwiseWayOld(TLongList c) { double angle = 0; double prevAng = 0; int px = 0; @@ -743,8 +762,7 @@ public class MapRenderRepositories { return angle < 0; } - - private void processMultipolygonLine(List completedRings, List incompletedRings, + private void processMultipolygonLine(List completedRings, List incompletedRings, List completedRingsNames, List incompletedRingsNames, TLongList coordinates, String name) { if (coordinates.size() > 0) { if (coordinates.get(0) == coordinates.get(coordinates.size() - 1)) { @@ -772,7 +790,7 @@ public class MapRenderRepositories { } if (coordinates.get(0) == coordinates.get(coordinates.size() - 1)) { completedRings.add(coordinates); - if(oldName != null){ + if (oldName != null) { completedRingsNames.add(oldName); } else { completedRingsNames.add(name); @@ -789,12 +807,11 @@ public class MapRenderRepositories { } } - private void unifyIncompletedRings(List incompletedRings, List completedRings, - List completedRingNames, List incompletedRingNames, - int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) { + private void unifyIncompletedRings(List incompletedRings, List completedRings, List completedRingNames, + List incompletedRingNames, int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) { int mask = 0xffffffff; Set nonvisitedRings = new LinkedHashSet(); - for(int j = 0; j< incompletedRings.size(); j++){ + for (int j = 0; j < incompletedRings.size(); j++) { TLongList i = incompletedRings.get(j); int x = (int) (i.get(i.size() - 1) >> 32); int y = (int) (i.get(i.size() - 1) & mask); @@ -812,34 +829,32 @@ public class MapRenderRepositories { float dy = (float) MapUtils.get31LatitudeY(y); float dsy = (float) MapUtils.get31LatitudeY(sy); String str; - if(!end){ + if (!end) { str = " Start point (to close) not found : end_x = {0}, end_y = {1}, start_x = {2}, start_y = {3} : bounds {4} {5} - {6} {7}"; //$NON-NLS-1$ - System.err.println( - MessageFormat.format(dbId + str, - dx, dy, dsx, dsy, leftX+"", topY+"", rightX+"", bottomY+"")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ + System.err + .println(MessageFormat.format(dbId + str, dx, dy, dsx, dsy, leftX + "", topY + "", rightX + "", bottomY + "")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ } - if(!st){ + if (!st) { str = " End not found : end_x = {0}, end_y = {1}, start_x = {2}, start_y = {3} : bounds {4} {5} - {6} {7}"; //$NON-NLS-1$ - System.err.println( - MessageFormat.format(dbId + str, - dx, dy, dsx, dsy, leftX+"", topY+"", rightX+"", bottomY+"")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ + System.err + .println(MessageFormat.format(dbId + str, dx, dy, dsx, dsy, leftX + "", topY + "", rightX + "", bottomY + "")); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$ } } else { nonvisitedRings.add(j); } } - for(int j = 0; j< incompletedRings.size(); j++){ + for (int j = 0; j < incompletedRings.size(); j++) { TLongList i = incompletedRings.get(j); String name = incompletedRingNames.get(j); - if(!nonvisitedRings.contains(j)){ + if (!nonvisitedRings.contains(j)) { continue; } - + int x = (int) (i.get(i.size() - 1) >> 32); int y = (int) (i.get(i.size() - 1) & mask); // 31 - (zoom + 8) - int EVAL_DELTA = 6 << (23 - zoom); - int UNDEFINED_MIN_DIFF = -1 - EVAL_DELTA; + int EVAL_DELTA = 6 << (23 - zoom); + int UNDEFINED_MIN_DIFF = -1 - EVAL_DELTA; while (true) { int st = 0; // st already checked to be one of the four if (y == topY) { @@ -863,7 +878,7 @@ public class MapRenderRepositories { int csy = (int) (cni.get(0) & mask); if (h % 4 == 0) { // top - if (csy == topY && csx >= safelyAddDelta(x, - EVAL_DELTA)) { + if (csy == topY && csx >= safelyAddDelta(x, -EVAL_DELTA)) { if (mindiff == UNDEFINED_MIN_DIFF || (csx - x) <= mindiff) { mindiff = (csx - x); nextRingIndex = ni; @@ -871,7 +886,7 @@ public class MapRenderRepositories { } } else if (h % 4 == 1) { // right - if (csx == rightX && csy >= safelyAddDelta(y, - EVAL_DELTA)) { + if (csx == rightX && csy >= safelyAddDelta(y, -EVAL_DELTA)) { if (mindiff == UNDEFINED_MIN_DIFF || (csy - y) <= mindiff) { mindiff = (csy - y); nextRingIndex = ni; @@ -934,28 +949,26 @@ public class MapRenderRepositories { y = (int) (i.get(i.size() - 1) & mask); } } - - + completedRings.add(i); completedRingNames.add(name); } } - - private int safelyAddDelta(int number, int delta){ + + private int safelyAddDelta(int number, int delta) { int res = number + delta; - if(delta > 0 && res < number){ + if (delta > 0 && res < number) { return Integer.MAX_VALUE; - } else if(delta < 0 && res > number){ + } else if (delta < 0 && res > number) { return Integer.MIN_VALUE; } return res; } - + /** * @return -1 if there is no instersection or x<<32 | y */ - private long calculateIntersection(int x, int y, int px, int py, int leftX, int rightX, - int bottomY, int topY){ + private long calculateIntersection(int x, int y, int px, int py, int leftX, int rightX, int bottomY, int topY) { int by = -1; int bx = -1; // firstly try to search if the line goes in @@ -993,7 +1006,7 @@ public class MapRenderRepositories { } } - + // try to search if point goes out if (py > topY && y <= topY) { int tx = (int) (px + ((double) (x - px) * (topY - py)) / (y - py)); @@ -1030,7 +1043,7 @@ public class MapRenderRepositories { } - if(px == rightX || px == leftX || py == topY || py == bottomY){ + if (px == rightX || px == leftX || py == topY || py == bottomY) { bx = px; by = py; } @@ -1054,11 +1067,11 @@ public class MapRenderRepositories { } } else { long is = calculateIntersection(x, y, px, py, leftX, rightX, bottomY, topY); - if(inside){ + if (inside) { // assert is != -1; coordinates.add(is); coordinates.add((((long) x) << 32) | ((long) y)); - } else if(is != -1){ + } else if (is != -1) { int bx = (int) (is >> 32); int by = (int) (is & 0xffffffff); coordinates.add(is); @@ -1067,11 +1080,10 @@ public class MapRenderRepositories { lineEnded = true; } } - + return lineEnded; } - public Map getMetaInfoFiles() { return files; } diff --git a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java index 06902166a5..08f6662f79 100644 --- a/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java +++ b/OsmAnd/src/net/osmand/plus/render/OsmandRenderer.java @@ -1,7 +1,7 @@ package net.osmand.plus.render; import gnu.trove.list.array.TIntArrayList; -import gnu.trove.map.hash.TFloatObjectHashMap; +import gnu.trove.map.hash.TIntObjectHashMap; import java.util.ArrayList; import java.util.Arrays; @@ -11,12 +11,16 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import net.osmand.Algoritms; import net.osmand.LogUtil; import net.osmand.binary.BinaryMapDataObject; import net.osmand.binary.BinaryMapIndexReader.TagValuePair; import net.osmand.data.MapTileDownloader.IMapDownloaderCallback; import net.osmand.osm.MapRenderingTypes; import net.osmand.osm.MultyPolygon; +import net.osmand.render.RenderingRuleProperty; +import net.osmand.render.RenderingRuleSearchRequest; +import net.osmand.render.RenderingRulesStorage; import net.sf.junidecode.Junidecode; import org.apache.commons.logging.Log; @@ -86,19 +90,22 @@ public class OsmandRenderer { int shieldRes = 0; int textOrder = 20; - public void fillProperties(RenderingContext rc, float centerX, float centerY){ - this.centerX = centerX + rc.textDx; - this.centerY = centerY + rc.textDy; - textColor = rc.textColor; - textSize = rc.textSize; - textShadow = (int) rc.textHaloRadius; - textWrap = rc.textWrapWidth; - bold = rc.textBold; - minDistance = rc.textMinDistance; - shieldRes = rc.textShield; - if(rc.textOrder >= 0){ - textOrder = rc.textOrder; + public void fillProperties(RenderingRuleSearchRequest render, float centerX, float centerY){ + this.centerX = centerX; + this.centerY = centerY + render.getIntPropertyValue(render.ALL.R_TEXT_DY, 0); + textColor = render.getIntPropertyValue(render.ALL.R_TEXT_COLOR); + if(textColor == 0){ + textColor = Color.BLACK; } + textSize = render.getIntPropertyValue(render.ALL.R_TEXT_SIZE); + textShadow = render.getIntPropertyValue(render.ALL.R_TEXT_HALO_RADIUS, 0); + textWrap = render.getIntPropertyValue(render.ALL.R_TEXT_WRAP_WIDTH, 0); + bold = render.getIntPropertyValue(render.ALL.R_TEXT_BOLD, 0) > 0; + minDistance = render.getIntPropertyValue(render.ALL.R_TEXT_MIN_DISTANCE,0); + if(render.isSpecified(render.ALL.R_TEXT_SHIELD)) { + shieldRes = RenderingIcons.getIcons().get(render.getStringPropertyValue(render.ALL.R_TEXT_SHIELD)); + } + textOrder = render.getIntPropertyValue(render.ALL.R_TEXT_ORDER, 20); } } @@ -137,94 +144,8 @@ public class OsmandRenderer { float cosRotateTileSize; float sinRotateTileSize; - // These properties are used for rendering one object - // polyline props - boolean showTextOnPath = false; - String showAnotherText = null; - float textSize = 0; - int textColor = 0; - int textMinDistance = 0; - int textWrapWidth = 0; - float textDx = 0; - float textDy = 0; - float textHaloRadius = 0; - boolean textBold; - int textShield = 0; - int textOrder = -1; - String renderingDebugInfo; - RenderingPaintProperties main = new RenderingPaintProperties(); - RenderingPaintProperties second = new RenderingPaintProperties(); - RenderingPaintProperties third = new RenderingPaintProperties(); - RenderingPaintProperties[] adds = null; - - - - public void clearText() { - showAnotherText = null; - showTextOnPath = false; - textSize = 0; - textColor = 0; - textOrder = -1; - textMinDistance = 0; - textWrapWidth = 0; - textDx = 0; - textDy = 0; - textHaloRadius = 0; - textBold = false; - textShield = 0; - } - - - } - - /* package*/ static class RenderingPaintProperties { - int color; - float strokeWidth; - int shadowLayer; - int shadowColor; - boolean fillArea; - PathEffect pathEffect; - Shader shader; - Cap cap; - - public void emptyLine(){ - color = 0; - strokeWidth = 0; - cap = Cap.BUTT; - pathEffect = null; - fillArea = false; - shader = null; - shadowColor = 0; - shadowLayer = 0; - } - - public void updatePaint(Paint p){ - p.setStyle(fillArea ? Style.FILL_AND_STROKE : Style.STROKE); - p.setColor(color); - p.setShader(shader); - if(shadowColor == 0){ - shadowLayer = 0; - } - p.setShadowLayer(shadowLayer, 0, 0, shadowColor); - p.setStrokeWidth(strokeWidth); - p.setStrokeCap(cap); - if (!fillArea) { - p.setPathEffect(pathEffect); - } - } - - public void emptyArea(){ - color = 0; - strokeWidth = 0; - cap = Cap.BUTT; - fillArea = false; - shader = null; - pathEffect = null; - shadowColor = 0; - shadowLayer = 0; - } } public OsmandRenderer(Context context) { @@ -273,7 +194,7 @@ public class OsmandRenderer { return shaders.get(resId); } - private void put(TFloatObjectHashMap map, Float k, int v, int init){ + private void put(TIntObjectHashMap map, int k, int v, int init){ if(!map.containsKey(k)){ map.put(k, new TIntArrayList()); } @@ -282,33 +203,33 @@ public class OsmandRenderer { public Bitmap generateNewBitmap(RenderingContext rc, List objects, Bitmap bmp, boolean useEnglishNames, - BaseOsmandRender renderer, List notifyList) { + RenderingRuleSearchRequest render, List notifyList, int defaultColor) { long now = System.currentTimeMillis(); // fill area Canvas cv = new Canvas(bmp); - if(renderer != null){ - int dc = renderer.getDefaultColor(rc.nightMode); - if(dc != 0){ - paintFillEmpty.setColor(dc); - } + if(defaultColor != 0){ + paintFillEmpty.setColor(defaultColor); } cv.drawRect(0, 0, bmp.getWidth(), bmp.getHeight(), paintFillEmpty); // put in order map int sz = objects.size(); int init = sz / 4; - TFloatObjectHashMap orderMap = new TFloatObjectHashMap(); - if (renderer != null) { + TIntObjectHashMap orderMap = new TIntObjectHashMap(); + if (render != null) { for (int i = 0; i < sz; i++) { BinaryMapDataObject o = objects.get(i); int sh = i << 8; if (o instanceof MultyPolygon) { - int mask = MapRenderingTypes.MULTY_POLYGON_TYPE; int layer = ((MultyPolygon) o).getLayer(); - put(orderMap, renderer.getObjectOrder(((MultyPolygon) o).getTag(), ((MultyPolygon) o).getValue(), - mask, layer), sh, init); + render.setInitialTagValueZoom(((MultyPolygon) o).getTag(), ((MultyPolygon) o).getValue(), rc.zoom); + render.setIntFilter(render.ALL.R_LAYER, layer); + render.setIntFilter(render.ALL.R_ORDER_TYPE, MapRenderingTypes.POLYGON_TYPE); + if(render.search(RenderingRulesStorage.ORDER_RULES)) { + put(orderMap, render.getIntPropertyValue(render.ALL.R_ORDER), sh, init); + } } else { for (int j = 0; j < o.getTypes().length; j++) { // put(orderMap, BinaryMapDataObject.getOrder(o.getTypes()[j]), sh + j, init); @@ -322,7 +243,12 @@ public class OsmandRenderer { TagValuePair pair = o.getMapIndex().decodeType(MapRenderingTypes.getMainObjectType(wholeType), MapRenderingTypes.getObjectSubType(wholeType)); if (pair != null) { - put(orderMap, renderer.getObjectOrder(pair.tag, pair.value, mask, layer), sh + j, init); + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.setIntFilter(render.ALL.R_LAYER, layer); + render.setIntFilter(render.ALL.R_ORDER_TYPE, mask); + if(render.search(RenderingRulesStorage.ORDER_RULES)) { + put(orderMap, render.getIntPropertyValue(render.ALL.R_ORDER), sh + j, init); + } } } @@ -341,7 +267,7 @@ public class OsmandRenderer { rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE; - float[] keys = orderMap.keys(); + int[] keys = orderMap.keys(); Arrays.sort(keys); int objCount = 0; for (int k = 0; k < keys.length; k++) { @@ -353,7 +279,7 @@ public class OsmandRenderer { BinaryMapDataObject obj = objects.get(ind); // show text only for main type - drawObj(obj, renderer, cv, rc, l, l == 0); + drawObj(obj, render, cv, rc, l, l == 0); objCount++; } @@ -647,10 +573,10 @@ public class OsmandRenderer { } - protected void drawObj(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, int l, boolean renderText) { + protected void drawObj(BinaryMapDataObject obj, RenderingRuleSearchRequest render, Canvas canvas, RenderingContext rc, int l, boolean renderText) { rc.allObjects++; if (obj instanceof MultyPolygon) { - drawMultiPolygon(obj, render,canvas, rc); + drawMultiPolygon(obj, render, canvas, rc); } else { int mainType = obj.getTypes()[l]; int t = mainType & 3; @@ -707,28 +633,20 @@ public class OsmandRenderer { return rc.tempPoint; } - - - - - public void clearCachedResources(){ cachedIcons.clear(); shaders.clear(); } - private void drawMultiPolygon(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc) { + private void drawMultiPolygon(BinaryMapDataObject obj, RenderingRuleSearchRequest render, Canvas canvas, RenderingContext rc) { String tag = ((MultyPolygon)obj).getTag(); String value = ((MultyPolygon)obj).getValue(); if(render == null || tag == null){ return; } - rc.main.emptyArea(); - rc.second.emptyLine(); - rc.main.color = Color.rgb(245, 245, 245); - - boolean rendered = render.renderPolygon(tag, value, rc.zoom, rc, this, rc.nightMode); - if(!rendered){ + render.setInitialTagValueZoom(tag, value, rc.zoom); + boolean rendered = render.search(RenderingRulesStorage.POLYGON_RULES); + if(!rendered || !updatePaint(render, paint, 0, true)){ return; } rc.visible++; @@ -754,21 +672,16 @@ public class OsmandRenderer { } } } - rc.main.updatePaint(paint); canvas.drawPath(path, paint); // for test purpose -// rc.second.strokeWidth = 1.5f; -// rc.second.color = Color.BLACK; - - if (rc.second.strokeWidth != 0) { - rc.second.updatePaint(paint); +// render.strokeWidth = 1.5f; +// render.color = Color.BLACK; + if (updatePaint(render, paint, 1, false)) { canvas.drawPath(path, paint); } } - - private void drawPolygon(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair) { - + private void drawPolygon(BinaryMapDataObject obj, RenderingRuleSearchRequest render, Canvas canvas, RenderingContext rc, TagValuePair pair) { if(render == null || pair == null){ return; } @@ -776,12 +689,11 @@ public class OsmandRenderer { float yText = 0; int zoom = rc.zoom; Path path = null; - rc.main.emptyArea(); - rc.second.emptyLine(); - // rc.main.color = Color.rgb(245, 245, 245); - boolean rendered = render.renderPolygon(pair.tag, pair.value, zoom, rc, this, rc.nightMode); - if(!rendered){ + // rc.main.color = Color.rgb(245, 245, 245); + render.setInitialTagValueZoom(pair.tag, pair.value, zoom); + boolean rendered = render.search(RenderingRulesStorage.POLYGON_RULES); + if(!rendered || !updatePaint(render, paint, 0, true)){ return; } rc.visible++; @@ -800,11 +712,8 @@ public class OsmandRenderer { } if (path != null && len > 0) { - - rc.main.updatePaint(paint); canvas.drawPath(path, paint); - if (rc.second.strokeWidth != 0) { - rc.second.updatePaint(paint); + if (updatePaint(render, paint, 1, false)) { canvas.drawPath(path, paint); } String name = obj.getName(); @@ -812,11 +721,81 @@ public class OsmandRenderer { drawPointText(render, rc, pair, xText / len, yText / len, name); } } - return; } + + private boolean updatePaint(RenderingRuleSearchRequest req, Paint p, int ind, boolean area){ + RenderingRuleProperty rColor; + RenderingRuleProperty rStrokeW; + RenderingRuleProperty rCap; + RenderingRuleProperty rPathEff; + if(ind == 0){ + rColor = req.ALL.R_COLOR; + rStrokeW = req.ALL.R_STROKE_WIDTH; + rCap = req.ALL.R_CAP; + rPathEff = req.ALL.R_PATH_EFFECT; + } else if(ind == 1){ + rColor = req.ALL.R_COLOR_2; + rStrokeW = req.ALL.R_STROKE_WIDTH_2; + rCap = req.ALL.R_CAP_2; + rPathEff = req.ALL.R_PATH_EFFECT_2; + } else { + rColor = req.ALL.R_COLOR_3; + rStrokeW = req.ALL.R_STROKE_WIDTH_3; + rCap = req.ALL.R_CAP_3; + rPathEff = req.ALL.R_PATH_EFFECT_3; + } + if(area){ + if(!req.isSpecified(rColor) && !req.isSpecified(req.ALL.R_SHADER)){ + return false; + } + p.setStyle(Style.FILL_AND_STROKE); + p.setStrokeWidth(0); + } else { + if(!req.isSpecified(rStrokeW)){ + return false; + } + p.setStyle(Style.STROKE); + p.setStrokeWidth(req.getFloatPropertyValue(rStrokeW)); + String cap = req.getStringPropertyValue(rCap); + if(!Algoritms.isEmpty(cap)){ + p.setStrokeCap(Cap.valueOf(cap.toUpperCase())); + } else { + p.setStrokeCap(Cap.BUTT); + } + String pathEffect = req.getStringPropertyValue(rPathEff); + if (!Algoritms.isEmpty(pathEffect)) { + p.setPathEffect(getDashEffect(pathEffect)); + } else { + p.setPathEffect(null); + } + } + p.setColor(req.getIntPropertyValue(rColor)); + + if(ind == 0){ + Integer resId = RenderingIcons.getIcons().get(req.getStringPropertyValue(req.ALL.R_SHADER)); + if(resId != null){ + p.setColor(Color.BLACK); + p.setShader(getShader(resId)); + } else { + p.setShader(null); + } + + int shadowColor = req.getIntPropertyValue(req.ALL.R_SHADOW_COLOR); + int shadowLayer = req.getIntPropertyValue(req.ALL.R_SHADOW_RADIUS); + if(shadowColor == 0){ + shadowLayer = 0; + } + p.setShadowLayer(shadowLayer, 0, 0, shadowColor); + } else { + p.setShader(null); + p.setShadowLayer(0, 0, 0, 0); + } + return true; + + } + - private void drawPointText(BaseOsmandRender render, RenderingContext rc, TagValuePair pair, float xText, float yText, String name) { - rc.clearText(); + private void drawPointText(RenderingRuleSearchRequest render, RenderingContext rc, TagValuePair pair, float xText, float yText, String name) { String ref = null; if (name.charAt(0) == MapRenderingTypes.REF_CHAR) { ref = name.substring(1); @@ -833,28 +812,39 @@ public class OsmandRenderer { } if (ref != null && ref.trim().length() > 0) { - rc.clearText(); - ref = render.renderObjectText(ref, pair.tag, pair.value, rc, true, rc.nightMode); - TextDrawInfo text = new TextDrawInfo(ref); - text.fillProperties(rc, xText, yText); - rc.textToDraw.add(text); + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.setIntFilter(render.ALL.R_TEXT_LENGTH, ref.length()); + render.setBooleanFilter(render.ALL.R_REF, true); + if(render.search(RenderingRulesStorage.TEXT_RULES)){ + if(render.getIntPropertyValue(render.ALL.R_TEXT_SIZE) > 0){ + TextDrawInfo text = new TextDrawInfo(ref); + text.fillProperties(render, xText, yText); + rc.textToDraw.add(text); + } + } } - name = render.renderObjectText(name, pair.tag, pair.value, rc, false, rc.nightMode); - if (rc.textSize > 0 && name != null) { - TextDrawInfo info = new TextDrawInfo(name); - info.fillProperties(rc, xText, yText); - rc.textToDraw.add(info); + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.setIntFilter(render.ALL.R_TEXT_LENGTH, name.length()); + render.setBooleanFilter(render.ALL.R_REF, false); + if(render.search(RenderingRulesStorage.TEXT_RULES) ){ + if(render.getIntPropertyValue(render.ALL.R_TEXT_SIZE) > 0){ + TextDrawInfo info = new TextDrawInfo(name); + info.fillProperties(render, xText, yText); + rc.textToDraw.add(info); + } } } - private void drawPoint(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair, boolean renderText) { + private void drawPoint(BinaryMapDataObject obj, RenderingRuleSearchRequest render, Canvas canvas, RenderingContext rc, TagValuePair pair, boolean renderText) { if(render == null || pair == null){ return; } + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.search(RenderingRulesStorage.POINT_RULES); - Integer resId = render.getPointIcon(pair.tag, pair.value, rc.zoom, rc.nightMode); + Integer resId = RenderingIcons.getIcons().get(render.getStringPropertyValue(render.ALL.R_ICON)); String name = null; if (renderText) { name = obj.getName(); @@ -890,7 +880,7 @@ public class OsmandRenderer { - private void drawPolyline(BinaryMapDataObject obj, BaseOsmandRender render, Canvas canvas, RenderingContext rc, TagValuePair pair, int layer) { + private void drawPolyline(BinaryMapDataObject obj, RenderingRuleSearchRequest render, Canvas canvas, RenderingContext rc, TagValuePair pair, int layer) { if(render == null || pair == null){ return; } @@ -898,16 +888,15 @@ public class OsmandRenderer { if(length < 2){ return; } - rc.main.emptyLine(); - rc.second.emptyLine(); - rc.third.emptyLine(); - rc.adds = null; - boolean res = render.renderPolyline(pair.tag, pair.value, rc.zoom, rc, this, layer, rc.nightMode); - if(rc.main.strokeWidth == 0 || !res){ + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.setIntFilter(render.ALL.R_LAYER, layer); + boolean rendered = render.search(RenderingRulesStorage.LINE_RULES); + if(!rendered || !updatePaint(render, paint, 0, false)){ return; } + boolean oneway = false; if(rc.zoom >= 16 && "highway".equals(pair.tag) && MapRenderingTypes.isOneWayWay(obj.getHighwayAttributes())){ //$NON-NLS-1$ - rc.adds = getOneWayProperties(); + oneway = true; } @@ -953,20 +942,17 @@ public class OsmandRenderer { yPrev = p.y; } if (path != null) { - rc.main.updatePaint(paint); canvas.drawPath(path, paint); - if (rc.second.strokeWidth != 0) { - rc.second.updatePaint(paint); + if (updatePaint(render, paint, 1, false)) { canvas.drawPath(path, paint); - if (rc.third.strokeWidth != 0) { - rc.third.updatePaint(paint); + if (updatePaint(render, paint, 2, false)) { canvas.drawPath(path, paint); } } - if (rc.adds != null) { - for (int i = 0; i < rc.adds.length; i++) { - rc.adds[i].updatePaint(paint); - canvas.drawPath(path, paint); + if(oneway){ + Paint[] paints = getOneWayPaints(); + for (int i = 0; i < paints.length; i++) { + canvas.drawPath(path, paints[i]); } } if (obj.getName() != null && obj.getName().length() > 0) { @@ -986,22 +972,28 @@ public class OsmandRenderer { } } if(ref != null && ref.trim().length() > 0){ - rc.clearText(); - ref = render.renderObjectText(ref, pair.tag, pair.value, rc, true, rc.nightMode); - TextDrawInfo text = new TextDrawInfo(ref); - text.fillProperties(rc, middlePoint.x, middlePoint.y); - text.pathRotate = pathRotate; - rc.textToDraw.add(text); + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.setIntFilter(render.ALL.R_TEXT_LENGTH, ref.length()); + render.setBooleanFilter(render.ALL.R_REF, true); + if(render.search(RenderingRulesStorage.TEXT_RULES)){ + if(render.getIntPropertyValue(render.ALL.R_TEXT_SIZE) > 0){ + TextDrawInfo text = new TextDrawInfo(ref); + text.fillProperties(render, middlePoint.x, middlePoint.y); + text.pathRotate = pathRotate; + rc.textToDraw.add(text); + } + } } if(name != null && name.trim().length() > 0){ - rc.clearText(); - name = render.renderObjectText(name, pair.tag, pair.value, rc, false, rc.nightMode); - if (rc.textSize > 0) { + render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom); + render.setIntFilter(render.ALL.R_TEXT_LENGTH, name.length()); + render.setBooleanFilter(render.ALL.R_REF, false); + if (render.search(RenderingRulesStorage.TEXT_RULES) && render.getIntPropertyValue(render.ALL.R_TEXT_SIZE) > 0) { TextDrawInfo text = new TextDrawInfo(name); - if (!rc.showTextOnPath) { - text.fillProperties(rc, middlePoint.x, middlePoint.y); + if (render.getIntPropertyValue(render.ALL.R_TEXT_ON_PATH, 0) == 0) { + text.fillProperties(render, middlePoint.x, middlePoint.y); rc.textToDraw.add(text); } else { paintText.setTextSize(text.textSize); @@ -1019,10 +1011,11 @@ public class OsmandRenderer { } } } - text.fillProperties(rc, xMid / 2, yMid / 2); + text.fillProperties(render, xMid / 2, yMid / 2); text.pathRotate = pathRotate; text.drawOnPath = path; - text.vOffset = rc.main.strokeWidth / 2 - 1; + float strokeWidth = render.getFloatPropertyValue(render.ALL.R_STROKE_WIDTH); + text.vOffset = strokeWidth / 2 - 1; rc.textToDraw.add(text); } } @@ -1032,38 +1025,37 @@ public class OsmandRenderer { } } } - private static RenderingPaintProperties[] oneWay = null; - public static RenderingPaintProperties[] getOneWayProperties(){ + private static Paint[] oneWay = null; + private static Paint oneWayPaint(){ + Paint oneWay = new Paint(); + oneWay.setStyle(Style.STROKE); + oneWay.setColor(0xff6c70d5); + oneWay.setAntiAlias(true); + return oneWay; + } + public static Paint[] getOneWayPaints(){ if(oneWay == null){ PathEffect arrowDashEffect1 = new DashPathEffect(new float[] { 0, 12, 10, 152 }, 0); PathEffect arrowDashEffect2 = new DashPathEffect(new float[] { 0, 12, 9, 153 }, 1); PathEffect arrowDashEffect3 = new DashPathEffect(new float[] { 0, 18, 2, 154 }, 1); PathEffect arrowDashEffect4 = new DashPathEffect(new float[] { 0, 18, 1, 155 }, 1); - oneWay = new RenderingPaintProperties[4]; - oneWay[0] = new RenderingPaintProperties(); - oneWay[0].emptyLine(); - oneWay[0].color = 0xff6c70d5; - oneWay[0].strokeWidth = 1; - oneWay[0].pathEffect = arrowDashEffect1; + oneWay = new Paint[4]; + oneWay[0] = oneWayPaint(); + oneWay[0].setStrokeWidth(1); + oneWay[0].setPathEffect(arrowDashEffect1); - oneWay[1] = new RenderingPaintProperties(); - oneWay[1].emptyLine(); - oneWay[1].color = 0xff6c70d5; - oneWay[1].strokeWidth = 2; - oneWay[1].pathEffect = arrowDashEffect2; + oneWay[1] = oneWayPaint(); + oneWay[1].setStrokeWidth(2); + oneWay[1].setPathEffect(arrowDashEffect2); + + oneWay[2] = oneWayPaint(); + oneWay[2].setStrokeWidth(3); + oneWay[2].setPathEffect(arrowDashEffect3); - oneWay[2] = new RenderingPaintProperties(); - oneWay[2].emptyLine(); - oneWay[2].color = 0xff6c70d5; - oneWay[2].strokeWidth = 3; - oneWay[2].pathEffect = arrowDashEffect3; + oneWay[3] = oneWayPaint(); + oneWay[3].setStrokeWidth(4); + oneWay[3].setPathEffect(arrowDashEffect4); - oneWay[3] = new RenderingPaintProperties(); - oneWay[3].emptyLine(); - oneWay[3].color = 0xff6c70d5; - oneWay[3].strokeWidth = 4; - oneWay[3].pathEffect = arrowDashEffect4; - } return oneWay; } diff --git a/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java b/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java index f40788e61a..859e1994bb 100644 --- a/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java +++ b/OsmAnd/src/net/osmand/plus/render/RendererRegistry.java @@ -4,16 +4,15 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Set; +import net.osmand.Algoritms; import net.osmand.LogUtil; -import net.osmand.render.OsmandRenderingRulesParser; +import net.osmand.render.RenderingRulesStorage; import org.apache.commons.logging.Log; import org.xml.sax.SAXException; @@ -24,72 +23,27 @@ public class RendererRegistry { private final static Log log = LogUtil.getLog(RendererRegistry.class); public final static String DEFAULT_RENDER = "default"; //$NON-NLS-1$ - public final static String CAR_RENDER = "car"; //$NON-NLS-1$ - public final static String BICYCLE_RENDER = "bicycle"; //$NON-NLS-1$ - public final static String PEDESTRIAN_RENDER = "pedestrian"; //$NON-NLS-1$ - - - public RendererRegistry(){ - internalRenderers.put(DEFAULT_RENDER, "default.render.xml"); //$NON-NLS-1$ - internalRenderers.put(CAR_RENDER, "car.render.xml"); //$NON-NLS-1$ - internalRenderers.put(BICYCLE_RENDER, "bicycle.render.xml"); //$NON-NLS-1$ - internalRenderers.put(PEDESTRIAN_RENDER, "pedestrian.render.xml"); //$NON-NLS-1$ - internalRenderers.put("all-purpose (more detail)", "all-purpose.render.xml"); //$NON-NLS-1$ - internalRenderers.put("bicycle (more detail)", "bicycle-all.render.xml"); //$NON-NLS-1$ - internalRenderers.put("pedestrian (more detail)", "pedestrian-all.render.xml"); //$NON-NLS-1$ - } - - private BaseOsmandRender defaultRender = null; - private BaseOsmandRender currentSelectedRender = null; + private RenderingRulesStorage defaultRender = null; + private RenderingRulesStorage currentSelectedRender = null; private Map externalRenderers = new LinkedHashMap(); private Map internalRenderers = new LinkedHashMap(); - private Map renderers = new LinkedHashMap(); + private Map renderers = new LinkedHashMap(); - public BaseOsmandRender defaultRender() { + public RendererRegistry(){ + internalRenderers.put(DEFAULT_RENDER, "new_default.render.xml"); + } + + public RenderingRulesStorage defaultRender() { if(defaultRender == null){ defaultRender = getRenderer(DEFAULT_RENDER); - if (defaultRender == null) { - try { - defaultRender = new BaseOsmandRender(); - defaultRender.init(OsmandRenderingRulesParser.class.getResourceAsStream("default.render.xml")); //$NON-NLS-1$ - } catch (IOException e) { - log.error("Exception initialize renderer", e); //$NON-NLS-1$ - } catch (SAXException e) { - log.error("Exception initialize renderer", e); //$NON-NLS-1$ - } - } } return defaultRender; } - - public BaseOsmandRender carRender() { - BaseOsmandRender renderer = getRenderer(CAR_RENDER); - if(renderer == null){ - return defaultRender(); - } - return renderer; - } - - public BaseOsmandRender bicycleRender() { - BaseOsmandRender renderer = getRenderer(BICYCLE_RENDER); - if(renderer == null){ - return defaultRender(); - } - return renderer; - } - - public BaseOsmandRender pedestrianRender() { - BaseOsmandRender renderer = getRenderer(PEDESTRIAN_RENDER); - if(renderer == null){ - return defaultRender(); - } - return renderer; - } - public BaseOsmandRender getRenderer(String name){ + public RenderingRulesStorage getRenderer(String name){ if(renderers.containsKey(name)){ return renderers.get(name); } @@ -103,7 +57,7 @@ public class RendererRegistry { return externalRenderers.containsKey(name) || internalRenderers.containsKey(name); } - private BaseOsmandRender getRenderer(String name, Set loadedRenderers) { + private RenderingRulesStorage getRenderer(String name, Set loadedRenderers) { try { return loadRenderer(name); } catch (IOException e) { @@ -114,38 +68,35 @@ public class RendererRegistry { return null; } - public BaseOsmandRender loadRenderer(String name) throws IOException, SAXException { + public RenderingRulesStorage loadRenderer(String name) throws IOException, SAXException { return loadRenderer(name, new LinkedHashSet()); } - private BaseOsmandRender loadRenderer(String name, Set loadedRenderers) throws IOException, SAXException { + private RenderingRulesStorage loadRenderer(String name, Set loadedRenderers) throws IOException, SAXException { InputStream is = null; if(externalRenderers.containsKey(name)){ is = new FileInputStream(externalRenderers.get(name)); } else if(internalRenderers.containsKey(name)){ - is = OsmandRenderingRulesParser.class.getResourceAsStream(internalRenderers.get(name)); + is = RenderingRulesStorage.class.getResourceAsStream(internalRenderers.get(name)); } else { throw new IllegalArgumentException("Not found " + name); //$NON-NLS-1$ } - BaseOsmandRender b = new BaseOsmandRender(); - b.init(is); + RenderingRulesStorage main = new RenderingRulesStorage(); + main.parseRulesFromXmlInputStream(is); loadedRenderers.add(name); - List dependencies = new ArrayList(); - for (String s : b.getDepends()) { - if (loadedRenderers.contains(s)) { + if(!Algoritms.isEmpty(main.getDepends())){ + if (loadedRenderers.contains(main.getDepends())) { log.warn("Circular dependencies found " + name); //$NON-NLS-1$ } else { - BaseOsmandRender dep = getRenderer(s, loadedRenderers); + RenderingRulesStorage dep = getRenderer(main.getDepends(), loadedRenderers); if (dep == null) { log.warn("Dependent renderer not found : " + name); //$NON-NLS-1$ - } else{ - dependencies.add(dep); } + main.setDependsStorage(dep); } } - b.setDependRenderers(dependencies); - renderers.put(name, b); - return b; + renderers.put(name, main); + return main; } @@ -161,14 +112,14 @@ public class RendererRegistry { return names; } - public BaseOsmandRender getCurrentSelectedRenderer() { + public RenderingRulesStorage getCurrentSelectedRenderer() { if(currentSelectedRender == null){ return defaultRender(); } return currentSelectedRender; } - public void setCurrentSelectedRender(BaseOsmandRender currentSelectedRender) { + public void setCurrentSelectedRender(RenderingRulesStorage currentSelectedRender) { this.currentSelectedRender = currentSelectedRender; }