Skip to content

Commit

Permalink
Add buffer to vector tiles so wide symbols are not clipped at tile bo…
Browse files Browse the repository at this point in the history
…undaries
  • Loading branch information
smithkm committed Jun 13, 2017
1 parent 8d09c28 commit 43c8a18
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static class Context {

public double pixelSizeInTargetCRS; // approximate size of a pixel in the Target CRS

public int queryBuffer;
}

Context context;
Expand All @@ -98,20 +99,24 @@ private PipelineBuilder(Context context) {
* @throws FactoryException
*/
public static PipelineBuilder newBuilder(ReferencedEnvelope renderingArea, Rectangle paintArea,
CoordinateReferenceSystem sourceCrs, double overSampleFactor) throws FactoryException {
CoordinateReferenceSystem sourceCrs, double overSampleFactor, int queryBuffer)
throws FactoryException {

Context context = createContext(renderingArea, paintArea, sourceCrs, overSampleFactor);
Context context = createContext(renderingArea, paintArea, sourceCrs, overSampleFactor,
queryBuffer);
return new PipelineBuilder(context);
}

private static Context createContext(ReferencedEnvelope mapArea, Rectangle paintArea,
CoordinateReferenceSystem sourceCrs, double overSampleFactor) throws FactoryException {
CoordinateReferenceSystem sourceCrs, double overSampleFactor, int queryBuffer)
throws FactoryException {

Context context = new Context();
context.renderingArea = mapArea;
context.paintArea = paintArea;
context.sourceCrs = sourceCrs;
context.worldToScreen = RendererUtilities.worldToScreenTransform(mapArea, paintArea);
context.queryBuffer = queryBuffer;

final boolean wrap = false;
context.projectionHandler = ProjectionHandlerFinder.getHandler(mapArea, sourceCrs, wrap);
Expand Down Expand Up @@ -288,12 +293,12 @@ public PipelineBuilder clip(boolean clipToMapBounds, boolean transformToScreenCo
Rectangle screen = context.paintArea;

Envelope paintArea = new Envelope(0, screen.getWidth(), 0, screen.getHeight());
paintArea.expandBy(clipBBOXSizeIncreasePixels);
paintArea.expandBy(clipBBOXSizeIncreasePixels+context.queryBuffer);

clippingEnvelope = paintArea;
} else {
ReferencedEnvelope renderingArea = context.renderingArea;
renderingArea.expandBy(clipBBOXSizeIncreasePixels * context.pixelSizeInTargetCRS);
renderingArea.expandBy((clipBBOXSizeIncreasePixels+context.queryBuffer) * context.pixelSizeInTargetCRS);
clippingEnvelope = renderingArea;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.Layer;
import org.geotools.renderer.lite.VectorMapRenderUtils;
import org.geotools.util.logging.Logging;
import org.opengis.feature.Attribute;
import org.opengis.feature.ComplexAttribute;
import org.opengis.feature.Feature;
import org.opengis.feature.GeometryAttribute;
import org.opengis.feature.Property;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
Expand Down Expand Up @@ -114,71 +116,42 @@ public WebMap produceMap(final WMSMapContent mapContent) throws ServiceException
}

sourceCrs = geometryDescriptor.getType().getCoordinateReferenceSystem();

PipelineBuilder builder;
try {
builder = PipelineBuilder.newBuilder(renderingArea, paintArea, sourceCrs,
overSamplingFactor);
} catch (FactoryException e) {
throw new ServiceException(e);
}

Pipeline pipeline = builder.preprocess().transform(transformToScreenCoordinates)
.simplify(transformToScreenCoordinates)
.clip(clipToMapBounds, transformToScreenCoordinates).collapseCollections()
.build();

int buffer = VectorMapRenderUtils.getComputedBuffer(mapContent.getBuffer(),
VectorMapRenderUtils.getFeatureStyles(layer, paintArea,
VectorMapRenderUtils.getMapScale(mapContent, renderingArea),
(FeatureType)featureSource.getSchema()));
Pipeline pipeline = getPipeline(mapContent, renderingArea, paintArea, sourceCrs, buffer);

Query query = getStyleQuery(layer, mapContent);
query.getHints().remove(Hints.SCREENMAP);

FeatureCollection<?, ?> features = featureSource.getFeatures(query);
Feature feature;
Stopwatch sw = Stopwatch.createStarted();
int count = 0;
int total = 0;

try (FeatureIterator<?> it = features.features()) {
while (it.hasNext()) {
feature = it.next();
total++;
Geometry originalGeom;
Geometry finalGeom;

originalGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
try {
finalGeom = pipeline.execute(originalGeom);
} catch (Exception processingException) {
processingException.printStackTrace();
continue;
}
if (finalGeom.isEmpty()) {
continue;
}

final String layerName = feature.getName().getLocalPart();
final String featureId = feature.getIdentifier().toString();
final String geometryName = geometryDescriptor.getName().getLocalPart();

final Map<String, Object> properties = getProperties(feature);

vectorTileBuilder.addFeature(layerName, featureId, geometryName, finalGeom,
properties);
count++;
}
}
sw.stop();
if (LOGGER.isLoggable(Level.FINE)) {
String msg = String.format("Added %,d out of %,d features of '%s' in %s", count,
total, layer.getTitle(), sw);
// System.err.println(msg);
LOGGER.fine(msg);
}

run(features, pipeline, geometryDescriptor, vectorTileBuilder, layer);
}

WebMap map = vectorTileBuilder.build(mapContent);
return map;
}

