Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2014-03-07 02:42:31 +01:00
commit a0271410bd
3 changed files with 176 additions and 75 deletions

View file

@ -51,6 +51,7 @@ public class RenderingContext {
public int shadowRenderingMode = ShadowRenderingMode.BLUR_SHADOW.value; public int shadowRenderingMode = ShadowRenderingMode.BLUR_SHADOW.value;
public int shadowRenderingColor = 0xff969696; public int shadowRenderingColor = 0xff969696;
public String renderingDebugInfo; public String renderingDebugInfo;
public double polygonMinSizeToDisplay;
private float density = 1; private float density = 1;

View file

@ -376,6 +376,7 @@ public class MapRenderRepositories {
if (checkWhetherInterrupted()) { if (checkWhetherInterrupted()) {
return false; return false;
} }
boolean objectsFromMapSectionRead = tempResult.size() > 0;
if (renderRouteDataFile >= 0 && zoom >= zoomOnlyForBasemaps ) { if (renderRouteDataFile >= 0 && zoom >= zoomOnlyForBasemaps ) {
searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, null); searchRequest = BinaryMapIndexReader.buildSearchRequest(leftX, rightX, topY, bottomY, zoom, null);
for (BinaryMapIndexReader c : files.values()) { for (BinaryMapIndexReader c : files.values()) {
@ -391,7 +392,7 @@ public class MapRenderRepositories {
boolean addBasemapCoastlines = true; boolean addBasemapCoastlines = true;
boolean emptyData = zoom > zoomOnlyForBasemaps && tempResult.isEmpty() && coastLines.isEmpty(); boolean emptyData = zoom > zoomOnlyForBasemaps && tempResult.isEmpty() && coastLines.isEmpty();
boolean basemapMissing = zoom <= zoomOnlyForBasemaps && basemapCoastLines.isEmpty() && mi == null; boolean basemapMissing = zoom <= zoomOnlyForBasemaps && basemapCoastLines.isEmpty() && mi == null;
boolean detailedLandData = zoom >= zoomForBaseRouteRendering && tempResult.size() > 0 && renderRouteDataFile < 0; boolean detailedLandData = zoom >= zoomForBaseRouteRendering && tempResult.size() > 0 && objectsFromMapSectionRead;
if (!coastLines.isEmpty()) { if (!coastLines.isEmpty()) {
long ms = System.currentTimeMillis(); long ms = System.currentTimeMillis();
boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom, boolean coastlinesWereAdded = processCoastlines(coastLines, leftX, rightX, bottomY, topY, zoom,
@ -650,6 +651,9 @@ public class MapRenderRepositories {
currentRenderingContext.shadowRenderingMode = renderingReq.getIntPropertyValue(renderingReq.ALL.R_ATTR_INT_VALUE); currentRenderingContext.shadowRenderingMode = renderingReq.getIntPropertyValue(renderingReq.ALL.R_ATTR_INT_VALUE);
currentRenderingContext.shadowRenderingColor = renderingReq.getIntPropertyValue(renderingReq.ALL.R_SHADOW_COLOR); currentRenderingContext.shadowRenderingColor = renderingReq.getIntPropertyValue(renderingReq.ALL.R_SHADOW_COLOR);
} }
if(renderingReq.searchRenderingAttribute("polygonMinSizeToDisplay")) {
currentRenderingContext.polygonMinSizeToDisplay = renderingReq.getIntPropertyValue(renderingReq.ALL.R_ATTR_INT_VALUE);
}
final QuadPointDouble lt = requestedBox.getLeftTopTile(requestedBox.getZoom()); final QuadPointDouble lt = requestedBox.getLeftTopTile(requestedBox.getZoom());
// LatLon ltn = requestedBox.getLeftTopLatLon(); // LatLon ltn = requestedBox.getLeftTopLatLon();
final float mapDensity = (float) Math.pow(2, requestedBox.getZoomScale()); final float mapDensity = (float) Math.pow(2, requestedBox.getZoomScale());

View file

@ -24,6 +24,7 @@ import net.osmand.render.RenderingRuleProperty;
import net.osmand.render.RenderingRuleSearchRequest; import net.osmand.render.RenderingRuleSearchRequest;
import net.osmand.render.RenderingRulesStorage; import net.osmand.render.RenderingRulesStorage;
import net.osmand.util.Algorithms; import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -61,6 +62,7 @@ public class OsmandRenderer {
private Paint paintIcon; private Paint paintIcon;
public static final int TILE_SIZE = 256; public static final int TILE_SIZE = 256;
private static final int MAX_V = 75;
private Map<float[], PathEffect> dashEffect = new LinkedHashMap<float[], PathEffect>(); private Map<float[], PathEffect> dashEffect = new LinkedHashMap<float[], PathEffect>();
private Map<String, float[]> parsedDashEffects = new LinkedHashMap<String, float[]>(); private Map<String, float[]> parsedDashEffects = new LinkedHashMap<String, float[]>();
@ -72,6 +74,12 @@ public class OsmandRenderer {
private TextRenderer textRenderer; private TextRenderer textRenderer;
public class MapDataObjectPrimitive {
BinaryMapDataObject obj;
int typeInd;
double order;
int objectType;
};
private static class IconDrawInfo { private static class IconDrawInfo {
float x = 0; float x = 0;
@ -103,6 +111,7 @@ public class OsmandRenderer {
int shadowLevelMax = 0; int shadowLevelMax = 0;
boolean ended = false; boolean ended = false;
@Override @Override
protected byte[] getIconRawData(String data) { protected byte[] getIconRawData(String data) {
@ -197,6 +206,32 @@ public class OsmandRenderer {
} }
} }
void drawObject(RenderingContext rc, Canvas cv, RenderingRuleSearchRequest req,
List<MapDataObjectPrimitive> array, int objOrder) {
//double polygonLimit = 100;
//float orderToSwitch = 0;
double minPolygonSize = 1. / rc.polygonMinSizeToDisplay;
for (int i = 0; i < array.size(); i++) {
rc.allObjects++;
BinaryMapDataObject mObj = array.get(i).obj;
TagValuePair pair = mObj.getMapIndex().decodeType(mObj.getTypes()[array.get(i).typeInd]);
if (objOrder == 0) {
if (array.get(i).order > minPolygonSize + ((int) array.get(i).order)) {
continue;
}
// polygon
drawPolygon(mObj, req, cv, rc, pair);
} else if (objOrder == 1 || objOrder == 2) {
drawPolyline(mObj, req, cv, rc, pair, mObj.getSimpleLayer(), objOrder == 1);
} else if (objOrder == 3) {
drawPoint(mObj, req, cv, rc, pair, array.get(i).typeInd == 0);
}
if (i % 25 == 0 && rc.interrupted) {
return;
}
}
}
public void generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp, public void generateNewBitmap(RenderingContext rc, List<BinaryMapDataObject> objects, Bitmap bmp,
RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList) { RenderingRuleSearchRequest render, final List<IMapDownloaderCallback> notifyList) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@ -210,57 +245,25 @@ public class OsmandRenderer {
rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE; rc.sinRotateTileSize = FloatMath.sin((float) Math.toRadians(rc.rotate)) * TILE_SIZE;
// put in order map // put in order map
TIntObjectHashMap<TIntArrayList> orderMap = sortObjectsByProperOrder(rc, objects, render); List<MapDataObjectPrimitive> pointsArray = new ArrayList<OsmandRenderer.MapDataObjectPrimitive>();
List<MapDataObjectPrimitive> polygonsArray = new ArrayList<OsmandRenderer.MapDataObjectPrimitive>();
List<MapDataObjectPrimitive> linesArray = new ArrayList<OsmandRenderer.MapDataObjectPrimitive>();
sortObjectsByProperOrder(rc, objects, render, pointsArray, polygonsArray, linesArray);
int objCount = 0; rc.lastRenderedKey = 0;
int[] keys = orderMap.keys();
Arrays.sort(keys);
boolean shadowDrawn = false;
for (int k = 0; k < keys.length; k++) {
if (!shadowDrawn && (keys[k]>>2) >= rc.shadowLevelMin && (keys[k]>>2) <= rc.shadowLevelMax && rc.shadowRenderingMode > 1) {
for (int ki = k; ki < keys.length; ki++) {
if ((keys[ki]>>2) > rc.shadowLevelMax || rc.interrupted) {
break;
}
TIntArrayList list = orderMap.get(keys[ki]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, render, cv, rc, l, l == 0, true, (keys[ki] & 3));
objCount++;
}
}
shadowDrawn = true;
}
if (rc.interrupted) {
return;
}
TIntArrayList list = orderMap.get(keys[k]);
for (int j = 0; j < list.size(); j++) {
int i = list.get(j);
int ind = i >> 8;
int l = i & 0xff;
BinaryMapDataObject obj = objects.get(ind);
// show text only for main type
drawObj(obj, render, cv, rc, l, l == 0, false, (keys[k] & 3));
objCount++;
}
rc.lastRenderedKey = (keys[k] >> 2);
if (objCount > 25) {
notifyListeners(notifyList);
objCount = 0;
}
drawObject(rc, cv, render, polygonsArray, 0);
rc.lastRenderedKey = 5;
if (rc.shadowRenderingMode > 1) {
drawObject(rc, cv, render, linesArray, 1);
} }
rc.lastRenderedKey = 40;
drawObject(rc, cv, render, linesArray, 2);
rc.lastRenderedKey = 60;
drawObject(rc, cv, render, pointsArray, 3);
rc.lastRenderedKey = 125;
long beforeIconTextTime = System.currentTimeMillis() - now; long beforeIconTextTime = System.currentTimeMillis() - now;
notifyListeners(notifyList); notifyListeners(notifyList);
@ -344,22 +347,53 @@ public class OsmandRenderer {
} }
} }
} }
Comparator<MapDataObjectPrimitive> sortByOrder() {
return new Comparator<MapDataObjectPrimitive>() {
private TIntObjectHashMap<TIntArrayList> sortObjectsByProperOrder(RenderingContext rc, List<BinaryMapDataObject> objects, @Override
RenderingRuleSearchRequest render) { public int compare(MapDataObjectPrimitive i, MapDataObjectPrimitive j) {
if (i.order == j.order) {
if (i.typeInd == j.typeInd) {
if(i.obj.getPointsLength() == j.obj.getPointsLength()) {
return 0;
}
return i.obj.getPointsLength() < j.obj.getPointsLength() ? -1 : 1;
}
return i.typeInd < j.typeInd ? -1 : 1;
}
return (i.order < j.order ? -1 : 1);
}
};
}
Comparator<MapDataObjectPrimitive> sortPolygonsOrder() {
return new Comparator<MapDataObjectPrimitive>() {
@Override
public int compare(MapDataObjectPrimitive i, MapDataObjectPrimitive j) {
if (i.order == j.order)
return i.typeInd < j.typeInd ? -1 : 1;
return (i.order > j.order) ? -1 : 1;
}
};
}
private void sortObjectsByProperOrder(RenderingContext rc, List<BinaryMapDataObject> objects,
RenderingRuleSearchRequest render,
List<MapDataObjectPrimitive> pointsArray, List<MapDataObjectPrimitive> polygonsArray,
List<MapDataObjectPrimitive> linesResArray) {
int sz = objects.size(); int sz = objects.size();
TIntObjectHashMap<TIntArrayList> orderMap = new TIntObjectHashMap<TIntArrayList>(); List<MapDataObjectPrimitive> linesArray = new ArrayList<OsmandRenderer.MapDataObjectPrimitive>();
if (render != null) { if (render != null) {
render.clearState(); render.clearState();
float mult = (float) (1. / MapUtils.getPowZoom(Math.max(31 - (rc.zoom + 8), 0)));
for (int i = 0; i < sz; i++) { for (int i = 0; i < sz; i++) {
BinaryMapDataObject o = objects.get(i); BinaryMapDataObject o = objects.get(i);
int sh = i << 8;
for (int j = 0; j < o.getTypes().length; j++) { for (int j = 0; j < o.getTypes().length; j++) {
// put(orderMap, BinaryMapDataObject.getOrder(o.getTypes()[j]), sh + j, init);
int wholeType = o.getTypes()[j]; int wholeType = o.getTypes()[j];
int layer = 0; int layer = 0;
if (o.getPointsLength() > 1) { if (o.getPointsLength() > 1) {
layer = o.getSimpleLayer(); layer = o.getSimpleLayer();
@ -374,10 +408,24 @@ public class OsmandRenderer {
if (render.search(RenderingRulesStorage.ORDER_RULES)) { if (render.search(RenderingRulesStorage.ORDER_RULES)) {
int objectType = render.getIntPropertyValue(render.ALL.R_OBJECT_TYPE); int objectType = render.getIntPropertyValue(render.ALL.R_OBJECT_TYPE);
int order = render.getIntPropertyValue(render.ALL.R_ORDER); int order = render.getIntPropertyValue(render.ALL.R_ORDER);
put(orderMap, (order << 2) | objectType, sh + j); MapDataObjectPrimitive mapObj = new MapDataObjectPrimitive();
mapObj.objectType = objectType;
mapObj.order = order;
mapObj.typeInd = j;
mapObj.obj = o;
if(objectType == 3) { if(objectType == 3) {
// add icon point all the time MapDataObjectPrimitive pointObj = mapObj;
put(orderMap,(128 << 2)|1, sh + j); pointObj.objectType = 1;
double area = polygonArea(mapObj, mult);
if(area > MAX_V) {
mapObj.order = mapObj.order + (1. / area);
polygonsArray.add(mapObj);
pointsArray.add(pointObj); // TODO fix duplicate text? verify if it is needed for icon
}
} else if(objectType == 1) {
pointsArray.add(mapObj);
} else {
linesArray.add(mapObj);
} }
if (render.isSpecified(render.ALL.R_SHADOW_LEVEL)) { if (render.isSpecified(render.ALL.R_SHADOW_LEVEL)) {
rc.shadowLevelMin = Math.min(rc.shadowLevelMin, order); rc.shadowLevelMin = Math.min(rc.shadowLevelMin, order);
@ -390,12 +438,74 @@ public class OsmandRenderer {
} }
if (rc.interrupted) { if (rc.interrupted) {
return orderMap; return;
} }
} }
} }
return orderMap; Collections.sort(polygonsArray, sortByOrder());
Collections.sort(pointsArray, sortByOrder());
Collections.sort(linesArray, sortByOrder());
filterLinesByDensity(rc, linesResArray, linesArray);
} }
void filterLinesByDensity(RenderingContext rc, List<MapDataObjectPrimitive> linesResArray,
List<MapDataObjectPrimitive> linesArray) {
// int roadsLimit = rc->roadsDensityLimitPerTile;
// int densityZ = rc->roadDensityZoomTile;
// if(densityZ == 0 || roadsLimit == 0) {
// linesResArray = linesArray;
// return;
// }
// linesResArray.reserve(linesArray.size());
// UNORDERED(map)<int64_t, pair<int, int> > densityMap;
// for (int i = linesArray.size() - 1; i >= 0; i--) {
// bool accept = true;
// int o = linesArray[i].order;
// MapDataObject* line = linesArray[i].obj;
// tag_value& ts = line->types[linesArray[i].typeInd];
// if (ts.first == "highway") {
// accept = false;
// int64_t prev = 0;
// for (uint k = 0; k < line->points.size(); k++) {
// int dz = rc->getZoom() + densityZ;
// int64_t x = (line->points[k].first) >> (31 - dz);
// int64_t y = (line->points[k].second) >> (31 - dz);
// int64_t tl = (x << dz) + y;
// if (prev != tl) {
// prev = tl;
// pair<int, int>& p = densityMap[tl];
// if (p.first < roadsLimit/* && p.second > o */) {
// accept = true;
// p.first++;
// p.second = o;
// densityMap[tl] = p;
// }
// }
// }
// }
// if(accept) {
// linesResArray.push_back(linesArray[i]);
// }
// }
// reverse(linesResArray.begin(), linesResArray.end());
// TODO
linesResArray.addAll(linesArray);
}
private double polygonArea(MapDataObjectPrimitive mapObj, float mult) {
double area = 0.;
int j = mapObj.obj.getPointsLength() - 1;
for (int i = 0; i < mapObj.obj.getPointsLength(); i++) {
int px = mapObj.obj.getPoint31XTile(i);
int py = mapObj.obj.getPoint31YTile(i);
int sx = mapObj.obj.getPoint31XTile(j);
int sy = mapObj.obj.getPoint31YTile(j);
area += (sx + ((float) px)) * (sy - ((float) py));
j = i;
}
return Math.abs(area) * mult * mult * .5;
}
private void notifyListeners(List<IMapDownloaderCallback> notifyList) { private void notifyListeners(List<IMapDownloaderCallback> notifyList) {
if (notifyList != null) { if (notifyList != null) {
for (IMapDownloaderCallback c : notifyList) { for (IMapDownloaderCallback c : notifyList) {
@ -404,20 +514,6 @@ public class OsmandRenderer {
} }
} }
protected void drawObj(BinaryMapDataObject obj, RenderingRuleSearchRequest render, Canvas canvas, RenderingContext rc, int l,
boolean renderText, boolean drawOnlyShadow, int type) {
rc.allObjects++;
TagValuePair pair = obj.getMapIndex().decodeType(obj.getTypes()[l]);
if (type == RenderingRulesStorage.POINT_RULES && !drawOnlyShadow) {
drawPoint(obj, render, canvas, rc, pair, renderText);
} else if (type == RenderingRulesStorage.LINE_RULES) {
drawPolyline(obj, render, canvas, rc, pair, obj.getSimpleLayer(), drawOnlyShadow);
} else if (type == RenderingRulesStorage.POLYGON_RULES && !drawOnlyShadow) {
drawPolygon(obj, render, canvas, rc, pair);
}
}
private PointF calcPoint(int xt, int yt, RenderingContext rc){ private PointF calcPoint(int xt, int yt, RenderingContext rc){
rc.pointCount ++; rc.pointCount ++;
double tx = xt / rc.tileDivisor; double tx = xt / rc.tileDivisor;