github-advanced-security[bot] commented on code in PR #884: URL: https://github.com/apache/incubator-baremaps/pull/884#discussion_r1698249007
########## baremaps-raster/src/test/java/org/apache/baremaps/raster/elevation/ChaikinSmootherTest.java: ########## @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 org.apache.baremaps.raster.elevation; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.LineString; + +class ChaikinSmootherTest { Review Comment: ## Unused classes and interfaces Unused class: ChaikinSmootherTest is not referenced within this codebase. If not used as an external API it should be removed. [Show more details](https://github.com/apache/incubator-baremaps/security/code-scanning/1528) ########## baremaps-cli/src/main/java/org/apache/baremaps/cli/raster/Hillshade.java: ########## @@ -0,0 +1,344 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 org.apache.baremaps.cli.raster; + +import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN; +import static com.google.common.net.HttpHeaders.CONTENT_TYPE; +import static org.apache.baremaps.utils.ObjectMapperUtils.objectMapper; + +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; +import com.linecorp.armeria.common.*; +import com.linecorp.armeria.server.Server; +import com.linecorp.armeria.server.annotation.Blocking; +import com.linecorp.armeria.server.annotation.Get; +import com.linecorp.armeria.server.annotation.JacksonResponseConverterFunction; +import com.linecorp.armeria.server.annotation.Param; +import com.linecorp.armeria.server.cors.CorsService; +import com.linecorp.armeria.server.docs.DocService; +import com.linecorp.armeria.server.file.HttpFile; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.zip.GZIPOutputStream; +import javax.imageio.ImageIO; +import org.apache.baremaps.maplibre.vectortile.*; +import org.apache.baremaps.raster.elevation.*; +import org.apache.baremaps.server.TileResource; +import org.apache.baremaps.tilestore.TileCoord; +import org.apache.baremaps.tilestore.TileStore; +import org.apache.baremaps.tilestore.TileStoreException; +import org.locationtech.jts.geom.util.AffineTransformation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +@Command(name = "hillshade", description = "Start a tile server that computes hillshades.") +public class Hillshade implements Callable<Integer> { + + @Option(names = {"--host"}, paramLabel = "HOST", description = "The host of the server.") + private String host = "localhost"; + + @Option(names = {"--port"}, paramLabel = "PORT", description = "The port of the server.") + private int port = 9000; + + @Override + public Integer call() throws Exception { + + var serverBuilder = Server.builder(); + serverBuilder.http(port); + + var objectMapper = objectMapper(); + var jsonResponseConverter = new JacksonResponseConverterFunction(objectMapper); + + LoadingCache<TileCoord, BufferedImage> cache = Caffeine.newBuilder() + .maximumSize(1000) + .build(this::getImage); + + var rasterHillshadeTileStore = new RasterHillshadeTileStore(cache); + serverBuilder.annotatedService(new HillShadeTileResource(() -> rasterHillshadeTileStore), + jsonResponseConverter); + + var contourTileStore = new ContourTileStore(cache); + serverBuilder.annotatedService(new TileResource(() -> contourTileStore), + jsonResponseConverter); + + var index = HttpFile.of(ClassLoader.getSystemClassLoader(), "/raster/hillshade.html"); + serverBuilder.service("/", index.asService()); + + serverBuilder.decorator(CorsService.builderForAnyOrigin() + .allowAllRequestHeaders(true) + .allowRequestMethods( + HttpMethod.GET, + HttpMethod.POST, + HttpMethod.PUT, + HttpMethod.DELETE, + HttpMethod.OPTIONS, + HttpMethod.HEAD) + .allowCredentials() + .exposeHeaders(HttpHeaderNames.LOCATION) + .newDecorator()); + + serverBuilder.serviceUnder("/docs", new DocService()); + + serverBuilder.disableServerHeader(); + serverBuilder.disableDateHeader(); + + var server = serverBuilder.build(); + + var startFuture = server.start(); + startFuture.join(); + + var shutdownFuture = server.closeOnJvmShutdown(); + shutdownFuture.join(); + + return 0; + } + + private String url = "https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"; + + public BufferedImage getImage(TileCoord tileCoord) throws IOException { + var tileUrl = new URL(this.url + .replace("{z}", String.valueOf(tileCoord.z())) + .replace("{x}", String.valueOf(tileCoord.x())) + .replace("{y}", String.valueOf(tileCoord.y()))); + return ImageIO.read(tileUrl); + } + + public static BufferedImage getKernel(TileCoord tileCoord, + Function<TileCoord, BufferedImage> provider) { + BufferedImage z1 = + provider.apply(new TileCoord(tileCoord.x() - 1, tileCoord.y() - 1, tileCoord.z())); + BufferedImage z2 = + provider.apply(new TileCoord(tileCoord.x(), tileCoord.y() - 1, tileCoord.z())); + BufferedImage z3 = + provider.apply(new TileCoord(tileCoord.x() + 1, tileCoord.y() - 1, tileCoord.z())); + BufferedImage z4 = + provider.apply(new TileCoord(tileCoord.x() - 1, tileCoord.y(), tileCoord.z())); + BufferedImage z5 = provider.apply(tileCoord); + BufferedImage z6 = + provider.apply(new TileCoord(tileCoord.x() + 1, tileCoord.y(), tileCoord.z())); + BufferedImage z7 = + provider.apply(new TileCoord(tileCoord.x() - 1, tileCoord.y() + 1, tileCoord.z())); + BufferedImage z8 = + provider.apply(new TileCoord(tileCoord.x(), tileCoord.y() + 1, tileCoord.z())); + BufferedImage z9 = + provider.apply(new TileCoord(tileCoord.x() + 1, tileCoord.y() + 1, tileCoord.z())); + int kernelSize = z5.getWidth() * 3; + BufferedImage kernel = new BufferedImage(kernelSize, kernelSize, z5.getType()); + for (int y = 0; y < z5.getHeight(); y++) { + for (int x = 0; x < z5.getWidth(); x++) { + kernel.setRGB(x, y, z1.getRGB(x, y)); + kernel.setRGB(x + z5.getWidth(), y, z2.getRGB(x, y)); + kernel.setRGB(x + 2 * z5.getWidth(), y, z3.getRGB(x, y)); + kernel.setRGB(x, y + z5.getHeight(), z4.getRGB(x, y)); + kernel.setRGB(x + z5.getWidth(), y + z5.getHeight(), z5.getRGB(x, y)); + kernel.setRGB(x + 2 * z5.getWidth(), y + z5.getHeight(), z6.getRGB(x, y)); + kernel.setRGB(x, y + 2 * z5.getHeight(), z7.getRGB(x, y)); + kernel.setRGB(x + z5.getWidth(), y + 2 * z5.getHeight(), z8.getRGB(x, y)); + kernel.setRGB(x + 2 * z5.getWidth(), y + 2 * z5.getHeight(), z9.getRGB(x, y)); + } + } + return kernel; + } + + public static class RasterHillshadeTileStore implements TileStore { + + private final LoadingCache<TileCoord, BufferedImage> cache; + + public RasterHillshadeTileStore(LoadingCache<TileCoord, BufferedImage> cache) { + this.cache = cache; + } + + @Override + public ByteBuffer read(TileCoord tileCoord) throws TileStoreException { + try { + + var image = cache.get(tileCoord); + var kernel = getKernel(tileCoord, cache::get); + var buffer = kernel.getSubimage( + image.getWidth() - 1, + image.getHeight() - 1, + image.getWidth() + 2, + image.getHeight() + 2); + + var grid = ElevationUtils.imageToGrid(buffer); + var hillshadeGrid = + new HillshadeCalculator(grid, buffer.getWidth(), buffer.getHeight(), 1, false) + .calculate(45, 315); + + // Create an output image + BufferedImage hillshadeImage = + new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY); + for (int y = 0; y < image.getHeight(); y++) { + for (int x = 0; x < image.getWidth(); x++) { + int value = (int) hillshadeGrid[(y + 1) * buffer.getHeight() + x + 1]; + hillshadeImage.setRGB(x, y, new Color(value, value, value).getRGB()); + } + } + + try (var baos = new ByteArrayOutputStream()) { + ImageIO.write(hillshadeImage, "png", baos); + baos.flush(); + return ByteBuffer.wrap(baos.toByteArray()); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void write(TileCoord tileCoord, ByteBuffer blob) throws TileStoreException { + throw new UnsupportedOperationException(); + } + + @Override + public void delete(TileCoord tileCoord) throws TileStoreException { + throw new UnsupportedOperationException(); + } + + @Override + public void close() throws Exception { + // Do nothing + } + } + + public class HillShadeTileResource { Review Comment: ## Inner class could be static HillShadeTileResource should be made static, since the enclosing instance is not used. [Show more details](https://github.com/apache/incubator-baremaps/security/code-scanning/1527) ########## baremaps-raster/src/main/java/org/apache/baremaps/raster/elevation/ChaikinSmoother.java: ########## @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you 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 org.apache.baremaps.raster.elevation; + +import org.locationtech.jts.geom.*; +import org.locationtech.jts.geom.impl.CoordinateArraySequence; +import org.locationtech.jts.geom.util.GeometryTransformer; + +public class ChaikinSmoother extends GeometryTransformer { + + private final int iterations; + + private final double factor; + + public ChaikinSmoother(int iterations, double factor) { + this.iterations = iterations; + this.factor = factor; + } + + @Override + protected CoordinateSequence transformCoordinates( + CoordinateSequence coordinateSequence, + Geometry parent) { + return smooth(coordinateSequence, iterations, factor); + } + + public static LinearRing smooth(LinearRing linearRing, int iterations, double factor) { + CoordinateSequence coordinateSequence = + smooth(linearRing.getCoordinateSequence(), iterations, factor); + return linearRing.getFactory().createLinearRing(coordinateSequence); + } + + public static LineString smooth(LineString lineString, int iterations, double factor) { Review Comment: ## Confusing overloading of methods Method ChaikinSmoother.smooth(..) could be confused with overloaded method [smooth](1), since dispatch depends on static types. [Show more details](https://github.com/apache/incubator-baremaps/security/code-scanning/1529) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
