/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2017, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * */ package org.geotools.mbstyle.layer; import org.geotools.mbstyle.MBStyle; import org.geotools.mbstyle.parse.MBFilter; import org.geotools.mbstyle.parse.MBObjectParser; import org.geotools.mbstyle.transform.MBStyleTransformer; import org.geotools.styling.*; import org.geotools.text.Text; import org.json.simple.JSONObject; import org.opengis.filter.expression.Expression; import org.opengis.style.GraphicFill; import org.opengis.style.SemanticType; import org.opengis.style.Symbolizer; import javax.measure.unit.NonSI; import java.awt.*; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; /** * The background color or pattern of the map. * <p> * MBLayer wrapper around a {@link JSONObject} representation of a "background" type latyer. All * methods act as accessors on provided JSON layer, no other state is maintained. This allows * modifications to be made cleanly with out chance of side-effect. * * <ul> * <li>get methods: access the json directly</li> * <li>query methods: provide logic / transforms to GeoTools classes as required.</li> * </ul> */ public class BackgroundMBLayer extends MBLayer { private JSONObject paint; private JSONObject layout; private static String TYPE = "background"; public BackgroundMBLayer(JSONObject json) { super(json, new MBObjectParser(BackgroundMBLayer.class)); paint = paint(); layout = layout(); } @Override protected SemanticType defaultSemanticType() { return SemanticType.POLYGON; } /** * Optional color. Defaults to #000000. Disabled by background-pattern. * * @return The color with which the background will be drawn. */ public Color getBackgroundColor() { return parse.convertToColor(parse.optional(String.class, paint, "background-color", "#000000")); } /** * Maps {@link #getBackgroundColor()} to an {@link Expression}. * * Optional color. Defaults to #000000. Disabled by background-pattern. * * @return The color with which the background will be drawn. */ public Expression backgroundColor() { return parse.color(paint, "background-color", Color.BLACK); } /** * Optional string. Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor * of two (2, 4, 8, ..., 512). * * @return Name of image in sprite to use for drawing an image background, or null if not defined. */ public String getBackgroundPattern() { return parse.optional(String.class, paint, "background-pattern", null); } /** * * @return True if the layer has a background-pattern explicitly provided. */ public boolean hasBackgroundPattern() { return parse.isPropertyDefined(paint, "background-pattern"); } /** * Maps {@link #getBackgroundPattern()} to an {@link Expression}. * * Optional string. Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor * of two (2, 4, 8, ..., 512). * * @return Name of image in sprite to use for drawing an image background, or null if not defined. */ public Expression backgroundPattern() { return parse.string(paint, "background-pattern", null); } /** * Optional number. Defaults to 1. * * @return The opacity at which the background will be drawn. */ public Number getBackgroundOpacity() { return parse.optional(Number.class, paint, "background-opacity", 1.0); } /** * Maps {@link #getBackgroundOpacity()} to an {@link Expression}. * * Optional number. Defaults to 1. * * @retur The opacity at which the background will be drawn. */ public Expression backgroundOpacity() { return parse.percentage(paint, "background-opacity", 1.0); } /** * Transform {@link BackgroundMBLayer} to GeoTools FeatureTypeStyle. * <p> * Notes: * </p> * <ul> * </ul> * * @param styleContext The MBStyle to which this layer belongs, used as a context for things like resolving sprite and glyph names to full urls. * @return FeatureTypeStyle */ public List<FeatureTypeStyle> transformInternal(MBStyle styleContext) { MBStyleTransformer transformer = new MBStyleTransformer(parse); Fill fill; if (hasBackgroundPattern()) { ExternalGraphic eg = transformer.createExternalGraphicForSprite(backgroundPattern(), styleContext); GraphicFill gf = sf.graphicFill(Arrays.asList(eg), backgroundOpacity(), null, null, null, null); fill = sf.fill(gf, backgroundColor(), backgroundOpacity()); } else { fill = sf.fill(null, backgroundColor(), backgroundOpacity()); } Symbolizer symbolizer = sf.polygonSymbolizer(getId(), ff.property((String) null), sf.description(Text.text("fill"), null), NonSI.PIXEL, null, // stroke fill, null, ff.literal(0)); List<Symbolizer> symbolizers = new ArrayList<Symbolizer>(); symbolizers.add(symbolizer); // List of opengis rules here (needed for constructor) MBFilter filter = getFilter(); List<org.opengis.style.Rule> rules = new ArrayList<>(); Rule rule = sf.rule( getId(), null, null, 0.0, Double.POSITIVE_INFINITY, symbolizers, filter.filter()); rule.setLegendGraphic(new Graphic[0]); rules.add(rule); return Collections.singletonList(sf.featureTypeStyle(getId(), sf.description(Text.text("MBStyle " + getId()), Text.text("Generated for " + getSourceLayer())), null, // (unused) Collections.emptySet(), filter.semanticTypeIdentifiers(), rules)); } /** * Rendering type of this layer. * * @return {@link #TYPE} */ @Override public String getType() { return TYPE; } }