use of org.geotoolkit.process.ProcessEvent in project geotoolkit by Geomatys.
the class AbstractTileGenerator method generate.
@Override
public void generate(TileMatrixSet pyramid, Envelope env, NumberRange resolutions, ProcessListener listener) throws DataStoreException, InterruptedException {
if (env != null) {
try {
env = Envelopes.transform(env, pyramid.getCoordinateReferenceSystem());
} catch (TransformException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
final long total = TileMatrices.countTiles(pyramid, env, resolutions);
final AtomicLong al = new AtomicLong();
// generate mosaic in resolution order
// this order allows the pyramid to be used at high scales until she is not completed.
final List<TileMatrix> mosaics = new ArrayList<>(pyramid.getTileMatrices());
mosaics.sort((TileMatrix o1, TileMatrix o2) -> Double.compare(o2.getScale(), o1.getScale()));
for (final TileMatrix mosaic : mosaics) {
if (resolutions == null || resolutions.containsAny(mosaic.getScale())) {
final Rectangle rect;
try {
rect = TileMatrices.getTilesInEnvelope(mosaic, env);
} catch (NoSuchDataException ex) {
continue;
}
final long nbTile = ((long) rect.width) * ((long) rect.height);
final long eventstep = Math.min(1000, Math.max(1, nbTile / 100l));
Stream<Tile> stream = LongStream.range(0, nbTile).parallel().mapToObj(new LongFunction<Tile>() {
@Override
public Tile apply(long value) {
final long x = rect.x + (value % rect.width);
final long y = rect.y + (value / rect.width);
Tile data = null;
try {
// do not regenerate existing tiles
// if (!mosaic.isMissing((int)x, (int)y)) return;
final Point coord = new Point((int) x, (int) y);
try {
data = generateTile(pyramid, mosaic, coord);
} catch (Exception ex) {
data = TileInError.create(coord, null, ex);
}
} finally {
long v = al.incrementAndGet();
if (listener != null & (v % eventstep == 0)) {
listener.progressing(new ProcessEvent(DUMMY, v + "/" + total + " mosaic=" + mosaic.getIdentifier() + " scale=" + mosaic.getScale(), (float) ((((double) v) / ((double) total)) * 100.0)));
}
}
return data;
}
}).filter(this::emptyFilter);
batchWrite(stream, mosaic, listener == null ? null : err -> listener.progressing(new ProcessEvent(DUMMY, "Error while writing tile batch", (float) ((((double) al.get()) / ((double) total)) * 100.0))), 200);
long v = al.get();
if (listener != null) {
listener.progressing(new ProcessEvent(DUMMY, v + "/" + total + " mosaic=" + mosaic.getIdentifier() + " scale=" + mosaic.getScale(), (float) ((((double) v) / ((double) total)) * 100.0)));
}
}
}
}
use of org.geotoolkit.process.ProcessEvent in project geotoolkit by Geomatys.
the class MapContextTileGenerator method generate.
@Override
public void generate(TileMatrixSet pyramid, Envelope env, NumberRange resolutions, ProcessListener listener) throws DataStoreException, InterruptedException {
// check if we can optimize tiles generation
boolean rasterOptimisation = true;
search: for (MapLayer layer : MapBuilder.getLayers(sceneDef.getContext())) {
final Style style = layer.getStyle();
for (FeatureTypeStyle fts : style.featureTypeStyles()) {
for (Rule rule : fts.rules()) {
double scaleMin = rule.getMinScaleDenominator();
double scaleMax = rule.getMaxScaleDenominator();
// CanvasUtilities.computeSEScale
if (scaleMin != 0.0 || scaleMax < 5.0E9) {
rasterOptimisation = false;
break search;
}
for (Symbolizer symbolizer : rule.symbolizers()) {
if (symbolizer instanceof RasterSymbolizer || symbolizer instanceof DynamicRangeSymbolizer) {
// ok
} else if (symbolizer instanceof PolygonSymbolizer) {
PolygonSymbolizer ps = (PolygonSymbolizer) symbolizer;
// check if we have a plain fill
Displacement displacement = ps.getDisplacement();
Fill fill = ps.getFill();
Stroke stroke = ps.getStroke();
Expression perpendicularOffset = ps.getPerpendicularOffset();
if (displacement != null) {
Double dx = doubleValue(displacement.getDisplacementX());
Double dy = doubleValue(displacement.getDisplacementX());
if ((dx != null && dx != 0.0) || (dy != null && dy != 0.0)) {
rasterOptimisation = false;
break search;
}
}
if (perpendicularOffset != null) {
Double off = doubleValue(perpendicularOffset);
if (off != null && off != 0.0) {
rasterOptimisation = false;
break search;
}
}
if (stroke != null) {
Double op = doubleValue(stroke.getOpacity());
Double wd = doubleValue(stroke.getWidth());
if ((op == null || op == 0.0) || (wd == null || wd == 0.0)) {
// not visible
} else {
rasterOptimisation = false;
break search;
}
}
if (fill != null) {
if (fill.getGraphicFill() != null) {
rasterOptimisation = false;
break search;
}
}
} else {
rasterOptimisation = false;
break search;
}
}
}
}
}
if (rasterOptimisation) {
/*
We can generate the pyramid starting from the lowest level then going up
using the previously generated level.
*/
if (env != null) {
try {
CoordinateReferenceSystem targetCrs = pyramid.getCoordinateReferenceSystem();
Envelope baseEnv = env;
env = Envelopes.transform(env, targetCrs);
double[] minres = new double[] { resolutions.getMinDouble(), resolutions.getMinDouble() };
double[] maxres = new double[] { resolutions.getMaxDouble(), resolutions.getMaxDouble() };
minres = ReferencingUtilities.convertResolution(baseEnv, minres, targetCrs, null);
maxres = ReferencingUtilities.convertResolution(baseEnv, maxres, targetCrs, null);
resolutions = NumberRange.create(minres[0], true, maxres[0], true);
} catch (TransformException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
// generate lower level from data
final TileMatrix[] mosaics = pyramid.getTileMatrices().toArray(new TileMatrix[0]);
Arrays.sort(mosaics, (TileMatrix o1, TileMatrix o2) -> Double.compare(o1.getScale(), o2.getScale()));
MapLayers parent = sceneDef.getContext();
Hints hints = sceneDef.getHints();
final long total = TileMatrices.countTiles(pyramid, env, resolutions);
final AtomicLong al = new AtomicLong();
// send an event only every few seconds
final AtomicLong tempo = new AtomicLong(System.currentTimeMillis());
final String msg = " / " + NumberFormat.getIntegerInstance(Locale.FRANCE).format(total);
for (final TileMatrix mosaic : mosaics) {
if (resolutions == null || resolutions.contains(mosaic.getScale())) {
final Rectangle rect;
try {
rect = TileMatrices.getTilesInEnvelope(mosaic, env);
} catch (NoSuchDataException ex) {
continue;
}
final CanvasDef canvasDef = new CanvasDef();
canvasDef.setBackground(this.canvasDef.getBackground());
canvasDef.setEnvelope(mosaic.getEnvelope());
final SceneDef sceneDef = new SceneDef(parent, hints);
// one thread per line, the progressive image generates multiple tiles when drawing
// this approach is more efficient from profiling result then using tile by tile
// generation
Stream<Tile> stream = LongStream.range(rect.y, rect.y + rect.height).parallel().boxed().flatMap((Long y) -> {
try {
final ProgressiveImage img = new ProgressiveImage(canvasDef, sceneDef, mosaic.getGridSize(), mosaic.getTileSize(), mosaic.getScale(), 0);
return img.generate(rect.x, rect.x + rect.width, y.intValue(), skipEmptyTiles);
} catch (Exception ex) {
LOGGER.log(Level.INFO, "Failed to generate a tile {0}", ex.getMessage());
LOGGER.log(Level.FINER, "Failed to generate a tile ", ex);
return Stream.empty();
}
});
if (listener != null) {
final NumberFormat format = NumberFormat.getIntegerInstance(Locale.FRANCE);
stream = stream.map((Tile t) -> {
long n = al.incrementAndGet();
if (n % 1000 == 0) {
final long time = System.currentTimeMillis();
if (tempo.updateAndGet((long operand) -> ((time - operand) > 3000) ? time : operand) == time) {
listener.progressing(new ProcessEvent(DUMMY, format.format(n) + msg, (float) ((((double) n) / ((double) total)) * 100.0)));
}
}
return t;
});
}
mosaic.writeTiles(stream, null);
// last level event
final NumberFormat format = NumberFormat.getIntegerInstance(Locale.FRANCE);
long v = al.get();
if (listener != null) {
listener.progressing(new ProcessEvent(DUMMY, format.format(v) + msg, (float) ((((double) v) / ((double) total)) * 100.0)));
}
// modify context
final DefaultTileMatrixSet pm = new DefaultTileMatrixSet(pyramid.getCoordinateReferenceSystem());
pm.getMosaicsInternal().add(mosaic);
final InMemoryTiledGridCoverageResource r = new InMemoryTiledGridCoverageResource(NamesExt.create("test"));
r.setSampleDimensions(sampleDimensions);
r.getTileMatrixSets().add(pm);
final MapLayers mc = MapBuilder.createContext();
mc.getComponents().add(MapBuilder.createLayer(r));
parent = mc;
hints = new Hints(hints);
hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
}
}
} else {
super.generate(pyramid, env, resolutions, listener);
}
}
use of org.geotoolkit.process.ProcessEvent in project geotoolkit by Geomatys.
the class CoverageTileGenerator method generate.
@Override
public void generate(TileMatrixSet pyramid, Envelope env, NumberRange resolutions, ProcessListener listener) throws DataStoreException, InterruptedException {
if (!coverageIsHomogeneous) {
super.generate(pyramid, env, resolutions, listener);
return;
}
/*
We can generate the pyramid starting from the lowest level then going up
using the previously generated level.
*/
if (env != null) {
try {
CoordinateReferenceSystem targetCrs = pyramid.getCoordinateReferenceSystem();
Envelope baseEnv = env;
env = Envelopes.transform(env, targetCrs);
if (resolutions != null) {
double[] minres = new double[] { resolutions.getMinDouble(), resolutions.getMinDouble() };
double[] maxres = new double[] { resolutions.getMaxDouble(), resolutions.getMaxDouble() };
minres = ReferencingUtilities.convertResolution(baseEnv, minres, targetCrs, null);
maxres = ReferencingUtilities.convertResolution(baseEnv, maxres, targetCrs, null);
resolutions = NumberRange.create(minres[0], true, maxres[0], true);
}
} catch (TransformException ex) {
throw new DataStoreException(ex.getMessage(), ex);
}
}
// generate lower level from data
final TileMatrix[] mosaics = pyramid.getTileMatrices().toArray(new TileMatrix[0]);
Arrays.sort(mosaics, (TileMatrix o1, TileMatrix o2) -> Double.compare(o1.getScale(), o2.getScale()));
final long total = TileMatrices.countTiles(pyramid, env, resolutions);
final double totalAsDouble = total;
final AtomicLong al = new AtomicLong();
final Supplier<Float> progress = () -> (float) (al.get() / totalAsDouble * 100.0);
GridCoverageResource resourceCenter = this.resource;
GridCoverageResource resourceBorder = this.resource;
for (final TileMatrix mosaic : mosaics) {
if (resolutions == null || resolutions.contains(mosaic.getScale())) {
final Rectangle rect;
try {
rect = TileMatrices.getTilesInEnvelope(mosaic, env);
} catch (NoSuchDataException ex) {
continue;
}
final GridCoverageResource sourceCenter = resourceCenter;
final GridCoverageResource sourceBorder = resourceBorder;
final long nbTile = ((long) rect.width) * ((long) rect.height);
final long eventstep = Math.min(1000, Math.max(1, nbTile / 100l));
Stream<Tile> stream = LongStream.range(0, nbTile).parallel().mapToObj(new LongFunction<Tile>() {
@Override
public Tile apply(long value) {
final long x = rect.x + (value % rect.width);
final long y = rect.y + (value / rect.width);
final boolean isBorderTile = (x == rect.x || x == (rect.x + rect.width - 1)) || (y == rect.y || y == (rect.y + rect.height - 1));
Tile data = null;
try {
if (skipExistingTiles && !mosaic.isMissing((int) x, (int) y)) {
// tile already exist
return null;
}
final Point coord = new Point((int) x, (int) y);
try {
data = generateTile(pyramid, mosaic, coord, isBorderTile ? sourceBorder : sourceCenter);
} catch (Exception ex) {
data = TileInError.create(coord, null, ex);
}
} finally {
long v = al.incrementAndGet();
if (listener != null & (v % eventstep == 0)) {
listener.progressing(new ProcessEvent(DUMMY, v + "/" + total + " mosaic=" + mosaic.getIdentifier() + " scale=" + mosaic.getScale(), progress.get()));
}
}
return data;
}
}).filter(this::emptyFilter);
batchWrite(stream, mosaic, listener == null ? null : err -> listener.progressing(new ProcessEvent(DUMMY, "Error while writing tile batch", progress.get(), err)), 200);
long v = al.get();
if (listener != null) {
listener.progressing(new ProcessEvent(DUMMY, v + "/" + total + " mosaic=" + mosaic.getIdentifier() + " scale=" + mosaic.getScale(), progress.get()));
}
if (!generateFromSource) {
// modify context
final DefaultTileMatrixSet pm = new DefaultTileMatrixSet(pyramid.getCoordinateReferenceSystem());
pm.getMosaicsInternal().add(mosaic);
final InMemoryTiledGridCoverageResource r = new InMemoryTiledGridCoverageResource(NamesExt.create("test"));
r.setSampleDimensions(resourceCenter.getSampleDimensions());
r.getTileMatrixSets().add(pm);
// we must still use the original resource for generation because
// lower level tiles may not be sufficient to generate border tiles
final AggregatedCoverageResource aggregated = new AggregatedCoverageResource();
aggregated.setMode(AggregatedCoverageResource.Mode.ORDER);
aggregated.add(r);
aggregated.add(this.resource);
aggregated.setInterpolation(interpolation.toSis());
resourceCenter = r;
resourceBorder = aggregated;
}
}
}
}
use of org.geotoolkit.process.ProcessEvent in project geotoolkit by Geomatys.
the class ForwardProcessListener method fireProgressing.
private void fireProgressing(String message, float progress, Exception ex) {
final ProcessEvent event = new ProcessEvent(parentProcess, message, progress, ex);
final ProcessListener[] listeners = parentProcess.getListeners();
for (ProcessListener listener : listeners) {
listener.progressing(event);
}
}
use of org.geotoolkit.process.ProcessEvent in project geotoolkit by Geomatys.
the class PredictorTest method sampleDrift.
@Test
public void sampleDrift() throws Exception {
final Parameters input = Parameters.castOrWrap(DESCRIPTOR.getInputDescriptor().createValue());
input.getOrCreate(PredictorDescriptor.MAX_POINTS).setValue(200);
addWeight(input, 0.5f, 0.5f, 0.5f);
addWeight(input, 0.2f, 0.8f, 0.8f);
input.getOrCreate(PredictorDescriptor.TARGET_RESOLUTION).setValue(1);
input.getOrCreate(PredictorDescriptor.TARGET_WIDTH).setValue(256);
input.getOrCreate(PredictorDescriptor.TARGET_HEIGHT).setValue(256);
input.getOrCreate(PredictorDescriptor.TIMESTEP).setValue(1);
input.getOrCreate(PredictorDescriptor.START_TIMESTAMP).setValue(0);
final long expectedEndTime = 7000;
input.getOrCreate(PredictorDescriptor.END_TIMESTAMP).setValue(expectedEndTime);
input.getOrCreate(PredictorDescriptor.START_POINT).setValue(new DirectPosition2D(CommonCRS.defaultGeographic(), 0.1, 0.2));
input.getOrCreate(PredictorDescriptor.WIND_RESOURCE).setValue(new MemoryGridResource(null, MOCK_UV_DATA));
input.getOrCreate(PredictorDescriptor.CURRENT_RESOURCE).setValue(new MemoryGridResource(null, MOCK_UV_DATA));
final Predictor predictor = new Predictor(DESCRIPTOR, input);
predictor.addListener(new ProcessListenerAdapter() {
@Override
public void progressing(ProcessEvent event) {
final Exception error = event.getException();
if (error != null) {
Utilities.LOGGER.log(Level.WARNING, event.getTask().toString(), error);
} else {
Utilities.LOGGER.log(Level.INFO, event.getTask().toString());
}
}
});
Utilities.LOGGER.info("Starting drift processing");
final Parameters output = CompletableFuture.supplyAsync(() -> {
try {
return predictor.call();
} catch (ProcessException ex) {
throw new RuntimeException(ex);
}
}).thenApply(Parameters::castOrWrap).get(30, TimeUnit.SECONDS);
final long outTime = output.getMandatoryValue(PredictorDescriptor.ACTUAL_END_TIMESTAMP);
final Path netcdf = output.getMandatoryValue(PredictorDescriptor.OUTPUT_DATA);
try {
assertEquals("Expected time of ending", expectedEndTime, outTime);
assertNotNull("Output file path", netcdf);
assertTrue("Output file is not readable", Files.isRegularFile(netcdf));
checkContent(netcdf);
} finally {
Files.delete(netcdf);
}
}
Aggregations