protected Pipeline getPipeline(final WMSMapContent mapContent,
final ReferencedEnvelope renderingArea, final Rectangle paintArea,
CoordinateReferenceSystem sourceCrs, int buffer) {
Pipeline pipeline;
try {
final PipelineBuilder builder = PipelineBuilder.newBuilder(renderingArea, paintArea, sourceCrs,
overSamplingFactor, buffer);

pipeline = builder.preprocess().transform(transformToScreenCoordinates)
.simplify(transformToScreenCoordinates)
.clip(clipToMapBounds, transformToScreenCoordinates).collapseCollections()
.build();
} catch (FactoryException e) {
throw new ServiceException(e);
}
return pipeline;
}

private Map<String, Object> getProperties(ComplexAttribute feature) {
Map<String, Object> props = new TreeMap<>();
for (Property p : feature.getProperties()) {
Expand All @@ -199,6 +172,52 @@ private Map<String, Object> getProperties(ComplexAttribute feature) {
return props;
}

void run(FeatureCollection<?, ?> features, Pipeline pipeline,
GeometryDescriptor geometryDescriptor,
VectorTileBuilder vectorTileBuilder, Layer layer){
Stopwatch sw = Stopwatch.createStarted();
int count = 0;
int total = 0;
Feature feature;

try (FeatureIterator<?> it = features.features()) {
while (it.hasNext()) {
feature = it.next();
total++;
Geometry originalGeom;
Geometry finalGeom;

originalGeom = (Geometry) feature.getDefaultGeometryProperty().getValue();
try {
finalGeom = pipeline.execute(originalGeom);
} catch (Exception processingException) {
processingException.printStackTrace();
continue;
}
if (finalGeom.isEmpty()) {
continue;
}

final String layerName = feature.getName().getLocalPart();
final String featureId = feature.getIdentifier().toString();
final String geometryName = geometryDescriptor.getName().getLocalPart();

final Map<String, Object> properties = getProperties(feature);

vectorTileBuilder.addFeature(layerName, featureId, geometryName, finalGeom,
properties);
count++;
}
}
sw.stop();
if (LOGGER.isLoggable(Level.FINE)) {
String msg = String.format("Added %,d out of %,d features of '%s' in %s", count,
total, layer.getTitle(), sw);
// System.err.println(msg);
LOGGER.fine(msg);
}
}

/**
* @return {@code null}, not a raster format.
*/
Expand Down

0 comments on commit 43c8a18

Please sign in to comment.