Commit 9a96d656 authored by Matija Obreza's avatar Matija Obreza

Using round "dots" in accession tile server

parent 76f89223
......@@ -26,7 +26,7 @@ import org.genesys2.server.service.impl.FilterHandler.AppliedFilters;
public interface MappingService {
/** The default tile color. */
public Color DEFAULT_TILE_COLOR = Color.decode("#88ba41");
public Color DEFAULT_TILE_COLOR = Color.decode("#578218");
/**
* Clear the tiles cache.
......
......@@ -28,25 +28,29 @@ import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.QueryResults;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Predicate;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQuery;
import org.genesys.blocks.model.filters.BasicModelFilter;
import org.genesys2.server.exception.MaxPageLimitException;
import org.genesys2.server.model.elastic.AccessionDetails;
import org.genesys2.server.model.genesys.*;
import org.genesys2.server.model.genesys.Accession;
import org.genesys2.server.model.genesys.Method;
import org.genesys2.server.model.genesys.QAccession;
import org.genesys2.server.model.genesys.QAccessionGeo;
import org.genesys2.server.model.impl.Country;
import org.genesys2.server.model.impl.Crop;
import org.genesys2.server.model.impl.FaoInstitute;
import org.genesys2.server.model.impl.GeoRegion;
import org.genesys2.server.persistence.AccessionRepository;
import org.genesys2.server.persistence.MethodRepository;
import org.genesys2.server.service.*;
import org.genesys2.server.service.CropService;
import org.genesys2.server.service.ElasticsearchService;
import org.genesys2.server.service.ElasticsearchService.Term;
import org.genesys2.server.service.ElasticsearchService.TermResult;
import org.genesys2.server.service.FilterConstants;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.GenesysService;
import org.genesys2.server.service.GeoRegionService;
import org.genesys2.server.service.GeoService;
import org.genesys2.server.service.InstituteService;
import org.genesys2.server.service.TaxonomyService;
import org.genesys2.server.service.filter.AccessionFilter;
import org.genesys2.server.service.filter.AppliedFiltersConverter;
import org.genesys2.server.service.impl.DirectMysqlQuery.MethodResolver;
......@@ -68,6 +72,11 @@ import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.JPQLQuery;
import com.querydsl.jpa.impl.JPAQuery;
@Service
@Transactional(readOnly = true)
public class GenesysFilterServiceImpl implements GenesysFilterService {
......@@ -444,6 +453,7 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
query.select(accessionGeo.longitude, accessionGeo.latitude).distinct().from(accession);
BooleanBuilder filt = new BooleanBuilder();
filt.and(accession.tileIndex.isNotNull());
if (filter != null) {
filt.and(filter.buildQuery());
}
......@@ -467,9 +477,9 @@ public class GenesysFilterServiceImpl implements GenesysFilterService {
}
query.where(filt);
QueryResults<Tuple> results = query.fetchResults();
List<Tuple> results = query.fetch();
return results.getResults().stream()
return results.stream()
.map(item -> new Double[]{
item.get(accessionGeo.longitude),
item.get(accessionGeo.latitude),
......
......@@ -16,6 +16,7 @@
package org.genesys2.server.service.impl;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
......@@ -23,11 +24,12 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.imageio.ImageIO;
import org.genesys.blocks.model.filters.BasicModelFilter;
import org.genesys2.server.service.GenesysFilterService;
import org.genesys2.server.service.MappingService;
import org.genesys2.server.service.filter.AccessionFilter;
......@@ -35,6 +37,7 @@ import org.genesys2.server.service.impl.FilterHandler.AppliedFilters;
import org.genesys2.util.CoordUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
......@@ -47,7 +50,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@Service
public class MappingServiceImpl implements MappingService {
public class MappingServiceImpl implements MappingService, InitializingBean {
// A 3x3 kernel that blurs an image
// Kernel kernel = new Kernel(3, 3, new float[] { 0.05f, 0.1f, 0.05f, 0.05f,
......@@ -76,40 +79,42 @@ public class MappingServiceImpl implements MappingService {
private final ObjectMapper mapper = new ObjectMapper();
private List<BufferedImage> zoomTemplates = new ArrayList<>();
@Override
public void filteredKml(AppliedFilters filters, OutputStream outputStream) throws IOException {
filterService.transformFiltersIfNeed(filters);
LOG.debug(filters.toString());
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
writer.write("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
writer.write("<Document>");
final OutputStreamWriter finalWriter = writer;
filterService.listGeo(filters, null, new RowCallbackHandler() {
@Override
public void processRow(final ResultSet rs) throws SQLException {
try {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<Placemark>");
stringBuilder.append("<name>").append(rs.getString("acceNumb")).append("</name>");
stringBuilder.append("<description></description>");
stringBuilder.append("<Point><coordinates>");
stringBuilder.append(rs.getDouble("longitude")).append(",").append(rs.getDouble("latitude"));
stringBuilder.append("</coordinates></Point>");
stringBuilder.append("</Placemark>");
finalWriter.write(stringBuilder.toString());
finalWriter.flush();
} catch (final SQLException e) {
LOG.warn(e.getMessage());
throw e;
} catch (final IOException e) {
LOG.warn(e.getMessage());
}
}
});
finalWriter.write("</Document></kml>");
finalWriter.flush();
OutputStreamWriter writer = new OutputStreamWriter(outputStream);
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
writer.write("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
writer.write("<Document>");
final OutputStreamWriter finalWriter = writer;
filterService.listGeo(filters, null, new RowCallbackHandler() {
@Override
public void processRow(final ResultSet rs) throws SQLException {
try {
final StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<Placemark>");
stringBuilder.append("<name>").append(rs.getString("acceNumb")).append("</name>");
stringBuilder.append("<description></description>");
stringBuilder.append("<Point><coordinates>");
stringBuilder.append(rs.getDouble("longitude")).append(",").append(rs.getDouble("latitude"));
stringBuilder.append("</coordinates></Point>");
stringBuilder.append("</Placemark>");
finalWriter.write(stringBuilder.toString());
finalWriter.flush();
} catch (final SQLException e) {
LOG.warn(e.getMessage());
throw e;
} catch (final IOException e) {
LOG.warn(e.getMessage());
}
}
});
finalWriter.write("</Document></kml>");
finalWriter.flush();
}
@Override
......@@ -165,34 +170,86 @@ public class MappingServiceImpl implements MappingService {
@Cacheable(value = "tileserver", key = "'tile-' + #zoom + '-' + #xtile + '-' + #ytile + '-' + #filters")
public byte[] getTile(AccessionFilter filters, int zoom, int xtile, int ytile) {
final BufferedImage bufferedImage = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
final int[] pixelSizes = new int[] { 0, 0, 0, 1, 1, 2, 2, 2, 3, 2, 2, 3 };
final int pixelSize = pixelSizes[zoom >= pixelSizes.length ? pixelSizes.length - 1 : zoom];
final int colorWithoutAlpha = MappingService.DEFAULT_TILE_COLOR.getRGB();
BufferedImage accessionDot = zoomTemplates.get(zoomTemplates.size() > zoom ? zoom : zoomTemplates.size() - 1);
List<Double[]> geoTiles = filterService.listGeoTile(filters, null, zoom, xtile, ytile);
geoTiles.forEach(item -> {
final int longitude = CoordUtil.lonToImg3(zoom, xtile, item[0]);
final int latitude = CoordUtil.latToImg3(zoom, ytile, item[1]);
AtomicInteger paints = new AtomicInteger(0);
geoTiles.stream().map(item -> new TilePos(zoom, xtile, ytile, item)).distinct().forEach(item -> {
paints.incrementAndGet();
for (int i = -pixelSize / 2; i <= pixelSize / 2; i++) {
for (int j = -pixelSize / 2; j <= pixelSize / 2; j++) {
if (longitude + i >= 0 && latitude + j >= 0 && longitude + i < 256 && latitude + j < 256) {
bufferedImage.setRGB(longitude + i, latitude + j, colorWithoutAlpha);
}
}
}
// calculates the coordinate where the image is painted
int topLeftX = item.longitude - accessionDot.getWidth() / 2;
int topLeftY = item.latitude - accessionDot.getHeight() / 2;
// paints the image watermark
g2d.drawImage(accessionDot, topLeftX, topLeftY, null);
});
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", baos);
LOG.trace("zoom={} dot={}x{} paints={} of={}", zoom, accessionDot.getWidth(), accessionDot.getHeight(), paints.intValue(), geoTiles.size());
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", baos);
return baos.toByteArray();
} catch (final IOException e) {
LOG.warn(e.getMessage(), e);
throw new RuntimeException("Couldn't render image", e);
} finally {
g2d.dispose();
}
}
@Override
public void afterPropertiesSet() throws Exception {
for (int i = 0; i < 20; i++) {
String accessionDotSource = "/tileserver/accessionDot" + i + ".png";
try {
BufferedImage accessionAtZoom = ImageIO.read(this.getClass().getResourceAsStream(accessionDotSource));
zoomTemplates.add(accessionAtZoom);
} catch (Throwable e) {
LOG.warn("Could not read accession time template {}: {}", accessionDotSource, e.getMessage());
}
}
}
/**
* Allows us to generate distinct dot locations
*/
private static class TilePos {
private int longitude;
private int latitude;
public TilePos(int zoom, int xtile, int ytile, Double[] item) {
this.longitude = CoordUtil.lonToImg3(zoom, xtile, item[0]);
this.latitude = CoordUtil.latToImg3(zoom, ytile, item[1]);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + latitude;
result = prime * result + longitude;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TilePos other = (TilePos) obj;
if (latitude != other.latitude)
return false;
if (longitude != other.longitude)
return false;
return true;
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment