simplify rendertheme 'closed' and 'element' matching

This commit is contained in:
Hannes Janetzek
2012-07-10 09:00:45 +02:00
parent 380b5e019d
commit b410059282
16 changed files with 195 additions and 402 deletions

View File

@@ -16,7 +16,7 @@ package org.mapsforge.android.rendertheme;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
final class AnyMatcher implements ElementMatcher, AttributeMatcher, ClosedMatcher { final class AnyMatcher implements AttributeMatcher {
private static final AnyMatcher INSTANCE = new AnyMatcher(); private static final AnyMatcher INSTANCE = new AnyMatcher();
static AnyMatcher getInstance() { static AnyMatcher getInstance() {
@@ -35,26 +35,6 @@ final class AnyMatcher implements ElementMatcher, AttributeMatcher, ClosedMatche
return attributeMatcher == this; return attributeMatcher == this;
} }
@Override
public boolean isCoveredBy(ClosedMatcher closedMatcher) {
return closedMatcher == this;
}
@Override
public boolean isCoveredBy(ElementMatcher elementMatcher) {
return elementMatcher == this;
}
@Override
public boolean matches(Closed closed) {
return true;
}
@Override
public boolean matches(Element element) {
return true;
}
@Override @Override
public boolean matches(Tag[] tags) { public boolean matches(Tag[] tags) {
return true; return true;

View File

@@ -14,6 +14,8 @@
*/ */
package org.mapsforge.android.rendertheme; package org.mapsforge.android.rendertheme;
enum Closed { class Closed {
ANY, NO, YES; public static final int ANY = 0;
public static final int NO = 1;
public static final int YES = 2;
} }

View File

@@ -1,21 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.rendertheme;
interface ClosedMatcher {
boolean isCoveredBy(ClosedMatcher closedMatcher);
boolean matches(Closed closed);
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.rendertheme;
final class ClosedWayMatcher implements ClosedMatcher {
private static final ClosedWayMatcher INSTANCE = new ClosedWayMatcher();
static ClosedWayMatcher getInstance() {
return INSTANCE;
}
/**
* Private constructor to prevent instantiation from other classes.
*/
private ClosedWayMatcher() {
// do nothing
}
@Override
public boolean isCoveredBy(ClosedMatcher closedMatcher) {
return closedMatcher.matches(Closed.YES);
}
@Override
public boolean matches(Closed closed) {
return closed == Closed.YES;
}
}

View File

@@ -14,6 +14,8 @@
*/ */
package org.mapsforge.android.rendertheme; package org.mapsforge.android.rendertheme;
enum Element { class Element {
ANY, NODE, WAY; public static final int ANY = 0;
public static final int NODE = 1;
public static final int WAY = 2;
} }

View File

@@ -1,21 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.rendertheme;
interface ElementMatcher {
boolean isCoveredBy(ElementMatcher elementMatcher);
boolean matches(Element element);
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.rendertheme;
final class ElementNodeMatcher implements ElementMatcher {
private static final ElementNodeMatcher INSTANCE = new ElementNodeMatcher();
static ElementNodeMatcher getInstance() {
return INSTANCE;
}
/**
* Private constructor to prevent instantiation from other classes.
*/
private ElementNodeMatcher() {
// do nothing
}
@Override
public boolean isCoveredBy(ElementMatcher elementMatcher) {
return elementMatcher.matches(Element.NODE);
}
@Override
public boolean matches(Element element) {
return element == Element.NODE;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.rendertheme;
final class ElementWayMatcher implements ElementMatcher {
private static final ElementWayMatcher INSTANCE = new ElementWayMatcher();
static ElementWayMatcher getInstance() {
return INSTANCE;
}
/**
* Private constructor to prevent instantiation from other classes.
*/
private ElementWayMatcher() {
// do nothing
}
@Override
public boolean isCoveredBy(ElementMatcher elementMatcher) {
return elementMatcher.matches(Element.WAY);
}
@Override
public boolean matches(Element element) {
return element == Element.WAY;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.rendertheme;
final class LinearWayMatcher implements ClosedMatcher {
private static final LinearWayMatcher INSTANCE = new LinearWayMatcher();
static LinearWayMatcher getInstance() {
return INSTANCE;
}
/**
* Private constructor to prevent instantiation from other classes.
*/
private LinearWayMatcher() {
// do nothing
}
@Override
public boolean isCoveredBy(ClosedMatcher closedMatcher) {
return closedMatcher.matches(Closed.NO);
}
@Override
public boolean matches(Closed closed) {
return closed == Closed.NO;
}
}

View File

@@ -19,9 +19,9 @@ import org.mapsforge.core.Tag;
class NegativeRule extends Rule { class NegativeRule extends Rule {
final AttributeMatcher mAttributeMatcher; final AttributeMatcher mAttributeMatcher;
NegativeRule(ElementMatcher elementMatcher, ClosedMatcher closedMatcher, byte zoomMin, byte zoomMax, NegativeRule(int element, int closed, byte zoomMin, byte zoomMax,
AttributeMatcher attributeMatcher) { AttributeMatcher attributeMatcher) {
super(elementMatcher, closedMatcher, zoomMin, zoomMax); super(element, closed, zoomMin, zoomMax);
mAttributeMatcher = attributeMatcher; mAttributeMatcher = attributeMatcher;
} }
@@ -29,14 +29,15 @@ class NegativeRule extends Rule {
@Override @Override
boolean matchesNode(Tag[] tags, byte zoomLevel) { boolean matchesNode(Tag[] tags, byte zoomLevel) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mElementMatcher == null || mElementMatcher.matches(Element.NODE)) && (mElement == Element.NODE || mElement == Element.ANY)
&& mAttributeMatcher.matches(tags); && mAttributeMatcher.matches(tags);
} }
@Override @Override
boolean matchesWay(Tag[] tags, byte zoomLevel, Closed closed) { boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mElementMatcher == null || mElementMatcher.matches(Element.WAY)) && (mElement == Element.WAY || mElement == Element.ANY)
&& (mClosedMatcher == null || mClosedMatcher.matches(closed)) && mAttributeMatcher.matches(tags); && (mClosed == closed || mClosed == Closed.ANY)
&& mAttributeMatcher.matches(tags);
} }
} }

View File

@@ -20,9 +20,9 @@ class PositiveRule extends Rule {
final AttributeMatcher mKeyMatcher; final AttributeMatcher mKeyMatcher;
final AttributeMatcher mValueMatcher; final AttributeMatcher mValueMatcher;
PositiveRule(ElementMatcher elementMatcher, ClosedMatcher closedMatcher, byte zoomMin, byte zoomMax, PositiveRule(int element, int closed, byte zoomMin, byte zoomMax,
AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) { AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
super(elementMatcher, closedMatcher, zoomMin, zoomMax); super(element, closed, zoomMin, zoomMax);
if (keyMatcher instanceof AnyMatcher) if (keyMatcher instanceof AnyMatcher)
mKeyMatcher = null; mKeyMatcher = null;
@@ -38,16 +38,16 @@ class PositiveRule extends Rule {
@Override @Override
boolean matchesNode(Tag[] tags, byte zoomLevel) { boolean matchesNode(Tag[] tags, byte zoomLevel) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mElementMatcher == null || mElementMatcher.matches(Element.NODE)) && (mElement == Element.NODE || mElement == Element.ANY)
&& (mKeyMatcher == null || mKeyMatcher.matches(tags)) && (mKeyMatcher == null || mKeyMatcher.matches(tags))
&& (mValueMatcher == null || mValueMatcher.matches(tags)); && (mValueMatcher == null || mValueMatcher.matches(tags));
} }
@Override @Override
boolean matchesWay(Tag[] tags, byte zoomLevel, Closed closed) { boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mElementMatcher == null || mElementMatcher.matches(Element.WAY)) && (mElement == Element.WAY || mElement == Element.ANY)
&& (mClosedMatcher == null || mClosedMatcher.matches(closed)) && (mClosed == closed || mClosed == Closed.ANY)
&& (mKeyMatcher == null || mKeyMatcher.matches(tags)) && (mKeyMatcher == null || mKeyMatcher.matches(tags))
&& (mValueMatcher == null || mValueMatcher.matches(tags)); && (mValueMatcher == null || mValueMatcher.matches(tags));
} }

View File

@@ -32,15 +32,19 @@ public class RenderTheme {
private static final int MATCHING_CACHE_SIZE = 1024; private static final int MATCHING_CACHE_SIZE = 1024;
private static final int RENDER_THEME_VERSION = 1; private static final int RENDER_THEME_VERSION = 1;
private static void validate(String elementName, Integer version, float baseStrokeWidth, float baseTextSize) { private static void validate(String elementName, Integer version,
float baseStrokeWidth, float baseTextSize) {
if (version == null) { if (version == null) {
throw new IllegalArgumentException("missing attribute version for element:" + elementName); throw new IllegalArgumentException("missing attribute version for element:"
+ elementName);
} else if (version.intValue() != RENDER_THEME_VERSION) { } else if (version.intValue() != RENDER_THEME_VERSION) {
throw new IllegalArgumentException("invalid render theme version:" + version); throw new IllegalArgumentException("invalid render theme version:" + version);
} else if (baseStrokeWidth < 0) { } else if (baseStrokeWidth < 0) {
throw new IllegalArgumentException("base-stroke-width must not be negative: " + baseStrokeWidth); throw new IllegalArgumentException("base-stroke-width must not be negative: "
+ baseStrokeWidth);
} else if (baseTextSize < 0) { } else if (baseTextSize < 0) {
throw new IllegalArgumentException("base-text-size must not be negative: " + baseTextSize); throw new IllegalArgumentException("base-text-size must not be negative: "
+ baseTextSize);
} }
} }
@@ -93,9 +97,12 @@ public class RenderTheme {
mBaseTextSize = baseTextSize; mBaseTextSize = baseTextSize;
mRulesList = new ArrayList<Rule>(); mRulesList = new ArrayList<Rule>();
mMatchingCacheNodes = new LRUCache<MatchingCacheKey, RenderInstruction[]>(MATCHING_CACHE_SIZE); mMatchingCacheNodes = new LRUCache<MatchingCacheKey, RenderInstruction[]>(
mMatchingCacheWay = new LRUCache<MatchingCacheKey, RenderInstruction[]>(MATCHING_CACHE_SIZE); MATCHING_CACHE_SIZE);
mMatchingCacheArea = new LRUCache<MatchingCacheKey, RenderInstruction[]>(MATCHING_CACHE_SIZE); mMatchingCacheWay = new LRUCache<MatchingCacheKey, RenderInstruction[]>(
MATCHING_CACHE_SIZE);
mMatchingCacheArea = new LRUCache<MatchingCacheKey, RenderInstruction[]>(
MATCHING_CACHE_SIZE);
} }
/** /**
@@ -207,7 +214,8 @@ public class RenderTheme {
* @param changed * @param changed
* ... * ...
*/ */
public void matchWay(RenderCallback renderCallback, Tag[] tags, byte zoomLevel, boolean closed, boolean changed) { public void matchWay(RenderCallback renderCallback, Tag[] tags, byte zoomLevel,
boolean closed, boolean changed) {
RenderInstruction[] renderInstructions = null; RenderInstruction[] renderInstructions = null;
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache; LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
@@ -241,10 +249,11 @@ public class RenderTheme {
} }
} else { } else {
// cache miss // cache miss
Closed c = (closed ? Closed.YES : Closed.NO); int c = (closed ? Closed.YES : Closed.NO);
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4); List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
for (int i = 0, n = mRulesList.size(); i < n; ++i) { for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c, matchingList); mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c,
matchingList);
} }
int size = matchingList.size(); int size = matchingList.size();
if (size > 0) { if (size > 0) {

View File

@@ -33,21 +33,20 @@ abstract class Rule {
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|"); private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|");
private static final String STRING_NEGATION = "~"; private static final String STRING_NEGATION = "~";
private static final String STRING_WILDCARD = "*"; private static final String STRING_WILDCARD = "*";
private static final String UNKNOWN_ENUM_VALUE = "unknown enum value: ";
private static Rule createRule(Stack<Rule> ruleStack, Element element, String keys, String values, Closed closed, private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
String values, int closed,
byte zoomMin, byte zoomMax) { byte zoomMin, byte zoomMax) {
ElementMatcher elementMatcher = getElementMatcher(element);
ClosedMatcher closedMatcher = getClosedMatcher(closed);
List<String> keyList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN.split(keys)));
List<String> valueList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN.split(values)));
elementMatcher = RuleOptimizer.optimize(elementMatcher, ruleStack); List<String> keyList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN
closedMatcher = RuleOptimizer.optimize(closedMatcher, ruleStack); .split(keys)));
List<String> valueList = new ArrayList<String>(Arrays.asList(SPLIT_PATTERN
.split(values)));
if (valueList.remove(STRING_NEGATION)) { if (valueList.remove(STRING_NEGATION)) {
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList); AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList);
return new NegativeRule(elementMatcher, closedMatcher, zoomMin, zoomMax, attributeMatcher); return new NegativeRule(element, closed, zoomMin, zoomMax,
attributeMatcher);
} }
AttributeMatcher keyMatcher = getKeyMatcher(keyList); AttributeMatcher keyMatcher = getKeyMatcher(keyList);
@@ -56,33 +55,8 @@ abstract class Rule {
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack); keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack); valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack);
return new PositiveRule(elementMatcher, closedMatcher, zoomMin, zoomMax, keyMatcher, valueMatcher); return new PositiveRule(element, closed, zoomMin, zoomMax,
} keyMatcher, valueMatcher);
private static ClosedMatcher getClosedMatcher(Closed closed) {
switch (closed) {
case YES:
return ClosedWayMatcher.getInstance();
case NO:
return LinearWayMatcher.getInstance();
case ANY:
return AnyMatcher.getInstance();
}
throw new IllegalArgumentException(UNKNOWN_ENUM_VALUE + closed);
}
private static ElementMatcher getElementMatcher(Element element) {
switch (element) {
case NODE:
return ElementNodeMatcher.getInstance();
case WAY:
return ElementWayMatcher.getInstance();
case ANY:
return AnyMatcher.getInstance();
}
throw new IllegalArgumentException(UNKNOWN_ENUM_VALUE + element);
} }
private static AttributeMatcher getKeyMatcher(List<String> keyList) { private static AttributeMatcher getKeyMatcher(List<String> keyList) {
@@ -119,28 +93,31 @@ abstract class Rule {
return attributeMatcher; return attributeMatcher;
} }
private static void validate(String elementName, Element element, String keys, String values, byte zoomMin, private static void validate(String elementName, String keys, String values,
byte zoomMax) { byte zoomMin, byte zoomMax) {
if (element == null) { if (keys == null) {
throw new IllegalArgumentException("missing attribute e for element: " + elementName); throw new IllegalArgumentException("missing attribute k for element: "
} else if (keys == null) { + elementName);
throw new IllegalArgumentException("missing attribute k for element: " + elementName);
} else if (values == null) { } else if (values == null) {
throw new IllegalArgumentException("missing attribute v for element: " + elementName); throw new IllegalArgumentException("missing attribute v for element: "
+ elementName);
} else if (zoomMin < 0) { } else if (zoomMin < 0) {
throw new IllegalArgumentException("zoom-min must not be negative: " + zoomMin); throw new IllegalArgumentException("zoom-min must not be negative: "
+ zoomMin);
} else if (zoomMax < 0) { } else if (zoomMax < 0) {
throw new IllegalArgumentException("zoom-max must not be negative: " + zoomMax); throw new IllegalArgumentException("zoom-max must not be negative: "
+ zoomMax);
} else if (zoomMin > zoomMax) { } else if (zoomMin > zoomMax) {
throw new IllegalArgumentException("zoom-min must be less or equal zoom-max: " + zoomMin); throw new IllegalArgumentException(
"zoom-min must be less or equal zoom-max: " + zoomMin);
} }
} }
static Rule create(String elementName, Attributes attributes, Stack<Rule> ruleStack) { static Rule create(String elementName, Attributes attributes, Stack<Rule> ruleStack) {
Element element = null; int element = Element.ANY;
String keys = null; String keys = null;
String values = null; String values = null;
Closed closed = Closed.ANY; int closed = Closed.ANY;
byte zoomMin = 0; byte zoomMin = 0;
byte zoomMax = Byte.MAX_VALUE; byte zoomMax = Byte.MAX_VALUE;
@@ -149,13 +126,21 @@ abstract class Rule {
String value = attributes.getValue(i); String value = attributes.getValue(i);
if ("e".equals(name)) { if ("e".equals(name)) {
element = Element.valueOf(value.toUpperCase(Locale.ENGLISH)); String val = value.toUpperCase(Locale.ENGLISH);
if ("WAY".equals(val))
element = Element.WAY;
else if ("NODE".equals(val))
element = Element.NODE;
} else if ("k".equals(name)) { } else if ("k".equals(name)) {
keys = value; keys = value;
} else if ("v".equals(name)) { } else if ("v".equals(name)) {
values = value; values = value;
} else if ("closed".equals(name)) { } else if ("closed".equals(name)) {
closed = Closed.valueOf(value.toUpperCase(Locale.ENGLISH)); String val = value.toUpperCase(Locale.ENGLISH);
if ("YES".equals(val))
closed = Closed.YES;
else if ("NO".equals(val))
closed = Closed.NO;
} else if ("zoom-min".equals(name)) { } else if ("zoom-min".equals(name)) {
zoomMin = Byte.parseByte(value); zoomMin = Byte.parseByte(value);
} else if ("zoom-max".equals(name)) { } else if ("zoom-max".equals(name)) {
@@ -165,7 +150,7 @@ abstract class Rule {
} }
} }
validate(elementName, element, keys, values, zoomMin, zoomMax); validate(elementName, keys, values, zoomMin, zoomMax);
return createRule(ruleStack, element, keys, values, closed, zoomMin, zoomMax); return createRule(ruleStack, element, keys, values, closed, zoomMin, zoomMax);
} }
@@ -175,22 +160,16 @@ abstract class Rule {
private Rule[] mSubRuleArray; private Rule[] mSubRuleArray;
private RenderInstruction[] mRenderInstructionArray; private RenderInstruction[] mRenderInstructionArray;
final ClosedMatcher mClosedMatcher;
final ElementMatcher mElementMatcher;
final byte mZoomMax; final byte mZoomMax;
final byte mZoomMin; final byte mZoomMin;
final int mElement;
final int mClosed;
Rule(ElementMatcher elementMatcher, ClosedMatcher closedMatcher, byte zoomMin, byte zoomMax) { Rule(int element, int closed, byte zoomMin,
if (elementMatcher instanceof AnyMatcher) byte zoomMax) {
mElementMatcher = null;
else
mElementMatcher = elementMatcher;
if (closedMatcher instanceof AnyMatcher)
mClosedMatcher = null;
else
mClosedMatcher = closedMatcher;
mClosed = closed;
mElement = element;
mZoomMin = zoomMin; mZoomMin = zoomMin;
mZoomMax = zoomMax; mZoomMax = zoomMax;
@@ -208,7 +187,7 @@ abstract class Rule {
abstract boolean matchesNode(Tag[] tags, byte zoomLevel); abstract boolean matchesNode(Tag[] tags, byte zoomLevel);
abstract boolean matchesWay(Tag[] tags, byte zoomLevel, Closed closed); abstract boolean matchesWay(Tag[] tags, byte zoomLevel, int closed);
void matchNode(RenderCallback renderCallback, Tag[] tags, byte zoomLevel) { void matchNode(RenderCallback renderCallback, Tag[] tags, byte zoomLevel) {
if (matchesNode(tags, zoomLevel)) { if (matchesNode(tags, zoomLevel)) {
@@ -221,7 +200,8 @@ abstract class Rule {
} }
} }
void matchWay(RenderCallback renderCallback, Tag[] tags, byte zoomLevel, Closed closed, void matchWay(RenderCallback renderCallback, Tag[] tags, byte zoomLevel,
int closed,
List<RenderInstruction> matchingList) { List<RenderInstruction> matchingList) {
if (matchesWay(tags, zoomLevel, closed)) { if (matchesWay(tags, zoomLevel, closed)) {
@@ -229,7 +209,8 @@ abstract class Rule {
matchingList.add(mRenderInstructionArray[i]); matchingList.add(mRenderInstructionArray[i]);
for (int i = 0, n = mSubRuleArray.length; i < n; i++) for (int i = 0, n = mSubRuleArray.length; i < n; i++)
mSubRuleArray[i].matchWay(renderCallback, tags, zoomLevel, closed, matchingList); mSubRuleArray[i].matchWay(renderCallback, tags, zoomLevel, closed,
matchingList);
} }
} }

View File

@@ -20,11 +20,13 @@ import java.util.logging.Logger;
final class RuleOptimizer { final class RuleOptimizer {
private static final Logger LOG = Logger.getLogger(RuleOptimizer.class.getName()); private static final Logger LOG = Logger.getLogger(RuleOptimizer.class.getName());
private static AttributeMatcher optimizeKeyMatcher(AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) { private static AttributeMatcher optimizeKeyMatcher(AttributeMatcher attributeMatcher,
Stack<Rule> ruleStack) {
for (int i = 0, n = ruleStack.size(); i < n; ++i) { for (int i = 0, n = ruleStack.size(); i < n; ++i) {
if (ruleStack.get(i) instanceof PositiveRule) { if (ruleStack.get(i) instanceof PositiveRule) {
PositiveRule positiveRule = (PositiveRule) ruleStack.get(i); PositiveRule positiveRule = (PositiveRule) ruleStack.get(i);
if (positiveRule.mKeyMatcher != null && positiveRule.mKeyMatcher.isCoveredBy(attributeMatcher)) { if (positiveRule.mKeyMatcher != null
&& positiveRule.mKeyMatcher.isCoveredBy(attributeMatcher)) {
return null; // AnyMatcher.getInstance(); return null; // AnyMatcher.getInstance();
} }
} }
@@ -33,12 +35,14 @@ final class RuleOptimizer {
return attributeMatcher; return attributeMatcher;
} }
private static AttributeMatcher optimizeValueMatcher(AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) { private static AttributeMatcher optimizeValueMatcher(
AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) {
for (int i = 0, n = ruleStack.size(); i < n; ++i) { for (int i = 0, n = ruleStack.size(); i < n; ++i) {
if (ruleStack.get(i) instanceof PositiveRule) { if (ruleStack.get(i) instanceof PositiveRule) {
PositiveRule positiveRule = (PositiveRule) ruleStack.get(i); PositiveRule positiveRule = (PositiveRule) ruleStack.get(i);
if (positiveRule.mValueMatcher != null && positiveRule.mValueMatcher.isCoveredBy(attributeMatcher)) { if (positiveRule.mValueMatcher != null
&& positiveRule.mValueMatcher.isCoveredBy(attributeMatcher)) {
return null; // AnyMatcher.getInstance(); return null; // AnyMatcher.getInstance();
} }
} }
@@ -47,7 +51,8 @@ final class RuleOptimizer {
return attributeMatcher; return attributeMatcher;
} }
static AttributeMatcher optimize(AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) { static AttributeMatcher optimize(AttributeMatcher attributeMatcher,
Stack<Rule> ruleStack) {
if (attributeMatcher instanceof AnyMatcher) if (attributeMatcher instanceof AnyMatcher)
return attributeMatcher;// return null; return attributeMatcher;// return null;
else if (attributeMatcher instanceof NegativeMatcher) { else if (attributeMatcher instanceof NegativeMatcher) {
@@ -61,60 +66,61 @@ final class RuleOptimizer {
} else if (attributeMatcher instanceof MultiValueMatcher) { } else if (attributeMatcher instanceof MultiValueMatcher) {
return optimizeValueMatcher(attributeMatcher, ruleStack); return optimizeValueMatcher(attributeMatcher, ruleStack);
} }
throw new IllegalArgumentException("unknown AttributeMatcher: " + attributeMatcher); throw new IllegalArgumentException("unknown AttributeMatcher: "
+ attributeMatcher);
} }
static ClosedMatcher optimize(ClosedMatcher closedMatcher, Stack<Rule> ruleStack) { // static ClosedMatcher optimize(ClosedMatcher closedMatcher, Stack<Rule> ruleStack) {
if (closedMatcher == null) { // if (closedMatcher == null) {
return null; // return null;
} // }
//
if (closedMatcher instanceof AnyMatcher) { // if (closedMatcher instanceof AnyMatcher) {
return null; // return null;
} // }
//
for (int i = 0, n = ruleStack.size(); i < n; ++i) { // for (int i = 0, n = ruleStack.size(); i < n; ++i) {
ClosedMatcher matcher = ruleStack.get(i).mClosedMatcher; // ClosedMatcher matcher = ruleStack.get(i).mClosedMatcher;
if (matcher == null) // if (matcher == null)
return null; // return null;
//
if (matcher.isCoveredBy(closedMatcher)) { // if (matcher.isCoveredBy(closedMatcher)) {
return null; // AnyMatcher.getInstance(); // return null; // AnyMatcher.getInstance();
//
} else if (!closedMatcher.isCoveredBy(ruleStack.get(i).mClosedMatcher)) { // } else if (!closedMatcher.isCoveredBy(ruleStack.get(i).mClosedMatcher)) {
LOG.warning("unreachable rule (closed)"); // LOG.warning("unreachable rule (closed)");
} // }
} // }
//
return closedMatcher; // return closedMatcher;
} // }
//
static ElementMatcher optimize(ElementMatcher elementMatcher, Stack<Rule> ruleStack) { // static ElementMatcher optimize(ElementMatcher elementMatcher, Stack<Rule> ruleStack) {
//
if (elementMatcher == null) { // if (elementMatcher == null) {
return null; // return null;
} // }
//
if (elementMatcher instanceof AnyMatcher) { // if (elementMatcher instanceof AnyMatcher) {
return null; // return null;
} // }
//
for (int i = 0, n = ruleStack.size(); i < n; ++i) { // for (int i = 0, n = ruleStack.size(); i < n; ++i) {
ElementMatcher matcher = ruleStack.get(i).mElementMatcher; // ElementMatcher matcher = ruleStack.get(i).mElementMatcher;
//
if (matcher == null) // if (matcher == null)
return null; // return null;
//
if (matcher.isCoveredBy(elementMatcher)) { // if (matcher.isCoveredBy(elementMatcher)) {
return null; // AnyMatcher.getInstance(); // return null; // AnyMatcher.getInstance();
//
} else if (!elementMatcher.isCoveredBy(ruleStack.get(i).mElementMatcher)) { // } else if (!elementMatcher.isCoveredBy(ruleStack.get(i).mElementMatcher)) {
LOG.warning("unreachable rule (e)"); // LOG.warning("unreachable rule (e)");
} // }
} // }
//
return elementMatcher; // return elementMatcher;
} // }
/** /**
* Private constructor to prevent instantiation from other classes. * Private constructor to prevent instantiation from other classes.

View File

@@ -8,9 +8,17 @@
<rule e="way" k="*" v="*"> <rule e="way" k="*" v="*">
<!-- landuse --> <!-- landuse -->
<rule e="way" k="landuse" v="*" zoom-min="10"> <rule e="way" k="landuse" v="*">
<rule e="way" k="landuse" v="residential|farmyard|retail|commercial"> <rule e="way" k="*" zoom-min="12" v="farmland|farm">
<area fill="#ededec" fade="10" /> <area fill="#fff8bf" fade="12" />
</rule>
<rule e="way" k="landuse" v="grass">
<area fill="#deecb9" fade="12" />
</rule>
<rule e="way" k="*" zoom-min="10" v="residential|farmyard|retail|commercial">
<area fill="#efefeb" fade="10" />
</rule> </rule>
<!-- <rule e="way" k="landuse" v="industrial|brownfield|railway"> <area <!-- <rule e="way" k="landuse" v="industrial|brownfield|railway"> <area
@@ -19,9 +27,7 @@
stroke="#e4e4e4" stroke-width="0.2" /> </rule> --> stroke="#e4e4e4" stroke-width="0.2" /> </rule> -->
<!-- <rule e="way" k="landuse" v="garages"> <area fill="#d6d6e4" /> </rule> --> <!-- <rule e="way" k="landuse" v="garages"> <area fill="#d6d6e4" /> </rule> -->
<rule e="way" k="landuse" v="grass">
<area fill="#deecb9" fade="12" />
</rule>
</rule> </rule>
<rule e="way" k="outline" v="*"> <rule e="way" k="outline" v="*">
@@ -103,9 +109,7 @@
<rule e="way" k="*" v="meadow|scrub"> <rule e="way" k="*" v="meadow|scrub">
<area fill="#deecb9" fade="12" /> <area fill="#deecb9" fade="12" />
</rule> </rule>
<rule e="way" k="*" v="farmland|farm">
<area fill="#fff8bf" fade="12" />
</rule>
<!-- <rule e="way" k="*" v="village_green|recreation_ground"> <!-- <rule e="way" k="*" v="village_green|recreation_ground">
<area fill="#daebaf" fade="12" /> <area fill="#daebaf" fade="12" />
</rule> --> </rule> -->
@@ -130,9 +134,14 @@
</rule> </rule>
<rule e="way" k="natural|landuse" v="forest|wood" zoom-min="10"> <rule e="way" k="natural|landuse" v="forest|wood" zoom-min="9">
<!-- <area fill="#BCCBB0" fade="10" /> --> <!-- <area fill="#BCCBB0" fade="10" /> -->
<area fill="#cde2bc" fade="10" /> <!-- <rule e="way" k="*" v="*" zoom-max="11"> -->
<area fill="#d3dec8" fade="9" />
<!-- </rule> -->
<!-- <rule e="way" k="*" v="*" zoom-min="12">
<area fill="#cde2bc" fade="12" />
</rule> -->
<!-- <area fill="#87a670" fade="10" /> --> <!-- <area fill="#87a670" fade="10" /> -->
</rule> </rule>
@@ -169,8 +178,8 @@
<area fill="#fcfeab" /> <area fill="#fcfeab" />
</rule> </rule>
<!-- Heideland --> <!-- Heideland -->
<rule e="way" k="*" v="heath"> <rule e="way" k="*" zoom-min="12" v="heath">
<area fill="#ffffc0" fade="10" /> <area fill="#ffffc0" fade="12" />
</rule> </rule>
<rule e="way" k="*" v="marsh|wetland"> <rule e="way" k="*" v="marsh|wetland">
<area fill="#deecb9" fade="12" /> <area fill="#deecb9" fade="12" />
@@ -207,7 +216,8 @@
</rule> </rule>
<rule e="way" k="natural" v="water"> <rule e="way" k="natural" v="water">
<area fill="#b4cbdc" /> <line stroke="#eea4bbcc" fixed="true" stroke-width="1.4" stroke-linecap="butt" />
<area fill="#b4cbdc" />
</rule> </rule>
<!-- waterways --> <!-- waterways -->
@@ -232,6 +242,7 @@
fixed="true" /> fixed="true" />
</rule> </rule>
<rule e="way" k="waterway" v="riverbank|dock"> <rule e="way" k="waterway" v="riverbank|dock">
<line stroke="#eea4bbcc" fixed="true" stroke-width="1.4" stroke-linecap="butt" />
<area fill="#b4cbdc" /> <area fill="#b4cbdc" />
</rule> </rule>
<rule e="way" k="waterway" v="weir"> <rule e="way" k="waterway" v="weir">
@@ -323,9 +334,8 @@
</rule>--> </rule>-->
<rule e="way" k="*" v="*" zoom-min="15"> <rule e="way" k="*" v="*" zoom-min="15">
<line stroke="#c9c3c3" stroke-width="0.6" fixed="true" <line stroke="#c9c3c1" stroke-width="0.6" fixed="true" stroke-linecap="butt" />
stroke-linecap="butt" /> <area fill="#e9e6e3" fade="15" />
<area fill="#e9e6e6" fade="15" />
</rule> </rule>
<!-- <rule e="way" k="*" v="*" zoom-min="17"> <!-- <rule e="way" k="*" v="*" zoom-min="17">
@@ -359,31 +369,31 @@
<rule e="way" k="*" v="*" zoom-min="5" zoom-max="10"> <rule e="way" k="*" v="*" zoom-min="5" zoom-max="10">
<rule e="way" k="*" v="secondary|primary_link" zoom-min="9"> <rule e="way" k="*" v="secondary|primary_link" zoom-min="9">
<!-- <line stroke="#eeee4a" stroke-width="1.3" stroke-linecap="butt" <!-- <line stroke="#eeee4a" stroke-width="1.8" stroke-linecap="butt"
fixed="true" /> --> fixed="true" /> -->
<line stroke="#f2df6d" stroke-width="1.2" stroke-linecap="butt" <line stroke="#f2df6d" stroke-width="1.7" stroke-linecap="butt"
fixed="true" /> fixed="true" />
</rule> </rule>
<rule e="way" k="*" v="trunk_link|motorway_link" zoom-min="8"> <rule e="way" k="*" v="trunk_link|motorway_link" zoom-min="8">
<line stroke="#fed6a3" stroke-width="1.4" stroke-linecap="butt" <line stroke="#fed6a3" stroke-width="1.9" stroke-linecap="butt"
fixed="true" /> fixed="true" />
</rule> </rule>
<rule e="way" k="*" v="primary" zoom-min="8"> <rule e="way" k="*" v="primary" zoom-min="7">
<!-- <line stroke="#eeee4a" stroke-width="1.4" stroke-linecap="butt" <!-- <line stroke="#eeee4a" stroke-width="1.4" stroke-linecap="butt"
fixed="true" /> --> fixed="true" /> -->
<line stroke="#f2df6d" stroke-width="1.4" stroke-linecap="butt" <line stroke="#f2df6d" stroke-width="1.9" stroke-linecap="butt"
fixed="true" /> fixed="true" />
</rule> </rule>
<rule e="way" k="*" v="trunk" zoom-min="8"> <rule e="way" k="*" v="trunk" zoom-min="7">
<line stroke="#fed6a3" stroke-width="1.4" stroke-linecap="butt" <line stroke="#fed6a3" stroke-width="1.9" stroke-linecap="butt"
fixed="true" /> fixed="true" />
</rule> </rule>
<rule e="way" k="*" v="motorway"> <rule e="way" k="*" v="motorway">
<line stroke="#eec693" stroke-width="1.5" stroke-linecap="butt" <line stroke="#eec693" stroke-width="2.0" stroke-linecap="butt"
fixed="true" /> fixed="true" />
</rule> </rule>
</rule> </rule>

View File

@@ -47,7 +47,8 @@ public final class Line implements RenderInstruction {
* @throws IOException * @throws IOException
* if an I/O error occurs while reading a resource. * if an I/O error occurs while reading a resource.
*/ */
public static Line create(String elementName, Attributes attributes, int level) throws IOException { public static Line create(String elementName, Attributes attributes, int level)
throws IOException {
String src = null; String src = null;
int stroke = Color.BLACK; int stroke = Color.BLACK;
float strokeWidth = 0; float strokeWidth = 0;
@@ -83,12 +84,14 @@ public final class Line implements RenderInstruction {
} }
validate(strokeWidth); validate(strokeWidth);
return new Line(src, stroke, strokeWidth, strokeDasharray, strokeLinecap, level, outline, fixed); return new Line(src, stroke, strokeWidth, strokeDasharray, strokeLinecap, level,
outline, fixed);
} }
private static void validate(float strokeWidth) { private static void validate(float strokeWidth) {
if (strokeWidth < 0) { if (strokeWidth < 0) {
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth); throw new IllegalArgumentException("stroke-width must not be negative: "
+ strokeWidth);
} }
} }
@@ -131,7 +134,8 @@ public final class Line implements RenderInstruction {
*/ */
public final boolean fixed; public final boolean fixed;
private Line(String src, int stroke, float strokeWidth, float[] strokeDasharray, Cap strokeLinecap, int level, private Line(String src, int stroke, float strokeWidth, float[] strokeDasharray,
Cap strokeLinecap, int level,
int outline, boolean fixed) int outline, boolean fixed)
throws IOException { throws IOException {
super(); super();
@@ -146,7 +150,7 @@ public final class Line implements RenderInstruction {
paint.setPathEffect(new DashPathEffect(strokeDasharray, 0)); paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
} }
paint.setStrokeCap(strokeLinecap); paint.setStrokeCap(strokeLinecap);
round = strokeLinecap == Cap.ROUND; round = (strokeLinecap == Cap.ROUND);
this.color = stroke; this.color = stroke;
this.strokeWidth = strokeWidth; this.strokeWidth = strokeWidth;
this.level = level; this.level = level;