use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class MapArea method splitIntoAreas.
/**
* Spit the polygon into areas
*
* @param areas The available areas to choose from.
* @param e The map element.
* @param used flag vector to say area has been added to.
*/
private void splitIntoAreas(MapArea[] areas, MapShape e) {
if (areas.length == 1) {
// this happens quite a lot
areas[0].addShape(e);
return;
}
// quick check if bbox of shape lies fully inside one of the areas
Area shapeBounds = e.getBounds();
// this is worked out at standard precision, along with Area.contains() and so can get
// tricky problems as it might not really be fully within the area.
// so: pretend the shape is a touch bigger. Will get the optimisation most of the time
// and in the boundary cases will fall into the precise code.
int xtra = 2;
// notices with an debug message and then output filters probably chuck away.
if (Math.min(shapeBounds.getWidth(), shapeBounds.getHeight()) > 8)
// pretend shape is smaller
xtra = -2;
shapeBounds = new Area(shapeBounds.getMinLat() - xtra, shapeBounds.getMinLong() - xtra, shapeBounds.getMaxLat() + xtra, shapeBounds.getMaxLong() + xtra);
for (int areaIndex = 0; areaIndex < areas.length; ++areaIndex) {
if (areas[areaIndex].getBounds().contains(shapeBounds)) {
areas[areaIndex].addShape(e);
return;
}
}
if (areasHashMap == null)
areasHashMap = new Long2ObjectOpenHashMap<>();
if (areas.length == 2) {
// just divide along the line between the two areas
int dividingLine = 0;
boolean isLongitude = false;
boolean commonLine = true;
if (areas[0].getBounds().getMaxLat() == areas[1].getBounds().getMinLat()) {
dividingLine = areas[0].getBounds().getMaxLat();
isLongitude = false;
} else if (areas[0].getBounds().getMaxLong() == areas[1].getBounds().getMinLong()) {
dividingLine = areas[0].getBounds().getMaxLong();
isLongitude = true;
} else {
commonLine = false;
log.error("Split into 2 expects shared edge between the areas");
}
if (commonLine) {
List<List<Coord>> lessList = new ArrayList<>(), moreList = new ArrayList<>();
ShapeSplitter.splitShape(e.getPoints(), dividingLine << Coord.DELTA_SHIFT, isLongitude, lessList, moreList, areasHashMap);
for (List<Coord> subShape : lessList) {
MapShape s = e.copy();
s.setPoints(subShape);
s.setClipped(true);
areas[0].addShape(s);
}
for (List<Coord> subShape : moreList) {
MapShape s = e.copy();
s.setPoints(subShape);
s.setClipped(true);
areas[1].addShape(s);
}
return;
}
}
for (int areaIndex = 0; areaIndex < areas.length; ++areaIndex) {
List<List<Coord>> subShapePoints = ShapeSplitter.clipToBounds(e.getPoints(), areas[areaIndex].getBounds(), areasHashMap);
for (List<Coord> subShape : subShapePoints) {
MapShape s = e.copy();
s.setPoints(subShape);
s.setClipped(true);
areas[areaIndex].addShape(s);
}
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class MapArea method addPolygons.
/**
* Add the polygons
* @param src The map data.
* @param resolution The current resolution of the layer.
*/
private void addPolygons(MapDataSource src, final int resolution) {
MapFilterChain chain = new MapFilterChain() {
public void doFilter(MapElement element) {
MapShape shape = (MapShape) element;
addShape(shape);
}
};
PolygonSubdivSizeSplitterFilter filter = new PolygonSubdivSizeSplitterFilter();
FilterConfig config = new FilterConfig();
config.setResolution(resolution);
config.setBounds(bounds);
filter.init(config);
for (MapShape s : src.getShapes()) {
if (s.getMaxResolution() < resolution)
continue;
if (splitPolygonsIntoArea || this.bounds.isEmpty() || this.bounds.contains(s.getBounds()))
// if splitPolygonsIntoArea, don't want to have other splitting as well.
// PolygonSubdivSizeSplitterFilter is a bit drastic - filters by both size and number of points
// so use splitPolygonsIntoArea logic for this as well. This is fine as long as there
// aren't bits of the shape outside the initial area.
addShape(s);
else
filter.doFilter(s, chain);
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class MapBuilder method processShapes.
/**
* Step through the polygons, filter, simplify if necessary, and create a map
* shape which is then added to the map.
*
* Note that the location and resolution of map elements is relative to the
* subdivision that they occur in.
*
* @param map The map to add polygons to.
* @param div The subdivision that the polygons belong to.
* @param shapes The polygons to be added.
*/
private void processShapes(Map map, Subdivision div, List<MapShape> shapes) {
// Signal that we are beginning to draw the shapes.
div.startShapes();
int res = div.getResolution();
FilterConfig config = new FilterConfig();
config.setResolution(res);
config.setLevel(div.getZoom().getLevel());
config.setRoutable(doRoads);
if (mergeShapes) {
ShapeMergeFilter shapeMergeFilter = new ShapeMergeFilter(res, orderByDecreasingArea);
List<MapShape> mergedShapes = shapeMergeFilter.merge(shapes);
shapes = mergedShapes;
}
if (orderByDecreasingArea && shapes.size() > 1) {
// sort so that the shape with the largest area is processed first
Collections.sort(shapes, new Comparator<MapShape>() {
public int compare(MapShape s1, MapShape s2) {
return Long.compare(Math.abs(s2.getFullArea()), Math.abs(s1.getFullArea()));
}
});
}
preserveHorizontalAndVerticalLines(res, shapes);
LayerFilterChain filters = new LayerFilterChain(config);
filters.addFilter(new PolygonSplitterFilter());
if (enableLineCleanFilters && (res < 24)) {
filters.addFilter(new RoundCoordsFilter());
int sizefilterVal = getMinSizePolygonForResolution(res);
if (sizefilterVal > 0)
filters.addFilter(new SizeFilter(sizefilterVal));
// Is there an similar algorithm for polygons?
if (reducePointErrorPolygon > 0)
filters.addFilter(new DouglasPeuckerFilter(reducePointErrorPolygon));
}
filters.addFilter(new RemoveObsoletePointsFilter());
filters.addFilter(new RemoveEmpty());
filters.addFilter(new LinePreparerFilter(div));
filters.addFilter(new ShapeAddFilter(div, map));
for (MapShape shape : shapes) {
if (shape.getMinResolution() > res)
continue;
filters.startFilter(shape);
}
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class MapBuilder method prepShapesForMerge.
/**
* for the overview map:
* Make sure that all {@link Coord} instances are
* identical when they are equal.
* @param shapes the list of shapes
*/
private static void prepShapesForMerge(List<MapShape> shapes) {
Long2ObjectOpenHashMap<Coord> coordMap = new Long2ObjectOpenHashMap<>();
for (MapShape s : shapes) {
List<Coord> points = s.getPoints();
int n = points.size();
for (int i = 0; i < n; i++) {
Coord co = points.get(i);
Coord repl = coordMap.get(Utils.coord2Long(co));
if (repl == null)
coordMap.put(Utils.coord2Long(co), co);
else
points.set(i, repl);
}
}
return;
}
use of uk.me.parabola.mkgmap.general.MapShape in project mkgmap by openstreetmap.
the class MapBuilder method makeSubdivision.
/**
* Make an individual subdivision for the map. To do this we need a link
* to its parent and the zoom level that we are working at.
*
* @param map The map to add this subdivision into.
* @param parent The parent division.
* @param ma The area of the map that we are fitting into this division.
* @param z The zoom level.
* @return The new subdivsion.
*/
private Subdivision makeSubdivision(Map map, Subdivision parent, MapArea ma, Zoom z) {
List<MapPoint> points = ma.getPoints();
List<MapLine> lines = ma.getLines();
List<MapShape> shapes = ma.getShapes();
Subdivision div = map.createSubdivision(parent, ma.getFullBounds(), z);
if (ma.hasPoints())
div.setHasPoints(true);
if (ma.hasIndPoints())
div.setHasIndPoints(true);
if (ma.hasLines())
div.setHasPolylines(true);
if (ma.hasShapes())
div.setHasPolygons(true);
div.startDivision();
processPoints(map, div, points);
processLines(map, div, lines);
processShapes(map, div, shapes);
div.endDivision();
return div;
}
Aggregations