package org.simantics.maps.elevation.server; import java.awt.geom.Point2D; import java.awt.image.DataBuffer; import java.nio.file.Path; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.gce.geotiff.GeoTiffReader; import org.geotools.geometry.Envelope2D; import org.geotools.geometry.TransformedDirectPosition; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.simantics.maps.elevation.server.prefs.MapsElevationServerPreferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TiffInterface { private static final Logger LOGGER = LoggerFactory.getLogger(TiffInterface.class); private final Path tifPath; private GridCoverage2D coverage; private CoordinateReferenceSystem crs; private boolean init = false; public TiffInterface(Path tifPath) { this.tifPath = tifPath; loadMetadata(); } private void loadMetadata() { GeoTiffReader reader = null; try { reader = new GeoTiffReader(this.tifPath.toFile()); this.coverage = reader.read(null); this.crs = coverage.getCoordinateReferenceSystem(); this.init = true; } catch (Exception e) { LOGGER.error("Could not load {}", tifPath, e); } finally { if (reader != null) { reader.dispose(); } } } public boolean contains(DirectPosition pos) { ensureInit(); Envelope2D e = coverage.getEnvelope2D(); try { TransformedDirectPosition tdp = new TransformedDirectPosition(pos.getCoordinateReferenceSystem(), crs, null); tdp.transform(pos); Point2D p = tdp.toPoint2D(); boolean contains = e.contains(p); return contains; } catch (Exception ex) { ex.printStackTrace(); return false; } } public Number lookup(DirectPosition pos) { ensureInit(); Object r = coverage.evaluate(pos); final int dataType = coverage.getRenderedImage().getSampleModel().getDataType(); int pipeDepthUnderGround = MapsElevationServerPreferences.pipeDepthUnderGround(); switch (dataType) { case DataBuffer.TYPE_BYTE: { // TODO: if the result is byte how does one subtract the pipeDepth form the value? // Might not be even relevant with this use case return new Byte(((byte[]) r)[0]); } case DataBuffer.TYPE_SHORT: // Fall through case DataBuffer.TYPE_USHORT: // Fall through case DataBuffer.TYPE_INT: { int val = ((int[]) r)[0] - pipeDepthUnderGround; return new Integer(val); } case DataBuffer.TYPE_FLOAT: { float val = ((float[]) r)[0] - pipeDepthUnderGround; return new Float(val); } case DataBuffer.TYPE_DOUBLE: { double val = ((double[]) r)[0] - pipeDepthUnderGround; return new Double(val); } default: return null; } } private void ensureInit() { if (!init) { throw new IllegalStateException("Interface is not initialized for " + this.tifPath); } } public void close() { coverage.dispose(true); } public Envelope2D getCornerCoords() { return coverage.getEnvelope2D(); } public CoordinateReferenceSystem getCRS() { return crs; } }