use of org.opengis.style.FeatureTypeStyle 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.opengis.style.FeatureTypeStyle in project geotoolkit by Geomatys.
the class DefaultPortrayalService method present.
public static Stream<Presentation> present(MapLayer layer, Resource resource, RenderingContext2D renderContext) {
final Style style = layer.getStyle();
Stream<Presentation> stream = Stream.empty();
FeatureType type = null;
if (resource instanceof FeatureSet) {
try {
type = ((FeatureSet) resource).getType();
} catch (DataStoreException ex) {
ExceptionPresentation ep = new ExceptionPresentation(ex);
ep.setLayer(layer);
ep.setResource(resource);
return Stream.of(ep);
}
} else if (resource instanceof GridCoverageResource || resource instanceof BandedCoverageResource) {
type = null;
} else if (resource instanceof Aggregate) {
try {
// combine each component resource in the stream
for (Resource r : ((Aggregate) resource).components()) {
stream = Stream.concat(stream, present(layer, r, renderContext));
}
} catch (DataStoreException ex) {
ExceptionPresentation ep = new ExceptionPresentation(ex);
ep.setLayer(layer);
ep.setResource(resource);
return Stream.of(ep);
}
return stream;
} else {
// unknown type
return Stream.empty();
}
final boolean keepAllProperties = GO2Utilities.mustPreserveAllProperties(renderContext);
for (FeatureTypeStyle fts : style.featureTypeStyles()) {
final List<Rule> rules = GO2Utilities.getValidRules(fts, renderContext.getSEScale(), type);
if (rules.isEmpty())
continue;
// prepare the renderers
final CachedRule[] cachedRules = toCachedRules(rules, type);
final RenderingRules renderers = new RenderingRules(cachedRules, renderContext);
{
// special case for group symbolizers
// group symbolizers must be alone in a FTS
SymbolizerRenderer groupRenderer = null;
int count = 0;
for (int i = 0; i < renderers.renderers.length; i++) {
for (int k = 0; k < renderers.renderers[i].length; k++) {
count++;
if (renderers.renderers[i][k].getService().isGroupSymbolizer()) {
groupRenderer = renderers.renderers[i][k];
}
}
}
if (groupRenderer != null) {
if (count > 1) {
ExceptionPresentation ep = new ExceptionPresentation(new PortrayalException("Group symbolizer (" + groupRenderer.getService().getSymbolizerClass().getSimpleName() + ") must be alone in a FeatureTypeStyle element."));
ep.setLayer(layer);
ep.setResource(resource);
stream = Stream.concat(stream, Stream.of(ep));
} else {
stream = Stream.concat(stream, groupRenderer.presentations(layer, resource));
}
continue;
}
}
// extract the used names
Set<String> names;
if (keepAllProperties) {
names = null;
} else {
names = GO2Utilities.propertiesNames(rules);
if (names.contains("*")) {
// we need all properties
names = null;
}
}
// performance routine, only one symbol to render
if (renderers.rules.length == 1 && (renderers.rules[0].getFilter() == null || renderers.rules[0].getFilter() == Filter.include()) && renderers.rules[0].symbolizers().length == 1) {
stream = Stream.concat(stream, renderers.renderers[0][0].presentations(layer, resource));
continue;
}
if (resource instanceof GridCoverageResource) {
boolean painted = false;
for (int i = 0; i < renderers.elseRuleIndex; i++) {
final CachedRule rule = renderers.rules[i];
final Filter ruleFilter = rule.getFilter();
// test if the rule is valid for this feature
if (ruleFilter == null || ruleFilter.test(resource)) {
painted = true;
for (final SymbolizerRenderer renderer : renderers.renderers[i]) {
stream = Stream.concat(stream, renderer.presentations(layer, resource));
}
}
}
// the data hasn't been painted, paint it with the 'else' rules
if (!painted) {
for (int i = renderers.elseRuleIndex; i < renderers.rules.length; i++) {
final CachedRule rule = renderers.rules[i];
final Filter ruleFilter = rule.getFilter();
// test if the rule is valid for this feature
if (ruleFilter == null || ruleFilter.test(resource)) {
for (final SymbolizerRenderer renderer : renderers.renderers[i]) {
stream = Stream.concat(stream, renderer.presentations(layer, resource));
}
}
}
}
} else if (resource instanceof FeatureSet) {
final FeatureSet fs = (FeatureSet) resource;
// calculate max symbol size, to expand search envelope.
double symbolsMargin = 0.0;
for (CachedRule rule : cachedRules) {
for (CachedSymbolizer cs : rule.symbolizers()) {
symbolsMargin = Math.max(symbolsMargin, cs.getMargin(null, renderContext));
}
}
if (Double.isNaN(symbolsMargin) || Double.isInfinite(symbolsMargin)) {
// symbol margin can not be pre calculated, expect a max of 300pixels
symbolsMargin = 300f;
}
if (symbolsMargin > 0) {
final double scale = AffineTransforms2D.getScale(renderContext.getDisplayToObjective());
symbolsMargin = scale * symbolsMargin;
}
// optimize
final Query query;
try {
query = RenderingRoutines.prepareQuery(renderContext, fs, layer, names, rules, symbolsMargin);
final Stream<Presentation> s = fs.subset(query).features(false).flatMap(new Function<Feature, Stream<Presentation>>() {
@Override
public Stream<Presentation> apply(Feature feature) {
Stream<Presentation> stream = Stream.empty();
boolean painted = false;
for (int i = 0; i < renderers.elseRuleIndex; i++) {
final CachedRule rule = renderers.rules[i];
final Filter ruleFilter = rule.getFilter();
// test if the rule is valid for this feature
if (ruleFilter == null || ruleFilter.test(feature)) {
painted = true;
for (final SymbolizerRenderer renderer : renderers.renderers[i]) {
stream = Stream.concat(stream, renderer.presentations(layer, feature));
}
}
}
// the feature hasn't been painted, paint it with the 'else' rules
if (!painted) {
for (int i = renderers.elseRuleIndex; i < renderers.rules.length; i++) {
final CachedRule rule = renderers.rules[i];
final Filter ruleFilter = rule.getFilter();
// test if the rule is valid for this feature
if (ruleFilter == null || ruleFilter.test(feature)) {
for (final SymbolizerRenderer renderer : renderers.renderers[i]) {
stream = Stream.concat(stream, renderer.presentations(layer, feature));
}
}
}
}
return stream;
}
});
stream = Stream.concat(stream, s);
} catch (PortrayalException | DataStoreException ex) {
ExceptionPresentation ep = new ExceptionPresentation(ex);
ep.setLayer(layer);
ep.setResource(resource);
return Stream.of(ep);
}
}
}
return stream;
}
use of org.opengis.style.FeatureTypeStyle in project geotoolkit by Geomatys.
the class ListingPropertyVisitor method visit.
@Override
public Object visit(final Style style, Object data) {
final List<? extends FeatureTypeStyle> ftss = style.featureTypeStyles();
if (ftss != null) {
for (FeatureTypeStyle fts : ftss) {
data = fts.accept(this, data);
}
}
final Symbolizer def = style.getDefaultSpecification();
if (def != null) {
data = def.accept(this, data);
}
return data;
}
use of org.opengis.style.FeatureTypeStyle in project geotoolkit by Geomatys.
the class J2DLegendUtilities method estimateWithTemplate.
/**
* Estimate the size (pixels) needed to render the given {@link MapItem} legend
* using the input rendering hint (see {@link LegendTemplate}).
* @param g2d The {@link Graphics2D} to paint legend into.
* @param source The source map item to render.
* @param toSet The {@link Dimension} to store estimation result into.
* @param template the {@link LegendTemplate} to use as rendering hint.
* @param images A map in which we'll store eventual legend we generated
* during the process (key = layer name, value = layer legend). Can be null.
* @param considerBackground A boolean to specify if we must count input
* {@link LegendTemplate} background margins in the result size (true) or
* not (false).
*/
private static void estimateWithTemplate(final Graphics2D g2d, final MapItem source, final Dimension toSet, final LegendTemplate template, final Map<GenericName, BufferedImage> images, final boolean considerBackground) {
final FontMetrics layerFontMetric = g2d.getFontMetrics(template.getLayerFont());
final FontMetrics ruleFontMetric = g2d.getFontMetrics(template.getRuleFont());
final int ruleFontHeight = ruleFontMetric.getHeight();
final Dimension glyphSize = template.getGlyphSize();
final List<MapItem> childItems = (source instanceof MapLayers) ? ((MapLayers) source).getComponents() : Collections.EMPTY_LIST;
for (int l = 0, n = childItems.size(); l < n; l++) {
/* If legend template asks for visible items only, we have to proceed
* in two steps, because we cannot just check item visibility.
* If we are on a container (not a layer), it must be considered as
* invisible if none of its children is visible.
*/
final MapItem currentItem = childItems.get(l);
if (template.displayOnlyVisibleLayers() && !isVisible(currentItem)) {
continue;
}
if (template.isLayerVisible()) {
if (l != 0) {
toSet.height += template.getGapSize();
}
// Determines space to reserve for title.
final Dimension titleDim = estimateTitle(currentItem, layerFontMetric);
toSet.height += titleDim.height;
if (toSet.width < titleDim.width) {
toSet.width = titleDim.width;
}
if (titleDim.height > 0) {
toSet.height += template.getGapSize();
}
}
if (!(currentItem instanceof MapLayer)) {
estimateWithTemplate(g2d, currentItem, toSet, template, images, considerBackground);
continue;
}
final MapLayer layer = (MapLayer) currentItem;
final Style style = layer.getStyle();
if (style == null) {
continue;
}
int numElement = 0;
for (final FeatureTypeStyle fts : style.featureTypeStyles()) {
for (final Rule rule : fts.rules()) {
if (numElement != 0) {
toSet.height += template.getGapSize();
}
// calculate the text length
int textLenght = 0;
final Description description = rule.getDescription();
if (description != null) {
final InternationalString titleTmp = description.getTitle();
if (titleTmp != null) {
final String title = titleTmp.toString();
textLenght = ruleFontMetric.stringWidth(title);
}
}
// calculate the glyph size
final int glyphHeight;
final int glyphWidth;
final Dimension preferred = DefaultGlyphService.glyphPreferredSize(rule, null, layer);
if (glyphSize == null) {
// find the best size
glyphHeight = preferred.height;
glyphWidth = preferred.width;
} else {
// use the defined size
glyphHeight = glyphSize.height > preferred.height ? glyphSize.height : preferred.height;
glyphWidth = glyphSize.width > preferred.width ? glyphSize.width : preferred.width;
}
final int totalWidth = glyphWidth + ((textLenght == 0) ? 0 : (GLYPH_SPACE + textLenght));
final int fh = (textLenght > 0) ? ruleFontHeight : 0;
final int totalHeight = (glyphHeight > fh) ? glyphHeight : fh;
toSet.height += totalHeight;
if (toSet.width < totalWidth) {
toSet.width = totalWidth;
}
numElement++;
}
}
}
if (considerBackground && template.getBackground() != null) {
final Insets insets = template.getBackground().getBackgroundInsets();
toSet.width += insets.left + insets.right;
toSet.height += insets.bottom + insets.top;
}
}
use of org.opengis.style.FeatureTypeStyle in project geotoolkit by Geomatys.
the class RenderingRoutines method mergeStyles.
/**
* Merge a layer style with a selection style.
* The selection style fts elements will be placed after those of the default style.
*/
public static MutableStyle mergeStyles(MutableStyle style, Filter selectionFilter, MutableStyle selectionStyle) {
if (selectionFilter == null || Filter.exclude().equals(selectionFilter) || selectionStyle == null) {
// unmodified
return style;
}
final Filter exclusionFilter = FILTER_FACTORY.not(selectionFilter);
final MutableStyle result = GO2Utilities.STYLE_FACTORY.style();
for (FeatureTypeStyle fts : style.featureTypeStyles()) {
final MutableFeatureTypeStyle resultfts = GO2Utilities.STYLE_FACTORY.featureTypeStyle();
resultfts.setDescription(fts.getDescription());
resultfts.setFeatureInstanceIDs(fts.getFeatureInstanceIDs());
resultfts.setName(fts.getName());
resultfts.setOnlineResource(fts.getOnlineResource());
result.featureTypeStyles().add(resultfts);
for (Rule rule : fts.rules()) {
final MutableRule modifiedRule = STYLE_FACTORY.rule(rule.symbolizers().toArray(new Symbolizer[0]));
Filter f = rule.getFilter();
if (f == null) {
f = exclusionFilter;
} else {
f = FILTER_FACTORY.and(f, exclusionFilter);
}
modifiedRule.setFilter(f);
resultfts.rules().add(modifiedRule);
}
}
if (selectionStyle != null) {
for (FeatureTypeStyle fts : selectionStyle.featureTypeStyles()) {
final MutableFeatureTypeStyle resultfts = GO2Utilities.STYLE_FACTORY.featureTypeStyle();
resultfts.setDescription(fts.getDescription());
resultfts.setFeatureInstanceIDs(fts.getFeatureInstanceIDs());
resultfts.setName(fts.getName());
resultfts.setOnlineResource(fts.getOnlineResource());
result.featureTypeStyles().add(resultfts);
for (Rule rule : fts.rules()) {
final MutableRule modifiedRule = STYLE_FACTORY.rule(rule.symbolizers().toArray(new Symbolizer[0]));
Filter f = rule.getFilter();
if (f == null) {
f = selectionFilter;
} else {
f = FILTER_FACTORY.and(f, selectionFilter);
}
modifiedRule.setFilter(f);
resultfts.rules().add(modifiedRule);
}
}
}
return result;
}
Aggregations