use of org.apache.sis.coverage.grid.GridExtent in project sis by apache.
the class StatusBar method apply.
/**
* Implementation of {@link #applyCanvasGeometry(GridGeometry)} without changing {@link #position} visibility state.
* Invoking this method usually invalidate the coordinates shown in this status bar. The new coordinates can not be
* easily recomputed because the {@link #lastX} and {@link #lastY} values may not be valid anymore, as a result of
* possible changes in JavaFX local coordinate system. Consequently the coordinates should be temporarily hidden
* until a new {@link MouseEvent} gives us the new local coordinates, unless this method is invoked in a context
* where we know that the "real world" coordinates should be the same even if local coordinates changed.
*
* @param geometry geometry of the coverage shown in {@link MapCanvas}, or {@code null}.
*/
private void apply(final GridGeometry geometry) {
/*
* Compute values in local variables without modifying `StatusBar` fields for now.
* The fields will be updated only after we know that this operation is successful.
*/
MathTransform localToCRS = null;
CoordinateReferenceSystem crs = null;
double resolution = 1;
double[] inflate = null;
Unit<?> unit = Units.PIXEL;
if (geometry != null) {
if (geometry.isDefined(GridGeometry.CRS)) {
crs = geometry.getCoordinateReferenceSystem();
}
if (geometry.isDefined(GridGeometry.GRID_TO_CRS)) {
localToCRS = geometry.getGridToCRS(PixelInCell.CELL_CENTER);
}
/*
* Compute the precision of coordinates to format. We use the finest resolution,
* looking only at axes having the same units of measurement than the first axis.
* This will be used as a fallback if we can not compute the precision specific
* to a coordinate, for example if we can not compute the derivative.
*/
if (geometry.isDefined(GridGeometry.RESOLUTION)) {
double[] resolutions = geometry.getResolution(true);
if (crs != null && resolutions.length != 0) {
final CoordinateSystem cs = crs.getCoordinateSystem();
unit = cs.getAxis(0).getUnit();
for (int i = 0; i < resolutions.length; i++) {
if (unit.equals(cs.getAxis(i).getUnit())) {
final double r = resolutions[i];
if (r < resolution)
resolution = r;
}
}
}
}
/*
* Add a tolerance factor of ½ pixel when computing the number of significant
* fraction digits to show in coordinates.
*/
if (geometry.isDefined(GridGeometry.EXTENT)) {
final GridExtent extent = geometry.getExtent();
final int n = extent.getDimension();
inflate = new double[n];
for (int i = 0; i < n; i++) {
inflate[i] = (0.5 / extent.getSize(i)) + 1;
}
}
}
final boolean sameCRS = Utilities.equalsIgnoreMetadata(objectiveCRS, crs);
if (localToCRS == null) {
localToCRS = MathTransforms.identity(BIDIMENSIONAL);
}
final int srcDim = Math.max(localToCRS.getSourceDimensions(), BIDIMENSIONAL);
final int tgtDim = localToCRS.getTargetDimensions();
/*
* Remaining code should not fail, so we can start modifying the `StatusBar` fields.
* The buffers for source and target coordinates are recreated because the number of
* dimensions may have changed. The `lastX` and `lastY` coordinates are local to the
* JavaFX view and considered invalid because they depend on the transforms applied
* on JavaFX node, which may have changed together with `localToObjectiveCRS` change.
* So we can not use those values for updating the coordinates shown in status bar.
* Instead we will wait for the next mouse event to provide new local coordinates.
*/
((LocalToObjective) localToObjectiveCRS).setNoCheck(localToCRS);
targetCoordinates = new GeneralDirectPosition(tgtDim);
sourceCoordinates = (srcDim == tgtDim) ? targetCoordinates.coordinates : new double[srcDim];
objectiveCRS = crs;
// May be updated again below.
localToPositionCRS = localToCRS;
inflatePrecisions = inflate;
precisions = null;
// Not valid anymove — see above block comment.
lastX = lastY = Double.NaN;
if (sameCRS) {
updateLocalToPositionCRS();
// Keep the format CRS unchanged since we made `localToPositionCRS` consistent with its value.
if (fullOperationSearchRequired != null && fullOperationSearchRequired.test(canvas)) {
setPositionCRS(format.getDefaultCRS());
}
} else {
objectiveToPositionCRS = null;
// Should be invoked before to set precision.
setFormatCRS(crs, null);
crs = OperationFinder.toGeospatial(crs, canvas);
// May invoke setFormatCRS(…) after background work.
crs = setReplaceablePositionCRS(crs);
}
format.setGroundPrecision(Quantities.create(resolution, unit));
/*
* If the CRS changed, we may need to update the selected menu item. It happens when this method
* is invoked because new data have been loaded, as opposed to this method being invoked after a
* gesture event (zoom, pan, rotation).
*/
if (!sameCRS && selectedSystem != null) {
selectedSystem.set(crs);
}
}
use of org.apache.sis.coverage.grid.GridExtent in project sis by apache.
the class CoverageCanvas method toString.
/**
* Returns a string representation for debugging purposes.
* The string content may change in any future version.
*/
@Override
public String toString() {
if (!Platform.isFxApplicationThread()) {
return super.toString();
}
final String lineSeparator = System.lineSeparator();
final StringBuilder buffer = new StringBuilder(1000);
final TableAppender table = new TableAppender(buffer);
table.setMultiLinesCells(true);
try {
table.nextLine('═');
getGridGeometry().getGeographicExtent().ifPresent((bbox) -> {
table.append(String.format("Canvas geographic bounding box (λ,ɸ):%n" + "Max: % 10.5f° % 10.5f°%n" + "Min: % 10.5f° % 10.5f°", bbox.getEastBoundLongitude(), bbox.getNorthBoundLatitude(), bbox.getWestBoundLongitude(), bbox.getSouthBoundLatitude())).appendHorizontalSeparator();
});
final Rectangle2D aoi = getAreaOfInterest();
final DirectPosition poi = getPointOfInterest(true);
if (aoi != null && poi != null) {
table.append(String.format("A/P of interest in objective CRS (x,y):%n" + "Max: %, 16.4f %, 16.4f%n" + "POI: %, 16.4f %, 16.4f%n" + "Min: %, 16.4f %, 16.4f%n", aoi.getMaxX(), aoi.getMaxY(), poi.getOrdinate(0), poi.getOrdinate(1), aoi.getMinX(), aoi.getMinY())).appendHorizontalSeparator();
}
final Rectangle source = data.objectiveToData(aoi);
if (source != null) {
table.append("Extent in source coverage:").append(lineSeparator).append(String.valueOf(new GridExtent(source))).append(lineSeparator).nextLine();
}
table.nextLine('═');
table.flush();
} catch (RenderException | TransformException | IOException e) {
buffer.append(e).append(lineSeparator);
}
return buffer.toString();
}
use of org.apache.sis.coverage.grid.GridExtent in project sis by apache.
the class ImageRequest method load.
/**
* Loads the image. If the coverage has more than {@value #BIDIMENSIONAL} dimensions,
* only two of them are taken for the image; for all other dimensions, only the values
* at lowest index will be read.
*
* <p>If the {@link #coverage} field was null, it will be initialized as a side-effect.
* No other fields will be modified.</p>
*
* <h4>Thread safety</h4>
* This class does not need to be thread-safe because it should be used only once in a well-defined life cycle.
* We nevertheless synchronize as a safety (e.g. user could give the same {@code ImageRequest} to two different
* {@link CoverageExplorer} instances). In such case the {@link GridCoverage} will be loaded only once,
* but no caching is done for the {@link RenderedImage} (because usually not needed).
*
* @param task the task invoking this method (for checking for cancellation).
* @return the image loaded from the source given at construction time, or {@code null}
* if the task has been cancelled.
* @throws DataStoreException if an error occurred while loading the grid coverage.
*/
final synchronized RenderedImage load(final FutureTask<?> task) throws DataStoreException {
GridCoverage cv = coverage;
final Long id = LogHandler.loadingStart(resource);
try {
if (cv == null) {
cv = MultiResolutionImageLoader.getInstance(resource, null).getOrLoad(domain, range);
}
coverage = cv = cv.forConvertedValues(true);
if (task.isCancelled()) {
return null;
}
GridExtent ex = sliceExtent;
if (ex == null) {
final GridGeometry gg = cv.getGridGeometry();
if (gg.getDimension() > MultiResolutionImageLoader.BIDIMENSIONAL) {
ex = MultiResolutionImageLoader.slice(gg.derive(), gg.getExtent()).getIntersection();
}
}
return cv.render(ex);
} finally {
LogHandler.loadingStop(id);
}
}
use of org.apache.sis.coverage.grid.GridExtent in project sis by apache.
the class RasterReader method readAsCoverage.
/**
* Parses a raster from the given input stream and returns as a coverage.
*
* @param input source of bytes to read.
* @return the raster as a coverage, or {@code null} if the raster is empty.
* @throws Exception in an error occurred while reading from the given input or creating the coverage.
* Exception type may be I/O, SQL, factory, data store, arithmetic, raster format, <i>etc.</i>,
* too numerous for enumerating them all.
*/
public GridCoverage readAsCoverage(final ChannelDataInput input) throws Exception {
final BufferedImage image = readAsImage(input);
if (image == null) {
return null;
}
CoordinateReferenceSystem crs = null;
final int srid = getSRID();
if (spatialRefSys != null) {
crs = spatialRefSys.fetchCRS(srid);
} else if (srid > 0) {
crs = CRS.forCode(Constants.EPSG + ':' + srid);
}
if (crs == null) {
crs = defaultCRS;
}
final GridExtent extent = new GridExtent(image.getWidth(), image.getHeight());
final GridGeometry domain = new GridGeometry(extent, ANCHOR, getGridToCRS(), crs);
/*
* Create pseudo-categories with a transfer function if we need to specify "no data" value,
* or the sign of stored data do not match the sign of expected values.
*/
List<SampleDimension> range = null;
if (needsTransferFunction()) {
final SampleDimension[] sd = new SampleDimension[bands.length];
final SampleDimension.Builder builder = new SampleDimension.Builder();
for (int b = 0; b < sd.length; b++) {
final Band band = bands[b];
if ((band.getDataBufferType() & OPPOSITE_SIGN) != 0) {
// See `Band.OPPOSITE_SIGN` javadoc for more information on this limitation.
throw new RasterFormatException("Data type not yet supported.");
}
sd[b] = builder.setName(b + 1).setBackground(band.noDataValue).build();
builder.clear();
}
range = Arrays.asList(sd);
}
return new GridCoverage2D(domain, range, image);
}
use of org.apache.sis.coverage.grid.GridExtent in project sis by apache.
the class AbstractGridResource method logReadOperation.
/**
* Logs the execution of a {@link #read(GridGeometry, int...)} operation.
* The log level will be {@link Level#FINE} if the operation was quick enough,
* or {@link PerformanceLevel#SLOW} or higher level otherwise.
*
* @param file the file that was opened, or {@code null} for {@link #getSourceName()}.
* @param domain domain of the created grid coverage.
* @param startTime value of {@link System#nanoTime()} when the loading process started.
*/
protected final void logReadOperation(final Object file, final GridGeometry domain, final long startTime) {
final Logger logger = getLogger();
final long nanos = System.nanoTime() - startTime;
final Level level = PerformanceLevel.forDuration(nanos, TimeUnit.NANOSECONDS);
if (logger.isLoggable(level)) {
final Locale locale = getLocale();
final Object[] parameters = new Object[6];
parameters[0] = IOUtilities.filename(file != null ? file : getSourceName());
parameters[5] = nanos / (double) StandardDateFormat.NANOS_PER_SECOND;
JDK9.ifPresentOrElse(domain.getGeographicExtent(), (box) -> {
final AngleFormat f = new AngleFormat(locale);
double min = box.getSouthBoundLatitude();
double max = box.getNorthBoundLatitude();
f.setPrecision(max - min, true);
f.setRoundingMode(RoundingMode.FLOOR);
parameters[1] = f.format(new Latitude(min));
f.setRoundingMode(RoundingMode.CEILING);
parameters[2] = f.format(new Latitude(max));
min = box.getWestBoundLongitude();
max = box.getEastBoundLongitude();
f.setPrecision(max - min, true);
f.setRoundingMode(RoundingMode.FLOOR);
parameters[3] = f.format(new Longitude(min));
f.setRoundingMode(RoundingMode.CEILING);
parameters[4] = f.format(new Longitude(max));
}, () -> {
// If no geographic coordinates, fallback on the 2 first dimensions.
if (domain.isDefined(GridGeometry.ENVELOPE)) {
final Envelope box = domain.getEnvelope();
final int dimension = Math.min(box.getDimension(), 2);
for (int t = 1, i = 0; i < dimension; i++) {
parameters[t++] = box.getMinimum(i);
parameters[t++] = box.getMaximum(i);
}
} else if (domain.isDefined(GridGeometry.EXTENT)) {
final GridExtent box = domain.getExtent();
final int dimension = Math.min(box.getDimension(), 2);
for (int t = 1, i = 0; i < dimension; i++) {
parameters[t++] = box.getLow(i);
parameters[t++] = box.getHigh(i);
}
}
});
final LogRecord record = Resources.forLocale(locale).getLogRecord(level, Resources.Keys.LoadedGridCoverage_6, parameters);
record.setSourceClassName(GridCoverageResource.class.getName());
record.setSourceMethodName("read");
record.setLoggerName(logger.getName());
logger.log(record);
}
}
Aggregations