use of uk.me.parabola.mkgmap.general.MapLine in project mkgmap by openstreetmap.
the class DouglasPeuckerFilter method doFilter.
/**
* This applies to both lines and polygons. We are going to smooth out
* the points in the line so that you do not get jaggies.
*
* @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) {
// First off we don't touch things if at the highest level of detail
if (resolution == 24) {
// XXX 24 is not necessarily the highest level.
next.doFilter(element);
return;
}
MapLine line = (MapLine) element;
List<Coord> points = line.getPoints();
// Create a new list to rewrite the points into. Don't alter the original one
List<Coord> coords = new ArrayList<>(points.size());
coords.addAll(points);
// Loop runs downwards, as the list length gets modified while running
int endIndex = coords.size() - 1;
for (int i = endIndex - 1; i > 0; i--) {
Coord p = coords.get(i);
// TODO: Should consider only nodes connected to roads visible at current resolution.
if (p.preserved()) {
// point is "preserved", don't remove it
douglasPeucker(coords, i, endIndex, maxErrorDistance);
endIndex = i;
}
}
// Simplify the rest
douglasPeucker(coords, 0, endIndex, maxErrorDistance);
if (coords.size() == points.size())
// nothing changed, no need to copy
next.doFilter(line);
else {
MapLine newline = line.copy();
newline.setPoints(coords);
next.doFilter(newline);
}
}
use of uk.me.parabola.mkgmap.general.MapLine in project mkgmap by openstreetmap.
the class LineMergeFilter method merge.
// TODO: This routine has a side effect: it modifies some of the MapLine instances
// instead of creating copies. It seems that this has no bad effect, but it is not clean
public List<MapLine> merge(List<MapLine> lines, int res) {
// better use LinkedList??
linesMerged = new ArrayList<MapLine>(lines.size());
for (MapLine line : lines) {
if (line.getMinResolution() > res || line.getMaxResolution() < res)
continue;
if (line.isRoad()) {
linesMerged.add(line);
continue;
}
boolean isMerged = false;
List<Coord> points = line.getPoints();
Coord start = points.get(0);
Coord end = points.get(points.size() - 1);
// (can the end of current line connected to an existing line?)
for (MapLine line2 : startPoints.get(end)) {
if (line.isSimilar(line2)) {
addPointsAtStart(line2, points);
// both lines has to be merged and one of them dropped)
for (MapLine line1 : endPoints.get(start)) {
if (line2.isSimilar(line1) && // don't make a closed loop a double loop
!line2.equals(line1)) {
mergeLines(line1, line2);
break;
}
}
isMerged = true;
break;
}
}
if (isMerged)
continue;
// (can the start of current line connected to an existing line?)
for (MapLine line2 : endPoints.get(start)) {
if (line.isSimilar(line2)) {
addPointsAtEnd(line2, points);
isMerged = true;
break;
}
}
if (isMerged)
continue;
// No matching, create a copy of line
MapLine l = line.copy();
// use better LinkedList for performance?
List<Coord> p = new ArrayList<Coord>(line.getPoints());
l.setPoints(p);
addLine(l);
}
return linesMerged;
}
use of uk.me.parabola.mkgmap.general.MapLine in project mkgmap by openstreetmap.
the class LineSizeSplitterFilter method doFilter.
/**
* Keep track of the max dimensions of a line and split when they get too
* big.
*
* @param element A map element.
* @param next This is used to pass the possibly transformed element onward.
*/
public void doFilter(MapElement element, MapFilterChain next) {
// We do not deal with shapes.
assert !(element instanceof MapShape) && element instanceof MapLine;
MapLine line = (MapLine) element;
if (line.getBounds().getMaxDimension() < maxSize) {
next.doFilter(element);
return;
}
if (line instanceof MapRoad) {
MapRoad road = ((MapRoad) line);
log.error("Way " + road.getRoadDef() + " has a max dimension of " + line.getBounds().getMaxDimension() + " and is about to be split (routing will be broken)");
}
// ensure that all single lines do not exceed the maximum size
// use a slightly decreased max size (-10) to get better results
// in the subdivision creation
List<Coord> points = splitLinesToMaxSize(line.getPoints(), maxSize - 10);
log.debug("line bbox too big, splitting");
MapLine l = line.copy();
List<Coord> coords = new ArrayList<Coord>();
boolean first = true;
/**
* Class to keep track of the dimensions.
*/
class Dim {
private int minLat;
private int minLong;
private int maxLat;
private int maxLong;
Dim() {
reset();
}
private void reset() {
minLat = Integer.MAX_VALUE;
minLong = Integer.MAX_VALUE;
maxLat = Integer.MIN_VALUE;
maxLong = Integer.MIN_VALUE;
}
private void addToBounds(Coord co) {
int lat = co.getLatitude();
if (lat < minLat)
minLat = lat;
if (lat > maxLat)
maxLat = lat;
int lon = co.getLongitude();
if (lon < minLong)
minLong = lon;
if (lon > maxLong)
maxLong = lon;
}
private int getMaxDim() {
int dx = maxLong - minLong;
int dy = maxLat - minLat;
return Math.max(dx, dy);
}
}
Dim dim = new Dim();
Coord prev = null;
// Add points while not too big and then start again with a fresh line.
for (Coord co : points) {
dim.addToBounds(co);
if (dim.getMaxDim() > maxSize) {
if (first)
log.debug("bigness saving first part");
else
log.debug("bigness saving next part");
l.setPoints(coords);
next.doFilter(l);
l = line.copy();
first = false;
dim.reset();
coords = new ArrayList<Coord>();
coords.add(prev);
dim.addToBounds(prev);
dim.addToBounds(co);
}
coords.add(co);
prev = co;
}
assert coords.size() > 1;
if (coords.size() > 1) {
log.debug("bigness saving a final part");
l.setPoints(coords);
next.doFilter(l);
}
}
use of uk.me.parabola.mkgmap.general.MapLine in project mkgmap by openstreetmap.
the class SizeFilter method doFilter.
/**
* This applies to both lines and polygons.
* Elements too small for current resolution will be dropped.
*
* @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;
if ((line.isSkipSizeFilter() || (checkRouting && line.isRoad())) == false) {
if (line.getBounds().getMaxDimension() < minSize) {
return;
}
}
next.doFilter(line);
}
use of uk.me.parabola.mkgmap.general.MapLine in project mkgmap by openstreetmap.
the class SmoothingFilter method doFilter.
/**
* This applies to both lines and polygons. We are going to smooth out
* the points in the line so that you do not get jaggies. We are assuming
* that there is not an excess of points at the highest resolution.
*
* <ol>
* <li>If there is just one point, the drop it.
* <li>Ff the element is too small altogether, then drop it.
* <li>If there are just two points the pass it on unchanged. This is
* probably a pretty common case.
* <li>The first point goes in unchanged.
* <li>Average points in groups so that they exceed the step size
* at the shifted resolution.
* </ol>
*
* @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;
// First off we don't touch things if at the highest level of detail
if (shift == 0) {
next.doFilter(element);
return;
}
// If the line is not very long then just let it through. This is done
// mainly for the background polygons.
List<Coord> points = line.getPoints();
int n = points.size();
if (n <= 5) {
next.doFilter(element);
return;
}
// Create a new list to rewrite the points into.
List<Coord> coords = new ArrayList<Coord>(n);
// Get the step size, we want to place a point every time the
// average exceeds this size.
int stepsize = MIN_SPACING << shift;
// Always add the first point
Coord last = points.get(0);
coords.add(last);
// Average the rest
Average av = new Average(last, stepsize);
for (int i = 1; i < n; i++) {
Coord co = points.get(i);
av.add(co);
if (av.isMoreThanStep()) {
Coord nco = av.getAverageCoord();
coords.add(nco);
if (av.pointCounter() > 1)
i--;
last = nco;
av.reset(last);
}
}
Coord end = points.get(n - 1);
if (!last.equals(end))
coords.add(end);
MapLine newline = line.copy();
newline.setPoints(coords);
next.doFilter(newline);
}
Aggregations