package com.revolsys.elevation.gridded.compactbinary; import java.io.Closeable; import java.io.IOException; import java.nio.IntBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import com.revolsys.elevation.gridded.GriddedElevationModel; import com.revolsys.elevation.gridded.IntArrayScaleGriddedElevationModel; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.GeometryFactory; import com.revolsys.io.IoFactory; import com.revolsys.io.channels.ChannelReader; import com.revolsys.properties.BaseObjectWithProperties; import com.revolsys.spring.resource.Resource; import com.revolsys.util.Exceptions; public class CompactBinaryGriddedElevationReader extends BaseObjectWithProperties implements Closeable { protected static GeometryFactory readGeometryFactory(final ChannelReader reader, final short version) { GeometryFactory geometryFactory; final int coordinateSystemId = reader.getInt(); // Coordinate System ID if (version == 1) { final double scaleX = reader.getDouble(); final double scaleZ = reader.getDouble(); geometryFactory = GeometryFactory.fixed(coordinateSystemId, 3, scaleX, scaleX, scaleZ); } else { final double offsetX = reader.getDouble(); final double scaleX = reader.getDouble(); final double offsetY = reader.getDouble(); final double scaleY = reader.getDouble(); final double offsetZ = reader.getDouble(); final double scaleZ = reader.getDouble(); geometryFactory = GeometryFactory.newWithOffsets(coordinateSystemId, offsetX, scaleX, offsetY, scaleY, offsetZ, scaleZ); } return geometryFactory; } private Resource resource; private ChannelReader reader; private GeometryFactory geometryFactory; private BoundingBox boundingBox; private int gridCellSize; private int gridWidth; private int gridHeight; private boolean memoryMapped = false; CompactBinaryGriddedElevationReader(final Resource resource) { this.resource = resource; } @Override public void close() { super.close(); final ChannelReader reader = this.reader; this.reader = null; if (reader != null) { reader.close(); } this.resource = null; } public boolean isMemoryMapped() { return this.memoryMapped; } public void open() { if (this.reader == null) { this.reader = IoFactory.newChannelReader(this.resource); readHeader(); } } public GriddedElevationModel read() { open(); try { final ChannelReader in = this.reader; final int cellCount = this.gridWidth * this.gridHeight; final int[] elevations = new int[cellCount]; final ReadableByteChannel channel = in.getChannel(); if (isMemoryMapped() && channel instanceof FileChannel) { final FileChannel fileChannel = (FileChannel)channel; final MappedByteBuffer mappedBytes = fileChannel.map(MapMode.READ_ONLY, CompactBinaryGriddedElevation.HEADER_SIZE, cellCount * CompactBinaryGriddedElevation.RECORD_SIZE); final IntBuffer intBuffer = mappedBytes.asIntBuffer(); for (int index = 0; index < cellCount; index++) { elevations[index] = intBuffer.get(); } } else { for (int index = 0; index < cellCount; index++) { final int elevation = in.getInt(); elevations[index] = elevation; } } final IntArrayScaleGriddedElevationModel elevationModel = new IntArrayScaleGriddedElevationModel( this.geometryFactory, this.boundingBox, this.gridWidth, this.gridHeight, this.gridCellSize, elevations); elevationModel.setResource(this.resource); return elevationModel; } catch (final IOException e) { throw Exceptions.wrap("Unable to read DEM: " + this.resource, e); } } private void readHeader() { final byte[] fileTypeBytes = new byte[6]; this.reader.getBytes(fileTypeBytes); @SuppressWarnings("unused") final String fileType = new String(fileTypeBytes, StandardCharsets.UTF_8); // File // type final short version = this.reader.getShort(); final GeometryFactory geometryFactory = readGeometryFactory(this.reader, version); this.geometryFactory = geometryFactory; final double minX = this.reader.getDouble(); final double minY = this.reader.getDouble(); final double minZ = this.reader.getDouble(); final double maxX = this.reader.getDouble(); final double maxY = this.reader.getDouble(); final double maxZ = this.reader.getDouble(); this.gridCellSize = this.reader.getInt(); // Grid Cell Size this.gridWidth = this.reader.getInt(); // Grid Width this.gridHeight = this.reader.getInt(); // Grid Height this.boundingBox = geometryFactory.newBoundingBox(3, minX, minY, minZ, maxX, maxY, maxZ); } public void setMemoryMapped(final boolean memoryMapped) { this.memoryMapped = memoryMapped; } }