/******************************************************************************* * Copyright 2013-2016 alladin-IT GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package at.alladin.rmbt.mapServer; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Path2D; import java.io.ByteArrayOutputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.imageio.ImageIO; import org.postgis.Geometry; import org.postgis.MultiPolygon; import org.postgis.PGgeometry; import org.postgis.Point; import org.postgis.Polygon; import org.restlet.data.Form; import at.alladin.rmbt.mapServer.MapServerOptions.MapOption; import at.alladin.rmbt.mapServer.MapServerOptions.SQLFilter; import at.alladin.rmbt.mapServer.parameters.ShapeTileParameters; import at.alladin.rmbt.mapServer.parameters.TileParameters.Path; import com.google.common.base.Strings; public class ShapeTiles extends TileRestlet<ShapeTileParameters> { private static class GeometryColor { final Geometry geometry; final Color color; public GeometryColor(final Geometry geometry, final Color color) { this.geometry = geometry; this.color = color; } } @Override protected ShapeTileParameters getTileParameters(Path path, Form params) { return new ShapeTileParameters(path, params); } @Override protected byte[] generateTile(final ShapeTileParameters params, final int tileSizeIdx, final int zoom, final DBox box, final MapOption mo, final List<SQLFilter> filters, final float quantile) { Connection con = null; PreparedStatement ps = null; ResultSet rs = null; double _transparency = params.getTransparency(); try { con = DbConnection.getConnection(); final StringBuilder whereSQL = new StringBuilder(mo.sqlFilter); for (final SQLFilter sf : filters) whereSQL.append(" AND ").append(sf.where); /* * old zip code * final String sql = String.format( "WITH box AS" + " (SELECT ST_SetSRID(ST_MakeBox2D(ST_Point(?,?)," + " ST_Point(?,?)), 900913) AS box)" + " SELECT" + " ST_SnapToGrid(ST_intersection(p.the_geom, box.box), ?,?,?,?) AS geom," + " count(\"%1$s\") count," + " quantile(\"%1$s\",?) val" + " FROM box, plz2001 p" + " JOIN v_test2 t ON t.zip_code=p.plz_4" + " WHERE" + " %2$s" + " AND p.the_geom && box.box" + " AND ST_intersects(p.the_geom, box.box)" + " GROUP BY p.the_geom, box.box", mo.valueColumnLog, whereSQL); */ final String sql = String.format( "WITH box AS" + " (SELECT ST_SetSRID(ST_MakeBox2D(ST_Point(?,?)," + " ST_Point(?,?)), 900913) AS box)" + " SELECT" + " ST_SnapToGrid(ST_intersection(p.the_geom, box.box), ?,?,?,?) AS geom," + " count(\"%1$s\") count," + " quantile(\"%1$s\",?) val" + " FROM box, kategorisierte_gemeinden p" + " JOIN v_test2 t ON t.gkz=p.gemeinde_i" + " WHERE" + " %2$s" + " AND p.the_geom && box.box" + " AND ST_intersects(p.the_geom, box.box)" + " GROUP BY p.the_geom, box.box", mo.valueColumnLog, whereSQL); ps = con.prepareStatement(sql); int idx = 1; /* makeBox2D */ final double margin = box.res * 1; ps.setDouble(idx++, box.x1 - margin); ps.setDouble(idx++, box.y1 - margin); ps.setDouble(idx++, box.x2 + margin); ps.setDouble(idx++, box.y2 + margin); /* snapToGrid */ ps.setDouble(idx++, box.x1); ps.setDouble(idx++, box.y1); ps.setDouble(idx++, box.res); ps.setDouble(idx++, box.res); ps.setFloat(idx++, quantile); for (final SQLFilter sf : filters) idx = sf.fillParams(idx, ps); rs = ps.executeQuery(); if (rs == null) throw new IllegalArgumentException(); final List<GeometryColor> geoms = new ArrayList<>(); while (rs.next()) { final String geomStr = rs.getString("geom"); if (! Strings.isNullOrEmpty(geomStr)) { final Geometry geom = PGgeometry.geomFromString(geomStr); final long count = rs.getLong("count"); final double val = rs.getDouble("val"); final int colorInt = valueToColor(mo.colorsSorted, mo.intervalsSorted, val); double transparency = ((double)count / 20d) * _transparency; if (transparency > _transparency) transparency = _transparency; final int alpha = (int) Math.round(transparency * 255) << 24; final Color color = new Color(colorInt | alpha, true); geoms.add(new GeometryColor(geom, color)); } } if (geoms.isEmpty()) return null; final Image img = images[tileSizeIdx].get(); final Graphics2D g = img.g; g.setBackground(new Color(0, 0, 0, 0)); g.clearRect(0, 0, img.width, img.height); // g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); final Path2D.Double path = new Path2D.Double(); for (final GeometryColor geomColor : geoms) { final Geometry geom = geomColor.geometry; final Polygon[] polys; if (geom instanceof MultiPolygon) polys = ((MultiPolygon) geom).getPolygons(); else if (geom instanceof Polygon) polys = new Polygon[] { (Polygon) geom }; else polys = new Polygon[] {}; for (final Polygon poly : polys) for (int i = 0; i < poly.numRings(); i++) { final Point[] points = poly.getRing(i).getPoints(); path.reset(); boolean initial = true; for (final Point point : points) { final double relX = (point.x - box.x1) / box.res; final double relY = TILE_SIZES[tileSizeIdx] - (point.y - box.y1) / box.res; if (initial) { initial = false; path.moveTo(relX, relY); } path.lineTo(relX, relY); } g.setPaint(geomColor.color); g.fill(path); } } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(img.bi, "png", baos); final byte[] data = baos.toByteArray(); return data; } catch (final Exception e) { e.printStackTrace(); throw new IllegalStateException(e); } finally { try { if (rs != null) rs.close(); if (ps != null) ps.close(); if (con != null) con.close(); } catch (final SQLException e) { e.printStackTrace(); throw new IllegalStateException(e); } } } }