Merge branch 'renderingAxes'

This commit is contained in:
Victor Shcherb 2011-10-20 11:29:26 +02:00
commit db0966450f
17 changed files with 3077 additions and 1504 deletions

View file

@ -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;

View file

@ -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<FilterState> filters = new ArrayList<FilterState>();
}
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> effectAttributes = new ArrayList<EffectAttributes>(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<Object> stack = new Stack<Object>();
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<FilterState> 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<FilterState> popAndAggregateState() {
FilterState pop = (FilterState) stack.pop();
List<FilterState> 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<FilterState> filters = ((SwitchState)o).filters;
if (res == null) {
res = new ArrayList<FilterState>();
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<toMerge.effectAttributes.size(); i++){
mergeStateInto(toMerge.effectAttributes.get(i), mergeInto.effectAttributes.get(i));
}
}
public void mergeStateInto(EffectAttributes toMerge, EffectAttributes mergeInto){
if(toMerge.color != 0 && mergeInto.color == 0){
mergeInto.color = toMerge.color;
}
if(toMerge.strokeWidth != 0 && mergeInto.strokeWidth == 0){
mergeInto.strokeWidth = toMerge.strokeWidth;
}
if(toMerge.pathEffect != null && mergeInto.pathEffect == null){
mergeInto.pathEffect = toMerge.pathEffect;
}
if(toMerge.shadowRadius != 0 && mergeInto.shadowRadius == 0){
mergeInto.shadowRadius = toMerge.shadowRadius;
}
if(toMerge.shadowColor != 0 && mergeInto.shadowColor == 0){
mergeInto.shadowColor = toMerge.shadowColor;
}
if(toMerge.cap != null && mergeInto.cap == null){
mergeInto.cap = toMerge.cap;
}
}
public FilterState parseFilterAttributes(Attributes attributes){
FilterState state = new FilterState();
if(this.state == TEXT_STATE){
state.text = new TextAttributes();
}
for(int i=0; i<attributes.getLength(); i++){
String name = attributes.getLocalName(i);
String val = attributes.getValue(i);
if(name.equals("tag")){ //$NON-NLS-1$
state.tag = val;
} else if(name.equals("value")){ //$NON-NLS-1$
state.val = val;
} else if(name.equals("minzoom")){ //$NON-NLS-1$
state.minzoom = Integer.parseInt(val);
} else if(name.equals("maxzoom")){ //$NON-NLS-1$
state.maxzoom = Integer.parseInt(val);
} else if(name.equals("maxzoom")){ //$NON-NLS-1$
state.maxzoom = Integer.parseInt(val);
} else if(name.equals("layer")){ //$NON-NLS-1$
state.layer = Integer.parseInt(val);
} else if(name.equals("orderType")){ //$NON-NLS-1$
int i1 = val.equals("polygon") ? 3 : (val.equals("line") ? 2 : 1); //$NON-NLS-1$ //$NON-NLS-2$
state.orderType = i1;
} else if(name.equals("order")){ //$NON-NLS-1$
state.order = Float.parseFloat(val);
} else if(name.equals("nightMode")){ //$NON-NLS-1$
state.nightMode = Boolean.parseBoolean(val);
} else if(name.equals("icon")){ //$NON-NLS-1$
state.icon = val;
} else if(name.equals("color")){ //$NON-NLS-1$
state.main.color = parseColor(val);
} else if(name.startsWith("color_")){ //$NON-NLS-1$
EffectAttributes ef = state.getEffectAttributes(Integer.parseInt(name.substring(6)));
ef.color = parseColor(val);
} else if(name.equals("shader")){ //$NON-NLS-1$
state.shader = val;
} else if(name.equals("strokeWidth")){ //$NON-NLS-1$
state.main.strokeWidth = Float.parseFloat(val);
} else if(name.startsWith("strokeWidth_")){ //$NON-NLS-1$
EffectAttributes ef = state.getEffectAttributes(Integer.parseInt(name.substring(12)));
ef.strokeWidth = Float.parseFloat(val);
} else if(name.equals("pathEffect")){ //$NON-NLS-1$
state.main.pathEffect = val;
} else if(name.startsWith("pathEffect_")){ //$NON-NLS-1$
EffectAttributes ef = state.getEffectAttributes(Integer.parseInt(name.substring(11)));
ef.pathEffect = val;
} else if(name.equals("shadowRadius")){ //$NON-NLS-1$
state.main.shadowRadius = Float.parseFloat(val);
} else if(name.startsWith("shadowRadius_")){ //$NON-NLS-1$
EffectAttributes ef = state.getEffectAttributes(Integer.parseInt(name.substring(14)));
ef.shadowRadius = Float.parseFloat(val);
} else if(name.equals("shadowColor")){ //$NON-NLS-1$
state.main.shadowColor = parseColor(val);
} else if(name.startsWith("shadowColor_")){ //$NON-NLS-1$
EffectAttributes ef = state.getEffectAttributes(Integer.parseInt(name.substring(12)));
ef.shadowColor = parseColor(val);
} else if(name.equals("cap")){ //$NON-NLS-1$
state.main.cap = val;
} else if(name.startsWith("cap_")){ //$NON-NLS-1$
EffectAttributes ef = state.getEffectAttributes(Integer.parseInt(name.substring(4)));
ef.cap = val;
} else if(name.equals("ref")){ //$NON-NLS-1$
state.text.ref = val;
} else if(name.equals("textSize")){ //$NON-NLS-1$
state.text.textSize = Float.parseFloat(val);
} else if(name.equals("textOrder")){ //$NON-NLS-1$
state.text.textOrder = Integer.parseInt(val);
} else if(name.equals("textBold")){ //$NON-NLS-1$
state.text.textBold = Boolean.parseBoolean(val);
} else if(name.equals("textColor")){ //$NON-NLS-1$
state.text.textColor = parseColor(val);
} else if(name.equals("textLength")){ //$NON-NLS-1$
state.textLength = Integer.parseInt(val);
} else if(name.equals("textShield")){ //$NON-NLS-1$
state.text.textShield = val;
} else if(name.equals("textMinDistance")){ //$NON-NLS-1$
state.text.textMinDistance = Integer.parseInt(val);
} else if(name.equals("textOnPath")){ //$NON-NLS-1$
state.text.textOnPath = Boolean.parseBoolean(val);
} else if(name.equals("textWrapWidth")){ //$NON-NLS-1$
state.text.textWrapWidth = Integer.parseInt(val);
} else if(name.equals("textDy")){ //$NON-NLS-1$
state.text.textDy = Integer.parseInt(val);
} else if(name.equals("textHaloRadius")){ //$NON-NLS-1$
state.text.textHaloRadius = Float.parseFloat(val);
} else {
log.warn("Unknown attribute " + name); //$NON-NLS-1$
}
}
return state;
}
}
/**
* 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$
}
// TEST purpose
public static void main(String[] args) throws IOException, SAXException {
OsmandRenderingRulesParser parser = new OsmandRenderingRulesParser();
parser.parseRenderingRules(OsmandRenderingRulesParser.class.getResourceAsStream("hm.render.xml"), //$NON-NLS-1$
new RenderingRuleVisitor() {
@Override
public void rendering(String name, String depends, int defColor, int defaultNightColor) {
System.out.println("Renderer " + name); //$NON-NLS-1$
}
@Override
public void visitRule(int state, FilterState filter) {
if(filter.nightMode != null){
System.out.println(filter.minzoom +" " +filter.tag + " " + filter.val);
}
String gen = generateAttributes(state, filter);
if (gen != null) {
String res = ""; //$NON-NLS-1$
if (filter.maxzoom != -1) {
res += " zoom : " +filter.minzoom + "-" + filter.maxzoom; //$NON-NLS-1$ //$NON-NLS-2$
} else {
res += " zoom : " +filter.minzoom; //$NON-NLS-1$
}
res += " tag="+filter.tag; //$NON-NLS-1$
res += " val="+filter.val; //$NON-NLS-1$
if(filter.layer != 0){
res += " layer="+filter.layer; //$NON-NLS-1$
}
res += gen;
System.out.println(res);
}
}
});
}
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$
}
}
private static String generateAttributes(int state, FilterState s){
String res = ""; //$NON-NLS-1$
if(s.shader != null){
res+=" shader=" + s.shader; //$NON-NLS-1$
}
if(s.icon != null){
res+= " icon="+s.icon; //$NON-NLS-1$
}
if(s.order != 0){
res+= " order="+s.order; //$NON-NLS-1$
}
if(s.orderType != 0){
res+= " orderType="+s.orderType; //$NON-NLS-1$
}
res = generateAttributes(s.main, res, ""); //$NON-NLS-1$
int p = 2;
for(EffectAttributes ef : s.effectAttributes){
res = generateAttributes(ef, res, "_"+(p++)); //$NON-NLS-1$
}
if(s.text != null){
if(s.text.textSize != 0){
res+= " textSize="+s.text.textSize; //$NON-NLS-1$
}
if(s.text.textOrder != 0){
res+= " textOrder="+s.text.textOrder; //$NON-NLS-1$
}
if(s.text.ref != null){
res+= " ref="+s.text.ref; //$NON-NLS-1$
}
if(s.text.textColor != 0){
res+= " textColor="+colorToString(s.text.textColor); //$NON-NLS-1$
}
if(s.text.textShield != null){
res+= " textShield="+s.text.textShield; //$NON-NLS-1$
}
}
if(state == POLYGON_STATE){
// return res;
} else if(state == LINE_STATE){
// return res;
} else if(state == POINT_STATE){
// return res;
} else if(state == TEXT_STATE){
// return res;
} else if(state == ORDER_STATE){
return res;
}
return null;
}
private static String generateAttributes(EffectAttributes s, String res, String prefix) {
if(s.color != 0){
res +=" color"+prefix+"="+colorToString(s.color); //$NON-NLS-1$ //$NON-NLS-2$
}
if(s.strokeWidth != 0){
res+= " strokeWidth"+prefix+"="+s.strokeWidth; //$NON-NLS-1$ //$NON-NLS-2$
}
if(s.pathEffect != null){
res+= " pathEffect"+prefix+"="+s.pathEffect; //$NON-NLS-1$ //$NON-NLS-2$
}
return res;
}
}

View file

@ -0,0 +1,132 @@
package net.osmand.render;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class RenderingRule {
private RenderingRuleProperty[] properties;
private int[] intProperties;
private float[] floatProperties;
private List<RenderingRule> ifElseChildren;
private List<RenderingRule> ifChildren;
private final RenderingRulesStorage storage;
public RenderingRule(Map<String, String> attributes, RenderingRulesStorage storage){
this.storage = storage;
process(attributes);
}
private void process(Map<String, String> attributes) {
ArrayList<RenderingRuleProperty> props = new ArrayList<RenderingRuleProperty>(attributes.size());
intProperties = new int[attributes.size()];
int i = 0;
Iterator<Entry<String, String>> it = attributes.entrySet().iterator();
while (it.hasNext()) {
Entry<String, String> e = it.next();
RenderingRuleProperty property = storage.PROPS.get(e.getKey());
if (property != null) {
props.add(property);
if (property.isString()) {
intProperties[i] = storage.getDictionaryValue(e.getValue());
} else if (property.isFloat()) {
if (floatProperties == null) {
// lazy creates
floatProperties = new float[attributes.size()];
}
floatProperties[i] = property.parseFloatValue(e.getValue());
} else {
intProperties[i] = property.parseIntValue(e.getValue());
}
i++;
}
}
properties = props.toArray(new RenderingRuleProperty[props.size()]);
}
private int getPropertyIndex(String property){
for (int i = 0; i < properties.length; i++) {
RenderingRuleProperty prop = properties[i];
if (prop.getAttrName().equals(property)) {
return i;
}
}
return -1;
}
public String getStringPropertyValue(String property) {
int i = getPropertyIndex(property);
if(i >= 0){
return storage.getStringValue(intProperties[i]);
}
return null;
}
public float getFloatPropertyValue(String property) {
int i = getPropertyIndex(property);
if(i >= 0){
return floatProperties[i];
}
return 0;
}
public String getColorPropertyValue(String property) {
int i = getPropertyIndex(property);
if(i >= 0){
return RenderingRuleProperty.colorToString(intProperties[i]);
}
return null;
}
public int getIntPropertyValue(String property) {
int i = getPropertyIndex(property);
if(i >= 0){
return intProperties[i];
}
return -1;
}
protected int getIntProp(int ind){
return intProperties[ind];
}
protected float getFloatProp(int ind){
return floatProperties[ind];
}
public RenderingRuleProperty[] getProperties() {
return properties;
}
@SuppressWarnings("unchecked")
public List<RenderingRule> getIfChildren() {
return ifChildren != null ? ifChildren : Collections.EMPTY_LIST ;
}
@SuppressWarnings("unchecked")
public List<RenderingRule> getIfElseChildren() {
return ifElseChildren != null ? ifElseChildren : Collections.EMPTY_LIST ;
}
public void addIfChildren(RenderingRule rr){
if(ifChildren == null){
ifChildren = new ArrayList<RenderingRule>();
}
ifChildren.add(rr);
}
public void addIfElseChildren(RenderingRule rr){
if(ifElseChildren == null){
ifElseChildren = new ArrayList<RenderingRule>();
}
ifElseChildren.add(rr);
}
}

View file

@ -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$
}
}
}

View file

@ -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;
}
}

View file

@ -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<String, RenderingRuleProperty> properties = new LinkedHashMap<String, RenderingRuleProperty>();
final List<RenderingRuleProperty> rules = new ArrayList<RenderingRuleProperty>();
final List<RenderingRuleProperty> customRules = new ArrayList<RenderingRuleProperty>();
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<RenderingRuleProperty> 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;
}
}

View file

@ -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<String> dictionary = new ArrayList<String>();
Map<String, Integer> dictionaryMap = new LinkedHashMap<String, Integer>();
public final RenderingRuleStorageProperties PROPS = new RenderingRuleStorageProperties();
@SuppressWarnings("unchecked")
protected TIntObjectHashMap<RenderingRule>[] 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<String, String> 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<String, String> groupAttributes = new LinkedHashMap<String, String>();
List<RenderingRule> children = new ArrayList<RenderingRule>();
List<GroupRules> childrenGroups = new ArrayList<GroupRules>();
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<Object> stack = new Stack<Object>();
Map<String, String> attrsMap = new LinkedHashMap<String, String>();
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<RenderingRule>();
}
}
private Map<String, String> parseAttributes(Attributes attributes, Map<String, String> 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");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
<string name="pref_vector_rendering">Vector rendering</string>
<string name="pref_overlay">Overlay/underlay</string>
<string name="pref_raster_map">Raster map</string>
<string name="pref_vector_map">Vector map</string>
<string name="delete_confirmation_title">About to delete</string>
<string name="delete_confirmation_msg">Are you sure about deleting %1$s?</string>
<string name="city_type_suburb">Suburb</string>

View file

@ -5,27 +5,31 @@
<PreferenceScreen android:key="map_settings" android:title="@string/rendering_settings" android:summary="@string/rendering_settings_descr">
<PreferenceCategory android:title="@string/pref_raster_map">
<ListPreference android:title="@string/map_tile_source" android:summary="@string/map_tile_source_descr" android:key="map_tile_sources"></ListPreference>
<CheckBoxPreference android:key="use_internet_to_download_tiles" android:title="@string/use_internet" android:summary="@string/use_internet_to_download_tile"></CheckBoxPreference>
<ListPreference android:title="@string/max_level_download_tile" android:summary="@string/max_level_download_tile_descr"
android:key="max_level_download_tile"></ListPreference>
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_vector_map">
<CheckBoxPreference android:summary="@string/map_vector_data_descr" android:title="@string/map_vector_data"
android:key="map_vector_data"></CheckBoxPreference>
<ListPreference android:title="@string/map_tile_source" android:summary="@string/map_tile_source_descr" android:key="map_tile_sources"></ListPreference>
<CheckBoxPreference android:summary="@string/use_english_names_descr" android:title="@string/use_english_names"
android:key="use_english_names"></CheckBoxPreference>
<CheckBoxPreference android:key="show_more_map_detail" android:title="@string/show_more_map_detail"
android:summary="@string/show_more_map_detail_descr"></CheckBoxPreference>
<ListPreference android:key="renderer" android:title="@string/renderers" android:summary="@string/renderers_descr"></ListPreference>
<ListPreference android:key="daynight_mode" android:title="@string/daynight" android:summary="@string/daynight_descr"></ListPreference>
<ListPreference android:title="@string/level_to_switch_vector_raster" android:summary="@string/level_to_switch_vector_raster_descr"
android:key="level_to_switch_vector_raster"></ListPreference>
<ListPreference android:key="map_text_size" android:title="@string/map_text_size" android:summary="@string/map_text_size_descr"/>
</PreferenceCategory>
<CheckBoxPreference android:key="use_high_res_maps" android:title="@string/use_high_res_maps" android:summary="@string/use_high_res_maps_descr"></CheckBoxPreference>
<PreferenceCategory android:title="@string/pref_overlay">
<ListPreference android:title="@string/map_overlay" android:summary="@string/map_overlay_descr" android:key="map_overlay"></ListPreference>
<net.osmand.plus.views.SeekBarPreference android:key="overlay_transparency" android:defaultValue="0" android:max="255"
android:dialogMessage="@string/modify_transparency" android:title="@string/overlay_transparency" android:summary="@string/overlay_transparency_descr"/>
<ListPreference android:title="@string/map_underlay" android:summary="@string/map_underlay_descr" android:key="map_underlay"></ListPreference>
<net.osmand.plus.views.SeekBarPreference android:key="map_transparency" android:defaultValue="0" android:max="255"
android:dialogMessage="@string/modify_transparency" android:title="@string/map_transparency" android:summary="@string/map_transparency_descr"/>
<CheckBoxPreference android:summary="@string/continuous_rendering_descr" android:title="@string/continuous_rendering"
android:key="use_step_by_step_rendering" />
<ListPreference android:key="map_text_size" android:title="@string/map_text_size" android:summary="@string/map_text_size_descr"/>
<CheckBoxPreference android:key="use_high_res_maps" android:title="@string/use_high_res_maps" android:summary="@string/use_high_res_maps_descr"></CheckBoxPreference>
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_vector_rendering" android:key="custom_vector_rendering">
</PreferenceCategory>
</PreferenceScreen>
@ -69,17 +73,17 @@
<PreferenceScreen android:key="general_settings" android:title="@string/general_settings" android:summary="@string/general_settings_descr">
<CheckBoxPreference android:key="use_internet_to_download_tiles" android:title="@string/use_internet" android:summary="@string/use_internet_to_download_tile"></CheckBoxPreference>
<ListPreference android:title="@string/max_level_download_tile" android:summary="@string/max_level_download_tile_descr"
android:key="max_level_download_tile"></ListPreference>
<CheckBoxPreference android:summary="@string/use_english_names_descr" android:title="@string/use_english_names"
android:key="use_english_names"></CheckBoxPreference>
<ListPreference android:key="map_screen_orientation" android:title="@string/map_screen_orientation" android:summary="@string/map_screen_orientation_descr"></ListPreference>
<ListPreference android:key="daynight_mode" android:title="@string/daynight" android:summary="@string/daynight_descr"></ListPreference>
<CheckBoxPreference android:title="@string/auto_zoom_map" android:summary="@string/auto_zoom_map_descr" android:key="auto_zoom_map"></CheckBoxPreference>
<CheckBoxPreference android:key="show_view_angle" android:title="@string/show_view_angle" android:summary="@string/show_view_angle_descr"></CheckBoxPreference>
<ListPreference android:key="rotate_map" android:title="@string/rotate_map_to_bearing" android:summary="@string/rotate_map_to_bearing_descr"></ListPreference>
<ListPreference android:key="map_screen_orientation" android:title="@string/map_screen_orientation" android:summary="@string/map_screen_orientation_descr"></ListPreference>
<ListPreference android:key="preferred_locale" android:title="@string/preferred_locale" android:summary="@string/preferred_locale_descr"></ListPreference>
<ListPreference android:key="default_metric_system" android:title="@string/unit_of_length" android:summary="@string/unit_of_length_descr"></ListPreference>
<ListPreference android:key="position_on_map" android:title="@string/position_on_map" android:summary="@string/position_on_map_descr"></ListPreference>
<CheckBoxPreference android:key="use_trackball_for_movements" android:title="@string/use_trackball" android:summary="@string/use_trackball_descr"></CheckBoxPreference>
<ListPreference android:key="preferred_locale" android:title="@string/preferred_locale" android:summary="@string/preferred_locale_descr"></ListPreference>
<EditTextPreference android:title="@string/application_dir" android:key="external_storage_dir"></EditTextPreference>
</PreferenceScreen>

View file

@ -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<Boolean> 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<Boolean> 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<Boolean> 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<String, CommonPreference<String>> customRendersProps = new LinkedHashMap<String, OsmandSettings.CommonPreference<String>>();
public CommonPreference<String> getCustomRenderProperty(String attrName){
if(!customRendersProps.containsKey(attrName)){
customRendersProps.put(attrName, new StringPreference("renderer_"+attrName, "", false));
}
return customRendersProps.get(attrName);
}
{
CommonPreference<String> pref = getCustomRenderProperty("appMode");
pref.setModeDefaultValue(ApplicationMode.CAR, "car");
pref.setModeDefaultValue(ApplicationMode.PEDESTRIAN, "pedestrian");
pref.setModeDefaultValue(ApplicationMode.BICYCLE, "bicycle");
}
public final OsmandPreference<Boolean> VOICE_MUTE = new BooleanPreference("voice_mute", false, true);

View file

@ -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);
}

View file

@ -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<String> 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<String, Object> vals = new LinkedHashMap<String, Object>();
screenPreferences.put(custom.getId(), lp);
listPreferences.put(custom.getId(), custom);
listPrefValues.put(custom.getId(), vals);
String[] names = p.getPossibleValues();
for(int i=0; i<names.length; i++){
vals.put(names[i], names[i]);
}
}
}
}
private void reloadVoiceListPreference(PreferenceScreen screen) {
String[] entries;
String[] entrieValues;
@ -516,6 +551,7 @@ public class SettingsActivity extends PreferenceActivity implements OnPreference
} else {
Toast.makeText(this, R.string.renderer_load_exception, Toast.LENGTH_SHORT).show();
}
createCustomRenderingProperties();
}
} else if(preference == applicationDir){
warnAboutChangingStorage((String) newValue);

View file

@ -1,414 +0,0 @@
package net.osmand.plus.render;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import net.osmand.LogUtil;
import net.osmand.plus.render.OsmandRenderer.RenderingContext;
import net.osmand.plus.render.OsmandRenderer.RenderingPaintProperties;
import net.osmand.render.OsmandRenderingRulesParser;
import net.osmand.render.OsmandRenderingRulesParser.EffectAttributes;
import net.osmand.render.OsmandRenderingRulesParser.FilterState;
import net.osmand.render.OsmandRenderingRulesParser.RenderingRuleVisitor;
import org.apache.commons.logging.Log;
import org.xml.sax.SAXException;
import android.graphics.Color;
import android.graphics.Paint.Cap;
public class BaseOsmandRender implements RenderingRuleVisitor {
public String name = "default"; //$NON-NLS-1$
public List<String> depends = new ArrayList<String>();
public List<BaseOsmandRender> dependRenderers = new ArrayList<BaseOsmandRender>();
private static final Log log = LogUtil.getLog(BaseOsmandRender.class);
@SuppressWarnings("unchecked")
private Map<String, Map<String, List<FilterState>>>[] rules = new LinkedHashMap[6];
private int defaultColor;
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<String, Map<String, List<FilterState>>>();
}
if (rules[state].get(filter.tag) == null) {
rules[state].put(filter.tag, new LinkedHashMap<String, List<FilterState>>());
}
if (rules[state].get(filter.tag).get(filter.val) == null) {
rules[state].get(filter.tag).put(filter.val, new ArrayList<FilterState>(3));
}
rules[state].get(filter.tag).get(filter.val).add(filter);
}
}
public Integer getPointIcon(String tag, String val, int zoom, 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<String, List<FilterState>> map = rules[OsmandRenderingRulesParser.ORDER_STATE].get(tag);
if (map != null) {
List<FilterState> 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<String, Map<String, List<FilterState>>> mapTag) {
if (mapTag != null) {
Map<String, List<FilterState>> map = mapTag.get(tag);
if (map != null) {
List<FilterState> 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<String> getDepends() {
return depends;
}
public void setDependRenderers(List<BaseOsmandRender> dependRenderers) {
this.dependRenderers = dependRenderers;
}
}

View file

@ -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;
@ -57,7 +61,6 @@ public class MapRenderRepositories {
private static String BASEMAP_NAME = "basemap";
// lat/lon box of requested vector data
private RectF cObjectsBox = new RectF();
// cached objects in order to render rotation without reloading data from db
@ -81,7 +84,8 @@ public class MapRenderRepositories {
private RenderingContext currentRenderingContext;
private SearchRequest<BinaryMapDataObject> 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());
@ -92,10 +96,9 @@ public class MapRenderRepositories {
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) {
@ -140,7 +143,7 @@ public class MapRenderRepositories {
return prevBmpLocation;
}
protected void closeConnection(BinaryMapIndexReader c, String file){
protected void closeConnection(BinaryMapIndexReader c, String file) {
files.remove(file);
try {
c.close();
@ -160,60 +163,59 @@ public class MapRenderRepositories {
return false;
}
public void clearAllResources(){
public void clearAllResources() {
clearCache();
for(String f : new ArrayList<String>(files.keySet())){
for (String f : new ArrayList<String>(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;
@ -222,7 +224,7 @@ 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;
@ -256,13 +258,22 @@ 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)) {
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(pair != null && mask == OsmandRenderingRulesParser.POINT_STATE &&
renderingType.isObjectVisible(pair.tag, pair.value, zoom, OsmandRenderingRulesParser.TEXT_STATE, nightMode)){
if (mask == RenderingRulesStorage.POINT_RULES) {
renderingReq.setInitialTagValueZoom(pair.tag, pair.value, zoom);
if (renderingReq.search(RenderingRulesStorage.TEXT_RULES, false)) {
return true;
}
}
}
}
return false;
}
@ -283,7 +294,7 @@ 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);
@ -299,12 +310,12 @@ public class MapRenderRepositories {
}
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<BinaryMapDataObject>());
@ -334,34 +345,53 @@ public class MapRenderRepositories {
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<IMapDownloaderCallback> 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<String> 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);
@ -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;
}
@ -406,22 +436,16 @@ 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);
renderer.generateNewBitmap(currentRenderingContext, cObjects, bmp, prefs.USE_ENGLISH_NAMES.get(), renderingReq,
notifyList, storage.getBgColor(nightMode));
String renderingDebugInfo = currentRenderingContext.renderingDebugInfo;
if (checkWhetherInterrupted()) {
currentRenderingContext = null;
@ -430,20 +454,15 @@ public class MapRenderRepositories {
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;
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,7 +481,7 @@ public class MapRenderRepositories {
log.error("Out of memory error", e); //$NON-NLS-1$
cObjects = new ArrayList<BinaryMapDataObject>();
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();
@ -481,7 +500,6 @@ public class MapRenderRepositories {
return prevBmp;
}
public synchronized void clearCache() {
cObjects = new ArrayList<BinaryMapDataObject>();
cObjectsBox = new RectF();
@ -489,10 +507,10 @@ public class MapRenderRepositories {
requestedBox = prevBmpLocation = bmpLocation = null;
}
// / Manipulating with multipolygons
/// Manipulating with multipolygons
public List<MultyPolygon> proccessMultiPolygons(Map<TagValuePair, List<BinaryMapDataObject>> multyPolygons, int leftX, int rightX, int bottomY, int topY, int zoom){
public List<MultyPolygon> proccessMultiPolygons(Map<TagValuePair, List<BinaryMapDataObject>> multyPolygons, int leftX, int rightX,
int bottomY, int topY, int zoom) {
List<MultyPolygon> listPolygons = new ArrayList<MultyPolygon>(multyPolygons.size());
List<TLongList> completedRings = new ArrayList<TLongList>();
List<TLongList> incompletedRings = new ArrayList<TLongList>();
@ -501,7 +519,7 @@ public class MapRenderRepositories {
for (TagValuePair type : multyPolygons.keySet()) {
List<BinaryMapDataObject> directList;
List<BinaryMapDataObject> 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);
@ -523,10 +541,10 @@ public class MapRenderRepositories {
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$
" 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){
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<MultyPolygon> listPolygons,
List<TLongList> completedRings, List<TLongList> incompletedRings, List<String> completedRingNames, List<String> incompletedRingNames,
TagValuePair type, List<BinaryMapDataObject> directList, List<BinaryMapDataObject> inverselist, int zoom) {
List<TLongList> completedRings, List<TLongList> incompletedRings, List<String> completedRingNames,
List<String> incompletedRingNames, TagValuePair type, List<BinaryMapDataObject> directList,
List<BinaryMapDataObject> inverselist, int zoom) {
MultyPolygon pl = new MultyPolygon();
// delete direction last bit (to not show point)
pl.setTag(type.tag);
@ -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)) {
@ -622,15 +641,15 @@ public class MapRenderRepositories {
}
// 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++) {
for (int i = 0; i < c.size(); i++) {
middleY += (c.get(i) & mask);
}
middleY /= (long) c.size();
@ -671,9 +690,9 @@ public class MapRenderRepositories {
}
}
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);
@ -687,7 +706,7 @@ public class MapRenderRepositories {
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,7 +762,6 @@ public class MapRenderRepositories {
return angle < 0;
}
private void processMultipolygonLine(List<TLongList> completedRings, List<TLongList> incompletedRings,
List<String> completedRingsNames, List<String> incompletedRingsNames, TLongList coordinates, String name) {
if (coordinates.size() > 0) {
@ -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<TLongList> incompletedRings, List<TLongList> completedRings,
List<String> completedRingNames, List<String> incompletedRingNames,
int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) {
private void unifyIncompletedRings(List<TLongList> incompletedRings, List<TLongList> completedRings, List<String> completedRingNames,
List<String> incompletedRingNames, int leftX, int rightX, int bottomY, int topY, long dbId, int zoom) {
int mask = 0xffffffff;
Set<Integer> nonvisitedRings = new LinkedHashSet<Integer>();
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,26 +829,24 @@ 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;
}
@ -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;
@ -935,17 +950,16 @@ public class MapRenderRepositories {
}
}
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;
@ -954,8 +968,7 @@ public class MapRenderRepositories {
/**
* @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
@ -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);
@ -1071,7 +1084,6 @@ public class MapRenderRepositories {
return lineEnded;
}
public Map<String, BinaryMapIndexReader> getMetaInfoFiles() {
return files;
}

View file

@ -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<TIntArrayList> map, Float k, int v, int init){
private void put(TIntObjectHashMap<TIntArrayList> 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<BinaryMapDataObject> objects, Bitmap bmp, boolean useEnglishNames,
BaseOsmandRender renderer, List<IMapDownloaderCallback> notifyList) {
RenderingRuleSearchRequest render, List<IMapDownloaderCallback> 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<TIntArrayList> orderMap = new TFloatObjectHashMap<TIntArrayList>();
if (renderer != null) {
TIntObjectHashMap<TIntArrayList> orderMap = new TIntObjectHashMap<TIntArrayList>();
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 void drawPointText(BaseOsmandRender render, RenderingContext rc, TagValuePair pair, float xText, float yText, String name) {
rc.clearText();
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(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);
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(rc, xText, yText);
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) {
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(rc, xText, yText);
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);
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(rc, middlePoint.x, middlePoint.y);
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,37 +1025,36 @@ 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] = new RenderingPaintProperties();
oneWay[2].emptyLine();
oneWay[2].color = 0xff6c70d5;
oneWay[2].strokeWidth = 3;
oneWay[2].pathEffect = arrowDashEffect3;
oneWay[2] = oneWayPaint();
oneWay[2].setStrokeWidth(3);
oneWay[2].setPathEffect(arrowDashEffect3);
oneWay[3] = new RenderingPaintProperties();
oneWay[3].emptyLine();
oneWay[3].color = 0xff6c70d5;
oneWay[3].strokeWidth = 4;
oneWay[3].pathEffect = arrowDashEffect4;
oneWay[3] = oneWayPaint();
oneWay[3].setStrokeWidth(4);
oneWay[3].setPathEffect(arrowDashEffect4);
}
return oneWay;

View file

@ -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<String, File> externalRenderers = new LinkedHashMap<String, File>();
private Map<String, String> internalRenderers = new LinkedHashMap<String, String>();
private Map<String, BaseOsmandRender> renderers = new LinkedHashMap<String, BaseOsmandRender>();
private Map<String, RenderingRulesStorage> renderers = new LinkedHashMap<String, RenderingRulesStorage>();
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<String> loadedRenderers) {
private RenderingRulesStorage getRenderer(String name, Set<String> 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<String>());
}
private BaseOsmandRender loadRenderer(String name, Set<String> loadedRenderers) throws IOException, SAXException {
private RenderingRulesStorage loadRenderer(String name, Set<String> 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<BaseOsmandRender> dependencies = new ArrayList<BaseOsmandRender>();
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;
}