import View from 'ol/View.js';
import OSM from 'ol/source/OSM.js';
import TileLayer from 'ol/layer/Tile.js';
-import { fromLonLat } from 'ol/proj.js';
+import { fromLonLat, getPointResolution } from 'ol/proj.js';
import VectorSource from 'ol/source/Vector.js';
import Feature from 'ol/Feature.js';
import { Point } from 'ol/geom.js';
import Overlay from 'ol/Overlay.js';
import { Style, Icon } from 'ol/style.js';
+import * as SLDReader from '@nieuwlandgeo/sldreader';
+
import MapPart from './MapPart.js';
import { SentinelCloudless } from './OpenLayerTileSources.js';
}));
}
- addUrlLayer(url, format, style) {
- let vectorSource;
+ addUrlLayer(url, format, style, sld) {
+ let featureFormat;
if (format === 'GEOJSON') {
- vectorSource = new VectorSource({ url: url, format: new GeoJSON() })
+ featureFormat = new GeoJSON();
}
else if (format === 'GPX') {
- vectorSource = new VectorSource({ url: url, format: new GPX() })
+ featureFormat = new GPX();
+ } else {
+ throw new Error("Unsupported format " + format);
}
- this.#map.addLayer(new VectorLayer({
+ const vectorSource = new VectorSource({
+ url: url,
+ format: featureFormat,
+ });
+ const vectorLayer = new VectorLayer({
source: vectorSource,
- style: style,
- }));
+ });
+ if (sld) {
+ this.#applySLD(vectorLayer, style);
+ } else {
+ vectorLayer.setStyle(style);
+ }
+ this.#map.addLayer(vectorLayer);
}
+
/* CALLBACKS */
enableFeatureSingleClick() {
// we cannot use 'this' in the function provided to OpenLayers
//
// STATIC FOR EXTENSION
//
- static newStyle(args){
+ static newStyle(args) {
return new Style(args);
}
-
- static newIcon(args){
+
+ static newIcon(args) {
return new Icon(args);
}
-
-
+
+ //
+ // SLD STYLING
+ //
+ #applySLD(vectorLayer, text) {
+ const sldObject = SLDReader.Reader(text);
+ const sldLayer = SLDReader.getLayer(sldObject);
+ const style = SLDReader.getStyle(sldLayer);
+ const featureTypeStyle = style.featuretypestyles[0];
+
+ const viewProjection = this.#map.getView().getProjection();
+ const olStyleFunction = SLDReader.createOlStyleFunction(featureTypeStyle, {
+ // Use the convertResolution option to calculate a more accurate resolution.
+ convertResolution: viewResolution => {
+ const viewCenter = this.#map.getView().getCenter();
+ return getPointResolution(viewProjection, viewResolution, viewCenter);
+ },
+ // If you use point icons with an ExternalGraphic, you have to use imageLoadCallback
+ // to update the vector layer when an image finishes loading.
+ // If you do not do this, the image will only be visible after next layer pan/zoom.
+ imageLoadedCallback: () => {
+ vectorLayer.changed();
+ },
+ });
+ vectorLayer.setStyle(olStyleFunction);
+ }
+
+
}
import javax.measure.Quantity;
import javax.measure.quantity.Area;
+import javax.xml.transform.TransformerException;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
+import org.geotools.factory.CommonFactoryFinder;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.geotools.styling.AnchorPoint;
+import org.geotools.styling.Displacement;
+import org.geotools.styling.FeatureTypeConstraint;
+import org.geotools.styling.FeatureTypeStyle;
+import org.geotools.styling.Fill;
+import org.geotools.styling.Graphic;
+import org.geotools.styling.PointSymbolizer;
+import org.geotools.styling.Rule;
+import org.geotools.styling.Stroke;
+import org.geotools.styling.Style;
+import org.geotools.styling.StyleFactory;
+import org.geotools.styling.StyledLayerDescriptor;
+import org.geotools.styling.UserLayer;
+import org.geotools.styling.css.CssParser;
+import org.geotools.styling.css.CssTranslator;
+import org.geotools.styling.css.Stylesheet;
+import org.geotools.xml.styling.SLDTransformer;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
+import org.opengis.filter.Filter;
+import org.opengis.filter.FilterFactory2;
+import org.opengis.filter.expression.Expression;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
+import org.opengis.style.GraphicalSymbol;
import si.uom.SI;
import tech.units.indriya.quantity.Quantities;
}
}
+ public static org.opengis.style.Style createStyleFromCss(String css) {
+ Stylesheet ss = CssParser.parse(css);
+ CssTranslator translator = new CssTranslator();
+ org.opengis.style.Style style = translator.translate(ss);
+
+// try {
+// SLDTransformer styleTransform = new SLDTransformer();
+// String xml = styleTransform.transform(style);
+// System.out.println(xml);
+// } catch (TransformerException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+// }
+
+ return style;
+ }
+
+ public static String createSldFromCss(String name, String title, String css) {
+
+ StyleFactory sf = CommonFactoryFinder.getStyleFactory();
+
+ StyledLayerDescriptor sld = sf.createStyledLayerDescriptor();
+ sld.setName(name);
+ sld.setTitle(title);
+
+ UserLayer layer = sf.createUserLayer();
+ layer.setName("default");
+
+ org.opengis.style.Style style = createStyleFromCss(css);
+ layer.userStyles().add((Style) style);
+
+ sld.layers().add(layer);
+ try {
+ SLDTransformer styleTransform = new SLDTransformer();
+ String xml = styleTransform.transform(sld);
+// System.out.println(xml);
+ return xml;
+ } catch (TransformerException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static void main(String... args) {
+ String css = """
+ * {
+ mark: symbol(circle);
+ mark-size: 6px;
+ }
+
+ :mark {
+ fill: red;
+ }
+
+ """;
+ createSldFromCss("test", "Test", css);
+ }
+
+ public static String createTestSLD() {
+
+ StyleFactory sf = CommonFactoryFinder.getStyleFactory();
+ FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
+
+ StyledLayerDescriptor sld = sf.createStyledLayerDescriptor();
+ sld.setName("sld");
+ sld.setTitle("Example");
+ sld.setAbstract("Example Style Layer Descriptor");
+
+ UserLayer layer = sf.createUserLayer();
+ layer.setName("layer");
+
+ //
+ // define constraint limited what features the sld applies to
+ FeatureTypeConstraint constraint = sf.createFeatureTypeConstraint("Feature", Filter.INCLUDE);
+
+ layer.layerFeatureConstraints().add(constraint);
+
+ //
+ // create a "user defined" style
+ Style style = sf.createStyle();
+ style.setName("style");
+ style.getDescription().setTitle("User Style");
+ style.getDescription().setAbstract("Definition of Style");
+
+ //
+ // define feature type styles used to actually define how features are rendered
+ FeatureTypeStyle featureTypeStyle = sf.createFeatureTypeStyle();
+
+ // RULE 1
+ // first rule to draw cities
+ Rule rule1 = sf.createRule();
+ rule1.setName("rule1");
+ rule1.getDescription().setTitle("City");
+ rule1.getDescription().setAbstract("Rule for drawing cities");
+// rule1.setFilter(ff.less(ff.property("POPULATION"), ff.literal(50000)));
+
+ //
+ // create the graphical mark used to represent a city
+ Stroke stroke = sf.stroke(ff.literal("#000000"), null, null, null, null, null, null);
+ Fill fill = sf.fill(null, ff.literal(java.awt.Color.BLUE), ff.literal(1.0));
+
+// // OnLineResource implemented by gt-metadata - so no factory!
+// OnLineResourceImpl svg = new OnLineResourceImpl(new URI("file:city.svg"));
+// svg.freeze(); // freeze to prevent modification at runtime
+//
+// OnLineResourceImpl png = new OnLineResourceImpl(new URI("file:city.png"));
+// png.freeze(); // freeze to prevent modification at runtime
+
+ //
+ // List of symbols is considered in order with the rendering engine choosing
+ // the first one it can handle. Allowing for svg, png, mark order
+ List<GraphicalSymbol> symbols = new ArrayList<>();
+// symbols.add(sf.externalGraphic(svg, "svg", null)); // svg preferred
+// symbols.add(sf.externalGraphic(png, "png", null)); // png preferred
+ symbols.add(sf.mark(ff.literal("circle"), fill, stroke)); // simple circle backup plan
+
+ Expression opacity = null; // use default
+ Expression size = ff.literal(10);
+ Expression rotation = null; // use default
+ AnchorPoint anchor = null; // use default
+ Displacement displacement = null; // use default
+
+ // define a point symbolizer of a small circle
+ Graphic city = sf.graphic(symbols, opacity, size, rotation, anchor, displacement);
+ PointSymbolizer pointSymbolizer = sf.pointSymbolizer("point", ff.property("the_geom"), null, null, city);
+
+ rule1.symbolizers().add(pointSymbolizer);
+
+ featureTypeStyle.rules().add(rule1);
+
+ //
+ // RULE 2 Default
+
+// List<GraphicalSymbol> dotSymbols = new ArrayList<>();
+// dotSymbols.add(sf.mark(ff.literal("circle"), null, null));
+// Graphic dotGraphic = sf.graphic(dotSymbols, null, ff.literal(3), null, null, null);
+// PointSymbolizer dotSymbolizer = sf.pointSymbolizer("dot", ff.property("the_geom"), null, null, dotGraphic);
+// List<org.opengis.style.Symbolizer> symbolizers = new ArrayList<>();
+// symbolizers.add(dotSymbolizer);
+// Filter other = null; // null will mark this rule as "other" accepting all remaining features
+// Rule rule2 = sf.rule("default", null, null, Double.MIN_VALUE, Double.MAX_VALUE, symbolizers, other);
+// featureTypeStyle.rules().add(rule2);
+
+ style.featureTypeStyles().add(featureTypeStyle);
+
+ layer.userStyles().add(style);
+
+ sld.layers().add(layer);
+
+ try {
+ SLDTransformer styleTransform = new SLDTransformer();
+ String xml = styleTransform.transform(sld);
+ System.out.println(xml);
+ return xml;
+ } catch (TransformerException e) {
+ throw new IllegalStateException(e);
+ }
+
+ }
+
/** Singleton. */
private GeoUtils() {
}