I'm using GeoTools in my java project to draw points in different sizes, color and opacity into a map. As there are a lot of different styles for them, I ended up with thousands of layers in my map. Currently each added point has his own layer cause I did not manage to add them to one single layer.
I'm getting the points from my Entity object. Every point from the same entity has the same color. There are more entities with the same name/color.
This is how one entity should be drawn on the map:
The size of the points is calculated dynamically in the following code snippet:
public class Stackoverflow {
private final MapContent mapContent;
public Stackoverflow() {
this.mapContent = new MapContent();
}
public void addPoints(final HashMap<String, Color> colorsForEntities, final List<Entity> toDraw){
final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
// Create SimpleFeatureType for Point
final SimpleFeatureTypeBuilder pointTb = new SimpleFeatureTypeBuilder();
pointTb.setName("points");
pointTb.setCRS(DefaultGeographicCRS.WGS84);
pointTb.add("point", Point.class);
final SimpleFeatureBuilder pointFeatureBuilder = new SimpleFeatureBuilder(pointTb.buildFeatureType());
for (final Entity entity : toDraw) {
final List<Point2D> pathPoints = entity.getPoints();
Color color = colorsForEntities.get(entity.getName());
Layer layerPoints;
Style pointStyle;
final float maxOpacity = MyProperties.getFloat(Constants.POINT_STYLE_OPACITY);
final float maxSize = MyProperties.getFloat(Constants.POINT_STYLE_SIZE);
final int NumPoints = pathPoints.size();
float opacity = maxOpacity;
float size = maxSize;
final float deltaOpacity = maxOpacity / NumPoints;
final float deltaSize = maxSize / NumPoints;
for (final Point2D point2D : pathPoints) {
final Point point = geometryFactory.createPoint(new Coordinate(point2D.getX(), point2D.getY()));
pointFeatureBuilder.add(point);
final SimpleFeature feature = pointFeatureBuilder.buildFeature(null);
final DefaultFeatureCollection pointCollection = new DefaultFeatureCollection();
pointCollection.add(feature);
pointStyle = SLD.createPointStyle("Circle", color, color, opacity, size);
opacity = opacity - deltaOpacity;
size = size - deltaSize;
layerPoints = new FeatureLayer(pointCollection, pointStyle);
mapContent.addLayer(layerPoints);
}
}
}
}
Is it possible to add the points to one single layer or at least getting much smaller amount of layers?
It can be done more efficiently :-) I think the easiest way would be to build your SimpleFeature
s from the entity
s so that they contain the color, size and opacity required. Something like:
final SimpleFeatureTypeBuilder pointTb = new SimpleFeatureTypeBuilder();
pointTb.setName("points");
pointTb.setCRS(DefaultGeographicCRS.WGS84);
pointTb.add("point", Point.class);
pointTb.add("color", String.class);
pointTb.add("size", Integer.class);
pointTb.add("opacity", Float.class);
final SimpleFeatureBuilder pointFeatureBuilder = new SimpleFeatureBuilder(pointTb.buildFeatureType());
Then you can create a single Style
that takes those properties and uses them to style each point. Something like (untested):
StyleBuilder sb = new StyleBuilder();
FilterFactory2 ff = sb.getFilterFactory();
Mark testMark = sb.createMark(sb.literalExpression("Circle"),
sb.createFill(sb.attributeExpression("color"),sb.attributeExpression("opacity")),
null);
Graphic graph = sb.createGraphic(null, // An external graphics if needed
new Mark[] { testMark }, // a Mark if not an external graphics
null, // aSymbol
ff.literal(sb.attributeExpression("opacity")), // opacity
ff.property("size"), // read from feature "size" attribute
ff.literal(0)); // rotation, here read into the feature
PointSymbolizer aPointSymbolizer = sb.createPointSymbolizer(graph);
// creation of the style
org.geotools.styling.Style style = sb.createStyle(aPointSymbolizer);
Since SLD doesn't provide any support for looping, I don't think there is any way to avoid having to break each entity
into a set of individual points with their own styling, unless you want to write a custom mark factory.