diff --git a/src/main/java/org/genesys2/server/service/MappingService.java b/src/main/java/org/genesys2/server/service/MappingService.java index 76cf58cef1ce34426bb1f8f3734c6f9a7d716f95..2b2d99a00ea21af99c9ef8a21d68e6352f78e267 100644 --- a/src/main/java/org/genesys2/server/service/MappingService.java +++ b/src/main/java/org/genesys2/server/service/MappingService.java @@ -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. diff --git a/src/main/java/org/genesys2/server/service/impl/GenesysFilterServiceImpl.java b/src/main/java/org/genesys2/server/service/impl/GenesysFilterServiceImpl.java index db515dd524dd2621341d4645eec5c30c2cdcb30e..cfdaab890fb28f0e5883cefcddda2cd11db90540 100644 --- a/src/main/java/org/genesys2/server/service/impl/GenesysFilterServiceImpl.java +++ b/src/main/java/org/genesys2/server/service/impl/GenesysFilterServiceImpl.java @@ -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 results = query.fetchResults(); + List results = query.fetch(); - return results.getResults().stream() + return results.stream() .map(item -> new Double[]{ item.get(accessionGeo.longitude), item.get(accessionGeo.latitude), diff --git a/src/main/java/org/genesys2/server/service/impl/MappingServiceImpl.java b/src/main/java/org/genesys2/server/service/impl/MappingServiceImpl.java index 535f3647285ecf1df24950a228d203cbed2b88a1..d243b19a246dc8f6061f3f00ebf9241f98b0a54f 100644 --- a/src/main/java/org/genesys2/server/service/impl/MappingServiceImpl.java +++ b/src/main/java/org/genesys2/server/service/impl/MappingServiceImpl.java @@ -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 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(""); - writer.write(""); - writer.write(""); - 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(""); - stringBuilder.append("").append(rs.getString("acceNumb")).append(""); - stringBuilder.append(""); - stringBuilder.append(""); - stringBuilder.append(rs.getDouble("longitude")).append(",").append(rs.getDouble("latitude")); - stringBuilder.append(""); - stringBuilder.append(""); - 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(""); - finalWriter.flush(); + OutputStreamWriter writer = new OutputStreamWriter(outputStream); + writer.write(""); + writer.write(""); + writer.write(""); + 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(""); + stringBuilder.append("").append(rs.getString("acceNumb")).append(""); + stringBuilder.append(""); + stringBuilder.append(""); + stringBuilder.append(rs.getDouble("longitude")).append(",").append(rs.getDouble("latitude")); + stringBuilder.append(""); + stringBuilder.append(""); + 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(""); + 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 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; } } } diff --git a/src/main/resources/tileserver/accessionDot-v2.xcf b/src/main/resources/tileserver/accessionDot-v2.xcf new file mode 100644 index 0000000000000000000000000000000000000000..18cfccb459d6125f369a25a63a0c071017f700be Binary files /dev/null and b/src/main/resources/tileserver/accessionDot-v2.xcf differ diff --git a/src/main/resources/tileserver/accessionDot.xcf b/src/main/resources/tileserver/accessionDot.xcf new file mode 100644 index 0000000000000000000000000000000000000000..8e9aeccebd5d7fc0bb8cd8ae0cb524b6f85ba681 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot.xcf differ diff --git a/src/main/resources/tileserver/accessionDot0.png b/src/main/resources/tileserver/accessionDot0.png new file mode 100644 index 0000000000000000000000000000000000000000..0f67eec9347448d897feeed2d51b4e3afdd82336 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot0.png differ diff --git a/src/main/resources/tileserver/accessionDot1.png b/src/main/resources/tileserver/accessionDot1.png new file mode 100644 index 0000000000000000000000000000000000000000..0f67eec9347448d897feeed2d51b4e3afdd82336 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot1.png differ diff --git a/src/main/resources/tileserver/accessionDot10.png b/src/main/resources/tileserver/accessionDot10.png new file mode 100644 index 0000000000000000000000000000000000000000..e4ee72f917294d4199c6b6ba535978a07bf00464 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot10.png differ diff --git a/src/main/resources/tileserver/accessionDot11.png b/src/main/resources/tileserver/accessionDot11.png new file mode 100644 index 0000000000000000000000000000000000000000..009456aaa801dc8dfd7d2a8ece95b684725e1c3e Binary files /dev/null and b/src/main/resources/tileserver/accessionDot11.png differ diff --git a/src/main/resources/tileserver/accessionDot12.png b/src/main/resources/tileserver/accessionDot12.png new file mode 100644 index 0000000000000000000000000000000000000000..a97c271ae6d8e00197eb5aebcddca9fdac55ffc6 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot12.png differ diff --git a/src/main/resources/tileserver/accessionDot13.png b/src/main/resources/tileserver/accessionDot13.png new file mode 100644 index 0000000000000000000000000000000000000000..ed5762573c230cfa04baa033c3969fb92d56a450 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot13.png differ diff --git a/src/main/resources/tileserver/accessionDot14.png b/src/main/resources/tileserver/accessionDot14.png new file mode 100644 index 0000000000000000000000000000000000000000..d8559a6847c3d6dab94216033ad35f15a6bca90f Binary files /dev/null and b/src/main/resources/tileserver/accessionDot14.png differ diff --git a/src/main/resources/tileserver/accessionDot2.png b/src/main/resources/tileserver/accessionDot2.png new file mode 100644 index 0000000000000000000000000000000000000000..0f67eec9347448d897feeed2d51b4e3afdd82336 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot2.png differ diff --git a/src/main/resources/tileserver/accessionDot3.png b/src/main/resources/tileserver/accessionDot3.png new file mode 100644 index 0000000000000000000000000000000000000000..fd8097431f06b8c23e57ee24a39eebb726b11203 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot3.png differ diff --git a/src/main/resources/tileserver/accessionDot4.png b/src/main/resources/tileserver/accessionDot4.png new file mode 100644 index 0000000000000000000000000000000000000000..2ddfe89d0f1db8fd2d5c5e2b83eab632c890e38f Binary files /dev/null and b/src/main/resources/tileserver/accessionDot4.png differ diff --git a/src/main/resources/tileserver/accessionDot5.png b/src/main/resources/tileserver/accessionDot5.png new file mode 100644 index 0000000000000000000000000000000000000000..ffc83fce8e936fe40e854f3f4a7b5990b0f59c09 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot5.png differ diff --git a/src/main/resources/tileserver/accessionDot6.png b/src/main/resources/tileserver/accessionDot6.png new file mode 100644 index 0000000000000000000000000000000000000000..da4e8ee18ec3d621905d3a49a271c8b6a19b321c Binary files /dev/null and b/src/main/resources/tileserver/accessionDot6.png differ diff --git a/src/main/resources/tileserver/accessionDot7.png b/src/main/resources/tileserver/accessionDot7.png new file mode 100644 index 0000000000000000000000000000000000000000..dcff9dc5d28c06fce5a7a62d336ce82ca6637ec3 Binary files /dev/null and b/src/main/resources/tileserver/accessionDot7.png differ diff --git a/src/main/resources/tileserver/accessionDot8.png b/src/main/resources/tileserver/accessionDot8.png new file mode 100644 index 0000000000000000000000000000000000000000..25fd21d0388b626e696592ecf5ea3fdb7fb0ca6a Binary files /dev/null and b/src/main/resources/tileserver/accessionDot8.png differ diff --git a/src/main/resources/tileserver/accessionDot9.png b/src/main/resources/tileserver/accessionDot9.png new file mode 100644 index 0000000000000000000000000000000000000000..c365bbbb7dbd01ebc6549e7b0a8c665c8e5ec32b Binary files /dev/null and b/src/main/resources/tileserver/accessionDot9.png differ