use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class MapBuilder method preserveHorizontalAndVerticalLines.
/**
* Preserve shape points which a) lie on the shape boundary or
* b) which appear multiple times in the shape (excluding the start
* point which should always be identical to the end point).
* The preserved points are kept treated specially in the
* Line-Simplification-Filters, this should avoid artifacts like
* white triangles in the sea for lower resolutions.
* @param res the current resolution
* @param shapes list of shapes
*/
private static void preserveHorizontalAndVerticalLines(int res, List<MapShape> shapes) {
if (res == 24)
return;
for (MapShape shape : shapes) {
if (shape.getMinResolution() > res)
continue;
int minLat = shape.getBounds().getMinLat();
int maxLat = shape.getBounds().getMaxLat();
int minLon = shape.getBounds().getMinLong();
int maxLon = shape.getBounds().getMaxLong();
List<Coord> points = shape.getPoints();
int n = shape.getPoints().size();
IdentityHashMap<Coord, Coord> coords = new IdentityHashMap<>(n);
Coord first = points.get(0);
Coord prev = first;
Coord last = first;
for (int i = 1; i < points.size(); ++i) {
last = points.get(i);
// to connect holes
if (coords.get(last) == null) {
coords.put(last, last);
} else {
if (!last.preserved()) {
last.preserved(true);
}
}
// on the bbox of the shape.
if (last.getLatitude() == prev.getLatitude() && (last.getLatitude() == minLat || last.getLatitude() == maxLat) || last.getLongitude() == prev.getLongitude() && (last.getLongitude() == minLon || last.getLongitude() == maxLon)) {
last.preserved(true);
prev.preserved(true);
}
prev = last;
}
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class OverviewBuilder method calcLevels.
private void calcLevels() {
List<MapShape> shapes = overviewSource.getShapes();
// we can write a 0x4a polygon for planet in res 16
int maxRes = 16;
if (wantedLevels != null)
maxRes = wantedLevels[wantedLevels.length - 1].getBits();
int maxSize = 0xffff << (24 - maxRes);
for (MapShape s : shapes) {
if (s.getType() != 0x4a)
continue;
int maxDimPoly = s.getBounds().getMaxDimension();
if (maxDimPoly > maxSize) {
int oldMaxRes = maxRes;
while (maxDimPoly > maxSize) {
maxRes--;
maxSize = 0xffff << (24 - maxRes);
}
String[] name = s.getName().split("\u001d");
String msg = "Tile selection (0x4a) polygon for ";
if (name != null && name.length == 2)
msg += "tile " + name[1].trim();
else
msg += s.getBounds();
log.error(msg, "cannot be written in level 0 resolution", oldMaxRes + ", using", maxRes, "instead");
}
}
if (wantedLevels == null)
setRes(maxRes);
else {
// make sure that the wanted levels for the overview map
// can store the largest 0x4a polygon at level 0
int n = wantedLevels.length - 1;
while (n > 0 && wantedLevels[n].getBits() > maxRes) n--;
if (n > 0) {
int l = 0;
while (n >= 0) {
wantedLevels[n] = new LevelInfo(l++, wantedLevels[n].getBits());
n--;
}
wantedLevels = Arrays.copyOfRange(wantedLevels, 0, l);
overviewSource.setMapLevels(wantedLevels);
} else
setRes(maxRes);
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class OverviewBuilder method readShapes.
/**
* Read the polygons from the .img file and add them to the overview map.
* We read from the least detailed level (apart from the empty one).
*
* @param mapReader Map reader on the detailed .img file.
*/
private void readShapes(MapReader mapReader) {
Zoom[] levels = mapReader.getLevels();
for (int l = 1; l < levels.length; l++) {
int min = levels[l].getLevel();
int res = levels[l].getResolution();
List<Polygon> list = mapReader.shapesForLevel(min, MapReader.WITH_EXT_TYPE_DATA);
for (Polygon shape : list) {
if (log.isDebugEnabled())
log.debug("got polygon", shape);
if (shape.getType() == 0x4b) {
hasBackground = true;
}
MapShape ms = new MapShape();
List<Coord> points = shape.getPoints();
if (log.isDebugEnabled())
log.debug("polygon point list", points);
if (points.size() < 3)
continue;
ms.setType(shape.getType());
if (shape.getLabel() != null)
ms.setName(shape.getLabel().getText());
ms.setMaxResolution(res);
ms.setMinResolution(res);
ms.setPoints(points);
overviewSource.addShape(ms);
}
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class PolygonSubdivSizeSplitterFilter method doFilter.
/**
* Split up polygons that exceeds the limits of a subdivision.
*
* @param element A map element, only polygons will be processed.
* @param next This is used to pass the possibly transformed element onward.
*/
public void doFilter(MapElement element, MapFilterChain next) {
assert element instanceof MapShape;
MapShape shape = (MapShape) element;
if (isSizeOk(shape)) {
// This is ok let it through and return.
next.doFilter(element);
return;
}
List<MapShape> outputs = new ArrayList<MapShape>();
// Do an initial split
split(shape, outputs);
// NOTE: the end condition is changed from within the loop.
for (int i = 0; i < outputs.size(); i++) {
MapShape s = outputs.get(i);
if (!isSizeOk(s)) {
// Not small enough, so remove it and split it again. The resulting
// pieces will be placed at the end of the list and will be
// picked up later on.
outputs.set(i, null);
split(s, outputs);
}
}
// Now add all to the chain.
for (MapShape s : outputs) {
if (s == null)
continue;
next.doFilter(s);
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class RemoveObsoletePointsFilter method doFilter.
/**
* @param element A map element that will be a line or a polygon.
* @param next This is used to pass the possibly transformed element onward.
*/
public void doFilter(MapElement element, MapFilterChain next) {
MapLine line = (MapLine) element;
List<Coord> points = line.getPoints();
int numPoints = points.size();
if (numPoints <= 1) {
return;
}
int requiredPoints = (line instanceof MapShape) ? 4 : 2;
List<Coord> newPoints = new ArrayList<Coord>(numPoints);
while (true) {
boolean removedSpike = false;
numPoints = points.size();
Coord lastP = points.get(0);
newPoints.add(lastP);
for (int i = 1; i < numPoints; i++) {
Coord newP = points.get(i);
int last = newPoints.size() - 1;
lastP = newPoints.get(last);
if (lastP.equals(newP)) {
// coordinates to the last point or is preserved
if (checkPreserved && line.isRoad()) {
if (newP.preserved() == false)
continue;
else if (lastP.preserved() == false) {
// replace last
newPoints.set(last, newP);
}
} else
continue;
}
if (newPoints.size() > 1) {
switch(Utils.isStraight(newPoints.get(last - 1), lastP, newP)) {
case Utils.STRICTLY_STRAIGHT:
if (checkPreserved && lastP.preserved() && line.isRoad()) {
// keep it
} else {
log.debug("found three consecutive points on strictly straight line");
newPoints.set(last, newP);
continue;
}
break;
case Utils.STRAIGHT_SPIKE:
if (line instanceof MapShape) {
log.debug("removing spike");
newPoints.remove(last);
removedSpike = true;
if (newPoints.get(last - 1).equals(newP))
continue;
}
break;
default:
break;
}
}
newPoints.add(newP);
}
if (!removedSpike || newPoints.size() < requiredPoints)
break;
points = newPoints;
newPoints = new ArrayList<Coord>(points.size());
}
if (line instanceof MapShape) {
// in a shape are identical.
while (newPoints.size() > 3) {
int nPoints = newPoints.size();
switch(Utils.isStraight(newPoints.get(newPoints.size() - 2), newPoints.get(0), newPoints.get(1))) {
case Utils.STRAIGHT_SPIKE:
newPoints.remove(0);
newPoints.set(newPoints.size() - 1, newPoints.get(0));
if (newPoints.get(newPoints.size() - 2).equals(newPoints.get(newPoints.size() - 1)))
newPoints.remove(newPoints.size() - 1);
break;
case Utils.STRICTLY_STRAIGHT:
newPoints.remove(newPoints.size() - 1);
newPoints.set(0, newPoints.get(newPoints.size() - 1));
break;
}
if (nPoints == newPoints.size())
break;
}
}
if (newPoints.size() != line.getPoints().size()) {
if (line instanceof MapShape && newPoints.size() <= 3 || newPoints.size() <= 1)
return;
MapLine newLine = line.copy();
newLine.setPoints(newPoints);
next.doFilter(newLine);
} else {
// no need to create new object
next.doFilter(line);
}
}
Aggregations