Draft implementation

This commit is contained in:
Victor Shcherb 2011-10-19 14:50:16 +02:00
parent cfa7138ed0
commit 93098a731f
12 changed files with 550 additions and 1017 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

@ -15,8 +15,11 @@ public class RenderingRuleSearchRequest {
private List<RenderingRule> searchedScope = new ArrayList<RenderingRule>();
public final RenderingRuleStorageProperties ALL;
public RenderingRuleSearchRequest(RenderingRulesStorage storage) {
this.storage = storage;
this.ALL = storage.PROPS;
props = storage.PROPS.getPoperties();
values = new int[props.length];
for (int i = 0; i < props.length; i++) {
@ -55,6 +58,14 @@ public class RenderingRuleSearchRequest {
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 searchedScope.size() > 0;
}
@ -174,4 +185,9 @@ public class RenderingRuleSearchRequest {
return values[property.getId()];
}
public int getIntPropertyValue(RenderingRuleProperty property, int defValue) {
int val = values[property.getId()];
return val == -1 ? defValue : val;
}
}

View file

@ -94,12 +94,13 @@ public class RenderingRuleStorageProperties {
R_MAXZOOM = registerRule(RenderingRuleProperty.createInputLessIntProperty(MAXZOOM));
R_NIGHT_MODE = registerRule(RenderingRuleProperty.createInputBooleanProperty(NIGHT_MODE));
R_LAYER = registerRule(RenderingRuleProperty.createInputIntProperty(LAYER));
R_ORDER_TYPE = registerRule(RenderingRuleProperty.createInputStringProperty(ORDER_TYPE));
R_ORDER_TYPE = registerRule(RenderingRuleProperty.createInputIntProperty(ORDER_TYPE));
R_TEXT_LENGTH = registerRule(RenderingRuleProperty.createInputIntProperty(TEXT_LENGTH));
R_REF = registerRule(RenderingRuleProperty.createInputBooleanProperty(REF));
// order - no sense to make it float
R_ORDER = registerRule(RenderingRuleProperty.createOutputIntProperty(ORDER));
// text properties
R_TEXT_WRAP_WIDTH = registerRule(RenderingRuleProperty.createOutputIntProperty(TEXT_WRAP_WIDTH));
R_TEXT_DY = registerRule(RenderingRuleProperty.createOutputIntProperty(TEXT_DY));
@ -107,9 +108,8 @@ public class RenderingRuleStorageProperties {
R_TEXT_SIZE = registerRule(RenderingRuleProperty.createOutputIntProperty(TEXT_SIZE));
R_TEXT_ORDER = registerRule(RenderingRuleProperty.createOutputIntProperty(TEXT_ORDER));
R_TEXT_MIN_DISTANCE = registerRule(RenderingRuleProperty.createOutputIntProperty(TEXT_MIN_DISTANCE));
R_TEXT_LENGTH = registerRule(RenderingRuleProperty.createOutputIntProperty(TEXT_LENGTH));
R_TEXT_SHIELD = registerRule(RenderingRuleProperty.createOutputStringProperty(TEXT_SHIELD));
R_REF = registerRule(RenderingRuleProperty.createOutputStringProperty(REF));
R_TEXT_COLOR = registerRule(RenderingRuleProperty.createOutputColorProperty(TEXT_COLOR));

View file

@ -17,6 +17,7 @@ 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;
@ -27,9 +28,10 @@ public class RenderingRulesStorage {
private final static Log log = LogUtil.getLog(RenderingRulesStorage.class);
public final static int POINT_RULES = 1;
public final static int LINE_RULES = 2;
public final static int POLYGON_RULES = 3;
// 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;
@ -83,6 +85,10 @@ public class RenderingRulesStorage {
return bgNightColor;
}
public int getBgColor(boolean nightMode){
return nightMode ? bgNightColor : bgColor;
}
public String getDepends() {
return depends;
}
@ -107,6 +113,8 @@ public class RenderingRulesStorage {
@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());
@ -168,8 +176,6 @@ public class RenderingRulesStorage {
this.parser = parser;
}
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
name = parser.isNamespaceAware() ? localName : name;
@ -272,6 +278,12 @@ public class RenderingRulesStorage {
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
System.out.println(""+stack);
}
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);
@ -353,19 +365,19 @@ public class RenderingRulesStorage {
public static void main(String[] args) throws SAXException, IOException {
RenderingRulesStorage storage = new RenderingRulesStorage();
storage.parseRulesFromXmlInputStream(RenderingRulesStorage.class.getResourceAsStream("new_default.render.xml"));
// storage.printDebug(TEXT_RULES, System.out);
// storage.printDebug(POLYGON_RULES, System.out);
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.setStringFilter(storage.PROPS.R_TAG, "landuse");
searchRequest.setStringFilter(storage.PROPS.R_VALUE, "grass");
// searchRequest.setIntFilter(storage.PROPS.R_LAYER, 1);
searchRequest.setIntFilter(storage.PROPS.R_MINZOOM, 17);
searchRequest.setIntFilter(storage.PROPS.R_MAXZOOM, 17);
// 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(LINE_RULES);
searchRequest.search(POLYGON_RULES);
printResult(searchRequest, System.out);
}

View file

@ -54,11 +54,14 @@
<!-- types : string, int, boolean; possibleValues comma separated possible values for int/string -->
<renderingProperty attr="hmRendered" name="All-Purpose Renderer" description="All-Purpose Renderer by Hardy"
type="boolean" possibleValues=""/>
<renderingProperty attr="appMode" name="Rendering mode" description="Select rendering specific mode"
type="string" possibleValues=",car,bicycle,pedestrian"/>
<!-- input exact layer, orderType check tag, value -->
<!-- point = 1, line = 2, polygon = 3 -->
<order>
<!-- point has order 128 -->
<group orderType="polygon">
<group orderType="3">
<filter tag="building" value="" order="64" />
<filter tag="building" value="" layer="-1" order="2" />
@ -79,7 +82,7 @@
</group>
<group orderType="line">
<group orderType="2">
<!-- Below see level -->
<filter tag="admin_level" value="0" order="0" />
<filter tag="admin_level" value="1" order="0" />
@ -120,14 +123,14 @@
<filter tag="highway" value="bridleway" order="35" />
</group>
<filter tag="" value="" order="128" orderType="point"/>
<filter tag="" value="" layer="-1" order="1" orderType="polygon"/>
<filter tag="" value="" layer="1" order="64" orderType="polygon"/>
<filter tag="" value="" order="1" orderType="polygon"/>
<filter tag="" value="" order="128" orderType="1"/>
<filter tag="" value="" layer="-1" order="1" orderType="3"/>
<filter tag="" value="" layer="1" order="64" orderType="3"/>
<filter tag="" value="" order="1" orderType="3"/>
<filter tag="" value="" layer="-1" order="10" orderType="line"/>
<filter tag="" value="" layer="1" order="67" orderType="line"/>
<filter tag="" value="" order="11" orderType="line"/>
<filter tag="" value="" layer="-1" order="10" orderType="2"/>
<filter tag="" value="" layer="1" order="67" orderType="2"/>
<filter tag="" value="" order="11" orderType="2"/>
</order>
@ -135,7 +138,7 @@
<!-- PRIORITY Input to filter : tag, value, zoom [minzoom, maxzoom], textLength, ref, textOrder (default=20) -->
<text>
<!-- Highway ref -->
<filter minzoom="10" tag="highway" value="motorway" ref="only" textMinDistance="70" textColor="#ffffff" textSize="12" textBold="true"
<filter minzoom="10" tag="highway" value="motorway" ref="true" textMinDistance="70" textColor="#ffffff" textSize="12" textBold="true"
textOrder="6">
<filter textLength="1" textShield="mot_shield1" />
<filter textLength="2" textShield="mot_shield2" />
@ -145,7 +148,7 @@
<filter textLength="6" textShield="mot_shield6" />
</filter>
<filter minzoom="10" tag="highway" value="trunk" ref="only" textMinDistance="70" textColor="#ffffff" textSize="12" textBold="true"
<filter minzoom="10" tag="highway" value="trunk" ref="true" textMinDistance="70" textColor="#ffffff" textSize="12" textBold="true"
textOrder="6">
<filter textLength="1" textShield="tru_shield1" />
<filter textLength="2" textShield="tru_shield2" />
@ -155,7 +158,7 @@
<filter textLength="6" textShield="tru_shield6" />
</filter>
<filter minzoom="11" tag="highway" value="primary" ref="only" textMinDistance="70" textColor="#ffffff" textSize="12"
<filter minzoom="11" tag="highway" value="primary" ref="true" textMinDistance="70" textColor="#ffffff" textSize="12"
textBold="true" textOrder="7">
<filter textLength="1" textShield="pri_shield1" />
<filter textLength="2" textShield="pri_shield2" />
@ -165,7 +168,7 @@
<filter textLength="6" textShield="pri_shield6" />
</filter>
<filter minzoom="13" tag="highway" value="secondary" ref="only" textMinDistance="70" textColor="#ffffff" textSize="12"
<filter minzoom="13" tag="highway" value="secondary" ref="true" textMinDistance="70" textColor="#ffffff" textSize="12"
textBold="true" textOrder="8">
<filter textLength="1" textShield="sec_shield1" />
<filter textLength="2" textShield="sec_shield2" />
@ -175,7 +178,7 @@
<filter textLength="6" textShield="sec_shield6" />
</filter>
<filter minzoom="14" tag="highway" value="tertiary" ref="only" textMinDistance="70" textColor="#ffffff" textSize="12"
<filter minzoom="14" tag="highway" value="tertiary" ref="true" textMinDistance="70" textColor="#ffffff" textSize="12"
textBold="true" textOrder="9">
<filter textLength="1" textShield="ter_shield1" />
<filter textLength="2" textShield="ter_shield2" />
@ -638,11 +641,12 @@
</groupFilter>
</group>
<!-- ZM 13 -->
<group minzoom="14" strokeWidth_2="0.5" color_2="#b0b0b0" color="#ECECEC">
<group >
<filter tag="highway" value="service" />
<filter tag="highway" value="pedestrian" />
<filter tag="highway" value="footway" />
<groupFilter minzoom="14" strokeWidth_2="0.5" color_2="#b0b0b0" color="#ECECEC"/>
<groupFilter hmRendered="true" minzoom="13" strokeWidth_2="0.5" color_2="#b0b0b0" color="#ECECEC"/>
</group>
<filter minzoom="11" tag="railway" value="station" color="#d4aaaa">
@ -753,7 +757,7 @@
<!-- ZM 10 -->
<filter minzoom="9" shader="nr" color="#abdf96" tag="leisure" value="nature_reserve">
<filter nightMode="true" shader="" color="#000034">
<filter nightMode="true" shader="" color="#000034" />
</filter>
<group>
@ -889,8 +893,8 @@
</group>
<filter minzoom="10" color="#a0ffa8a8" tag="landuse" value="military" />
<filter nightMode="true" color="#a0560000" >
<filter minzoom="10" color="#a0ffa8a8" tag="landuse" value="military">
<filter nightMode="true" color="#a0560000" />
</filter>
@ -901,7 +905,7 @@
</filter>
<filter tag="landuse" value="wood" />
<filter tag="landuse" value="wood">
<filter hmRendered="true">
<filter minzoom="10" color="#aed1a0" />
</filter>
@ -980,117 +984,92 @@
</groupFilter>
</group>
<!-- TODO START ->
<group>
<filter tag="highway" value="tertiary" maxzoom="13" />
<filter tag="highway" value="tertiary_link" maxzoom="13" />
<filter color="#fefeb3" color_2="#fefeb3" shadowColor="#bababa" shadowRadius="1" >
<groupFilter color="#fefeb3" color_2="#fefeb3" shadowColor="#bababa">
<filter minzoom="10" maxzoom="10" strokeWidth="3" />
<filter minzoom="11" maxzoom="11" strokeWidth="4" />
<filter minzoom="12" maxzoom="12" strokeWidth="5" />
<filter minzoom="13" maxzoom="13" strokeWidth="6" />
<switch>
<case layer="-1" pathEffect="4_4" />
<case /> <!- all other cases ->
<filter>
<filter minzoom="14" maxzoom="14" strokeWidth="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="10" />
<!- radius 0 to avoid showing many black lines, but removed again due to bad visibility on some backgrounds ->
<filter minzoom="17" maxzoom="17" strokeWidth="13" />
<filter minzoom="18" strokeWidth="18" />
</filter>
</switch>
<!- bridge ->
<switch>
<case nightMode="false" color="#000000" />
<case nightMode="true" color="#ffffff" />
<filter layer="1" cap_2="SQUARE" >
<filter minzoom="13" maxzoom="14" strokeWidth="8" strokeWidth_2="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="10" strokeWidth_2="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="12" strokeWidth_2="10" />
<filter minzoom="17" maxzoom="17" strokeWidth="15" strokeWidth_2="13" />
<filter minzoom="18" strokeWidth="20" strokeWidth_2="18" />
</filter>
</switch>
</filter>
</group>
<switch>
<case tag="highway" value="road" />
<case tag="highway" value="unclassified" />
<case tag="highway" value="residential" />
<filter>
<switch>
<case nightMode="true" color="#9F9F9F" color_2="#9F9F9F" shadowColor="#666666" shadowRadius="1" />
<case nightMode="false" color="#ffffff" color_2="#ffffff" shadowColor="#464646" shadowRadius="1" />
<filter>
<!- ZM <filter minzoom="12" maxzoom="12" strokeWidth="3" /> ->
<filter minzoom="13" maxzoom="13" strokeWidth="4" />
<switch>
<case layer="-1" pathEffect="4_4" />
<case /> <!- all other cases ->
<filter>
<filter minzoom="14" maxzoom="14" strokeWidth="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="10" />
<!- radius 0 to avoid showing many black lines, but removed again due to bad visibility on some backgrounds ->
<filter minzoom="17" maxzoom="17" strokeWidth="13" />
<filter minzoom="18" strokeWidth="18" />
</filter>
</switch>
</filter>
</switch>
<!- bridge ->
<switch>
<case nightMode="false" color="#000000" color_2="#ffffff" shadowColor="#464646" />
<case nightMode="true" color="#ffffff" color_2="#9F9F9F" shadowColor="#666666" />
<filter layer="1" cap_2="SQUARE" >
<!-- bridge -->
<filter layer="1" cap_2="SQUARE" color="#000000">
<filter minzoom="13" maxzoom="14" strokeWidth="8" strokeWidth_2="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="10" strokeWidth_2="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="12" strokeWidth_2="10" />
<filter minzoom="17" maxzoom="17" strokeWidth="15" strokeWidth_2="13" />
<filter minzoom="18" strokeWidth="20" strokeWidth_2="18" />
<groupFilter nightMode="true" color="#ffffff" />
</filter>
<filter shadowRadius="1">
<filter minzoom="14" maxzoom="14" strokeWidth="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="10" />
<!-- radius 0 to avoid showing many black lines, but removed again due to bad visibility on some backgrounds -->
<filter minzoom="17" maxzoom="17" strokeWidth="13" />
<filter minzoom="18" strokeWidth="18" />
<groupFilter layer="-1" pathEffect="4_4"/>
</filter>
</switch>
</filter>
</switch>
<switch>
<case tag="highway" value="service" color="#ececec" color_2="#ececec" shadowColor="#b0b0b0" />
<case tag="highway" value="living_street" color="#ececec" color_2="#ececec" shadowColor="#b0b0b0" />
<case tag="highway" value="pedestrian" color="#ececec" color_2="#ececec" shadowColor="#b0b0b0" />
<filter shadowRadius="1">
<switch>
<case layer="-1" pathEffect="4_4" />
<case layer="1" nightMode="false" cap_2="SQUARE" color="#000000" />
<case layer="1" nightMode="true" cap_2="SQUARE" color="#000000" />
<case /> <!- all other cases ->
<filter>
<!- ZM <filter minzoom="13" maxzoom="13" strokeWidth="2" />
<filter minzoom="14" maxzoom="14" strokeWidth="3" /> ->
<object minzoom="15" maxzoom="15" strokeWidth="4">
<object layer="1" cap_2="SQUARE" strokeWidth="6" strokeWidth_2="4" />
</object>
<filter minzoom="16" maxzoom="16" strokeWidth="5" />
<filter minzoom="17" maxzoom="17" strokeWidth="8" />
<filter minzoom="18" strokeWidth="12"/>
</groupFilter>
</group>
<group>
<filter tag="highway" value="road" />
<filter tag="highway" value="unclassified" />
<filter tag="highway" value="residential" />
<groupFilter>
<filter hmRendered="true" minzoom="12" maxzoom="12" strokeWidth="3" />
<filter minzoom="13" maxzoom="13" strokeWidth="4" />
<!-- bridge -->
<filter layer="1" cap_2="SQUARE" color="#000000" color_2="#ffffff" shadowColor="#464646" >
<filter minzoom="14" maxzoom="14" strokeWidth="8" strokeWidth_2="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="10" strokeWidth_2="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="12" strokeWidth_2="10" />
<filter minzoom="17" maxzoom="17" strokeWidth="15" strokeWidth_2="13" />
<filter minzoom="18" strokeWidth="20" strokeWidth_2="18" />
<groupFilter nightMode="true" color="#ffffff" color_2="#9F9F9F" shadowColor="#666666" />
</filter>
<filter shadowRadius="1" color="#ffffff" color_2="#ffffff" shadowColor="#464646">
<filter minzoom="14" maxzoom="14" strokeWidth="6" />
<filter minzoom="15" maxzoom="15" strokeWidth="8" />
<filter minzoom="16" maxzoom="16" strokeWidth="10" />
<!-- radius 0 to avoid showing many black lines, but removed again due to bad visibility on some backgrounds -->
<filter minzoom="17" maxzoom="17" strokeWidth="13" />
<filter minzoom="18" strokeWidth="18" />
<groupFilter layer="-1" pathEffect="4_4"/>
<groupFilter nightMode="true" color="#9F9F9F" color_2="#9F9F9F" shadowColor="#666666"/>
</filter>
</switch>
<!- bridge ->
<switch>
</groupFilter>
</group>
<filter layer="1" cap_2="SQUARE">
<!- ZM <filter minzoom="13" maxzoom="14" strokeWidth="5" strokeWidth_2="3" /> ->
<group>
<filter tag="highway" value="service" color="#ececec" color_2="#ececec" shadowColor="#b0b0b0" />
<filter tag="highway" value="living_street" color="#ececec" color_2="#ececec" shadowColor="#b0b0b0" />
<filter tag="highway" value="pedestrian" color="#ececec" color_2="#ececec" shadowColor="#b0b0b0" />
<groupFilter shadowRadius="1">
<filter hmRendered="true" minzoom="13" maxzoom="13" strokeWidth="2" />
<filter hmRendered="true" minzoom="14" maxzoom="14" strokeWidth="3" />
<!-- bridge -->
<filter layer="1" cap_2="SQUARE" color="#000000" color_2="#ffffff" shadowColor="#464646" >
<filter hmRendered="true" minzoom="13" maxzoom="14" strokeWidth="5" strokeWidth_2="3" />
<filter minzoom="15" maxzoom="15" strokeWidth="6" strokeWidth_2="4" />
<filter minzoom="16" maxzoom="16" strokeWidth="7" strokeWidth_2="5" />
<filter minzoom="17" maxzoom="17" strokeWidth="10" strokeWidth_2="8" />
<filter minzoom="18" strokeWidth="14" strokeWidth_2="12" />
<groupFilter nightMode="true" color="#000000"/>
</filter>
<filter shadowRadius="1" color="#ffffff" color_2="#ffffff" shadowColor="#464646">
<filter minzoom="15" maxzoom="15" strokeWidth="4" />
<filter minzoom="16" maxzoom="16" strokeWidth="5" />
<filter minzoom="17" maxzoom="17" strokeWidth="8" />
<filter minzoom="18" strokeWidth="12"/>
<groupFilter layer="-1" pathEffect="4_4"/>
</filter>
</switch>
</filter>
</switch>
<!- TODO END -->
</groupFilter>
</group>
<filter tag="highway" value="cycleway">
<filter layer="1" minzoom="14" maxzoom="15" color="#0000ff" strokeWidth="1" pathEffect="2_2" />

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();
}
@ -1001,7 +1001,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,10 +1011,12 @@ public class OsmandSettings {
return false;
};
};
public final CommonPreference<String> RENDERER_APP_NAME = new StringPreference("renderer_appName", "", false);
{
RENDERER.setModeDefaultValue(ApplicationMode.CAR, RendererRegistry.CAR_RENDER);
RENDERER.setModeDefaultValue(ApplicationMode.PEDESTRIAN, RendererRegistry.PEDESTRIAN_RENDER);
RENDERER.setModeDefaultValue(ApplicationMode.BICYCLE, RendererRegistry.BICYCLE_RENDER);
RENDERER.setModeDefaultValue(ApplicationMode.CAR, "car");
RENDERER.setModeDefaultValue(ApplicationMode.PEDESTRIAN, "pedestrian");
RENDERER.setModeDefaultValue(ApplicationMode.BICYCLE, "bicycle");
}

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

@ -160,7 +160,7 @@ public class DownloadFileHelper {
fs = toIndex;
first = false;
} else {
String name = entry.getAttrName();
String name = entry.getName();
// small simplification
int ind = name.lastIndexOf('_');
if (ind > 0) {
@ -174,7 +174,7 @@ public class DownloadFileHelper {
toIndex = fs;
}
} else {
fs = new File(fileToUnZip, entry.getAttrName());
fs = new File(fileToUnZip, entry.getName());
}
out = new FileOutputStream(fs);
int read;

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;
@ -35,7 +36,8 @@ 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.RenderingRuleSearchRequest;
import net.osmand.render.RenderingRulesStorage;
import org.apache.commons.logging.Log;
@ -57,31 +59,31 @@ 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
private List<BinaryMapDataObject> cObjects = new LinkedList<BinaryMapDataObject>();
// currently rendered box (not the same as already rendered)
// this box is checked for interrupted process or
// this box is checked for interrupted process or
private RotatedTileBox requestedBox = null;
// location of rendered bitmap
private RotatedTileBox prevBmpLocation = null;
// already rendered bitmap
// already rendered bitmap
private Bitmap prevBmp;
// location of rendered bitmap
private RotatedTileBox bmpLocation = null;
// already rendered bitmap
// already rendered bitmap
private Bitmap bmp;
private boolean interrupted = false;
private RenderingContext currentRenderingContext;
private SearchRequest<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 +94,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 +104,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 +119,7 @@ public class MapRenderRepositories {
}
return null;
} catch (OutOfMemoryError oome) {
if(raf != null){
if (raf != null) {
try {
raf.close();
} catch (IOException e1) {
@ -140,7 +141,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 +161,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 +222,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,12 +256,17 @@ public class MapRenderRepositories {
int type = types.get(j);
int mask = type & 3;
TagValuePair pair = root.decodeType(type);
if (pair != null && renderingType.isObjectVisible(pair.tag, pair.value, zoom, mask, nightMode)) {
return true;
}
if(pair != null && mask == OsmandRenderingRulesParser.POINT_STATE &&
renderingType.isObjectVisible(pair.tag, pair.value, zoom, OsmandRenderingRulesParser.TEXT_STATE, nightMode)){
return true;
if (pair != null) {
renderingReq.setInitialTagValueZoom(pair.tag, pair.value, zoom);
if (renderingReq.search(mask)) {
return true;
}
if (mask == RenderingRulesStorage.POINT_RULES) {
if (renderingReq.search(RenderingRulesStorage.TEXT_RULES)) {
return true;
}
}
}
}
return false;
@ -283,10 +288,10 @@ public class MapRenderRepositories {
}
for (String mapName : files.keySet()) {
if(basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)){
if (basemapSearch && !mapName.toLowerCase().contains(BASEMAP_NAME)) {
continue;
}
BinaryMapIndexReader c = files.get(mapName);
BinaryMapIndexReader c = files.get(mapName);
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, searchFilter);
List<BinaryMapDataObject> res = c.searchMapIndex(searchRequest);
for (BinaryMapDataObject r : res) {
@ -299,12 +304,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 +339,40 @@ 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);
// TODO pass all global parameters
renderingReq.setBooleanFilter(renderingReq.ALL.R_NIGHT_MODE, nightMode);
if (renderingReq.ALL.get("appName") != null && !Algoritms.isEmpty(app.getSettings().RENDERER_APP_NAME.get())) {
renderingReq.setStringFilter(renderingReq.ALL.get("appName"), app.getSettings().RENDERER_APP_NAME.get());
}
renderingReq.saveState();
// prevent editing
requestedBox = new RotatedTileBox(tileRect);
@ -383,7 +394,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,7 +417,6 @@ 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();
@ -418,10 +428,8 @@ public class MapRenderRepositories {
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,
stepByStep ? notifyList : null, storage.getBgColor(nightMode));
String renderingDebugInfo = currentRenderingContext.renderingDebugInfo;
if (checkWhetherInterrupted()) {
currentRenderingContext = null;
@ -437,13 +445,13 @@ public class MapRenderRepositories {
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 +460,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 +470,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,18 +489,17 @@ public class MapRenderRepositories {
return prevBmp;
}
public synchronized void clearCache() {
cObjects = new ArrayList<BinaryMapDataObject>();
cObjectsBox = new RectF();
prevBmp = bmp = null;
prevBmp = bmp = null;
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 +508,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);
@ -522,11 +529,11 @@ public class MapRenderRepositories {
incompletedRings.clear();
completedRingNames.clear();
incompletedRingNames.clear();
log.debug("Process multypolygon " + type.tag + " " + type.value + //$NON-NLS-1$ //$NON-NLS-2$
" direct list : " +directList + " rev : " + inverselist); //$NON-NLS-1$ //$NON-NLS-2$
log.debug("Process multypolygon " + type.tag + " " + type.value + //$NON-NLS-1$ //$NON-NLS-2$
" direct list : " + directList + " rev : " + inverselist); //$NON-NLS-1$ //$NON-NLS-2$
MultyPolygon pl = processMultiPolygon(leftX, rightX, bottomY, topY, listPolygons, completedRings, incompletedRings,
completedRingNames, incompletedRingNames, type, directList, inverselist, zoom);
if(pl != null){
completedRingNames, incompletedRingNames, type, directList, inverselist, zoom);
if (pl != null) {
listPolygons.add(pl);
}
}
@ -534,8 +541,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 +572,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 +582,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 +630,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 +679,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 +695,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 +720,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 +751,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 +779,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 +796,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 +818,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 +867,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 +875,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 +939,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 +957,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 +1032,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 +1056,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 +1073,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, 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,35 @@ public class OsmandRenderer {
}
if (ref != null && ref.trim().length() > 0) {
rc.clearText();
ref = render.renderObjectText(ref, pair.tag, pair.value, rc, true, rc.nightMode);
TextDrawInfo text = new TextDrawInfo(ref);
text.fillProperties(rc, xText, yText);
rc.textToDraw.add(text);
render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom);
render.setIntFilter(render.ALL.R_TEXT_LENGTH, ref.length());
render.setBooleanFilter(render.ALL.R_REF, true);
if(render.search(RenderingRulesStorage.TEXT_RULES)){
TextDrawInfo text = new TextDrawInfo(ref);
text.fillProperties(render, xText, yText);
rc.textToDraw.add(text);
}
}
name = render.renderObjectText(name, pair.tag, pair.value, rc, false, rc.nightMode);
if (rc.textSize > 0 && name != null) {
render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom);
render.setIntFilter(render.ALL.R_TEXT_LENGTH, name.length());
render.setBooleanFilter(render.ALL.R_REF, true);
if(render.search(RenderingRulesStorage.TEXT_RULES)){
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 +876,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 +884,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 +938,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 +968,26 @@ public class OsmandRenderer {
}
}
if(ref != null && ref.trim().length() > 0){
rc.clearText();
ref = render.renderObjectText(ref, pair.tag, pair.value, rc, true, rc.nightMode);
TextDrawInfo text = new TextDrawInfo(ref);
text.fillProperties(rc, middlePoint.x, middlePoint.y);
text.pathRotate = pathRotate;
rc.textToDraw.add(text);
render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom);
render.setIntFilter(render.ALL.R_TEXT_LENGTH, ref.length());
render.setBooleanFilter(render.ALL.R_REF, true);
if(render.search(RenderingRulesStorage.TEXT_RULES)){
TextDrawInfo text = new TextDrawInfo(ref);
text.fillProperties(render, middlePoint.x, middlePoint.y);
text.pathRotate = pathRotate;
rc.textToDraw.add(text);
}
}
if(name != null && name.trim().length() > 0){
rc.clearText();
name = render.renderObjectText(name, pair.tag, pair.value, rc, false, rc.nightMode);
if (rc.textSize > 0) {
render.setInitialTagValueZoom(pair.tag, pair.value, rc.zoom);
render.setIntFilter(render.ALL.R_TEXT_LENGTH, name.length());
render.setBooleanFilter(render.ALL.R_REF, false);
if (render.search(RenderingRulesStorage.TEXT_RULES)) {
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 +1005,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 +1019,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,36 +68,33 @@ 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 b = new RenderingRulesStorage();
b.parseRulesFromXmlInputStream(is);
loadedRenderers.add(name);
List<BaseOsmandRender> dependencies = new ArrayList<BaseOsmandRender>();
for (String s : b.getDepends()) {
if (loadedRenderers.contains(s)) {
if(!Algoritms.isEmpty(b.getDepends())){
if (loadedRenderers.contains(b.getDepends())) {
log.warn("Circular dependencies found " + name); //$NON-NLS-1$
} else {
BaseOsmandRender dep = getRenderer(s, loadedRenderers);
RenderingRulesStorage dep = getRenderer(b.getDepends(), loadedRenderers);
if (dep == null) {
log.warn("Dependent renderer not found : " + name); //$NON-NLS-1$
} else{
dependencies.add(dep);
}
// TODO set dependent renders
}
}
b.setDependRenderers(dependencies);
renderers.put(name, b);
return b;
}
@ -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;
}