use of uk.me.parabola.imgfmt.app.Area in project mkgmap by openstreetmap.
the class ElementQuadTreeNode method split.
/**
* Splits this quadtree node into 4 subnodes.
*/
private void split() {
if (bounds.getHeight() <= 5 || bounds.getWidth() <= 5) {
log.error("Do not split more due to too small bounds: " + bounds);
return;
}
int halfLat = (bounds.getMinLat() + bounds.getMaxLat()) / 2;
int halfLong = (bounds.getMinLong() + bounds.getMaxLong()) / 2;
children = new ElementQuadTreeNode[4];
Area[] childBounds = new Area[4];
childBounds[0] = new Area(bounds.getMinLat(), bounds.getMinLong(), halfLat, halfLong);
childBounds[1] = new Area(halfLat, bounds.getMinLong(), bounds.getMaxLat(), halfLong);
childBounds[2] = new Area(bounds.getMinLat(), halfLong, halfLat, bounds.getMaxLong());
childBounds[3] = new Area(halfLat, halfLong, bounds.getMaxLat(), bounds.getMaxLong());
List<Map<Element, List<Coord>>> childElems = new ArrayList<Map<Element, List<Coord>>>(4);
for (int i = 0; i < 4; i++) {
childElems.add(new HashMap<Element, List<Coord>>());
}
for (Entry<Element, List<Coord>> elem : elementMap.entrySet()) {
if (elem.getKey() instanceof Node) {
Node node = (Node) elem.getKey();
for (int i = 0; i < childBounds.length; i++) {
if (childBounds[i].contains(node.getLocation())) {
childElems.get(i).put(node, EMPTY_LIST);
break;
}
}
} else if (elem.getKey() instanceof Way) {
List<List<Coord>> points = new ArrayList<List<Coord>>(4);
for (int i = 0; i < 4; i++) {
// usually ways are quite local
// therefore there is a high probability that only one child is covered
// dim the new list as the old list
points.add(new ArrayList<Coord>(elem.getValue().size()));
}
for (Coord c : elem.getValue()) {
for (int i = 0; i < childBounds.length; i++) {
if (childBounds[i].contains(c)) {
points.get(i).add(c);
break;
}
}
}
for (int i = 0; i < 4; i++) {
if (points.get(i).isEmpty() == false) {
childElems.get(i).put(elem.getKey(), points.get(i));
}
}
}
}
for (int i = 0; i < 4; i++) {
children[i] = new ElementQuadTreeNode(childBounds[i], childElems.get(i));
}
elementMap = null;
}
use of uk.me.parabola.imgfmt.app.Area in project mkgmap by openstreetmap.
the class ElementQuadTreeNode method get.
/**
* Retrieves all elements that intersects the given polygon.
* @param polygon the polygon
* @param resultList results are stored in this collection
* @return the resultList
*/
public Set<Element> get(ElementQuadTreePolygon polygon, Set<Element> resultList) {
if (isEmpty()) {
return resultList;
}
if (polygon.getBbox().intersects(getBounds())) {
if (isLeaf()) {
for (Entry<Element, List<Coord>> elem : elementMap.entrySet()) {
if (resultList.contains(elem.getKey())) {
continue;
}
if (elem.getKey() instanceof Node) {
Node n = (Node) elem.getKey();
Coord c = n.getLocation();
if (polygon.getArea().contains(c.getLongitude(), c.getLatitude())) {
resultList.add(n);
}
} else if (elem.getKey() instanceof Way) {
for (Coord c : elem.getValue()) {
if (polygon.getArea().contains(c.getLongitude(), c.getLatitude())) {
resultList.add(elem.getKey());
break;
}
}
}
}
} else {
for (ElementQuadTreeNode child : children) {
if (child.isEmpty() == false && polygon.getArea().intersects(child.getBoundsAsRectangle())) {
java.awt.geom.Area subArea = (java.awt.geom.Area) polygon.getArea().clone();
subArea.intersect(Java2DConverter.createBoundsArea(new Area(child.getBounds().getMinLat() - 1, child.getBounds().getMinLong() - 1, child.getBounds().getMaxLat() + 1, child.getBounds().getMaxLong() + 1)));
child.get(new ElementQuadTreePolygon(subArea), resultList);
}
}
}
}
return resultList;
}
use of uk.me.parabola.imgfmt.app.Area in project mkgmap by openstreetmap.
the class LineClipperTest method testAllInside.
/**
* If all the lines are inside, then it should just return null to indicate that.
*/
@Test
public void testAllInside() {
Area a = new Area(100, 100, 200, 200);
List<Coord> l = Arrays.asList(new Coord(102, 110), new Coord(150, 150), new Coord(190, 195));
List<List<Coord>> list = LineClipper.clip(a, l);
assertNull("all lines inside", list);
}
use of uk.me.parabola.imgfmt.app.Area in project mkgmap by openstreetmap.
the class LineClipperTest method testExampleClip.
/**
* This is the example as given on the referenced web page.
* We now use integers instead of floats so the 101.425 from the
* example is just 101 here.
*/
@Test
public void testExampleClip() {
Area a = new Area(60, 70, 150, 230);
Coord[] co = { new Coord(20, 30), new Coord(160, 280) };
List<List<Coord>> listList = LineClipper.clip(a, Arrays.asList(co));
assertTrue("list should be empty", !listList.isEmpty());
Coord[] result = { new Coord(60, 101), new Coord(132, 230) };
assertArrayEquals("example result", result, listList.get(0).toArray());
}
use of uk.me.parabola.imgfmt.app.Area in project mkgmap by openstreetmap.
the class MapArea method split.
/**
* Split this area into several pieces. All the map elements are reallocated
* to the appropriate subarea. Usually this instance would now be thrown
* away and the new sub areas used instead.
* <p>
* This code is dealing with a lot of factors that govern the splitting, eg:
* splitPolygonsIntoArea,
* tooSmallToDivide,
* item.minResolution vs. areaResolution,
* number/size of items and the limits of a subDivision,
* items that exceed maximum subDivision on their own,
* items that extend up to 50% outside the current area,
* items bigger than this.
*
* @param nx The number of pieces in the x (longitude) direction.
* @param ny The number of pieces in the y direction.
* @param bounds the bounding box that is used to create the areas.
* @param tooSmallToDivide the area is small and data overflows; split into overflow areas
*
* @return An array of the new MapArea's or null if can't split.
*/
public MapArea[] split(int nx, int ny, Area bounds, boolean tooSmallToDivide) {
int resolutionShift = MAX_RESOLUTION - areaResolution;
Area[] areas = bounds.split(nx, ny, resolutionShift);
if (areas == null) {
// Failed to split!
if (log.isDebugEnabled()) {
// see what is here
for (MapLine e : this.lines) if (e.getMinResolution() <= areaResolution)
log.debug("line. locn=", e.getPoints().get(0).toOSMURL(), " type=", uk.me.parabola.mkgmap.reader.osm.GType.formatType(e.getType()), " name=", e.getName(), " min=", e.getMinResolution(), " max=", e.getMaxResolution());
for (MapShape e : this.shapes) if (e.getMinResolution() <= areaResolution)
log.debug("shape. locn=", e.getPoints().get(0).toOSMURL(), " type=", uk.me.parabola.mkgmap.reader.osm.GType.formatType(e.getType()), " name=", e.getName(), " min=", e.getMinResolution(), " max=", e.getMaxResolution(), " full=", e.getFullArea(), " calc=", uk.me.parabola.mkgmap.filters.ShapeMergeFilter.calcAreaSizeTestVal(e.getPoints()));
// the main culprits are lots of bits of sea and coastline in an overview map (res 12)
}
return null;
}
MapArea[] mapAreas = new MapArea[nx * ny];
log.info("Splitting area " + bounds + " into " + nx + "x" + ny + " pieces at resolution " + areaResolution, tooSmallToDivide);
List<MapArea> addedAreas = new ArrayList<>();
for (int i = 0; i < mapAreas.length; i++) {
mapAreas[i] = new MapArea(areas[i], areaResolution, splitPolygonsIntoArea);
if (log.isDebugEnabled())
log.debug("area before", mapAreas[i].getBounds());
}
int xbaseHp = areas[0].getMinLong() << Coord.DELTA_SHIFT;
int ybaseHp = areas[0].getMinLat() << Coord.DELTA_SHIFT;
int dxHp = areas[0].getWidth() << Coord.DELTA_SHIFT;
int dyHp = areas[0].getHeight() << Coord.DELTA_SHIFT;
// Some of the work done by PolygonSubdivSizeSplitterFilter now done here
final int maxSize = Math.min((1 << 24) - 1, Math.max(MapSplitter.MAX_DIVISION_SIZE << (MAX_RESOLUTION - areaResolution), 0x8000));
/**
* These constants control when an item (shape unless splitPolygonsIntoArea or line) is shifted into its own MapArea/SubDivision.
* Generally, an item is allowed into the MapArea chosen by centre provided it is no bigger than the MapArea.
* This means that there could be big items near the edges of the MapArea that stick out by almost half, so must
* ensure that this doesn't cause the mapArea to exceed subDivision size limits.
* When the MapArea get small, we don't want to shift lots if items into their own areas;
* The *2 of LARGE_OBJECT_DIM is to keep to the same behaviour as earlier versions.
*/
final int maxWidth = Math.max(Math.min(areas[0].getWidth(), maxSize / 2), LARGE_OBJECT_DIM * 2);
final int maxHeight = Math.max(Math.min(areas[0].getHeight(), maxSize / 2), LARGE_OBJECT_DIM * 2);
// and don't have a good tooSmallToDivide strategy when not splitPolygonsIntoArea.
if (tooSmallToDivide) {
distShapesIntoNewAreas(addedAreas, mapAreas[0]);
} else {
for (MapShape e : this.shapes) {
Area shapeBounds = e.getBounds();
if (splitPolygonsIntoArea || shapeBounds.getMaxDimension() > maxSize) {
splitIntoAreas(mapAreas, e);
continue;
}
int areaIndex = pickArea(mapAreas, e, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
if ((shapeBounds.getHeight() > maxHeight || shapeBounds.getWidth() > maxWidth) && !areas[areaIndex].contains(shapeBounds)) {
// use splitIntoAreas to deal with overflow
MapArea largeObjectArea = new MapArea(shapeBounds, areaResolution, true);
largeObjectArea.addShape(e);
addedAreas.add(largeObjectArea);
continue;
}
mapAreas[areaIndex].addShape(e);
}
}
if (tooSmallToDivide) {
distPointsIntoNewAreas(addedAreas, mapAreas[0]);
} else {
for (MapPoint p : this.points) {
int areaIndex = pickArea(mapAreas, p, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
mapAreas[areaIndex].addPoint(p);
}
}
if (tooSmallToDivide) {
distLinesIntoNewAreas(addedAreas, mapAreas[0]);
} else {
for (MapLine l : this.lines) {
// Drop any zero sized lines.
if (l instanceof MapRoad == false && l.getRect().height <= 0 && l.getRect().width <= 0)
continue;
Area lineBounds = l.getBounds();
int areaIndex = pickArea(mapAreas, l, xbaseHp, ybaseHp, nx, ny, dxHp, dyHp);
if ((lineBounds.getHeight() > maxHeight || lineBounds.getWidth() > maxWidth) && !areas[areaIndex].contains(lineBounds)) {
MapArea largeObjectArea = new MapArea(lineBounds, areaResolution, false);
largeObjectArea.addLine(l);
addedAreas.add(largeObjectArea);
continue;
}
mapAreas[areaIndex].addLine(l);
}
}
if (!addedAreas.isEmpty()) {
// combine list and array
int pos = mapAreas.length;
mapAreas = Arrays.copyOf(mapAreas, mapAreas.length + addedAreas.size());
for (MapArea ma : addedAreas) {
if (// distShapesIntoNewAreas etc didn't know how big it was going to be
ma.getBounds() == null)
// so set to bounds of all elements
ma.setBounds(ma.getFullBounds());
mapAreas[pos++] = ma;
}
}
return mapAreas;
}
Aggregations