Merge branch 'theme_refactor'

This commit is contained in:
Hannes Janetzek 2014-03-17 23:24:46 +01:00
commit 604c1449e4
50 changed files with 1548 additions and 1182 deletions

@ -1 +1 @@
Subproject commit 43a6277c1aa089f778f10ec1f2fd9b7034e63f0a
Subproject commit 7449e47e8ec147c816eb3b8b77d07109035fab4d

View File

@ -22,7 +22,7 @@ import java.io.InputStream;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.XmlThemeBuilder;
import org.oscim.tiling.TileSource.OpenResult;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@ -40,7 +40,7 @@ public final class ValidRenderTheme implements ValidFileFilter {
try {
inputStream = new FileInputStream(file);
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder();
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
xmlReader.setContentHandler(renderThemeHandler);
xmlReader.parse(new InputSource(inputStream));

View File

@ -15,8 +15,8 @@ import org.oscim.jeo.JeoUtils;
import org.oscim.map.Map;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.MeshLayer;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -117,7 +117,7 @@ public class JeoVectorLayer extends JtsLayer {
if (ll.line == null) {
RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black);
float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f);
ll.line = new Line(0, JeoUtils.color(color), width);
ll.line = new LineStyle(0, JeoUtils.color(color), width);
ll.setDropDistance(0.5f);
}
@ -131,14 +131,14 @@ public class JeoVectorLayer extends JtsLayer {
if (ll.line == null) {
float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f);
RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black);
ll.line = new Line(0, JeoUtils.color(color), width);
ll.line = new LineStyle(0, JeoUtils.color(color), width);
ll.setDropDistance(0.5f);
}
MeshLayer mesh = t.layers.getMeshLayer(0);
if (mesh.area == null) {
int color = JeoUtils.color(rule.color(f, CartoCSS.POLYGON_FILL, RGB.red));
mesh.area = new Area(color);
mesh.area = new AreaStyle(color);
}
addPolygon(t, g, mesh, ll);

View File

