Buildings overzoom: use TileSeparator (#518)

This commit is contained in:
Gustl22 2018-03-22 16:15:04 +01:00 committed by Emux
parent 27a3c5a926
commit 345b57c57a
No known key found for this signature in database
GPG Key ID: 89C6921D7AF2BDD0
4 changed files with 112 additions and 19 deletions

View File

@ -91,8 +91,7 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook {
@Override
public boolean process(MapTile tile, RenderBuckets buckets, MapElement element,
RenderStyle style, int level) {
// FIXME check why some buildings are processed up to 4 times (should avoid overhead)
// FIXME fix artifacts at tile borders
// FIXME artifacts at tile borders in last extraction zoom as they're clipped
if (!(style instanceof ExtrusionStyle))
return false;

View File

@ -1,5 +1,6 @@
/*
* Copyright 2018 devemux86
* Copyright 2018 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
@ -19,12 +20,14 @@ import org.oscim.backend.canvas.Bitmap;
import org.oscim.core.MapElement;
import org.oscim.core.Tile;
import org.oscim.utils.geom.TileClipper;
import org.oscim.utils.geom.TileSeparator;
class OverzoomDataSink implements ITileDataSink {
private final ITileDataSink sink;
private final TileClipper clipper;
private final TileSeparator separator;
private final float dx, dy, scale;
OverzoomDataSink(ITileDataSink sink, Tile overzoomTile, Tile tile) {
@ -37,12 +40,19 @@ class OverzoomDataSink implements ITileDataSink {
float buffer = 32 * CanvasAdapter.getScale();
clipper = new TileClipper((dx - buffer) / scale, (dy - buffer) / scale,
(dx + Tile.SIZE + buffer) / scale, (dy + Tile.SIZE + buffer) / scale);
separator = new TileSeparator(dx / scale, dy / scale,
(dx + Tile.SIZE) / scale, (dy + Tile.SIZE) / scale);
}
@Override
public void process(MapElement element) {
if (!clipper.clip(element))
return;
if (element.isBuilding() || element.isBuildingPart()) {
if (!separator.separate(element))
return;
} else {
if (!clipper.clip(element))
return;
}
element.scale(scale, scale);
element.translate(-dx, -dy);
sink.process(element);

View File

@ -37,6 +37,7 @@ import org.oscim.tiling.TileSource;
import org.oscim.tiling.source.mapfile.header.SubFileParameter;
import org.oscim.utils.Parameters;
import org.oscim.utils.geom.TileClipper;
import org.oscim.utils.geom.TileSeparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -206,6 +207,7 @@ public class MapDatabase implements ITileDataSource {
private final TileProjection mTileProjection;
private final TileClipper mTileClipper;
private final TileSeparator mTileSeparator;
private final MapFileTileSource mTileSource;
@ -229,6 +231,7 @@ public class MapDatabase implements ITileDataSource {
mTileProjection = new TileProjection();
mTileClipper = new TileClipper(0, 0, 0, 0);
mTileSeparator = new TileSeparator(0, 0, 0, 0);
}
public MapFileTileSource getTileSource() {
@ -406,9 +409,9 @@ public class MapDatabase implements ITileDataSource {
// private long mCurrentRow;
// private long mCurrentCol;
private int xmin, ymin, xmax, ymax;
private int xmin, ymin, xmax, ymax, xSmin, ySmin, xSmax, ySmax;
private void setTileClipping(QueryParameters queryParameters, long mCurrentRow, long mCurrentCol) {
private synchronized void setTileClipping(QueryParameters queryParameters, long mCurrentRow, long mCurrentCol) {
long numRows = queryParameters.toBlockY - queryParameters.fromBlockY;
long numCols = queryParameters.toBlockX - queryParameters.fromBlockX;
@ -421,28 +424,29 @@ public class MapDatabase implements ITileDataSource {
else
buffer = (int) (16 * CanvasAdapter.getScale() + 0.5f);
xmin = -buffer;
ymin = -buffer;
xmax = Tile.SIZE + buffer;
ymax = Tile.SIZE + buffer;
xmin = ymin = -buffer;
xmax = ymax = Tile.SIZE + buffer;
xSmin = ySmin = 0;
xSmax = ySmax = Tile.SIZE;
if (numRows > 0) {
int w = (int) (Tile.SIZE / (numCols + 1));
int h = (int) (Tile.SIZE / (numRows + 1));
if (mCurrentCol > 0)
xmin = (int) (mCurrentCol * w);
xSmin = xmin = (int) (mCurrentCol * w);
if (mCurrentCol < numCols)
xmax = (int) (mCurrentCol * w + w);
xSmax = xmax = (int) (mCurrentCol * w + w);
if (mCurrentRow > 0)
ymin = (int) (mCurrentRow * h);
ySmin = ymin = (int) (mCurrentRow * h);
if (mCurrentRow < numRows)
ymax = (int) (mCurrentRow * h + h);
ySmax = ymax = (int) (mCurrentRow * h + h);
}
mTileClipper.setRect(xmin, ymin, xmax, ymax);
mTileSeparator.setRect(xSmin, ySmin, xSmax, ySmax);
}
//private final static Tag mWaterTag = new Tag("natural", "water");
@ -957,12 +961,13 @@ public class MapDatabase implements ITileDataSource {
// Avoid clipping for buildings, which slows rendering.
// But clip everything if buildings are displayed.
if ((!e.tags.containsKey(Tag.KEY_BUILDING)
&& !e.tags.containsKey(Tag.KEY_BUILDING_PART))
|| queryParameters.queryZoomLevel >= BuildingLayer.MIN_ZOOM) {
if (!mTileClipper.clip(e)) {
if (!e.tags.containsKey(Tag.KEY_BUILDING)
&& !e.tags.containsKey(Tag.KEY_BUILDING_PART)) {
if (!mTileClipper.clip(e))
continue;
} else if (queryParameters.queryZoomLevel >= BuildingLayer.MIN_ZOOM) {
if (!mTileSeparator.separate(e))
continue;
}
}
e.simplify(1, true);

View File

@ -0,0 +1,79 @@
/*
* Copyright 2013 Hannes Janetzek
* Copyright 2018 Gustl22
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.oscim.utils.geom;
import org.oscim.core.GeometryBuffer;
public class TileSeparator {
private float xmin;
private float xmax;
private float ymin;
private float ymax;
public TileSeparator(float xmin, float ymin, float xmax, float ymax) {
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
this.ymax = ymax;
}
public void setRect(float xmin, float ymin, float xmax, float ymax) {
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
this.ymax = ymax;
}
/**
* Separates a poly geometry from tile (doesn't clip it).
*
* @param geom the geometry to be separated
* @return true if geometry is inside the tile, false otherwise
*/
public boolean separate(GeometryBuffer geom) {
if (!geom.isPoly())
return false;
int pointPos = 0;
for (int indexPos = 0, n = geom.index.length; indexPos < n; indexPos++) {
int len = geom.index[indexPos];
if (len < 0)
break;
if (len < 6) {
pointPos += len;
continue;
}
int end = pointPos + len;
for (int i = pointPos; i < end; ) {
float cx = geom.points[i++];
float cy = geom.points[i++];
if (cx >= xmin && cx < xmax && cy >= ymin && cy < ymax) {
/* current is inside */
return true;
}
}
pointPos += len;
}
geom.clear();
return false;
}
}