@ -15,9 +15,10 @@ import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.MeshLayer;
import org.oscim.renderer.elements.TextItem;
import org.oscim.renderer.elements.TextLayer;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.theme.styles.TextStyle.TextBuilder;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
@ -26,7 +27,10 @@ import com.vividsolutions.jts.geom.LineString;
public class OSMIndoorLayer extends JeoVectorLayer {
protected TextLayer mTextLayer;
protected Text mText = Text.createText(16, 2.2f, Color.BLACK, Color.WHITE, true);
protected TextStyle mText = new TextBuilder()
.setFontSize(16).setColor(Color.BLACK)
.setStrokeWidth(2.2f).setStroke(Color.WHITE)
.build();
public OSMIndoorLayer(Map map, VectorDataset data, Style style) {
super(map, data, style);
@ -58,7 +62,7 @@ public class OSMIndoorLayer extends JeoVectorLayer {
if (ll.line == null) {
RGB color = rule.color(f, CartoCSS.LINE_COLOR, RGB.black);
float width = rule.number(f, CartoCSS.LINE_WIDTH, 1.2f);
ll.line = new Line(0, JeoUtils.color(color), width);
ll.line = new LineStyle(0, JeoUtils.color(color), width);
ll.heightOffset = level * 4;
ll.setDropDistance(0);
}
@ -80,7 +84,7 @@ public class OSMIndoorLayer extends JeoVectorLayer {
if (level > -2 && !active)
color = Color.fade(color, 0.1f);
ll.line = new Line(0, color, width);
ll.line = new LineStyle(0, color, width);
ll.heightOffset = level * 4;
ll.setDropDistance(0);
}
@ -91,7 +95,7 @@ public class OSMIndoorLayer extends JeoVectorLayer {
if (level > -2 && !active)
color = Color.fade(color, 0.1f);
mesh.area = new Area(color);
mesh.area = new AreaStyle(color);
//mesh.area = new Area(Color.fade(Color.DKGRAY, 0.1f));
mesh.heightOffset = level * 4f;
}

View File

@ -19,8 +19,8 @@ import org.oscim.core.MapElement;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;
public class RenderTheme implements IRenderTheme {
@ -147,11 +147,11 @@ public class RenderTheme implements IRenderTheme {
}
if (p != null) {
s.ri[0] = new Area(mCurLevel++, color(p));
s.ri[0] = new AreaStyle(mCurLevel++, color(p));
}
if (l != null) {
s.ri[1] = new Line(mCurLevel++, color(l), 1);
s.ri[1] = new LineStyle(mCurLevel++, color(l), 1);
}
if (p != null || l != null) {
@ -198,7 +198,7 @@ public class RenderTheme implements IRenderTheme {
RGB c = r.color(f, CartoCSS.POLYGON_FILL, RGB.black);
out.println(z + " " + c);
return new RenderStyle[] {
new Area(z, color(c))
new AreaStyle(z, color(c))
};
} else if (type == GeometryType.LINE) {
@ -207,7 +207,7 @@ public class RenderTheme implements IRenderTheme {
//out.println(z + " " + c);
return new RenderStyle[] {
new Line(100 + z, color(c), width)
new LineStyle(100 + z, color(c), width)
};
} else if (type == GeometryType.POINT) {
@ -258,7 +258,7 @@ public class RenderTheme implements IRenderTheme {
}
@Override
public void updateInstructions() {
public void updateStyles() {
// TODO Auto-generated method stub
}

View File

@ -79,7 +79,7 @@
stipple-stroke="#be6253" />
<style-line id="water:outline" stroke="#a4bbcc" width="1.0" fix="true" cap="butt" />
<style-line id="water" stroke="#a4bbcc" width="1.0" cap="butt" fix="true"/>
<style-line id="water" stroke="#a4bbcc" width="1.0" cap="butt" fix="true" />
<style-line id="river" use="water" stroke="#a4bbcc" fix="false" />
<!--<style-area id="water" fill="#97b7e5" afc5e3 /> -->
@ -143,7 +143,7 @@
</atlas>
<!-- all closed ways that are not 'highway' or 'building'-->
<m e="way" k="highway|building" v="~" closed="yes">
<!-- landuse base -->
@ -151,11 +151,11 @@
<m v="urban">
<area fill="#f4f3f0" />
</m>
<m v="meadow|conservation">
<area use="greens" fade="11" />
</m>
<m v="residential|commercial|retail|farmyard">
<area use="residential" />
</m>
@ -1064,7 +1064,10 @@
<m k="amenity" v="cinema">
<symbol src="cinema" />
</m>
<text use="poi" />
<m select="when-matched">
<text use="poi" />
</m>
</m>
<m zoom-min="16" select="first">
@ -1089,7 +1092,9 @@
<m k="amenity" v="bus_station">
<symbol src="bus_station" />
</m>
<text use="poi" />
<m select="when-matched">
<text use="poi" />
</m>
</m>
<m zoom-min="17" select="first">
@ -1152,7 +1157,9 @@
<m k="amenity" v="theatre">
<symbol src="theatre" />
</m>
<text use="poi" />
<m select="when-matched">
<text use="poi" />
</m>
</m>
<m zoom-min="17">
@ -1176,17 +1183,18 @@
<m v="supermarket|organic">
<symbol src="shop_supermarket" />
</m>
<m>
<m zoom-min="17">
<symbol src="city" />
</m>
</m>
<m zoom-min="17">
<text use="poi" />
<m select="when-matched" zoom-min="17">
<text use="poi" />
</m>
</m>
</m>
<m k="tourism">
<m zoom-min="15" select="first">
<m v="alpine_hut">
<symbol src="triangle-stroked" />
@ -1200,7 +1208,10 @@
<m v="hotel">
<symbol src="hotel" />
</m>
<text use="poi" />
<m select="when-matched">
<text use="poi" />
</m>
</m>
<m zoom-min="16" select="first">

View File

@ -779,19 +779,19 @@
<m k="bridge" v="yes|true">
<m select="first">
<m v="service">
<line stroke="#ffffff" width="0.85" outline="casing-bridge"/>
<line stroke="#ffffff" width="0.85" outline="casing-bridge" />
<m zoom-min="15">
<text k="name" style="bold" size="10" stroke="#ffffff" stroke-width="2.0" />
</m>
</m>
<m v="construction">
<line stroke="#d0d0d0" width="1.0" outline="casing-bridge"/>
<line stroke="#d0d0d0" width="1.0" outline="casing-bridge" />
<m zoom-min="15">
<text k="name" style="bold" size="10" stroke="#d0d0d0" stroke-width="2.0" />
</m>
</m>
<m v="road">
<line stroke="#d0d0d0" width="1.25" outline="casing-bridge"/>
<line stroke="#d0d0d0" width="1.25" outline="casing-bridge" />
<m zoom-min="15">
<text k="name" style="bold" size="10" stroke="#d0d0d0" stroke-width="2.0" />
</m>
@ -803,69 +803,69 @@
</m>
</m>
<m v="unclassified|residential|living_street">
<line stroke="#ffffff" width="1.25" outline="casing-bridge"/>
<line stroke="#ffffff" width="1.25" outline="casing-bridge" />
<m zoom-min="15">
<text k="name" style="bold" size="10" stroke="#ffffff" stroke-width="2.0" />
</m>
</m>
<m v="byway">
<line stroke="#efadaa" width="1.15" outline="casing-bridge"/>
<line stroke="#efadaa" width="1.15" outline="casing-bridge" />
<m zoom-min="15">
<text k="name" style="bold" size="10" stroke="#efadaa" stroke-width="2.0" />
</m>
</m>
<m v="tertiary|tertiary_link">
<line use="tertiary" cap="square" outline="casing-bridge"/>
<line use="tertiary" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#ffff90" stroke-width="2.0" />
</m>
</m>
<m v="secondary_link">
<line use="secondary" width="-0.1" cap="square" outline="casing-bridge"/>
<line use="secondary" width="-0.1" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#fdbf6f" stroke-width="2.0" />
</m>
</m>
<m v="primary_link">
<line use="primary" width="-0.1" cap="square" outline="casing-bridge"/>
<line use="primary" width="-0.1" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#e46d71" stroke-width="2.0" />
</m>
</m>
<m v="trunk_link">
<line use="trunk" cap="square" outline="casing-bridge"/>
<line use="trunk" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#7fc97f" stroke-width="2.0" />
</m>
</m>
<m v="motorway_link">
<line use="motorway" width="-0.2" cap="square" outline="casing-bridge"/>
<line use="motorway" width="-0.2" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#809bc0" stroke-width="2.0" />
</m>
</m>
<m v="secondary">
<line use="secondary" cap="square" outline="casing-bridge"/>
<line use="secondary" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#fdbf6f" stroke-width="2.0" />
</m>
</m>
<m v="primary">
<line use="primary" cap="square" outline="casing-bridge"/>
<line use="primary" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#e46d71" stroke-width="2.0" />
<text k="ref" style="bold" size="12" stroke="#ffffff" fill="#606060" stroke-width="2.0" />
</m>
</m>
<m v="trunk">
<line use="trunk" outline="casing-bridge"/>
<line use="trunk" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#7fc97f" stroke-width="2.0" />
<text k="ref" style="bold" size="12" stroke="#ffffff" fill="#606060" stroke-width="2.0" />
</m>
</m>
<m v="motorway">
<line use="motorway" cap="square" outline="casing-bridge"/>
<line use="motorway" cap="square" outline="casing-bridge" />
<m zoom-min="14">
<text k="name" style="bold" size="10" stroke="#809bc0" stroke-width="2.0" />
<text k="ref" style="bold" size="12" stroke="#ffffff" fill="#606060" stroke-width="2.0" />

View File

@ -2,7 +2,7 @@
<rendertheme xmlns="http://opensciencemap.org/rendertheme" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://opensciencemap.org/rendertheme ../../rendertheme.xsd" version="1" map-background="#050508">
<atlas img="styles/osmarender.png">
<atlas img="styles/osmarender.png">
<rect id="airport" pos="226 38 24 24" />
<rect id="alpine_hut" pos="198 41 26 21" />
<rect id="atm" pos="279 2 14 16" />
@ -62,10 +62,10 @@
<rect id="vulcan" pos="315 25 9 8" />
<rect id="windmill" pos="310 2 13 19" />
</atlas>
<style-text id="caption-small-blue" caption="true" dy="12" k="name" style="bold" size="16" fill="#4040ff"
<style-text id="caption-small-blue" caption="true" dy="12" k="name" style="bold" size="16" fill="#4040ff"
stroke="#ffffff" stroke-width="2.0" />
<style-text id="road" k="name" style="bold" size="18" stroke="#606050" fill="#eeffee" stroke-width="2.5" />
<style-text id="major-road" k="name" style="bold" size="19" fill="#ffef7d" stroke="#624f00" stroke-width="2.5" />
@ -1312,7 +1312,7 @@
</m>
<m k="tourism">
<m k="tourism" select="first">
<m v="alpine_hut" zoom-min="16">
<symbol src="alpine_hut" />
</m>
@ -1332,7 +1332,7 @@
<symbol src="viewpoint" />
</m>
<m zoom-min="17">
<m select="when-matched" zoom-min="17">
<text use="caption-small-blue" />
</m>
</m>

View File

@ -32,7 +32,7 @@ import org.oscim.renderer.ElementRenderer;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineStyle;
import org.oscim.utils.FastMath;
import org.oscim.utils.async.SimpleWorker;
import org.oscim.utils.geom.LineClipper;
@ -45,14 +45,14 @@ public class PathLayer extends Layer {
protected boolean mUpdatePoints;
/** Line style */
Line mLineStyle;
LineStyle mLineStyle;
final Worker mWorker;
public PathLayer(Map map, int lineColor, float lineWidth) {
super(map);
mWorker = new Worker(map);
mLineStyle = new Line(lineColor, lineWidth, Cap.BUTT);
mLineStyle = new LineStyle(lineColor, lineWidth, Cap.BUTT);
mRenderer = new RenderPath();
mPoints = new ArrayList<GeoPoint>();
}

View File

@ -3,8 +3,8 @@ package org.oscim.layers;
import org.oscim.backend.canvas.Paint.Cap;
import org.oscim.map.Map;
import org.oscim.renderer.GridRenderer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.TextStyle;
public class TileGridLayer extends GenericLayer {
@ -13,10 +13,10 @@ public class TileGridLayer extends GenericLayer {
}
public TileGridLayer(Map map, int color, float width, int repeat) {
super(map, new GridRenderer(repeat, new Line(color, width, Cap.BUTT), null));
super(map, new GridRenderer(repeat, new LineStyle(color, width, Cap.BUTT), null));
}
public TileGridLayer(Map map, int color, float width, Text text, int repeat) {
super(map, new GridRenderer(repeat, new Line(color, width, Cap.BUTT), text));
public TileGridLayer(Map map, int color, float width, TextStyle text, int repeat) {
super(map, new GridRenderer(repeat, new LineStyle(color, width, Cap.BUTT), text));
}
}

View File

@ -28,7 +28,7 @@ import org.oscim.layers.tile.VectorTileRenderer;
import org.oscim.map.Map;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -52,7 +52,7 @@ public class TestTileLayer extends TileLayer {
}
GeometryBuffer mGeom = new GeometryBuffer(128, 16);
Line mLineStyle = new Line(Color.BLUE, 2f, Cap.ROUND);
LineStyle mLineStyle = new LineStyle(Color.BLUE, 2f, Cap.ROUND);
@Override
public boolean loadTile(MapTile tile) {

View File

@ -40,14 +40,13 @@ import org.oscim.renderer.elements.SymbolItem;
import org.oscim.renderer.elements.TextItem;
import org.oscim.theme.IRenderTheme;
import org.oscim.theme.RenderTheme;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Circle;
import org.oscim.theme.styles.Extrusion;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineSymbol;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.CircleStyle;
import org.oscim.theme.styles.ExtrusionStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.theme.styles.Symbol;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.SymbolStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.tiling.ITileDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -248,7 +247,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
/*** RenderThemeCallback ***/
@Override
public void renderWay(Line line, int level) {
public void renderWay(LineStyle line, int level) {
int numLayer = mCurLayer + level;
if (line.stipple == 0) {
@ -297,7 +296,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
protected final static boolean USE_MESH_POLY = false;
@Override
public void renderArea(Area area, int level) {
public void renderArea(AreaStyle area, int level) {
int numLayer = mCurLayer + level;
if (USE_MESH_POLY) {
MeshLayer l = mTile.layers.getMeshLayer(numLayer);
@ -311,7 +310,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
}
@Override
public void renderAreaText(Text text) {
public void renderAreaText(TextStyle text) {
// TODO place somewhere on polygon
String value = mElement.tags.getValue(text.textKey);
if (value == null || value.length() == 0)
@ -332,7 +331,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
}
@Override
public void renderPointText(Text text) {
public void renderPointText(TextStyle text) {
String value = mElement.tags.getValue(text.textKey);
if (value == null || value.length() == 0)
return;
@ -344,7 +343,7 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
}
@Override
public void renderWayText(Text text) {
public void renderWayText(TextStyle text) {
String value = mElement.tags.getValue(text.textKey);
if (value == null || value.length() == 0)
return;
@ -362,11 +361,11 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
}
@Override
public void renderPointCircle(Circle circle, int level) {
public void renderPointCircle(CircleStyle circle, int level) {
}
@Override
public void renderPointSymbol(Symbol symbol) {
public void renderPointSymbol(SymbolStyle symbol) {
if (symbol.texture == null)
return;
@ -380,16 +379,11 @@ public class VectorTileLoader extends TileLoader implements IRenderTheme.Callbac
}
@Override
public void renderAreaSymbol(Symbol symbol) {
public void renderAreaSymbol(SymbolStyle symbol) {
}
@Override
public void renderWaySymbol(LineSymbol symbol) {
}
@Override
public void renderExtrusion(Extrusion extrusion, int level) {
public void renderExtrusion(ExtrusionStyle extrusion, int level) {
int height = 0;
int minHeight = 0;

View File

@ -20,14 +20,14 @@ package org.oscim.layers.tile.vector;
import org.oscim.core.Tile;
import org.oscim.layers.tile.MapTile;
import org.oscim.renderer.elements.TextItem;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.TextStyle;
import org.oscim.utils.geom.GeometryUtils;
import org.oscim.utils.geom.LineClipper;
public final class WayDecorator {
public static void renderText(LineClipper clipper, float[] coordinates, String string,
Text text, int pos, int len, MapTile tile) {
TextStyle text, int pos, int len, MapTile tile) {
//TextItem items = textItems;
TextItem t = null;

View File

@ -22,7 +22,7 @@ import org.oscim.renderer.GLViewport;
import org.oscim.renderer.elements.ElementLayers;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.TextItem;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineStyle;
class Debug {
@ -71,12 +71,12 @@ class Debug {
int alpha = 0xaaffffff;
dbg.clear();
dbg.addLineLayer(0, new Line((Color.BLUE & alpha), 2));
dbg.addLineLayer(1, new Line((Color.RED & alpha), 2));
dbg.addLineLayer(3, new Line((Color.YELLOW & alpha), 2));
dbg.addLineLayer(2, new Line((Color.GREEN & alpha), 2));
dbg.addLineLayer(4, new Line((Color.CYAN & alpha), 2));
dbg.addLineLayer(5, new Line((Color.MAGENTA & alpha), 2));
dbg.addLineLayer(0, new LineStyle((Color.BLUE & alpha), 2));
dbg.addLineLayer(1, new LineStyle((Color.RED & alpha), 2));
dbg.addLineLayer(3, new LineStyle((Color.YELLOW & alpha), 2));
dbg.addLineLayer(2, new LineStyle((Color.GREEN & alpha), 2));
dbg.addLineLayer(4, new LineStyle((Color.CYAN & alpha), 2));
dbg.addLineLayer(5, new LineStyle((Color.MAGENTA & alpha), 2));
}
public static void draw(MapPosition pos, GLViewport m, ElementLayers layers) {

View File

@ -23,12 +23,13 @@ import org.oscim.core.Tile;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.TextItem;
import org.oscim.renderer.elements.TextLayer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.theme.styles.TextStyle.TextBuilder;
public class GridRenderer extends ElementRenderer {
private final TextLayer mTextLayer;
private final Text mText;
private final TextStyle mText;
private final LineLayer mLineLayer;
private final GeometryBuffer mLines;
private final StringBuffer mStringBuffer;
@ -36,11 +37,11 @@ public class GridRenderer extends ElementRenderer {
private int mCurX, mCurY, mCurZ;
public GridRenderer() {
this(1, new Line(Color.LTGRAY, 1.2f, Cap.BUTT),
Text.createText(22, 0, Color.RED, 0, false));
this(1, new LineStyle(Color.LTGRAY, 1.2f, Cap.BUTT),
new TextBuilder().setFontSize(22).setColor(Color.RED).build());
}
public GridRenderer(int numLines, Line lineStyle, Text textStyle) {
public GridRenderer(int numLines, LineStyle lineStyle, TextStyle textStyle) {
int size = Tile.SIZE;
// not needed to set but we know:

View File

@ -25,8 +25,8 @@ import java.nio.ShortBuffer;
import org.oscim.backend.GL20;
import org.oscim.renderer.BufferObject;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -83,7 +83,7 @@ public class ElementLayers {
* add the LineLayer for a level with a given Line style. Levels are
* ordered from bottom (0) to top
*/
public LineLayer addLineLayer(int level, Line style) {
public LineLayer addLineLayer(int level, LineStyle style) {
LineLayer l = (LineLayer) getLayer(level, LINE);
if (l == null)
return null;
@ -93,7 +93,7 @@ public class ElementLayers {
return l;
}
public PolygonLayer addPolygonLayer(int level, Area style) {
public PolygonLayer addPolygonLayer(int level, AreaStyle style) {
PolygonLayer l = (PolygonLayer) getLayer(level, POLYGON);
if (l == null)
return null;
@ -101,7 +101,7 @@ public class ElementLayers {
return l;
}
public MeshLayer addMeshLayer(int level, Area style) {
public MeshLayer addMeshLayer(int level, AreaStyle style) {
MeshLayer l = (MeshLayer) getLayer(level, MESH);
if (l == null)
return null;

View File

@ -29,7 +29,7 @@ import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineStyle;
import org.oscim.utils.pool.Inlist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -64,7 +64,7 @@ public final class LineLayer extends RenderElement {
/* lines referenced by this outline layer */
public LineLayer outlines;
public Line line;
public LineStyle line;
public float scale = 1;
public boolean roundCap;
@ -749,7 +749,7 @@ public final class LineLayer extends RenderElement {
RenderElement l = curLayer;
for (; l != null && l.type == RenderElement.LINE; l = l.next) {
LineLayer ll = (LineLayer) l;
Line line = (Line) ll.line.getCurrent();
LineStyle line = (LineStyle) ll.line.getCurrent();
if (ll.heightOffset != heightOffset) {
heightOffset = ll.heightOffset;
@ -758,9 +758,9 @@ public final class LineLayer extends RenderElement {
MercatorProjection.groundResolution(v.pos));
}
if (line.fade < v.pos.zoomLevel) {
if (line.fadeScale < v.pos.zoomLevel) {
GLUtils.setColor(uLineColor, line.color, 1);
} else if (line.fade > v.pos.zoomLevel) {
} else if (line.fadeScale > v.pos.zoomLevel) {
continue;
} else {
float alpha = (float) (scale > 1.2 ? scale : 1.2) - 1;
@ -820,7 +820,7 @@ public final class LineLayer extends RenderElement {
/* draw LineLayers references by this outline */
for (LineLayer ref = ll.outlines; ref != null; ref = ref.outlines) {
Line core = (Line) ref.line.getCurrent();
LineStyle core = (LineStyle) ref.line.getCurrent();
// core width
if (core.fixed) {

View File

@ -26,7 +26,7 @@ import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineStyle;
import org.oscim.utils.pool.Inlist;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -86,7 +86,7 @@ public final class LineTexLayer extends RenderElement {
/* lines referenced by this outline layer */
public LineLayer outlines;
public Line line;
public LineStyle line;
public float width;
//public boolean roundCap;
@ -362,7 +362,7 @@ public final class LineTexLayer extends RenderElement {
RenderElement l = curLayer;
for (; l != null && l.type == TEXLINE; l = l.next) {
LineTexLayer ll = (LineTexLayer) l;
Line line = ll.line;
LineStyle line = ll.line;
GLUtils.setColor(hTexColor, line.stippleColor, 1);
GLUtils.setColor(hBgColor, line.color, 1);

View File

@ -27,7 +27,7 @@ import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.utils.Tessellator;
import org.oscim.utils.pool.Inlist;
import org.slf4j.Logger;
@ -41,7 +41,7 @@ public class MeshLayer extends RenderElement {
int numIndices;
VertexItem indiceItems;
public Area area;
public AreaStyle area;
public float heightOffset;
public MeshLayer(int level) {

View File

@ -29,7 +29,7 @@ import org.oscim.renderer.GLState;
import org.oscim.renderer.GLUtils;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.MapRenderer;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.utils.FastMath;
import org.oscim.utils.math.Interpolation;
import org.oscim.utils.pool.Inlist;
@ -46,7 +46,7 @@ public final class PolygonLayer extends RenderElement {
private static final boolean enableTexture = true;
public Area area;
public AreaStyle area;
PolygonLayer(int layer) {
super(RenderElement.POLYGON);
@ -181,7 +181,7 @@ public final class PolygonLayer extends RenderElement {
int shader = polyShader;
for (int c = start; c < end; c++) {
Area a = (Area) mFillPolys[c].area.getCurrent();
AreaStyle a = (AreaStyle) mFillPolys[c].area.getCurrent();
if (enableTexture && a.texture != null) {
shader = texShader;
@ -194,10 +194,10 @@ public final class PolygonLayer extends RenderElement {
GLState.blend(true);
a.texture.bind();
} else if (a.fade >= zoom) {
} else if (a.fadeScale >= zoom) {
float f = 1.0f;
/* fade in/out */
if (a.fade >= zoom) {
if (a.fadeScale >= zoom) {
if (scale > FADE_START)
f = scale - 1;
else
@ -207,11 +207,11 @@ public final class PolygonLayer extends RenderElement {
GLUtils.setColor(hPolygonColor[shader], a.color, f);
} else if (a.blend > 0 && a.blend <= zoom) {
} else if (a.blendScale > 0 && a.blendScale <= zoom) {
/* blend colors (not alpha) */
GLState.blend(false);
if (a.blend == zoom)
if (a.blendScale == zoom)
GLUtils.setColorBlend(hPolygonColor[shader],
a.color, a.blendColor, scale - 1.0f);
else
@ -301,7 +301,7 @@ public final class PolygonLayer extends RenderElement {
PolygonLayer pl = (PolygonLayer) l;
// fade out polygon layers (set in RenderTheme)
if (pl.area.fade > 0 && pl.area.fade > zoom)
if (pl.area.fadeScale > 0 && pl.area.fadeScale > zoom)
continue;
if (cur == start) {

View File

@ -16,7 +16,7 @@
*/
package org.oscim.renderer.elements;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.TextStyle;
import org.oscim.utils.pool.Inlist;
import org.oscim.utils.pool.SyncPool;
@ -57,7 +57,7 @@ public class TextItem extends Inlist<TextItem> {
return ti;
}
public TextItem set(float x, float y, String string, Text text) {
public TextItem set(float x, float y, String string, TextStyle text) {
this.x = x;
this.y = y;
this.string = string;
@ -77,7 +77,7 @@ public class TextItem extends Inlist<TextItem> {
public String string;
// text style
public Text text;
public TextStyle text;
// label width
public float width;

View File

@ -28,8 +28,9 @@ import org.oscim.renderer.atlas.TextureAtlas.Slot;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.renderer.elements.TextItem;
import org.oscim.renderer.elements.TextLayer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.theme.styles.TextStyle.TextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -42,19 +43,19 @@ public class AtlasRenderLayer extends ElementRenderer {
TextureAtlas mAtlas = TextureAtlas.create(2048, 2048, 1);
LineLayer ll = layers.getLineLayer(0);
ll.line = new Line(Color.BLUE, 3, Cap.BUTT);
ll.line = new LineStyle(Color.BLUE, 3, Cap.BUTT);
ll.scale = 1f;
LineLayer ll2 = layers.getLineLayer(1);
ll2.line = new Line(Color.RED, 3, Cap.BUTT);
ll2.line = new LineStyle(Color.RED, 3, Cap.BUTT);
ll2.scale = 1f;
LineLayer ll3 = layers.getLineLayer(2);
ll3.line = new Line(Color.GREEN, 3, Cap.BUTT);
ll3.line = new LineStyle(Color.GREEN, 3, Cap.BUTT);
ll3.scale = 1f;
TextLayer tl = new TextLayer();
Text t = Text.createText(20, 0, Color.BLACK, 0, false);
TextStyle t = new TextBuilder().setFontSize(20).setColor(Color.BLACK).build();
layers.setTextureLayers(tl);
float[] points = new float[10];

View File

@ -8,7 +8,7 @@ import org.oscim.core.Point;
import org.oscim.renderer.ElementRenderer;
import org.oscim.renderer.GLViewport;
import org.oscim.renderer.elements.LineLayer;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineStyle;
import org.oscim.utils.geom.BezierPath;
public class BezierPathLayer extends ElementRenderer {
@ -27,7 +27,7 @@ public class BezierPathLayer extends ElementRenderer {
// System.out.println(pts[i]);
g.addPoint(pts[i]);
}
LineLayer ll = layers.addLineLayer(0, new Line(Color.BLUE, 2f));
LineLayer ll = layers.addLineLayer(0, new LineStyle(Color.BLUE, 2f));
ll.addLine(g);
List<Point> ctrl = BezierPath.cubicSplineControlPoints(pts, 0.1f);
@ -49,7 +49,7 @@ public class BezierPathLayer extends ElementRenderer {
}
p0 = p3;
}
ll = layers.addLineLayer(1, new Line(Color.CYAN, 2f));
ll = layers.addLineLayer(1, new LineStyle(Color.CYAN, 2f));
ll.addLine(g);
}

View File

@ -3,14 +3,14 @@ package org.oscim.theme;
import org.oscim.backend.canvas.Color;
import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.TagSet;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;
public class DebugTheme implements IRenderTheme {
private final static Line[] line = { new Line(1, Color.MAGENTA, 2) };
private final static Area[] area = { new Area(0, Color.CYAN) };
private final static LineStyle[] line = { new LineStyle(1, Color.MAGENTA, 2) };
private final static AreaStyle[] area = { new AreaStyle(0, Color.CYAN) };
@Override
public RenderStyle[] matchElement(GeometryType type, TagSet tags, int zoomLevel) {
@ -41,7 +41,7 @@ public class DebugTheme implements IRenderTheme {
}
@Override
public void updateInstructions() {
public void updateStyles() {
}

View File

@ -19,14 +19,13 @@ package org.oscim.theme;
import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.TagSet;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Circle;
import org.oscim.theme.styles.Extrusion;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineSymbol;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.CircleStyle;
import org.oscim.theme.styles.ExtrusionStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.theme.styles.Symbol;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.SymbolStyle;
import org.oscim.theme.styles.TextStyle;
public interface IRenderTheme {
@ -56,7 +55,7 @@ public interface IRenderTheme {
*/
public abstract int getMapBackground();
public void updateInstructions();
public void updateStyles();
/**
* Scales the text size of this RenderTheme by the given factor.
@ -76,7 +75,7 @@ public interface IRenderTheme {
* @param area
* @param level
*/
void renderArea(Area area, int level);
void renderArea(AreaStyle area, int level);
/**
* Renders an extrusion with the given parameters.
@ -84,7 +83,7 @@ public interface IRenderTheme {
* @param extrusion
* @param level
*/
void renderExtrusion(Extrusion extrusion, int level);
void renderExtrusion(ExtrusionStyle extrusion, int level);
/**
* Renders an area symbol with the given bitmap.
@ -92,7 +91,7 @@ public interface IRenderTheme {
* @param symbol
* the symbol to be rendered.
*/
void renderAreaSymbol(Symbol symbol);
void renderAreaSymbol(SymbolStyle symbol);
/**
* Renders an area caption with the given text.
@ -100,7 +99,7 @@ public interface IRenderTheme {
* @param text
* the text to be rendered.
*/
void renderAreaText(Text text);
void renderAreaText(TextStyle text);
/**
* Renders a point of interest circle with the given parameters.
@ -110,7 +109,7 @@ public interface IRenderTheme {
* @param level
* the drawing level on which the circle should be rendered.
*/
void renderPointCircle(Circle circle, int level);
void renderPointCircle(CircleStyle circle, int level);
/**
* Renders a point of interest symbol with the given bitmap.
@ -118,7 +117,7 @@ public interface IRenderTheme {
* @param symbol
* the symbol to be rendered.
*/
void renderPointSymbol(Symbol symbol);
void renderPointSymbol(SymbolStyle symbol);
/**
* Renders a point of interest caption with the given text.
@ -126,7 +125,7 @@ public interface IRenderTheme {
* @param text
* the text to be rendered.
*/
void renderPointText(Text text);
void renderPointText(TextStyle text);
/**
* Renders a way with the given parameters.
@ -134,22 +133,14 @@ public interface IRenderTheme {
* @param line
* @param level
*/
void renderWay(Line line, int level);
/**
* Renders a way with the given symbol along the way path.
*
* @param symbol
* the symbol to be rendered.
*/
void renderWaySymbol(LineSymbol symbol);
void renderWay(LineStyle line, int level);
/**
* Renders a way with the given text along the way path.
*
* @param text
*/
void renderWayText(Text text);
void renderWayText(TextStyle text);
}

View File

@ -1,6 +1,5 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
* Copyright 2014 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
@ -25,14 +24,12 @@ import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.TagSet;
import org.oscim.theme.rule.Element;
import org.oscim.theme.rule.Rule;
import org.oscim.theme.rule.Rule.RuleVisitor;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.utils.LRUCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A RenderTheme defines how map elements are drawn.
*/
public class RenderTheme implements IRenderTheme {
static final Logger log = LoggerFactory.getLogger(RenderTheme.class);
@ -41,8 +38,8 @@ public class RenderTheme implements IRenderTheme {
private final float mBaseTextSize;
private final int mMapBackground;
private int mLevels;
private Rule[] mRules;
private final int mLevels;
private final Rule[] mRules;
class RenderStyleCache {
final int matchType;
@ -75,9 +72,14 @@ public class RenderTheme implements IRenderTheme {
private final RenderStyleCache[] mStyleCache;
public RenderTheme(int mapBackground, float baseStrokeWidth, float baseTextSize) {
public RenderTheme(int mapBackground, float baseTextSize, Rule[] rules, int levels) {
if (rules == null)
throw new IllegalArgumentException("rules missing");
mMapBackground = mapBackground;
mBaseTextSize = baseTextSize;
mLevels = levels;
mRules = rules;
mStyleCache = new RenderStyleCache[3];
mStyleCache[0] = new RenderStyleCache(Element.NODE);
@ -91,10 +93,8 @@ public class RenderTheme implements IRenderTheme {
for (int i = 0; i < 3; i++)
mStyleCache[i].cache.clear();
if (mRules != null) {
for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].onDestroy();
}
for (Rule rule : mRules)
rule.dispose();
}
@Override
@ -107,13 +107,17 @@ public class RenderTheme implements IRenderTheme {
return mMapBackground;
}
//AtomicInteger hitCount = new AtomicInteger(0);
//AtomicInteger missCount = new AtomicInteger(0);
//AtomicInteger sameCount = new AtomicInteger(0);
@Override
public RenderStyle[] matchElement(GeometryType geometryType, TagSet tags, int zoomLevel) {
// list of renderinsctruction items in cache
/* list of items in cache */
RenderStyleItem ris = null;
// the item matching tags and zoomlevel
/* the item matching tags and zoomlevel */
RenderStyleItem ri = null;
int type = geometryType.nativeInt;
@ -124,35 +128,42 @@ public class RenderTheme implements IRenderTheme {
RenderStyleCache cache = mStyleCache[type - 1];
// NOTE: maximum zoom level supported is 32
/* NOTE: maximum zoom level supported is 32 */
int zoomMask = 1 << zoomLevel;
synchronized (cache) {
if ((cache.prevItem == null) || (cache.prevItem.zoom & zoomMask) == 0) {
// previous instructions zoom does not match
/* previous instructions zoom does not match */
cache.cacheKey.set(tags, null);
} else {
// compare if tags match previous instructions
/* compare if tags match previous instructions */
if (cache.cacheKey.set(tags, cache.prevItem.key)) {
//log.debug("same as previous " + Arrays.deepToString(tags));
ri = cache.prevItem;
//log.debug(hitCount + "/" + sameCount.incrementAndGet()
// + "/" + missCount + "same hit " + tags);
}
}
if (ri == null) {
// get instruction for current cacheKey
/* get instruction for current cacheKey */
ris = cache.getRenderInstructions();
for (ri = ris; ri != null; ri = ri.next)
if ((ri.zoom & zoomMask) != 0)
// cache hit
for (ri = ris; ri != null; ri = ri.next) {
if ((ri.zoom & zoomMask) != 0) {
/* cache hit */
//log.debug(hitCount.incrementAndGet()
// + "/" + sameCount + "/" + missCount
// + " cache hit " + tags);
break;
}
}
}
if (ri == null) {
// cache miss
//log.debug(missCnt++ + " / " + hitCnt + " Cache Miss");
/* cache miss */
//missCount.incrementAndGet();
List<RenderStyle> matches = cache.instructionList;
matches.clear();
@ -176,13 +187,13 @@ public class RenderTheme implements IRenderTheme {
}
}
}
// check if same instructions are used in another level
/* check if same instructions are used in another level */
for (ri = ris; ri != null; ri = ri.next) {
if (size == 0) {
if (ri.list != null)
continue;
// both matchinglists are empty
/* both matchinglists are empty */
break;
}
@ -199,13 +210,13 @@ public class RenderTheme implements IRenderTheme {
i++;
}
if (i == size)
// both matching lists contain the same items
/* both matching lists contain the same items */
break;
}
if (ri != null) {
// we found a same matchting list on another zoomlevel add
// this zoom level to the existing RenderInstructionItem.
/* we found a same matchting list on another zoomlevel add
* this zoom level to the existing RenderInstructionItem. */
ri.zoom |= zoomMask;
//log.debug(zoomLevel + " same instructions " + size + " "
@ -222,7 +233,7 @@ public class RenderTheme implements IRenderTheme {
matches.toArray(ri.list);
}
// attach this list to the one found for MatchingKey
/* attach this list to the one found for MatchingKey */
if (ris != null) {
ri.next = ris.next;
ri.key = ris.key;
@ -233,34 +244,26 @@ public class RenderTheme implements IRenderTheme {
}
}
}
cache.prevItem = ri;
}
return ri.list;
}
void complete(List<Rule> rulesList, int levels) {
mLevels = levels;
mRules = new Rule[rulesList.size()];
rulesList.toArray(mRules);
for (int i = 0, n = mRules.length; i < n; i++) {
mRules[i].onComplete();
}
}
@Override
public void scaleTextSize(float scaleFactor) {
for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].scaleTextSize(scaleFactor * mBaseTextSize);
for (Rule rule : mRules)
rule.scaleTextSize(scaleFactor * mBaseTextSize);
}
@Override
public void updateInstructions() {
for (int i = 0, n = mRules.length; i < n; i++)
mRules[i].updateInstructions();
public void updateStyles() {
for (Rule rule : mRules)
rule.updateStyles();
}
public void traverseRules(RuleVisitor visitor) {
for (Rule rule : mRules)
rule.apply(visitor);
}
}

View File

@ -0,0 +1,125 @@
package org.oscim.theme;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;
import org.oscim.core.GeometryBuffer.GeometryType;
import org.oscim.core.Tag;
import org.oscim.core.TagSet;
import org.oscim.theme.rule.Element;
import org.oscim.theme.rule.Rule;
import org.oscim.theme.rule.RuleBuilder;
import org.oscim.theme.rule.Selector;
import org.oscim.theme.rule.SingleKeyMatcher;
import org.oscim.theme.rule.SingleValueMatcher;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.RenderStyle;
public class ThemeBuilder {
protected final ArrayList<RuleBuilder> mRulesList = new ArrayList<RuleBuilder>();
protected final Stack<RuleBuilder> mRuleStack = new Stack<RuleBuilder>();
protected int mLevels = 0;
protected int mMapBackground = 0xffffffff;
protected float mBaseTextSize = 1;
protected RuleBuilder mCurrentRule;
protected RenderTheme build() {
Rule[] rules = new Rule[mRulesList.size()];
for (int i = 0, n = rules.length; i < n; i++)
rules[i] = mRulesList.get(i).onComplete();
RenderTheme theme = new RenderTheme(mMapBackground, mBaseTextSize, rules, mLevels);
mRulesList.clear();
mRuleStack.clear();
return theme;
}
public ThemeBuilder pop() {
mRuleStack.pop();
if (mRuleStack.empty()) {
mRulesList.add(mCurrentRule);
} else {
mCurrentRule = mRuleStack.peek();
}
return this;
}
public ThemeBuilder push(RuleBuilder rule) {
if (!mRuleStack.empty())
mCurrentRule.addSubRule(rule);
mCurrentRule = rule;
mRuleStack.push(mCurrentRule);
return this;
}
public ThemeBuilder push(String key, String value) {
RuleBuilder b = new RuleBuilder(true, Element.ANY, ~0, 0,
key == null ? null : new SingleKeyMatcher(key),
value == null ? null : new SingleValueMatcher(value));
push(b);
return this;
}
public RuleBuilder pushParse(String keys, String values) {
return RuleBuilder.create(mRuleStack, keys, values)
.zoom(~0)
.element(Element.ANY);
}
public ThemeBuilder addStyle(RenderStyle style) {
mCurrentRule.addStyle(style);
return this;
}
public static void main(String[] args) {
ThemeBuilder b = new ThemeBuilder();
//b.pushParse("highway", "residential|primary|motorway")
b.push(RuleBuilder.get().select(Selector.FIRST))
.push("highway", null)
.addStyle(new LineStyle(1, 1, 1))
.pop()
.push(RuleBuilder.get().select(Selector.WHEN_MATCHED))
.addStyle(new AreaStyle(1, 1))
.pop()
.pop();
RenderTheme t = b.build();
TagSet tags = new TagSet(1);
RenderStyle[] styles;
tags.add(new Tag("ahighway", "residential"));
styles = t.matchElement(GeometryType.LINE, tags, 1);
System.out.println(Arrays.deepToString(styles));
// tags.clear();
// tags.add(new Tag("highway", "motorway"));
// styles = t.matchElement(GeometryType.LINE, tags, 1);
// out.println(styles);
//
// tags.clear();
// tags.add(new Tag("sup", "wup"));
// styles = t.matchElement(GeometryType.LINE, tags, 1);
// out.println(styles);
//
// tags.clear();
// tags.add(new Tag("highway", "motorway"));
// styles = t.matchElement(GeometryType.LINE, tags, 1);
// out.println(styles);
}
}

View File

@ -45,7 +45,7 @@ public class ThemeLoader {
InputStream inputStream = null;
try {
inputStream = theme.getRenderThemeAsStream();
IRenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
IRenderTheme t = XmlThemeBuilder.read(inputStream);
if (t != null)
t.scaleTextSize(CanvasAdapter.textScale + (CanvasAdapter.dpi / 240 - 1) * 0.5f);

View File

@ -17,6 +17,10 @@
*/
package org.oscim.theme;
import static java.lang.Boolean.parseBoolean;
import static java.lang.Float.parseFloat;
import static java.lang.Integer.parseInt;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@ -36,14 +40,17 @@ import org.oscim.renderer.atlas.TextureRegion;
import org.oscim.renderer.elements.TextureItem;
import org.oscim.theme.IRenderTheme.ThemeException;
import org.oscim.theme.rule.Rule;
import org.oscim.theme.styles.Area;
import org.oscim.theme.styles.Circle;
import org.oscim.theme.styles.Extrusion;
import org.oscim.theme.styles.Line;
import org.oscim.theme.styles.LineSymbol;
import org.oscim.theme.rule.RuleBuilder;
import org.oscim.theme.styles.AreaStyle;
import org.oscim.theme.styles.AreaStyle.AreaBuilder;
import org.oscim.theme.styles.CircleStyle;
import org.oscim.theme.styles.ExtrusionStyle;
import org.oscim.theme.styles.LineStyle;
import org.oscim.theme.styles.LineStyle.LineBuilder;
import org.oscim.theme.styles.RenderStyle;
import org.oscim.theme.styles.Symbol;
import org.oscim.theme.styles.Text;
import org.oscim.theme.styles.SymbolStyle;
import org.oscim.theme.styles.TextStyle;
import org.oscim.theme.styles.TextStyle.TextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
@ -51,8 +58,8 @@ import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
public class RenderThemeHandler extends DefaultHandler {
static final Logger log = LoggerFactory.getLogger(RenderThemeHandler.class);
public class XmlThemeBuilder extends DefaultHandler {
static final Logger log = LoggerFactory.getLogger(XmlThemeBuilder.class);
private static final int RENDER_THEME_VERSION = 1;
@ -60,7 +67,7 @@ public class RenderThemeHandler extends DefaultHandler {
RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE, ATLAS;
}
//private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
private static final String ELEMENT_NAME_MATCH = "m";
private static final String UNEXPECTED_ELEMENT = "unexpected element: ";
@ -82,10 +89,10 @@ public class RenderThemeHandler extends DefaultHandler {
* @throws IOException
* if an I/O error occurs while reading from the input stream.
*/
public static IRenderTheme getRenderTheme(InputStream inputStream)
public static IRenderTheme read(InputStream inputStream)
throws SAXException, IOException {
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
XmlThemeBuilder renderThemeHandler = new XmlThemeBuilder();
new XMLReaderAdapter().parse(renderThemeHandler, inputStream);
@ -118,36 +125,39 @@ public class RenderThemeHandler extends DefaultHandler {
log.debug(sb.toString());
}
private ArrayList<Rule> mRulesList = new ArrayList<Rule>();
private Rule mCurrentRule;
private Stack<Element> mElementStack = new Stack<Element>();
private Stack<Rule> mRuleStack = new Stack<Rule>();
private HashMap<String, RenderStyle> mStyles =
private final ArrayList<RuleBuilder> mRulesList = new ArrayList<RuleBuilder>();
private final Stack<Element> mElementStack = new Stack<Element>();
private final Stack<RuleBuilder> mRuleStack = new Stack<RuleBuilder>();
private final HashMap<String, RenderStyle> mStyles =
new HashMap<String, RenderStyle>(10);
private final TextBuilder mTextBuilder = new TextBuilder();
private final AreaBuilder mAreaBuilder = new AreaBuilder();
private final LineBuilder mLineBuilder = new LineBuilder();
private RuleBuilder mCurrentRule;
private TextureAtlas mTextureAtlas;
private int mLevel;
private int mLevels = 0;
private int mMapBackground = 0xffffffff;
private float mBaseTextSize = 1;
private RenderTheme mRenderTheme;
@Override
public void endDocument() {
if (mRenderTheme == null) {
throw new IllegalArgumentException("missing element: rules");
}
mRenderTheme.complete(mRulesList, mLevel);
Rule[] rules = new Rule[mRulesList.size()];
for (int i = 0, n = rules.length; i < n; i++)
rules[i] = mRulesList.get(i).onComplete();
mRenderTheme = new RenderTheme(mMapBackground, mBaseTextSize, rules, mLevels);
mRulesList.clear();
mStyles.clear();
mRuleStack.clear();
mElementStack.clear();
mStyles = null;
mRuleStack = null;
mRulesList = null;
mElementStack = null;
mTextureAtlas = null;
}
@ -179,13 +189,13 @@ public class RenderThemeHandler extends DefaultHandler {
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
try {
if ("rendertheme".equals(localName)) {
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) {
checkState(localName, Element.RENDER_THEME);
mRenderTheme = createRenderTheme(localName, attributes);
createRenderTheme(localName, attributes);
} else if (ELEMENT_NAME_MATCH.equals(localName)) {
checkState(localName, Element.RULE);
Rule rule = Rule.create(localName, attributes, mRuleStack);
RuleBuilder rule = RuleBuilder.create(localName, attributes, mRuleStack);
if (!mRuleStack.empty()) {
mCurrentRule.addSubRule(rule);
}
@ -194,7 +204,7 @@ public class RenderThemeHandler extends DefaultHandler {
} else if ("style-text".equals(localName)) {
checkState(localName, Element.STYLE);
Text text = createText(localName, attributes, false);
TextStyle text = createText(localName, attributes, false);
mStyles.put(TEXT_STYLE + text.style, text);
} else if ("style-area".equals(localName)) {
@ -207,7 +217,7 @@ public class RenderThemeHandler extends DefaultHandler {
} else if ("outline-layer".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Line line = createLine(null, localName, attributes, mLevel++, true);
LineStyle line = createLine(null, localName, attributes, mLevels++, true);
mStyles.put(OUTLINE_STYLE + line.style, line);
} else if ("area".equals(localName)) {
@ -216,40 +226,35 @@ public class RenderThemeHandler extends DefaultHandler {
} else if ("caption".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Text text = createText(localName, attributes, true);
mCurrentRule.addRenderingInstruction(text);
TextStyle text = createText(localName, attributes, true);
mCurrentRule.addStyle(text);
} else if ("circle".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Circle circle = createCircle(localName, attributes, mLevel++);
mCurrentRule.addRenderingInstruction(circle);
CircleStyle circle = createCircle(localName, attributes, mLevels++);
mCurrentRule.addStyle(circle);
} else if ("line".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
handleLineElement(localName, attributes, false);
} else if ("lineSymbol".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
LineSymbol lineSymbol = createLineSymbol(localName, attributes);
mCurrentRule.addRenderingInstruction(lineSymbol);
} else if ("text".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
String style = attributes.getValue("use");
if (style == null) {
Text text = createText(localName, attributes, false);
mCurrentRule.addRenderingInstruction(text);
TextStyle text = createText(localName, attributes, false);
mCurrentRule.addStyle(text);
} else {
Text pt = (Text) mStyles.get(TEXT_STYLE + style);
TextStyle pt = (TextStyle) mStyles.get(TEXT_STYLE + style);
if (pt != null)
mCurrentRule.addRenderingInstruction(pt);
mCurrentRule.addStyle(pt);
else
log.debug("BUG not a path text style: " + style);
}
} else if ("symbol".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Symbol symbol = createSymbol(localName, attributes);
mCurrentRule.addRenderingInstruction(symbol);
SymbolStyle symbol = createSymbol(localName, attributes);
mCurrentRule.addStyle(symbol);
} else if ("outline".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
@ -257,8 +262,8 @@ public class RenderThemeHandler extends DefaultHandler {
} else if ("extrusion".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Extrusion extrusion = createExtrusion(localName, attributes, mLevel++);
mCurrentRule.addRenderingInstruction(extrusion);
ExtrusionStyle extrusion = createExtrusion(localName, attributes, mLevels++);
mCurrentRule.addStyle(extrusion);
} else if ("atlas".equals(localName)) {
checkState(localName, Element.ATLAS);
@ -295,22 +300,22 @@ public class RenderThemeHandler extends DefaultHandler {
throws SAXException {
String use = attributes.getValue("use");
Line style = null;
LineStyle style = null;
if (use != null) {
style = (Line) mStyles.get(LINE_STYLE + use);
style = (LineStyle) mStyles.get(LINE_STYLE + use);
if (style == null) {
log.debug("missing line style 'use': " + use);
return;
}
}
Line line = createLine(style, localName, attributes, mLevel++, false);
LineStyle line = createLine(style, localName, attributes, mLevels++, false);
if (isStyle) {
mStyles.put(LINE_STYLE + line.style, line);
} else {
mCurrentRule.addRenderingInstruction(line);
mCurrentRule.addStyle(line);
// Note 'outline' will not be inherited, it's just a
// shorcut to add the outline RenderInstruction.
addOutline(attributes.getValue("outline"));
@ -320,53 +325,24 @@ public class RenderThemeHandler extends DefaultHandler {
/**
* @param line
* optional: line style defaults
* @param elementName
* the name of the XML element.
* @param attributes
* the attributes of the XML element.
* @param level
* the drawing level of this instruction.
* @param isOutline
* is outline layer
* @return a new Line with the given rendering attributes.
*/
private static Line createLine(Line line, String elementName, Attributes attributes,
private LineStyle createLine(LineStyle line, String elementName, Attributes attributes,
int level, boolean isOutline) {
// Style name
String style = null;
float width = 0;
Cap cap = Cap.ROUND;
// Extras
int fade = -1;
boolean fixed = false;
float blur = 0;
// Stipple
int stipple = 0;
float stippleWidth = 1;
int color = Color.TRANSPARENT;
int stippleColor = Color.BLACK;
if (line != null) {
color = line.color;
fixed = line.fixed;
fade = line.fade;
cap = line.cap;
blur = line.blur;
stipple = line.stipple;
stippleColor = line.stippleColor;
stippleWidth = line.stippleWidth;
}
LineBuilder b = mLineBuilder.set(line);
b.isOutline(isOutline);
b.level(level);
for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
if ("id".equals(name))
style = value;
b.style = value;
else if ("src".equals(name))
;// src = value;
@ -378,34 +354,43 @@ public class RenderThemeHandler extends DefaultHandler {
;// ignore
else if ("stroke".equals(name))
color = Color.parseColor(value);
else if ("width".equals(name) || "stroke-width".equals(name))
width = Float.parseFloat(value);
b.color(value);
else if ("width".equals(name) || "stroke-width".equals(name)) {
float width = parseFloat(value);
if (line == null) {
validateNonNegative("width", width);
} else {
/* use stroke width relative to 'line' */
width += line.width;
if (width <= 0)
width = 1;
}
b.width = width;
}
else if ("cap".equals(name) || "stroke-linecap".equals(name))
cap = Cap.valueOf(value.toUpperCase());
b.cap = Cap.valueOf(value.toUpperCase());
else if ("fix".equals(name))
fixed = Boolean.parseBoolean(value);
b.fixed = parseBoolean(value);
else if ("stipple".equals(name))
stipple = Integer.parseInt(value);
b.stipple = parseInt(value);
else if ("stipple-stroke".equals(name))
stippleColor = Color.parseColor(value);
b.stippleColor(value);
else if ("stipple-width".equals(name))
stippleWidth = Float.parseFloat(value);
b.stippleWidth = parseFloat(value);
else if ("fade".equals(name))
fade = Integer.parseInt(value);
b.fadeScale = Integer.parseInt(value);
else if ("min".equals(name))
; //min = Float.parseFloat(value);
else if ("blur".equals(name))
blur = Float.parseFloat(value);
b.blur = parseFloat(value);
else if ("style".equals(name))
; // ignore
@ -416,92 +401,49 @@ public class RenderThemeHandler extends DefaultHandler {
else
logUnknownAttribute(elementName, name, value, i);
}
// inherit properties from 'line'
if (line != null) {
// use stroke width relative to 'line'
width = line.width + width;
if (width <= 0)
width = 1;
} else if (!isOutline) {
validateLine(width);
}
return new Line(level, style, color, width, cap, fixed,
stipple, stippleColor, stippleWidth,
fade, blur, isOutline);
}
private static void validateLine(float strokeWidth) {
if (strokeWidth < 0)
throw new ThemeException("width must not be negative: " + strokeWidth);
return b.build();
}
private void handleAreaElement(String localName, Attributes attributes, boolean isStyle)
throws SAXException {
String use = attributes.getValue("use");
Area style = null;
AreaStyle style = null;
if (use != null) {
style = (Area) mStyles.get(AREA_STYLE + use);
style = (AreaStyle) mStyles.get(AREA_STYLE + use);
if (style == null) {
log.debug("missing area style 'use': " + use);
return;
}
}
Area area = createArea(style, localName, attributes, mLevel);
mLevel += 2;
AreaStyle area = createArea(style, localName, attributes, mLevels);
mLevels += 2;
if (isStyle) {
mStyles.put(AREA_STYLE + area.style, area);
} else {
mCurrentRule.addRenderingInstruction(area);
mCurrentRule.addStyle(area);
}
}
/**
* @param elementName
* the name of the XML element.
* @param attributes
* the attributes of the XML element.
* @param level
* the drawing level of this instruction.
* @return a new Area with the given rendering attributes.
*/
private static Area createArea(Area area, String elementName, Attributes attributes, int level) {
private AreaStyle createArea(AreaStyle area, String elementName, Attributes attributes,
int level) {
AreaBuilder b = mAreaBuilder.set(area);
b.level(level);
String src = null;
int fill = Color.BLACK;
int stroke = Color.TRANSPARENT;
float strokeWidth = 1;
int fade = -1;
int blend = -1;
int blendFill = Color.TRANSPARENT;
String style = null;
TextureItem texture = null;
if (area != null) {
fill = area.color;
blend = area.blend;
blendFill = area.blendColor;
fade = area.fade;
// TODO texture = area.texture
if (area.outline != null) {
stroke = area.outline.color;
strokeWidth = area.outline.width;
}
}
for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
if ("id".equals(name))
style = value;
b.style = value;
else if ("use".equals(name))
;// ignore
@ -510,47 +452,46 @@ public class RenderThemeHandler extends DefaultHandler {
src = value;
else if ("fill".equals(name))
fill = Color.parseColor(value);
b.color(value);
else if ("stroke".equals(name))
stroke = Color.parseColor(value);
b.outlineColor(value);
else if ("stroke-width".equals(name))
strokeWidth = Float.parseFloat(value);
else if ("stroke-width".equals(name)) {
float strokeWidth = Float.parseFloat(value);
validateNonNegative("stroke-width", strokeWidth);
b.outlineWidth = strokeWidth;
else if ("fade".equals(name))
fade = Integer.parseInt(value);
} else if ("fade".equals(name))
b.fadeScale = Integer.parseInt(value);
else if ("blend".equals(name))
blend = Integer.parseInt(value);
b.blendScale = Integer.parseInt(value);
else if ("blend-fill".equals(name))
blendFill = Color.parseColor(value);
b.blendColor(value);
else
logUnknownAttribute(elementName, name, value, i);
}
validateLine(strokeWidth);
if (src != null) {
try {
Bitmap b = CanvasAdapter.g.loadBitmapAsset(src);
if (b != null)
texture = new TextureItem(b, true);
Bitmap bitmap = CanvasAdapter.g.loadBitmapAsset(src);
if (bitmap != null)
b.texture = new TextureItem(bitmap, true);
} catch (Exception e) {
log.debug(e.getMessage());
}
}
return new Area(style, fill, stroke, strokeWidth, fade, level, blend,
blendFill, texture);
return b.build();
}
private void addOutline(String style) {
if (style != null) {
Line line = (Line) mStyles.get(OUTLINE_STYLE + style);
LineStyle line = (LineStyle) mStyles.get(OUTLINE_STYLE + style);
if (line != null && line.outline)
mCurrentRule.addRenderingInstruction(line);
mCurrentRule.addStyle(line);
else
log.debug("BUG not an outline style: " + style);
}
@ -566,11 +507,10 @@ public class RenderThemeHandler extends DefaultHandler {
if ("img".equals(name)) {
img = value;
} else {
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i);
}
}
if (img == null)
throw new ThemeException("missing attribute 'img' for element: " + elementName);
validateExists("img", img, elementName);
Bitmap bitmap = CanvasAdapter.g.loadBitmapAsset(IMG_PATH + img);
mTextureAtlas = new TextureAtlas(bitmap);
@ -595,12 +535,11 @@ public class RenderThemeHandler extends DefaultHandler {
Integer.parseInt(pos[3]));
}
} else {
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i);
}
}
if (regionName == null || r == null)
throw new ThemeException("missing attribute 'id' or 'rect' for element: "
+ elementName);
validateExists("id", regionName, elementName);
validateExists("pos", r, elementName);
mTextureAtlas.addTextureRegion(regionName.intern(), r);
}
@ -652,7 +591,7 @@ public class RenderThemeHandler extends DefaultHandler {
mElementStack.push(element);
}
static RenderTheme createRenderTheme(String elementName, Attributes attributes) {
private void createRenderTheme(String elementName, Attributes attributes) {
Integer version = null;
int mapBackground = Color.WHITE;
float baseStrokeWidth = 1;
@ -678,115 +617,91 @@ public class RenderThemeHandler extends DefaultHandler {
baseTextSize = Float.parseFloat(value);
else
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i);
}
if (version == null)
throw new ThemeException("missing attribute version for element:" + elementName);
else if (version.intValue() != RENDER_THEME_VERSION)
throw new ThemeException("invalid render theme version:" + version);
else if (baseStrokeWidth < 0)
throw new ThemeException("base-stroke-width must not be negative: " + baseStrokeWidth);
else if (baseTextSize < 0)
throw new ThemeException("base-text-size must not be negative: " + baseTextSize);
validateExists("version", version, elementName);
return new RenderTheme(mapBackground, baseStrokeWidth, baseTextSize);
if (version.intValue() != RENDER_THEME_VERSION)
throw new ThemeException("invalid render theme version:"
+ version);
validateNonNegative("base-stroke-width", baseStrokeWidth);
validateNonNegative("base-test-size", baseTextSize);
mMapBackground = mapBackground;
mBaseTextSize = baseTextSize;
}
/**
* @param elementName
* the name of the XML element.
* @param attributes
* the attributes of the XML element.
* @param caption
* ...
* @return a new Text with the given rendering attributes.
*/
private Text createText(String elementName, Attributes attributes, boolean caption) {
String textKey = null;
FontFamily fontFamily = FontFamily.DEFAULT;
FontStyle fontStyle = FontStyle.NORMAL;
float fontSize = 0;
int fill = Color.BLACK;
int stroke = Color.BLACK;
float strokeWidth = 0;
String style = null;
float dy = 0;
int priority = Integer.MAX_VALUE;
TextureRegion symbol = null;
private TextStyle createText(String elementName, Attributes attributes, boolean caption) {
TextBuilder b = mTextBuilder.reset();
b.caption = caption;
for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
if ("id".equals(name))
style = value;
b.style = value;
else if ("k".equals(name))
textKey = value.intern();
b.textKey = value.intern();
else if ("font-family".equals(name))
fontFamily = FontFamily.valueOf(value.toUpperCase());
b.fontFamily = FontFamily.valueOf(value.toUpperCase());
else if ("style".equals(name))
fontStyle = FontStyle.valueOf(value.toUpperCase());
b.fontStyle = FontStyle.valueOf(value.toUpperCase());
else if ("size".equals(name))
fontSize = Float.parseFloat(value);
b.fontSize = Float.parseFloat(value);
else if ("fill".equals(name))
fill = Color.parseColor(value);
b.color = Color.parseColor(value);
else if ("stroke".equals(name))
stroke = Color.parseColor(value);
b.stroke = Color.parseColor(value);
else if ("stroke-width".equals(name))
strokeWidth = Float.parseFloat(value);
b.strokeWidth = Float.parseFloat(value);
else if ("caption".equals(name))
caption = Boolean.parseBoolean(value);
b.caption = Boolean.parseBoolean(value);
else if ("priority".equals(name))
priority = Integer.parseInt(value);
b.priority = Integer.parseInt(value);
else if ("dy".equals(name))
dy = Float.parseFloat(value);
// NB: minus..
b.dy = -Float.parseFloat(value);
else if ("symbol".equals(name))
symbol = getAtlasRegion(value);
b.texture = getAtlasRegion(value);
else
logUnknownAttribute(elementName, name, value, i);
}
validateText(elementName, textKey, fontSize, strokeWidth);
validateExists("k", b.textKey, elementName);
validateNonNegative("size", b.fontSize);
validateNonNegative("stroke-width", b.strokeWidth);
return new Text(style, textKey, fontFamily, fontStyle, fontSize, fill, stroke, strokeWidth,
dy, caption, symbol, priority);
}
private static void validateText(String elementName, String textKey, float fontSize,
float strokeWidth) {
if (textKey == null)
throw new ThemeException("missing attribute k for element: " + elementName);
else if (fontSize < 0)
throw new ThemeException("font-size must not be negative: " + fontSize);
else if (strokeWidth < 0)
throw new ThemeException("stroke-width must not be negative: " + strokeWidth);
return b.buildInternal();
}
/**
* @param elementName
* the name of the XML element.
* @param attributes
* the attributes of the XML element.
* @param level
* the drawing level of this instruction.
* @return a new Circle with the given rendering attributes.
*/
private static Circle createCircle(String elementName, Attributes attributes, int level) {
private static CircleStyle createCircle(String elementName, Attributes attributes, int level) {
Float radius = null;
boolean scaleRadius = false;
int fill = Color.TRANSPARENT;
@ -816,60 +731,17 @@ public class RenderThemeHandler extends DefaultHandler {
logUnknownAttribute(elementName, name, value, i);
}
validateCircle(elementName, radius, strokeWidth);
return new Circle(radius, scaleRadius, fill, stroke, strokeWidth, level);
}
validateExists("r", radius, elementName);
validateNonNegative("radius", radius);
validateNonNegative("stroke-width", strokeWidth);
private static void validateCircle(String elementName, Float radius, float strokeWidth) {
if (radius == null)
throw new ThemeException("missing attribute r for element: " + elementName);
else if (radius.floatValue() < 0)
throw new ThemeException("radius must not be negative: " + radius);
else if (strokeWidth < 0)
throw new ThemeException("stroke-width must not be negative: " + strokeWidth);
return new CircleStyle(radius, scaleRadius, fill, stroke, strokeWidth, level);
}
/**
* @param elementName
* the name of the XML element.
* @param attributes
* the attributes of the XML element.
* @return a new LineSymbol with the given rendering attributes.
*/
private static LineSymbol createLineSymbol(String elementName, Attributes attributes) {
String src = null;
boolean alignCenter = false;
boolean repeat = false;
for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
if ("src".equals(name))
src = value;
else if ("align-center".equals(name))
alignCenter = Boolean.parseBoolean(value);
else if ("repeat".equals(name))
repeat = Boolean.parseBoolean(value);
else
logUnknownAttribute(elementName, name, value, i);
}
validateSymbol(elementName, src);
return new LineSymbol(src, alignCenter, repeat);
}
/**
* @param elementName
* the name of the XML element.
* @param attributes
* the attributes of the XML element.
* @return a new Symbol with the given rendering attributes.
*/
private Symbol createSymbol(String elementName, Attributes attributes) {
private SymbolStyle createSymbol(String elementName, Attributes attributes) {
String src = null;
for (int i = 0; i < attributes.getLength(); ++i) {
@ -882,17 +754,12 @@ public class RenderThemeHandler extends DefaultHandler {
logUnknownAttribute(elementName, name, value, i);
}
validateSymbol(elementName, src);
validateExists("src", src, elementName);
return new Symbol(getAtlasRegion(src));
return new SymbolStyle(getAtlasRegion(src));
}
private static void validateSymbol(String elementName, String src) {
if (src == null)
throw new ThemeException("missing attribute src for element: " + elementName);
}
private Extrusion createExtrusion(String elementName, Attributes attributes, int level) {
private ExtrusionStyle createExtrusion(String elementName, Attributes attributes, int level) {
int colorSide = 0;
int colorTop = 0;
int colorLine = 0;
@ -918,6 +785,18 @@ public class RenderThemeHandler extends DefaultHandler {
logUnknownAttribute(elementName, name, value, i);
}
return new Extrusion(level, colorSide, colorTop, colorLine, defaultHeight);
return new ExtrusionStyle(level, colorSide, colorTop, colorLine, defaultHeight);
}
public static void validateNonNegative(String name, float value) {
if (value < 0)
throw new ThemeException(name + " must not be negative: "
+ value);
}
public static void validateExists(String name, Object obj, String elementName) {
if (obj == null)
throw new ThemeException("missing attribute " + name
+ " for element: " + elementName);
}
}

View File

@ -1,6 +1,4 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
/* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*

View File

@ -18,12 +18,14 @@
package org.oscim.theme.rule;
import org.oscim.core.Tag;
import org.oscim.theme.styles.RenderStyle;
class NegativeRule extends Rule {
final AttributeMatcher mAttributeMatcher;
NegativeRule(int element, int zoom, boolean matchFirst, AttributeMatcher attributeMatcher) {
super(element, zoom, matchFirst);
NegativeRule(int element, int zoom, int selector, AttributeMatcher attributeMatcher,
Rule[] subRules, RenderStyle[] styles) {
super(element, zoom, selector, subRules, styles);
mAttributeMatcher = attributeMatcher;
}

View File

@ -18,14 +18,15 @@
package org.oscim.theme.rule;
import org.oscim.core.Tag;
import org.oscim.theme.styles.RenderStyle;
class PositiveRule extends Rule {
final AttributeMatcher mKeyMatcher;
final AttributeMatcher mValueMatcher;
PositiveRule(int element, int zoom, boolean matchFirst, AttributeMatcher keyMatcher,
AttributeMatcher valueMatcher) {
super(element, zoom, matchFirst);
PositiveRule(int element, int zoom, int selector, AttributeMatcher keyMatcher,
AttributeMatcher valueMatcher, Rule[] subRules, RenderStyle[] styles) {
super(element, zoom, selector, subRules, styles);
if (keyMatcher instanceof AnyMatcher)
mKeyMatcher = null;

View File

@ -1,5 +1,4 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
@ -17,305 +16,138 @@
*/
package org.oscim.theme.rule;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.oscim.core.Tag;
import org.oscim.theme.IRenderTheme.ThemeException;
import org.oscim.theme.RenderThemeHandler;
import org.oscim.theme.styles.RenderStyle;
import org.xml.sax.Attributes;
public abstract class Rule {
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_KEY =
new HashMap<List<String>, AttributeMatcher>();
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE =
new HashMap<List<String>, AttributeMatcher>();
public final static RenderStyle[] EMPTY_STYLE = new RenderStyle[0];
public final static Rule[] EMPTY_RULES = new Rule[0];
private static final String STRING_NEGATION = "~";
private static final String STRING_EXCLUSIVE = "-";
private static final String STRING_WILDCARD = "*";
private final Rule[] subRules;
public final RenderStyle[] styles;
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
String values, byte zoomMin, byte zoomMax, boolean matchFirst) {
private final int zoom;
private final int element;
private final boolean selectFirstMatch;
private final boolean selectWhenMatched;
// zoom-level bitmask
int zoom = 0;
for (int z = zoomMin; z <= zoomMax && z < 32; z++)
zoom |= (1 << z);
Rule(int element, int zoom, int selector, Rule[] subRules, RenderStyle[] styles) {
this.element = element;
this.zoom = zoom;
List<String> keyList = null, valueList = null;
boolean negativeRule = false;
boolean exclusionRule = false;
this.subRules = (subRules == null) ? EMPTY_RULES : subRules;
this.styles = (styles == null) ? EMPTY_STYLE : styles;
AttributeMatcher keyMatcher, valueMatcher = null;
if (values == null) {
valueMatcher = AnyMatcher.getInstance();
} else {
valueList = new ArrayList<String>(Arrays.asList(values.split("\\|")));
if (valueList.remove(STRING_NEGATION))
negativeRule = true;
else if (valueList.remove(STRING_EXCLUSIVE))
exclusionRule = true;
else {
valueMatcher = getValueMatcher(valueList);
valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack);
}
}
if (keys == null) {
if (negativeRule || exclusionRule) {
throw new ThemeException("negative rule requires key");
}
keyMatcher = AnyMatcher.getInstance();
} else {
keyList = new ArrayList<String>(Arrays.asList(keys.split("\\|")));
keyMatcher = getKeyMatcher(keyList);
if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) {
throw new ThemeException("negative rule requires key");
}
if (negativeRule) {
AttributeMatcher m = new NegativeMatcher(keyList, valueList, false);
return new NegativeRule(element, zoom, matchFirst, m);
} else if (exclusionRule) {
AttributeMatcher m = new NegativeMatcher(keyList, valueList, true);
return new NegativeRule(element, zoom, matchFirst, m);
}
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
}
return new PositiveRule(element, zoom, matchFirst, keyMatcher, valueMatcher);
}
private static AttributeMatcher getKeyMatcher(List<String> keyList) {
if (STRING_WILDCARD.equals(keyList.get(0))) {
return AnyMatcher.getInstance();
}
AttributeMatcher attributeMatcher = MATCHERS_CACHE_KEY.get(keyList);
if (attributeMatcher == null) {
if (keyList.size() == 1) {
attributeMatcher = new SingleKeyMatcher(keyList.get(0));
} else {
attributeMatcher = new MultiKeyMatcher(keyList);
}
MATCHERS_CACHE_KEY.put(keyList, attributeMatcher);
}
return attributeMatcher;
}
private static AttributeMatcher getValueMatcher(List<String> valueList) {
if (STRING_WILDCARD.equals(valueList.get(0))) {
return AnyMatcher.getInstance();
}
AttributeMatcher attributeMatcher = MATCHERS_CACHE_VALUE.get(valueList);
if (attributeMatcher == null) {
if (valueList.size() == 1) {
attributeMatcher = new SingleValueMatcher(valueList.get(0));
} else {
attributeMatcher = new MultiValueMatcher(valueList);
}
MATCHERS_CACHE_VALUE.put(valueList, attributeMatcher);
}
return attributeMatcher;
}
private static void validate(byte zoomMin, byte zoomMax) {
if (zoomMin < 0)
throw new ThemeException("zoom-min must not be negative: " + zoomMin);
else if (zoomMax < 0)
throw new ThemeException("zoom-max must not be negative: " + zoomMax);
else if (zoomMin > zoomMax)
throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin);
}
public static Rule create(String elementName, Attributes attributes, Stack<Rule> ruleStack) {
int element = Element.ANY;
int closed = Closed.ANY;
String keys = null;
String values = null;
byte zoomMin = 0;
byte zoomMax = Byte.MAX_VALUE;
boolean matchFirst = false;
for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
if ("e".equals(name)) {
String val = value.toUpperCase();
if ("WAY".equals(val))
element = Element.WAY;
else if ("NODE".equals(val))
element = Element.NODE;
} else if ("k".equals(name)) {
keys = value;
} else if ("v".equals(name)) {
values = value;
} else if ("closed".equals(name)) {
String val = value.toUpperCase();
if ("YES".equals(val))
closed = Closed.YES;
else if ("NO".equals(val))
closed = Closed.NO;
} else if ("zoom-min".equals(name)) {
zoomMin = Byte.parseByte(value);
} else if ("zoom-max".equals(name)) {
zoomMax = Byte.parseByte(value);
} else if ("select".equals(name)) {
matchFirst = "first".equals(value);
} else {
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
}
}
if (closed == Closed.YES)
element = Element.POLY;
else if (closed == Closed.NO)
element = Element.LINE;
validate(zoomMin, zoomMax);
return createRule(ruleStack, element, keys, values, zoomMin, zoomMax, matchFirst);
}
private Rule[] mSubRules;
private RenderStyle[] mRenderInstructions;
final int mZoom;
final int mElement;
final boolean mMatchFirst;
static class Builder {
ArrayList<RenderStyle> renderInstructions = new ArrayList<RenderStyle>(4);
ArrayList<Rule> subRules = new ArrayList<Rule>(4);
public void clear() {
renderInstructions.clear();
renderInstructions = null;
subRules.clear();
subRules = null;
}
}
private Builder builder;
Rule(int type, int zoom, boolean matchFirst) {
builder = new Builder();
mElement = type;
mZoom = zoom;
mMatchFirst = matchFirst;
}
public void addRenderingInstruction(RenderStyle renderInstruction) {
builder.renderInstructions.add(renderInstruction);
}
public void addSubRule(Rule rule) {
builder.subRules.add(rule);
selectFirstMatch = (selector & Selector.FIRST) != 0;
selectWhenMatched = (selector & Selector.WHEN_MATCHED) != 0;
}
abstract boolean matchesTags(Tag[] tags);
public boolean matchElement(int type, Tag[] tags, int zoomLevel,
List<RenderStyle> matchingList) {
if (((mElement & type) != 0) && ((mZoom & zoomLevel) != 0) && (matchesTags(tags))) {
public boolean matchElement(int type, Tag[] tags, int zoomLevel, List<RenderStyle> result) {
if (((element & type) != 0) && ((zoom & zoomLevel) != 0) && (matchesTags(tags))) {
boolean matched = false;
// check subrules
for (Rule subRule : mSubRules) {
if (subRule.matchElement(type, tags, zoomLevel, matchingList) && mMatchFirst) {
matched = true;
break;
if (subRules != EMPTY_RULES) {
if (selectFirstMatch) {
/* only add first matching rule and when-matched rules iff a
* previous rule matched */
for (Rule r : subRules) {
/* continue if matched xor selectWhenMatch */
if (matched ^ r.selectWhenMatched)
continue;
if (r.matchElement(type, tags, zoomLevel, result))
matched = true;
}
} else {
/* add all rules and when-matched rules iff a previous rule
* matched */
for (Rule r : subRules) {
if (r.selectWhenMatched && !matched)
continue;
if (r.matchElement(type, tags, zoomLevel, result))
matched = true;
}
}
}
if (!mMatchFirst || matched) {
// add instructions for this rule
for (RenderStyle ri : mRenderInstructions)
matchingList.add(ri);
}
if (styles == EMPTY_STYLE)
/* matched if styles where added */
return matched;
// this rule did match
/* add instructions for this rule */
for (RenderStyle ri : styles)
result.add(ri);
/* this rule did not match */
return true;
}
// this rule did not match
/* this rule did not match */
return false;
}
public void onComplete() {
MATCHERS_CACHE_KEY.clear();
MATCHERS_CACHE_VALUE.clear();
public void dispose() {
for (RenderStyle ri : styles)
ri.dispose();
mRenderInstructions = new RenderStyle[builder.renderInstructions.size()];
builder.renderInstructions.toArray(mRenderInstructions);
mSubRules = new Rule[builder.subRules.size()];
builder.subRules.toArray(mSubRules);
builder.clear();
builder = null;
for (Rule subRule : mSubRules)
subRule.onComplete();
}
public void onDestroy() {
for (RenderStyle ri : mRenderInstructions)
ri.destroy();
for (Rule subRule : mSubRules)
subRule.onDestroy();
for (Rule subRule : subRules)
subRule.dispose();
}
public void scaleTextSize(float scaleFactor) {
for (RenderStyle ri : mRenderInstructions)
for (RenderStyle ri : styles)
ri.scaleTextSize(scaleFactor);
for (Rule subRule : mSubRules)
for (Rule subRule : subRules)
subRule.scaleTextSize(scaleFactor);
}
public void updateInstructions() {
for (RenderStyle ri : mRenderInstructions)
public void updateStyles() {
for (RenderStyle ri : styles)
ri.update();
for (Rule subRule : mSubRules)
subRule.updateInstructions();
for (Rule subRule : subRules)
subRule.updateStyles();
}
public static class RuleVisitor {
boolean apply(Rule r) {
for (Rule subRule : r.mSubRules)
public void apply(Rule r) {
for (Rule subRule : r.subRules)
this.apply(subRule);
}
}
return true;
public static class TextSizeVisitor extends RuleVisitor {
float scaleFactor = 1;
public void setScaleFactor(float scaleFactor) {
this.scaleFactor = scaleFactor;
}
@Override
public void apply(Rule r) {
for (RenderStyle ri : r.styles)
ri.scaleTextSize(scaleFactor);
super.apply(r);
}
}
public static class UpdateVisitor extends RuleVisitor {
@Override
boolean apply(Rule r) {
for (RenderStyle ri : r.mRenderInstructions)
public void apply(Rule r) {
for (RenderStyle ri : r.styles)
ri.update();
return super.apply(r);
super.apply(r);
}
}
public boolean apply(RuleVisitor v) {
return v.apply(this);
public void apply(RuleVisitor v) {
v.apply(this);
}
}

View File

@ -0,0 +1,271 @@
package org.oscim.theme.rule;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import org.oscim.theme.IRenderTheme.ThemeException;
import org.oscim.theme.XmlThemeBuilder;
import org.oscim.theme.styles.RenderStyle;
import org.xml.sax.Attributes;
public class RuleBuilder {
boolean positiveRule;
int zoom;
int element;
int selector;
AttributeMatcher keyMatcher;
AttributeMatcher valueMatcher;
ArrayList<RenderStyle> renderStyles = new ArrayList<RenderStyle>(4);
ArrayList<RuleBuilder> subRules = new ArrayList<RuleBuilder>(4);
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_KEY =
new HashMap<List<String>, AttributeMatcher>();
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE =
new HashMap<List<String>, AttributeMatcher>();
private static final String STRING_NEGATION = "~";
private static final String STRING_EXCLUSIVE = "-";
private static final String STRING_WILDCARD = "*";
private static final int SELECT_FIRST = 1 << 0;
private static final int SELECT_WHEN_MATCHED = 1 << 1;
public RuleBuilder(boolean positive, int element, int zoom, int selector,
AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
this.positiveRule = positive;
this.element = element;
this.zoom = zoom;
this.selector = selector;
this.keyMatcher = keyMatcher;
this.valueMatcher = valueMatcher;
}
public RuleBuilder(boolean positive, AttributeMatcher keyMatcher, AttributeMatcher valueMatcher) {
this.positiveRule = positive;
this.keyMatcher = keyMatcher;
this.valueMatcher = valueMatcher;
}
public static RuleBuilder create(Stack<RuleBuilder> ruleStack, String keys, String values) {
List<String> keyList = null, valueList = null;
boolean negativeRule = false;
boolean exclusionRule = false;
AttributeMatcher keyMatcher, valueMatcher = null;
if (values == null) {
valueMatcher = AnyMatcher.getInstance();
} else {
valueList = new ArrayList<String>(Arrays.asList(values.split("\\|")));
if (valueList.remove(STRING_NEGATION))
negativeRule = true;
else if (valueList.remove(STRING_EXCLUSIVE))
exclusionRule = true;
else {
valueMatcher = getValueMatcher(valueList);
valueMatcher = RuleOptimizer.optimize(valueMatcher, ruleStack);
}
}
if (keys == null) {
if (negativeRule || exclusionRule) {
throw new ThemeException("negative rule requires key");
}
keyMatcher = AnyMatcher.getInstance();
} else {
keyList = new ArrayList<String>(Arrays.asList(keys.split("\\|")));
keyMatcher = getKeyMatcher(keyList);
if ((keyMatcher instanceof AnyMatcher) && (negativeRule || exclusionRule)) {
throw new ThemeException("negative rule requires key");
}
if (negativeRule) {
AttributeMatcher m = new NegativeMatcher(keyList, valueList, false);
return new RuleBuilder(false, m, null);
} else if (exclusionRule) {
AttributeMatcher m = new NegativeMatcher(keyList, valueList, true);
return new RuleBuilder(false, m, null);
}
keyMatcher = RuleOptimizer.optimize(keyMatcher, ruleStack);
}
return new RuleBuilder(true, keyMatcher, valueMatcher);
}
private static AttributeMatcher getKeyMatcher(List<String> keyList) {
if (STRING_WILDCARD.equals(keyList.get(0))) {
return AnyMatcher.getInstance();
}
AttributeMatcher attributeMatcher = MATCHERS_CACHE_KEY.get(keyList);
if (attributeMatcher == null) {
if (keyList.size() == 1) {
attributeMatcher = new SingleKeyMatcher(keyList.get(0));
} else {
attributeMatcher = new MultiKeyMatcher(keyList);
}
MATCHERS_CACHE_KEY.put(keyList, attributeMatcher);
}
return attributeMatcher;
}
private static AttributeMatcher getValueMatcher(List<String> valueList) {
if (STRING_WILDCARD.equals(valueList.get(0))) {
return AnyMatcher.getInstance();
}
AttributeMatcher attributeMatcher = MATCHERS_CACHE_VALUE.get(valueList);
if (attributeMatcher == null) {
if (valueList.size() == 1) {
attributeMatcher = new SingleValueMatcher(valueList.get(0));
} else {
attributeMatcher = new MultiValueMatcher(valueList);
}
MATCHERS_CACHE_VALUE.put(valueList, attributeMatcher);
}
return attributeMatcher;
}
private static void validate(byte zoomMin, byte zoomMax) {
XmlThemeBuilder.validateNonNegative("zoom-min", zoomMin);
XmlThemeBuilder.validateNonNegative("zoom-max", zoomMax);
if (zoomMin > zoomMax)
throw new ThemeException("zoom-min must be less or equal zoom-max: " + zoomMin);
}
public static RuleBuilder create(String elementName, Attributes attributes,
Stack<RuleBuilder> ruleStack) {
int element = Element.ANY;
int closed = Closed.ANY;
String keys = null;
String values = null;
byte zoomMin = 0;
byte zoomMax = Byte.MAX_VALUE;
int selector = 0;
for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
if ("e".equals(name)) {
String val = value.toUpperCase();
if ("WAY".equals(val))
element = Element.WAY;
else if ("NODE".equals(val))
element = Element.NODE;
} else if ("k".equals(name)) {
keys = value;
} else if ("v".equals(name)) {
values = value;
} else if ("closed".equals(name)) {
String val = value.toUpperCase();
if ("YES".equals(val))
closed = Closed.YES;
else if ("NO".equals(val))
closed = Closed.NO;
} else if ("zoom-min".equals(name)) {
zoomMin = Byte.parseByte(value);
} else if ("zoom-max".equals(name)) {
zoomMax = Byte.parseByte(value);
} else if ("select".equals(name)) {
if ("first".equals(value))
selector |= SELECT_FIRST;
if ("when-matched".equals(value))
selector |= SELECT_WHEN_MATCHED;
} else {
XmlThemeBuilder.logUnknownAttribute(elementName, name, value, i);
}
}
if (closed == Closed.YES)
element = Element.POLY;
else if (closed == Closed.NO)
element = Element.LINE;
validate(zoomMin, zoomMax);
RuleBuilder b = create(ruleStack, keys, values);
b.setZoom(zoomMin, zoomMax);
b.element = element;
b.selector = selector;
return b;
}
public RuleBuilder setZoom(byte zoomMin, byte zoomMax) {
// zoom-level bitmask
zoom = 0;
for (int z = zoomMin; z <= zoomMax && z < 32; z++)
zoom |= (1 << z);
return this;
}
public Rule onComplete() {
MATCHERS_CACHE_KEY.clear();
MATCHERS_CACHE_VALUE.clear();
RenderStyle[] styles = null;
Rule[] rules = null;
if (renderStyles.size() > 0) {
styles = new RenderStyle[renderStyles.size()];
renderStyles.toArray(styles);
}
if (subRules.size() > 0) {
rules = new Rule[subRules.size()];
for (int i = 0; i < rules.length; i++)
rules[i] = subRules.get(i).onComplete();
}
if (positiveRule)
return new PositiveRule(element, zoom, selector, keyMatcher,
valueMatcher, rules, styles);
else
return new NegativeRule(element, zoom, selector, keyMatcher,
rules, styles);
}
public void addStyle(RenderStyle style) {
renderStyles.add(style);
}
public void addSubRule(RuleBuilder rule) {
subRules.add(rule);
}
RuleBuilder(boolean positive) {
this.positiveRule = positive;
this.element = Element.ANY;
this.zoom = ~0;
}
public static RuleBuilder get() {
return new RuleBuilder(true);
}
public RuleBuilder select(int selector) {
this.selector = selector;
return this;
}
public RuleBuilder zoom(int zoom) {
this.zoom = zoom;
return this;
}
public RuleBuilder element(int element) {
this.element = element;
return this;
}
}

View File

@ -22,12 +22,13 @@ import java.util.Stack;
final class RuleOptimizer {
private static AttributeMatcher optimizeKeyMatcher(AttributeMatcher attributeMatcher,
Stack<Rule> ruleStack) {
Stack<RuleBuilder> ruleStack) {
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
if (ruleStack.get(i) instanceof PositiveRule) {
PositiveRule positiveRule = (PositiveRule) ruleStack.get(i);
if (positiveRule.mKeyMatcher != null
&& positiveRule.mKeyMatcher.isCoveredBy(attributeMatcher)) {
if (ruleStack.get(i).positiveRule) {
RuleBuilder positiveRule = ruleStack.get(i);
if (positiveRule.keyMatcher != null
&& positiveRule.keyMatcher.isCoveredBy(attributeMatcher)) {
return null;
}
}
@ -37,13 +38,13 @@ final class RuleOptimizer {
}
private static AttributeMatcher optimizeValueMatcher(
AttributeMatcher attributeMatcher, Stack<Rule> ruleStack) {
AttributeMatcher attributeMatcher, Stack<RuleBuilder> ruleStack) {
for (int i = 0, n = ruleStack.size(); i < n; ++i) {
if (ruleStack.get(i) instanceof PositiveRule) {
PositiveRule positiveRule = (PositiveRule) ruleStack.get(i);
if (ruleStack.get(i).positiveRule) {
RuleBuilder positiveRule = ruleStack.get(i);
if (positiveRule.mValueMatcher != null
&& positiveRule.mValueMatcher.isCoveredBy(attributeMatcher)) {
if (positiveRule.valueMatcher != null
&& positiveRule.valueMatcher.isCoveredBy(attributeMatcher)) {
return null;
}
}
@ -53,7 +54,7 @@ final class RuleOptimizer {
}
static AttributeMatcher optimize(AttributeMatcher attributeMatcher,
Stack<Rule> ruleStack) {
Stack<RuleBuilder> ruleStack) {
if (attributeMatcher instanceof AnyMatcher)
return attributeMatcher;// return null;
else if (attributeMatcher instanceof NegativeMatcher) {

View File

@ -0,0 +1,8 @@
package org.oscim.theme.rule;
public class Selector {
public static final int ANY = 0;
public static final int FIRST = 1 << 0;
public static final int WHEN_MATCHED = 1 << 1;
}

View File

@ -19,10 +19,10 @@ package org.oscim.theme.rule;
import org.oscim.core.Tag;
class SingleKeyMatcher implements AttributeMatcher {
public class SingleKeyMatcher implements AttributeMatcher {
private final String mKey;
SingleKeyMatcher(String key) {
public SingleKeyMatcher(String key) {
mKey = key.intern();
}

View File

@ -19,10 +19,10 @@ package org.oscim.theme.rule;
import org.oscim.core.Tag;
class SingleValueMatcher implements AttributeMatcher {
public class SingleValueMatcher implements AttributeMatcher {
private final String mValue;
SingleValueMatcher(String value) {
public SingleValueMatcher(String value) {
mValue = value.intern();
}

View File

@ -1,79 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import org.oscim.backend.canvas.Color;
import org.oscim.renderer.elements.TextureItem;
import org.oscim.theme.IRenderTheme.Callback;
/**
* Represents a closed polygon on the map.
*/
public final class Area extends RenderStyle {
public Area(int fill) {
this(0, fill);
}
public Area(int level, int fill) {
this.level = level;
this.style = "";
this.fade = -1;
this.blendColor = 0;
this.blend = -1;
this.color = fill;
this.texture = null;
this.outline = null;
}
public Area(String style, int fill, int stroke, float strokeWidth,
int fade, int level, int blend, int blendFill, TextureItem texture) {
this.style = style;
this.color = fill;
this.blendColor = blendFill;
this.blend = blend;
this.fade = fade;
this.level = level;
this.texture = texture;
if (stroke == Color.TRANSPARENT) {
this.outline = null;
return;
}
this.outline = new Line(level + 1, stroke, strokeWidth);
}
@Override
public void renderWay(Callback renderCallback) {
renderCallback.renderArea(this, level);
if (outline != null)
renderCallback.renderWay(outline, level + 1);
}
private final int level;
public String style;
public final Line outline;
public final int color;
public final int fade;
public final int blendColor;
public final int blend;
public final TextureItem texture;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import org.oscim.theme.IRenderTheme.Callback;
public class AreaLevel extends RenderStyle {
private final Area area;
private final int level;
public AreaLevel(Area area, int level) {
this.area = area;
this.level = level;
}
@Override
public void renderWay(Callback renderCallback) {
renderCallback.renderArea(this.area, level);
if (this.area.outline != null)
renderCallback.renderWay(this.area.outline, level + 1);
}
}

View File

@ -0,0 +1,227 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import static org.oscim.backend.canvas.Color.parseColor;
import org.oscim.backend.canvas.Color;
import org.oscim.renderer.elements.TextureItem;
import org.oscim.theme.IRenderTheme.Callback;
public class AreaStyle extends RenderStyle {
/** Drawing order level */
private final int level;
/** Style name */
public final String style;
/** Fill color */
public final int color;
/** Fade-out zoom-level */
public final int fadeScale;
/** Fade to blendColor zoom-level */
public final int blendColor;
/** Blend fill color */
public final int blendScale;
/** Pattern texture */
public final TextureItem texture;
/** Outline */
public final LineStyle outline;
public AreaStyle(int color) {
this(0, color);
}
public AreaStyle(int level, int color) {
this.level = level;
this.style = "";
this.fadeScale = -1;
this.blendColor = 0;
this.blendScale = -1;
this.color = color;
this.texture = null;
this.outline = null;
}
public AreaStyle(AreaBuilder b) {
this.level = b.level;
this.style = b.style;
this.fadeScale = b.fadeScale;
this.blendColor = b.blendColor;
this.blendScale = b.blendScale;
this.color = b.color;
this.texture = b.texture;
if (b.outline != null &&
b.outlineColor == b.outline.color &&
b.outlineWidth == b.outline.width) {
this.outline = b.outline;
} else if (b.outlineColor != Color.TRANSPARENT) {
this.outline = new LineStyle(-1, b.outlineColor, b.outlineWidth);
} else {
this.outline = null;
}
}
@Override
public void update() {
super.update();
if (outline != null)
outline.update();
}
public AreaStyle current() {
return (AreaStyle) (mCurrent == null ? this : mCurrent);
}
@Override
public void renderWay(Callback renderCallback) {
renderCallback.renderArea(this, level);
if (outline != null)
renderCallback.renderWay(outline, level + 1);
}
public static class AreaBuilder {
public int level;
public String style;
public LineStyle outline;
public int color;
public int fadeScale;
public int blendColor;
public int blendScale;
public int outlineColor;
public float outlineWidth;
public TextureItem texture;
public AreaBuilder set(AreaStyle area) {
if (area == null)
return reset();
this.level = area.level;
this.style = area.style;
this.fadeScale = area.fadeScale;
this.blendColor = area.blendColor;
this.blendScale = area.blendScale;
this.color = area.color;
this.texture = area.texture;
this.outline = area.outline;
if (area.outline != null) {
this.outlineColor = outline.color;
this.outlineWidth = outline.width;
} else {
outlineColor = Color.TRANSPARENT;
outlineWidth = 1;
}
return this;
}
public AreaBuilder style(String name) {
this.style = name;
return this;
}
public AreaBuilder level(int level) {
this.level = level;
return this;
}
public AreaBuilder outline(int color, float width) {
this.outlineColor = color;
this.outlineWidth = width;
return this;
}
public AreaBuilder outlineColor(int color) {
this.outlineColor = color;
return this;
}
public AreaBuilder outlineColor(String color) {
this.outlineColor = parseColor(color);
return this;
}
public AreaBuilder outlineWidth(float width) {
this.outlineWidth = width;
return this;
}
public AreaBuilder color(int color) {
this.color = color;
return this;
}
public AreaBuilder color(String color) {
this.color = parseColor(color);
return this;
}
public AreaBuilder blendScale(int zoom) {
this.blendScale = zoom;
return this;
}
public AreaBuilder blendColor(int color) {
this.blendColor = color;
return this;
}
public AreaBuilder blendColor(String color) {
this.blendColor = parseColor(color);
return this;
}
public AreaBuilder texture(TextureItem texture) {
this.texture = texture;
return this;
}
public AreaBuilder fadeScale(int zoom) {
this.fadeScale = zoom;
return this;
}
public AreaBuilder reset() {
color = Color.BLACK;
outlineColor = Color.TRANSPARENT;
outlineWidth = 1;
fadeScale = -1;
blendScale = -1;
blendColor = Color.TRANSPARENT;
style = null;
texture = null;
return this;
}
public AreaStyle build() {
return new AreaStyle(this);
}
}
}

View File

@ -22,7 +22,7 @@ import org.oscim.theme.IRenderTheme.Callback;
/**
* Represents a round area on the map.
*/
public final class Circle extends RenderStyle {
public final class CircleStyle extends RenderStyle {
public final int level;
@ -33,7 +33,7 @@ public final class Circle extends RenderStyle {
public final boolean scaleRadius;
public final float strokeWidth;
public Circle(Float radius, boolean scaleRadius, int fill, int stroke,
public CircleStyle(Float radius, boolean scaleRadius, int fill, int stroke,
float strokeWidth, int level) {
super();

View File

@ -19,9 +19,9 @@ package org.oscim.theme.styles;
import org.oscim.backend.canvas.Color;
import org.oscim.theme.IRenderTheme.Callback;
public class Extrusion extends RenderStyle {
public class ExtrusionStyle extends RenderStyle {
public Extrusion(int level, int colorSides, int colorTop, int colorLine, int defaultHeight) {
public ExtrusionStyle(int level, int colorSides, int colorTop, int colorLine, int defaultHeight) {
this.colors = new float[16];
fillColors(colorSides, colorTop, colorLine, colors);

View File

@ -1,96 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import org.oscim.backend.canvas.Paint.Cap;
import org.oscim.theme.IRenderTheme.Callback;
/**
* Represents a polyline on the map.
*/
public final class Line extends RenderStyle {
private final int level;
public final String style;
public final float width;
public final int color;
public final Cap cap;
public final boolean outline;
public final boolean fixed;
public final int fade;
public final float blur;
public final int stipple;
public final int stippleColor;
public final float stippleWidth;
public Line(int level, String style, int color, float width,
Cap cap, boolean fixed,
int stipple, int stippleColor, float stippleWidth,
int fade, float blur, boolean isOutline) {
this.level = level;
this.style = style;
this.outline = isOutline;
// paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//
// if (src != null) {
// Shader shader = BitmapUtils.createBitmapShader(src);
// paint.setShader(shader);
// }
//
// paint.setStyle(Style.STROKE);
// paint.setColor(stroke);
// if (strokeDasharray != null) {
// paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
// }
//GlUtils.changeSaturation(color, 1.02f);
this.cap = cap;
this.color = color;
this.width = width;
this.fixed = fixed;
this.stipple = stipple;
this.stippleColor = stippleColor;
this.stippleWidth = stippleWidth;
this.blur = blur;
this.fade = fade;
}
public Line(int stroke, float width) {
this(0, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false);
}
public Line(int level, int stroke, float width) {
this(level, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false);
}
public Line(int stroke, float width, Cap cap) {
this(0, "", stroke, width, cap, true, 0, 0, 0, -1, 0, false);
}
@Override
public void renderWay(Callback renderCallback) {
renderCallback.renderWay(this, level);
}
}

View File

@ -0,0 +1,202 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import static org.oscim.backend.canvas.Color.parseColor;
import org.oscim.backend.canvas.Color;
import org.oscim.backend.canvas.Paint.Cap;
import org.oscim.theme.IRenderTheme.Callback;
public final class LineStyle extends RenderStyle {
final int level;
public final String style;
public final float width;
public final int color;
public final Cap cap;
public final boolean outline;
public final boolean fixed;
public final int fadeScale;
public final float blur;
public final int stipple;
public final int stippleColor;
public final float stippleWidth;
private LineStyle(LineBuilder builer) {
this.level = builer.level;
this.style = builer.style;
this.width = builer.width;
this.color = builer.color;
this.cap = builer.cap;
this.outline = builer.outline;
this.fixed = builer.fixed;
this.fadeScale = builer.fadeScale;
this.blur = builer.blur;
this.stipple = builer.stipple;
this.stippleColor = builer.stippleColor;
this.stippleWidth = builer.stippleWidth;
}
public LineStyle(int level, String style, int color, float width,
Cap cap, boolean fixed,
int stipple, int stippleColor, float stippleWidth,
int fadeScale, float blur, boolean isOutline) {
this.level = level;
this.style = style;
this.outline = isOutline;
this.cap = cap;
this.color = color;
this.width = width;
this.fixed = fixed;
this.stipple = stipple;
this.stippleColor = stippleColor;
this.stippleWidth = stippleWidth;
this.blur = blur;
this.fadeScale = fadeScale;
}
public LineStyle(int stroke, float width) {
this(0, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false);
}
public LineStyle(int level, int stroke, float width) {
this(level, "", stroke, width, Cap.BUTT, true, 0, 0, 0, -1, 0, false);
}
public LineStyle(int stroke, float width, Cap cap) {
this(0, "", stroke, width, cap, true, 0, 0, 0, -1, 0, false);
}
@Override
public void renderWay(Callback renderCallback) {
renderCallback.renderWay(this, level);
}
public final static class LineBuilder {
public int level;
public String style;
public float width;
public int color;
public Cap cap;
public boolean outline;
public boolean fixed;
public int fadeScale;
public float blur;
public int stipple;
public int stippleColor;
public float stippleWidth;
public LineBuilder set(LineStyle line) {
if (line == null)
return reset();
this.level = line.level;
this.style = line.style;
this.width = line.width;
this.color = line.color;
this.cap = line.cap;
this.outline = line.outline;
this.fixed = line.fixed;
this.fadeScale = line.fadeScale;
this.blur = line.blur;
this.stipple = line.stipple;
this.stippleColor = line.stippleColor;
this.stippleWidth = line.stippleWidth;
return this;
}
public LineBuilder reset() {
level = -1;
style = null;
color = Color.BLACK;
cap = Cap.ROUND;
width = 1;
fixed = false;
fadeScale = -1;
blur = 0;
stipple = 0;
stippleWidth = 1;
stippleColor = Color.BLACK;
return this;
}
public LineBuilder style(String name) {
this.style = name;
return this;
}
public LineBuilder level(int level) {
this.level = level;
return this;
}
public LineBuilder color(int color) {
this.color = color;
return this;
}
public LineBuilder width(float width) {
this.width = width;
return this;
}
public LineBuilder blur(float blur) {
this.blur = blur;
return this;
}
public LineBuilder fadeScale(int zoom) {
this.fadeScale = zoom;
return this;
}
public LineBuilder stippleColor(int color) {
this.stippleColor = color;
return this;
}
public LineBuilder color(String color) {
this.color = parseColor(color);
return this;
}
public LineBuilder stippleColor(String color) {
this.stippleColor = parseColor(color);
return this;
}
public LineBuilder isOutline(boolean outline) {
this.outline = outline;
return this;
}
public LineStyle build() {
return new LineStyle(this);
}
}
}

View File

@ -1,45 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import org.oscim.theme.IRenderTheme.Callback;
/**
* Represents an icon along a polyline on the map.
*/
public final class LineSymbol extends RenderStyle {
public final boolean alignCenter;
// public final Bitmap bitmap;
public final boolean repeat;
public final String bitmap;
public LineSymbol(String src, boolean alignCenter, boolean repeat) {
super();
this.bitmap = src;
// this.bitmap = BitmapUtils.createBitmap(src);
this.alignCenter = alignCenter;
this.repeat = repeat;
}
@Override
public void renderWay(Callback renderCallback) {
renderCallback.renderWaySymbol(this);
}
}

View File

@ -41,7 +41,7 @@ public abstract class RenderStyle {
/**
* Destroys this RenderInstruction and cleans up all its internal resources.
*/
public void destroy() {
public void dispose() {
}
/**

View File

@ -23,16 +23,16 @@ import org.oscim.theme.IRenderTheme.Callback;
/**
* Represents an icon on the map.
*/
public final class Symbol extends RenderStyle {
public final class SymbolStyle extends RenderStyle {
public final TextureRegion texture;
public Symbol(TextureRegion symbol) {
public SymbolStyle(TextureRegion symbol) {
this.texture = symbol;
}
@Override
public void destroy() {
public void dispose() {
}
@Override

View File

@ -1,136 +0,0 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.canvas.Paint;
import org.oscim.backend.canvas.Paint.Align;
import org.oscim.backend.canvas.Paint.FontFamily;
import org.oscim.backend.canvas.Paint.FontStyle;
import org.oscim.renderer.atlas.TextureRegion;
import org.oscim.theme.IRenderTheme.Callback;
/**
* Represents a text along a polyline on the map.
*/
public final class Text extends RenderStyle {
public final String style;
public final float fontSize;
public final Paint paint;
public final Paint stroke;
public final String textKey;
public final boolean caption;
public final float dy;
public final int priority;
public float fontHeight;
public float fontDescent;
public final TextureRegion texture;
public static Text createText(float fontSize, float strokeWidth, int fill, int outline,
boolean billboard) {
return createText("", fontSize, strokeWidth, fill, outline, billboard);
}
public static Text createText(String textKey, float fontSize, float strokeWidth, int fill,
int outline,
boolean billboard) {
Text t = new Text("",
textKey,
FontFamily.DEFAULT,
FontStyle.NORMAL,
fontSize,
fill,
outline,
strokeWidth,
0,
billboard,
null,
Integer.MAX_VALUE);
t.fontHeight = t.paint.getFontHeight();
t.fontDescent = t.paint.getFontDescent();
return t;
}
public Text(String style, String textKey, FontFamily fontFamily, FontStyle fontStyle,
float fontSize, int fill, int outline, float strokeWidth, float dy, boolean caption,
TextureRegion symbol, int priority) {
this.style = style;
this.textKey = textKey;
this.caption = caption;
this.dy = -dy;
this.priority = priority;
this.texture = symbol;
paint = CanvasAdapter.g.getPaint();
paint.setTextAlign(Align.CENTER);
paint.setTypeface(fontFamily, fontStyle);
paint.setColor(fill);
paint.setTextSize(fontSize);
if (strokeWidth > 0) {
stroke = CanvasAdapter.g.getPaint();
stroke.setStyle(Paint.Style.STROKE);
stroke.setTextAlign(Align.CENTER);
stroke.setTypeface(fontFamily, fontStyle);
stroke.setColor(outline);
stroke.setStrokeWidth(strokeWidth);
stroke.setTextSize(fontSize);
} else
stroke = null;
this.fontSize = fontSize;
//fontHeight = paint.getFontHeight();
//fontDescent = paint.getFontDescent();
}
@Override
public void renderNode(Callback renderCallback) {
if (caption)
renderCallback.renderPointText(this);
}
@Override
public void renderWay(Callback renderCallback) {
if (caption)
renderCallback.renderAreaText(this);
else
renderCallback.renderWayText(this);
}
@Override
public void scaleTextSize(float scaleFactor) {
paint.setTextSize(fontSize * scaleFactor);
if (stroke != null)
stroke.setTextSize(fontSize * scaleFactor);
fontHeight = paint.getFontHeight();
fontDescent = paint.getFontDescent();
}
}

View File

@ -0,0 +1,207 @@
/*
* Copyright 2013 Hannes Janetzek
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.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.oscim.theme.styles;
import org.oscim.backend.CanvasAdapter;
import org.oscim.backend.canvas.Color;
import org.oscim.backend.canvas.Paint;
import org.oscim.backend.canvas.Paint.Align;
import org.oscim.backend.canvas.Paint.FontFamily;
import org.oscim.backend.canvas.Paint.FontStyle;
import org.oscim.renderer.atlas.TextureRegion;
import org.oscim.theme.IRenderTheme.Callback;
public final class TextStyle extends RenderStyle {
public static class TextBuilder {
public String style;
public float fontSize;
public String textKey;
public boolean caption;
public float dy;
public int priority;
public TextureRegion texture;
public FontFamily fontFamily;
public FontStyle fontStyle;
public int color;
public int stroke;
public float strokeWidth;
public TextBuilder reset() {
fontFamily = FontFamily.DEFAULT;
fontStyle = FontStyle.NORMAL;
style = null;
textKey = null;
fontSize = 0;
caption = false;
priority = Integer.MAX_VALUE;
texture = null;
color = Color.BLACK;
stroke = Color.BLACK;
strokeWidth = 0;
dy = 0;
return this;
}
public TextBuilder() {
reset();
}
public TextStyle build() {
TextStyle t = new TextStyle(this);
t.fontHeight = t.paint.getFontHeight();
t.fontDescent = t.paint.getFontDescent();
return t;
}
public TextStyle buildInternal() {
return new TextStyle(this);
}
public TextBuilder setStyle(String style) {
this.style = style;
return this;
}
public TextBuilder setFontSize(float fontSize) {
this.fontSize = fontSize;
return this;
}
public TextBuilder setTextKey(String textKey) {
this.textKey = textKey;
return this;
}
public TextBuilder setCaption(boolean caption) {
this.caption = caption;
return this;
}
public TextBuilder setOffsetY(float dy) {
this.dy = dy;
return this;
}
public TextBuilder setPriority(int priority) {
this.priority = priority;
return this;
}
public TextBuilder setTexture(TextureRegion texture) {
this.texture = texture;
return this;
}
public TextBuilder setFontFamily(FontFamily fontFamily) {
this.fontFamily = fontFamily;
return this;
}
public TextBuilder setFontStyle(FontStyle fontStyle) {
this.fontStyle = fontStyle;
return this;
}
public TextBuilder setColor(int color) {
this.color = color;
return this;
}
public TextBuilder setStroke(int stroke) {
this.stroke = stroke;
return this;
}
public TextBuilder setStrokeWidth(float strokeWidth) {
this.strokeWidth = strokeWidth;
return this;
}
}
TextStyle(TextBuilder tb) {
this.style = tb.style;
this.textKey = tb.textKey;
this.caption = tb.caption;
this.dy = tb.dy;
this.priority = tb.priority;
this.texture = tb.texture;
paint = CanvasAdapter.g.getPaint();
paint.setTextAlign(Align.CENTER);
paint.setTypeface(tb.fontFamily, tb.fontStyle);
paint.setColor(tb.color);
paint.setTextSize(tb.fontSize);
if (tb.strokeWidth > 0) {
stroke = CanvasAdapter.g.getPaint();
stroke.setStyle(Paint.Style.STROKE);
stroke.setTextAlign(Align.CENTER);
stroke.setTypeface(tb.fontFamily, tb.fontStyle);
stroke.setColor(tb.stroke);
stroke.setStrokeWidth(tb.strokeWidth);
stroke.setTextSize(tb.fontSize);
} else
stroke = null;
this.fontSize = tb.fontSize;
}
public final String style;
public final float fontSize;
public final Paint paint;
public final Paint stroke;
public final String textKey;
public final boolean caption;
public final float dy;
public final int priority;
public float fontHeight;
public float fontDescent;
public final TextureRegion texture;
@Override
public void renderNode(Callback renderCallback) {
if (caption)
renderCallback.renderPointText(this);
}
@Override
public void renderWay(Callback renderCallback) {
if (caption)
renderCallback.renderAreaText(this);
else
renderCallback.renderWayText(this);
}
@Override
public void scaleTextSize(float scaleFactor) {
paint.setTextSize(fontSize * scaleFactor);
if (stroke != null)
stroke.setTextSize(fontSize * scaleFactor);
fontHeight = paint.getFontHeight();
fontDescent = paint.getFontDescent();
}
}